Renamed trans_{rx,tx}() to tcpip_{rx,tx}(), since they are specific to
[gpxe.git] / src / net / tcpip.c
1 #include <stdint.h>
2 #include <string.h>
3 #include <errno.h>
4 #include <malloc.h>
5 #include <byteswap.h>
6 #include <gpxe/in.h>
7 #include <gpxe/ip.h>
8 #include <gpxe/pkbuff.h>
9 #include <gpxe/tables.h>
10 #include <gpxe/netdevice.h>
11 #include <gpxe/tcpip.h>
12
13 /** @file
14  *
15  * Transport-network layer interface
16  *
17  * This file contains functions and utilities for the transport-network layer interface
18  */
19
20 /** Registered network-layer protocols that support TCPIP */
21 static struct tcpip_net_protocol tcpip_net_protocols[0] __table_start ( tcpip_net_protocols );
22 static struct tcpip_net_protocol tcpip_net_protocols_end[0] __table_end ( tcpip_net_protocols );
23
24 struct tcpip_protocol;
25
26 /** Registered transport-layer protocols that support TCPIP */
27 static struct tcpip_protocol tcpip_protocols[0] __table_start ( tcpip_protocols );
28 static struct tcpip_protocol tcpip_protocols_end[0] __table_end ( tcpip_protocols );
29
30 /** Identify TCPIP network-layer protocol
31  *
32  * @v sa_family  Network address family
33  * @ret tcpip      Protocol supporting TCPIP, or NULL
34  */
35 static struct tcpip_net_protocol * tcpip_find_protocol ( sa_family_t sa_family ) {
36         struct tcpip_net_protocol *tcpip_net;
37
38         for ( tcpip_net = tcpip_net_protocols; 
39                 tcpip_net < tcpip_net_protocols_end; ++tcpip_net ) {
40                 if ( tcpip_net->sa_family == sa_family ) {
41                         return tcpip_net;
42                 }
43         }
44         return NULL;
45 }
46
47 /** Identify TCPIP transport-layer protocol
48  *
49  * @v trans_proto       Transport-layer protocol number, IP_XXX
50  * @ret tcpip_protocol  Transport-layer protocol, or NULL
51  */
52 struct tcpip_protocol* find_tcpip_protocol ( uint8_t trans_proto ) {
53         struct tcpip_protocol *tcpip;
54
55         for ( tcpip = tcpip_protocols; tcpip <= tcpip_protocols_end; 
56                 ++tcpip ) {
57                 if ( tcpip->trans_proto == trans_proto ) {
58                         return tcpip;
59                 }
60         }
61         return NULL;
62 }
63
64 /** Process a received packet
65  *
66  * @v pkb               Packet buffer
67  * @v trans_proto       Transport-layer protocol number
68  * @v src               Source network-layer address
69  * @v dest              Destination network-layer address
70  *
71  * This function expects a transport-layer segment from the network-layer
72  */
73 void tcpip_rx ( struct pk_buff *pkb, uint8_t trans_proto, struct in_addr *src,
74                 struct in_addr *dest ) {
75         struct tcpip_protocol *tcpip;
76
77         /* Identify the transport layer protocol */
78         for ( tcpip = tcpip_protocols; tcpip <= tcpip_protocols_end; ++tcpip ) {
79                 if ( tcpip->trans_proto == trans_proto ) {
80                         DBG ( "Packet sent to %s module", tcpip->name );
81                         tcpip->rx ( pkb, src, dest );
82                 }
83         }
84 }
85
86 /** Transmit a transport-layer segment
87  *
88  * @v pkb               Packet buffer
89  * @v trans_proto       Transport-layer protocol
90  * @v sock              Destination socket address
91  * @ret                 Status
92  */
93 int tcpip_tx ( struct pk_buff *pkb, struct tcpip_protocol *tcpip,
94                struct sockaddr *sock ) {
95
96         /* Identify the network layer protocol and send it using xxx_tx() */
97         switch ( sock->sa_family ) {
98         case AF_INET: /* IPv4 network family */
99                 return ipv4_tx ( pkb, tcpip, &sock->sin.sin_addr );
100         case AF_INET6: /* IPv6 network family */
101                 return ipv6_tx ( pkb, tcpip, &sock->sin6.sin6_addr );
102         }
103         DBG ( "Network family %d not supported", sock->sa_family );
104         return -EAFNOSUPPORT;
105 }
106
107 /**
108  * Calculate continued TCP/IP checkum
109  *
110  * @v partial           Checksum of already-summed data, in network byte order
111  * @v data              Data buffer
112  * @v len               Length of data buffer
113  * @ret cksum           Updated checksum, in network byte order
114  *
115  * Calculates a TCP/IP-style 16-bit checksum over the data block.  The
116  * checksum is returned in network byte order.
117  *
118  * This function may be used to add new data to an existing checksum.
119  * The function assumes that both the old data and the new data start
120  * on even byte offsets; if this is not the case then you will need to
121  * byte-swap either the input partial checksum, the output checksum,
122  * or both.  Deciding which to swap is left as an exercise for the
123  * interested reader.
124  */
125 unsigned int tcpip_continue_chksum ( unsigned int partial, const void *data,
126                                      size_t len ) {
127         unsigned int cksum = ( ( ~partial ) & 0xffff );
128         unsigned int value;
129         unsigned int i;
130         
131         for ( i = 0 ; i < len ; i++ ) {
132                 value = * ( ( uint8_t * ) data + i );
133                 if ( i & 1 ) {
134                         /* Odd bytes: swap on little-endian systems */
135                         value = be16_to_cpu ( value );
136                 } else {
137                         /* Even bytes: swap on big-endian systems */
138                         value = le16_to_cpu ( value );
139                 }
140                 cksum += value;
141                 if ( cksum > 0xffff )
142                         cksum -= 0xffff;
143         }
144         
145         return ( ( ~cksum ) & 0xffff );
146 }
147
148 /**
149  * Calculate TCP/IP checkum
150  *
151  * @v data              Data buffer
152  * @v len               Length of data buffer
153  * @ret cksum           Checksum, in network byte order
154  *
155  * Calculates a TCP/IP-style 16-bit checksum over the data block.  The
156  * checksum is returned in network byte order.
157  */
158 unsigned int tcpip_chksum ( const void *data, size_t len ) {
159         return tcpip_continue_chksum ( 0xffff, data, len );
160 }