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