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