iPXE
Functions | Variables
ipv4.c File Reference

IPv4 protocol. More...

#include <string.h>
#include <stdint.h>
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <byteswap.h>
#include <ipxe/list.h>
#include <ipxe/in.h>
#include <ipxe/arp.h>
#include <ipxe/if_ether.h>
#include <ipxe/iobuf.h>
#include <ipxe/netdevice.h>
#include <ipxe/ip.h>
#include <ipxe/tcpip.h>
#include <ipxe/dhcp.h>
#include <ipxe/settings.h>
#include <ipxe/fragment.h>
#include <ipxe/ipstat.h>
#include <ipxe/profile.h>

Go to the source code of this file.

Functions

 FILE_LICENCE (GPL2_OR_LATER_OR_UBDL)
struct ip_statistics_family
ipv4_stats_family 
__ip_statistics_family (IP_STATISTICS_IPV4)
 IPv4 statistics family.
static int add_ipv4_miniroute (struct net_device *netdev, struct in_addr address, struct in_addr netmask, struct in_addr gateway)
 Add IPv4 minirouting table entry.
static void del_ipv4_miniroute (struct ipv4_miniroute *miniroute)
 Delete IPv4 minirouting table entry.
static struct ipv4_minirouteipv4_route (unsigned int scope_id, struct in_addr *dest)
 Perform IPv4 routing.
static struct net_deviceipv4_netdev (struct sockaddr_tcpip *st_dest)
 Determine transmitting network device.
static int ipv4_is_fragment (struct fragment *fragment, struct io_buffer *iobuf, size_t hdrlen __unused)
 Check if IPv4 fragment matches fragment reassembly buffer.
static size_t ipv4_fragment_offset (struct io_buffer *iobuf, size_t hdrlen __unused)
 Get IPv4 fragment offset.
static int ipv4_more_fragments (struct io_buffer *iobuf, size_t hdrlen __unused)
 Check if more fragments exist.
static uint16_t ipv4_pshdr_chksum (struct io_buffer *iobuf, uint16_t csum)
 Add IPv4 pseudo-header checksum to existing checksum.
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)
 Transmit IP packet.
int ipv4_has_any_addr (struct net_device *netdev)
 Check if network device has any IPv4 address.
static int ipv4_has_addr (struct net_device *netdev, struct in_addr addr)
 Check if network device has a specific IPv4 address.
static int ipv4_rx (struct io_buffer *iobuf, struct net_device *netdev, const void *ll_dest __unused, const void *ll_source __unused, unsigned int flags)
 Process incoming packets.
static int ipv4_arp_check (struct net_device *netdev, const void *net_addr)
 Check existence of IPv4 address for ARP.
int inet_aton (const char *string, struct in_addr *in)
 Parse IPv4 address.
char * inet_ntoa (struct in_addr in)
 Convert IPv4 address to dotted-quad notation.
static const char * ipv4_ntoa (const void *net_addr)
 Transcribe IPv4 address.
static const char * ipv4_sock_ntoa (struct sockaddr *sa)
 Transcribe IPv4 socket address.
static int ipv4_sock_aton (const char *string, struct sockaddr *sa)
 Parse IPv4 socket address.
int parse_ipv4_setting (const struct setting_type *type __unused, const char *value, void *buf, size_t len)
 Parse IPv4 address setting value.
int format_ipv4_setting (const struct setting_type *type __unused, const void *raw, size_t raw_len, char *buf, size_t len)
 Format IPv4 address setting value.
struct setting ip_setting __setting (SETTING_IP4, ip)
 IPv4 address setting.
struct setting netmask_setting __setting (SETTING_IP4, netmask)
 IPv4 subnet mask setting.
struct setting gateway_setting __setting (SETTING_IP4, gateway)
 Default gateway setting.
static int ipv4_gratuitous_arp (struct net_device *netdev, struct in_addr address, struct in_addr netmask __unused, struct in_addr gateway __unused)
 Send gratuitous ARP, if applicable.
static int ipv4_settings (int(*apply)(struct net_device *netdev, struct in_addr address, struct in_addr netmask, struct in_addr gateway))
 Process IPv4 network device settings.
static int ipv4_create_routes (void)
 Create IPv4 routing table based on configured settings.
 REQUIRING_SYMBOL (ipv4_protocol)
 REQUIRE_OBJECT (icmpv4)

Variables

static uint8_t next_ident_high = 0
struct list_head ipv4_miniroutes = LIST_HEAD_INIT ( ipv4_miniroutes )
 List of IPv4 miniroutes.
static struct ip_statistics ipv4_stats
 IPv4 statistics.
static struct profiler
ipv4_tx_profiler 
__profiler = { .name = "ipv4.tx" }
 Transmit profiler.
static struct fragment_reassembler ipv4_reassembler
 IPv4 fragment reassembler.
struct net_protocol ipv4_protocol __net_protocol
 IPv4 protocol.
struct tcpip_net_protocol
ipv4_tcpip_protocol 
__tcpip_net_protocol
 IPv4 TCPIP net protocol.
