/****************************************************************************** * arch/xen/drivers/netif/backend/interface.c * * Network-device interface management. * * Copyright (c) 2004, Keir Fraser */ #include "u.h" #include "../port/lib.h" #include "mem.h" #include "dat.h" #include "fns.h" #include "../port/error.h" #include "xennet.h" #include "../port/netif.h" #include "etherif.h" #define DPRINT print #define NETIF_HASHSZ 1024 #define NETIF_HASH(_d,_h) \ (((int)(_d)^(int)((_d)>>32)^(int)(_h))&(NETIF_HASHSZ-1)) /* they's only 32 of these things ... just allocate 'em. * move to pointers later if needed. Leave the next infrastructure * in there until we found out if that's what we want. */ static netif_t *netif_hash[NETIF_HASHSZ]; /* static struct net_device *bridge_dev; static struct net_bridge *bridge_br; */ netif_t *netif_find_by_handle(domid_t domid, unsigned int handle) { netif_t *netif = netif_hash[NETIF_HASH(domid, handle)]; while ( (netif != 0) && ((netif->domid != domid) || (netif->handle != handle)) ) netif = netif->hash_next; return netif; } void __netif_disconnect_complete(netif_t *netif) { ctrl_msg_t cmsg; netif_be_disconnect_t disc; // void unbind_evtchn_from_irq(int evtchn); /* * These can't be done in __netif_disconnect() because at that point there * may be outstanding requests at the disc whose asynchronous responses * must still be notified to the remote driver. */ unbind_evtchn_from_irq(netif->evtchn); /* vfree(netif->tx); /* Frees netif->rx as well. */ print("MEMORY LEAK!\n"); // rtnl_lock(); // (void)br_del_if(bridge_br, netif->dev); // (void)dev_close(netif->dev); //rtnl_unlock(); /* Construct the deferred response message. */ cmsg.type = CMSG_NETIF_BE; cmsg.subtype = CMSG_NETIF_BE_DISCONNECT; cmsg.id = netif->disconnect_rspid; cmsg.length = sizeof(netif_be_disconnect_t); disc.domid = netif->domid; disc.netif_handle = netif->handle; disc.status = NETIF_BE_STATUS_OKAY; memmove(cmsg.msg, &disc, sizeof(disc)); /* * Make sure message is constructed /before/ status change, because * after the status change the 'netif' structure could be deallocated at * any time. Also make sure we send the response /after/ status change, * as otherwise a subsequent CONNECT request could spuriously fail if * another CPU doesn't see the status change yet. */ //mb(); if ( netif->status != DISCONNECTING ) panic("__netif_disconnect_complete: state not DISCONNECTING\n"); netif->status = DISCONNECTED; //mb(); /* Send the successful response. */ ctrl_if_send_response(&cmsg); } /* the link from Ether * to netif struct is via the 'special' numbering. * Thus we don't munge pointers into things the way linux does */ void netif_create(netif_be_create_t *create) { domid_t domid = create->domid; unsigned int handle = create->netif_handle; unsigned int hash; char name[8]; int i; netif_t *netif, **pnetif; Chan *c = 0; /* spec gives us a number between 0 and MaxEther */ netif = malloc(sizeof(&netif_hash[hash])); if (! netif) { DPRINT("create: outof memory for netif\n"); create->status = NETIF_BE_STATUS_OUT_OF_MEMORY; return; } for(i = 0; i < MaxEther; i++) { snprint(name, sizeof(name), "#l%d", i); DPRINT("open :%s:\n", name); c = namec(name, Aopen, ORDWR, 0); if ( c == 0 ) { DPRINTK("Could not create netif: out of memory\n"); create->status = NETIF_BE_STATUS_OUT_OF_MEMORY; return; } } memset(netif, 0, sizeof(*netif)); netif->domid = domid; netif->handle = handle; netif->status = DISCONNECTED; /* you just memset it ... why did they do this one? atomic_set(&netif->refcnt, 0); */ netif->dev = c; netif->credit_bytes = netif->remaining_credit = ~0UL; netif->credit_usec = 0UL; /*init_ac_timer(&new_vif->credit_timeout);*/ pnetif = &netif_hash[NETIF_HASH(domid, handle)]; while ( *pnetif != 0 ) { if ( ((*pnetif)->domid == domid) && ((*pnetif)->handle == handle) ) { DPRINTK("Could not create netif: already exists\n"); create->status = NETIF_BE_STATUS_INTERFACE_EXISTS; return; } pnetif = &(*pnetif)->hash_next; } //memcpy(dev->dev_addr, create->mac, ETH_ALEN); /* XXX In bridge mode we should force a different MAC from remote end. * dev->dev_addr[2] ^= 1; */ netif->hash_next = *pnetif; *pnetif = netif; DPRINTK("Successfully created netif\n"); create->status = NETIF_BE_STATUS_OKAY; } void netif_destroy(netif_be_destroy_t *destroy) { domid_t domid = destroy->domid; unsigned int handle = destroy->netif_handle; netif_t **pnetif, *netif; pnetif = &netif_hash[NETIF_HASH(domid, handle)]; while ( (netif = *pnetif) != 0 ) { if ( (netif->domid == domid) && (netif->handle == handle) ) { if ( netif->status != DISCONNECTED ) goto still_connected; goto destroy; } pnetif = &netif->hash_next; } destroy->status = NETIF_BE_STATUS_INTERFACE_NOT_FOUND; return; still_connected: destroy->status = NETIF_BE_STATUS_INTERFACE_CONNECTED; return; destroy: *pnetif = netif->hash_next; /* unregister_netdev(netif->dev); kfree(netif->dev); */ destroy->status = NETIF_BE_STATUS_OKAY; } void netif_interrupt(Ureg *, void *) { DPRINT("netif interrupt!\n"); } void netif_connect(netif_be_connect_t *connect) { domid_t domid = connect->domid; unsigned int handle = connect->netif_handle; unsigned int evtchn = connect->evtchn; unsigned long tx_shmem_frame = connect->tx_shmem_frame; unsigned long rx_shmem_frame = connect->rx_shmem_frame; netif_t *netif; unsigned long pa; netif = netif_find_by_handle(domid, handle); if (! netif) { print("netif_connect attempted for non-existent netif (%llux,%ux)\n", connect->domid, connect->netif_handle); connect->status = NETIF_BE_STATUS_INTERFACE_NOT_FOUND; return; } if ( netif->status != DISCONNECTED ) { connect->status = NETIF_BE_STATUS_INTERFACE_CONNECTED; return; } /* allocate a chunk of space */ pa = upamalloc(0, 2*BY2PG, BY2PG); if (! pa) { panic("ENOMEM in netinterface.c"); } /* now have to make the two va's point to the frames that are * passed in */ DPRINT("Set va %p to frame %lx\n", KADDR(pa), tx_shmem_frame); add_va_pfn(KADDR(pa), tx_shmem_frame, PTEWRITE); DPRINT("Set va %p to frame %lx\n", KADDR(pa), rx_shmem_frame); add_va_pfn(KADDR(pa+BY2PG), rx_shmem_frame, PTEWRITE); netif->evtchn = evtchn; netif->irq = bind_evtchn_to_irq(evtchn, 0); DPRINT("netif connect: irq is %d\n", netif->irq); (void) intrenable(netif->irq, netif_interrupt ,nil, 0, "netif interrupt"); netif->tx_shmem_frame = tx_shmem_frame; netif->rx_shmem_frame = rx_shmem_frame; netif->tx = (netif_tx_interface_t *)KADDR(pa); netif->rx = (netif_rx_interface_t *)KADDR(pa+BY2PG); netif->status = CONNECTED; /* need to get an irq to point to netif_be_int ...*/ connect->status = NETIF_BE_STATUS_OKAY; } int netif_disconnect(netif_be_disconnect_t *disconnect, u8 rsp_id) { domid_t domid = disconnect->domid; unsigned int handle = disconnect->netif_handle; netif_t *netif; netif = netif_find_by_handle(domid, handle); if (netif == 0) { DPRINTK("netif_disconnect attempted for non-existent netif" " (%llux,%ux)\n", disconnect->domid, disconnect->netif_handle); disconnect->status = NETIF_BE_STATUS_INTERFACE_NOT_FOUND; return 1; /* Caller will send response error message. */ } if ( netif->status == CONNECTED ) { netif->status = DISCONNECTING; netif->disconnect_rspid = rsp_id; /*wmb(); /* Let other CPUs see the status change. */ /*netif_stop_queue(netif->dev); free_irq(netif->irq, NULL); netif_deschedule(netif); netif_put(netif); */ } return 0; /* Caller should not send response message. */ } void netif_interface_init(void) { memset(netif_hash, 0, sizeof(netif_hash)); }