10 #include <gpxe/if_ether.h>
11 #include <gpxe/pkbuff.h>
12 #include <gpxe/netdevice.h>
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).
27 struct net_protocol ipv4_protocol;
29 /** An IPv4 address/routing table entry */
30 struct ipv4_miniroute {
31 /** List of miniroutes */
32 struct list_head list;
34 struct net_device *netdev;
36 struct in_addr address;
38 struct in_addr netmask;
39 /** Gateway address */
40 struct in_addr gateway;
43 /** List of IPv4 miniroutes */
44 static LIST_HEAD ( miniroutes );
49 * @v netdev Network device
50 * @v address IPv4 address
51 * @v netmask Subnet mask
52 * @v gateway Gateway address (or @c INADDR_NONE for no gateway)
53 * @ret rc Return status code
56 int add_ipv4_address ( struct net_device *netdev, struct in_addr address,
57 struct in_addr netmask, struct in_addr gateway ) {
58 struct ipv4_miniroute *miniroute;
60 /* Allocate and populate miniroute structure */
61 miniroute = malloc ( sizeof ( *miniroute ) );
64 miniroute->netdev = netdev;
65 miniroute->address = address;
66 miniroute->netmask = netmask;
67 miniroute->gateway = gateway;
69 /* Add to end of list if we have a gateway, otherwise to start
72 if ( gateway.s_addr != INADDR_NONE ) {
73 list_add_tail ( &miniroute->list, &miniroutes );
75 list_add ( &miniroute->list, &miniroutes );
81 * Remove IPv4 interface
83 * @v netdev Network device
85 void del_ipv4_address ( struct net_device *netdev ) {
86 struct ipv4_miniroute *miniroute;
88 list_for_each_entry ( miniroute, &miniroutes, list ) {
89 if ( miniroute->netdev == netdev ) {
90 list_del ( &miniroute->list );
97 * Transmit packet constructed by uIP
99 * @v pkb Packet buffer
100 * @ret rc Return status code
103 int ipv4_uip_tx ( struct pk_buff *pkb ) {
104 struct iphdr *iphdr = pkb->data;
105 struct ipv4_miniroute *miniroute;
106 struct net_device *netdev = NULL;
107 struct in_addr next_hop;
108 struct in_addr source;
109 uint8_t ll_dest_buf[MAX_LL_ADDR_LEN];
110 const uint8_t *ll_dest = ll_dest_buf;
113 /* Use routing table to identify next hop and transmitting netdev */
114 next_hop = iphdr->dest;
115 list_for_each_entry ( miniroute, &miniroutes, list ) {
116 if ( ( ( ( iphdr->dest.s_addr ^ miniroute->address.s_addr ) &
117 miniroute->netmask.s_addr ) == 0 ) ||
118 ( miniroute->gateway.s_addr != INADDR_NONE ) ) {
119 netdev = miniroute->netdev;
120 source = miniroute->address;
121 if ( miniroute->gateway.s_addr != INADDR_NONE )
122 next_hop = miniroute->gateway;
127 /* Abort if no network device identified */
129 DBG ( "No route to %s\n", inet_ntoa ( iphdr->dest ) );
134 /* Determine link-layer destination address */
135 if ( next_hop.s_addr == INADDR_BROADCAST ) {
136 /* Broadcast address */
137 ll_dest = netdev->ll_protocol->ll_broadcast;
138 } else if ( IN_MULTICAST ( next_hop.s_addr ) ) {
139 /* Special case: IPv4 multicast over Ethernet. This
140 * code may need to be generalised once we find out
141 * what happens for other link layers.
143 uint8_t *next_hop_bytes = ( uint8_t * ) &next_hop;
144 ll_dest_buf[0] = 0x01;
145 ll_dest_buf[0] = 0x00;
146 ll_dest_buf[0] = 0x5e;
147 ll_dest_buf[3] = next_hop_bytes[1] & 0x7f;
148 ll_dest_buf[4] = next_hop_bytes[2];
149 ll_dest_buf[5] = next_hop_bytes[3];
151 /* Unicast address: resolve via ARP */
152 if ( ( rc = arp_resolve ( netdev, &ipv4_protocol, &next_hop,
153 &source, ll_dest_buf ) ) != 0 ) {
154 DBG ( "No ARP entry for %s\n",
155 inet_ntoa ( iphdr->dest ) );
160 /* Hand off to link layer */
161 return net_tx ( pkb, netdev, &ipv4_protocol, ll_dest );
169 * Process incoming IP packets
171 * @v pkb Packet buffer
172 * @v netdev Network device
173 * @v ll_source Link-layer source address
174 * @ret rc Return status code
176 * This handles IP packets by handing them off to the uIP protocol
179 static int ipv4_rx ( struct pk_buff *pkb, struct net_device *netdev __unused,
180 const void *ll_source __unused ) {
182 /* Transfer to uIP buffer. Horrendously space-inefficient,
183 * but will do as a proof-of-concept for now.
185 uip_len = pkb_len ( pkb );
186 memcpy ( uip_buf, pkb->data, uip_len );
189 /* Hand to uIP for processing */
192 pkb = alloc_pkb ( MAX_LL_HEADER_LEN + uip_len );
195 pkb_reserve ( pkb, MAX_LL_HEADER_LEN );
196 memcpy ( pkb_put ( pkb, uip_len ), uip_buf, uip_len );
203 * Check existence of IPv4 address for ARP
205 * @v netdev Network device
206 * @v net_addr Network-layer address
207 * @ret rc Return status code
209 static int ipv4_arp_check ( struct net_device *netdev, const void *net_addr ) {
210 const struct in_addr *address = net_addr;
211 struct ipv4_miniroute *miniroute;
213 list_for_each_entry ( miniroute, &miniroutes, list ) {
214 if ( ( miniroute->netdev == netdev ) &&
215 ( miniroute->address.s_addr == address->s_addr ) ) {
216 /* Found matching address */
224 * Convert IPv4 address to dotted-quad notation
227 * @ret string IP address in dotted-quad notation
229 char * inet_ntoa ( struct in_addr in ) {
230 static char buf[16]; /* "xxx.xxx.xxx.xxx" */
231 uint8_t *bytes = ( uint8_t * ) ∈
233 sprintf ( buf, "%d.%d.%d.%d", bytes[0], bytes[1], bytes[2], bytes[3] );
238 * Transcribe IP address
240 * @v net_addr IP address
241 * @ret string IP address in dotted-quad notation
244 static const char * ipv4_ntoa ( const void *net_addr ) {
245 return inet_ntoa ( * ( ( struct in_addr * ) net_addr ) );
249 struct net_protocol ipv4_protocol = {
251 .net_proto = htons ( ETH_P_IP ),
252 .net_addr_len = sizeof ( struct in_addr ),
257 NET_PROTOCOL ( ipv4_protocol );
259 /** IPv4 ARP protocol */
260 struct arp_net_protocol ipv4_arp_protocol = {
261 .net_protocol = &ipv4_protocol,
262 .check = ipv4_arp_check,
265 ARP_NET_PROTOCOL ( ipv4_arp_protocol );