|
|
1.1 root 1: /******************************************************************************
2: * Copyright (c) 2004, 2008 IBM Corporation
3: * All rights reserved.
4: * This program and the accompanying materials
5: * are made available under the terms of the BSD License
6: * which accompanies this distribution, and is available at
7: * http://www.opensource.org/licenses/bsd-license.php
8: *
9: * Contributors:
10: * IBM Corporation - initial implementation
11: *****************************************************************************/
12:
13:
14: /*>>>>>>>>>>>>>>>>>>>>> DEFINITIONS & DECLARATIONS <<<<<<<<<<<<<<<<<<<<<<*/
15:
16: #include <ipv4.h>
17: #include <udp.h>
18: #include <tcp.h>
19: #include <ethernet.h>
20: #include <sys/socket.h>
21: #include <string.h>
22:
23: /* ARP Message types */
24: #define ARP_REQUEST 1
25: #define ARP_REPLY 2
26:
27: /* ARP talbe size (+1) */
28: #define ARP_ENTRIES 10
29:
30: /* ICMP Message types */
31: #define ICMP_ECHO_REPLY 0
32: #define ICMP_DST_UNREACHABLE 3
33: #define ICMP_SRC_QUENCH 4
34: #define ICMP_REDIRECT 5
35: #define ICMP_ECHO_REQUEST 8
36: #define ICMP_TIME_EXCEEDED 11
37: #define ICMP_PARAMETER_PROBLEM 12
38: #define ICMP_TIMESTAMP_REQUEST 13
39: #define ICMP_TIMESTAMP_REPLY 14
40: #define ICMP_INFORMATION_REQUEST 15
41: #define ICMP_INFORMATION_REPLY 16
42:
43: /** \struct arp_entry
44: * A entry that describes a mapping between IPv4- and MAC-address.
45: */
46: typedef struct arp_entry arp_entry_t;
47: struct arp_entry {
48: uint32_t ipv4_addr;
49: uint8_t mac_addr[6];
50: uint8_t eth_frame[ETH_MTU_SIZE];
51: int eth_len;
52: };
53:
54: /** \struct icmphdr
55: * ICMP packet
56: */
57: struct icmphdr {
58: unsigned char type;
59: unsigned char code;
60: unsigned short int checksum;
61: union {
62: /* for type 3 "Destination Unreachable" */
63: unsigned int unused;
64: /* for type 0 and 8 */
65: struct echo {
66: unsigned short int id;
67: unsigned short int seq;
68: } echo;
69: } options;
70: union {
71: /* payload for destination unreachable */
72: struct dun {
73: unsigned char iphdr[20];
74: unsigned char data[64];
75: } dun;
76: /* payload for echo or echo reply */
77: /* maximum size supported is 84 */
78: unsigned char data[84];
79: } payload;
80: };
81:
82: /*>>>>>>>>>>>>>>>>>>>>>>>>>>>>> PROTOTYPES <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<*/
83:
84: static unsigned short
85: checksum(unsigned short *packet, int words);
86:
87: static void
88: arp_send_request(uint32_t dest_ip);
89:
90: static void
91: arp_send_reply(uint32_t src_ip, uint8_t * src_mac);
92:
93: static void
94: fill_arphdr(uint8_t * packet, uint8_t opcode,
95: const uint8_t * src_mac, uint32_t src_ip,
96: const uint8_t * dest_mac, uint32_t dest_ip);
97:
98: static arp_entry_t*
99: lookup_mac_addr(uint32_t ipv4_addr);
100:
101: static void
102: fill_udp_checksum(struct iphdr *ipv4_hdr);
103:
104: static int8_t
105: handle_icmp(struct iphdr * iph, uint8_t * packet, int32_t packetsize);
106:
107: /*>>>>>>>>>>>>>>>>>>>>>>>>>>>>> LOCAL VARIABLES <<<<<<<<<<<<<<<<<<<<<<<<<*/
108:
109: /* Routing parameters */
110: static uint32_t own_ip = 0;
111: static uint32_t multicast_ip = 0;
112: static uint32_t router_ip = 0;
113: static uint32_t subnet_mask = 0;
114:
115: /* helper variables */
116: static uint32_t ping_dst_ip;
117: static const uint8_t null_mac_addr[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
118: static const uint8_t broadcast_mac[] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
119: static uint8_t multicast_mac[] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
120:
121: /* There are only (ARP_ENTRIES-1) effective entries because
122: * the entry that is pointed by arp_producer is never used.
123: */
124: static unsigned int arp_consumer = 0;
125: static unsigned int arp_producer = 0;
126: static arp_entry_t arp_table[ARP_ENTRIES];
127:
128: /* Function pointer send_ip. Points either to send_ipv4() or send_ipv6() */
129: int (*send_ip) (void *, int);
130:
131: /*>>>>>>>>>>>>>>>>>>>>>>>>>>>> IMPLEMENTATION <<<<<<<<<<<<<<<<<<<<<<<<<<<*/
132:
133: /**
134: * IPv4: Initialize the environment for the IPv4 layer.
135: */
136: static void
137: ipv4_init(void)
138: {
139: int i;
140:
141: ping_dst_ip = 0;
142:
143: // clear ARP table
144: arp_consumer = 0;
145: arp_producer = 0;
146: for(i=0; i<ARP_ENTRIES; ++i) {
147: arp_table[i].ipv4_addr = 0;
148: memset(arp_table[i].mac_addr, 0, 6);
149: arp_table[i].eth_len = 0;
150: }
151:
152: /* Set IP send function to send_ipv4() */
153: send_ip = &send_ipv4;
154: }
155:
156: /**
157: * IPv4: Set the own IPv4 address.
158: *
159: * @param _own_ip client IPv4 address (e.g. 127.0.0.1)
160: */
161: void
162: set_ipv4_address(uint32_t _own_ip)
163: {
164: own_ip = _own_ip;
165: ipv4_init();
166: }
167:
168: /**
169: * IPv4: Get the own IPv4 address.
170: *
171: * @return client IPv4 address (e.g. 127.0.0.1)
172: */
173: uint32_t
174: get_ipv4_address(void)
175: {
176: return own_ip;
177: }
178:
179: /**
180: * IPv4: Set the IPv4 multicast address.
181: *
182: * @param _own_ip multicast IPv4 address (224.0.0.0 - 239.255.255.255)
183: */
184: void
185: set_ipv4_multicast(uint32_t _multicast_ip)
186: {
187: // is this IP Multicast out of range (224.0.0.0 - 239.255.255.255)
188: if((htonl(_multicast_ip) < 0xE0000000)
189: || (htonl(_multicast_ip) > 0xEFFFFFFF)) {
190: multicast_ip = 0;
191: memset(multicast_mac, 0xFF, 6);
192: return;
193: }
194:
195: multicast_ip = _multicast_ip;
196: multicast_mac[0] = 0x01;
197: multicast_mac[1] = 0x00;
198: multicast_mac[2] = 0x5E;
199: multicast_mac[3] = (uint8_t) 0x7F & (multicast_ip >> 16);
200: multicast_mac[4] = (uint8_t) 0xFF & (multicast_ip >> 8);
201: multicast_mac[5] = (uint8_t) 0xFF & (multicast_ip >> 0);
202: }
203:
204: /**
205: * IPv4: Get the IPv4 multicast address.
206: *
207: * @return multicast IPv4 address (224.0.0.0 - 239.255.255.255 or 0 if not set)
208: */
209: uint32_t
210: get_ipv4_multicast(void)
211: {
212: return multicast_ip;
213: }
214:
215: /**
216: * IPv4: Set the routers IPv4 address.
217: *
218: * @param _router_ip router IPv4 address
219: */
220: void
221: set_ipv4_router(uint32_t _router_ip)
222: {
223: router_ip = _router_ip;
224: ipv4_init();
225: }
226:
227: /**
228: * IPv4: Get the routers IPv4 address.
229: *
230: * @return router IPv4 address
231: */
232: uint32_t
233: get_ipv4_router(void)
234: {
235: return router_ip;
236: }
237:
238: /**
239: * IPv4: Set the subnet mask.
240: *
241: * @param _subnet_mask netmask of the own IPv4 address
242: */
243: void
244: set_ipv4_netmask(uint32_t _subnet_mask)
245: {
246: subnet_mask = _subnet_mask;
247: ipv4_init();
248: }
249:
250: /**
251: * IPv4: Get the subnet mask.
252: *
253: * @return netmask of the own IPv4 address
254: */
255: uint32_t
256: get_ipv4_netmask(void)
257: {
258: return subnet_mask;
259: }
260:
261: /**
262: * IPv4: Creates IP-packet. Places IP-header in a packet and fills it
263: * with corresponding information.
264: * <p>
265: * Use this function with similar functions for other network layers
266: * (fill_ethhdr, fill_udphdr, fill_dnshdr, fill_btphdr).
267: *
268: * @param packet Points to the place where IP-header must be placed.
269: * @param packetsize Size of the packet in bytes incl. this hdr and data.
270: * @param ip_proto Type of the next level protocol (e.g. UDP).
271: * @param ip_src Sender IP address
272: * @param ip_dst Receiver IP address
273: * @see iphdr
274: * @see fill_ethhdr
275: * @see fill_udphdr
276: * @see fill_dnshdr
277: * @see fill_btphdr
278: */
279: void
280: fill_iphdr(uint8_t * packet, uint16_t packetsize,
281: uint8_t ip_proto, uint32_t ip_src, uint32_t ip_dst) {
282: struct iphdr * iph = (struct iphdr *) packet;
283:
284: iph -> ip_hlv = 0x45;
285: iph -> ip_tos = 0x10;
286: iph -> ip_len = htons(packetsize);
287: iph -> ip_id = htons(0);
288: iph -> ip_off = 0;
289: iph -> ip_ttl = 0xFF;
290: iph -> ip_p = ip_proto;
291: iph -> ip_src = htonl(ip_src);
292: iph -> ip_dst = htonl(ip_dst);
293: iph -> ip_sum = 0;
294: }
295:
296: /**
297: * IPv4: Handles IPv4-packets according to Receive-handle diagram.
298: *
299: * @param ip_packet IP-packet to be handled
300: * @param packetsize Length of the packet
301: * @return ZERO - packet handled successfully;
302: * NON ZERO - packet was not handled (e.g. bad format)
303: * @see receive_ether
304: * @see iphdr
305: */
306: int8_t
307: handle_ipv4(uint8_t * ip_packet, int32_t packetsize)
308: {
309: struct iphdr * iph;
310: int32_t old_sum;
311: static uint8_t ip_heap[65536 + ETH_MTU_SIZE];
312:
313: if (packetsize < sizeof(struct iphdr))
314: return -1; // packet is too small
315:
316: iph = (struct iphdr * ) ip_packet;
317:
318: /* Drop it if destination IPv4 address is no IPv4 Broadcast, no
319: * registered IPv4 Multicast and not our Unicast address
320: */
321: if((multicast_ip == 0 && iph->ip_dst >= 0xE0000000 && iph->ip_dst <= 0xEFFFFFFF)
322: || (multicast_ip != iph->ip_dst && iph->ip_dst != 0xFFFFFFFF &&
323: own_ip != 0 && iph->ip_dst != own_ip)) {
324: return -1;
325: }
326:
327: old_sum = iph -> ip_sum;
328: iph -> ip_sum = 0;
329: if (old_sum != checksum((uint16_t *) iph, sizeof (struct iphdr) >> 1))
330: return -1; // Wrong IP checksum
331:
332: // is it the first fragment in a packet?
333: if (((iph -> ip_off) & 0x1FFF) == 0) {
334: // is it part of more fragments?
335: if (((iph -> ip_off) & 0x2000) == 0x2000) {
336: memcpy(ip_heap, ip_packet, iph->ip_len);
337: return 0;
338: }
339: }
340: // it's not the first fragment
341: else {
342: // get the first fragment
343: struct iphdr * iph_first = (struct iphdr * ) ip_heap;
344:
345: // is this fragment not part of the first one, then exit
346: if ((iph_first->ip_id != iph->ip_id ) ||
347: (iph_first->ip_p != iph->ip_p ) ||
348: (iph_first->ip_src != iph->ip_src) ||
349: (iph_first->ip_dst != iph->ip_dst)) {
350: return 0;
351: }
352:
353: // this fragment is part of the first one!
354: memcpy(ip_heap + sizeof(struct iphdr) +
355: ((iph -> ip_off) & 0x1FFF) * 8,
356: ip_packet + sizeof(struct iphdr),
357: iph -> ip_len - sizeof(struct iphdr));
358:
359: // is it part of more fragments? Then return.
360: if (((iph -> ip_off) & 0x2000) == 0x2000) {
361: return 0;
362: }
363:
364: // packet is completly reassambled now!
365:
366: // recalculate ip_len and set iph and ip_packet to the
367: iph_first->ip_len = iph->ip_len + ((iph->ip_off) & 0x1FFF) * 8;
368:
369: // set iph and ip_packet to the resulting packet.
370: ip_packet = ip_heap;
371: iph = (struct iphdr * ) ip_packet;
372: }
373:
374: switch (iph -> ip_p) {
375: case IPTYPE_ICMP:
376: return handle_icmp(iph, ip_packet + sizeof(struct iphdr),
377: iph -> ip_len - sizeof(struct iphdr));
378: case IPTYPE_UDP:
379: return handle_udp(ip_packet + sizeof(struct iphdr),
380: iph -> ip_len - sizeof(struct iphdr));
381: case IPTYPE_TCP:
382: return handle_tcp(ip_packet + sizeof(struct iphdr),
383: iph -> ip_len - sizeof(struct iphdr));
384: default:
385: break;
386: }
387: return -1; // Unknown protocol
388: }
389:
390: /**
391: * IPv4: Send IPv4-packets.
392: *
393: * Before the packet is sent there are some patcches performed:
394: * - IPv4 source address is replaced by our unicast IPV4 address
395: * if it is set to 0 or 1
396: * - IPv4 destination address is replaced by our multicast IPV4 address
397: * if it is set to 1
398: * - IPv4 checksum is calculaded.
399: * - If payload type is UDP, then the UDP checksum is calculated also.
400: *
401: * We sent an ARP request first, if this is the first packet sent to
402: * the declared IPv4 destination address. In this case we store the
403: * the packet and sent it later if we receive the ARP response.
404: * If the MAC address is known already, then we send the packet immediatly.
405: * If there is already an ARP request pending, then we drop this packet
406: * and send again an ARP request.
407: *
408: * @param ip_packet IP-packet to be handled
409: * @param packetsize Length of the packet
410: * @return -2 - packet dropped (MAC address not resolved - ARP request pending)
411: * -1 - packet dropped (bad format)
412: * 0 - packet stored (ARP request sent - packet will be sent if
413: * ARP response is received)
414: * >0 - packet send (number of transmitted bytes is returned)
415: *
416: * @see receive_ether
417: * @see iphdr
418: */
419: int
420: send_ipv4(void* buffer, int len)
421: {
422: arp_entry_t *arp_entry;
423: struct iphdr *ip;
424: const uint8_t *mac_addr = 0;
425:
426: if(len + sizeof(struct ethhdr) > ETH_MTU_SIZE)
427: return -1;
428:
429: ip = (struct iphdr *) buffer;
430:
431: /* Replace source IPv4 address with our own unicast IPv4 address
432: * if it's 0 (= own unicast source address not specified).
433: */
434: if(ip->ip_src == 0) {
435: ip->ip_src = htonl( own_ip );
436: }
437: /* Replace source IPv4 address with our unicast IPv4 address and
438: * replace destination IPv4 address with our multicast IPv4 address
439: * if source address is set to 1.
440: */
441: else if(ip->ip_src == 1) {
442: ip->ip_src = htonl( own_ip );
443: ip->ip_dst = htonl( multicast_ip );
444: }
445:
446: // Calculate the IPv4 checksum
447: ip->ip_sum = 0;
448: ip->ip_sum = checksum((uint16_t *) ip, sizeof (struct iphdr) >> 1);
449:
450: // if payload type is UDP, then we need to calculate the
451: // UDP checksum that depends on the IP header
452: if(ip->ip_p == IPTYPE_UDP) {
453: fill_udp_checksum(ip);
454: }
455:
456: // Check if the MAC address is already cached
457: if(~ip->ip_dst == 0
458: || ( ((~subnet_mask) & ip->ip_dst) == ~subnet_mask &&
459: ( subnet_mask & ip->ip_dst) == (subnet_mask & own_ip))) {
460: arp_entry = &arp_table[arp_producer];
461: mac_addr = broadcast_mac;
462: }
463: else if(ip->ip_dst == multicast_ip) {
464: arp_entry = &arp_table[arp_producer];
465: mac_addr = multicast_mac;
466: }
467: else {
468: // Check if IP address is in the same subnet as we are
469: if((subnet_mask & own_ip) == (subnet_mask & ip->ip_dst))
470: arp_entry = lookup_mac_addr(ip->ip_dst);
471: // if not then we need to know the router's IP address
472: else
473: arp_entry = lookup_mac_addr(router_ip);
474: if(arp_entry && memcmp(arp_entry->mac_addr, null_mac_addr, 6) != 0)
475: mac_addr = arp_entry->mac_addr;
476: }
477:
478: // If we could not resolv the MAC address by our own...
479: if(!mac_addr) {
480: // send the ARP request
481: arp_send_request(ip->ip_dst);
482:
483: // drop the current packet if there is already a ARP request pending
484: if(arp_entry)
485: return -2;
486:
487: // take the next entry in the ARP table to prepare a the new ARP entry.
488: arp_entry = &arp_table[arp_producer];
489: arp_producer = (arp_producer+1)%ARP_ENTRIES;
490:
491: // if ARP table is full then we must drop the oldes entry.
492: if(arp_consumer == arp_producer)
493: arp_consumer = (arp_consumer+1)%ARP_ENTRIES;
494:
495: // store the packet to be send if the ARP reply is received
496: arp_entry->ipv4_addr = ip->ip_dst;
497: memset(arp_entry->mac_addr, 0, 6);
498: fill_ethhdr (arp_entry->eth_frame, htons(ETHERTYPE_IP),
499: get_mac_address(), null_mac_addr);
500: memcpy(&arp_entry->eth_frame[sizeof(struct ethhdr)],
501: buffer, len);
502: arp_entry->eth_len = len + sizeof(struct ethhdr);
503:
504: return 0;
505: }
506:
507: // Send the packet with the known MAC address
508: fill_ethhdr(arp_entry->eth_frame, htons(ETHERTYPE_IP),
509: get_mac_address(), mac_addr);
510: memcpy(&arp_entry->eth_frame[sizeof(struct ethhdr)], buffer, len);
511: return send_ether(arp_entry->eth_frame, len + sizeof(struct ethhdr));
512: }
513:
514: /**
515: * IPv4: Calculate UDP checksum. Places the result into the UDP-header.
516: * <p>
517: * Use this function after filling the UDP payload.
518: *
519: * @param ipv4_hdr Points to the place where IPv4-header starts.
520: */
521:
522: static void
523: fill_udp_checksum(struct iphdr *ipv4_hdr)
524: {
525: int i;
526: unsigned long checksum = 0;
527: struct iphdr ip_hdr;
528: char *ptr;
529: udp_hdr_t *udp_hdr;
530:
531: udp_hdr = (udp_hdr_t *) (ipv4_hdr + 1);
532: udp_hdr->uh_sum = 0;
533:
534: memset(&ip_hdr, 0, sizeof(struct iphdr));
535: ip_hdr.ip_src = ipv4_hdr->ip_src;
536: ip_hdr.ip_dst = ipv4_hdr->ip_dst;
537: ip_hdr.ip_len = udp_hdr->uh_ulen;
538: ip_hdr.ip_p = ipv4_hdr->ip_p;
539:
540: ptr = (char*) udp_hdr;
541: for (i = 0; i < udp_hdr->uh_ulen; i+=2)
542: checksum += *((uint16_t*) &ptr[i]);
543:
544: ptr = (char*) &ip_hdr;
545: for (i = 0; i < sizeof(struct iphdr); i+=2)
546: checksum += *((uint16_t*) &ptr[i]);
547:
548: checksum = (checksum >> 16) + (checksum & 0xffff);
549: checksum += (checksum >> 16);
550: udp_hdr->uh_sum = ~checksum;
551: }
552:
553: /**
554: * IPv4: Calculates checksum for IP header.
555: *
556: * @param packet Points to the IP-header
557: * @param words Size of the packet in words incl. IP-header and data.
558: * @return Checksum
559: * @see iphdr
560: */
561: static unsigned short
562: checksum(unsigned short * packet, int words)
563: {
564: unsigned long checksum;
565:
566: for (checksum = 0; words > 0; words--)
567: checksum += *packet++;
568: checksum = (checksum >> 16) + (checksum & 0xffff);
569: checksum += (checksum >> 16);
570:
571: return ~checksum;
572: }
573:
574: static arp_entry_t*
575: lookup_mac_addr(uint32_t ipv4_addr)
576: {
577: unsigned int i;
578:
579: for(i=arp_consumer; i != arp_producer; i = ((i+1)%ARP_ENTRIES) ) {
580: if(arp_table[i].ipv4_addr == ipv4_addr)
581: return &arp_table[i];
582: }
583: return 0;
584: }
585:
586:
587: /**
588: * ARP: Sends an ARP-request package.
589: * For given IPv4 retrieves MAC via ARP (makes several attempts)
590: *
591: * @param dest_ip IP of the host which MAC should be obtained
592: */
593: static void
594: arp_send_request(uint32_t dest_ip)
595: {
596: arp_entry_t *arp_entry = &arp_table[arp_producer];
597:
598: memset(arp_entry->eth_frame, 0, sizeof(struct ethhdr) + sizeof(struct arphdr));
599: fill_arphdr(&arp_entry->eth_frame[sizeof(struct ethhdr)], ARP_REQUEST,
600: get_mac_address(), own_ip, broadcast_mac, dest_ip);
601: fill_ethhdr(arp_entry->eth_frame, ETHERTYPE_ARP,
602: get_mac_address(), broadcast_mac);
603:
604: send_ether(arp_entry->eth_frame,
605: sizeof(struct ethhdr) + sizeof(struct arphdr));
606: }
607:
608: /**
609: * ARP: Sends an ARP-reply package.
610: * This package is used to serve foreign requests (in case IP in
611: * foreign request matches our host IP).
612: *
613: * @param src_ip requester IP address (foreign IP)
614: * @param src_mac requester MAC address (foreign MAC)
615: */
616: static void
617: arp_send_reply(uint32_t src_ip, uint8_t * src_mac)
618: {
619: arp_entry_t *arp_entry = &arp_table[arp_producer];
620:
621: memset(arp_entry->eth_frame, 0, sizeof(struct ethhdr) + sizeof(struct arphdr));
622: fill_ethhdr(arp_entry->eth_frame, ETHERTYPE_ARP,
623: get_mac_address(), src_mac);
624: fill_arphdr(&arp_entry->eth_frame[sizeof(struct ethhdr)], ARP_REPLY,
625: get_mac_address(), own_ip, src_mac, src_ip);
626:
627: send_ether(arp_entry->eth_frame,
628: sizeof(struct ethhdr) + sizeof(struct arphdr));
629: }
630:
631: /**
632: * ARP: Creates ARP package. Places ARP-header in a packet and fills it
633: * with corresponding information.
634: * <p>
635: * Use this function with similar functions for other network layers
636: * (fill_ethhdr).
637: *
638: * @param packet Points to the place where ARP-header must be placed.
639: * @param opcode Identifies is it request (ARP_REQUEST)
640: * or reply (ARP_REPLY) package.
641: * @param src_mac sender MAC address
642: * @param src_ip sender IP address
643: * @param dest_mac receiver MAC address
644: * @param dest_ip receiver IP address
645: * @see arphdr
646: * @see fill_ethhdr
647: */
648: static void
649: fill_arphdr(uint8_t * packet, uint8_t opcode,
650: const uint8_t * src_mac, uint32_t src_ip,
651: const uint8_t * dest_mac, uint32_t dest_ip)
652: {
653: struct arphdr * arph = (struct arphdr *) packet;
654:
655: arph -> hw_type = htons(1);
656: arph -> proto_type = htons(ETHERTYPE_IP);
657: arph -> hw_len = 6;
658: arph -> proto_len = 4;
659: arph -> opcode = htons(opcode);
660:
661: memcpy(arph->src_mac, src_mac, 6);
662: arph->src_ip = htonl(src_ip);
663: memcpy(arph->dest_mac, dest_mac, 6);
664: arph->dest_ip = htonl(dest_ip);
665: }
666:
667: /**
668: * ARP: Handles ARP-messages according to Receive-handle diagram.
669: * Updates arp_table for outstanding ARP requests (see arp_getmac).
670: *
671: * @param packet ARP-packet to be handled
672: * @param packetsize length of the packet
673: * @return ZERO - packet handled successfully;
674: * NON ZERO - packet was not handled (e.g. bad format)
675: * @see arp_getmac
676: * @see receive_ether
677: * @see arphdr
678: */
679: int8_t
680: handle_arp(uint8_t * packet, int32_t packetsize)
681: {
682: struct arphdr * arph = (struct arphdr *) packet;
683:
684: if (packetsize < sizeof(struct arphdr))
685: return -1; // Packet is too small
686:
687: if (arph -> hw_type != htons(1) || arph -> proto_type != htons(ETHERTYPE_IP))
688: return -1; // Unknown hardware or unsupported protocol
689:
690: if (arph -> dest_ip != htonl(own_ip))
691: return -1; // receiver IP doesn't match our IP
692:
693: switch(htons(arph -> opcode)) {
694: case ARP_REQUEST:
695: // foreign request
696: if(own_ip != 0)
697: arp_send_reply(htonl(arph->src_ip), arph -> src_mac);
698: return 0; // no error
699: case ARP_REPLY: {
700: unsigned int i;
701: // if it is not for us -> return immediately
702: if(memcmp(get_mac_address(), arph->dest_mac, 6)) {
703: return 0; // no error
704: }
705:
706: if(arph->src_ip == 0) {
707: // we are not interested for a MAC address if
708: // the IPv4 address is 0.0.0.0 or ff.ff.ff.ff
709: return -1;
710: }
711:
712: // now let's find the corresponding entry in the ARP table
713:
714: for(i=arp_consumer; i != arp_producer; i = ((i+1)%ARP_ENTRIES) ) {
715: if(arp_table[i].ipv4_addr == arph->src_ip)
716: break;
717: }
718: if(i == arp_producer || memcmp(arp_table[i].mac_addr, null_mac_addr, 6) != 0) {
719: // we have not asked to resolve this IPv4 address !
720: return -1;
721: }
722:
723: memcpy(arp_table[i].mac_addr, arph->src_mac, 6);
724:
725: // do we have something to send
726: if(arp_table[i].eth_len > 0) {
727: struct ethhdr * ethh = (struct ethhdr *) arp_table[i].eth_frame;
728: memcpy(ethh -> dest_mac, arp_table[i].mac_addr, 6);
729:
730: send_ether(arp_table[i].eth_frame, arp_table[i].eth_len);
731: arp_table[i].eth_len = 0;
732: }
733: return 0; // no error
734: }
735: default:
736: break;
737: }
738: return -1; // Invalid message type
739: }
740:
741: /**
742: * ICMP: Send an ICMP Echo request to destination IPv4 address.
743: * This function does also set a global variable to the
744: * destination IPv4 address. If there is an ICMP Echo Reply
745: * received later then the variable is set back to 0.
746: * In other words, reading a value of 0 form this variable
747: * means that an answer to the request has been arrived.
748: *
749: * @param _ping_dst_ip destination IPv4 address
750: */
751: void
752: ping_ipv4(uint32_t _ping_dst_ip)
753: {
754: unsigned char packet[sizeof(struct iphdr) + sizeof(struct icmphdr)];
755: struct icmphdr *icmp;
756:
757: ping_dst_ip = _ping_dst_ip;
758:
759: if(ping_dst_ip == 0)
760: return;
761:
762: fill_iphdr(packet, sizeof(struct iphdr) + sizeof(struct icmphdr), IPTYPE_ICMP,
763: 0, ping_dst_ip);
764: icmp = (struct icmphdr *) (packet + sizeof(struct iphdr));
765: icmp->type = ICMP_ECHO_REQUEST;
766: icmp->code = 0;
767: icmp->checksum = 0;
768: icmp->options.echo.id = 0xd476;
769: icmp->options.echo.seq = 1;
770:
771: memset(icmp->payload.data, '*', sizeof(icmp->payload.data));
772:
773: icmp->checksum =
774: checksum((unsigned short *) icmp, sizeof(struct icmphdr) >> 1);
775: send_ipv4(packet, sizeof(struct iphdr) + sizeof(struct icmphdr));
776: }
777:
778: /**
779: * ICMP: Return host IPv4 address that we are waiting for a
780: * ICMP Echo reply message. If this value is 0 then we have
781: * received an reply.
782: *
783: * @return ping_dst_ip host IPv4 address
784: */
785: uint32_t
786: pong_ipv4(void)
787: {
788: return ping_dst_ip;
789: }
790:
791: /**
792: * ICMP: Handles ICMP-packets according to Receive-handle diagram.
793: *
794: * @param icmp_packet ICMP-packet to be handled
795: * @param packetsize Length of the packet
796: * @return ZERO - packet handled successfully;
797: * NON ZERO - packet was not handled (e.g. bad format)
798: * @see handle_ipv4
799: */
800: static int8_t
801: handle_icmp(struct iphdr * iph, uint8_t * packet, int32_t packetsize)
802: {
803: struct icmphdr *icmp = (struct icmphdr *) packet;
804:
805: switch(icmp->type) {
806: case ICMP_ECHO_REPLY:
807: if (icmp->options.echo.id != 0xd476)
808: return -1;
809: if (icmp->options.echo.seq != 1)
810: return -1;
811: if(ping_dst_ip != iph->ip_src
812: || ping_dst_ip == 0)
813: return -1;
814: ping_dst_ip = 0;
815: break;
816: case ICMP_DST_UNREACHABLE: {
817: // We've got Destination Unreachable msg
818: // Inform corresponding upper network layers
819: struct iphdr * bad_iph = (struct iphdr * ) &icmp->payload;
820:
821: switch(bad_iph->ip_p) {
822: case IPTYPE_TCP:
823: handle_tcp_dun((uint8_t *) (bad_iph + 1), packetsize
824: - sizeof(struct icmphdr)
825: - sizeof(struct iphdr), icmp->code);
826: break;
827: case IPTYPE_UDP:
828: handle_udp_dun((uint8_t *) (bad_iph + 1), packetsize
829: - sizeof(struct icmphdr)
830: - sizeof(struct iphdr), icmp->code);
831: break;
832: }
833: break;
834: }
835: case ICMP_SRC_QUENCH:
836: break;
837: case ICMP_REDIRECT:
838: break;
839: case ICMP_ECHO_REQUEST: {
840: // We've got an Echo Request - answer with Echo Replay msg
841: unsigned char reply_packet[sizeof(struct iphdr) + packetsize];
842: struct icmphdr *reply_icmph;
843:
844: fill_iphdr(reply_packet, sizeof(struct iphdr) + packetsize,
845: IPTYPE_ICMP, 0, iph->ip_src);
846:
847: reply_icmph = (struct icmphdr *) &reply_packet[sizeof(struct iphdr)];
848: memcpy(reply_icmph, packet, packetsize);
849: reply_icmph -> type = ICMP_ECHO_REPLY;
850: reply_icmph -> checksum = 0;
851: reply_icmph->checksum = checksum((unsigned short *) reply_icmph,
852: sizeof(struct icmphdr) >> 1);
853:
854: send_ipv4(reply_packet, sizeof(struct iphdr) + packetsize);
855: break;
856: }
857: case ICMP_TIME_EXCEEDED:
858: break;
859: case ICMP_PARAMETER_PROBLEM:
860: break;
861: case ICMP_TIMESTAMP_REQUEST:
862: break;
863: case ICMP_TIMESTAMP_REPLY:
864: break;
865: case ICMP_INFORMATION_REQUEST:
866: break;
867: case ICMP_INFORMATION_REPLY:
868: break;
869: }
870: return 0;
871: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.