Fixes some 32 bit usages of NOW
[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         NHASH = (1 << 6),
22         NCACHE = 256,
23
24         AOK = 1,
25         AWAIT = 2,
26 };
27
28 char *arpstate[] = {
29         "UNUSED",
30         "OK",
31         "WAIT",
32 };
33
34 /*
35  *  one per Fs
36  */
37 struct arp {
38         qlock_t qlock;
39         struct Fs *f;
40         struct arpent *hash[NHASH];
41         struct arpent cache[NCACHE];
42         struct arpent *rxmt;
43         struct proc *rxmitp;            /* neib sol re-transmit proc */
44         struct rendez rxmtq;
45         struct block *dropf, *dropl;
46 };
47
48 char *Ebadarp = "bad arp";
49
50 #define haship(s) ((s)[IPaddrlen-1]%NHASH)
51
52 int ReTransTimer = RETRANS_TIMER;
53 static void rxmitproc(void *v);
54
55 void arpinit(struct Fs *f)
56 {
57         f->arp = kzmalloc(sizeof(struct arp), KMALLOC_WAIT);
58         qlock_init(&f->arp->qlock);
59         rendez_init(&f->arp->rxmtq);
60         f->arp->f = f;
61         f->arp->rxmt = NULL;
62         f->arp->dropf = f->arp->dropl = NULL;
63         ktask("rxmitproc", rxmitproc, f->arp);
64 }
65
66 /*
67  *  create a new arp entry for an ip address.
68  */
69 static struct arpent *newarp6(struct arp *arp, uint8_t * ip, struct Ipifc *ifc,
70                                                           int addrxt)
71 {
72         unsigned int t;
73         struct block *next, *xp;
74         struct arpent *a, *e, *f, **l;
75         struct medium *m = ifc->m;
76         int empty;
77
78         /* find oldest entry */
79         e = &arp->cache[NCACHE];
80         a = arp->cache;
81         t = a->utime;
82         for (f = a; f < e; f++) {
83                 if (f->utime < t) {
84                         t = f->utime;
85                         a = f;
86                 }
87         }
88
89         /* dump waiting packets */
90         xp = a->hold;
91         a->hold = NULL;
92
93         if (isv4(a->ip)) {
94                 while (xp) {
95                         next = xp->list;
96                         freeblist(xp);
97                         xp = next;
98                 }
99         } else {        // queue icmp unreachable for rxmitproc later on, w/o arp lock
100                 if (xp) {
101                         if (arp->dropl == NULL)
102                                 arp->dropf = xp;
103                         else
104                                 arp->dropl->list = xp;
105
106                         for (next = xp->list; next; next = next->list)
107                                 xp = next;
108                         arp->dropl = xp;
109                         rendez_wakeup(&arp->rxmtq);
110                 }
111         }
112
113         /* take out of current chain */
114         l = &arp->hash[haship(a->ip)];
115         for (f = *l; f; f = f->hash) {
116                 if (f == a) {
117                         *l = a->hash;
118                         break;
119                 }
120                 l = &f->hash;
121         }
122
123         /* insert into new chain */
124         l = &arp->hash[haship(ip)];
125         a->hash = *l;
126         *l = a;
127
128         memmove(a->ip, ip, sizeof(a->ip));
129         a->utime = NOW;
130         a->ctime = a->utime;
131         a->type = m;
132
133         a->rtime = NOW + ReTransTimer;
134         a->rxtsrem = MAX_MULTICAST_SOLICIT;
135         a->ifc = ifc;
136         a->ifcid = ifc->ifcid;
137
138         /* put to the end of re-transmit chain; addrxt is 0 when isv4(a->ip) */
139         if (!ipismulticast(a->ip) && addrxt) {
140                 l = &arp->rxmt;
141                 empty = (*l == NULL);
142
143                 for (f = *l; f; f = f->nextrxt) {
144                         if (f == a) {
145                                 *l = a->nextrxt;
146                                 break;
147                         }
148                         l = &f->nextrxt;
149                 }
150                 for (f = *l; f; f = f->nextrxt) {
151                         l = &f->nextrxt;
152                 }
153                 *l = a;
154                 if (empty)
155                         rendez_wakeup(&arp->rxmtq);
156         }
157
158         a->nextrxt = NULL;
159
160         return a;
161 }
162
163 /* called with arp qlocked */
164
165 void cleanarpent(struct arp *arp, struct arpent *a)
166 {
167         struct arpent *f, **l;
168
169         a->utime = 0;
170         a->ctime = 0;
171         a->type = 0;
172         a->state = 0;
173
174         /* take out of current chain */
175         l = &arp->hash[haship(a->ip)];
176         for (f = *l; f; f = f->hash) {
177                 if (f == a) {
178                         *l = a->hash;
179                         break;
180                 }
181                 l = &f->hash;
182         }
183
184         /* take out of re-transmit chain */
185         l = &arp->rxmt;
186         for (f = *l; f; f = f->nextrxt) {
187                 if (f == a) {
188                         *l = a->nextrxt;
189                         break;
190                 }
191                 l = &f->nextrxt;
192         }
193         a->nextrxt = NULL;
194         a->hash = NULL;
195         a->hold = NULL;
196         a->last = NULL;
197         a->ifc = NULL;
198 }
199
200 /*
201  *  fill in the media address if we have it.  Otherwise return an
202  *  arpent that represents the state of the address resolution FSM
203  *  for ip.  Add the packet to be sent onto the list of packets
204  *  waiting for ip->mac to be resolved.
205  */
206 struct arpent *arpget(struct arp *arp, struct block *bp, int version,
207                                           struct Ipifc *ifc, uint8_t * ip, uint8_t * mac)
208 {
209         int hash, len;
210         struct arpent *a;
211         struct medium *type = ifc->m;
212         uint8_t v6ip[IPaddrlen];
213         uint16_t *s, *d;
214
215         if (version == V4) {
216                 v4tov6(v6ip, ip);
217                 ip = v6ip;
218         }
219
220         qlock(&arp->qlock);
221         hash = haship(ip);
222         for (a = arp->hash[hash]; a; a = a->hash) {
223                 if (ipcmp(ip, a->ip) == 0)
224                         if (type == a->type)
225                                 break;
226         }
227
228         if (a == NULL) {
229                 a = newarp6(arp, ip, ifc, (version != V4));
230                 a->state = AWAIT;
231         }
232         a->utime = NOW;
233         if (a->state == AWAIT) {
234                 if (bp != NULL) {
235                         if (a->hold)
236                                 a->last->list = bp;
237                         else
238                                 a->hold = bp;
239                         a->last = bp;
240                         bp->list = NULL;
241                 }
242                 return a;       /* return with arp qlocked */
243         }
244
245         s = (uint16_t *)a->mac;
246         d = (uint16_t *)mac;
247         len = a->type->maclen / 2;
248         while (len) {
249                 *d++ = *s++;
250                 len--;
251         }
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 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 *arpresolve(struct arp *arp, struct arpent *a, struct medium *type,
276                                                  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         /* brho: it looks like we return the entire hold list, though it might be
299          * purged by now via some other crazy arp list management.  our callers
300          * can't handle the arp's b->list stuff. */
301         assert(!bp->list);
302         qunlock(&arp->qlock);
303
304         return bp;
305 }
306
307 void
308 arpenter(struct Fs *fs, int version, uint8_t * ip, uint8_t * mac, int n,
309                  int refresh)
310 {
311         ERRSTACK(1);
312         struct arp *arp;
313         struct route *r;
314         struct arpent *a, *f, **l;
315         struct Ipifc *ifc;
316         struct medium *type;
317         struct block *bp, *next;
318         uint8_t v6ip[IPaddrlen];
319
320         arp = fs->arp;
321
322         if (n != 6) {
323 //      print("arp: len = %d\n", n);
324                 return;
325         }
326
327         switch (version) {
328                 case V4:
329                         r = v4lookup(fs, ip, NULL);
330                         v4tov6(v6ip, ip);
331                         ip = v6ip;
332                         break;
333                 case V6:
334                         r = v6lookup(fs, ip, NULL);
335                         break;
336                 default:
337                         panic("arpenter: version %d", version);
338                         return; /* to supress warnings */
339         }
340
341         if (r == NULL) {
342 //      print("arp: no route for entry\n");
343                 return;
344         }
345
346         ifc = r->rt.ifc;
347         type = ifc->m;
348
349         qlock(&arp->qlock);
350         for (a = arp->hash[haship(ip)]; a; a = a->hash) {
351                 if (a->type != type || (a->state != AWAIT && a->state != AOK))
352                         continue;
353
354                 if (ipcmp(a->ip, ip) == 0) {
355                         a->state = AOK;
356                         memmove(a->mac, mac, type->maclen);
357
358                         if (version == V6) {
359                                 /* take out of re-transmit chain */
360                                 l = &arp->rxmt;
361                                 for (f = *l; f; f = f->nextrxt) {
362                                         if (f == a) {
363                                                 *l = a->nextrxt;
364                                                 break;
365                                         }
366                                         l = &f->nextrxt;
367                                 }
368                         }
369
370                         a->ifc = ifc;
371                         a->ifcid = ifc->ifcid;
372                         bp = a->hold;
373                         a->hold = NULL;
374                         if (version == V4)
375                                 ip += IPv4off;
376                         a->utime = NOW;
377                         a->ctime = a->utime;
378                         qunlock(&arp->qlock);
379
380                         while (bp) {
381                                 next = bp->list;
382                                 if (ifc != NULL) {
383                                         if (waserror()) {
384                                                 runlock(&ifc->rwlock);
385                                                 nexterror();
386                                         }
387                                         rlock(&ifc->rwlock);
388                                         if (ifc->m != NULL)
389                                                 ifc->m->bwrite(ifc, bp, version, ip);
390                                         else
391                                                 freeb(bp);
392                                         runlock(&ifc->rwlock);
393                                         poperror();
394                                 } else
395                                         freeb(bp);
396                                 bp = next;
397                         }
398                         return;
399                 }
400         }
401
402         if (refresh == 0) {
403                 a = newarp6(arp, ip, ifc, 0);
404                 a->state = AOK;
405                 a->type = type;
406                 a->ctime = NOW;
407                 memmove(a->mac, mac, type->maclen);
408         }
409
410         qunlock(&arp->qlock);
411 }
412
413 int arpwrite(struct Fs *fs, char *s, int len)
414 {
415         int n;
416         struct route *r;
417         struct arp *arp;
418         struct block *bp;
419         struct arpent *a, *fl, **l;
420         struct medium *m;
421         char *f[4], buf[256];
422         uint8_t ip[IPaddrlen], mac[MAClen];
423
424         arp = fs->arp;
425
426         if (len == 0)
427                 error(Ebadarp);
428         if (len >= sizeof(buf))
429                 len = sizeof(buf) - 1;
430         strncpy(buf, s, len);
431         buf[len] = 0;
432         if (len > 0 && buf[len - 1] == '\n')
433                 buf[len - 1] = 0;
434
435         n = getfields(buf, f, 4, 1, " ");
436         if (strcmp(f[0], "flush") == 0) {
437                 qlock(&arp->qlock);
438                 for (a = arp->cache; a < &arp->cache[NCACHE]; a++) {
439                         memset(a->ip, 0, sizeof(a->ip));
440                         memset(a->mac, 0, sizeof(a->mac));
441                         a->hash = NULL;
442                         a->state = 0;
443                         a->utime = 0;
444                         while (a->hold != NULL) {
445                                 bp = a->hold->list;
446                                 freeblist(a->hold);
447                                 a->hold = bp;
448                         }
449                 }
450                 memset(arp->hash, 0, sizeof(arp->hash));
451 // clear all pkts on these lists (rxmt, dropf/l)
452                 arp->rxmt = NULL;
453                 arp->dropf = NULL;
454                 arp->dropl = NULL;
455                 qunlock(&arp->qlock);
456         } else if (strcmp(f[0], "add") == 0) {
457                 switch (n) {
458                         default:
459                                 error(Ebadarg);
460                         case 3:
461                                 parseip(ip, f[1]);
462                                 if (isv4(ip))
463                                         r = v4lookup(fs, ip + IPv4off, NULL);
464                                 else
465                                         r = v6lookup(fs, ip, NULL);
466                                 if (r == NULL)
467                                         error("Destination unreachable");
468                                 m = r->rt.ifc->m;
469                                 n = parsemac(mac, f[2], m->maclen);
470                                 break;
471                         case 4:
472                                 m = ipfindmedium(f[1]);
473                                 if (m == NULL)
474                                         error(Ebadarp);
475                                 parseip(ip, f[2]);
476                                 n = parsemac(mac, f[3], m->maclen);
477                                 break;
478                 }
479
480                 if (m->ares == NULL)
481                         error(Ebadarp);
482
483                 m->ares(fs, V6, ip, mac, n, 0);
484         } else if (strcmp(f[0], "del") == 0) {
485                 if (n != 2)
486                         error(Ebadarg);
487
488                 parseip(ip, f[1]);
489                 qlock(&arp->qlock);
490
491                 l = &arp->hash[haship(ip)];
492                 for (a = *l; a; a = a->hash) {
493                         if (memcmp(ip, a->ip, sizeof(a->ip)) == 0) {
494                                 *l = a->hash;
495                                 break;
496                         }
497                         l = &a->hash;
498                 }
499
500                 if (a) {
501                         /* take out of re-transmit chain */
502                         l = &arp->rxmt;
503                         for (fl = *l; fl; fl = fl->nextrxt) {
504                                 if (fl == a) {
505                                         *l = a->nextrxt;
506                                         break;
507                                 }
508                                 l = &fl->nextrxt;
509                         }
510
511                         a->nextrxt = NULL;
512                         a->hash = NULL;
513                         a->hold = NULL;
514                         a->last = NULL;
515                         a->ifc = NULL;
516                         memset(a->ip, 0, sizeof(a->ip));
517                         memset(a->mac, 0, sizeof(a->mac));
518                 }
519                 qunlock(&arp->qlock);
520         } else
521                 error(Ebadarp);
522
523         return len;
524 }
525
526 enum {
527         Alinelen = 90,
528 };
529
530 char *aformat = "%-6.6s %-8.8s %-40.40I %E\n";
531
532 static void convmac(char *p, uint8_t * mac, int n)
533 {
534         int left = n;
535         while (n-- > 0) {
536                 p += snprintf(p, left, "%02x", *mac++);
537                 if (n > 1)
538                         p += snprintf(p, left, ":");
539                 left -= n;
540         }
541 }
542
543 int arpread(struct arp *arp, char *p, uint32_t offset, int len)
544 {
545         struct arpent *a;
546         int n;
547         char mac[2 * MAClen + 1];
548         int left = len;
549         int amt;
550
551         if (offset % Alinelen)
552                 return 0;
553
554         offset = offset / Alinelen;
555         len = len / Alinelen;
556
557         n = 0;
558         for (a = arp->cache; len > 0 && a < &arp->cache[NCACHE]; a++) {
559                 if (a->state == 0)
560                         continue;
561                 if (offset > 0) {
562                         offset--;
563                         continue;
564                 }
565                 len--;
566                 left--;
567                 qlock(&arp->qlock);
568                 convmac(mac, a->mac, a->type->maclen);
569                 amt = snprintf(p + n, left,
570                                            aformat, a->type->name, arpstate[a->state], a->ip, mac);
571                 n += amt;
572                 left -= amt;
573                 qunlock(&arp->qlock);
574         }
575
576         return n;
577 }
578
579 static uint64_t rxmitsols(struct arp *arp)
580 {
581         unsigned int sflag;
582         struct block *next, *xp;
583         struct arpent *a, *b, **l;
584         struct Fs *f;
585         uint8_t ipsrc[IPaddrlen];
586         struct Ipifc *ifc = NULL;
587         uint64_t nrxt;
588
589         qlock(&arp->qlock);
590         f = arp->f;
591
592         a = arp->rxmt;
593         if (a == NULL) {
594                 nrxt = 0;
595                 goto dodrops;   //return nrxt;
596         }
597         nrxt = a->rtime - NOW;
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))
605                         || (a->ifcid != ifc->ifcid)) {
606                         xp = a->hold;
607                         a->hold = NULL;
608
609                         if (xp) {
610                                 if (arp->dropl == NULL)
611                                         arp->dropf = xp;
612                                 else
613                                         arp->dropl->list = xp;
614                         }
615
616                         cleanarpent(arp, a);
617                 } else
618                         break;
619         }
620         if (a == NULL)
621                 goto dodrops;
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 rxready(void *v)
669 {
670         struct arp *arp = (struct arp *)v;
671         int x;
672
673         x = ((arp->rxmt != NULL) || (arp->dropf != NULL));
674
675         return x;
676 }
677
678 static void rxmitproc(void *v)
679 {
680         ERRSTACK(2);
681         struct arp *arp = v;
682         uint64_t 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 }