struct arp_net_protocol
ipv4_arp_protocol 
__arp_net_protocol
 IPv4 ARP protocol.
struct sockaddr_converter
ipv4_sockaddr_converter 
__sockaddr_converter
 IPv4 socket address converter.
struct settings_applicator
ipv4_settings_applicator 
__settings_applicator
 IPv4 settings applicator.

Detailed Description

IPv4 protocol.

Definition in file ipv4.c.


Function Documentation

FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL  )
struct ip_statistics_family ipv4_stats_family __ip_statistics_family ( IP_STATISTICS_IPV4  ) [read]

IPv4 statistics family.

static int add_ipv4_miniroute ( struct net_device netdev,
struct in_addr  address,
struct in_addr  netmask,
struct in_addr  gateway 
) [static]

Add IPv4 minirouting table entry.

Parameters:
netdevNetwork device
addressIPv4 address
netmaskSubnet mask
gatewayGateway address (if any)
Return values:
rcReturn status code

Definition at line 84 of file ipv4.c.

References ipv4_miniroute::address, address, DBGC, ENOMEM, ipv4_miniroute::gateway, inet_ntoa(), ipv4_miniroute::list, list_add, list_add_tail, malloc(), net_device::name, ipv4_miniroute::netdev, netdev_get(), ipv4_miniroute::netmask, and in_addr::s_addr.

Referenced by ipv4_create_routes().

                                                         {
        struct ipv4_miniroute *miniroute;

        DBGC ( netdev, "IPv4 add %s", inet_ntoa ( address ) );
        DBGC ( netdev, "/%s ", inet_ntoa ( netmask ) );
        if ( gateway.s_addr )
                DBGC ( netdev, "gw %s ", inet_ntoa ( gateway ) );
        DBGC ( netdev, "via %s\n", netdev->name );

        /* Allocate and populate miniroute structure */
        miniroute = malloc ( sizeof ( *miniroute ) );
        if ( ! miniroute ) {
                DBGC ( netdev, "IPv4 could not add miniroute\n" );
                return -ENOMEM;
        }

        /* 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 0;
}
static void del_ipv4_miniroute ( struct ipv4_miniroute miniroute) [static]

Delete IPv4 minirouting table entry.

Parameters:
minirouteRouting table entry

Definition at line 125 of file ipv4.c.

References ipv4_miniroute::address, DBGC, free, ipv4_miniroute::gateway, inet_ntoa(), ipv4_miniroute::list, list_del, net_device::name, netdev, ipv4_miniroute::netdev, netdev_put(), ipv4_miniroute::netmask, and in_addr::s_addr.

Referenced by ipv4_create_routes().

                                                                    {
        struct net_device *netdev = miniroute->netdev;

        DBGC ( netdev, "IPv4 del %s", inet_ntoa ( miniroute->address ) );
        DBGC ( netdev, "/%s ", inet_ntoa ( miniroute->netmask ) );
        if ( miniroute->gateway.s_addr )
                DBGC ( netdev, "gw %s ", inet_ntoa ( miniroute->gateway ) );
        DBGC ( netdev, "via %s\n", miniroute->netdev->name );

        netdev_put ( miniroute->netdev );
        list_del ( &miniroute->list );
        free ( miniroute );
}
static struct ipv4_miniroute* ipv4_route ( unsigned int  scope_id,
struct in_addr dest 
) [static, read]

Perform IPv4 routing.

Parameters:
scope_idDestination address scope ID
destFinal destination address
Return values:
destNext hop destination address
minirouteRouting 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.

Definition at line 150 of file ipv4.c.

References ipv4_miniroute::address, ipv4_miniroute::gateway, IN_IS_MULTICAST, net_device::index, ipv4_miniroute::list, list_for_each_entry, ipv4_miniroute::netdev, netdev_is_open(), ipv4_miniroute::netmask, NULL, and in_addr::s_addr.

Referenced by ipv4_netdev(), and ipv4_tx().

                                                                   {
        struct ipv4_miniroute *miniroute;

        /* Find first usable route in routing table */
        list_for_each_entry ( miniroute, &ipv4_miniroutes, list ) {

                /* Skip closed network devices */
                if ( ! netdev_is_open ( miniroute->netdev ) )
                        continue;

                if ( IN_IS_MULTICAST ( dest->s_addr ) ) {

                        /* If destination is non-global, and the scope ID
                         * matches this network device, then use this route.
                         */
                        if ( miniroute->netdev->index == scope_id )
                                return miniroute;

                } else {

                        /* If destination is an on-link global
                         * address, then use this route.
                         */
                        if ( ( ( dest->s_addr ^ miniroute->address.s_addr )
                               & miniroute->netmask.s_addr ) == 0 )
                                return miniroute;

                        /* If destination is an off-link global
                         * address, and we have a default gateway,
                         * then use this route.
                         */
                        if ( miniroute->gateway.s_addr ) {
                                *dest = miniroute->gateway;
                                return miniroute;
                        }
                }
        }

        return NULL;
}
static struct net_device* ipv4_netdev ( struct sockaddr_tcpip st_dest) [static, read]

