Subversion Repositories shark

Rev

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

Rev Author Line No. Line
583 mauro 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
 ------------
584 mauro 23
 CVS :        $Id: arp.c,v 1.2 2004-04-23 18:13:51 mauro Exp $
583 mauro 24
 
25
 File:        $File$
584 mauro 26
 Revision:    $Revision: 1.2 $
27
 Last update: $Date: 2004-04-23 18:13:51 $
583 mauro 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
 
584 mauro 74
//#define __ARP_DBG__
75
#define ARP_INFO "[ARP] "
76
 
583 mauro 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 {
584 mauro 93
        int len;
94
        void *next;
583 mauro 95
} PKT_NXT;
96
 
97
typedef struct arp_pkt{
584 mauro 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;
583 mauro 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
{
584 mauro 132
        int i, j, minused;
583 mauro 133
 
584 mauro 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
                }
583 mauro 140
        }
584 mauro 141
        if (j == -1) {
142
                cprintf("ARP table overflow.\n");
143
                sys_abort(AARPFULL);
144
        }
145
        arpTable[j].valid = FALSE;
583 mauro 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
{
584 mauro 154
        ARP_PKT *pkt;
155
        BYTE *arpBuff;
583 mauro 156
 
584 mauro 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
        }
583 mauro 172
}
173
 
174
/* Retry task (periodic) */
175
TASK arp_retry(void)
176
{
584 mauro 177
        int i;
178
        PKT_NXT *p, *p1;
583 mauro 179
 
584 mauro 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);
583 mauro 194
#ifdef __ARP_DBG__
584 mauro 195
                                                        printk(KERN_DEBUG ARP_INFO "Pacchetto : %lp scartato.\n",p);
583 mauro 196
#endif
584 mauro 197
                                                        p = p1;
198
                                                }
199
                                                arpTable[i].valid = FALSE;
200
                                        } else {
201
                                                arp_sendRequest(i);
202
                                                arpTable[i].time = ARP_TIMEOUT;
203
                                        }
204
                                }
583 mauro 205
                        }
206
                }
584 mauro 207
                sem_post(&arpMutex);
208
                task_endcycle();
583 mauro 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
{
584 mauro 215
        int j, done;
583 mauro 216
 
584 mauro 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
        }
583 mauro 225
 
584 mauro 226
        if (!done)
227
                return -1;
228
 
229
        /* Fill the entry */
230
        setIpAddr(arpTable[j].ip, dest);
583 mauro 231
#ifdef __ARP_DBG__
584 mauro 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]);
583 mauro 234
#endif
584 mauro 235
        arpTable[j].time = ARP_TIMEOUT;
236
        arpTable[j].ntrans = 0;
237
 
238
        return j;
583 mauro 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
{
584 mauro 247
        int i,j;
248
        PKT_NXT *p,*p1 = NULL;
249
        int caso;
583 mauro 250
 
584 mauro 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
                }
583 mauro 267
        }
268
 
584 mauro 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;
583 mauro 286
#ifdef __ARP_DBG__
584 mauro 287
                printk(KERN_DEBUG ARP_INFO "Pacchetto : %lp accodato.\n", pkt);
583 mauro 288
#endif
584 mauro 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;
583 mauro 303
#ifdef __ARP_DBG__
584 mauro 304
                printk(KERN_DEBUG ARP_INFO "Pacchetto : %lp accodato\n", pkt);
583 mauro 305
#endif
584 mauro 306
                /*...and send the request!!! */
307
                arp_sendRequest(j);
308
        }
309
        sem_post(&arpMutex);
583 mauro 310
}
311
 
312
/* ARP packet received CallBack*/
313
void arp_server_recv(void *pk)
314
{
584 mauro 315
        ARP_PKT *pkt,*rpkt;
316
        PKT_NXT *p1,*q1;
317
        int len;
318
        int i,j = 0;
319
        BYTE found;
583 mauro 320
 
321
        pkt = (ARP_PKT *)eth_getFDB(pk);
322
 
323
#if 0
584 mauro 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]);
583 mauro 332
        }
333
#endif
334
 
335
        /* Check if the packet is directed to this host...*/
336
        if (ip_compAddr(pkt->tip,myIpAddr)) {
584 mauro 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
                        }
583 mauro 345
                }
584 mauro 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
                                }
583 mauro 358
                }
584 mauro 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);
583 mauro 391
#ifdef __ARP_DBG__
584 mauro 392
                                                printk(KERN_DEBUG ARP_INFO "Pacchetto : %lp inviato\n", q1);
583 mauro 393
#endif
584 mauro 394
                                        }
395
                                }
396
                        }
583 mauro 397
                }
584 mauro 398
                sem_post(&arpMutex);
583 mauro 399
        }
400
}
401
 
402
void arp_init(char *localAddr)
403
{
584 mauro 404
        int i;
405
        PID s;
406
        SOFT_TASK_MODEL m;
583 mauro 407
 
584 mauro 408
        struct sigaction action;
583 mauro 409
 
584 mauro 410
        if (!arpIsInstalled) {
411
                for (i = 0; i < ARP_MAX_ENTRIES; i++) arpTable[i].valid = FALSE;
583 mauro 412
 
584 mauro 413
                /* ARP table mutex semaphore */
414
                sem_init(&arpMutex, 0, 1);
583 mauro 415
 
584 mauro 416
                netbuff_init(&arp_txbuff, 1, ARP_LEN);
583 mauro 417
 
584 mauro 418
                ip_str2addr(localAddr,&myIpAddr);
583 mauro 419
 
584 mauro 420
                eth_getAddress(&myEthAddr);
583 mauro 421
 
584 mauro 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");
433
                        sys_end();
434
                        l1_exit(-1);
435
                }
583 mauro 436
 
584 mauro 437
                eth_setProtocol(ETH_ARP_TYPE,arp_server_recv);
438
                eth_str2Addr("FF:FF:FF:FF:FF:FF",&broadcast);
439
                eth_str2Addr("00:00:00:00:00:00",&nulladdr);
583 mauro 440
 
584 mauro 441
//              for (i = ARP_ERROR_BASE; i <= XARP_TABLE_FULL; i++)
442
//                      exc_set(i, arp_exc);
443
                action.sa_flags = 0;
444
                action.sa_handler = arp_exc;
445
                sigfillset(&action.sa_mask); /* we block all the other signals... */
583 mauro 446
 
584 mauro 447
                if (sigaction(SIGARPFULL, &action, NULL) == -1) {
448
                        perror("Error initializing ARP signal...");
449
                        sys_abort(AARPFULL);
450
                }
583 mauro 451
 
584 mauro 452
                task_activate(s);
453
                arpIsInstalled = TRUE;
454
        } else
455
                cprintf("Arp: already installed.");
583 mauro 456
}