Subversion Repositories shark

Rev

Rev 629 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
629 giacomo 1
/*
2
 * Project: S.Ha.R.K.
3
 *
4
 * Coordinators:
5
 *   Giorgio Buttazzo    <giorgio@sssup.it>
6
 *   Paolo Gai           <pj@gandalf.sssup.it>
7
 *
8
 * Authors     :
9
 *   Paolo Gai           <pj@gandalf.sssup.it>
10
 *   Massimiliano Giorgi <massy@gandalf.sssup.it>
11
 *   Luca Abeni          <luca@gandalf.sssup.it>
12
 *   (see the web pages for full authors list)
13
 *
14
 * ReTiS Lab (Scuola Superiore S.Anna - Pisa - Italy)
15
 *
16
 * http://www.sssup.it
17
 * http://retis.sssup.it
18
 * http://shark.sssup.it
19
 */
20
 
21
/**
22
 ------------
23
 CVS :        $Id: udpip.c,v 1.5 2004-05-11 14:30:51 giacomo Exp $
24
 
25
 File:        $File$
26
 Revision:    $Revision: 1.5 $
27
 Last update: $Date: 2004-05-11 14:30:51 $
28
 ------------
29
**/
30
 
31
/*
32
 * Copyright (C) 2000 Luca Abeni and Giuseppe Lipari
33
 *
34
 * This program is free software; you can redistribute it and/or modify
35
 * it under the terms of the GNU General Public License as published by
36
 * the Free Software Foundation; either version 2 of the License, or
37
 * (at your option) any later version.
38
 *
39
 * This program is distributed in the hope that it will be useful,
40
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
41
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
42
 * GNU General Public License for more details.
43
 *
44
 * You should have received a copy of the GNU General Public License
45
 * along with this program; if not, write to the Free Software
46
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
47
 *
48
 */
49
 
50
/* Author:      Giuseppe Lipari & Luca Abeni                    */
51
/* Date:        1/12/97                                         */
52
 
53
/* File:        UDPIPDrv.C                                      */
54
/* Revision:    2.0                                             */
55
 
56
/*
57
   UDP and IP layers. IP doesn't support fragmented packets (fragmentation
58
   isn't Real-Time!!!). UDP allows to fill some entries of the ARP table
59
   at the moment of the creation of a socket (see udp_bind).
60
*/
61
 
62
#include <kernel/kern.h>
63
#include <semaphore.h>
64
 
65
#include "eth_priv.h"
66
#include "netbuff.h"
67
#include <drivers/udpip.h>
68
#include "arp.h"
69
 
70
//#define __UDP_DBG__
71
//#define __IP_DBG__
72
#define UDP_INFO "[UDP] "
73
#define IP_INFO  "[IP] "
74
 
75
/*
76
   UDP-buffers number and dimension (UDP-buffers are provided by NetBuff
77
   module
78
*/
79
#define UDP_RX_BUFFERS  4
80
#define UDP_TX_BUFFERS  4
81
#define UDP_MAX_LEN     1000
82
#define UDP_MAX_HANDLES 4
83
 
84
/* Only 4 debug */
85
extern int netlev;
86
 
87
int ipIsInstalled = FALSE;
88
extern struct ip_addr myIpAddr;
89
struct ip_table ipTable[IP_MAX_ENTRIES];
90
extern ARP_TABLE arpTable[ARP_MAX_ENTRIES];
91
IP_ADDR IPbroadcastaddress;
92
 
93
int udpIsInstalled = FALSE;
94
struct netbuff udp_txbuff;
95
struct netbuff udp_rxbuff;
96
struct udp_table udpTable[UDP_MAX_HANDLES];
97
struct eth_addr broadcast;
98
 
99
IP_ADDR *ip_getAddr()
100
{
101
    return &myIpAddr;
102
}
103
 
