b82dfe58a0b6589b4891eaa5d5dd313545a24502
[gpxe.git] / src / net / ipv4.c
1 #include <string.h>
2 #include <stdint.h>
3 #include <byteswap.h>
4 #include <vsprintf.h>
5 #include <gpxe/in.h>
6
7
8 #include <ip.h>
9
10
11 #include <gpxe/if_ether.h>
12 #include <gpxe/pkbuff.h>
13 #include <gpxe/netdevice.h>
14 #include "uip/uip.h"
15
16 /** @file
17  *
18  * IPv4 protocol
19  *
20  * The gPXE IP stack is currently implemented on top of the uIP
21  * protocol stack.  This file provides wrappers around uIP so that
22  * higher-level protocol implementations do not need to talk directly
23  * to uIP (which has a somewhat baroque API).
24  *
25  */
26
27 /** An IPv4 routing table entry */
28 struct ipv4_route {
29         /** Network address */
30         struct in_addr network;
31         /** Subnet mask */
32         struct in_addr netmask;
33         /** Gateway address */
34         struct in_addr gateway;
35         /** Gateway device */
36         struct in_addr gatewaydev;
37 };
38
39 enum {
40         STATIC_SINGLE_NETDEV_ROUTE = 0,
41         DEFAULT_ROUTE,
42         NUM_ROUTES
43 };
44
45 /** IPv4 routing table */
46 static struct ipv4_route routing_table[NUM_ROUTES];
47
48 #define routing_table_end ( routing_table + NUM_ROUTES )
49
50 #if 0
51 /**
52  * Set IP address
53  *
54  */
55 void set_ipaddr ( struct in_addr address ) {
56         union {
57                 struct in_addr address;
58                 uint16_t uip_address[2];
59         } u;
60
61         u.address = address;
62         uip_sethostaddr ( u.uip_address );
63 }
64
65 /**
66  * Set netmask
67  *
68  */
69 void set_netmask ( struct in_addr address ) {
70         union {
71                 struct in_addr address;
72                 uint16_t uip_address[2];
73         } u;
74
75         u.address = address;
76         uip_setnetmask ( u.uip_address );
77 }
78
79 /**
80  * Set default gateway
81  *
82  */
83 void set_gateway ( struct in_addr address ) {
84         union {
85                 struct in_addr address;
86                 uint16_t uip_address[2];
87         } u;
88
89         u.address = address;
90         uip_setdraddr ( u.uip_address );
91 }
92
93 /**
94  * Run the TCP/IP stack
95  *
96  * Call this function in a loop in order to allow TCP/IP processing to
97  * take place.  This call takes the stack through a single iteration;
98  * it will typically be used in a loop such as
99  *
100  * @code
101  *
102  * struct tcp_connection *my_connection;
103  * ...
104  * tcp_connect ( my_connection );
105  * while ( ! my_connection->finished ) {
106  *   run_tcpip();
107  * }
108  *
109  * @endcode
110  *
111  * where @c my_connection->finished is set by one of the connection's
112  * #tcp_operations methods to indicate completion.
113  */
114 void run_tcpip ( void ) {
115         void *data;
116         size_t len;
117         uint16_t type;
118         int i;
119         
120         if ( netdev_poll ( 1, &data, &len ) ) {
121                 /* We have data */
122                 memcpy ( uip_buf, data, len );
123                 uip_len = len;
124                 type = ntohs ( *( ( uint16_t * ) ( uip_buf + 12 ) ) );
125                 if ( type == UIP_ETHTYPE_ARP ) {
126                         uip_arp_arpin();
127                 } else {
128                         uip_arp_ipin();
129                         uip_input();
130                 }
131                 if ( uip_len > 0 )
132                         uip_transmit();
133         } else {
134                 for ( i = 0 ; i < UIP_CONNS ; i++ ) {
135                         uip_periodic ( i );
136                         if ( uip_len > 0 )
137                                 uip_transmit();
138                 }
139         }
140 }
141 #endif
142
143 /**
144  * Process incoming IP packets
145  *
146  * @v pkb               Packet buffer
147  * @ret rc              Return status code
148  *
149  * This handles IP packets by handing them off to the uIP protocol
150  * stack.
151  */
152 static int ipv4_rx ( struct pk_buff *pkb ) {
153
154         /* Transfer to uIP buffer.  Horrendously space-inefficient,
155          * but will do as a proof-of-concept for now.
156          */
157         uip_len = pkb_len ( pkb );
158         memcpy ( uip_buf, pkb->data, uip_len );
159
160         /* Hand to uIP for processing */
161         uip_input ();
162         if ( uip_len > 0 ) {
163                 pkb_empty ( pkb );
164                 pkb_put ( pkb, uip_len );
165                 memcpy ( pkb->data, uip_buf, uip_len );
166                 net_transmit ( pkb );
167         } else {
168                 free_pkb ( pkb );
169         }
170         return 0;
171 }
172
173 /**
174  * Perform IP layer routing
175  *
176  * @v pkb       Packet buffer
177  * @ret source  Network-layer source address
178  * @ret dest    Network-layer destination address
179  * @ret rc      Return status code
180  */
181 static int ipv4_route ( const struct pk_buff *pkb,
182                         struct net_header *nethdr ) {
183         struct iphdr *iphdr = pkb->data;
184         struct in_addr *source = ( struct in_addr * ) nethdr->source_net_addr;
185         struct in_addr *dest = ( struct in_addr * ) nethdr->dest_net_addr;
186         struct ipv4_route *route;
187
188         /* Route IP packet according to routing table */
189         source->s_addr = INADDR_NONE;
190         dest->s_addr = iphdr->dest.s_addr;
191         for ( route = routing_table ; route < routing_table_end ; route++ ) {
192                 if ( ( dest->s_addr & route->netmask.s_addr )
193                      == route->network.s_addr ) {
194                         source->s_addr = route->gatewaydev.s_addr;
195                         if ( route->gateway.s_addr )
196                                 dest->s_addr = route->gateway.s_addr;
197                         break;
198                 }
199         }
200
201         /* Set broadcast and multicast flags as applicable */
202         nethdr->flags = 0;
203         if ( dest->s_addr == htonl ( INADDR_BROADCAST ) ) {
204                 nethdr->flags = PKT_FL_BROADCAST;
205         } else if ( IN_MULTICAST ( dest->s_addr ) ) {
206                 nethdr->flags = PKT_FL_MULTICAST;
207         }
208
209         return 0;
210 }
211
212 /**
213  * Transcribe IP address
214  *
215  * @v net_addr  IP address
216  * @ret string  IP address in dotted-quad notation
217  *
218  */
219 static const char * ipv4_ntoa ( const void *net_addr ) {
220         static char buf[16]; /* "xxx.xxx.xxx.xxx" */
221         uint8_t *ip_addr = net_addr;
222
223         sprintf ( buf, "%d.%d.%d.%d", ip_addr[0], ip_addr[1], ip_addr[2],
224                   ip_addr[3] );
225         return buf;
226 }
227
228 /** IPv4 protocol */
229 struct net_protocol ipv4_protocol = {
230         .name = "IP",
231         .net_proto = htons ( ETH_P_IP ),
232         .net_addr_len = sizeof ( struct in_addr ),
233         .rx_process = ipv4_rx,
234         .route = ipv4_route,
235         .ntoa = ipv4_ntoa,
236 };
237
238 NET_PROTOCOL ( ipv4_protocol );
239
240 /** IPv4 address for the static single net device */
241 struct net_address static_single_ipv4_address = {
242         .net_protocol = &ipv4_protocol,
243
244 #warning "Remove this static-IP hack"
245         .net_addr = { 0x0a, 0xfe, 0xfe, 0x01 },
246 };
247
248 STATIC_SINGLE_NETDEV_ADDRESS ( static_single_ipv4_address );
249
250 #warning "Remove this static-IP hack"
251 static struct ipv4_route routing_table[NUM_ROUTES] = {
252         { { htonl ( 0x0afefe00 ) }, { htonl ( 0xfffffffc ) },
253           { htonl ( 0x00000000 ) }, { htonl ( 0x0afefe01 ) } },
254         { { htonl ( 0x00000000 ) }, { htonl ( 0x00000000 ) },
255           { htonl ( 0x0afefe02 ) }, { htonl ( 0x0afefe01 ) } },
256 };
257