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