Determine transmitting network device.

Parameters:
st_destDestination network-layer address
Return values:
netdevTransmitting network device, or NULL

Definition at line 198 of file ipv4.c.

References ipv4_route(), ipv4_miniroute::netdev, NULL, sockaddr_in::sin_addr, and sockaddr_in::sin_scope_id.

                                                                          {
        struct sockaddr_in *sin_dest = ( ( struct sockaddr_in * ) st_dest );
        struct in_addr dest = sin_dest->sin_addr;
        struct ipv4_miniroute *miniroute;

        /* Find routing table entry */
        miniroute = ipv4_route ( sin_dest->sin_scope_id, &dest );
        if ( ! miniroute )
                return NULL;

        return miniroute->netdev;
}
static int ipv4_is_fragment ( struct fragment fragment,
struct io_buffer iobuf,
size_t hdrlen  __unused 
) [static]

Check if IPv4 fragment matches fragment reassembly buffer.

Parameters:
fragmentFragment reassembly buffer
iobufI/O buffer
hdrlenLength of non-fragmentable potion of I/O buffer
Return values:
is_fragmentFragment matches this reassembly buffer

Definition at line 219 of file ipv4.c.

References io_buffer::data, iphdr::ident, fragment::iobuf, in_addr::s_addr, and iphdr::src.

                                                       {
        struct iphdr *frag_iphdr = fragment->iobuf->data;
        struct iphdr *iphdr = iobuf->data;

        return ( ( iphdr->src.s_addr == frag_iphdr->src.s_addr ) &&
                 ( iphdr->ident == frag_iphdr->ident ) );
}
static size_t ipv4_fragment_offset ( struct io_buffer iobuf,
size_t hdrlen  __unused 
) [static]

Get IPv4 fragment offset.

Parameters:
iobufI/O buffer
hdrlenLength of non-fragmentable potion of I/O buffer
Return values:
offsetOffset

Definition at line 236 of file ipv4.c.

References io_buffer::data, iphdr::frags, IP_MASK_OFFSET, and ntohs.

                                                              {
        struct iphdr *iphdr = iobuf->data;

        return ( ( ntohs ( iphdr->frags ) & IP_MASK_OFFSET ) << 3 );
}
static int ipv4_more_fragments ( struct io_buffer iobuf,
size_t hdrlen  __unused 
) [static]

Check if more fragments exist.

Parameters:
iobufI/O buffer
hdrlenLength of non-fragmentable potion of I/O buffer
Return values:
more_fragsMore fragments exist

Definition at line 250 of file ipv4.c.

References io_buffer::data, iphdr::frags, htons, and IP_MASK_MOREFRAGS.

                                                          {
        struct iphdr *iphdr = iobuf->data;

        return ( iphdr->frags & htons ( IP_MASK_MOREFRAGS ) );
}
static uint16_t ipv4_pshdr_chksum ( struct io_buffer iobuf,
uint16_t  csum 
) [static]

Add IPv4 pseudo-header checksum to existing checksum.

Parameters:
iobufI/O buffer
csumExisting checksum
Return values:
csumUpdated checksum

Definition at line 273 of file ipv4.c.

References io_buffer::data, iphdr::dest, ipv4_pseudo_header::dest, htons, iob_len(), IP_MASK_HLEN, ipv4_pseudo_header::len, iphdr::protocol, ipv4_pseudo_header::protocol, iphdr::src, ipv4_pseudo_header::src, tcpip_continue_chksum(), iphdr::verhdrlen, and ipv4_pseudo_header::zero_padding.

Referenced by ipv4_rx(), and ipv4_tx().

                                                                             {
        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 ) );
}
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 
) [static]

Transmit IP packet.

Parameters:
iobufI/O buffer
tcpipTransport-layer protocol
st_srcSource network-layer address
st_destDestination network-layer address
netdevNetwork device to use if no route found, or NULL
trans_csumTransport-layer checksum to complete, or NULL
Return values:
rcStatus

This function expects a transport-layer segment and prepends the IP header

Definition at line 302 of file ipv4.c.

