Subversion Repositories shark

Rev

Details | 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
 ------------
23
 CVS :        $Id: arp.c,v 1.1.1.1 2002-03-29 14:12:50 pj Exp $
24
 
25
 File:        $File$
26
 Revision:    $Revision: 1.1.1.1 $
27
 Last update: $Date: 2002-03-29 14:12:50 $
28
 ------------
29
**/
30
 
31
/*
32
 * Copyright (C) 2000 Luca Abeni
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
 
51
/* Author:      Giuseppe Lipari & Luca Abeni                    */
52
/* Date:        4/12/97                                         */
53
 
54
/* File:        ArpDrv.C                                        */
55
/* Revision:    2.0                                             */
56
 
57
/*
58
   ARP layer. It associates, the correct ethernet addresses to IP addresses
59
   this is done using an ARP table, created dinamicaly. This mechanism can
60
   introduce unpredictability (it is impossible to predict how much time is
61
   required to obtain an ethernet address from the network). To solve this
62
   problem, ARP is used only the first time that a computer is addressed.
63
*/
64
 
65
#include <kernel/kern.h>
66
#include <semaphore.h>
67
 
68
#include "eth_priv.h"
69
#include "netbuff.h"
70
#include <drivers/udpip.h>
71
#include "arp.h"
72
#include <signal.h>
73
 
74
#define FALSE   0
75
#define TRUE    1
76
#define PENDING 2
77
#define ARP_TIMEOUT     5
78
#define ARP_MAX_RETRANS 4
79
#define ARP_PRIORITY    10
80
 
81
#define ARP_LEN         70
82
 
83
/*
84
   Structure used to enqueue the packets destinated to an host whose ethernet
85
   address is still unknown. This structure overwrites the firsts fields of
86
   the ehternet header, but it isn't a problem because it is used only
87
   locally
88
*/
89
typedef struct {
90
    int len;
91
    void *next;
92
} PKT_NXT;
93
 
94
typedef struct arp_pkt{
95
    WORD htype;
96
    WORD ptype;
97
    BYTE hlen;
98
    BYTE plen;
99
    WORD operation;
100
    struct eth_addr sha;
101
    IP_ADDR sip;
102
    struct eth_addr tha;
103
    IP_ADDR tip;
104
} ARP_PKT;
105
 
106
struct netbuff arp_txbuff;
107
struct eth_addr broadcast,nulladdr;
108
 
109
BYTE reply[ETH_MAX_LEN];
110
extern struct netbuff udp_txbuff;
111
 
112
ARP_TABLE arpTable[ARP_MAX_ENTRIES];
113
sem_t arpMutex;
114
 
115
int arpIsInstalled = FALSE;
116
 
117
struct eth_addr myEthAddr;
118
IP_ADDR myIpAddr;
119
 
120
/*
121
   ARP Exceptions Handler: in particular, it is called when the ARP table
122
   is full. The default action is to free the less used entry in the table
123
   (it's the simpler thing to do!!!). An hard Real-Time task should have
124
   to disable the handler in this case. (for an hard task, the full table
125
   condition is an error condition, 'cause it can generate unpredictability).
126
*/
127
void arp_exc(int err)
128
{
129
    int i, j, minused;
130
 
131
    minused = ARP_MAX_USED; j = -1;
132
    for (i = 0; i < ARP_MAX_ENTRIES; i++) {
133
        if ((arpTable[i].valid != PENDING) && (arpTable[i].used <= minused)) {
134
            j = i;
135
            minused = arpTable[i].used;
136
        }
137
    }
138
    if (j == -1) {
139
        cprintf("ARP table overflow!!!\n");
140
        sys_abort(AARPFULL);
141
    }
142
    arpTable[j].valid = FALSE;
143
}
144
 