104
/* TRUE if the IP addresses ip1 and ip2 are equal, FALSE otherwise */
105
int ip_compAddr(IP_ADDR ip1, IP_ADDR ip2)
106
{
107
        int i;
108
 
109
        for (i=0; i < 4; i++)
110
                if (ip1.ad[i] != ip2.ad[i]) return FALSE;
111
 
112
        return TRUE;
113
}
114
 
115
/* traslate an IP address from text string to 4 bytes */
116
int ip_str2addr(char *a, IP_ADDR *ip)
117
{
118
        int ad[6];
119
        int i,j;
120
        char c;
121
 
122
        i = 0;
123
        for(j = 0; j < 4; j++) {
124
                ad[j] = 0;
125
                while((a[i] != '.') && (a[i] != 0)) {
126
                        c = a[i++];
127
                        if (c <= '9') c = c - '0';
128
                        else c = c - 'A' + 10;
129
                        ad[j] = ad[j] * 10 + c;
130
                }
131
                i++;
132
        }
133
 
134
        for (i=0; i<4; i++)
135
                ip->ad[i] = ad[i];
136
 
137
        return 1;
138
}
139
 
140
/* give the body of an IP packet */
141
void *ip_getFDB(void *pkt)
142
{
143
        return((void *)(((BYTE *)eth_getFDB(pkt)) + sizeof(IP_HEADER)));
144
}
145
 