References ipv4_miniroute::address, AF_INET, arp_tx(), net_device_stats::bad, iphdr::chksum, DBGC, DBGC2, iphdr::dest, ENETUNREACH, free_iob(), net_device_stats::good, htons, iphdr::ident, IN_IS_MULTICAST, INADDR_BROADCAST, inet_ntoa(), iob_len(), iob_push, IP_TOS, IP_TTL, IP_VER, ipv4_pshdr_chksum(), ipv4_route(), ipv4_stats, iphdr::len, net_device::ll_addr, net_device::ll_broadcast, net_device::ll_protocol, MAX_LL_ADDR_LEN, ll_protocol::mc_hash, memset(), net_device::name, net_tx(), ipv4_miniroute::netdev, ipv4_miniroute::netmask, next_ident_high, ntohs, NULL, ip_statistics::out_bcast_pkts, ip_statistics::out_mcast_pkts, ip_statistics::out_no_routes, ip_statistics::out_octets, ip_statistics::out_requests, ip_statistics::out_transmits, profile_start(), profile_stop(), iphdr::protocol, rc, net_device::rx_stats, in_addr::s_addr, iphdr::service, sockaddr_in::sin_addr, sockaddr_in::sin_scope_id, iphdr::src, strerror(), tcpip_chksum(), tcpip_protocol::tcpip_proto, iphdr::ttl, iphdr::verhdrlen, and tcpip_protocol::zero_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;
        struct in_addr netmask = { .s_addr = 0 };
        uint8_t ll_dest_buf[MAX_LL_ADDR_LEN];
        const void *ll_dest;
        int rc;

        /* Start profiling */
        profile_start ( &ipv4_tx_profiler );

        /* Update statistics */
        ipv4_stats.out_requests++;

        /* 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->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 ) &&
             ( ( miniroute = ipv4_route ( sin_dest->sin_scope_id,
                                          &next_hop ) ) != NULL ) ) {
                iphdr->src = miniroute->address;
                netmask = miniroute->netmask;
                netdev = miniroute->netdev;
        }
        if ( ! netdev ) {
                DBGC ( sin_dest->sin_addr, "IPv4 has no route to %s\n",
                       inet_ntoa ( iphdr->dest ) );
                ipv4_stats.out_no_routes++;
                rc = -ENETUNREACH;
                goto err;
        }

        /* (Ab)use the "ident" field to convey metadata about the
         * network device statistics into packet traces.  Useful for
         * extracting debug information from non-debug builds.
         */
        iphdr->ident = htons ( ( (++next_ident_high) << 8 ) |
                               ( ( netdev->rx_stats.bad & 0xf ) << 4 ) |
                               ( ( netdev->rx_stats.good & 0xf ) << 0 ) );

        /* Fix up checksums */
        if ( trans_csum ) {
                *trans_csum = ipv4_pshdr_chksum ( iobuf, *trans_csum );
                if ( ! *trans_csum )
                        *trans_csum = tcpip_protocol->zero_csum;
        }
        iphdr->chksum = tcpip_chksum ( iphdr, sizeof ( *iphdr ) );

        /* Print IP4 header for debugging */
        DBGC2 ( sin_dest->sin_addr, "IPv4 TX %s->", inet_ntoa ( iphdr->src ) );
        DBGC2 ( sin_dest->sin_addr, "%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 ) );

        /* Calculate link-layer destination address, if possible */
        if ( ( ( next_hop.s_addr ^ INADDR_BROADCAST ) & ~netmask.s_addr ) == 0){
                /* Broadcast address */
                ipv4_stats.out_bcast_pkts++;
                ll_dest = netdev->ll_broadcast;
        } else if ( IN_IS_MULTICAST ( next_hop.s_addr ) ) {
                /* Multicast address */
                ipv4_stats.out_mcast_pkts++;
                if ( ( rc = netdev->ll_protocol->mc_hash ( AF_INET, &next_hop,
                                                           ll_dest_buf ) ) !=0){
                        DBGC ( sin_dest->sin_addr, "IPv4 could not hash "
                               "multicast %s: %s\n",
                               inet_ntoa ( next_hop ), strerror ( rc ) );
                        goto err;
                }
                ll_dest = ll_dest_buf;
        } else {
                /* Unicast address */
                ll_dest = NULL;
        }

        /* Update statistics */
        ipv4_stats.out_transmits++;
        ipv4_stats.out_octets += iob_len ( iobuf );

        /* Hand off to link layer (via ARP if applicable) */
        if ( ll_dest ) {
                if ( ( rc = net_tx ( iobuf, netdev, &ipv4_protocol, ll_dest,
                                     netdev->ll_addr ) ) != 0 ) {
                        DBGC ( sin_dest->sin_addr, "IPv4 could not transmit "
                               "packet via %s: %s\n",
                               netdev->name, strerror ( rc ) );
                        return rc;
                }
        } else {
                if ( ( rc = arp_tx ( iobuf, netdev, &ipv4_protocol, &next_hop,
                                     &iphdr->src, netdev->ll_addr ) ) != 0 ) {
                        DBGC ( sin_dest->sin_addr, "IPv4 could not transmit "
                               "packet via %s: %s\n",
                               netdev->name, strerror ( rc ) );
                        return rc;
                }
        }

        profile_stop ( &ipv4_tx_profiler );
        return 0;

 err:
        free_iob ( iobuf );
        return rc;
}
int ipv4_has_any_addr ( struct net_device netdev)

Check if network device has any IPv4 address.

Parameters:
netdevNetwork device
Return values:
has_any_addrNetwork device has any IPv4 address

Definition at line 433 of file ipv4.c.

References ipv4_miniroute::list, list_for_each_entry, and ipv4_miniroute::netdev.

Referenced by dhcp_create_packet(), and ipv4_rx().

                                                    {
        struct ipv4_miniroute *miniroute;

        list_for_each_entry ( miniroute, &ipv4_miniroutes, list ) {
                if ( miniroute->netdev == netdev )
                        return 1;
        }
        return 0;
}
static int ipv4_has_addr ( struct net_device netdev,
struct in_addr  addr 
) [static]

