diff options
| author | Michael Brown | 2006-04-24 17:38:53 +0200 |
|---|---|---|
| committer | Michael Brown | 2006-04-24 17:38:53 +0200 |
| commit | 53f78346bf65c7080da1c750c7590cc343d55726 (patch) | |
| tree | e279237d8081272a0a9ca749a845c04093e17a13 /src/net | |
| parent | Network API now allows for multiple network devices (although the (diff) | |
| download | ipxe-53f78346bf65c7080da1c750c7590cc343d55726.tar.gz ipxe-53f78346bf65c7080da1c750c7590cc343d55726.tar.xz ipxe-53f78346bf65c7080da1c750c7590cc343d55726.zip | |
Network API now allows for multiple network devices (although the
implementation allows for only one, and does so without compromising on
the efficiency of static allocation).
Link-layer protocols are cleanly separated from the device drivers.
Network-layer protocols are cleanly separated from individual network
devices.
Link-layer and network-layer protocols are cleanly separated from each
other.
Diffstat (limited to 'src/net')
| -rw-r--r-- | src/net/ipv4.c | 226 | ||||
| -rw-r--r-- | src/net/pkbuff.c | 65 |
2 files changed, 291 insertions, 0 deletions
diff --git a/src/net/ipv4.c b/src/net/ipv4.c new file mode 100644 index 000000000..4200d234c --- /dev/null +++ b/src/net/ipv4.c @@ -0,0 +1,226 @@ +#include <string.h> +#include <stdint.h> +#include <byteswap.h> +#include <gpxe/in.h> + + +#include <ip.h> + + +#include <gpxe/if_ether.h> +#include <gpxe/pkbuff.h> +#include <gpxe/netdevice.h> +#include "../proto/uip/uip.h" + +/** @file + * + * IPv4 protocol + * + * The gPXE IP stack is currently implemented on top of the uIP + * protocol stack. This file provides wrappers around uIP so that + * higher-level protocol implementations do not need to talk directly + * to uIP (which has a somewhat baroque API). + * + */ + +/** An IPv4 routing table entry */ +struct ipv4_route { + /** Network address */ + struct in_addr network; + /** Subnet mask */ + struct in_addr netmask; + /** Gateway address */ + struct in_addr gateway; + /** Gateway device */ + struct in_addr gatewaydev; +}; + +enum { + STATIC_SINGLE_NETDEV_ROUTE = 0, + DEFAULT_ROUTE, + NUM_ROUTES +}; + +/** IPv4 routing table */ +static struct ipv4_route routing_table[NUM_ROUTES]; + +#define routing_table_end ( routing_table + NUM_ROUTES ) + +#if 0 +/** + * Set IP address + * + */ +void set_ipaddr ( struct in_addr address ) { + union { + struct in_addr address; + uint16_t uip_address[2]; + } u; + + u.address = address; + uip_sethostaddr ( u.uip_address ); +} + +/** + * Set netmask + * + */ +void set_netmask ( struct in_addr address ) { + union { + struct in_addr address; + uint16_t uip_address[2]; + } u; + + u.address = address; + uip_setnetmask ( u.uip_address ); +} + +/** + * Set default gateway + * + */ +void set_gateway ( struct in_addr address ) { + union { + struct in_addr address; + uint16_t uip_address[2]; + } u; + + u.address = address; + uip_setdraddr ( u.uip_address ); +} + +/** + * Run the TCP/IP stack + * + * Call this function in a loop in order to allow TCP/IP processing to + * take place. This call takes the stack through a single iteration; + * it will typically be used in a loop such as + * + * @code + * + * struct tcp_connection *my_connection; + * ... + * tcp_connect ( my_connection ); + * while ( ! my_connection->finished ) { + * run_tcpip(); + * } + * + * @endcode + * + * where @c my_connection->finished is set by one of the connection's + * #tcp_operations methods to indicate completion. + */ +void run_tcpip ( void ) { + void *data; + size_t len; + uint16_t type; + int i; + + if ( netdev_poll ( 1, &data, &len ) ) { + /* We have data */ + memcpy ( uip_buf, data, len ); + uip_len = len; + type = ntohs ( *( ( uint16_t * ) ( uip_buf + 12 ) ) ); + if ( type == UIP_ETHTYPE_ARP ) { + uip_arp_arpin(); + } else { + uip_arp_ipin(); + uip_input(); + } + if ( uip_len > 0 ) + uip_transmit(); + } else { + for ( i = 0 ; i < UIP_CONNS ; i++ ) { + uip_periodic ( i ); + if ( uip_len > 0 ) + uip_transmit(); + } + } +} +#endif + +/** + * Process incoming IP packets + * + * @v pkb Packet buffer + * @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 ) { + + /* Transfer to uIP buffer. Horrendously space-inefficient, + * but will do as a proof-of-concept for now. + */ + memcpy ( uip_buf, pkb->data, pkb_len ( pkb ) ); + + /* Hand to uIP for processing */ + uip_input (); + if ( uip_len > 0 ) { + pkb_empty ( pkb ); + pkb_put ( pkb, uip_len ); + memcpy ( pkb->data, uip_buf, uip_len ); + if ( net_transmit ( pkb ) != 0 ) + free_pkb ( pkb ); + } else { + free_pkb ( pkb ); + } + return 0; +} + +/** + * Perform IP layer routing + * + * @v pkb Packet buffer + * @ret source Network-layer source address + * @ret dest Network-layer destination address + * @ret rc Return status code + */ +static int ipv4_route ( const struct pk_buff *pkb, + struct net_header *nethdr ) { + struct iphdr *iphdr = pkb->data; + struct in_addr *source = ( struct in_addr * ) nethdr->source_net_addr; + struct in_addr *dest = ( struct in_addr * ) nethdr->dest_net_addr; + struct ipv4_route *route; + + /* Route IP packet according to routing table */ + source->s_addr = INADDR_NONE; + dest->s_addr = iphdr->dest.s_addr; + for ( route = routing_table ; route < routing_table_end ; route++ ) { + if ( ( dest->s_addr & route->netmask.s_addr ) + == route->network.s_addr ) { + source->s_addr = route->gatewaydev.s_addr; + if ( route->gateway.s_addr ) + dest->s_addr = route->gateway.s_addr; + break; + } + } + + /* Set broadcast and multicast flags as applicable */ + nethdr->dest_flags = 0; + if ( dest->s_addr == htonl ( INADDR_BROADCAST ) ) { + nethdr->dest_flags = NETADDR_FL_BROADCAST; + } else if ( IN_MULTICAST ( dest->s_addr ) ) { + nethdr->dest_flags = NETADDR_FL_MULTICAST; + } + + return 0; +} + +/** IPv4 protocol */ +struct net_protocol ipv4_protocol = { + .net_proto = ETH_P_IP, + .net_addr_len = sizeof ( struct in_addr ), + .rx = ipv4_rx, + .route = ipv4_route, +}; + +NET_PROTOCOL ( ipv4_protocol ); + +/** IPv4 address for the static single net device */ +struct net_address static_single_ipv4_address = { + .net_protocol = &ipv4_protocol, +}; + +STATIC_SINGLE_NETDEV_ADDRESS ( static_single_ipv4_address ); diff --git a/src/net/pkbuff.c b/src/net/pkbuff.c new file mode 100644 index 000000000..ec09ab1be --- /dev/null +++ b/src/net/pkbuff.c @@ -0,0 +1,65 @@ +/* + * Copyright (C) 2006 Michael Brown <mbrown@fensystems.co.uk>. + * + * 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 <stdint.h> +#include <gpxe/malloc.h> +#include <gpxe/pkbuff.h> + +/** @file + * + * Packet buffers + * + */ + +/** + * Allocate packet buffer + * + * @v len Required length of buffer + * @ret pkb Packet buffer, or NULL if none available + * + * The packet buffer will be aligned as per gmalloc(). + */ +struct pk_buff * alloc_pkb ( size_t len ) { + struct pk_buff *pkb = NULL; + void *data; + + /* Align buffer length */ + len = ( len + __alignof__ ( *pkb ) - 1 ) & ~ __alignof__ ( *pkb ); + + /* Allocate memory for buffer plus descriptor */ + data = gmalloc ( len + sizeof ( *pkb ) ); + if ( ! data ) + return NULL; + + pkb = ( struct pk_buff * ) ( data + len ); + pkb->head = pkb->data = pkb->tail = data; + pkb->end = pkb; + return pkb; +} + +/** + * Free packet buffer + * + * @v pkb Packet buffer + */ +void free_pkb ( struct pk_buff *pkb ) { + if ( pkb ) { + gfree ( pkb->head, + ( pkb->end - pkb->head ) + sizeof ( *pkb ) ); + } +} |
