~ubuntu-branches/ubuntu/wily/slof/wily

« back to all changes in this revision

Viewing changes to clients/net-snk/app/netlib/ipv4.c

  • Committer: Package Import Robot
  • Author(s): Aurelien Jarno
  • Date: 2012-09-16 23:05:23 UTC
  • Revision ID: package-import@ubuntu.com-20120916230523-r2ynulqmp2tyu2e5
Tags: upstream-20120217+dfsg
ImportĀ upstreamĀ versionĀ 20120217+dfsg

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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
}