Check if network device has a specific IPv4 address.

Parameters:
netdevNetwork device
addrIPv4 address
Return values:
has_addrNetwork device has this IPv4 address

Definition at line 450 of file ipv4.c.

References ipv4_miniroute::address, ipv4_miniroute::list, list_for_each_entry, ipv4_miniroute::netdev, and in_addr::s_addr.

Referenced by ipv4_arp_check(), ipv4_gratuitous_arp(), and ipv4_rx().

                                                                            {
        struct ipv4_miniroute *miniroute;

        list_for_each_entry ( miniroute, &ipv4_miniroutes, list ) {
                if ( ( miniroute->netdev == netdev ) &&
                     ( miniroute->address.s_addr == addr.s_addr ) ) {
                        /* Found matching address */
                        return 1;
                }
        }
        return 0;
}
static int ipv4_rx ( struct io_buffer iobuf,
struct net_device netdev,
const void *ll_dest  __unused,
const void *ll_source  __unused,
unsigned int  flags 
) [static]

Process incoming packets.

Parameters:
iobufI/O buffer
netdevNetwork device
ll_destLink-layer destination address
ll_sourceLink-layer destination source
flagsPacket flags
Return values:
rcReturn status code

This function expects an IP4 network datagram. It processes the headers and sends it to the transport layer.

Definition at line 476 of file ipv4.c.