145
/*
146
   Send an ARP request: if there aren't free buffers, do nothing (there will
147
   be a retry)
148
*/
149
void arp_sendRequest(int i)
150
{
151
    ARP_PKT *pkt;
152
    BYTE *arpBuff;
153
 
154
    if ((arpBuff= netbuff_get(&arp_txbuff, NON_BLOCK)) != NULL) {
155
        eth_setHeader(arpBuff,broadcast,ETH_ARP_TYPE);
156
        pkt = (ARP_PKT *)eth_getFDB(arpBuff);
157
        pkt->htype = htons(ARP_ETH_TYPE);
158
        pkt->ptype = htons(ARP_IP_TYPE);
159
        pkt->hlen = sizeof(struct eth_addr);
160
        pkt->plen = sizeof(IP_ADDR);
161
        pkt->operation = htons(ARP_REQUEST);
162
        setEthAddr(pkt->sha,myEthAddr);
163
        setEthAddr(pkt->tha,nulladdr);
164
        setIpAddr(pkt->sip,myIpAddr);
165
        setIpAddr(pkt->tip,arpTable[i].ip);
166
        eth_sendPkt(arpBuff,sizeof(ARP_PKT));
167
        netbuff_release(&arp_txbuff, (void *)arpBuff);
168
    }
169
}
170
 
171
/* Retry task (periodic) */
172
TASK arp_retry(void)
173
{
174
    int i;
175
    PKT_NXT *p, *p1;
176
#ifdef __ARP_DBG__
177
char msg[100];
178
#endif
179
 
180
    while (1) {
181
        /* mutual exclusion on the ARP table */
182
        sem_xwait(&arpMutex, 1, BLOCK);
183
        for (i = 0; i < ARP_MAX_ENTRIES; i++) {
184
            if (arpTable[i].valid == PENDING) {
185
                arpTable[i].time--;
186
                if (arpTable[i].time <= 0) {
187
                    arpTable[i].ntrans++;
188
                    if (arpTable[i].ntrans > ARP_MAX_RETRANS) {
189
                        /* N. Max Retry? If yes, discard all the packets */
190
                        p = (PKT_NXT *)arpTable[i].pkt;
191
                        while (p != NULL) {
192
                            p1 = p->next;
193
                            netbuff_release(&udp_txbuff, (void *)p);
194
#ifdef __ARP_DBG__
195
sprintf(msg,"Pacchetto : %lp scartato\n",p);
196
win_puts(&w1,msg);
197
#endif
198
                            p = p1;
199
                        }
200
                        arpTable[i].valid = FALSE;
201
                    }
202
                    else {
203
                        arp_sendRequest(i);
204
                        arpTable[i].time = ARP_TIMEOUT;
205
                    }
206
                }
207
            }
208
        }
209
        sem_post(&arpMutex);
210
        task_endcycle();
211
    }
212
}
213
 
214
/* Search for a free entry in the ARP table (if there isn't any, return -1 */
215
int arp_req(IP_ADDR dest)
216
{
217
    int j, done;
218
 
219
    done = 0; j = 0;
220
    while ((j < ARP_MAX_ENTRIES) && !done) {
221
        if (arpTable[j].valid == FALSE) {
222
            done = 1;
223
            arpTable[j].valid = PENDING;
224
        } else j++;
225
    }
226
 
227
    if (!done) return -1;
228
    /* Fill the entry */
229
    setIpAddr(arpTable[j].ip, dest);
230
#ifdef __ARP_DBG__
231
sprintf(msg,"Indirizzo : %d.%d.%d.%d\n",dest.ad[0],
232
                                      dest.ad[1],
233
                                      dest.ad[2],
234
                                      dest.ad[3]);
235
win_puts(&w1,msg);
236
sprintf(msg,"Indirizzo : %d.%d.%d.%d\n",arpTable[j].ip.ad[0],
237
                                      arpTable[j].ip.ad[1],
238
                                      arpTable[j].ip.ad[2],
239
                                      arpTable[j].ip.ad[3]);
240
win_puts(&w1,msg);
241
#endif
242
    arpTable[j].time = ARP_TIMEOUT;
243
    arpTable[j].ntrans = 0;
244
    return j;
245
}
246
 
