Subversion Repositories shark

Rev

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

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