References AF_INET, iphdr::chksum, io_buffer::data, DBGC, DBGC2, iphdr::dest, dest, EINVAL, fragment_reassemble(), iphdr::frags, free_iob(), htons, iphdr::ident, ip_statistics::in_addr_errors, ip_statistics::in_bcast_pkts, ip_statistics::in_hdr_errors, ip_statistics::in_mcast_pkts, ip_statistics::in_octets, ip_statistics::in_receives, ip_statistics::in_truncated_pkts, INADDR_BROADCAST, inet_ntoa(), iob_len(), iob_pull, iob_unput, IP_MASK_HLEN, IP_MASK_MOREFRAGS, IP_MASK_OFFSET, IP_MASK_VER, IP_VER, ipv4_has_addr(), ipv4_has_any_addr(), ipv4_pshdr_chksum(), ipv4_stats, iphdr::len, len, LL_BROADCAST, LL_MULTICAST, memset(), ntohs, profile_start(), profile_stop(), iphdr::protocol, rc, in_addr::s_addr, iphdr::src, src, strerror(), tcpip_chksum(), TCPIP_EMPTY_CSUM, tcpip_rx(), and iphdr::verhdrlen.

                                          {
        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;

        /* Start profiling */
        profile_start ( &ipv4_rx_profiler );

        /* Update statistics */
        ipv4_stats.in_receives++;
        ipv4_stats.in_octets += iob_len ( iobuf );
        if ( flags & LL_BROADCAST ) {
                ipv4_stats.in_bcast_pkts++;
        } else if ( flags & LL_MULTICAST ) {
                ipv4_stats.in_mcast_pkts++;
        }

        /* Sanity check the IPv4 header */
        if ( iob_len ( iobuf ) < sizeof ( *iphdr ) ) {
                DBGC ( iphdr->src, "IPv4 packet too short at %zd bytes (min "
                       "%zd bytes)\n", iob_len ( iobuf ), sizeof ( *iphdr ) );
                goto err_header;
        }
        if ( ( iphdr->verhdrlen & IP_MASK_VER ) != IP_VER ) {
                DBGC ( iphdr->src, "IPv4 version %#02x not supported\n",
                       iphdr->verhdrlen );
                goto err_header;
        }
        hdrlen = ( ( iphdr->verhdrlen & IP_MASK_HLEN ) * 4 );
        if ( hdrlen < sizeof ( *iphdr ) ) {
                DBGC ( iphdr->src, "IPv4 header too short at %zd bytes (min "
                       "%zd bytes)\n", hdrlen, sizeof ( *iphdr ) );
                goto err_header;
        }
        if ( hdrlen > iob_len ( iobuf ) ) {
                DBGC ( iphdr->src, "IPv4 header too long at %zd bytes "
                       "(packet is %zd bytes)\n", hdrlen, iob_len ( iobuf ) );
                goto err_header;
        }
        if ( ( csum = tcpip_chksum ( iphdr, hdrlen ) ) != 0 ) {
                DBGC ( iphdr->src, "IPv4 checksum incorrect (is %04x "
                       "including checksum field, should be 0000)\n", csum );
                goto err_header;
        }
        len = ntohs ( iphdr->len );
        if ( len < hdrlen ) {
                DBGC ( iphdr->src, "IPv4 length too short at %zd bytes "
                       "(header is %zd bytes)\n", len, hdrlen );
                goto err_header;
        }
        if ( len > iob_len ( iobuf ) ) {
                DBGC ( iphdr->src, "IPv4 length too long at %zd bytes "
                       "(packet is %zd bytes)\n", len, iob_len ( iobuf ) );
                ipv4_stats.in_truncated_pkts++;
                goto err_other;
        }

        /* Truncate packet to correct length */
        iob_unput ( iobuf, ( iob_len ( iobuf ) - len ) );

        /* Print IPv4 header for debugging */
        DBGC2 ( iphdr->src, "IPv4 RX %s<-", inet_ntoa ( iphdr->dest ) );
        DBGC2 ( iphdr->src, "%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 ) );

        /* Discard unicast packets not destined for us */
        if ( ( ! ( flags & LL_MULTICAST ) ) &&
             ( iphdr->dest.s_addr != INADDR_BROADCAST ) &&
             ipv4_has_any_addr ( netdev ) &&
             ( ! ipv4_has_addr ( netdev, iphdr->dest ) ) ) {
                DBGC ( iphdr->src, "IPv4 discarding non-local unicast packet "
                       "for %s\n", inet_ntoa ( iphdr->dest ) );
                ipv4_stats.in_addr_errors++;
                goto err_other;
        }

        /* Perform fragment reassembly if applicable */
        if ( iphdr->frags & htons ( IP_MASK_OFFSET | IP_MASK_MOREFRAGS ) ) {
                /* Pass the fragment to fragment_reassemble() which returns
                 * either a fully reassembled I/O buffer or NULL.
                 */
                iobuf = fragment_reassemble ( &ipv4_reassembler, iobuf,
                                              &hdrlen );
                if ( ! iobuf )
                        return 0;
                iphdr = iobuf->data;
        }

        /* Construct socket addresses, calculate pseudo-header
         * checksum, 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;
        pshdr_csum = ipv4_pshdr_chksum ( iobuf, TCPIP_EMPTY_CSUM );
        iob_pull ( iobuf, hdrlen );
        if ( ( rc = tcpip_rx ( iobuf, netdev, iphdr->protocol, &src.st,
                               &dest.st, pshdr_csum, &ipv4_stats ) ) != 0 ) {
                DBGC ( src.sin.sin_addr, "IPv4 received packet rejected by "
                       "stack: %s\n", strerror ( rc ) );
                return rc;
        }

        profile_stop ( &ipv4_rx_profiler );
        return 0;

 err_header:
        ipv4_stats.in_hdr_errors++;
 err_other:
        free_iob ( iobuf );
        return -EINVAL;
}
static int ipv4_arp_check ( struct net_device netdev,
const void *  net_addr 
) [static]

Check existence of IPv4 address for ARP.

Parameters:
netdevNetwork device
net_addrNetwork-layer address
Return values:
rcReturn status code

Definition at line 611 of file ipv4.c.

References address, ENOENT, and ipv4_has_addr().

                                                                              {
        const struct in_addr *address = net_addr;

        if ( ipv4_has_addr ( netdev, *address ) )
                return 0;

        return -ENOENT;
}
int inet_aton ( const char *  string,
struct in_addr in 
)

Parse IPv4 address.

Parameters:
stringIPv4 address string
Return values:
inIPv4 address to fill in
okIPv4 address is valid

Note that this function returns nonzero iff the address is valid, to match the standard BSD API function of the same name. Unlike most other iPXE functions, a zero therefore indicates failure.

Definition at line 631 of file ipv4.c.

References byte, strtoul(), and value.

Referenced by inet_aton_fail_okx(), inet_aton_okx(), ipv4_sock_aton(), parse_ipv4_setting(), slam_parse_multicast_address(), and tftp_process_multicast().

                                                         {
        const char *separator = "...";
        uint8_t *byte = ( ( uint8_t * ) in );
        char *endp;
        unsigned long value;

        while ( 1 ) {
                value = strtoul ( string, &endp, 0 );
                if ( string == endp )
                        return 0;
                if ( value > 0xff )
                        return 0;
                *(byte++) = value;
                if ( *endp != *separator )
                        return 0;
                if ( ! *(separator++) )
                        return 1;
                string = ( endp + 1 );
        }
}
char* inet_ntoa ( struct in_addr  in)

Convert IPv4 address to dotted-quad notation.

Parameters:
inIPv4 address
Return values:
stringIPv4 address in dotted-quad notation

Definition at line 658 of file ipv4.c.

References bytes, and sprintf.

Referenced by add_ipv4_miniroute(), del_ipv4_miniroute(), dhcp_deliver(), dhcp_discovery_rx(), dhcp_proxy_rx(), dhcp_proxy_tx(), dhcp_pxebs_accept(), dhcp_pxebs_rx(), dhcp_pxebs_tx(), dhcp_request_rx(), dhcp_request_tx(), efi_snp_mcast_ip_to_mac(), fetch_next_server_and_filename(), format_ipv4_setting(), ibft_ipaddr(), inet_aton_okx(), inet_ntoa_okx(), ipoib_transmit(), ipv4_gratuitous_arp(), ipv4_ntoa(), ipv4_rx(), ipv4_sock_ntoa(), ipv4_tx(), pxenv_udp_open(), pxenv_udp_read(), pxenv_udp_write(), pxenv_undi_get_mcast_address(), route_ipv4_print(), start_pxebs(), tftp_apply_settings(), and tftp_process_multicast().

                                       {
        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;
}
static const char* ipv4_ntoa ( const void *  net_addr) [static]

Transcribe IPv4 address.

Parameters:
net_addrIPv4 address
Return values:
stringIPv4 address in dotted-quad notation

Definition at line 673 of file ipv4.c.

References inet_ntoa().

                                                       {
        return inet_ntoa ( * ( ( struct in_addr * ) net_addr ) );
}
static const char* ipv4_sock_ntoa ( struct sockaddr sa) [static]

Transcribe IPv4 socket address.

Parameters:
saSocket address
Return values:
stringSocket address in standard notation

Definition at line 683 of file ipv4.c.

References inet_ntoa(), sin, and sockaddr_in::sin_addr.

                                                           {
        struct sockaddr_in *sin = ( ( struct sockaddr_in * ) sa );

        return inet_ntoa ( sin->sin_addr );
}
static int ipv4_sock_aton ( const char *  string,
struct sockaddr sa 
) [static]

Parse IPv4 socket address.

Parameters:
stringSocket address string
saSocket address to fill in
Return values:
rcReturn status code

Definition at line 696 of file ipv4.c.

References EINVAL, in, inet_aton(), sin, and sockaddr_in::sin_addr.

                                                                      {
        struct sockaddr_in *sin = ( ( struct sockaddr_in * ) sa );
        struct in_addr in;

        if ( inet_aton ( string, &in ) ) {
                sin->sin_addr = in;
                return 0;
        }
        return -EINVAL;
}
int parse_ipv4_setting ( const struct setting_type *type  __unused,
const char *  value,
void *  buf,
size_t  len 
)

Parse IPv4 address setting value.

Parameters:
typeSetting type
valueFormatted setting value
bufBuffer to contain raw value
lenLength of buffer
Return values:
lenLength of raw value, or negative error

Definition at line 755 of file ipv4.c.

References EINVAL, inet_aton(), and memcpy().

                                                                    {
        struct in_addr ipv4;

        /* Parse IPv4 address */
        if ( inet_aton ( value, &ipv4 ) == 0 )
                return -EINVAL;

        /* Copy to buffer */
        if ( len > sizeof ( ipv4 ) )
                len = sizeof ( ipv4 );
        memcpy ( buf, &ipv4, len );

        return ( sizeof ( ipv4 ) );
}
int format_ipv4_setting ( const struct setting_type *type  __unused,
const void *  raw,
size_t  raw_len,
char *  buf,
size_t  len 
)

Format IPv4 address setting value.

Parameters:
typeSetting type
rawRaw setting value
raw_lenLength of raw setting value
bufBuffer to contain formatted value
lenLength of buffer
Return values:
lenLength of formatted value, or negative error

Definition at line 781 of file ipv4.c.

References EINVAL, inet_ntoa(), raw, and snprintf().

                                       {
        const struct in_addr *ipv4 = raw;

        if ( raw_len < sizeof ( *ipv4 ) )
                return -EINVAL;
        return snprintf ( buf, len, "%s", inet_ntoa ( *ipv4 ) );
}
struct setting ip_setting __setting ( SETTING_IP4  ,
ip   
) [read]

IPv4 address setting.

struct setting netmask_setting __setting ( SETTING_IP4  ,
netmask   
) [read]

IPv4 subnet mask setting.

struct setting gateway_setting __setting ( SETTING_IP4  ,
gateway   
) [read]

Default gateway setting.

static int ipv4_gratuitous_arp ( struct net_device netdev,
struct in_addr  address,
struct in_addr netmask  __unused,
struct in_addr gateway  __unused 
) [static]

Send gratuitous ARP, if applicable.

Parameters:
netdevNetwork device
addressIPv4 address
netmaskSubnet mask
gatewayGateway address (if any)
Return values:
rcReturn status code

Definition at line 824 of file ipv4.c.

References arp_tx_request(), DBGC, inet_ntoa(), ipv4_has_addr(), net_device::name, rc, and strerror().

Referenced by ipv4_create_routes().

                                                                   {
        int rc;

        /* Do nothing if network device already has this IPv4 address */
        if ( ipv4_has_addr ( netdev, address ) )
                return 0;

        /* Transmit gratuitous ARP */
        DBGC ( netdev, "IPv4 sending gratuitous ARP for %s via %s\n",
               inet_ntoa ( address ), netdev->name );
        if ( ( rc = arp_tx_request ( netdev, &ipv4_protocol, &address,
                                     &address ) ) != 0 ) {
                DBGC ( netdev, "IPv4 could not transmit gratuitous ARP: %s\n",
                       strerror ( rc ) );
                /* Treat failures as non-fatal */
        }

        return 0;
}
static int ipv4_settings ( int(*)(struct net_device *netdev, struct in_addr address, struct in_addr netmask, struct in_addr gateway)  apply) [static]

Process IPv4 network device settings.

Parameters:
applyApplication method
Return values:
rcReturn status code

Definition at line 853 of file ipv4.c.

References fetch_ipv4_setting(), for_each_netdev, IN_IS_CLASSA, IN_IS_CLASSB, IN_IS_CLASSC, INADDR_NET_CLASSA, INADDR_NET_CLASSB, INADDR_NET_CLASSC, netdev, netdev_settings(), rc, and in_addr::s_addr.

Referenced by ipv4_create_routes().

                                                                        {
        struct net_device *netdev;
        struct settings *settings;
        struct in_addr address = { 0 };
        struct in_addr netmask = { 0 };
        struct in_addr gateway = { 0 };
        int rc;

        /* Process settings for each network device */
        for_each_netdev ( netdev ) {

                /* Get network device settings */
                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_IS_CLASSA ( address.s_addr ) ) {
                                netmask.s_addr = INADDR_NET_CLASSA;
                        } else if ( IN_IS_CLASSB ( address.s_addr ) ) {
                                netmask.s_addr = INADDR_NET_CLASSB;
                        } else if ( IN_IS_CLASSC ( address.s_addr ) ) {
                                netmask.s_addr = INADDR_NET_CLASSC;
                        }
                }

                /* Get default gateway, if present */
                fetch_ipv4_setting ( settings, &gateway_setting, &gateway );

                /* Apply settings */
                if ( ( rc = apply ( netdev, address, netmask, gateway ) ) != 0 )
                        return rc;
        }

        return 0;
}
static int ipv4_create_routes ( void  ) [static]