247
/*
248
   Send an IP packet. If the ethernet address isn't in the ARP table, send
249
   a request
250
*/
251
void arp_send(void *pkt, IP_ADDR dest, int len)
252
{
253
    int i,j;
254
    PKT_NXT *p,*p1;
255
    int caso;
256
#ifdef __ARP_DBG__
257
char msg[50];
258
#endif
259
 
260
    sem_xwait(&arpMutex, 1, BLOCK);
261
    caso = 0;
262
    j = -1;
263
    for (i = 0; i < ARP_MAX_ENTRIES; i++) {
264
        if (ip_compAddr(dest,arpTable[i].ip)) {
265
            /* found: CASE 1 */
266
            if (arpTable[i].valid == TRUE) {
267
                caso = 1;
268
                j = i;
269
            }
270
            else if (arpTable[i].valid == PENDING) {
271
                /* Entry found, but the ethernet address is still unknown: CASE 2 */
272
                caso = 2;
273
                j = i;
274
            }
275
        }
276
    }
277
 
278
    if (caso == 1) {
279
        /* Send the IP packet */
280
        eth_setHeader(pkt,arpTable[j].eth,ETH_IP_TYPE);
281
        eth_sendPkt(pkt,len);
282
        netbuff_release(&udp_txbuff, (void *)pkt);
283
        arpTable[j].used++;
284
        if (arpTable[j].used > ARP_MAX_USED) arpTable[j].used = ARP_MAX_USED;
285
    }
286
    else if (caso == 2) {
287
        /* Enqueue the packet until the ethernet address arrives */
288
        p = arpTable[j].pkt;
289
        while (p != NULL) {
290
            p1 = p;
291
            p = p1->next;
292
        }
293
        p1->next = pkt;
294
        ((PKT_NXT *)pkt)->next = NULL;
295
        ((PKT_NXT *)pkt)->len = len;
296
#ifdef __ARP_DBG__
297
sprintf(msg,"Pacchetto : %lp accodato\n",pkt);
298
win_puts(&w1,msg);
299
#endif
300
    }
301
    else {
302
        /* Search for a free entry in the ARP table...*/
303
        j = -1;
304
        while (j == -1) {
305
            j = arp_req(dest);
306
            if (j == -1) {
307
                cprintf("FULL!!!\n");
308
                kern_raise(XARP_TABLE_FULL,NIL);
309
            }
310
        }
311
        /*...fill it...*/
312
        arpTable[j].pkt = pkt;
313
        ((PKT_NXT *)arpTable[j].pkt)->next = NULL;
314
        ((PKT_NXT *)pkt)->len = len;
315
#ifdef __ARP_DBG__
316
sprintf(msg,"Pacchetto : %lp accodato\n",pkt);
317
win_puts(&w1,msg);
318
#endif
319
        /*...and send the request!!! */
320
        arp_sendRequest(j);
321
    }
322
    sem_post(&arpMutex);
323
}
324
 
