Home | History | Annotate | Download | only in net
      1 #include <stdint.h>
      2 #include <string.h>
      3 #include <errno.h>
      4 #include <byteswap.h>
      5 #include <gpxe/iobuf.h>
      6 #include <gpxe/tables.h>
      7 #include <gpxe/tcpip.h>
      8 
      9 /** @file
     10  *
     11  * Transport-network layer interface
     12  *
     13  * This file contains functions and utilities for the
     14  * TCP/IP transport-network layer interface
     15  */
     16 
     17 FILE_LICENCE ( GPL2_OR_LATER );
     18 
     19 /** Process a received TCP/IP packet
     20  *
     21  * @v iobuf		I/O buffer
     22  * @v tcpip_proto	Transport-layer protocol number
     23  * @v st_src		Partially-filled source address
     24  * @v st_dest		Partially-filled destination address
     25  * @v pshdr_csum	Pseudo-header checksum
     26  * @ret rc		Return status code
     27  *
     28  * This function expects a transport-layer segment from the network
     29  * layer.  The network layer should fill in as much as it can of the
     30  * source and destination addresses (i.e. it should fill in the
     31  * address family and the network-layer addresses, but leave the ports
     32  * and the rest of the structures as zero).
     33  */
     34 int tcpip_rx ( struct io_buffer *iobuf, uint8_t tcpip_proto,
     35 	       struct sockaddr_tcpip *st_src,
     36 	       struct sockaddr_tcpip *st_dest,
     37 	       uint16_t pshdr_csum ) {
     38 	struct tcpip_protocol *tcpip;
     39 
     40 	/* Hand off packet to the appropriate transport-layer protocol */
     41 	for_each_table_entry ( tcpip, TCPIP_PROTOCOLS ) {
     42 		if ( tcpip->tcpip_proto == tcpip_proto ) {
     43 			DBG ( "TCP/IP received %s packet\n", tcpip->name );
     44 			return tcpip->rx ( iobuf, st_src, st_dest, pshdr_csum );
     45 		}
     46 	}
     47 
     48 	DBG ( "Unrecognised TCP/IP protocol %d\n", tcpip_proto );
     49 	free_iob ( iobuf );
     50 	return -EPROTONOSUPPORT;
     51 }
     52 
     53 /** Transmit a TCP/IP packet
     54  *
     55  * @v iobuf		I/O buffer
     56  * @v tcpip_protocol	Transport-layer protocol
     57  * @v st_src		Source address, or NULL to use route default
     58  * @v st_dest		Destination address
     59  * @v netdev		Network device to use if no route found, or NULL
     60  * @v trans_csum	Transport-layer checksum to complete, or NULL
     61  * @ret rc		Return status code
     62  */
     63 int tcpip_tx ( struct io_buffer *iobuf, struct tcpip_protocol *tcpip_protocol,
     64 	       struct sockaddr_tcpip *st_src, struct sockaddr_tcpip *st_dest,
     65 	       struct net_device *netdev, uint16_t *trans_csum ) {
     66 	struct tcpip_net_protocol *tcpip_net;
     67 
     68 	/* Hand off packet to the appropriate network-layer protocol */
     69 	for_each_table_entry ( tcpip_net, TCPIP_NET_PROTOCOLS ) {
     70 		if ( tcpip_net->sa_family == st_dest->st_family ) {
     71 			DBG ( "TCP/IP sending %s packet\n", tcpip_net->name );
     72 			return tcpip_net->tx ( iobuf, tcpip_protocol, st_src,
     73 					       st_dest, netdev, trans_csum );
     74 		}
     75 	}
     76 
     77 	DBG ( "Unrecognised TCP/IP address family %d\n", st_dest->st_family );
     78 	free_iob ( iobuf );
     79 	return -EAFNOSUPPORT;
     80 }
     81 
     82 /**
     83  * Calculate continued TCP/IP checkum
     84  *
     85  * @v partial		Checksum of already-summed data, in network byte order
     86  * @v data		Data buffer
     87  * @v len		Length of data buffer
     88  * @ret cksum		Updated checksum, in network byte order
     89  *
     90  * Calculates a TCP/IP-style 16-bit checksum over the data block.  The
     91  * checksum is returned in network byte order.
     92  *
     93  * This function may be used to add new data to an existing checksum.
     94  * The function assumes that both the old data and the new data start
     95  * on even byte offsets; if this is not the case then you will need to
     96  * byte-swap either the input partial checksum, the output checksum,
     97  * or both.  Deciding which to swap is left as an exercise for the
     98  * interested reader.
     99  */
    100 uint16_t tcpip_continue_chksum ( uint16_t partial, const void *data,
    101 				 size_t len ) {
    102 	unsigned int cksum = ( ( ~partial ) & 0xffff );
    103 	unsigned int value;
    104 	unsigned int i;
    105 
    106 	for ( i = 0 ; i < len ; i++ ) {
    107 		value = * ( ( uint8_t * ) data + i );
    108 		if ( i & 1 ) {
    109 			/* Odd bytes: swap on little-endian systems */
    110 			value = be16_to_cpu ( value );
    111 		} else {
    112 			/* Even bytes: swap on big-endian systems */
    113 			value = le16_to_cpu ( value );
    114 		}
    115 		cksum += value;
    116 		if ( cksum > 0xffff )
    117 			cksum -= 0xffff;
    118 	}
    119 
    120 	return ( ~cksum );
    121 }
    122 
    123 /**
    124  * Calculate TCP/IP checkum
    125  *
    126  * @v data		Data buffer
    127  * @v len		Length of data buffer
    128  * @ret cksum		Checksum, in network byte order
    129  *
    130  * Calculates a TCP/IP-style 16-bit checksum over the data block.  The
    131  * checksum is returned in network byte order.
    132  */
    133 uint16_t tcpip_chksum ( const void *data, size_t len ) {
    134 	return tcpip_continue_chksum ( TCPIP_EMPTY_CSUM, data, len );
    135 }
    136