146
/* received IP packet CallBack */
147
void ip_server_recv(void *pkt)
148
{
149
        IP_HEADER *iphd;
150
        WORD *ptcheck;
151
        WORD checksum,oldChk;
152
        int hlen,i;
153
        int done;
154
        char dummystr[50];
155
        BYTE flag;
156
 
157
        UDP_HEADER *udphd;
158
        struct pseudo_hd ph;
159
        WORD sum, old;
160
        WORD *p;
161
        UDP_MSG usermsg;
162
        void *b, *s;
163
 
164
        /* debug...*/
165
        netlev = 2;
166
 
167
        sprintf(dummystr, "Packet arrived!\n");
168
        iphd = (IP_HEADER *)eth_getFDB(pkt);
169
 
170
        /* compute the checksum */
171
        ptcheck = (WORD *)iphd;
172
#ifdef __IP_DBG__
173
        //!!!ip_print_header(iphd);
174
#endif
175
        hlen = getHlen(iphd->vers_hlen) * 2;
176
        checksum = oldChk = *ptcheck;
177
        ptcheck++;
178
        for (i=1; i<hlen; i++) {
179
                checksum += *ptcheck;
180
                if (checksum < oldChk) checksum ++;
181
                oldChk = checksum;
182
                ptcheck++;
183
        }
184
        if (checksum != 0xffff) {
185
                /* wrong ChkSum */
186
#ifdef __IP_DBG__
187
                printk(KERN_DEBUG IP_INFO "Wrong checksum: %x.\n", checksum);
188
#endif
189
        } else if (!ip_compAddr(iphd->dest,myIpAddr)) {
190
#ifdef __IP_DBG__
191
                printk(KERN_DEBUG IP_INFO "Packet not addressed to this host.\n");
192
#endif
193
        } else if (getFlags(ntohs(iphd->flags_frOffset)) & 0x01) {
194
#ifdef __IP_DBG__
195
                /* fragment? */
196
                printk(KERN_DEBUG IP_INFO "Gotta a fragment!\n");
197
#endif
198
        } else if (getFrOffset(ntohs(iphd->flags_frOffset)) != 0) {
199
#ifdef __IP_DBG__
200
                printk(KERN_DEBUG IP_INFO "Gotta a fragment again!\n");
201
#endif
202
        } else {
203
                /* OK: the packet is good... */
204
                if (iphd->protocol != IP_UDP_TYPE) {
205
                        /* It isn't an UDP packet */
206
                        done = FALSE;
207
                        i = 0;
208
                        while ((i < IP_MAX_ENTRIES) && !done) {
209
                                if (ipTable[i].protocol == iphd->protocol) done = TRUE;
210
                                else i++;
211
                        }
212
                        if (!done) {
213
#ifdef __IP_DBG__
214
                                /* Unknown transport protocol */
215
                                printk(KERN_DEBUG IP_INFO "Wrong protocol.\n");
216
#endif
217
                        } else {
218
                                /* Call the correct transport protocol CallBack */
219
                        ipTable[i].rfun((void *)((BYTE *)iphd + 4*getHlen(iphd->vers_hlen)));
220
                        }
221
                } else {
222
                        /* UDP packet */
223
                        netlev = 4;
224
 
225
                        udphd = (UDP_HEADER *)(void *)((BYTE *)iphd + 4*getHlen(iphd->vers_hlen));
226
                        /* compute the UDP checksum */
227
                        for (i = 0; i < 4; i++) {
228
                                ph.source.ad[i]  = iphd->source.ad[i];
229
                                ph.dest.ad[i]  = iphd->dest.ad[i];
230
                        }
231
                        ph.zero = 0;
232
                        ph.protocoll = IP_UDP_TYPE;
233
                        ph.len = udphd->mlen;
234
                        sum = 0;
235
                        old = 0;
236
                        p = (WORD *)&ph;
237
                        for (i = 0; i < (sizeof(ph) >> 1); i++) {
238
                                sum += p[i];
239
                                if (sum < old) sum ++;
240
                                old = sum;
241
                        }
242
#ifdef __UDP_DBG__
243
                        printk(KERN_DEBUG UDP_INFO "Half sum: %x\n",sum);
244
#endif
245
                        p = (WORD *)udphd;
246
                        ((BYTE *)udphd)[ntohs(udphd->mlen)] = 0;
247
                        for (i = 0; i < ((ntohs(udphd->mlen) + 1) >> 1); i++) {
248
                                sum += p[i];
249
                                if (sum < old) sum ++;
250
                                old = sum;
251
                        }
252
#ifdef __UDP_DBG__
253
                        printk(KERN_DEBUG UDP_INFO "Packet received.\n");
254
                        printk(KERN_DEBUG UDP_INFO "s_port: %x\n",udphd->s_port);
255
                        printk(KERN_DEBUG UDP_INFO "d_port: %x\n",udphd->d_port);
256
                        printk(KERN_DEBUG UDP_INFO "m_len: %x %d\n",udphd->mlen, ntohs(udphd->mlen));
257
                        printk(KERN_DEBUG UDP_INFO "checksum: %x\n",udphd->checksum);
258
                        printk(KERN_DEBUG UDP_INFO "mysum: %x \n", sum);
259
#endif
260
                        if(sum != 0xFFFF) {
261
                                /* Wrong UDP ChkSum */
262
                                cprintf("Error %x!\n", sum);
263
                                kern_raise(XUDP_BADCHK_EXC,exec_shadow);
264
                        } else {
265
                                done = FALSE;
266
                                i = 0;
267
                                /* searching for the destination socket...*/
268
                                while((i < UDP_MAX_HANDLES) && !done) {
269
                                        if ((udpTable[i].valid == TRUE) && (udpTable[i].port == ntohs(udphd->d_port)))
270
                                                done = TRUE;
271
                                        else i++;
272
                                }
273
                                if (done) {
274
                                        /*...found! */
275
                                        s = (void *)(((BYTE *)udphd) + sizeof(UDP_HEADER));
276
                                        if (udpTable[i].notify == TRUE) {
277
                                                /* notify function associated to the socket: call it */
278
                                                udpTable[i].notify_fun(ntohs(udphd->mlen) - sizeof(UDP_HEADER),
279
                                                        s, udpTable[i].notify_par);
280
                                        } else {
281
                                                /* otherwise, send the packet to the correct port */
282
                                                if((b = netbuff_get(&udp_rxbuff, NON_BLOCK)) != 0) {
283
                                                        memcpy(b,s,ntohs(udphd->mlen) - sizeof(UDP_HEADER) + 1);
284
                                                        setIpAddr(usermsg.addr.s_addr, iphd->source);
285
                                                        usermsg.addr.s_port = ntohs(udphd->s_port);
286
                                                        usermsg.mlen = ntohs(udphd->mlen) - sizeof(UDP_HEADER);
287
                                                        usermsg.buff = b;
288
                                                        flag = port_send(udpTable[i].hport,&usermsg,NON_BLOCK);
289
                                                        if (!flag) {
290
                                                                netbuff_release(&udp_rxbuff, b);
291
#ifdef __UDP_DBG__
292
                                                                printk(KERN_DEBUG "Port is filled up.\n");
293
#endif
294
                                                        }
295
                                                }
296
                                        }
297
                                } else {
298
#ifdef __UDP_DBG__
299
                                        printk(KERN_DEBUG UDP_INFO "Port not found.\n");
300
#endif
301
                                }
302
                        }
303
                }
304
        }
305
}
306
 
