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 <lk/err.h>
13 #include <stdio.h>
14 #include <lk/debug.h>
15 #include <endian.h>
16 #include <errno.h>
17 #include <iovec.h>
18 #include <stdlib.h>
19 #include <string.h>
20 #include <lk/trace.h>
21 #include <malloc.h>
22 #include <lk/list.h>
23 #include <kernel/thread.h>
24
25 static struct list_node arp_list = LIST_INITIAL_VALUE(arp_list);
26
27 // TODO
28 // 1. Tear endian code out into something that flips words before/after tx/rx calls
29
30 #define LOCAL_TRACE 0
31 static uint32_t minip_ip = IPV4_NONE;
32 static uint32_t minip_netmask = IPV4_NONE;
33 static uint32_t minip_broadcast = IPV4_BCAST;
34 static uint32_t minip_gateway = IPV4_NONE;
35
36 static const uint8_t broadcast_mac[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
37 static uint8_t minip_mac[6] = {0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC};
38
39 static char minip_hostname[32] = "";
40
41 static void dump_mac_address(const uint8_t *mac);
42 static void dump_ipv4_addr(uint32_t addr);
43
minip_set_hostname(const char * name)44 void minip_set_hostname(const char *name) {
45 strlcpy(minip_hostname, name, sizeof(minip_hostname));
46 }
47
minip_get_hostname(void)48 const char *minip_get_hostname(void) {
49 return minip_hostname;
50 }
51
compute_broadcast_address(void)52 static void compute_broadcast_address(void) {
53 minip_broadcast = (minip_ip & minip_netmask) | (IPV4_BCAST & ~minip_netmask);
54 }
55
minip_get_macaddr(uint8_t * addr)56 void minip_get_macaddr(uint8_t *addr) {
57 mac_addr_copy(addr, minip_mac);
58 }
59
minip_set_macaddr(const uint8_t * addr)60 void minip_set_macaddr(const uint8_t *addr) {
61 mac_addr_copy(minip_mac, addr);
62 }
63
minip_get_ipaddr(void)64 uint32_t minip_get_ipaddr(void) {
65 return minip_ip;
66 }
67
minip_set_ipaddr(const uint32_t addr)68 void minip_set_ipaddr(const uint32_t addr) {
69 minip_ip = addr;
70 compute_broadcast_address();
71 }
72
gen_random_mac_address(uint8_t * mac_addr)73 void gen_random_mac_address(uint8_t *mac_addr) {
74 for (size_t i = 0; i < 6; i++) {
75 mac_addr[i] = rand() & 0xff;
76 }
77 /* unicast and locally administered */
78 mac_addr[0] &= ~(1<<0);
79 mac_addr[0] |= (1<<1);
80 }
81
82 /* This function is called by minip to send packets */
83 tx_func_t minip_tx_handler;
84 void *minip_tx_arg;
85
minip_init(tx_func_t tx_handler,void * tx_arg,uint32_t ip,uint32_t mask,uint32_t gateway)86 void minip_init(tx_func_t tx_handler, void *tx_arg,
87 uint32_t ip, uint32_t mask, uint32_t gateway) {
88 minip_tx_handler = tx_handler;
89 minip_tx_arg = tx_arg;
90
91 minip_ip = ip;
92 minip_netmask = mask;
93 minip_gateway = gateway;
94 compute_broadcast_address();
95
96 arp_cache_init();
97 net_timer_init();
98 }
99
ipv4_payload_len(struct ipv4_hdr * pkt)100 static uint16_t ipv4_payload_len(struct ipv4_hdr *pkt) {
101 return (pkt->len - ((pkt->ver_ihl >> 4) * 5));
102 }
103
minip_build_mac_hdr(struct eth_hdr * pkt,const uint8_t * dst,uint16_t type)104 void minip_build_mac_hdr(struct eth_hdr *pkt, const uint8_t *dst, uint16_t type) {
105 mac_addr_copy(pkt->dst_mac, dst);
106 mac_addr_copy(pkt->src_mac, minip_mac);
107 pkt->type = htons(type);
108 }
109
minip_build_ipv4_hdr(struct ipv4_hdr * ipv4,uint32_t dst,uint8_t proto,uint16_t len)110 void minip_build_ipv4_hdr(struct ipv4_hdr *ipv4, uint32_t dst, uint8_t proto, uint16_t len) {
111 ipv4->ver_ihl = 0x45;
112 ipv4->dscp_ecn = 0;
113 ipv4->len = htons(20 + len); // 5 * 4 from ihl, plus payload length
114 ipv4->id = 0;
115 ipv4->flags_frags = 0x40; // no offset, no fragments
116 ipv4->ttl = 64;
117 ipv4->proto = proto;
118 ipv4->dst_addr = dst;
119 ipv4->src_addr = minip_ip;
120
121 /* This may be unnecessary if the controller supports checksum offloading */
122 ipv4->chksum = 0;
123 ipv4->chksum = rfc1701_chksum((uint8_t *) ipv4, sizeof(struct ipv4_hdr));
124 }
125
send_arp_request(uint32_t addr)126 static int send_arp_request(uint32_t addr) {
127 pktbuf_t *p;
128 struct eth_hdr *eth;
129 struct arp_pkt *arp;
130
131 if ((p = pktbuf_alloc()) == NULL) {
132 return -1;
133 }
134
135 eth = pktbuf_prepend(p, sizeof(struct eth_hdr));
136 arp = pktbuf_append(p, sizeof(struct arp_pkt));
137 minip_build_mac_hdr(eth, bcast_mac, ETH_TYPE_ARP);
138
139 arp->htype = htons(0x0001);
140 arp->ptype = htons(0x0800);
141 arp->hlen = 6;
142 arp->plen = 4;
143 arp->oper = htons(ARP_OPER_REQUEST);
144 arp->spa = minip_ip;
145 arp->tpa = addr;
146 mac_addr_copy(arp->sha, minip_mac);
147 mac_addr_copy(arp->tha, bcast_mac);
148
149 minip_tx_handler(p);
150 return 0;
151 }
152
handle_arp_timeout_cb(void * arg)153 static void handle_arp_timeout_cb(void *arg) {
154 *(bool *)arg = true;
155 }
156
get_dest_mac(uint32_t host)157 const uint8_t *get_dest_mac(uint32_t host) {
158 uint8_t *dst_mac = NULL;
159 bool arp_timeout = false;
160 net_timer_t arp_timeout_timer;
161
162 if (host == IPV4_BCAST) {
163 return bcast_mac;
164 }
165
166 dst_mac = arp_cache_lookup(host);
167 if (dst_mac == NULL) {
168 send_arp_request(host);
169 memset(&arp_timeout_timer, 0, sizeof(arp_timeout_timer));
170 net_timer_set(&arp_timeout_timer, handle_arp_timeout_cb, &arp_timeout, 100);
171 while (!arp_timeout) {
172 dst_mac = arp_cache_lookup(host);
173 if (dst_mac) {
174 net_timer_cancel(&arp_timeout_timer);
175 break;
176 }
177 }
178 }
179
180 return dst_mac;
181 }
182
minip_ipv4_send(pktbuf_t * p,uint32_t dest_addr,uint8_t proto)183 status_t minip_ipv4_send(pktbuf_t *p, uint32_t dest_addr, uint8_t proto) {
184 status_t ret = 0;
185 size_t data_len = p->dlen;
186 const uint8_t *dst_mac;
187
188 struct ipv4_hdr *ip = pktbuf_prepend(p, sizeof(struct ipv4_hdr));
189 struct eth_hdr *eth = pktbuf_prepend(p, sizeof(struct eth_hdr));
190
191
192 if (dest_addr == IPV4_BCAST || dest_addr == minip_broadcast) {
193 dst_mac = bcast_mac;
194 goto ready;
195 }
196
197 dst_mac = get_dest_mac(dest_addr);
198 if (!dst_mac) {
199 pktbuf_free(p, true);
200 ret = -EHOSTUNREACH;
201 goto err;
202 }
203
204 ready:
205 minip_build_mac_hdr(eth, dst_mac, ETH_TYPE_IPV4);
206 minip_build_ipv4_hdr(ip, dest_addr, proto, data_len);
207
208 minip_tx_handler(p);
209
210 err:
211 return ret;
212 }
213
214 /* Swap the dst/src ip addresses and send an ICMP ECHO REPLY with the same payload.
215 * According to spec the data portion doesn't matter, but ping itself validates that
216 * the payload is identical
217 */
send_ping_reply(uint32_t ipaddr,struct icmp_pkt * req,size_t reqdatalen)218 static void send_ping_reply(uint32_t ipaddr, struct icmp_pkt *req, size_t reqdatalen) {
219 pktbuf_t *p;
220 size_t len;
221 struct eth_hdr *eth;
222 struct ipv4_hdr *ip;
223 struct icmp_pkt *icmp;
224
225 if ((p = pktbuf_alloc()) == NULL) {
226 return;
227 }
228
229 icmp = pktbuf_prepend(p, sizeof(struct icmp_pkt));
230 ip = pktbuf_prepend(p, sizeof(struct ipv4_hdr));
231 eth = pktbuf_prepend(p, sizeof(struct eth_hdr));
232 pktbuf_append_data(p, req->data, reqdatalen);
233
234 len = sizeof(struct icmp_pkt) + reqdatalen;
235
236 minip_build_mac_hdr(eth, arp_cache_lookup(ipaddr), ETH_TYPE_IPV4);
237 minip_build_ipv4_hdr(ip, ipaddr, IP_PROTO_ICMP, len);
238
239 icmp->type = ICMP_ECHO_REPLY;
240 icmp->code = 0;
241 memcpy(icmp->hdr_data, req->hdr_data, sizeof(icmp->hdr_data));
242 icmp->chksum = 0;
243 icmp->chksum = rfc1701_chksum((uint8_t *) icmp, len);
244
245 minip_tx_handler(p);
246 }
247
dump_ipv4_addr(uint32_t addr)248 static void dump_ipv4_addr(uint32_t addr) {
249 const uint8_t *a = (void *)&addr;
250
251 printf("%hhu.%hhu.%hhu.%hhu", a[0], a[1], a[2], a[3]);
252 }
253
dump_ipv4_packet(const struct ipv4_hdr * ip)254 static void dump_ipv4_packet(const struct ipv4_hdr *ip) {
255 printf("IP ");
256 dump_ipv4_addr(ip->src_addr);
257 printf(" -> ");
258 dump_ipv4_addr(ip->dst_addr);
259 printf(" hlen 0x%x, prot 0x%x, cksum 0x%x, len 0x%x, ident 0x%x, frag offset 0x%x\n",
260 (ip->ver_ihl & 0xf) * 4, ip->proto, ntohs(ip->chksum), ntohs(ip->len), ntohs(ip->id), ntohs(ip->flags_frags) & 0x1fff);
261 }
262
handle_ipv4_packet(pktbuf_t * p,const uint8_t * src_mac)263 __NO_INLINE static void handle_ipv4_packet(pktbuf_t *p, const uint8_t *src_mac) {
264 struct ipv4_hdr *ip;
265
266 ip = (struct ipv4_hdr *)p->data;
267 if (p->dlen < sizeof(struct ipv4_hdr))
268 return;
269
270 /* print packets for us */
271 if (LOCAL_TRACE) {
272 dump_ipv4_packet(ip);
273 }
274
275 /* reject bad packets */
276 if (((ip->ver_ihl >> 4) & 0xf) != 4) {
277 /* not version 4 */
278 LTRACEF("REJECT: not version 4\n");
279 return;
280 }
281
282 /* do we have enough buffer to hold the full header + options? */
283 size_t header_len = (ip->ver_ihl & 0xf) * 4;
284 if (p->dlen < header_len) {
285 LTRACEF("REJECT: not enough buffer to hold header\n");
286 return;
287 }
288
289 /* compute checksum */
290 if (rfc1701_chksum((void *)ip, header_len) != 0) {
291 /* bad checksum */
292 LTRACEF("REJECT: bad checksum\n");
293 return;
294 }
295
296 /* is the pkt_buf large enough to hold the length the header says the packet is? */
297 if (htons(ip->len) > p->dlen) {
298 LTRACEF("REJECT: packet exceeds size of buffer (header %d, dlen %d)\n", htons(ip->len), p->dlen);
299 return;
300 }
301
302 /* trim any excess bytes at the end of the packet */
303 if (p->dlen > htons(ip->len)) {
304 pktbuf_consume_tail(p, p->dlen - htons(ip->len));
305 }
306
307 /* remove the header from the front of the packet_buf */
308 if (pktbuf_consume(p, header_len) == NULL) {
309 return;
310 }
311
312 /* the packet is good, we can use it to populate our arp cache */
313 arp_cache_update(ip->src_addr, src_mac);
314
315 /* see if it's for us */
316 if (ip->dst_addr != IPV4_BCAST) {
317 if (minip_ip != IPV4_NONE && ip->dst_addr != minip_ip && ip->dst_addr != minip_broadcast) {
318 LTRACEF("REJECT: for another host\n");
319 return;
320 }
321 }
322
323 /* We only handle UDP and ECHO REQUEST */
324 switch (ip->proto) {
325 case IP_PROTO_ICMP: {
326 struct icmp_pkt *icmp;
327 if ((icmp = pktbuf_consume(p, sizeof(struct icmp_pkt))) == NULL) {
328 break;
329 }
330 if (icmp->type == ICMP_ECHO_REQUEST) {
331 send_ping_reply(ip->src_addr, icmp, p->dlen);
332 }
333 }
334 break;
335
336 case IP_PROTO_UDP:
337 udp_input(p, ip->src_addr);
338 break;
339
340 case IP_PROTO_TCP:
341 tcp_input(p, ip->src_addr, ip->dst_addr);
342 break;
343 }
344 }
345
handle_arp_pkt(pktbuf_t * p)346 __NO_INLINE static int handle_arp_pkt(pktbuf_t *p) {
347 struct eth_hdr *eth;
348 struct arp_pkt *arp;
349
350 eth = (void *) (p->data - sizeof(struct eth_hdr));
351
352 if ((arp = pktbuf_consume(p, sizeof(struct arp_pkt))) == NULL) {
353 return -1;
354 }
355
356 switch (ntohs(arp->oper)) {
357 case ARP_OPER_REQUEST: {
358 pktbuf_t *rp;
359 struct eth_hdr *reth;
360 struct arp_pkt *rarp;
361
362 if (memcmp(&arp->tpa, &minip_ip, sizeof(minip_ip)) == 0) {
363 if ((rp = pktbuf_alloc()) == NULL) {
364 break;
365 }
366
367 reth = pktbuf_prepend(rp, sizeof(struct eth_hdr));
368 rarp = pktbuf_append(rp, sizeof(struct arp_pkt));
369
370 // Eth header
371 minip_build_mac_hdr(reth, eth->src_mac, ETH_TYPE_ARP);
372
373 // ARP packet
374 rarp->oper = htons(ARP_OPER_REPLY);
375 rarp->htype = htons(0x0001);
376 rarp->ptype = htons(0x0800);
377 rarp->hlen = 6;
378 rarp->plen = 4;
379 mac_addr_copy(rarp->sha, minip_mac);
380 rarp->spa = minip_ip;
381 mac_addr_copy(rarp->tha, arp->sha);
382 rarp->tpa = arp->spa;
383
384 minip_tx_handler(rp);
385 }
386 }
387 break;
388
389 case ARP_OPER_REPLY: {
390 uint32_t addr;
391 memcpy(&addr, &arp->spa, sizeof(addr)); // unaligned word
392 arp_cache_update(addr, arp->sha);
393 }
394 break;
395 }
396
397 return 0;
398 }
399
dump_mac_address(const uint8_t * mac)400 static void dump_mac_address(const uint8_t *mac) {
401 printf("%02x:%02x:%02x:%02x:%02x:%02x",
402 mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
403 }
404
dump_eth_packet(const struct eth_hdr * eth)405 static void dump_eth_packet(const struct eth_hdr *eth) {
406 printf("ETH src ");
407 dump_mac_address(eth->src_mac);
408 printf(" dst ");
409 dump_mac_address(eth->dst_mac);
410 printf(" type 0x%hx\n", htons(eth->type));
411 }
412
minip_rx_driver_callback(pktbuf_t * p)413 void minip_rx_driver_callback(pktbuf_t *p) {
414 struct eth_hdr *eth;
415
416 if ((eth = (void *) pktbuf_consume(p, sizeof(struct eth_hdr))) == NULL) {
417 return;
418 }
419
420 if (LOCAL_TRACE) {
421 dump_eth_packet(eth);
422 }
423
424 if (memcmp(eth->dst_mac, minip_mac, 6) != 0 &&
425 memcmp(eth->dst_mac, broadcast_mac, 6) != 0) {
426 /* not for us */
427 return;
428 }
429
430 switch (htons(eth->type)) {
431 case ETH_TYPE_IPV4:
432 LTRACEF("ipv4 pkt\n");
433 handle_ipv4_packet(p, eth->src_mac);
434 break;
435
436 case ETH_TYPE_ARP:
437 LTRACEF("arp pkt\n");
438 handle_arp_pkt(p);
439 break;
440 }
441 }
442
minip_parse_ipaddr(const char * ipaddr_str,size_t len)443 uint32_t minip_parse_ipaddr(const char *ipaddr_str, size_t len) {
444 uint8_t ip[4] = { 0, 0, 0, 0 };
445 uint8_t pos = 0, i = 0;
446
447 while (pos < len) {
448 char c = ipaddr_str[pos];
449 if (c == '.') {
450 i++;
451 } else if (c == '\0') {
452 break;
453 } else {
454 ip[i] *= 10;
455 ip[i] += c - '0';
456 }
457 pos++;
458 }
459
460 return IPV4_PACK(ip);
461 }
462