summaryrefslogtreecommitdiff
path: root/gpxe/src/net/ipv4.c
diff options
context:
space:
mode:
authorH. Peter Anvin <hpa@zytor.com>2016-02-09 18:08:47 -0800
committerH. Peter Anvin <hpa@zytor.com>2016-02-09 18:08:47 -0800
commitf2f897a1762fab84d2905f32b1c15dd7b42abb56 (patch)
treea38f51d3f1fcbf44afddb4736d549c12eaf491be /gpxe/src/net/ipv4.c
parent72d2959272b4616f17a97667e6dfa9d06bf109a3 (diff)
downloadsyslinux-f2f897a1762fab84d2905f32b1c15dd7b42abb56.tar.gz
gpxe: delete long since obsolete snapshot of gPXE
gPXE has been deprecated in favor of iPXE for many, many years now. It is much better than users get it directly from the iPXE project, since we should no longer need any special modifications for Syslinux use. Signed-off-by: H. Peter Anvin <hpa@zytor.com>
Diffstat (limited to 'gpxe/src/net/ipv4.c')
-rw-r--r--gpxe/src/net/ipv4.c635
1 files changed, 0 insertions, 635 deletions
diff --git a/gpxe/src/net/ipv4.c b/gpxe/src/net/ipv4.c
deleted file mode 100644
index 4c1393f2..00000000
--- a/gpxe/src/net/ipv4.c
+++ /dev/null
@@ -1,635 +0,0 @@
-#include <string.h>
-#include <stdint.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <errno.h>
-#include <byteswap.h>
-#include <gpxe/list.h>
-#include <gpxe/in.h>
-#include <gpxe/arp.h>
-#include <gpxe/if_ether.h>
-#include <gpxe/iobuf.h>
-#include <gpxe/netdevice.h>
-#include <gpxe/ip.h>
-#include <gpxe/tcpip.h>
-#include <gpxe/dhcp.h>
-#include <gpxe/settings.h>
-
-/** @file
- *
- * IPv4 protocol
- *
- */
-
-FILE_LICENCE ( GPL2_OR_LATER );
-
-/* Unique IP datagram identification number */
-static uint16_t next_ident = 0;
-
-struct net_protocol ipv4_protocol;
-
-/** List of IPv4 miniroutes */
-struct list_head ipv4_miniroutes = LIST_HEAD_INIT ( ipv4_miniroutes );
-
-/** List of fragment reassembly buffers */
-static LIST_HEAD ( frag_buffers );
-
-/**
- * Add IPv4 minirouting table entry
- *
- * @v netdev Network device
- * @v address IPv4 address
- * @v netmask Subnet mask
- * @v gateway Gateway address (if any)
- * @ret miniroute Routing table entry, or NULL
- */
-static struct ipv4_miniroute * __malloc
-add_ipv4_miniroute ( struct net_device *netdev, struct in_addr address,
- struct in_addr netmask, struct in_addr gateway ) {
- struct ipv4_miniroute *miniroute;
-
- DBG ( "IPv4 add %s", inet_ntoa ( address ) );
- DBG ( "/%s ", inet_ntoa ( netmask ) );
- if ( gateway.s_addr )
- DBG ( "gw %s ", inet_ntoa ( gateway ) );
- DBG ( "via %s\n", netdev->name );
-
- /* Allocate and populate miniroute structure */
- miniroute = malloc ( sizeof ( *miniroute ) );
- if ( ! miniroute ) {
- DBG ( "IPv4 could not add miniroute\n" );
- return NULL;
- }
-
- /* Record routing information */
- miniroute->netdev = netdev_get ( netdev );
- miniroute->address = address;
- miniroute->netmask = netmask;
- miniroute->gateway = gateway;
-
- /* Add to end of list if we have a gateway, otherwise
- * to start of list.
- */
- if ( gateway.s_addr ) {
- list_add_tail ( &miniroute->list, &ipv4_miniroutes );
- } else {
- list_add ( &miniroute->list, &ipv4_miniroutes );
- }
-
- return miniroute;
-}
-
-/**
- * Delete IPv4 minirouting table entry
- *
- * @v miniroute Routing table entry
- */
-static void del_ipv4_miniroute ( struct ipv4_miniroute *miniroute ) {
-
- DBG ( "IPv4 del %s", inet_ntoa ( miniroute->address ) );
- DBG ( "/%s ", inet_ntoa ( miniroute->netmask ) );
- if ( miniroute->gateway.s_addr )
- DBG ( "gw %s ", inet_ntoa ( miniroute->gateway ) );
- DBG ( "via %s\n", miniroute->netdev->name );
-
- netdev_put ( miniroute->netdev );
- list_del ( &miniroute->list );
- free ( miniroute );
-}
-
-/**
- * Perform IPv4 routing
- *
- * @v dest Final destination address
- * @ret dest Next hop destination address
- * @ret miniroute Routing table entry to use, or NULL if no route
- *
- * If the route requires use of a gateway, the next hop destination
- * address will be overwritten with the gateway address.
- */
-static struct ipv4_miniroute * ipv4_route ( struct in_addr *dest ) {
- struct ipv4_miniroute *miniroute;
- int local;
- int has_gw;
-
- /* Never attempt to route the broadcast address */
- if ( dest->s_addr == INADDR_BROADCAST )
- return NULL;
-
- /* Find first usable route in routing table */
- list_for_each_entry ( miniroute, &ipv4_miniroutes, list ) {
- if ( ! ( miniroute->netdev->state & NETDEV_OPEN ) )
- continue;
- local = ( ( ( dest->s_addr ^ miniroute->address.s_addr )
- & miniroute->netmask.s_addr ) == 0 );
- has_gw = ( miniroute->gateway.s_addr );
- if ( local || has_gw ) {
- if ( ! local )
- *dest = miniroute->gateway;
- return miniroute;
- }
- }
-
- return NULL;
-}
-
-/**
- * Fragment reassembly counter timeout
- *
- * @v timer Retry timer
- * @v over If asserted, the timer is greater than @c MAX_TIMEOUT
- */
-static void ipv4_frag_expired ( struct retry_timer *timer __unused,
- int over ) {
- if ( over ) {
- DBG ( "Fragment reassembly timeout" );
- /* Free the fragment buffer */
- }
-}
-
-/**
- * Free fragment buffer
- *
- * @v fragbug Fragment buffer
- */
-static void free_fragbuf ( struct frag_buffer *fragbuf ) {
- free ( fragbuf );
-}
-
-/**
- * Fragment reassembler
- *
- * @v iobuf I/O buffer, fragment of the datagram
- * @ret frag_iob Reassembled packet, or NULL
- */
-static struct io_buffer * ipv4_reassemble ( struct io_buffer * iobuf ) {
- struct iphdr *iphdr = iobuf->data;
- struct frag_buffer *fragbuf;
-
- /**
- * Check if the fragment belongs to any fragment series
- */
- list_for_each_entry ( fragbuf, &frag_buffers, list ) {
- if ( fragbuf->ident == iphdr->ident &&
- fragbuf->src.s_addr == iphdr->src.s_addr ) {
- /**
- * Check if the packet is the expected fragment
- *
- * The offset of the new packet must be equal to the
- * length of the data accumulated so far (the length of
- * the reassembled I/O buffer
- */
- if ( iob_len ( fragbuf->frag_iob ) ==
- ( iphdr->frags & IP_MASK_OFFSET ) ) {
- /**
- * Append the contents of the fragment to the
- * reassembled I/O buffer
- */
- iob_pull ( iobuf, sizeof ( *iphdr ) );
- memcpy ( iob_put ( fragbuf->frag_iob,
- iob_len ( iobuf ) ),
- iobuf->data, iob_len ( iobuf ) );
- free_iob ( iobuf );
-
- /** Check if the fragment series is over */
- if ( ! ( iphdr->frags & IP_MASK_MOREFRAGS ) ) {
- iobuf = fragbuf->frag_iob;
- free_fragbuf ( fragbuf );
- return iobuf;
- }
-
- } else {
- /* Discard the fragment series */
- free_fragbuf ( fragbuf );
- free_iob ( iobuf );
- }
- return NULL;
- }
- }
-
- /** Check if the fragment is the first in the fragment series */
- if ( iphdr->frags & IP_MASK_MOREFRAGS &&
- ( ( iphdr->frags & IP_MASK_OFFSET ) == 0 ) ) {
-
- /** Create a new fragment buffer */
- fragbuf = ( struct frag_buffer* ) malloc ( sizeof( *fragbuf ) );
- fragbuf->ident = iphdr->ident;
- fragbuf->src = iphdr->src;
-
- /* Set up the reassembly I/O buffer */
- fragbuf->frag_iob = alloc_iob ( IP_FRAG_IOB_SIZE );
- iob_pull ( iobuf, sizeof ( *iphdr ) );
- memcpy ( iob_put ( fragbuf->frag_iob, iob_len ( iobuf ) ),
- iobuf->data, iob_len ( iobuf ) );
- free_iob ( iobuf );
-
- /* Set the reassembly timer */
- fragbuf->frag_timer.timeout = IP_FRAG_TIMEOUT;
- fragbuf->frag_timer.expired = ipv4_frag_expired;
- start_timer ( &fragbuf->frag_timer );
-
- /* Add the fragment buffer to the list of fragment buffers */
- list_add ( &fragbuf->list, &frag_buffers );
- }
-
- return NULL;
-}
-
-/**
- * Add IPv4 pseudo-header checksum to existing checksum
- *
- * @v iobuf I/O buffer
- * @v csum Existing checksum
- * @ret csum Updated checksum
- */
-static uint16_t ipv4_pshdr_chksum ( struct io_buffer *iobuf, uint16_t csum ) {
- struct ipv4_pseudo_header pshdr;
- struct iphdr *iphdr = iobuf->data;
- size_t hdrlen = ( ( iphdr->verhdrlen & IP_MASK_HLEN ) * 4 );
-
- /* Build pseudo-header */
- pshdr.src = iphdr->src;
- pshdr.dest = iphdr->dest;
- pshdr.zero_padding = 0x00;
- pshdr.protocol = iphdr->protocol;
- pshdr.len = htons ( iob_len ( iobuf ) - hdrlen );
-
- /* Update the checksum value */
- return tcpip_continue_chksum ( csum, &pshdr, sizeof ( pshdr ) );
-}
-
-/**
- * Determine link-layer address
- *
- * @v dest IPv4 destination address
- * @v src IPv4 source address
- * @v netdev Network device
- * @v ll_dest Link-layer destination address buffer
- * @ret rc Return status code
- */
-static int ipv4_ll_addr ( struct in_addr dest, struct in_addr src,
- struct net_device *netdev, uint8_t *ll_dest ) {
- struct ll_protocol *ll_protocol = netdev->ll_protocol;
-
- if ( dest.s_addr == INADDR_BROADCAST ) {
- /* Broadcast address */
- memcpy ( ll_dest, netdev->ll_broadcast,
- ll_protocol->ll_addr_len );
- return 0;
- } else if ( IN_MULTICAST ( ntohl ( dest.s_addr ) ) ) {
- return ll_protocol->mc_hash ( AF_INET, &dest, ll_dest );
- } else {
- /* Unicast address: resolve via ARP */
- return arp_resolve ( netdev, &ipv4_protocol, &dest,
- &src, ll_dest );
- }
-}
-
-/**
- * Transmit IP packet
- *
- * @v iobuf I/O buffer
- * @v tcpip Transport-layer protocol
- * @v st_src Source network-layer address
- * @v st_dest Destination network-layer address
- * @v netdev Network device to use if no route found, or NULL
- * @v trans_csum Transport-layer checksum to complete, or NULL
- * @ret rc Status
- *
- * This function expects a transport-layer segment and prepends the IP header
- */
-static int ipv4_tx ( struct io_buffer *iobuf,
- struct tcpip_protocol *tcpip_protocol,
- struct sockaddr_tcpip *st_src,
- struct sockaddr_tcpip *st_dest,
- struct net_device *netdev,
- uint16_t *trans_csum ) {
- struct iphdr *iphdr = iob_push ( iobuf, sizeof ( *iphdr ) );
- struct sockaddr_in *sin_src = ( ( struct sockaddr_in * ) st_src );
- struct sockaddr_in *sin_dest = ( ( struct sockaddr_in * ) st_dest );
- struct ipv4_miniroute *miniroute;
- struct in_addr next_hop;
- uint8_t ll_dest[MAX_LL_ADDR_LEN];
- int rc;
-
- /* Fill up the IP header, except source address */
- memset ( iphdr, 0, sizeof ( *iphdr ) );
- iphdr->verhdrlen = ( IP_VER | ( sizeof ( *iphdr ) / 4 ) );
- iphdr->service = IP_TOS;
- iphdr->len = htons ( iob_len ( iobuf ) );
- iphdr->ident = htons ( ++next_ident );
- iphdr->ttl = IP_TTL;
- iphdr->protocol = tcpip_protocol->tcpip_proto;
- iphdr->dest = sin_dest->sin_addr;
-
- /* Use routing table to identify next hop and transmitting netdev */
- next_hop = iphdr->dest;
- if ( sin_src )
- iphdr->src = sin_src->sin_addr;
- if ( ( next_hop.s_addr != INADDR_BROADCAST ) &&
- ( ! IN_MULTICAST ( ntohl ( next_hop.s_addr ) ) ) &&
- ( ( miniroute = ipv4_route ( &next_hop ) ) != NULL ) ) {
- iphdr->src = miniroute->address;
- netdev = miniroute->netdev;
- }
- if ( ! netdev ) {
- DBG ( "IPv4 has no route to %s\n", inet_ntoa ( iphdr->dest ) );
- rc = -ENETUNREACH;
- goto err;
- }
-
- /* Determine link-layer destination address */
- if ( ( rc = ipv4_ll_addr ( next_hop, iphdr->src, netdev,
- ll_dest ) ) != 0 ) {
- DBG ( "IPv4 has no link-layer address for %s: %s\n",
- inet_ntoa ( next_hop ), strerror ( rc ) );
- goto err;
- }
-
- /* Fix up checksums */
- if ( trans_csum )
- *trans_csum = ipv4_pshdr_chksum ( iobuf, *trans_csum );
- iphdr->chksum = tcpip_chksum ( iphdr, sizeof ( *iphdr ) );
-
- /* Print IP4 header for debugging */
- DBG ( "IPv4 TX %s->", inet_ntoa ( iphdr->src ) );
- DBG ( "%s len %d proto %d id %04x csum %04x\n",
- inet_ntoa ( iphdr->dest ), ntohs ( iphdr->len ), iphdr->protocol,
- ntohs ( iphdr->ident ), ntohs ( iphdr->chksum ) );
-
- /* Hand off to link layer */
- if ( ( rc = net_tx ( iobuf, netdev, &ipv4_protocol, ll_dest ) ) != 0 ) {
- DBG ( "IPv4 could not transmit packet via %s: %s\n",
- netdev->name, strerror ( rc ) );
- return rc;
- }
-
- return 0;
-
- err:
- free_iob ( iobuf );
- return rc;
-}
-
-/**
- * Process incoming packets
- *
- * @v iobuf I/O buffer
- * @v netdev Network device
- * @v ll_source Link-layer destination source
- *
- * This function expects an IP4 network datagram. It processes the headers
- * and sends it to the transport layer.
- */
-static int ipv4_rx ( struct io_buffer *iobuf, struct net_device *netdev __unused,
- const void *ll_source __unused ) {
- struct iphdr *iphdr = iobuf->data;
- size_t hdrlen;
- size_t len;
- union {
- struct sockaddr_in sin;
- struct sockaddr_tcpip st;
- } src, dest;
- uint16_t csum;
- uint16_t pshdr_csum;
- int rc;
-
- /* Sanity check the IPv4 header */
- if ( iob_len ( iobuf ) < sizeof ( *iphdr ) ) {
- DBG ( "IPv4 packet too short at %zd bytes (min %zd bytes)\n",
- iob_len ( iobuf ), sizeof ( *iphdr ) );
- goto err;
- }
- if ( ( iphdr->verhdrlen & IP_MASK_VER ) != IP_VER ) {
- DBG ( "IPv4 version %#02x not supported\n", iphdr->verhdrlen );
- goto err;
- }
- hdrlen = ( ( iphdr->verhdrlen & IP_MASK_HLEN ) * 4 );
- if ( hdrlen < sizeof ( *iphdr ) ) {
- DBG ( "IPv4 header too short at %zd bytes (min %zd bytes)\n",
- hdrlen, sizeof ( *iphdr ) );
- goto err;
- }
- if ( hdrlen > iob_len ( iobuf ) ) {
- DBG ( "IPv4 header too long at %zd bytes "
- "(packet is %zd bytes)\n", hdrlen, iob_len ( iobuf ) );
- goto err;
- }
- if ( ( csum = tcpip_chksum ( iphdr, hdrlen ) ) != 0 ) {
- DBG ( "IPv4 checksum incorrect (is %04x including checksum "
- "field, should be 0000)\n", csum );
- goto err;
- }
- len = ntohs ( iphdr->len );
- if ( len < hdrlen ) {
- DBG ( "IPv4 length too short at %zd bytes "
- "(header is %zd bytes)\n", len, hdrlen );
- goto err;
- }
- if ( len > iob_len ( iobuf ) ) {
- DBG ( "IPv4 length too long at %zd bytes "
- "(packet is %zd bytes)\n", len, iob_len ( iobuf ) );
- goto err;
- }
-
- /* Print IPv4 header for debugging */
- DBG ( "IPv4 RX %s<-", inet_ntoa ( iphdr->dest ) );
- DBG ( "%s len %d proto %d id %04x csum %04x\n",
- inet_ntoa ( iphdr->src ), ntohs ( iphdr->len ), iphdr->protocol,
- ntohs ( iphdr->ident ), ntohs ( iphdr->chksum ) );
-
- /* Truncate packet to correct length, calculate pseudo-header
- * checksum and then strip off the IPv4 header.
- */
- iob_unput ( iobuf, ( iob_len ( iobuf ) - len ) );
- pshdr_csum = ipv4_pshdr_chksum ( iobuf, TCPIP_EMPTY_CSUM );
- iob_pull ( iobuf, hdrlen );
-
- /* Fragment reassembly */
- if ( ( iphdr->frags & htons ( IP_MASK_MOREFRAGS ) ) ||
- ( ( iphdr->frags & htons ( IP_MASK_OFFSET ) ) != 0 ) ) {
- /* Pass the fragment to ipv4_reassemble() which either
- * returns a fully reassembled I/O buffer or NULL.
- */
- iobuf = ipv4_reassemble ( iobuf );
- if ( ! iobuf )
- return 0;
- }
-
- /* Construct socket addresses and hand off to transport layer */
- memset ( &src, 0, sizeof ( src ) );
- src.sin.sin_family = AF_INET;
- src.sin.sin_addr = iphdr->src;
- memset ( &dest, 0, sizeof ( dest ) );
- dest.sin.sin_family = AF_INET;
- dest.sin.sin_addr = iphdr->dest;
- if ( ( rc = tcpip_rx ( iobuf, iphdr->protocol, &src.st,
- &dest.st, pshdr_csum ) ) != 0 ) {
- DBG ( "IPv4 received packet rejected by stack: %s\n",
- strerror ( rc ) );
- return rc;
- }
-
- return 0;
-
- err:
- free_iob ( iobuf );
- return -EINVAL;
-}
-
-/**
- * Check existence of IPv4 address for ARP
- *
- * @v netdev Network device
- * @v net_addr Network-layer address
- * @ret rc Return status code
- */
-static int ipv4_arp_check ( struct net_device *netdev, const void *net_addr ) {
- const struct in_addr *address = net_addr;
- struct ipv4_miniroute *miniroute;
-
- list_for_each_entry ( miniroute, &ipv4_miniroutes, list ) {
- if ( ( miniroute->netdev == netdev ) &&
- ( miniroute->address.s_addr == address->s_addr ) ) {
- /* Found matching address */
- return 0;
- }
- }
- return -ENOENT;
-}
-
-/**
- * Convert IPv4 address to dotted-quad notation
- *
- * @v in IP address
- * @ret string IP address in dotted-quad notation
- */
-char * inet_ntoa ( struct in_addr in ) {
- static char buf[16]; /* "xxx.xxx.xxx.xxx" */
- uint8_t *bytes = ( uint8_t * ) &in;
-
- sprintf ( buf, "%d.%d.%d.%d", bytes[0], bytes[1], bytes[2], bytes[3] );
- return buf;
-}
-
-/**
- * Transcribe IP address
- *
- * @v net_addr IP address
- * @ret string IP address in dotted-quad notation
- *
- */
-static const char * ipv4_ntoa ( const void *net_addr ) {
- return inet_ntoa ( * ( ( struct in_addr * ) net_addr ) );
-}
-
-/** IPv4 protocol */
-struct net_protocol ipv4_protocol __net_protocol = {
- .name = "IP",
- .net_proto = htons ( ETH_P_IP ),
- .net_addr_len = sizeof ( struct in_addr ),
- .rx = ipv4_rx,
- .ntoa = ipv4_ntoa,
-};
-
-/** IPv4 TCPIP net protocol */
-struct tcpip_net_protocol ipv4_tcpip_protocol __tcpip_net_protocol = {
- .name = "IPv4",
- .sa_family = AF_INET,
- .tx = ipv4_tx,
-};
-
-/** IPv4 ARP protocol */
-struct arp_net_protocol ipv4_arp_protocol __arp_net_protocol = {
- .net_protocol = &ipv4_protocol,
- .check = ipv4_arp_check,
-};
-
-/******************************************************************************
- *
- * Settings
- *
- ******************************************************************************
- */
-
-/** IPv4 address setting */
-struct setting ip_setting __setting = {
- .name = "ip",
- .description = "IPv4 address",
- .tag = DHCP_EB_YIADDR,
- .type = &setting_type_ipv4,
-};
-
-/** IPv4 subnet mask setting */
-struct setting netmask_setting __setting = {
- .name = "netmask",
- .description = "IPv4 subnet mask",
- .tag = DHCP_SUBNET_MASK,
- .type = &setting_type_ipv4,
-};
-
-/** Default gateway setting */
-struct setting gateway_setting __setting = {
- .name = "gateway",
- .description = "Default gateway",
- .tag = DHCP_ROUTERS,
- .type = &setting_type_ipv4,
-};
-
-/**
- * Create IPv4 routing table based on configured settings
- *
- * @ret rc Return status code
- */
-static int ipv4_create_routes ( void ) {
- struct ipv4_miniroute *miniroute;
- struct ipv4_miniroute *tmp;
- struct net_device *netdev;
- struct settings *settings;
- struct in_addr address = { 0 };
- struct in_addr netmask = { 0 };
- struct in_addr gateway = { 0 };
-
- /* Delete all existing routes */
- list_for_each_entry_safe ( miniroute, tmp, &ipv4_miniroutes, list )
- del_ipv4_miniroute ( miniroute );
-
- /* Create a route for each configured network device */
- for_each_netdev ( netdev ) {
- settings = netdev_settings ( netdev );
- /* Get IPv4 address */
- address.s_addr = 0;
- fetch_ipv4_setting ( settings, &ip_setting, &address );
- if ( ! address.s_addr )
- continue;
- /* Get subnet mask */
- fetch_ipv4_setting ( settings, &netmask_setting, &netmask );
- /* Calculate default netmask, if necessary */
- if ( ! netmask.s_addr ) {
- if ( IN_CLASSA ( ntohl ( address.s_addr ) ) ) {
- netmask.s_addr = htonl ( IN_CLASSA_NET );
- } else if ( IN_CLASSB ( ntohl ( address.s_addr ) ) ) {
- netmask.s_addr = htonl ( IN_CLASSB_NET );
- } else if ( IN_CLASSC ( ntohl ( address.s_addr ) ) ) {
- netmask.s_addr = htonl ( IN_CLASSC_NET );
- }
- }
- /* Get default gateway, if present */
- fetch_ipv4_setting ( settings, &gateway_setting, &gateway );
- /* Configure route */
- miniroute = add_ipv4_miniroute ( netdev, address,
- netmask, gateway );
- if ( ! miniroute )
- return -ENOMEM;
- }
-
- return 0;
-}
-
-/** IPv4 settings applicator */
-struct settings_applicator ipv4_settings_applicator __settings_applicator = {
- .apply = ipv4_create_routes,
-};
-
-/* Drag in ICMP */
-REQUIRE_OBJECT ( icmp );