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/ipv4.c | |
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/ipv4.c')
-rw-r--r-- | src/net/ipv4.c | 226 |
1 files changed, 226 insertions, 0 deletions
diff --git a/src/net/ipv4.c b/src/net/ipv4.c new file mode 100644 index 00000000..4200d234 --- /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 ); |