diff --git a/src/include/gpxe/netdevice.h b/src/include/gpxe/netdevice.h index 6db95bbb6..1879bf1ba 100644 --- a/src/include/gpxe/netdevice.h +++ b/src/include/gpxe/netdevice.h @@ -103,15 +103,14 @@ struct net_protocol { int ( * route ) ( const struct pk_buff *pkb, struct net_header *nethdr ); /** - * Handle received packets + * Process received packet * * @v pkb Packet buffer * @ret rc Return status code * - * If this method returns success, it has taken ownership of - * the packet buffer. + * This method takes ownership of the packet buffer. */ - int ( * rx ) ( struct pk_buff *pkb ); + int ( * rx_process ) ( struct pk_buff *pkb ); /** * Transcribe network-layer address * @@ -240,9 +239,9 @@ struct net_device { * This method should cause the hardware to initiate * transmission of the packet buffer. * - * If the method returns success, ownership of the packet - * buffer is transferred to the @c net_device, which must - * eventually call free_pkb() to release the buffer. + * Ownership of the packet buffer is transferred to the @c + * net_device, which must eventually call free_pkb() to + * release the buffer. */ int ( * transmit ) ( struct net_device *netdev, struct pk_buff *pkb ); /** Poll for received packet @@ -332,9 +331,8 @@ free_netdev ( struct net_device *netdev __attribute__ (( unused )) ) { * @ret rc Return status code * * Transmits the packet via the specified network device. The - * link-layer header must already have been filled in. If this - * function returns success, it has taken ownership of the packet - * buffer. + * 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 ) { @@ -375,5 +373,6 @@ extern int net_transmit_via ( struct pk_buff *pkb, struct net_device *netdev ); extern int net_transmit ( struct pk_buff *pkb ); extern int net_poll ( void ); extern struct pk_buff * net_rx_dequeue ( void ); +extern int net_rx_process ( struct pk_buff *pkb ); #endif /* _GPXE_NETDEVICE_H */ diff --git a/src/net/arp.c b/src/net/arp.c index 3720acfc4..af7d6e122 100644 --- a/src/net/arp.c +++ b/src/net/arp.c @@ -154,10 +154,8 @@ int arp_resolve ( struct net_device *netdev, const struct net_header *nethdr, nethdr->dest_net_addr, net_protocol->net_addr_len ); /* Transmit ARP request */ - if ( ( rc = net_transmit_via ( pkb, netdev ) ) != 0 ) { - free_pkb ( pkb ); + if ( ( rc = net_transmit_via ( pkb, netdev ) ) != 0 ) return rc; - } return -ENOENT; } @@ -230,7 +228,7 @@ static int arp_rx ( struct pk_buff *pkb ) { if ( arphdr->ar_op != htons ( ARPOP_REQUEST ) ) goto done; - /* Change request to a reply, and send it */ + /* Change request to a reply */ DBG ( "ARP reply: %s %s => %s %s\n", net_protocol->name, net_protocol->ntoa ( arp_target_pa ( arphdr ) ), ll_protocol->name, ll_protocol->ntoa ( netdev->ll_addr ) ); @@ -238,8 +236,10 @@ static int arp_rx ( struct pk_buff *pkb ) { memswap ( arp_sender_ha ( arphdr ), arp_target_ha ( arphdr ), arphdr->ar_hln + arphdr->ar_pln ); memcpy ( arp_target_ha ( arphdr ), netdev->ll_addr, arphdr->ar_hln ); - if ( net_transmit_via ( pkb, netdev ) == 0 ) - pkb = NULL; + + /* Send reply */ + net_transmit_via ( pkb, netdev ); + pkb = NULL; done: free_pkb ( pkb ); @@ -286,7 +286,7 @@ arp_ntoa ( const void *net_addr __attribute__ (( unused )) ) { struct net_protocol arp_protocol = { .name = "ARP", .net_proto = htons ( ETH_P_ARP ), - .rx = arp_rx, + .rx_process = arp_rx, .route = arp_route, .ntoa = arp_ntoa, }; diff --git a/src/net/ipv4.c b/src/net/ipv4.c index 2fc506728..ecb44a2f9 100644 --- a/src/net/ipv4.c +++ b/src/net/ipv4.c @@ -163,8 +163,7 @@ static int ipv4_rx ( struct pk_buff *pkb ) { pkb_empty ( pkb ); pkb_put ( pkb, uip_len ); memcpy ( pkb->data, uip_buf, uip_len ); - if ( net_transmit ( pkb ) != 0 ) - free_pkb ( pkb ); + net_transmit ( pkb ); } else { free_pkb ( pkb ); } @@ -231,7 +230,7 @@ struct net_protocol ipv4_protocol = { .name = "IP", .net_proto = htons ( ETH_P_IP ), .net_addr_len = sizeof ( struct in_addr ), - .rx = ipv4_rx, + .rx_process = ipv4_rx, .route = ipv4_route, .ntoa = ipv4_ntoa, }; diff --git a/src/net/netdevice.c b/src/net/netdevice.c index 59861d05d..19db792e6 100644 --- a/src/net/netdevice.c +++ b/src/net/netdevice.c @@ -23,6 +23,7 @@ #include #include #include +#include #include /** @file @@ -66,9 +67,8 @@ static LIST_HEAD ( rx_queue ); * @v netdev Network device * @v pkb Packet buffer * - * The packet is added to the RX queue. Ownership of the packet is - * transferred to the RX queue; the caller must not touch the packet - * buffer after calling netdev_rx(). + * The packet is added to the RX queue. This function takes ownership + * of the packet buffer. */ void netdev_rx ( struct net_device *netdev, struct pk_buff *pkb ) { DBG ( "Packet received\n" ); @@ -137,9 +137,8 @@ find_netdev_by_net_addr ( struct net_protocol *net_protocol, * Transmits the packet via the specified network device. The packet * must begin with a network-layer header, and the @c net_protocol * field must have been filled in. If @c netdev is NULL, the network - * device is identified via the packet contents, if possible. If this - * function returns success, it has taken ownership of the packet - * buffer. + * device is identified via the packet contents, if possible. This + * function takes ownership of the packet buffer. */ int net_transmit_via ( struct pk_buff *pkb, struct net_device *netdev ) { struct net_protocol *net_protocol; @@ -155,6 +154,7 @@ int net_transmit_via ( struct pk_buff *pkb, struct net_device *netdev ) { DBG ( "Could not route to %s address %s\n", net_protocol->name, net_protocol->ntoa ( nethdr.dest_net_addr ) ); + free_pkb ( pkb ); return rc; } @@ -166,6 +166,7 @@ int net_transmit_via ( struct pk_buff *pkb, struct net_device *netdev ) { DBG ( "No network device for %s address %s\n", net_protocol->name, net_protocol->ntoa ( nethdr.source_net_addr ) ); + free_pkb ( pkb ); return -EHOSTUNREACH; } } @@ -177,6 +178,7 @@ int net_transmit_via ( struct pk_buff *pkb, struct net_device *netdev ) { DBG ( "No link-layer route to %s address %s\n", net_protocol->name, net_protocol->ntoa ( nethdr.dest_net_addr ) ); + free_pkb ( pkb ); return rc; } @@ -184,7 +186,7 @@ int net_transmit_via ( struct pk_buff *pkb, struct net_device *netdev ) { pkb_push ( pkb, ll_protocol->ll_header_len ); ll_protocol->fill_llh ( &llhdr, pkb ); - /* Transmit packet */ + /* Hand off packet to network device */ if ( ( rc = netdev->transmit ( netdev, pkb ) ) != 0 ) { DBG ( "Device failed to transmit packet\n" ); return rc; @@ -200,9 +202,8 @@ int net_transmit_via ( struct pk_buff *pkb, struct net_device *netdev ) { * @v pkb Packet buffer * @ret rc Return status code * - * Transmits the packet via the appropriate network device. If this - * function returns success, it has taken ownership of the packet - * buffer. + * Transmits the packet via the appropriate network device. This + * function takes ownership of the packet buffer. */ int net_transmit ( struct pk_buff *pkb ) { return net_transmit_via ( pkb, NULL ); @@ -244,41 +245,83 @@ struct pk_buff * net_rx_dequeue ( void ) { return NULL; } -void net_run ( void ) { - struct pk_buff *pkb; +/** + * Process received packet + * + * @v pkb Packet buffer + * @ret rc Return status code + * + * 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. + */ +int net_rx_process ( struct pk_buff *pkb ) { struct ll_protocol *ll_protocol; struct ll_header llhdr; struct net_protocol *net_protocol; + int rc; - while ( ( pkb = net_rx_dequeue () ) ) { - - /* 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 ); - continue; - } - pkb->net_protocol = net_protocol; - - /* Strip off link-layer header */ - pkb_pull ( pkb, ll_protocol->ll_header_len ); - - /* Hand off to network layer */ - if ( net_protocol->rx ( pkb ) != 0 ) { - DBG ( "Network-layer protocol refused packet\n" ); - free_pkb ( pkb ); - continue; - } - - DBG ( "Processed received packet\n" ); + /* 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; } + pkb->net_protocol = net_protocol; + + /* Strip off link-layer header */ + pkb_pull ( pkb, ll_protocol->ll_header_len ); + + /* Hand off to network layer */ + if ( ( rc = net_protocol->rx_process ( pkb ) ) != 0 ) { + DBG ( "Network-layer protocol dropped packet\n" ); + return rc; + } + + return 0; } +/** + * Single-step the network stack + * + * @v process Network stack process + * + * This polls all interfaces for any received packets, and processes + * any packets that are received during this poll. + */ +static void net_step ( struct process *process ) { + struct pk_buff *pkb; + + /* Poll for new packets */ + net_poll(); + + /* Handle any received packets */ + while ( ( pkb = net_rx_dequeue () ) ) { + net_rx_process ( pkb ); + DBG ( "Processed received packet\n" ); + } + + /* Re-schedule ourself */ + schedule ( process ); +} + +/** Networking stack process */ +static struct process net_process = { + .step = net_step, +}; + +static void init_net ( void ) { + schedule ( &net_process ); +} + +#include + +INIT_FN ( INIT_RPC, init_net, NULL, NULL );