From 6209bd873a075f01d43d58c67068a215d27c2d45 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Wed, 19 Apr 2006 12:07:46 +0000 Subject: [PATCH] First sketch of a new net device API. --- src/include/errno.h | 1 + src/include/gpxe/if_ether.h | 11 +-- src/include/gpxe/netdevice.h | 46 +++++----- src/net/netdevice.c | 163 +++++++++++++++++++++++++++++++++++ 4 files changed, 196 insertions(+), 25 deletions(-) create mode 100644 src/net/netdevice.c diff --git a/src/include/errno.h b/src/include/errno.h index 5df13451..f96231be 100644 --- a/src/include/errno.h +++ b/src/include/errno.h @@ -124,6 +124,7 @@ #define EINVAL 0xd3 #define ENOENT 0xd4 #define EAFNOSUPPORT 0xd5 +#define EAGAIN 0xd6 /* Data structures and declarations */ diff --git a/src/include/gpxe/if_ether.h b/src/include/gpxe/if_ether.h index 7f0abacb..f199220f 100644 --- a/src/include/gpxe/if_ether.h +++ b/src/include/gpxe/if_ether.h @@ -12,11 +12,12 @@ #define ETH_MAX_MTU (ETH_FRAME_LEN-ETH_HLEN) #endif -#define ETH_P_IP 0x0800 /* Internet Protocl Packet */ -#define ETH_P_ARP 0x0806 /* Address Resolution Protocol */ -#define ETH_P_RARP 0x8035 /* Reverse Address resolution Protocol */ -#define ETH_P_IPV6 0x86DD /* IPv6 over blueblook */ -#define ETH_P_SLOW 0x8809 /* Ethernet slow protocols */ +#define ETH_P_RAW 0x0000 /* Raw packet */ +#define ETH_P_IP 0x0800 /* Internet Protocl Packet */ +#define ETH_P_ARP 0x0806 /* Address Resolution Protocol */ +#define ETH_P_RARP 0x8035 /* Reverse Address resolution Protocol */ +#define ETH_P_IPV6 0x86DD /* IPv6 over blueblook */ +#define ETH_P_SLOW 0x8809 /* Ethernet slow protocols */ /** An Ethernet link-layer header */ struct ethhdr { diff --git a/src/include/gpxe/netdevice.h b/src/include/gpxe/netdevice.h index 7517c3e7..93a98634 100644 --- a/src/include/gpxe/netdevice.h +++ b/src/include/gpxe/netdevice.h @@ -100,6 +100,8 @@ struct net_device { * For Ethernet, this is the MAC address. */ uint8_t ll_addr[MAX_LLH_ADDR_LEN]; + /** Linked list of network devices */ + struct list_head devices; /** List of network interfaces */ struct list_head interfaces; /** Driver private data */ @@ -117,7 +119,7 @@ struct net_interface { /** Underlying net device */ struct net_device *netdev; /** Linked list of interfaces for this device */ - struct list_head list; + struct list_head interfaces; /** Network-layer protocol * * This is an ETH_P_XXX constant, in network byte order. @@ -127,21 +129,6 @@ struct net_interface { uint8_t net_addr_len; /** Network-layer address */ uint8_t net_addr[MAX_NET_ADDR_LEN]; - /** Packet processor - * - * @v netif Network interface - * @v pkb Packet buffer - * @ret rc Return status code - * - * This method is called for packets arriving on the - * associated network device that match this interface's - * network-layer protocol. - * - * When this method is called, the link-layer header will - * already have been stripped from the packet. - */ - int ( * process ) ( struct net_interface *netif, - struct pk_buff *pkb ); /** Fill in packet metadata * * @v netif Network interface @@ -154,6 +141,21 @@ struct net_interface { */ int ( * add_llh_metadata ) ( struct net_interface *netif, struct pk_buff *pkb ); + /** Received packet processor + * + * @v netif Network interface + * @v pkb Packet buffer + * @ret rc Return status code + * + * This method is called for packets arriving on the + * associated network device that match this interface's + * network-layer protocol. + * + * When this method is called, the link-layer header will + * already have been stripped from the packet. + */ + int ( * rx_packet ) ( struct net_interface *netif, + struct pk_buff *pkb ); }; /** @@ -168,15 +170,22 @@ static inline struct net_interface * netdev_find_netif ( const struct net_device *netdev, uint16_t net_proto ) { struct net_interface *netif; - list_for_each_entry ( netif, &netdev->interfaces, list ) { + list_for_each_entry ( netif, &netdev->interfaces, interfaces ) { if ( netif->net_proto == net_proto ) return netif; } return NULL; } +extern int register_netdevice ( struct net_device *netdev ); +extern void unregister_netdevice ( struct net_device *netdev ); extern int netdev_send ( struct net_device *netdev, struct pk_buff *pkb ); +extern int netdev_poll ( struct net_device *netdev, struct pk_buff *pkb ); extern int netif_send ( struct net_interface *netif, struct pk_buff *pkb ); +extern int netdev_rx_packet ( struct net_device *netdev, struct pk_buff *pkb ); +extern int net_poll ( struct pk_buff *pkb, struct net_device **netdev ); + + extern struct net_device static_single_netdev; @@ -186,9 +195,6 @@ extern struct net_device static_single_netdev; static_single_netdev.priv = priv_data; \ &static_single_netdev; } ) -extern int register_netdevice ( struct net_device *netdev ); - -extern void unregister_netdevice ( struct net_device *netdev ); static inline void free_netdevice ( struct net_device *netdev __unused ) { /* Do nothing */ diff --git a/src/net/netdevice.c b/src/net/netdevice.c new file mode 100644 index 00000000..d7ad3080 --- /dev/null +++ b/src/net/netdevice.c @@ -0,0 +1,163 @@ +/* + * Copyright (C) 2006 Michael Brown . + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include +#include +#include + +/** @file + * + * Network devices and network interfaces + * + */ + +/** List of all registered network devices */ +static LIST_HEAD ( net_devices ); + +/** + * Register network device + * + * @v netdev Network device + * @ret rc Return status code + * + * Adds the network device to the list of network devices. + */ +int register_netdevice ( struct net_device *netdev ) { + list_add ( &netdev->devices, &net_devices ); + return 0; +} + +/** + * Unregister network device + * + * @v netdev Network device + * + * Removes the network device from the list of network devices. + */ +void unregister_netdevice ( struct net_device *netdev ) { + list_del ( &netdev->devices ); +} + +/** + * Transmit packet via network device + * + * @v netdev Network device + * @v pkb Packet buffer + * @ret rc Return status code + * + * Transmits the packet via the network device. The @c pkb link-layer + * metadata must already have been filled in, and space for the + * link-layer header must already be present in the packet buffer. + */ +int netdev_send ( struct net_device *netdev, struct pk_buff *pkb ) { + int rc; + + if ( pkb->net_proto != ETH_P_RAW ) { + if ( ( rc = netdev->build_llh ( netdev, pkb ) ) != 0 ) + return rc; + } + return netdev->transmit ( netdev, pkb ); +} + +/** + * Poll for packet on network device + * + * @v netdev Network device + * @v pkb Packet buffer + * @ret rc Return status code + * + * Polls the network device for a packet. If a packet is available, + * it will be added to the packet buffer, and the link-layer metadata + * fields in @c pkb will be filled in. + */ +int netdev_poll ( struct net_device *netdev, struct pk_buff *pkb ) { + int rc; + + if ( ( rc = netdev->poll ( netdev, pkb ) ) != 0 ) + return rc; + return netdev->parse_llh ( netdev, pkb ); +} + +/** + * Transmit packet via network interface + * + * @v netif Network interface + * @v pkb Packet buffer + * @ret rc Return status code + * + * Transmits the packet via the network interface. The packet must + * start with a network-layer header (e.g. an IP header, for an IP + * interface). The packet contents are undefined on return. + */ +int netif_send ( struct net_interface *netif, struct pk_buff *pkb ) { + struct net_device *netdev = netif->netdev; + int rc; + + if ( ( rc = netif->add_llh_metadata ( netif, pkb ) ) != 0 ) + return rc; + pkb_push ( pkb, netdev->ll_hlen ); + return netdev_send ( netdev, pkb ); +} + +/** + * Process received packet + * + * @v netif Network interface + * @v pkb Packet buffer + * @ret rc Return status code + * + * Processes a packet received via netdev_poll(). The interface + * corresponding to the network-layer protocol is identified, the + * link-layer header is stripped from the packet and the packet is + * passed to the net_interface::rx_packet() method. + */ +int netdev_rx_packet ( struct net_device *netdev, struct pk_buff *pkb ) { + struct net_interface *netif; + + netif = netdev_find_netif ( netdev, pkb->net_proto ); + if ( ! netif ) + return -EAFNOSUPPORT; + + pkb_pull ( pkb, netdev->ll_hlen ); + return netif->rx_packet ( netif, pkb ); +} + +/** + * Poll for packet on all network devices + * + * @v pkb Packet buffer + * @ret netdev Network device + * @ret rc Return status code + * + * Polls all network devices for a packet. If a packet is available + * on any interface, @c netdev will be filled in and the packet will + * be received as per netdev_poll(). + */ +int net_poll ( struct pk_buff *pkb, struct net_device **netdev ) { + int rc; + + list_for_each_entry ( (*netdev), &net_devices, devices ) { + if ( ( rc = netdev_poll ( *netdev, pkb ) ) == 0 ) + return rc; + } + + return -EAGAIN; +}