Subversion Repositories shark

Rev

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