Create IPv4 routing table based on configured settings.

Return values:
rcReturn status code

Definition at line 906 of file ipv4.c.

References add_ipv4_miniroute(), del_ipv4_miniroute(), ipv4_gratuitous_arp(), ipv4_settings(), ipv4_miniroute::list, list_for_each_entry_safe, and rc.

                                       {
        struct ipv4_miniroute *miniroute;
        struct ipv4_miniroute *tmp;
        int rc;

        /* Send gratuitous ARPs for any new IPv4 addresses */
        ipv4_settings ( ipv4_gratuitous_arp );

        /* 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 */
        if ( ( rc = ipv4_settings ( add_ipv4_miniroute ) ) != 0 )
                return rc;

        return 0;
}
REQUIRING_SYMBOL ( ipv4_protocol  )
REQUIRE_OBJECT ( icmpv4  )

Variable Documentation

uint8_t next_ident_high = 0 [static]

Definition at line 54 of file ipv4.c.

Referenced by ipv4_tx().

List of IPv4 miniroutes.

Definition at line 57 of file ipv4.c.

Referenced by route_ipv4_print().

struct ip_statistics ipv4_stats [static]

IPv4 statistics.

Definition at line 60 of file ipv4.c.

Referenced by ipv4_rx(), and ipv4_tx().

