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