waserror() audit
[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         ktask("rxmitproc", rxmitproc, f->arp);
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                         rendez_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                         rendez_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         a->utime = NOW;
237         if(a->state == AWAIT){
238                 if(bp != NULL){
239                         if(a->hold)
240                                 a->last->list = bp;
241                         else
242                                 a->hold = bp;
243                         a->last = bp;
244                         bp->list = NULL; 
245                 }
246                 return a;               /* return with arp qlocked */
247         }
248
249         memmove(mac, a->mac, a->type->maclen);
250
251         /* remove old entries */
252         if(NOW - a->ctime > 15*60*1000)
253                 cleanarpent(arp, a);
254
255         qunlock(&arp->qlock);
256         return NULL;
257 }
258
259 /*
260  * called with arp locked
261  */
262 void
263 arprelease(struct arp *arp, struct arpent*a)
264 {
265         qunlock(&arp->qlock);
266 }
267
268 /*
269  * Copy out the mac address from the arpent.  Return the
270  * block waiting to get sent to this mac address.
271  *
272  * called with arp locked
273  */
274 struct block*
275 arpresolve(struct arp *arp, struct arpent *a, struct medium *type, uint8_t *mac)
276 {
277         struct block *bp;
278         struct arpent *f, **l;
279
280         if(!isv4(a->ip)){
281                 l = &arp->rxmt;
282                 for(f = *l; f; f = f->nextrxt){
283                         if(f == a){
284                                 *l = a->nextrxt;
285                                 break;
286                         }
287                         l = &f->nextrxt;
288                 }
289         }
290
291         memmove(a->mac, mac, type->maclen);
292         a->type = type;
293         a->state = AOK;
294         a->utime = NOW;
295         bp = a->hold;
296         a->hold = NULL;
297         qunlock(&arp->qlock);
298
299         return bp;
300 }
301
302 void
303 arpenter(struct Fs *fs, int version, uint8_t *ip, uint8_t *mac, int n, int refresh)
304 {
305         ERRSTACK(1);
306         struct arp *arp;
307         struct route *r;
308         struct arpent *a, *f, **l;
309         struct Ipifc *ifc;
310         struct medium *type;
311         struct block *bp, *next;
312         uint8_t v6ip[IPaddrlen];
313
314         arp = fs->arp;
315
316         if(n != 6){
317 //              print("arp: len = %d\n", n);
318                 return;
319         }
320
321         switch(version){
322         case V4:
323                 r = v4lookup(fs, ip, NULL);
324                 v4tov6(v6ip, ip);
325                 ip = v6ip;
326                 break;
327         case V6:
328                 r = v6lookup(fs, ip, NULL);
329                 break;
330         default:
331                 panic("arpenter: version %d", version);
332                 return; /* to supress warnings */
333         }
334
335         if(r == NULL){
336 //              print("arp: no route for entry\n");
337                 return;
338         }
339
340         ifc = r->rt.ifc;
341         type = ifc->m;
342
343         qlock(&arp->qlock);
344         for(a = arp->hash[haship(ip)]; a; a = a->hash){
345                 if(a->type != type || (a->state != AWAIT && a->state != AOK))
346                         continue;
347
348                 if(ipcmp(a->ip, ip) == 0){
349                         a->state = AOK;
350                         memmove(a->mac, mac, type->maclen);
351
352                         if(version == V6){
353                                 /* take out of re-transmit chain */
354                                 l = &arp->rxmt;
355                                 for(f = *l; f; f = f->nextrxt){
356                                         if(f == a){
357                                                 *l = a->nextrxt;
358                                                 break;
359                                         }
360                                         l = &f->nextrxt;
361                                 }
362                         }
363
364                         a->ifc = ifc;
365                         a->ifcid = ifc->ifcid;
366                         bp = a->hold;
367                         a->hold = NULL;
368                         if(version == V4)
369                                 ip += IPv4off;
370                         a->utime = NOW;
371                         a->ctime = a->utime;
372                         qunlock(&arp->qlock);
373
374                         while(bp){
375                                 next = bp->list;
376                                 if(ifc != NULL){
377                                         if(waserror()){
378                                                 runlock(&ifc->rwlock);
379                                                 nexterror();
380                                         }
381                                         rlock(&ifc->rwlock);
382                                         if(ifc->m != NULL)
383                                                 ifc->m->bwrite(ifc, bp, version, ip);
384                                         else
385                                                 freeb(bp);
386                                         runlock(&ifc->rwlock);
387                                         poperror();
388                                 } else
389                                         freeb(bp);
390                                 bp = next;
391                         }
392                         return;
393                 }
394         }
395
396         if(refresh == 0){
397                 a = newarp6(arp, ip, ifc, 0);
398                 a->state = AOK;
399                 a->type = type;
400                 a->ctime = NOW;
401                 memmove(a->mac, mac, type->maclen);
402         }
403
404         qunlock(&arp->qlock);
405 }
406
407 int
408 arpwrite(struct Fs *fs, char *s, int len)
409 {
410         int n;
411         struct route *r;
412         struct arp *arp;
413         struct block *bp;
414         struct arpent *a, *fl, **l;
415         struct medium *m;
416         char *f[4], buf[256];
417         uint8_t ip[IPaddrlen], mac[MAClen];
418
419         arp = fs->arp;
420
421         if(len == 0)
422                 error(Ebadarp);
423         if(len >= sizeof(buf))
424                 len = sizeof(buf)-1;
425         strncpy(buf, s, len);
426         buf[len] = 0;
427         if(len > 0 && buf[len-1] == '\n')
428                 buf[len-1] = 0;
429
430         n = getfields(buf, f, 4, 1, " ");
431         if(strcmp(f[0], "flush") == 0){
432                 qlock(&arp->qlock);
433                 for(a = arp->cache; a < &arp->cache[NCACHE]; a++){
434                         memset(a->ip, 0, sizeof(a->ip));
435                         memset(a->mac, 0, sizeof(a->mac));
436                         a->hash = NULL;
437                         a->state = 0;
438                         a->utime = 0;
439                         while(a->hold != NULL){
440                                 bp = a->hold->list;
441                                 freeblist(a->hold);
442                                 a->hold = bp;
443                         }
444                 }
445                 memset(arp->hash, 0, sizeof(arp->hash));
446 // clear all pkts on these lists (rxmt, dropf/l)
447                 arp->rxmt = NULL;
448                 arp->dropf = NULL;
449                 arp->dropl = NULL;
450                 qunlock(&arp->qlock);
451         } else if(strcmp(f[0], "add") == 0){
452                 switch(n){
453                 default:
454                         error(Ebadarg);
455                 case 3:
456                         parseip(ip, f[1]);
457                         if(isv4(ip))
458                                 r = v4lookup(fs, ip+IPv4off, NULL);
459                         else
460                                 r = v6lookup(fs, ip, NULL);
461                         if(r == NULL)
462                                 error("Destination unreachable");
463                         m = r->rt.ifc->m;
464                         n = parsemac(mac, f[2], m->maclen);
465                         break;
466                 case 4:
467                         m = ipfindmedium(f[1]);
468                         if(m == NULL)
469                                 error(Ebadarp);
470                         parseip(ip, f[2]);
471                         n = parsemac(mac, f[3], m->maclen);
472                         break;
473                 }
474
475                 if(m->ares == NULL)
476                         error(Ebadarp);
477
478                 m->ares(fs, V6, ip, mac, n, 0);
479         } else if(strcmp(f[0], "del") == 0){
480                 if(n != 2)
481                         error(Ebadarg);
482
483                 parseip(ip, f[1]);
484                 qlock(&arp->qlock);
485
486                 l = &arp->hash[haship(ip)];
487                 for(a = *l; a; a = a->hash){
488                         if(memcmp(ip, a->ip, sizeof(a->ip)) == 0){
489                                 *l = a->hash;
490                                 break;
491                         }
492                         l = &a->hash;
493                 }
494         
495                 if(a){
496                         /* take out of re-transmit chain */
497                         l = &arp->rxmt;
498                         for(fl = *l; fl; fl = fl->nextrxt){
499                                 if(fl == a){
500                                         *l = a->nextrxt;
501                                         break;
502                                 }
503                                 l = &fl->nextrxt;
504                         }
505
506                         a->nextrxt = NULL;
507                         a->hash = NULL;
508                         a->hold = NULL;
509                         a->last = NULL;
510                         a->ifc = NULL;
511                         memset(a->ip, 0, sizeof(a->ip));
512                         memset(a->mac, 0, sizeof(a->mac));
513                 }
514                 qunlock(&arp->qlock);
515         } else
516                 error(Ebadarp);
517
518         return len;
519 }
520
521 enum
522 {
523         Alinelen=       90,
524 };
525
526 char *aformat = "%-6.6s %-8.8s %-40.40I %-32.32s\n";
527
528 static void
529 convmac(char *p, uint8_t *mac, int n)
530 {
531         int left = n;
532         while(n-- > 0){
533                 p += snprintf(p, left, "%2.2ux", *mac++);
534                 left -= n;
535         }
536 }
537
538 int
539 arpread(struct arp *arp, char *p, uint32_t offset, int len)
540 {
541         struct arpent *a;
542         int n;
543         char mac[2*MAClen+1];
544         int left = len;
545         int amt;
546
547         if(offset % Alinelen)
548                 return 0;
549
550         offset = offset/Alinelen;
551         len = len/Alinelen;
552
553         n = 0;
554         for(a = arp->cache; len > 0 && a < &arp->cache[NCACHE]; a++){
555                 if(a->state == 0)
556                         continue;
557                 if(offset > 0){
558                         offset--;
559                         continue;
560                 }
561                 len--;
562                 left--;
563                 qlock(&arp->qlock);
564                 convmac(mac, a->mac, a->type->maclen);
565                 amt = snprintf(p+n, left,
566                               aformat, a->type->name, arpstate[a->state], a->ip, mac);
567                 n += amt;
568                 left -= amt;
569                 qunlock(&arp->qlock);
570         }
571
572         return n;
573 }
574
575 extern int
576 rxmitsols(struct arp *arp)
577 {
578         unsigned int sflag;
579         struct block *next, *xp;
580         struct arpent *a, *b, **l;
581         struct Fs *f;
582         uint8_t ipsrc[IPaddrlen];
583         struct Ipifc *ifc = NULL;
584         long nrxt;
585
586         qlock(&arp->qlock);
587         f = arp->f;
588
589         a = arp->rxmt;
590         if(a==NULL){
591                 nrxt = 0;
592                 goto dodrops;           //return nrxt;
593         }
594         nrxt = a->rtime - NOW;
595         if(nrxt > 3*ReTransTimer/4) 
596                 goto dodrops;           //return nrxt;
597
598         for(; a; a = a->nextrxt){
599                 ifc = a->ifc;
600                 assert(ifc != NULL);
601                 if((a->rxtsrem <= 0) || !(canrlock(&ifc->rwlock)) || (a->ifcid != ifc->ifcid)){
602                         xp = a->hold;
603                         a->hold = NULL;
604
605                         if(xp){
606                                 if(arp->dropl == NULL) 
607                                         arp->dropf = xp;
608                                 else
609                                         arp->dropl->list = xp;
610                         }
611
612                         cleanarpent(arp, a);
613                 }
614                 else
615                         break;
616         }
617         if(a == NULL)
618                 goto dodrops;
619
620
621         qunlock(&arp->qlock);   /* for icmpns */
622         if((sflag = ipv6anylocal(ifc, ipsrc)) != SRC_UNSPEC) 
623                 icmpns(f, ipsrc, sflag, a->ip, TARG_MULTI, ifc->mac); 
624
625         runlock(&ifc->rwlock);
626         qlock(&arp->qlock);     
627
628         /* put to the end of re-transmit chain */
629         l = &arp->rxmt;
630         for(b = *l; b; b = b->nextrxt){
631                 if(b == a){
632                         *l = a->nextrxt;
633                         break;
634                 }
635                 l = &b->nextrxt;
636         }
637         for(b = *l; b; b = b->nextrxt){
638                 l = &b->nextrxt;
639         }
640         *l = a;
641         a->rxtsrem--;
642         a->nextrxt = NULL;
643         a->rtime = NOW + ReTransTimer;
644
645         a = arp->rxmt;
646         if(a==NULL)
647                 nrxt = 0;
648         else 
649                 nrxt = a->rtime - NOW;
650
651 dodrops:
652         xp = arp->dropf;
653         arp->dropf = NULL;
654         arp->dropl = NULL;
655         qunlock(&arp->qlock);
656
657         for(; xp; xp = next){
658                 next = xp->list;
659                 icmphostunr(f, ifc, xp, icmp6_adr_unreach, 1);
660         }
661
662         return nrxt;
663
664 }
665
666 static int
667 rxready(void *v)
668 {
669         struct arp *arp = (struct arp *) v;
670         int x;
671
672         x = ((arp->rxmt != NULL) || (arp->dropf != NULL));
673
674         return x;
675 }
676
677 static void
678 rxmitproc(void *v)
679 {
680         ERRSTACK(2);
681         struct arp *arp = v;
682         long wakeupat;
683
684         arp->rxmitp = current;
685         //print("arp rxmitproc started\n");
686         if(waserror()){
687                 arp->rxmitp = 0;
688                 poperror();
689                 warn("arp rxmit ktask exited");
690                 return;
691         }
692         for(;;){
693                 wakeupat = rxmitsols(arp);
694                 if(wakeupat == 0) 
695                         rendez_sleep(&arp->rxmtq, rxready, v); 
696                 else if(wakeupat > ReTransTimer/4) 
697                         udelay_sched(wakeupat * 1000); 
698         }
699         poperror();
700 }
701