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
*
* 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
* @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 ) {
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 */
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;
}
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 ) );
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 );
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,
};
#include <gpxe/if_ether.h>
#include <gpxe/pkbuff.h>
#include <gpxe/tables.h>
+#include <gpxe/process.h>
#include <gpxe/netdevice.h>
/** @file
* @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" );
* 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;
DBG ( "Could not route to %s address %s\n",
net_protocol->name,
net_protocol->ntoa ( nethdr.dest_net_addr ) );
+ free_pkb ( pkb );
return rc;
}
DBG ( "No network device for %s address %s\n",
net_protocol->name,
net_protocol->ntoa ( nethdr.source_net_addr ) );
+ free_pkb ( pkb );
return -EHOSTUNREACH;
}
}
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;
}
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;
* @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 );
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 );
+ 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;
+ }
- /* Parse link-layer header */
- ll_protocol = pkb->ll_protocol;
- ll_protocol->parse_llh ( pkb, &llhdr );
+ return 0;
+}
- /* 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;
- }
+/**
+ * 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.h>
+INIT_FN ( INIT_RPC, init_net, NULL, NULL );