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