307
/* Send an IP packet */
308
void ip_send(IP_ADDR dest, void *pkt, WORD len)
309
{
310
        static WORD ip_ident = 0;
311
        IP_HEADER *iphd;
312
        WORD check = 0, oldCheck = 0;
313
        int i, done;
314
        WORD *pt;
315
 
316
        iphd = (IP_HEADER *)eth_getFDB(pkt);
317
        iphd->vers_hlen = (4 << 4) + 5;
318
        iphd->servType = 8;
319
        iphd->lenght = htons(len + sizeof(IP_HEADER));
320
        iphd->ident = htons(ip_ident++);
321
        iphd->flags_frOffset = 0;
322
        iphd->ttl = 10;
323
        iphd->protocol = IP_UDP_TYPE;
324
        iphd->headChecksum = 0;
325
        iphd->source = myIpAddr;
326
        iphd->dest = dest;
327
 
328
        /* Compute the checksum */
329
        pt = (WORD *)iphd;
330
        check = oldCheck = *pt;
331
        pt++;
332
        for (i = 1; i < 10; i++) {
333
                check += *pt;
334
                if (oldCheck > check) check++;
335
                oldCheck = check;
336
                pt++;
337
        }
338
        check = ~check;
339
        iphd->headChecksum = check;
340
#ifdef __IP_DBG__
341
        printk(KERN_DEBUG IP_INFO "Serv type : %d\n", iphd->servType);
342
#endif
343
        /* Is the destination IP address the broadcast address?*/
344
        if (ip_compAddr(dest,IPbroadcastaddress)) {
345
                /* Send the packet*/
346
                eth_setHeader(pkt,broadcast,ETH_IP_TYPE);
347
                eth_sendPkt(pkt,len + sizeof(IP_HEADER));
348
                netbuff_release(&udp_txbuff, (void *)pkt);
349
        } else {
350
                /* Is the destination ethernet address in the ARP table? */
351
                i = 0; done = 0;
352
                while (i < ARP_MAX_ENTRIES && !done)
353
                        if (arpTable[i].valid == TRUE) {
354
                                if (ip_compAddr(dest,arpTable[i].ip)) {
355
                                        done = TRUE;
356
                                } else i++;
357
                        } else i++;
358
                if (done == FALSE) {
359
                        /* No: call ARP to get the ethernet address */
360
                        arp_send(pkt, dest, len + sizeof(IP_HEADER));
361
                } else {
362
                        /* Yes: directly send the packet */
363
                        eth_setHeader(pkt,arpTable[i].eth,ETH_IP_TYPE);
364
                        eth_sendPkt(pkt, len + sizeof(IP_HEADER));
365
                        netbuff_release(&udp_txbuff, (void *)pkt);
366
                        arpTable[i].used++;
367
                        if (arpTable[i].used > ARP_MAX_USED) arpTable[i].used = ARP_MAX_USED;
368
                }
369
        }
370
}
371
 
