static int initialized;
-extern struct net_device static_single_netdev;
-
-
/**************************************************************************
MAIN - Kick off routine
**************************************************************************/
call_init_fns ();
probe_devices();
- /* Quick hack until netdevice.c uses proper dynamic registration */
- netdev = &static_single_netdev;
- if ( ! netdev->poll )
- netdev = NULL;
-
+ netdev = next_netdev ();
if ( netdev ) {
- test_aoeboot ( &static_single_netdev );
+ test_aoeboot ( netdev );
} else {
printf ( "No network device found\n" );
}
*
*/
+#include <gpxe/tables.h>
+
struct net_device;
struct net_protocol;
+/** A network-layer protocol that relies upon ARP */
+struct arp_net_protocol {
+ /** Network-layer protocol */
+ struct net_protocol *net_protocol;
+ /** Check existence of address
+ *
+ * @v netdev Network device
+ * @v net_addr Network-layer address
+ * @ret rc Return status code
+ */
+ int ( * check ) ( struct net_device *netdev,
+ const void *net_addr );
+};
+
+/**
+ * Register an ARP protocol
+ *
+ * @v protocol ARP protocol
+ */
+#define ARP_NET_PROTOCOL( protocol ) \
+ struct arp_net_protocol protocol __table ( arp_net_protocols, 01 )
+
extern int arp_resolve ( struct net_device *netdev,
struct net_protocol *net_protocol,
const void *dest_net_addr,
* @v priv_size Size of driver private data
* @ret netdev Network device, or NULL
*/
-#define alloc_etherdev( priv_size ) ( { \
- struct net_device *netdev; \
- netdev = alloc_netdev ( priv_size ); \
- if ( netdev ) \
- netdev->ll_protocol = ðernet_protocol; \
- netdev; } )
+static inline struct net_device * alloc_etherdev ( size_t priv_size ) {
+ struct net_device *netdev;
+
+ netdev = alloc_netdev ( priv_size );
+ if ( netdev ) {
+ netdev->ll_protocol = ðernet_protocol;
+ }
+ return netdev;
+}
#endif /* _GPXE_ETHERNET_H */
*
*/
+#include <ip.h>
+
struct net_protocol;
extern struct net_protocol ipv4_protocol;
struct in_addr address, struct in_addr netmask,
struct in_addr gateway );
extern void del_ipv4_address ( struct net_device *netdev );
-extern int ipv4_uip_transmit ( struct pk_buff *pkb );
+extern int ipv4_uip_tx ( struct pk_buff *pkb );
#endif /* _GPXE_IP_H */
*/
#include <stdint.h>
+#include <gpxe/list.h>
#include <gpxe/tables.h>
struct pk_buff;
/** Maximum length of a network-layer address */
#define MAX_NET_ADDR_LEN 4
-/* Network-layer address may be required to hold a link-layer address
- * (if NETADDR_FL_RAW is set
- */
-#if MAX_NET_ADDR_LEN < MAX_LL_ADDR_LEN
-#undef MAX_NET_ADDR_LEN
-#define MAX_NET_ADDR_LEN MAX_LL_ADDR_LEN
-#endif
-
-/** A generic network-layer header */
-struct net_header {
- /** Network-layer protocol */
- struct net_protocol *net_protocol;
- /** Flags
- *
- * This is the bitwise OR of zero or more PKT_FL_XXX
- * values.
- */
- int flags;
- /** Network-layer destination address */
- uint8_t dest_net_addr[MAX_NET_ADDR_LEN];
- /** Network-layer source address */
- uint8_t source_net_addr[MAX_NET_ADDR_LEN];
-};
-
-/** Packet is a broadcast packet */
-#define PKT_FL_BROADCAST 0x01
-
-/** Packet is a multicast packet */
-#define PKT_FL_MULTICAST 0x02
-
-/** Addresses are raw hardware addresses */
-#define PKT_FL_RAW_ADDR 0x04
-
-/** A generic link-layer header */
-struct ll_header {
- /** Link-layer protocol */
- struct ll_protocol *ll_protocol;
- /** Flags
- *
- * This is the bitwise OR of zero or more PKT_FL_XXX
- * values.
- */
- int flags;
- /** Link-layer destination address */
- uint8_t dest_ll_addr[MAX_LL_ADDR_LEN];
- /** Link-layer source address */
- uint8_t source_ll_addr[MAX_LL_ADDR_LEN];
- /** Network-layer protocol
- *
- *
- * This is an ETH_P_XXX constant, in network-byte order
- */
- uint16_t net_proto;
-};
-
/**
* A network-layer protocol
*
* Process received packet
*
* @v pkb Packet buffer
- * @ret rc Return status code
+ * @v netdev Network device
+ * @v ll_source Link-layer source address
*
* This method takes ownership of the packet buffer.
*/
- int ( * rx_process ) ( struct pk_buff *pkb );
+ int ( * rx ) ( struct pk_buff *pkb, struct net_device *netdev,
+ const void *ll_source );
/**
* Transcribe network-layer address
*
/**
* Transmit network-layer packet via network device
*
- *
* @v pkb Packet buffer
* @v netdev Network device
* @v net_protocol Network-layer protocol
* This method should prepend in the link-layer header
* (e.g. the Ethernet DIX header) and transmit the packet.
*/
- int ( * transmit ) ( struct pk_buff *pkb, struct net_device *netdev,
- struct net_protocol *net_protocol,
- const void *ll_dest );
+ int ( * tx ) ( struct pk_buff *pkb, struct net_device *netdev,
+ struct net_protocol *net_protocol,
+ const void *ll_dest );
/**
- * Parse media-specific link-layer header
+ * Handle received packet
*
* @v pkb Packet buffer
- * @v llhdr Generic link-layer header
+ * @v netdev Network device
*
- * This method should fill in the generic link-layer header
- * based on information in the link-layer header in the packet
- * buffer.
+ * This method should strip off the link-layer header
+ * (e.g. the Ethernet DIX header) and pass the packet to
+ * net_rx().
*/
- void ( * parse_llh ) ( const struct pk_buff *pkb,
- struct ll_header *llhdr );
-
+ void ( * rx ) ( struct pk_buff *pkb, struct net_device *netdev );
/**
* Transcribe link-layer address
*
* The buffer used to hold the transcription is statically
* allocated.
*/
- const char * ( *ntoa ) ( const void * ll_addr );
+ const char * ( * ntoa ) ( const void * ll_addr );
/** Link-layer protocol
*
* This is an ARPHRD_XXX constant, in network byte order.
const uint8_t *ll_broadcast;
};
-/**
- * A network-layer address assigned to a network device
- *
- */
-struct net_address {
- /** Network-layer protocol */
- struct net_protocol *net_protocol;
- /** Network-layer address */
- uint8_t net_addr[MAX_NET_ADDR_LEN];
-};
-
/**
* A network device
*
* not just an Ethernet device.
*/
struct net_device {
+ /** List of network devices */
+ struct list_head list;
/** Transmit packet
*
* @v netdev Network device
*/
uint8_t ll_addr[MAX_LL_ADDR_LEN];
+ /** Received packet queue */
+ struct list_head rx_queue;
+
/** Driver private data */
void *priv;
};
-extern struct net_device static_single_netdev;
-
-/**
- * Allocate network device
- *
- * @v priv_size Size of private data area (net_device::priv)
- * @ret netdev Network device, or NULL
- *
- * Allocates space for a network device and its private data area.
- *
- * This macro allows for a very efficient implementation in the case
- * of a single static network device; it neatly avoids dynamic
- * allocation and can never return failure, meaning that the failure
- * path will be optimised away. However, driver writers should not
- * rely on this feature; the drivers should be written to allow for
- * multiple instances of network devices.
- */
-#define alloc_netdev( priv_size ) ( { \
- static char priv_data[priv_size]; \
- static_single_netdev.priv = priv_data; \
- &static_single_netdev; } )
-
-/**
- * Free network device
- *
- * @v netdev Network device
- */
-static inline void
-free_netdev ( struct net_device *netdev __attribute__ (( unused )) ) {
- /* Nothing to do */
-}
-
-/**
- * Transmit raw packet via network device
- *
- * @v netdev Network device
- * @v pkb Packet buffer
- * @ret rc Return status code
- *
- * Transmits the packet via the specified network device. The
- * link-layer header must already have been filled in. This function
- * takes ownership of the packet buffer.
- */
-static inline int netdev_transmit ( struct net_device *netdev,
- struct pk_buff *pkb ) {
- return netdev->transmit ( netdev, pkb );
-}
-
-/**
- * Transmit network-layer packet
- *
- * @v pkb Packet buffer
- * @v netdev Network device
- * @v net_protocol Network-layer protocol
- * @v ll_dest Destination link-layer address
- * @ret rc Return status code
- *
- * Prepends link-layer headers to the packet buffer and transmits the
- * packet via the specified network device. This function takes
- * ownership of the packet buffer.
- */
-static inline int net_transmit ( struct pk_buff *pkb,
- struct net_device *netdev,
- struct net_protocol *net_protocol,
- const void *ll_dest ) {
- return netdev->ll_protocol->transmit ( pkb, netdev, net_protocol,
- ll_dest );
-}
-
/**
* Register a link-layer protocol
*
struct net_protocol protocol __table ( net_protocols, 01 )
/**
- * Register a network-layer address for the static single network device
+ * Get network device name
+ *
+ * @v netdev Network device
+ * @ret name Network device name
*
- * @v net_address Network-layer address
+ * The name will be the device's link-layer address.
*/
-#define STATIC_SINGLE_NETDEV_ADDRESS( address ) \
- struct net_address address __table ( sgl_netdev_addresses, 01 )
+static inline const char * netdev_name ( struct net_device *netdev ) {
+ return netdev->ll_protocol->ntoa ( netdev->ll_addr );
+}
+extern int netdev_tx ( struct net_device *netdev, struct pk_buff *pkb );
+extern void netdev_rx ( struct net_device *netdev, struct pk_buff *pkb );
+extern int net_tx ( struct pk_buff *pkb, struct net_device *netdev,
+ struct net_protocol *net_protocol, const void *ll_dest );
+extern void net_rx ( struct pk_buff *pkb, struct net_device *netdev,
+ uint16_t net_proto, const void *ll_source );
+extern int netdev_poll ( struct net_device *netdev );
+extern struct pk_buff * netdev_rx_dequeue ( struct net_device *netdev );
+extern struct net_device * alloc_netdev ( size_t priv_size );
extern int register_netdev ( struct net_device *netdev );
extern void unregister_netdev ( struct net_device *netdev );
-extern void netdev_rx ( struct net_device *netdev, struct pk_buff *pkb );
-
-extern struct net_protocol *find_net_protocol ( uint16_t net_proto );
-extern struct net_device *
-find_netdev_by_net_addr ( struct net_protocol *net_protocol, void *net_addr );
-
-extern int net_poll ( void );
-extern struct pk_buff * net_rx_dequeue ( void );
-extern int net_rx_process ( struct pk_buff *pkb );
+extern void free_netdev ( struct net_device *netdev );
+extern struct net_device * next_netdev ( void );
#endif /* _GPXE_NETDEVICE_H */
#include <assert.h>
#include <gpxe/list.h>
-struct net_protocol;
-struct ll_protocol;
-
/**
* Packet buffer alignment
*
* This structure is used to represent a network packet within gPXE.
*/
struct pk_buff {
+ /** List of which this buffer is a member */
+ struct list_head list;
+
/** Start of the buffer */
void *head;
/** Start of data */
void *tail;
/** End of the buffer */
void *end;
-
- /** List of which this buffer is a member */
- struct list_head list;
-
- /** The network-layer protocol */
- struct net_protocol *net_protocol;
- /** The link-layer protocol */
- struct ll_protocol *ll_protocol;
};
/**
data_out_len );
if ( ! pkb )
return -ENOMEM;
- pkb->net_protocol = &aoe_protocol;
pkb_reserve ( pkb, ETH_HLEN );
aoehdr = pkb_put ( pkb, sizeof ( *aoehdr ) );
aoecmd = pkb_put ( pkb, sizeof ( *aoecmd ) );
/* Send packet */
start_timer ( &aoe->timer );
- return net_transmit ( pkb, aoe->netdev, &aoe_protocol, aoe->target );
+ return net_tx ( pkb, aoe->netdev, &aoe_protocol, aoe->target );
}
/**
* Process incoming AoE packets
*
* @v pkb Packet buffer
+ * @v netdev Network device
+ * @v ll_source Link-layer source address
* @ret rc Return status code
*
*/
-static int aoe_rx ( struct pk_buff *pkb ) {
+static int aoe_rx ( struct pk_buff *pkb, struct net_device *netdev __unused,
+ const void *ll_source ) {
struct aoehdr *aoehdr = pkb->data;
unsigned int len = pkb_len ( pkb );
- struct ethhdr *ethhdr = pkb_push ( pkb, sizeof ( *ethhdr ) );
struct aoe_session *aoe;
int rc = 0;
continue;
if ( ntohl ( aoehdr->tag ) != aoe->tag )
continue;
- memcpy ( aoe->target, ethhdr->h_source,
- sizeof ( aoe->target ) );
+ memcpy ( aoe->target, ll_source, sizeof ( aoe->target ) );
rc = aoe_rx_response ( aoe, aoehdr, len );
break;
}
struct net_protocol aoe_protocol = {
.name = "AoE",
.net_proto = htons ( ETH_P_AOE ),
- .rx_process = aoe_rx,
+ .rx = aoe_rx,
};
NET_PROTOCOL ( aoe_protocol );
*
*/
+/** Registered ARP protocols */
+static struct arp_net_protocol arp_net_protocols[0]
+ __table_start ( arp_net_protocols );
+static struct arp_net_protocol arp_net_protocols_end[0]
+ __table_end ( arp_net_protocols );
+
/** An ARP cache entry */
struct arp_entry {
/** Network-layer protocol */
2 * ( MAX_LL_ADDR_LEN + MAX_NET_ADDR_LEN ) );
if ( ! pkb )
return -ENOMEM;
- pkb->net_protocol = &arp_protocol;
pkb_reserve ( pkb, MAX_LL_HEADER_LEN );
/* Build up ARP request */
dest_net_addr, net_protocol->net_addr_len );
/* Transmit ARP request */
- if ( ( rc = net_transmit ( pkb, netdev, &arp_protocol,
- ll_protocol->ll_broadcast ) ) != 0 )
+ if ( ( rc = net_tx ( pkb, netdev, &arp_protocol,
+ ll_protocol->ll_broadcast ) ) != 0 )
return rc;
return -ENOENT;
}
+/**
+ * Identify ARP protocol
+ *
+ * @v net_proto Network-layer protocol, in network-endian order
+ * @ret arp_net_protocol ARP protocol, or NULL
+ *
+ */
+static struct arp_net_protocol * arp_find_protocol ( uint16_t net_proto ) {
+ struct arp_net_protocol *arp_net_protocol;
+
+ for ( arp_net_protocol = arp_net_protocols ;
+ arp_net_protocol < arp_net_protocols_end ; arp_net_protocol++ ) {
+ if ( arp_net_protocol->net_protocol->net_proto == net_proto ) {
+ return arp_net_protocol;
+ }
+ }
+ return NULL;
+}
+
/**
* Process incoming ARP packets
*
* @v pkb Packet buffer
+ * @v netdev Network device
+ * @v ll_source Link-layer source address
* @ret rc Return status code
*
* This handles ARP requests and responses as detailed in RFC826. The
* avoiding the need for extraneous ARP requests; read the RFC for
* details.
*/
-static int arp_rx ( struct pk_buff *pkb ) {
+static int arp_rx ( struct pk_buff *pkb, struct net_device *netdev,
+ const void *ll_source __unused ) {
struct arphdr *arphdr = pkb->data;
- struct ll_protocol *ll_protocol;
+ struct arp_net_protocol *arp_net_protocol;
struct net_protocol *net_protocol;
+ struct ll_protocol *ll_protocol;
struct arp_entry *arp;
- struct net_device *netdev;
int merge = 0;
- /* Identify link-layer and network-layer protocols */
- ll_protocol = pkb->ll_protocol;
- net_protocol = find_net_protocol ( arphdr->ar_pro );
- if ( ! net_protocol )
+ /* Identify network-layer and link-layer protocols */
+ arp_net_protocol = arp_find_protocol ( arphdr->ar_pro );
+ if ( ! arp_net_protocol )
goto done;
+ net_protocol = arp_net_protocol->net_protocol;
+ ll_protocol = netdev->ll_protocol;
/* Sanity checks */
if ( ( arphdr->ar_hrd != ll_protocol->ll_proto ) ||
}
/* See if we own the target protocol address */
- netdev = find_netdev_by_net_addr ( net_protocol,
- arp_target_pa ( arphdr ) );
- if ( ! netdev )
+ if ( arp_net_protocol->check ( netdev, arp_target_pa ( arphdr ) ) != 0)
goto done;
/* Create new ARP table entry if necessary */
memcpy ( arp_sender_ha ( arphdr ), netdev->ll_addr, arphdr->ar_hln );
/* Send reply */
- net_transmit ( pkb, netdev, &arp_protocol, arp_target_ha (arphdr ) );
+ net_tx ( pkb, netdev, &arp_protocol, arp_target_ha (arphdr ) );
pkb = NULL;
done:
struct net_protocol arp_protocol = {
.name = "ARP",
.net_proto = htons ( ETH_P_ARP ),
- .rx_process = arp_rx,
+ .rx = arp_rx,
.ntoa = arp_ntoa,
};
*
* Prepends the Ethernet link-layer header and transmits the packet.
*/
-static int eth_transmit ( struct pk_buff *pkb, struct net_device *netdev,
- struct net_protocol *net_protocol,
- const void *ll_dest ) {
+static int eth_tx ( struct pk_buff *pkb, struct net_device *netdev,
+ struct net_protocol *net_protocol, const void *ll_dest ) {
struct ethhdr *ethhdr = pkb_push ( pkb, sizeof ( *ethhdr ) );
+ /* Build Ethernet header */
memcpy ( ethhdr->h_dest, ll_dest, ETH_ALEN );
memcpy ( ethhdr->h_source, netdev->ll_addr, ETH_ALEN );
ethhdr->h_protocol = net_protocol->net_proto;
- return netdev_transmit ( netdev, pkb );
+
+ /* Hand off to network device */
+ return netdev_tx ( netdev, pkb );
}
/**
- * Parse Ethernet link-layer header
+ * Process received Ethernet packet
*
* @v pkb Packet buffer
- * @v llhdr Generic link-layer header
+ * @v netdev Network device
*
- * Fills in the generic link-layer header based on information in the
- * Ethernet link-layer header in the packet buffer.
+ * Strips off the Ethernet link-layer header and passes up to the
+ * network-layer protocol.
*/
-static void eth_parse_llh ( const struct pk_buff *pkb,
- struct ll_header *llhdr ) {
+static void eth_rx ( struct pk_buff *pkb, struct net_device *netdev ) {
struct ethhdr *ethhdr = pkb->data;
- memcpy ( llhdr->dest_ll_addr, ethhdr->h_dest, ETH_ALEN );
- memcpy ( llhdr->source_ll_addr, ethhdr->h_source, ETH_ALEN );
- llhdr->net_proto = ethhdr->h_protocol;
-
- if ( memcmp ( ethhdr->h_dest, eth_broadcast, ETH_ALEN ) == 0 ) {
- llhdr->flags = PKT_FL_BROADCAST;
- } else if ( ethhdr->h_dest[0] & 0x01 ) {
- llhdr->flags = PKT_FL_MULTICAST;
- } else {
- llhdr->flags = 0;
+ /* Sanity check */
+ if ( pkb_len ( pkb ) < sizeof ( *ethhdr ) ) {
+ DBG ( "Ethernet packet too short (%d bytes)\n",
+ pkb_len ( pkb ) );
+ return;
}
+
+ /* Strip off Ethernet header */
+ pkb_pull ( pkb, sizeof ( *ethhdr ) );
+
+ /* Hand off to network-layer protocol */
+ net_rx ( pkb, netdev, ethhdr->h_protocol, ethhdr->h_source );
}
/**
.ll_proto = htons ( ARPHRD_ETHER ),
.ll_addr_len = ETH_ALEN,
.ll_broadcast = eth_broadcast,
- .transmit = eth_transmit,
- .parse_llh = eth_parse_llh,
+ .tx = eth_tx,
+ .rx = eth_rx,
.ntoa = eth_ntoa,
};
#include <gpxe/list.h>
#include <gpxe/in.h>
#include <gpxe/arp.h>
-
-#include <ip.h>
-
-
#include <gpxe/if_ether.h>
#include <gpxe/pkbuff.h>
#include <gpxe/netdevice.h>
* @ret rc Return status code
*
*/
-int ipv4_uip_transmit ( struct pk_buff *pkb ) {
+int ipv4_uip_tx ( struct pk_buff *pkb ) {
struct iphdr *iphdr = pkb->data;
struct ipv4_miniroute *miniroute;
struct net_device *netdev = NULL;
}
/* Hand off to link layer */
- return net_transmit ( pkb, netdev, &ipv4_protocol, ll_dest );
+ return net_tx ( pkb, netdev, &ipv4_protocol, ll_dest );
err:
free_pkb ( pkb );
* Process incoming IP packets
*
* @v pkb Packet buffer
+ * @v netdev Network device
+ * @v ll_source Link-layer source address
* @ret rc Return status code
*
* This handles IP packets by handing them off to the uIP protocol
* stack.
*/
-static int ipv4_rx ( struct pk_buff *pkb ) {
+static int ipv4_rx ( struct pk_buff *pkb, struct net_device *netdev __unused,
+ const void *ll_source __unused ) {
/* Transfer to uIP buffer. Horrendously space-inefficient,
* but will do as a proof-of-concept for now.
return -ENOMEM;
pkb_reserve ( pkb, MAX_LL_HEADER_LEN );
memcpy ( pkb_put ( pkb, uip_len ), uip_buf, uip_len );
- ipv4_uip_transmit ( pkb );
+ ipv4_uip_tx ( pkb );
}
return 0;
}
+/**
+ * Check existence of IPv4 address for ARP
+ *
+ * @v netdev Network device
+ * @v net_addr Network-layer address
+ * @ret rc Return status code
+ */
+static int ipv4_arp_check ( struct net_device *netdev, const void *net_addr ) {
+ const struct in_addr *address = net_addr;
+ struct ipv4_miniroute *miniroute;
+
+ list_for_each_entry ( miniroute, &miniroutes, list ) {
+ if ( ( miniroute->netdev == netdev ) &&
+ ( miniroute->address.s_addr == address->s_addr ) ) {
+ /* Found matching address */
+ return 0;
+ }
+ }
+ return -ENOENT;
+}
+
/**
* Convert IPv4 address to dotted-quad notation
*
.name = "IP",
.net_proto = htons ( ETH_P_IP ),
.net_addr_len = sizeof ( struct in_addr ),
- .rx_process = ipv4_rx,
+ .rx = ipv4_rx,
.ntoa = ipv4_ntoa,
};
NET_PROTOCOL ( ipv4_protocol );
-/** IPv4 address for the static single net device */
-struct net_address static_single_ipv4_address = {
+/** IPv4 ARP protocol */
+struct arp_net_protocol ipv4_arp_protocol = {
.net_protocol = &ipv4_protocol,
-
-#warning "Remove this static-IP hack"
- .net_addr = { 0x0a, 0xfe, 0xfe, 0x01 },
+ .check = ipv4_arp_check,
};
-STATIC_SINGLE_NETDEV_ADDRESS ( static_single_ipv4_address );
+ARP_NET_PROTOCOL ( ipv4_arp_protocol );
#include <byteswap.h>
#include <string.h>
#include <errno.h>
+#include <malloc.h>
#include <gpxe/if_ether.h>
#include <gpxe/pkbuff.h>
#include <gpxe/tables.h>
*
*/
-/**
- * Static single instance of a network device
- *
- * The gPXE API is designed to accommodate multiple network devices.
- * However, in the interests of code size, the implementation behind
- * the API supports only a single instance of a network device.
- *
- * No code outside of netdevice.c should ever refer directly to @c
- * static_single_netdev.
- *
- * Callers should always check the return status of alloc_netdev(),
- * register_netdev() etc. In the current implementation this code
- * will be optimised out by the compiler, so there is no penalty.
- */
-struct net_device static_single_netdev;
-
/** Registered network-layer protocols */
static struct net_protocol net_protocols[0] __table_start ( net_protocols );
static struct net_protocol net_protocols_end[0] __table_end ( net_protocols );
-/** Network-layer addresses for @c static_single_netdev */
-static struct net_address static_single_netdev_addresses[0]
- __table_start ( sgl_netdev_addresses );
-static struct net_address static_single_netdev_addresses_end[0]
- __table_end ( sgl_netdev_addresses );
-
-/** Recevied packet queue */
-static LIST_HEAD ( rx_queue );
+/** List of network devices */
+static LIST_HEAD ( net_devices );
#warning "Remove this static IP address hack"
#include <ip.h>
#include <gpxe/ip.h>
/**
- * Register network device
+ * Transmit raw packet via network device
*
* @v netdev Network device
+ * @v pkb Packet buffer
* @ret rc Return status code
*
- * Adds the network device to the list of network devices.
+ * Transmits the packet via the specified network device. This
+ * function takes ownership of the packet buffer.
*/
-int register_netdev ( struct net_device *netdev ) {
-
-#warning "Remove this static IP address hack"
- {
- const struct in_addr static_address = { htonl ( 0x0afefe01 ) };
- const struct in_addr static_netmask = { htonl ( 0xffffff00 ) };
- const struct in_addr static_gateway = { INADDR_NONE };
- int rc;
-
- if ( ( rc = add_ipv4_address ( netdev, static_address,
- static_netmask,
- static_gateway ) ) != 0 )
- return rc;
- }
-
- return 0;
+int netdev_tx ( struct net_device *netdev, struct pk_buff *pkb ) {
+ DBG ( "%s transmitting %p+%zx\n", netdev_name ( netdev ),
+ pkb->data, pkb_len ( pkb ) );
+ return netdev->transmit ( netdev, pkb );
}
/**
- * Unregister network device
+ * Add packet to receive queue
*
* @v netdev Network device
+ * @v pkb Packet buffer
*
- * Removes the network device from the list of network devices.
+ * The packet is added to the network device's RX queue. This
+ * function takes ownership of the packet buffer.
*/
-void unregister_netdev ( struct net_device *netdev ) {
-
-#warning "Remove this static IP address hack"
- del_ipv4_address ( netdev );
-
+void netdev_rx ( struct net_device *netdev, struct pk_buff *pkb ) {
+ DBG ( "%s received %p+%zx\n", netdev_name ( netdev ),
+ pkb->data, pkb_len ( pkb ) );
+ list_add_tail ( &pkb->list, &netdev->rx_queue );
}
/**
- * Add packet to receive queue
+ * Transmit network-layer packet
*
- * @v netdev Network device
* @v pkb Packet buffer
+ * @v netdev Network device
+ * @v net_protocol Network-layer protocol
+ * @v ll_dest Destination link-layer address
+ * @ret rc Return status code
*
- * The packet is added to the RX queue. This function takes ownership
- * of the packet buffer.
+ * Prepends link-layer headers to the packet buffer and transmits the
+ * packet via the specified network device. This function takes
+ * ownership of the packet buffer.
*/
-void netdev_rx ( struct net_device *netdev, struct pk_buff *pkb ) {
- DBG ( "Packet received\n" );
- pkb->ll_protocol = netdev->ll_protocol;
- list_add_tail ( &pkb->list, &rx_queue );
+int net_tx ( struct pk_buff *pkb, struct net_device *netdev,
+ struct net_protocol *net_protocol, const void *ll_dest ) {
+ return netdev->ll_protocol->tx ( pkb, netdev, net_protocol, ll_dest );
}
/**
- * Identify network protocol
+ * Process received network-layer packet
*
+ * @v pkb Packet buffer
+ * @v netdev Network device
* @v net_proto Network-layer protocol, in network-byte order
- * @ret net_protocol Network-layer protocol, or NULL
- *
- * Identify a network-layer protocol from a protocol number, which
- * must be an ETH_P_XXX constant in network-byte order.
+ * @v ll_source Source link-layer address
*/
-struct net_protocol * find_net_protocol ( uint16_t net_proto ) {
+void net_rx ( struct pk_buff *pkb, struct net_device *netdev,
+ uint16_t net_proto, const void *ll_source ) {
struct net_protocol *net_protocol;
+ /* Hand off to network-layer protocol, if any */
for ( net_protocol = net_protocols ; net_protocol < net_protocols_end ;
net_protocol++ ) {
- if ( net_protocol->net_proto == net_proto )
- return net_protocol;
- }
- return NULL;
-}
-
-/**
- * Identify network device by network-layer address
- *
- * @v net_protocol Network-layer protocol
- * @v net_addr Network-layer address
- * @ret netdev Network device, or NULL
- *
- * Searches through all network devices to find the device with the
- * specified network-layer address.
- *
- * Note that even with a static single network device, this function
- * can still return NULL.
- */
-struct net_device *
-find_netdev_by_net_addr ( struct net_protocol *net_protocol,
- void *net_addr ) {
- struct net_address *net_address;
- struct net_device *netdev = &static_single_netdev;
-
- for ( net_address = static_single_netdev_addresses ;
- net_address < static_single_netdev_addresses_end ;
- net_address ++ ) {
- if ( ( net_address->net_protocol == net_protocol ) &&
- ( memcmp ( net_address->net_addr, net_addr,
- net_protocol->net_addr_len ) == 0 ) )
- return netdev;
+ if ( net_protocol->net_proto == net_proto ) {
+ net_protocol->rx ( pkb, netdev, ll_source );
+ break;
+ }
}
-
- return NULL;
}
/**
- * Poll for packet on all network devices
+ * Poll for packet on network device
*
+ * @v netdev Network device
* @ret True There are packets present in the receive queue
* @ret False There are no packets present in the receive queue
*
- * Polls all network devices for received packets. Any received
+ * Polls the network device for received packets. Any received
* packets will be added to the RX packet queue via netdev_rx().
*/
-int net_poll ( void ) {
- struct net_device *netdev = &static_single_netdev;
-
- DBG ( "Polling network\n" );
+int netdev_poll ( struct net_device *netdev ) {
netdev->poll ( netdev );
-
- return ( ! list_empty ( &rx_queue ) );
+ return ( ! list_empty ( &netdev->rx_queue ) );
}
/**
- * Remove packet from receive queue
+ * Remove packet from device's receive queue
*
+ * @v netdev Network device
* @ret pkb Packet buffer, or NULL
*
- * Removes the first packet from the RX queue and returns it.
+ * Removes the first packet from the device's RX queue and returns it.
* Ownership of the packet is transferred to the caller.
*/
-struct pk_buff * net_rx_dequeue ( void ) {
+struct pk_buff * netdev_rx_dequeue ( struct net_device *netdev ) {
struct pk_buff *pkb;
- list_for_each_entry ( pkb, &rx_queue, list ) {
+ list_for_each_entry ( pkb, &netdev->rx_queue, list ) {
list_del ( &pkb->list );
return pkb;
}
}
/**
- * Process received packet
+ * Allocate network device
*
- * @v pkb Packet buffer
- * @ret rc Return status code
+ * @v priv_size Size of private data area (net_device::priv)
+ * @ret netdev Network device, or NULL
*
- * Processes a packet received from the network (and, usually, removed
- * from the RX queue by net_rx_dequeue()). This call takes ownership
- * of the packet buffer.
+ * Allocates space for a network device and its private data area.
*/
-int net_rx_process ( struct pk_buff *pkb ) {
- struct ll_protocol *ll_protocol;
- struct ll_header llhdr;
- struct net_protocol *net_protocol;
- int rc;
+struct net_device * alloc_netdev ( size_t priv_size ) {
+ struct net_device *netdev;
- /* Parse link-layer header */
- ll_protocol = pkb->ll_protocol;
- ll_protocol->parse_llh ( pkb, &llhdr );
-
- /* Identify network-layer protocol */
- net_protocol = find_net_protocol ( llhdr.net_proto );
- if ( ! net_protocol ) {
- DBG ( "Unknown network-layer protocol %x\n",
- ntohs ( llhdr.net_proto ) );
- free_pkb ( pkb );
- return -EPROTONOSUPPORT;
+ netdev = calloc ( 1, sizeof ( *netdev ) + priv_size );
+ if ( netdev ) {
+ INIT_LIST_HEAD ( &netdev->rx_queue );
+ netdev->priv = ( ( ( void * ) netdev ) + sizeof ( *netdev ) );
}
- pkb->net_protocol = net_protocol;
-
- /* Strip off link-layer header */
-#warning "Temporary hack"
- pkb_pull ( pkb, ETH_HLEN );
+ return netdev;
+}
+
+/**
+ * Register network device
+ *
+ * @v netdev Network device
+ * @ret rc Return status code
+ *
+ * Adds the network device to the list of network devices.
+ */
+int register_netdev ( struct net_device *netdev ) {
- /* Hand off to network layer */
- if ( ( rc = net_protocol->rx_process ( pkb ) ) != 0 ) {
- DBG ( "Network-layer protocol dropped packet\n" );
- return rc;
+#warning "Remove this static IP address hack"
+ {
+ const struct in_addr static_address = { htonl ( 0x0afefe01 ) };
+ const struct in_addr static_netmask = { htonl ( 0xffffff00 ) };
+ const struct in_addr static_gateway = { INADDR_NONE };
+ int rc;
+
+ if ( ( rc = add_ipv4_address ( netdev, static_address,
+ static_netmask,
+ static_gateway ) ) != 0 )
+ return rc;
}
+ /* Add to device list */
+ list_add_tail ( &netdev->list, &net_devices );
+ DBG ( "%s registered\n", netdev_name ( netdev ) );
+
return 0;
}
+/**
+ * Unregister network device
+ *
+ * @v netdev Network device
+ *
+ * Removes the network device from the list of network devices.
+ */
+void unregister_netdev ( struct net_device *netdev ) {
+ struct pk_buff *pkb;
+
+#warning "Remove this static IP address hack"
+ del_ipv4_address ( netdev );
+
+ /* Discard any packets in the RX queue */
+ while ( ( pkb = netdev_rx_dequeue ( netdev ) ) ) {
+ DBG ( "%s discarding %p+%zx\n", netdev_name ( netdev ),
+ pkb->data, pkb_len ( pkb ) );
+ free_pkb ( pkb );
+ }
+
+ /* Remove from device list */
+ list_del ( &netdev->list );
+ DBG ( "%s unregistered\n", netdev_name ( netdev ) );
+}
+
+/**
+ * Free network device
+ *
+ * @v netdev Network device
+ */
+void free_netdev ( struct net_device *netdev ) {
+ free ( netdev );
+}
+
+/**
+ * Iterate through network devices
+ *
+ * @ret netdev Network device, or NULL
+ *
+ * This returns the registered network devices in the order of
+ * registration. If no network devices are registered, it will return
+ * NULL.
+ */
+struct net_device * next_netdev ( void ) {
+ struct net_device *netdev;
+
+ list_for_each_entry ( netdev, &net_devices, list ) {
+ list_del ( &netdev->list );
+ list_add_tail ( &netdev->list, &net_devices );
+ return netdev;
+ }
+ return NULL;
+}
+
/**
* Single-step the network stack
*
* multiple packets are processed per poll.
*/
static void net_step ( struct process *process ) {
+ struct net_device *netdev;
struct pk_buff *pkb;
- /* Poll for new packets */
- net_poll();
+ /* Poll and process each network device */
+ list_for_each_entry ( netdev, &net_devices, list ) {
+
+ /* Poll for new packets */
+ netdev_poll ( netdev );
- /* Handle at most one received packet */
- if ( ( pkb = net_rx_dequeue () ) ) {
- net_rx_process ( pkb );
- DBG ( "Processed received packet\n" );
+ /* Handle at most one received packet per poll */
+ if ( ( pkb = netdev_rx_dequeue ( netdev ) ) ) {
+ DBG ( "%s processing %p+%zx\n", netdev_name ( netdev ),
+ pkb->data, pkb_len ( pkb ) );
+ netdev->ll_protocol->rx ( pkb, netdev );
+ }
}
/* Re-schedule ourself */
pkb_put ( pkb, uip_len );
memcpy ( pkb->data, uip_buf, uip_len );
- ipv4_uip_transmit ( pkb );
+ ipv4_uip_tx ( pkb );
}
}
}