struct profiler ipv4_rx_profiler __profiler = { .name = "ipv4.tx" } [static]

Transmit profiler.

Receive profiler.

Definition at line 70 of file ipv4.c.

Initial value:
 {
        .list = LIST_HEAD_INIT ( ipv4_reassembler.list ),
        .is_fragment = ipv4_is_fragment,
        .fragment_offset = ipv4_fragment_offset,
        .more_fragments = ipv4_more_fragments,
        .stats = &ipv4_stats,
}

IPv4 fragment reassembler.

Definition at line 258 of file ipv4.c.

struct net_protocol ipv4_protocol __net_protocol
Initial value:
 {
        .name = "IP",
        .net_proto = htons ( ETH_P_IP ),
        .net_addr_len = sizeof ( struct in_addr ),
        .rx = ipv4_rx,
        .ntoa = ipv4_ntoa,
}

IPv4 protocol.

AoE protocol.

Definition at line 708 of file ipv4.c.

struct tcpip_net_protocol ipv4_tcpip_protocol __tcpip_net_protocol
Initial value:
 {
        .name = "IPv4",
        .sa_family = AF_INET,
        .header_len = sizeof ( struct iphdr ),
        .net_protocol = &ipv4_protocol,
        .tx = ipv4_tx,
        .netdev = ipv4_netdev,
}

IPv4 TCPIP net protocol.

Definition at line 717 of file ipv4.c.

struct arp_net_protocol ipv4_arp_protocol __arp_net_protocol
Initial value:
 {
        .net_protocol = &ipv4_protocol,
        .check = ipv4_arp_check,
}

IPv4 ARP protocol.

Definition at line 727 of file ipv4.c.

struct sockaddr_converter ipv4_sockaddr_converter __sockaddr_converter
Initial value:
 {
        .family = AF_INET,
        .ntoa = ipv4_sock_ntoa,
        .aton = ipv4_sock_aton,
}

IPv4 socket address converter.

Definition at line 733 of file ipv4.c.

struct settings_applicator ipv4_settings_applicator __settings_applicator
Initial value:
 {
        .apply = ipv4_create_routes,
}

IPv4 settings applicator.

Definition at line 926 of file ipv4.c.