372
/* let IP manage a new transport protocol */
373
int ip_setProtocol(BYTE proto, void (*recv)(void *m))
374
{
375
        BYTE done, i;
376
 
377
        i = 0; done = 0;
378
        while (i < IP_MAX_ENTRIES && !done)
379
                if (ipTable[i].rfun == NULL) done = TRUE;
380
                else i++;
381
        if (!done)
382
                return FALSE;
383
        else {
384
                ipTable[i].protocol = proto;
385
                ipTable[i].rfun = recv;
386
        }
387
        return TRUE;
388
}
389
 
390
/*int ip_error(int code)
391
{
392
        cprintf("IP error\n");
393
        cprintf("Code [%d]\nCause : %s",code,ip_error_msg[code-IP_ERROR_BASE]);
394
        return(0);
395
}*/
396
 
397
/* Initialize the IP layer: it also call the ARP initialization function, pass a struct ip_params* */
398
void ip_init(void *p)
399
{
400
        int i;
401
 
402
        if (!ipIsInstalled) {
403
                arp_init(((struct ip_params*)p)->localAddr);
404
                //exc_set(IP_INIT_ERROR,ip_error);
405
                for (i=0; i < IP_MAX_ENTRIES; i++)
406
                        ipTable[i].rfun = NULL;
407
 
408
                eth_setProtocol(ETH_IP_TYPE, ip_server_recv);
409
                ip_str2addr(((struct ip_params*)p)->broadcastAddr,&IPbroadcastaddress);
410
                ipIsInstalled = TRUE;
411
                eth_str2Addr("FF:FF:FF:FF:FF:FF",&broadcast);
412
        } else
413
                cprintf("IP: already installed.\n");
414
}
415
 
416
/* Receive an UDP packet from a socket */
417
int udp_recvfrom(int s, void *buff, UDP_ADDR *from)
418
{
419
        UDP_MSG u;
420
 
421
        port_receive(udpTable[s].pport,&u,BLOCK);
422
        memcpy(buff,u.buff,u.mlen);
423
        netbuff_release(&udp_rxbuff, u.buff);
424
        *from = u.addr;
425
 
426
        return (u.mlen);
427
}
428
 
429
/* Associate a notify function to a socket */
430
int udp_notify(int s, int (*f)(int len, BYTE *buff, void *p), void *p)
431
{
432
        if (f == NULL) {
433
                udpTable[s].notify = FALSE;
434
                return 1;
435
        }
436
 
437
        if (udpTable[s].valid != TRUE)
438
                return -1;
439
        udpTable[s].notify = TRUE;
440
        udpTable[s].notify_fun = f;
441
        udpTable[s].notify_par = p;
442
 
443
        return 1;
444
}
445
 
446
/* Create a new socket binding it to a specified IP port */
447
int udp_bind(UDP_ADDR *local, IP_ADDR *bindlist)
448
{
449
        int i, j;
450
        BYTE done;
451
        char str[30];
452
 
453
        /* Search for a free entry in the socket table */
454
        i = 0; done = FALSE;
455
        while ((i < UDP_MAX_HANDLES) && !done) {
456
                kern_cli();
457
                if ((udpTable[i].valid == FALSE)) {
458
                        done = TRUE;
459
                        udpTable[i].valid = 2;
460
                } else i++;
461
                kern_sti();
462
        }
463
 
464
        /* No free entries: bind fail! */
465
        if (!done)
466
                return -1;
467
 
468
        /* Create a receive port for the socket */
469
        udpTable[i].port = local->s_port;
470
        sprintf(str,"UDP%d",i);
471
        udpTable[i].hport = port_create(str,sizeof(UDP_MSG),4,STREAM,WRITE);
472
        udpTable[i].pport = port_connect(str,sizeof(UDP_MSG),STREAM,READ);
473
        udpTable[i].valid = TRUE;
474
 
475
        /*
476
         * Request for the ethernet addresses associated to the IP addressed
477
         * given in the bindlist.
478
         */
479
        if (bindlist != NULL) {
480
                while (*(int*)bindlist != 0) {
481
                        /* Ignore broadcast IP address */
482
                        if (!ip_compAddr(*bindlist,IPbroadcastaddress)) {
483
                                j = arp_req(*bindlist);
484
                                arp_sendRequest(j);
485
                        }
486
                        bindlist ++;
487
                }
488
        }
489
 
490
        return i;
491
}
492
 