325
/* ARP packet received CallBack*/
326
void arp_server_recv(void *pk)
327
{
328
    ARP_PKT *pkt,*rpkt;
329
    PKT_NXT *p1,*q1;
330
    int len;
331
    int i,j;
332
#ifdef __ARP_DBG__
333
char msg[100];
334
#endif
335
    BYTE found;
336
 
337
        pkt = (ARP_PKT *)eth_getFDB(pk);
338
 
339
#if 0
340
        {int ii;
341
                        cprintf("Arp PKT...\n");
342
cprintf ("source...");
343
for (ii=0; ii<4; ii++) cprintf("%d ", pkt->sip.ad[ii]);
344
cprintf ("\ndest...");
345
for (ii=0; ii<4; ii++) cprintf("%d ", pkt->tip.ad[ii]);
346
        }
347
#endif
348
 
349
        /* Check if the packet is directed to this host...*/
350
        if (ip_compAddr(pkt->tip,myIpAddr)) {
351
            sem_xwait(&arpMutex, 1, BLOCK);
352
            /* 1 : Search an entry with his IP address */
353
            found = FALSE;
354
            for (i = 0; (i < ARP_MAX_ENTRIES) && !found; i++) {
355
                if ((arpTable[i].valid != FALSE) &&
356
                        ip_compAddr(arpTable[i].ip,pkt->sip)) {
357
                    setEthAddr(arpTable[i].eth,pkt->sha);
358
                    found = TRUE;
359
                }
360
            }
361
            /*
362
               If there isn't any, fill a new entry (if the table is
363
               not full)
364
            */
365
            if (!found) {
366
                for (i = 0; (i < ARP_MAX_ENTRIES) && !found; i++)
367
                    if (arpTable[i].valid == FALSE) {
368
                        j = i;
369
                        found = TRUE;
370
                    }
371
                if (found) {
372
                    setIpAddr(arpTable[j].ip,pkt->sip);
373
                    setEthAddr(arpTable[j].eth,pkt->sha);
374
                    arpTable[j].valid = TRUE;
375
                }
376
            }
377
            /* If it is a request, send the reply */
378
            if (ntohs(pkt->operation) == ARP_REQUEST) {
379
                rpkt = (ARP_PKT *)eth_getFDB(reply);
380
                rpkt->htype = htons(ARP_ETH_TYPE);
381
                rpkt->ptype = htons(ARP_IP_TYPE);
382
                rpkt->hlen = sizeof(struct eth_addr);
383
                rpkt->plen = sizeof(IP_ADDR);
384
                rpkt->operation = htons(ARP_REPLY);
385
                setEthAddr(rpkt->sha,myEthAddr);
386
                setIpAddr(rpkt->sip,myIpAddr);
387
                setEthAddr(rpkt->tha,pkt->sha);
388
                setIpAddr(rpkt->tip,pkt->sip);
389
                eth_setHeader(reply, pkt->sha, ETH_ARP_TYPE);
390
                eth_sendPkt(reply,sizeof(ARP_PKT));
391
            }
392
            /* If it is a reply, search for his pending request */
393
            else {
394
                for (i = 0; i < ARP_MAX_ENTRIES; i++) {
395
                    if ((arpTable[i].valid == PENDING) &&
396
                        ip_compAddr(arpTable[i].ip,pkt->sip)) {
397
                            /*
398
                               the eth field in the ARP table was
399
                               filled previously
400
                            */
401
                            arpTable[i].valid = TRUE;
402
                            /* Send pending packets */
403
                            p1 = (PKT_NXT *)arpTable[i].pkt;
404
                            while (p1 != NULL) {
405
                                q1 = p1;
406
                                p1 = q1->next;
407
                                len = q1->len;
408
                                eth_setHeader((struct ETH_HEADER *)q1,arpTable[i].eth,ETH_IP_TYPE);
409
                                eth_sendPkt(q1,len);
410
                                netbuff_release(&udp_txbuff, (void *)q1);
411
#ifdef __ARP_DBG__
412
sprintf(msg,"Pacchetto : %lp inviato\n",q1);
413
win_puts(&w1,msg);
414
#endif
415
                            }
416
                    }
417
                }
418
            }
419
            sem_post(&arpMutex);
420
        }
421
}
422
 
423
void arp_init(char *localAddr)
424
{
425
    int i;
426
    PID s;
427
    SOFT_TASK_MODEL m;
428
 
429
    struct sigaction action;
430
 
431
    if (!arpIsInstalled) {
432
        for (i = 0; i < ARP_MAX_ENTRIES; i++) arpTable[i].valid = FALSE;
433
 
434
        /* ARP table mutex semaphore */
435
        sem_init(&arpMutex, 0, 1);
436
 
437
        netbuff_init(&arp_txbuff, 1, ARP_LEN);
438
 
439
        ip_str2addr(localAddr,&myIpAddr);
440
 
441
        eth_getAddress(&myEthAddr);
442
 
443
        /* Retry task */
444
        soft_task_default_model(m);
445
        soft_task_def_wcet(m,1000);
446
        soft_task_def_period(m,1000000);
447
        soft_task_def_met(m,1000);
448
        soft_task_def_periodic(m);
449
        soft_task_def_system(m);
450
        soft_task_def_nokill(m);
451
        s = task_create("ArpRetry",arp_retry,&m,NULL);
452
        if (s == NIL) {
453
            kern_printf("Cannot create ArpRetry\n");
454
            sys_end();
455
            l1_exit(-1);
456
        }
457
 
458
        eth_setProtocol(ETH_ARP_TYPE,arp_server_recv);
459
        eth_str2Addr("FF:FF:FF:FF:FF:FF",&broadcast);
460
        eth_str2Addr("00:00:00:00:00:00",&nulladdr);
461
 
462
//      for (i = ARP_ERROR_BASE; i <= XARP_TABLE_FULL; i++)
463
//          exc_set(i, arp_exc);
464
        action.sa_flags = 0;
465
        action.sa_handler = arp_exc;
466
        sigfillset(&action.sa_mask); /* we block all the other signals... */
467
 
468
        if (sigaction(SIGARPFULL, &action, NULL) == -1) {
469
          perror("Error initializing ARP signal...");
470
          sys_abort(AARPFULL);
471
        }
472
 
473
        task_activate(s);
474
        arpIsInstalled = TRUE;
475
    } else cprintf("Arp: already installed!!!!");
476
}