1 /*
2  * Copyright (c) 2014 Chris Anderson
3  * Copyright (c) 2014 Brian Swetland
4  *
5  * Use of this source code is governed by a MIT-style
6  * license that can be found in the LICENSE file or at
7  * https://opensource.org/licenses/MIT
8  */
9 
10 #include "minip-internal.h"
11 
12 #include <assert.h>
13 #include <lk/err.h>
14 #include <stdio.h>
15 #include <lk/debug.h>
16 #include <endian.h>
17 #include <errno.h>
18 #include <iovec.h>
19 #include <stdlib.h>
20 #include <string.h>
21 #include <lk/trace.h>
22 #include <malloc.h>
23 #include <lk/list.h>
24 #include <lk/init.h>
25 #include <kernel/event.h>
26 #include <kernel/thread.h>
27 
28 // TODO
29 // 1. Tear endian code out into something that flips words before/after tx/rx calls
30 
31 #define LOCAL_TRACE 0
32 static uint32_t minip_ip      = IPV4_NONE;
33 static uint32_t minip_netmask = IPV4_NONE;
34 static uint32_t minip_broadcast = IPV4_BCAST;
35 static uint32_t minip_gateway = IPV4_NONE;
36 
37 static const uint8_t broadcast_mac[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
38 static uint8_t minip_mac[6] = {0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC};
39 
40 static char minip_hostname[32] = "";
41 
42 static volatile bool minip_configured = false;
43 static event_t minip_configured_event = EVENT_INITIAL_VALUE(minip_configured_event, false, 0);
44 
45 /* This function is called by minip to send packets */
46 tx_func_t minip_tx_handler;
47 void *minip_tx_arg;
48 
49 static void dump_mac_address(const uint8_t *mac);
50 static void dump_ipv4_addr(uint32_t addr);
51 
52 /* if all the important configuration bits are set, signal that we're configured */
check_and_set_configured(void)53 static void check_and_set_configured(void) {
54     if (minip_ip == IPV4_NONE) return;
55     if (minip_netmask == IPV4_NONE) return;
56     if (minip_broadcast == IPV4_BCAST) return;
57     // minip_gateway doesn't have to be set
58     if (minip_mac[0] == 0xcc &&
59         minip_mac[1] == 0xcc &&
60         minip_mac[2] == 0xcc &&
61         minip_mac[3] == 0xcc &&
62         minip_mac[4] == 0xcc &&
63         minip_mac[5] == 0xcc) return;
64 
65     // we're configured
66     printf("MINIP: setting configured state\n");
67     minip_set_configured();
68 }
69 
minip_set_hostname(const char * name)70 void minip_set_hostname(const char *name) {
71     strlcpy(minip_hostname, name, sizeof(minip_hostname));
72     check_and_set_configured();
73 }
74 
minip_get_hostname(void)75 const char *minip_get_hostname(void) {
76     return minip_hostname;
77 }
78 
compute_broadcast_address(void)79 static void compute_broadcast_address(void) {
80     minip_broadcast = (minip_ip & minip_netmask) | (IPV4_BCAST & ~minip_netmask);
81 }
82 
minip_get_macaddr(uint8_t * addr)83 void minip_get_macaddr(uint8_t *addr) {
84     mac_addr_copy(addr, minip_mac);
85 }
86 
minip_get_ipaddr(void)87 uint32_t minip_get_ipaddr(void) {
88     return minip_ip;
89 }
90 
minip_set_ipaddr(const uint32_t addr)91 void minip_set_ipaddr(const uint32_t addr) {
92     minip_ip = addr;
93     compute_broadcast_address();
94     check_and_set_configured();
95 }
96 
minip_get_broadcast(void)97 uint32_t minip_get_broadcast(void) {
98     return minip_broadcast;
99 }
100 
minip_get_netmask(void)101 uint32_t minip_get_netmask(void) {
102     return minip_netmask;
103 }
104 
minip_set_netmask(const uint32_t netmask)105 void minip_set_netmask(const uint32_t netmask) {
106     minip_netmask = netmask;
107     compute_broadcast_address();
108     check_and_set_configured();
109 }
110 
minip_get_gateway(void)111 uint32_t minip_get_gateway(void) {
112     return minip_gateway;
113 }
114 
minip_set_gateway(const uint32_t addr)115 void minip_set_gateway(const uint32_t addr) {
116     minip_gateway = addr;
117     // TODO: check that it is reacheable on local network
118     check_and_set_configured();
119 }
120 
minip_set_configured(void)121 void minip_set_configured(void) {
122     minip_configured = true;
123     event_signal(&minip_configured_event, true);
124 }
125 
minip_is_configured(void)126 bool minip_is_configured(void) {
127     return minip_configured;
128 }
129 
minip_wait_for_configured(lk_time_t timeout)130 status_t minip_wait_for_configured(lk_time_t timeout) {
131     return event_wait_timeout(&minip_configured_event, timeout);
132 }
133 
gen_random_mac_address(uint8_t * mac_addr)134 void gen_random_mac_address(uint8_t *mac_addr) {
135     for (size_t i = 0; i < 6; i++) {
136         mac_addr[i] = rand() & 0xff;
137     }
138     /* unicast and locally administered */
139     mac_addr[0] &= ~(1<<0);
140     mac_addr[0] |= (1<<1);
141 }
142 
minip_start_static(uint32_t ip,uint32_t mask,uint32_t gateway)143 void minip_start_static(uint32_t ip, uint32_t mask, uint32_t gateway) {
144     minip_set_ipaddr(ip);
145     minip_set_netmask(mask);
146     minip_set_gateway(gateway);
147 }
148 
minip_set_eth(tx_func_t tx_handler,void * tx_arg,const uint8_t * macaddr)149 void minip_set_eth(tx_func_t tx_handler, void *tx_arg, const uint8_t *macaddr) {
150     LTRACEF("handler %p, arg %p, macaddr %p\n", tx_handler, tx_arg, macaddr);
151 
152     DEBUG_ASSERT(minip_tx_handler == NULL);
153     DEBUG_ASSERT(minip_tx_arg == NULL);
154     // TODO: assert mac address is not already set
155 
156     // set up the low level driver handler
157     minip_tx_handler = tx_handler;
158     minip_tx_arg = tx_arg;
159 
160     mac_addr_copy(minip_mac, macaddr);
161 }
162 
ipv4_payload_len(struct ipv4_hdr * pkt)163 static uint16_t ipv4_payload_len(struct ipv4_hdr *pkt) {
164     return (pkt->len - ((pkt->ver_ihl >> 4) * 5));
165 }
166 
minip_build_mac_hdr(struct eth_hdr * pkt,const uint8_t * dst,uint16_t type)167 void minip_build_mac_hdr(struct eth_hdr *pkt, const uint8_t *dst, uint16_t type) {
168     mac_addr_copy(pkt->dst_mac, dst);
169     mac_addr_copy(pkt->src_mac, minip_mac);
170     pkt->type = htons(type);
171 }
172 
minip_build_ipv4_hdr(struct ipv4_hdr * ipv4,uint32_t dst,uint8_t proto,uint16_t len)173 void minip_build_ipv4_hdr(struct ipv4_hdr *ipv4, uint32_t dst, uint8_t proto, uint16_t len) {
174     ipv4->ver_ihl       = 0x45;
175     ipv4->dscp_ecn      = 0;
176     ipv4->len           = htons(20 + len); // 5 * 4 from ihl, plus payload length
177     ipv4->id            = 0;
178     ipv4->flags_frags   = 0x40; // no offset, no fragments
179     ipv4->ttl           = 64;
180     ipv4->proto         = proto;
181     ipv4->dst_addr      = dst;
182     ipv4->src_addr      = minip_ip;
183 
184     /* This may be unnecessary if the controller supports checksum offloading */
185     ipv4->chksum = 0;
186     ipv4->chksum = rfc1701_chksum((uint8_t *) ipv4, sizeof(struct ipv4_hdr));
187 }
188 
send_arp_request(uint32_t addr)189 static int send_arp_request(uint32_t addr) {
190     pktbuf_t *p;
191     struct eth_hdr *eth;
192     struct arp_pkt *arp;
193 
194     if ((p = pktbuf_alloc()) == NULL) {
195         return -1;
196     }
197 
198     eth = pktbuf_prepend(p, sizeof(struct eth_hdr));
199     arp = pktbuf_append(p, sizeof(struct arp_pkt));
200     minip_build_mac_hdr(eth, bcast_mac, ETH_TYPE_ARP);
201 
202     arp->htype = htons(0x0001);
203     arp->ptype = htons(0x0800);
204     arp->hlen = 6;
205     arp->plen = 4;
206     arp->oper = htons(ARP_OPER_REQUEST);
207     arp->spa = minip_ip;
208     arp->tpa = addr;
209     mac_addr_copy(arp->sha, minip_mac);
210     mac_addr_copy(arp->tha, bcast_mac);
211 
212     minip_tx_handler(minip_tx_arg, p);
213     return 0;
214 }
215 
handle_arp_timeout_cb(void * arg)216 static void handle_arp_timeout_cb(void *arg) {
217     *(bool *)arg = true;
218 }
219 
get_dest_mac(uint32_t host)220 const uint8_t *get_dest_mac(uint32_t host) {
221     uint8_t *dst_mac = NULL;
222     bool arp_timeout = false;
223     net_timer_t arp_timeout_timer;
224 
225     if (host == IPV4_BCAST) {
226         return bcast_mac;
227     }
228 
229     dst_mac = arp_cache_lookup(host);
230     if (dst_mac == NULL) {
231         send_arp_request(host);
232         memset(&arp_timeout_timer, 0, sizeof(arp_timeout_timer));
233         net_timer_set(&arp_timeout_timer, handle_arp_timeout_cb, &arp_timeout, 100);
234         while (!arp_timeout) {
235             dst_mac = arp_cache_lookup(host);
236             if (dst_mac) {
237                 net_timer_cancel(&arp_timeout_timer);
238                 break;
239             }
240         }
241     }
242 
243     return dst_mac;
244 }
245 
minip_ipv4_send(pktbuf_t * p,uint32_t dest_addr,uint8_t proto)246 status_t minip_ipv4_send(pktbuf_t *p, uint32_t dest_addr, uint8_t proto) {
247     status_t ret = 0;
248     size_t data_len = p->dlen;
249     const uint8_t *dst_mac;
250 
251     struct ipv4_hdr *ip = pktbuf_prepend(p, sizeof(struct ipv4_hdr));
252     struct eth_hdr *eth = pktbuf_prepend(p, sizeof(struct eth_hdr));
253 
254     // are we sending a broadcast packet?
255     if (dest_addr == IPV4_BCAST || dest_addr == minip_broadcast) {
256         dst_mac = bcast_mac;
257         goto ready;
258     }
259 
260     // is this a local subnet packet or do we need to send to the router?
261     uint32_t target_addr = dest_addr;
262     if ((dest_addr & minip_netmask) != (minip_ip & minip_netmask)) {
263         // need to use the gateway
264         if (minip_gateway == IPV4_NONE) {
265             return ERR_NOT_FOUND; // TODO: better error code
266         }
267 
268         target_addr = minip_gateway;
269     }
270 
271     dst_mac = arp_get_dest_mac(target_addr);
272     if (!dst_mac) {
273         pktbuf_free(p, true);
274         ret = -EHOSTUNREACH;
275         goto err;
276     }
277 
278 ready:
279     if (LOCAL_TRACE) {
280         printf("sending ipv4\n");
281     }
282 
283     minip_build_mac_hdr(eth, dst_mac, ETH_TYPE_IPV4);
284     minip_build_ipv4_hdr(ip, dest_addr, proto, data_len);
285 
286     minip_tx_handler(minip_tx_arg, p);
287 
288 err:
289     return ret;
290 }
291 
292 /* Swap the dst/src ip addresses and send an ICMP ECHO REPLY with the same payload.
293  * According to spec the data portion doesn't matter, but ping itself validates that
294  * the payload is identical
295  */
send_ping_reply(uint32_t ipaddr,struct icmp_pkt * req,size_t reqdatalen)296 static void send_ping_reply(uint32_t ipaddr, struct icmp_pkt *req, size_t reqdatalen) {
297     pktbuf_t *p;
298     size_t len;
299     struct eth_hdr *eth;
300     struct ipv4_hdr *ip;
301     struct icmp_pkt *icmp;
302 
303     if ((p = pktbuf_alloc()) == NULL) {
304         return;
305     }
306 
307     icmp = pktbuf_prepend(p, sizeof(struct icmp_pkt));
308     ip = pktbuf_prepend(p, sizeof(struct ipv4_hdr));
309     eth = pktbuf_prepend(p, sizeof(struct eth_hdr));
310     pktbuf_append_data(p, req->data, reqdatalen);
311 
312     len = sizeof(struct icmp_pkt) + reqdatalen;
313 
314     minip_build_mac_hdr(eth, arp_cache_lookup(ipaddr), ETH_TYPE_IPV4);
315     minip_build_ipv4_hdr(ip, ipaddr, IP_PROTO_ICMP, len);
316 
317     icmp->type = ICMP_ECHO_REPLY;
318     icmp->code = 0;
319     memcpy(icmp->hdr_data, req->hdr_data, sizeof(icmp->hdr_data));
320     icmp->chksum = 0;
321     icmp->chksum = rfc1701_chksum((uint8_t *) icmp, len);
322 
323     minip_tx_handler(minip_tx_arg, p);
324 }
325 
dump_ipv4_addr(uint32_t addr)326 static void dump_ipv4_addr(uint32_t addr) {
327     const uint8_t *a = (void *)&addr;
328 
329     printf("%hhu.%hhu.%hhu.%hhu", a[0], a[1], a[2], a[3]);
330 }
331 
dump_ipv4_packet(const struct ipv4_hdr * ip)332 static void dump_ipv4_packet(const struct ipv4_hdr *ip) {
333     printf("IP ");
334     dump_ipv4_addr(ip->src_addr);
335     printf(" -> ");
336     dump_ipv4_addr(ip->dst_addr);
337     printf(" hlen 0x%x, prot 0x%x, cksum 0x%x, len 0x%x, ident 0x%x, frag offset 0x%x\n",
338            (ip->ver_ihl & 0xf) * 4, ip->proto, ntohs(ip->chksum), ntohs(ip->len), ntohs(ip->id), ntohs(ip->flags_frags) & 0x1fff);
339 }
340 
handle_ipv4_packet(pktbuf_t * p,const uint8_t * src_mac)341 __NO_INLINE static void handle_ipv4_packet(pktbuf_t *p, const uint8_t *src_mac) {
342     struct ipv4_hdr *ip;
343 
344     ip = (struct ipv4_hdr *)p->data;
345     if (p->dlen < sizeof(struct ipv4_hdr))
346         return;
347 
348     /* print packets for us */
349     if (LOCAL_TRACE) {
350         dump_ipv4_packet(ip);
351     }
352 
353     /* reject bad packets */
354     if (((ip->ver_ihl >> 4) & 0xf) != 4) {
355         /* not version 4 */
356         LTRACEF("REJECT: not version 4\n");
357         return;
358     }
359 
360     /* do we have enough buffer to hold the full header + options? */
361     size_t header_len = (ip->ver_ihl & 0xf) * 4;
362     if (p->dlen < header_len) {
363         LTRACEF("REJECT: not enough buffer to hold header\n");
364         return;
365     }
366 
367     /* compute checksum */
368     if (rfc1701_chksum((void *)ip, header_len) != 0) {
369         /* bad checksum */
370         LTRACEF("REJECT: bad checksum\n");
371         return;
372     }
373 
374     /* is the pkt_buf large enough to hold the length the header says the packet is? */
375     if (htons(ip->len) > p->dlen) {
376         LTRACEF("REJECT: packet exceeds size of buffer (header %d, dlen %d)\n", htons(ip->len), p->dlen);
377         return;
378     }
379 
380     /* trim any excess bytes at the end of the packet */
381     if (p->dlen > htons(ip->len)) {
382         pktbuf_consume_tail(p, p->dlen - htons(ip->len));
383     }
384 
385     /* remove the header from the front of the packet_buf  */
386     if (pktbuf_consume(p, header_len) == NULL) {
387         return;
388     }
389 
390     /* the packet is good, we can use it to populate our arp cache */
391     arp_cache_update(ip->src_addr, src_mac);
392 
393     /* see if it's for us */
394     if (ip->dst_addr != IPV4_BCAST) {
395         if (minip_ip != IPV4_NONE && ip->dst_addr != minip_ip && ip->dst_addr != minip_broadcast) {
396             LTRACEF("REJECT: for another host\n");
397             return;
398         }
399     }
400 
401     /* We only handle UDP and ECHO REQUEST */
402     switch (ip->proto) {
403         case IP_PROTO_ICMP: {
404             struct icmp_pkt *icmp;
405             if ((icmp = pktbuf_consume(p, sizeof(struct icmp_pkt))) == NULL) {
406                 break;
407             }
408             if (icmp->type == ICMP_ECHO_REQUEST) {
409                 send_ping_reply(ip->src_addr, icmp, p->dlen);
410             }
411         }
412         break;
413 
414         case IP_PROTO_UDP:
415             udp_input(p, ip->src_addr);
416             break;
417 
418         case IP_PROTO_TCP:
419             tcp_input(p, ip->src_addr, ip->dst_addr);
420             break;
421     }
422 }
423 
handle_arp_pkt(pktbuf_t * p)424 __NO_INLINE static int handle_arp_pkt(pktbuf_t *p) {
425     struct eth_hdr *eth;
426     struct arp_pkt *arp;
427 
428     eth = (void *) (p->data - sizeof(struct eth_hdr));
429 
430     if ((arp = pktbuf_consume(p, sizeof(struct arp_pkt))) == NULL) {
431         return -1;
432     }
433 
434     switch (ntohs(arp->oper)) {
435         case ARP_OPER_REQUEST: {
436             pktbuf_t *rp;
437             struct eth_hdr *reth;
438             struct arp_pkt *rarp;
439 
440             if (memcmp(&arp->tpa, &minip_ip, sizeof(minip_ip)) == 0) {
441                 if ((rp = pktbuf_alloc()) == NULL) {
442                     break;
443                 }
444 
445                 reth = pktbuf_prepend(rp, sizeof(struct eth_hdr));
446                 rarp = pktbuf_append(rp, sizeof(struct arp_pkt));
447 
448                 // Eth header
449                 minip_build_mac_hdr(reth, eth->src_mac, ETH_TYPE_ARP);
450 
451                 // ARP packet
452                 rarp->oper = htons(ARP_OPER_REPLY);
453                 rarp->htype = htons(0x0001);
454                 rarp->ptype = htons(0x0800);
455                 rarp->hlen = 6;
456                 rarp->plen = 4;
457                 mac_addr_copy(rarp->sha, minip_mac);
458                 rarp->spa = minip_ip;
459                 mac_addr_copy(rarp->tha, arp->sha);
460                 rarp->tpa = arp->spa;
461 
462                 minip_tx_handler(minip_tx_arg, rp);
463             }
464         }
465         break;
466 
467         case ARP_OPER_REPLY: {
468             uint32_t addr;
469             memcpy(&addr, &arp->spa, sizeof(addr)); // unaligned word
470             arp_cache_update(addr, arp->sha);
471         }
472         break;
473     }
474 
475     return 0;
476 }
477 
dump_eth_packet(const struct eth_hdr * eth)478 static void dump_eth_packet(const struct eth_hdr *eth) {
479     printf("ETH src ");
480     dump_mac_address(eth->src_mac);
481     printf(" dst ");
482     dump_mac_address(eth->dst_mac);
483     printf(" type 0x%hx\n", htons(eth->type));
484 }
485 
minip_rx_driver_callback(pktbuf_t * p)486 void minip_rx_driver_callback(pktbuf_t *p) {
487     struct eth_hdr *eth;
488 
489     if ((eth = (void *) pktbuf_consume(p, sizeof(struct eth_hdr))) == NULL) {
490         return;
491     }
492 
493     if (LOCAL_TRACE) {
494         dump_eth_packet(eth);
495     }
496 
497     if (memcmp(eth->dst_mac, minip_mac, 6) != 0 &&
498             memcmp(eth->dst_mac, broadcast_mac, 6) != 0) {
499         /* not for us */
500         return;
501     }
502 
503     switch (htons(eth->type)) {
504         case ETH_TYPE_IPV4:
505             LTRACEF("ipv4 pkt\n");
506             handle_ipv4_packet(p, eth->src_mac);
507             break;
508 
509         case ETH_TYPE_ARP:
510             LTRACEF("arp pkt\n");
511             handle_arp_pkt(p);
512             break;
513     }
514 }
515 
dump_mac_address(const uint8_t * mac)516 void dump_mac_address(const uint8_t *mac) {
517     printf("%02x:%02x:%02x:%02x:%02x:%02x",
518            mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
519 }
520 
minip_parse_ipaddr(const char * ipaddr_str,size_t len)521 uint32_t minip_parse_ipaddr(const char *ipaddr_str, size_t len) {
522     uint8_t ip[4] = { 0, 0, 0, 0 };
523     uint8_t pos = 0, i = 0;
524 
525     while (pos < len) {
526         char c = ipaddr_str[pos];
527         if (c == '.') {
528             i++;
529         } else if (c == '\0') {
530             break;
531         } else {
532             ip[i] *= 10;
533             ip[i] += c - '0';
534         }
535         pos++;
536     }
537 
538     return IPV4_PACK(ip);
539 }
540 
541 // printf the ip address passed in
printip(uint32_t x)542 void printip(uint32_t x) {
543     union {
544         u32 u;
545         u8 b[4];
546     } ip;
547     ip.u = x;
548     printf("%d.%d.%d.%d", ip.b[0], ip.b[1], ip.b[2], ip.b[3]);
549 }
550 
printip_named(const char * s,uint32_t x)551 void printip_named(const char *s, uint32_t x) {
552     printf("%s ", s);
553     printip(x);
554 }
555 
556 // run static initialization
minip_init(uint level)557 static void minip_init(uint level) {
558     arp_cache_init();
559     net_timer_init();
560 }
561 
562 
563 LK_INIT_HOOK(minip, minip_init, LK_INIT_LEVEL_THREADING);
564