493
/* Send an UDP packet */
494
int udp_sendto(int s, void *buff, int nbytes, UDP_ADDR *to)
495
{
496
        void *pkt;
497
        UDP_HEADER *udphd;
498
        char *msg;
499
 
500
#ifdef __UDP_DBG__
501
        static int num_pack = 0;
502
#endif
503
 
504
        WORD sum, old;
505
        int i;
506
        struct pseudo_hd ph;
507
        WORD *p;
508
        IP_ADDR *source;
509
 
510
        pkt = netbuff_get(&udp_txbuff, BLOCK);
511
        udphd = (UDP_HEADER *)ip_getFDB(pkt);
512
        udphd->s_port = htons(udpTable[s].port);
513
        udphd->d_port = htons(to->s_port);
514
        udphd->mlen = htons((WORD)nbytes + sizeof(UDP_HEADER));
515
        msg = (char *)(((BYTE *)udphd) + sizeof(UDP_HEADER));
516
        if (nbytes > UDP_MAX_LEN) nbytes = UDP_MAX_LEN;
517
        memcpy(msg,buff,nbytes);
518
 
519
        source = ip_getAddr();
520
        /* Compute the CheckSum */
521
        udphd->checksum = 0;
522
        for (i = 0; i < 4; i++) {
523
                ph.source.ad[i]  = source->ad[i];
524
                ph.dest.ad[i]  = to->s_addr.ad[i];
525
        }
526
        ph.zero = 0;
527
        ph.protocoll = 17;
528
        ph.len = udphd->mlen;
529
        sum = 0; old = 0;
530
        p = (WORD *)&ph;
531
        for (i = 0; i < (sizeof(ph) >> 1); i++) {
532
                sum += p[i];
533
                if (sum < old) sum ++;
534
                old = sum;
535
        }
536
        p = (WORD *)udphd;
537
        ((BYTE *)udphd)[ntohs(udphd->mlen)] = 0;
538
        for (i = 0; i < ((ntohs(udphd->mlen) + 1) >> 1); i++) {
539
                sum += p[i];
540
                if (sum < old) sum++;
541
                old = sum;
542
        }
543
        udphd->checksum = ~sum;
544
 
545
        ip_send(to->s_addr, pkt, ((WORD)nbytes + sizeof(UDP_HEADER)));
546
#ifdef __UDP_DBG__
547
        printk(KERN_DEBUG UDP_INFO "Packets sent: %d.\n", num_pack++);
548
#endif
549
 
550
        return nbytes;
551
}
552
 
553
void udp_init(void *dummy)
554
{
555
        int i;
556
 
557
        if (!udpIsInstalled) {
558
                netbuff_init(&udp_rxbuff, UDP_RX_BUFFERS, UDP_MAX_LEN);
559
                netbuff_init(&udp_txbuff, UDP_TX_BUFFERS, ETH_MAX_LEN);
560
 
561
                for (i = 0; i < UDP_MAX_HANDLES; i++) {
562
                        udpTable[i].valid = FALSE;
563
                        udpTable[i].notify = FALSE;
564
                }
565
                udpIsInstalled = TRUE;
566
        } else
567
                printk(KERN_WARNING UDP_INFO ": Already installed.\n");
568
}