a42f947683ad1dcadeb0aeb4cbe45a71f275e786
[akaros.git] / kern / src / net / arp.c
1 // INFERNO
2 #include <vfs.h>
3 #include <kfs.h>
4 #include <slab.h>
5 #include <kmalloc.h>
6 #include <kref.h>
7 #include <string.h>
8 #include <stdio.h>
9 #include <assert.h>
10 #include <error.h>
11 #include <cpio.h>
12 #include <pmap.h>
13 #include <smp.h>
14 #include <ip.h>
15
16 /*
17  *  address resolution tables
18  */
19
20 enum
21 {
22         NHASH           = (1<<6),
23         NCACHE          = 256,
24
25         AOK             = 1,
26         AWAIT           = 2,
27 };
28
29 char *arpstate[] =
30 {
31         "UNUSED",
32         "OK",
33         "WAIT",
34 };
35
36 /*
37  *  one per Fs
38  */
39 struct arp
40 {
41         qlock_t qlock;
42         struct Fs       *f;
43         struct arpent   *hash[NHASH];
44         struct arpent   cache[NCACHE];
45         struct arpent   *rxmt;
46         struct proc     *rxmitp;        /* neib sol re-transmit proc */
47         struct rendez   rxmtq;
48         struct block    *dropf, *dropl;
49 };
50
51 char *Ebadarp = "bad arp";
52
53 #define haship(s) ((s)[IPaddrlen-1]%NHASH)
54
55 int     ReTransTimer = RETRANS_TIMER;
56 static void     rxmitproc(void *v);
57
58 void
59 arpinit(struct Fs *f)
60 {
61         f->arp = kzmalloc(sizeof(struct arp), 0);
62         f->arp->f = f;
63         f->arp->rxmt = NULL;
64         f->arp->dropf = f->arp->dropl = NULL;
65         kproc("rxmitproc", rxmitproc, f->arp, 0);
66 }
67
68 /*
69  *  create a new arp entry for an ip address.
70  */
71 static struct arpent*
72 newarp6(struct arp *arp, uint8_t *ip, struct Ipifc *ifc, int addrxt)
73 {
74         unsigned int t;
75         struct block *next, *xp;
76         struct arpent *a, *e, *f, **l;
77         struct medium *m = ifc->m;
78         int empty;
79
80         /* find oldest entry */
81         e = &arp->cache[NCACHE];
82         a = arp->cache;
83         t = a->utime;
84         for(f = a; f < e; f++){
85                 if(f->utime < t){
86                         t = f->utime;
87                         a = f;
88                 }
89         }
90
91         /* dump waiting packets */
92         xp = a->hold;
93         a->hold = NULL;
94
95         if(isv4(a->ip)){
96                 while(xp){
97                         next = xp->list;
98                         freeblist(xp);
99                         xp = next;
100                 }
101         }
102         else {  // queue icmp unreachable for rxmitproc later on, w/o arp lock
103                 if(xp){
104                         if(arp->dropl == NULL) 
105                                 arp->dropf = xp;
106                         else
107                                 arp->dropl->list = xp;
108
109                         for(next = xp->list; next; next = next->list)
110                                 xp = next;
111                         arp->dropl = xp;
112                         wakeup(&arp->rxmtq);
113                 }
114         }
115
116         /* take out of current chain */
117         l = &arp->hash[haship(a->ip)];
118         for(f = *l; f; f = f->hash){
119                 if(f == a){
120                         *l = a->hash;
121                         break;
122                 }
123                 l = &f->hash;
124         }
125
126         /* insert into new chain */
127         l = &arp->hash[haship(ip)];
128         a->hash = *l;
129         *l = a;
130
131         memmove(a->ip, ip, sizeof(a->ip));
132         //a->utime = NOW;
133         a->ctime = 0;
134         a->type = m;
135
136         //a->rtime = NOW + ReTransTimer;
137         a->rxtsrem = MAX_MULTICAST_SOLICIT;
138         a->ifc = ifc;
139         a->ifcid = ifc->ifcid;
140
141         /* put to the end of re-transmit chain; addrxt is 0 when isv4(a->ip) */
142         if(!ipismulticast(a->ip) && addrxt){
143                 l = &arp->rxmt;
144                 empty = (*l==NULL);
145
146                 for(f = *l; f; f = f->nextrxt){
147                         if(f == a){
148                                 *l = a->nextrxt;
149                                 break;
150                         }
151                         l = &f->nextrxt;
152                 }
153                 for(f = *l; f; f = f->nextrxt){
154                         l = &f->nextrxt;
155                 }
156                 *l = a;
157                 if(empty) 
158                         wakeup(&arp->rxmtq);
159         }
160
161         a->nextrxt = NULL;
162
163         return a;
164 }
165
166 /* called with arp qlocked */
167
168 void
169 cleanarpent(struct arp *arp, struct arpent *a)
170 {
171         struct arpent *f, **l;
172
173         a->utime = 0;
174         a->ctime = 0;
175         a->type = 0;
176         a->state = 0;
177         
178         /* take out of current chain */
179         l = &arp->hash[haship(a->ip)];
180         for(f = *l; f; f = f->hash){
181                 if(f == a){
182                         *l = a->hash;
183                         break;
184                 }
185                 l = &f->hash;
186         }
187
188         /* take out of re-transmit chain */
189         l = &arp->rxmt;
190         for(f = *l; f; f = f->nextrxt){
191                 if(f == a){
192                         *l = a->nextrxt;
193                         break;
194                 }
195                 l = &f->nextrxt;
196         }
197         a->nextrxt = NULL;
198         a->hash = NULL;
199         a->hold = NULL;
200         a->last = NULL;
201         a->ifc = NULL;
202 }
203
204 /*
205  *  fill in the media address if we have it.  Otherwise return an
206  *  arpent that represents the state of the address resolution FSM
207  *  for ip.  Add the packet to be sent onto the list of packets
208  *  waiting for ip->mac to be resolved.
209  */
210 struct arpent*
211 arpget(struct arp *arp, struct block *bp, int version, struct Ipifc *ifc, uint8_t *ip,
212        uint8_t *mac)
213 {
214         int hash;
215         struct arpent *a;
216         struct medium *type = ifc->m;
217         uint8_t v6ip[IPaddrlen];
218
219         if(version == V4){
220                 v4tov6(v6ip, ip);
221                 ip = v6ip;
222         }
223
224         qlock(&arp->qlock);
225         hash = haship(ip);
226         for(a = arp->hash[hash]; a; a = a->hash){
227                 if(memcmp(ip, a->ip, sizeof(a->ip)) == 0)
228                 if(type == a->type)
229                         break;
230         }
231
232         if(a == NULL){
233                 a = newarp6(arp, ip, ifc, (version != V4));
234                 a->state = AWAIT;
235         }
236 #warning "utime, NOW, rtime, etc."
237         //a->utime = NOW;
238         if(a->state == AWAIT){
239                 if(bp != NULL){
240                         if(a->hold)
241                                 a->last->list = bp;
242                         else
243                                 a->hold = bp;
244                         a->last = bp;
245                         bp->list = NULL; 
246                 }
247                 return a;               /* return with arp qlocked */
248         }
249
250         memmove(mac, a->mac, a->type->maclen);
251
252         /* remove old entries */
253         //if(NOW - a->ctime > 15*60*1000)
254         //      cleanarpent(arp, a);
255
256         qunlock(&arp->qlock);
257         return NULL;
258 }
259
260 /*
261  * called with arp locked
262  */
263 void
264 arprelease(struct arp *arp, struct arpent*a)
265 {
266         qunlock(&arp->qlock);
267 }
268
269 /*
270  * Copy out the mac address from the arpent.  Return the
271  * block waiting to get sent to this mac address.
272  *
273  * called with arp locked
274  */
275 struct block*
276 arpresolve(struct arp *arp, struct arpent *a, struct medium *type, uint8_t *mac)
277 {
278         struct block *bp;
279         struct arpent *f, **l;
280
281         if(!isv4(a->ip)){
282                 l = &arp->rxmt;
283                 for(f = *l; f; f = f->nextrxt){
284                         if(f == a){
285                                 *l = a->nextrxt;
286                                 break;
287                         }
288                         l = &f->nextrxt;
289                 }
290         }
291
292         memmove(a->mac, mac, type->maclen);
293         a->type = type;
294         a->state = AOK;
295         //a->utime = NOW;
296         bp = a->hold;
297         a->hold = NULL;
298         qunlock(&arp->qlock);
299
300         return bp;
301 }
302
303 void
304 arpenter(struct Fs *fs, int version, uint8_t *ip, uint8_t *mac, int n, int refresh)
305 {
306         ERRSTACK(1);
307         struct arp *arp;
308         struct route *r;
309         struct arpent *a, *f, **l;
310         struct Ipifc *ifc;
311         struct medium *type;
312         struct block *bp, *next;
313         uint8_t v6ip[IPaddrlen];
314
315         arp = fs->arp;
316
317         if(n != 6){
318 //              print("arp: len = %d\n", n);
319                 return;
320         }
321
322         switch(version){
323         case V4:
324                 r = v4lookup(fs, ip, NULL);
325                 v4tov6(v6ip, ip);
326                 ip = v6ip;
327                 break;
328         case V6:
329                 r = v6lookup(fs, ip, NULL);
330                 break;
331         default:
332                 panic("arpenter: version %d", version);
333                 return; /* to supress warnings */
334         }
335
336         if(r == NULL){
337 //              print("arp: no route for entry\n");
338                 return;
339         }
340
341         ifc = r->rt.ifc;
342         type = ifc->m;
343
344         qlock(&arp->qlock);
345         for(a = arp->hash[haship(ip)]; a; a = a->hash){
346                 if(a->type != type || (a->state != AWAIT && a->state != AOK))
347                         continue;
348
349                 if(ipcmp(a->ip, ip) == 0){
350                         a->state = AOK;
351                         memmove(a->mac, mac, type->maclen);
352
353                         if(version == V6){
354                                 /* take out of re-transmit chain */
355                                 l = &arp->rxmt;
356                                 for(f = *l; f; f = f->nextrxt){
357                                         if(f == a){
358                                                 *l = a->nextrxt;
359                                                 break;
360                                         }
361                                         l = &f->nextrxt;
362                                 }
363                         }
364
365                         a->ifc = ifc;
366                         a->ifcid = ifc->ifcid;
367                         bp = a->hold;
368                         a->hold = NULL;
369                         if(version == V4)
370                                 ip += IPv4off;
371                         //a->utime = NOW;
372                         a->ctime = a->utime;
373                         qunlock(&arp->qlock);
374
375                         while(bp){
376                                 next = bp->list;
377                                 if(ifc != NULL){
378                                         if(waserror()){
379                                                 runlock(&ifc->rwlock);
380                                                 nexterror();
381                                         }
382                                         rlock(&ifc->rwlock);
383                                         if(ifc->m != NULL)
384                                                 ifc->m->bwrite(ifc, bp, version, ip);
385                                         else
386                                                 freeb(bp);
387                                         runlock(&ifc->rwlock);
388                                         poperror();
389                                 } else
390                                         freeb(bp);
391                                 bp = next;
392                         }
393                         return;
394                 }
395         }
396
397         if(refresh == 0){
398                 a = newarp6(arp, ip, ifc, 0);
399                 a->state = AOK;
400                 a->type = type;
401                 //a->ctime = NOW;
402                 memmove(a->mac, mac, type->maclen);
403         }
404
405         qunlock(&arp->qlock);
406 }
407
408 int
409 arpwrite(struct Fs *fs, char *s, int len)
410 {
411         int n;
412         struct route *r;
413         struct arp *arp;
414         struct block *bp;
415         struct arpent *a, *fl, **l;
416         struct medium *m;
417         char *f[4], buf[256];
418         uint8_t ip[IPaddrlen], mac[MAClen];
419
420         arp = fs->arp;
421
422         if(len == 0)
423                 error(Ebadarp);
424         if(len >= sizeof(buf))
425                 len = sizeof(buf)-1;
426         strncpy(buf, s, len);
427         buf[len] = 0;
428         if(len > 0 && buf[len-1] == '\n')
429                 buf[len-1] = 0;
430
431         n = getfields(buf, f, 4, 1, " ");
432         if(strcmp(f[0], "flush") == 0){
433                 qlock(&arp->qlock);
434                 for(a = arp->cache; a < &arp->cache[NCACHE]; a++){
435                         memset(a->ip, 0, sizeof(a->ip));
436                         memset(a->mac, 0, sizeof(a->mac));
437                         a->hash = NULL;
438                         a->state = 0;
439                         a->utime = 0;
440                         while(a->hold != NULL){
441                                 bp = a->hold->list;
442                                 freeblist(a->hold);
443                                 a->hold = bp;
444                         }
445                 }
446                 memset(arp->hash, 0, sizeof(arp->hash));
447 // clear all pkts on these lists (rxmt, dropf/l)
448                 arp->rxmt = NULL;
449                 arp->dropf = NULL;
450                 arp->dropl = NULL;
451                 qunlock(&arp->qlock);
452         } else if(strcmp(f[0], "add") == 0){
453                 switch(n){
454                 default:
455                         error(Ebadarg);
456                 case 3:
457                         parseip(ip, f[1]);
458                         if(isv4(ip))
459                                 r = v4lookup(fs, ip+IPv4off, NULL);
460                         else
461                                 r = v6lookup(fs, ip, NULL);
462                         if(r == NULL)
463                                 error("Destination unreachable");
464                         m = r->rt.ifc->m;
465                         n = parsemac(mac, f[2], m->maclen);
466                         break;
467                 case 4:
468                         m = ipfindmedium(f[1]);
469                         if(m == NULL)
470                                 error(Ebadarp);
471                         parseip(ip, f[2]);
472                         n = parsemac(mac, f[3], m->maclen);
473                         break;
474                 }
475
476                 if(m->ares == NULL)
477                         error(Ebadarp);
478
479                 m->ares(fs, V6, ip, mac, n, 0);
480         } else if(strcmp(f[0], "del") == 0){
481                 if(n != 2)
482                         error(Ebadarg);
483
484                 parseip(ip, f[1]);
485                 qlock(&arp->qlock);
486
487                 l = &arp->hash[haship(ip)];
488                 for(a = *l; a; a = a->hash){
489                         if(memcmp(ip, a->ip, sizeof(a->ip)) == 0){
490                                 *l = a->hash;
491                                 break;
492                         }
493                         l = &a->hash;
494                 }
495         
496                 if(a){
497                         /* take out of re-transmit chain */
498                         l = &arp->rxmt;
499                         for(fl = *l; fl; fl = fl->nextrxt){
500                                 if(fl == a){
501                                         *l = a->nextrxt;
502                                         break;
503                                 }
504                                 l = &fl->nextrxt;
505                         }
506
507                         a->nextrxt = NULL;
508                         a->hash = NULL;
509                         a->hold = NULL;
510                         a->last = NULL;
511                         a->ifc = NULL;
512                         memset(a->ip, 0, sizeof(a->ip));
513                         memset(a->mac, 0, sizeof(a->mac));
514                 }
515                 qunlock(&arp->qlock);
516         } else
517                 error(Ebadarp);
518
519         return len;
520 }
521
522 enum
523 {
524         Alinelen=       90,
525 };
526
527 char *aformat = "%-6.6s %-8.8s %-40.40I %-32.32s\n";
528
529 static void
530 convmac(char *p, uint8_t *mac, int n)
531 {
532         int left = n;
533         while(n-- > 0){
534                 p += snprintf(p, left, "%2.2ux", *mac++);
535                 left -= n;
536         }
537 }
538
539 int
540 arpread(struct arp *arp, char *p, uint32_t offset, int len)
541 {
542         struct arpent *a;
543         int n;
544         char mac[2*MAClen+1];
545         int left = len;
546         int amt;
547
548         if(offset % Alinelen)
549                 return 0;
550
551         offset = offset/Alinelen;
552         len = len/Alinelen;
553
554         n = 0;
555         for(a = arp->cache; len > 0 && a < &arp->cache[NCACHE]; a++){
556                 if(a->state == 0)
557                         continue;
558                 if(offset > 0){
559                         offset--;
560                         continue;
561                 }
562                 len--;
563                 left--;
564                 qlock(&arp->qlock);
565                 convmac(mac, a->mac, a->type->maclen);
566                 amt = snprintf(p+n, left,
567                               aformat, a->type->name, arpstate[a->state], a->ip, mac);
568                 n += amt;
569                 left -= amt;
570                 qunlock(&arp->qlock);
571         }
572
573         return n;
574 }
575
576 extern int
577 rxmitsols(struct arp *arp)
578 {
579         unsigned int sflag;
580         struct block *next, *xp;
581         struct arpent *a, *b, **l;
582         struct Fs *f;
583         uint8_t ipsrc[IPaddrlen];
584         struct Ipifc *ifc = NULL;
585         long nrxt;
586
587         qlock(&arp->qlock);
588         f = arp->f;
589
590         a = arp->rxmt;
591         if(a==NULL){
592                 nrxt = 0;
593                 goto dodrops;           //return nrxt;
594         }
595         //nrxt = a->rtime - NOW;
596 #warning "NOW"
597         nrxt = 0;
598         if(nrxt > 3*ReTransTimer/4) 
599                 goto dodrops;           //return nrxt;
600
601         for(; a; a = a->nextrxt){
602                 ifc = a->ifc;
603                 assert(ifc != NULL);
604                 if((a->rxtsrem <= 0) || !(canrlock(&ifc->rwlock)) || (a->ifcid != ifc->ifcid)){
605                         xp = a->hold;
606                         a->hold = NULL;
607
608                         if(xp){
609                                 if(arp->dropl == NULL) 
610                                         arp->dropf = xp;
611                                 else
612                                         arp->dropl->list = xp;
613                         }
614
615                         cleanarpent(arp, a);
616                 }
617                 else
618                         break;
619         }
620         if(a == NULL)
621                 goto dodrops;
622
623
624         qunlock(&arp->qlock);   /* for icmpns */
625         if((sflag = ipv6anylocal(ifc, ipsrc)) != SRC_UNSPEC) 
626                 icmpns(f, ipsrc, sflag, a->ip, TARG_MULTI, ifc->mac); 
627
628         runlock(&ifc->rwlock);
629         qlock(&arp->qlock);     
630
631         /* put to the end of re-transmit chain */
632         l = &arp->rxmt;
633         for(b = *l; b; b = b->nextrxt){
634                 if(b == a){
635                         *l = a->nextrxt;
636                         break;
637                 }
638                 l = &b->nextrxt;
639         }
640         for(b = *l; b; b = b->nextrxt){
641                 l = &b->nextrxt;
642         }
643         *l = a;
644         a->rxtsrem--;
645         a->nextrxt = NULL;
646         //a->rtime = NOW + ReTransTimer;
647
648         a = arp->rxmt;
649         if(a==NULL)
650                 nrxt = 0;
651         else 
652                 nrxt = 1; //a->rtime - NOW;
653
654 dodrops:
655         xp = arp->dropf;
656         arp->dropf = NULL;
657         arp->dropl = NULL;
658         qunlock(&arp->qlock);
659
660         for(; xp; xp = next){
661                 next = xp->list;
662                 icmphostunr(f, ifc, xp, icmp6_adr_unreach, 1);
663         }
664
665         return nrxt;
666
667 }
668
669 static int
670 rxready(void *v)
671 {
672         struct arp *arp = (struct arp *) v;
673         int x;
674
675         x = ((arp->rxmt != NULL) || (arp->dropf != NULL));
676
677         return x;
678 }
679
680 static void
681 rxmitproc(void *v)
682 {
683         ERRSTACK(2);
684         struct arp *arp = v;
685         long wakeupat;
686
687         arp->rxmitp = current;
688         //print("arp rxmitproc started\n");
689         if(waserror()){
690                 arp->rxmitp = 0;
691 #warning "pexti"
692                 //pexit("hangup", 1);
693         }
694         for(;;){
695                 wakeupat = rxmitsols(arp);
696                 if(wakeupat == 0) 
697                         sleep(&arp->rxmtq, rxready, v); 
698                 else if(wakeupat > ReTransTimer/4) 
699                         tsleep(&arp->rxmtq, return0, 0, wakeupat); 
700         }
701 }
702