Fix a bunch of %lud and %lux
[akaros.git] / kern / src / net / ipifc.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 #define DPRINT if(0)print
17
18 enum {
19         Maxmedia = 32,
20         Nself = Maxmedia*5,
21         NHASH = (1<<6),
22         NCACHE = 256,
23         QMAX = 64*1024-1,
24 };
25
26 struct medium *media[Maxmedia] =
27 {
28         0
29 };
30
31 /*
32  *  cache of local addresses (addresses we answer to)
33  */
34 struct Ipself
35 {
36         uint8_t a[IPaddrlen];
37         struct Ipself   *hnext;         /* next address in the hash table */
38         struct Iplink   *link;          /* binding twixt Ipself and Ipifc */
39         uint32_t        expire;
40         uint8_t type;           /* type of address */
41         int     ref;
42         struct Ipself   *next;          /* free list */
43 };
44
45 struct Ipselftab
46 {
47         qlock_t qlock;
48         int     inited;
49         int     acceptall;      /* true if an interface has the null address */
50         struct Ipself   *hash[NHASH];   /* hash chains */
51 };
52
53 /*
54  *  Multicast addresses are chained onto a Chan so that
55  *  we can remove them when the Chan is closed.
56  */
57 typedef struct Ipmcast Ipmcast;
58 struct Ipmcast
59 {
60         Ipmcast *next;
61         uint8_t ma[IPaddrlen];  /* multicast address */
62         uint8_t ia[IPaddrlen];  /* interface address */
63 };
64
65 /* quick hash for ip addresses */
66 #define hashipa(a) ( ( ((a)[IPaddrlen-2]<<8) | (a)[IPaddrlen-1] )%NHASH )
67
68 static char tifc[] = "ifc ";
69
70 static void     addselfcache(struct Fs *f, struct Ipifc *ifc, struct Iplifc *lifc,
71                                 uint8_t *a, int type);
72 static void     remselfcache(struct Fs *f,
73                                 struct Ipifc *ifc,
74                                 struct Iplifc *lifc, uint8_t *a);
75 static char*    ipifcjoinmulti(struct Ipifc *ifc, char **argv, int argc);
76 static char*    ipifcleavemulti(struct Ipifc *ifc, char **argv, int argc);
77 static void     ipifcregisterproxy(struct Fs*, struct Ipifc*, uint8_t *unused_uint8_p_t);
78 static char*    ipifcremlifc(struct Ipifc*, struct Iplifc*);
79
80 /*
81  *  link in a new medium
82  */
83 void
84 addipmedium(struct medium *med)
85 {
86         int i;
87
88         for(i = 0; i < ARRAY_SIZE(media)-1; i++)
89                 if(media[i] == NULL){
90                         media[i] = med;
91                         break;
92                 }
93 }
94
95 /*
96  *  find the medium with this name
97  */
98 struct medium*
99 ipfindmedium(char *name)
100 {
101         struct medium **mp;
102
103         for(mp = media; *mp != NULL; mp++)
104                 if(strcmp((*mp)->name, name) == 0)
105                         break;
106         return *mp;
107 }
108
109 /*
110  *  attach a device (or pkt driver) to the interface.
111  *  called with c locked
112  */
113 static char*
114 ipifcbind(struct conv *c, char **argv, int argc)
115 {
116         ERRSTACK(1);
117         struct Ipifc *ifc;
118         struct medium *m;
119
120         if(argc < 2)
121                 return Ebadarg;
122
123         ifc = (struct Ipifc*)c->ptcl;
124
125         /* bind the device to the interface */
126         m = ipfindmedium(argv[1]);
127         if(m == NULL)
128                 return "unknown interface type";
129
130         wlock(&ifc->rwlock);
131         if(ifc->m != NULL){
132                 wunlock(&ifc->rwlock);
133                 return "interface already bound";       
134         }
135         if(waserror()){
136                 wunlock(&ifc->rwlock);
137                 nexterror();
138         }
139
140         /* do medium specific binding */
141         (*m->bind)(ifc, argc, argv);
142
143         /* set the bound device name */
144         if(argc > 2)
145                 strncpy(ifc->dev, argv[2], sizeof(ifc->dev));
146         else
147                 snprintf(ifc->dev, sizeof ifc->dev, "%s%d", m->name, c->x);
148         ifc->dev[sizeof(ifc->dev)-1] = 0;
149
150         /* set up parameters */
151         ifc->m = m;
152         ifc->mintu = ifc->m->mintu;
153         ifc->maxtu = ifc->m->maxtu;
154         if(ifc->m->unbindonclose == 0)
155                 ifc->conv->inuse++;
156         ifc->rp.mflag = 0;              // default not managed
157         ifc->rp.oflag = 0;
158         ifc->rp.maxraint = 600000;      // millisecs
159         ifc->rp.minraint = 200000;
160         ifc->rp.linkmtu = 0;            // no mtu sent
161         ifc->rp.reachtime = 0;
162         ifc->rp.rxmitra = 0;
163         ifc->rp.ttl = MAXTTL;
164         ifc->rp.routerlt = 3*(ifc->rp.maxraint);
165
166         /* any ancillary structures (like routes) no longer pertain */
167         ifc->ifcid++;
168
169         /* reopen all the queues closed by a previous unbind */
170         qreopen(c->rq);
171         qreopen(c->eq);
172         qreopen(c->sq);
173
174         wunlock(&ifc->rwlock);
175         poperror();
176
177         return NULL;
178 }
179
180 /*
181  *  detach a device from an interface, close the interface
182  *  called with ifc->conv closed
183  */
184 static char*
185 ipifcunbind(struct Ipifc *ifc)
186 {
187         ERRSTACK(1);
188         char *err;
189
190         if(waserror()){
191                 wunlock(&ifc->rwlock);
192                 nexterror();
193         }
194         wlock(&ifc->rwlock);
195
196         /* dissociate routes */
197         if(ifc->m != NULL && ifc->m->unbindonclose == 0)
198                 ifc->conv->inuse--;
199         ifc->ifcid++;
200
201         /* disassociate device */
202         if(ifc->m != NULL && ifc->m->unbind)
203                 (*ifc->m->unbind)(ifc);
204         memset(ifc->dev, 0, sizeof(ifc->dev));
205         ifc->arg = NULL;
206         ifc->reassemble = 0;
207
208         /* close queues to stop queuing of packets */
209         qclose(ifc->conv->rq);
210         qclose(ifc->conv->wq);
211         qclose(ifc->conv->sq);
212
213         /* disassociate logical interfaces */
214         while(ifc->lifc){
215                 err = ipifcremlifc(ifc, ifc->lifc);
216                 if(err)
217                         error(err);
218         }
219
220         ifc->m = NULL;
221         wunlock(&ifc->rwlock);
222         poperror();
223         return NULL;
224 }
225
226
227
228 char sfixedformat[] = "device %s maxtu %d sendra %d recvra %d mflag %d oflag %d maxraint %d minraint %d linkmtu %d reachtime %d rxmitra %d ttl %d routerlt %d pktin %lu pktout %lu errin %lu errout %lu\n";
229
230 char slineformat[] = "  %-40I %-10M %-40I %-12lu %-12lu\n";
231
232
233 static int
234 ipifcstate(struct conv *c, char *state, int n)
235 {
236         struct Ipifc *ifc;
237         struct Iplifc *lifc;
238         int m;
239
240         ifc = (struct Ipifc*)c->ptcl;
241
242         m = snprintf(state, n, sfixedformat,
243                 ifc->dev, ifc->maxtu, ifc->sendra6, ifc->recvra6,
244                      ifc->rp.mflag, ifc->rp.oflag, ifc->rp.maxraint,
245                      ifc->rp.minraint, ifc->rp.linkmtu, ifc->rp.reachtime,
246                      ifc->rp.rxmitra, ifc->rp.ttl, ifc->rp.routerlt,
247                      ifc->in, ifc->out, ifc->inerr, ifc->outerr);
248
249         rlock(&ifc->rwlock);
250         for(lifc = ifc->lifc; lifc && n > m; lifc = lifc->next)
251                 m += snprintf(state+m, n - m, slineformat,
252                         lifc->local, lifc->mask, lifc->remote,
253                         lifc->validlt, lifc->preflt);
254         if(ifc->lifc == NULL)
255                 m += snprintf(state+m, n - m, "\n");
256         runlock(&ifc->rwlock);
257         return m;
258 }
259
260 static int
261 ipifclocal(struct conv *c, char *state, int n)
262 {
263         struct Ipifc *ifc;
264         struct Iplifc *lifc;
265         struct Iplink *link;
266         int m;
267
268         ifc = (struct Ipifc*)c->ptcl;
269
270         m = 0;
271
272         rlock(&ifc->rwlock);
273         for(lifc = ifc->lifc; lifc; lifc = lifc->next){
274                 m += snprintf(state+m, n - m, "%-40.40I ->", lifc->local);
275                 for(link = lifc->link; link; link = link->lifclink)
276                         m += snprintf(state+m, n - m, " %-40.40I", link->self->a);
277                 m += snprintf(state+m, n - m, "\n");
278         }
279         runlock(&ifc->rwlock);
280         return m;
281 }
282
283 static int
284 ipifcinuse(struct conv *c)
285 {
286         struct Ipifc *ifc;
287
288         ifc = (struct Ipifc*)c->ptcl;
289         return ifc->m != NULL;
290 }
291
292 /*
293  *  called when a process writes to an interface's 'data'
294  */
295 static void
296 ipifckick(void *x)
297 {
298         ERRSTACK(1);
299         struct conv *c = x;
300         struct block *bp;
301         struct Ipifc *ifc;
302
303         bp = qget(c->wq);
304         if(bp == NULL)
305                 return;
306
307         ifc = (struct Ipifc*)c->ptcl;
308         if(!canrlock(&ifc->rwlock)){
309                 freeb(bp);
310                 return;
311         }
312         if(waserror()){
313                 runlock(&ifc->rwlock);
314                 nexterror();
315         }
316         if(ifc->m == NULL || ifc->m->pktin == NULL)
317                 freeb(bp);
318         else
319                 (*ifc->m->pktin)(c->p->f, ifc, bp);
320         runlock(&ifc->rwlock);
321         poperror();
322 }
323
324 /*
325  *  called when a new ipifc structure is created
326  */
327 static void
328 ipifccreate(struct conv *c)
329 {
330         struct Ipifc *ifc;
331
332         c->rq = qopen(QMAX, 0, 0, 0);
333         c->sq = qopen(2*QMAX, 0, 0, 0);
334         c->wq = qopen(QMAX, Qkick, ipifckick, c);
335         ifc = (struct Ipifc*)c->ptcl;
336         ifc->conv = c;
337         ifc->unbinding = 0;
338         ifc->m = NULL;
339         ifc->reassemble = 0;
340 }
341
342 /*
343  *  called after last close of ipifc data or ctl
344  *  called with c locked, we must unlock
345  */
346 static void
347 ipifcclose(struct conv *c)
348 {
349         struct Ipifc *ifc;
350         struct medium *m;
351
352         ifc = (struct Ipifc*)c->ptcl;
353         m = ifc->m;
354         if(m != NULL && m->unbindonclose)
355                 ipifcunbind(ifc);
356 }
357
358 /*
359  *  change an interface's mtu
360  */
361 char*
362 ipifcsetmtu(struct Ipifc *ifc, char **argv, int argc)
363 {
364         int mtu;
365
366         if(argc < 2)
367                 return Ebadarg;
368         if(ifc->m == NULL)
369                 return Ebadarg;
370         mtu = strtoul(argv[1], 0, 0);
371         if(mtu < ifc->m->mintu || mtu > ifc->m->maxtu)
372                 return Ebadarg;
373         ifc->maxtu = mtu;
374         return NULL;
375 }
376
377 /*
378  *  add an address to an interface.
379  */
380 char*
381 ipifcadd(struct Ipifc *ifc, char **argv, int argc, int tentative,
382          struct Iplifc *lifcp)
383 {
384         uint8_t ip[IPaddrlen], mask[IPaddrlen], rem[IPaddrlen];
385         uint8_t bcast[IPaddrlen], net[IPaddrlen];
386         struct Iplifc *lifc, **l;
387         int i, type, mtu;
388         struct Fs *f;
389         int sendnbrdisc = 0;
390
391         if(ifc->m == NULL)
392                 return "ipifc not yet bound to device";
393
394         f = ifc->conv->p->f;
395
396         type = Rifc;
397         memset(ip, 0, IPaddrlen);
398         memset(mask, 0, IPaddrlen);
399         memset(rem, 0, IPaddrlen);
400         switch(argc){
401         case 6:
402                 if(strcmp(argv[5], "proxy") == 0)
403                         type |= Rproxy;
404                 /* fall through */
405         case 5:
406                 mtu = strtoul(argv[4], 0, 0);
407                 if(mtu >= ifc->m->mintu && mtu <= ifc->m->maxtu)
408                         ifc->maxtu = mtu;
409                 /* fall through */
410         case 4:
411                 parseip(ip, argv[1]);
412                 parseipmask(mask, argv[2]);
413                 parseip(rem, argv[3]);
414                 maskip(rem, mask, net);
415                 break;
416         case 3:
417                 parseip(ip, argv[1]);
418                 parseipmask(mask, argv[2]);
419                 maskip(ip, mask, rem);
420                 maskip(rem, mask, net);
421                 break;
422         case 2:
423                 parseip(ip, argv[1]);
424                 memmove(mask, defmask(ip), IPaddrlen);
425                 maskip(ip, mask, rem);
426                 maskip(rem, mask, net);
427                 break;
428         default:
429                 return Ebadarg;
430                 break;
431         }
432         if(isv4(ip))
433                 tentative = 0;
434         wlock(&ifc->rwlock);
435
436         /* ignore if this is already a local address for this ifc */
437         for(lifc = ifc->lifc; lifc; lifc = lifc->next) {
438                 if(ipcmp(lifc->local, ip) == 0) {
439                         if(lifc->tentative != tentative)
440                                 lifc->tentative = tentative;
441                         if(lifcp != NULL) {
442                                 lifc->onlink = lifcp->onlink;
443                                 lifc->autoflag = lifcp->autoflag;
444                                 lifc->validlt = lifcp->validlt;
445                                 lifc->preflt = lifcp->preflt;
446                                 lifc->origint = lifcp->origint;
447                         }
448                         goto out;
449                 }
450         }
451
452         /* add the address to the list of logical ifc's for this ifc */
453         lifc = kzmalloc(sizeof(struct Iplifc), 0);
454         ipmove(lifc->local, ip);
455         ipmove(lifc->mask, mask);
456         ipmove(lifc->remote, rem);
457         ipmove(lifc->net, net);
458         lifc->tentative = tentative;
459         if(lifcp != NULL) {
460                 lifc->onlink = lifcp->onlink;
461                 lifc->autoflag = lifcp->autoflag;
462                 lifc->validlt = lifcp->validlt;
463                 lifc->preflt = lifcp->preflt;
464                 lifc->origint = lifcp->origint;
465         }
466         else {          // default values
467                 lifc->onlink = 1;
468                 lifc->autoflag = 1;
469                 lifc->validlt = 0xffffffff;
470                 lifc->preflt = 0xffffffff;
471                 lifc->origint = NOW / 10^3;
472         }
473         lifc->next = NULL;
474
475         for(l = &ifc->lifc; *l; l = &(*l)->next)
476                 ;
477         *l = lifc;
478
479         /* check for point-to-point interface */
480         if(ipcmp(ip, v6loopback))  /* skip v6 loopback, it's a special address */
481         if(ipcmp(mask, IPallbits) == 0)
482                 type |= Rptpt;
483
484         /* add local routes */
485         if(isv4(ip))
486                 v4addroute(f, tifc, rem+IPv4off, mask+IPv4off, rem+IPv4off, type);
487         else
488                 v6addroute(f, tifc, rem, mask, rem, type);
489
490         addselfcache(f, ifc, lifc, ip, Runi);
491
492         if((type & (Rproxy|Rptpt)) == (Rproxy|Rptpt)){
493                 ipifcregisterproxy(f, ifc, rem);
494                 goto out;
495         }
496
497         if(isv4(ip) || ipcmp(ip, IPnoaddr) == 0) {
498                 /* add subnet directed broadcast address to the self cache */
499                 for(i = 0; i < IPaddrlen; i++)
500                         bcast[i] = (ip[i] & mask[i]) | ~mask[i];
501                 addselfcache(f, ifc, lifc, bcast, Rbcast);
502
503                 /* add subnet directed network address to the self cache */
504                 for(i = 0; i < IPaddrlen; i++)
505                         bcast[i] = (ip[i] & mask[i]) & mask[i];
506                 addselfcache(f, ifc, lifc, bcast, Rbcast);
507
508                 /* add network directed broadcast address to the self cache */
509                 memmove(mask, defmask(ip), IPaddrlen);
510                 for(i = 0; i < IPaddrlen; i++)
511                         bcast[i] = (ip[i] & mask[i]) | ~mask[i];
512                 addselfcache(f, ifc, lifc, bcast, Rbcast);
513
514                 /* add network directed network address to the self cache */
515                 memmove(mask, defmask(ip), IPaddrlen);
516                 for(i = 0; i < IPaddrlen; i++)
517                         bcast[i] = (ip[i] & mask[i]) & mask[i];
518                 addselfcache(f, ifc, lifc, bcast, Rbcast);
519                 
520                 addselfcache(f, ifc, lifc, IPv4bcast, Rbcast);
521         }
522         else {
523                 if(ipcmp(ip, v6loopback) == 0) {
524                         /* add node-local mcast address */
525                         addselfcache(f, ifc, lifc, v6allnodesN, Rmulti);
526
527                         /* add route for all node multicast */
528                         v6addroute(f, tifc, v6allnodesN, v6allnodesNmask, v6allnodesN, Rmulti);
529                 }
530
531                 /* add all nodes multicast address */
532                 addselfcache(f, ifc, lifc, v6allnodesL, Rmulti);
533                 
534                 /* add route for all nodes multicast */
535                 v6addroute(f, tifc, v6allnodesL, v6allnodesLmask, v6allnodesL, Rmulti);
536                 
537                 /* add solicited-node multicast address */
538                 ipv62smcast(bcast, ip);
539                 addselfcache(f, ifc, lifc, bcast, Rmulti);
540
541                 sendnbrdisc = 1;
542         }
543
544         /* register the address on this network for address resolution */
545         if(isv4(ip) && ifc->m->areg != NULL)
546                 (*ifc->m->areg)(ifc, ip);
547
548 out:
549         wunlock(&ifc->rwlock);
550         if(tentative && sendnbrdisc)
551                 icmpns(f, 0, SRC_UNSPEC, ip, TARG_MULTI, ifc->mac);
552         return NULL;
553 }
554
555 /*
556  *  remove a logical interface from an ifc
557  *  always called with ifc wlock'd
558  */
559 static char*
560 ipifcremlifc(struct Ipifc *ifc, struct Iplifc *lifc)
561 {
562         struct Iplifc **l;
563         struct Fs *f;
564
565         f = ifc->conv->p->f;
566
567         /*
568          *  find address on this interface and remove from chain.
569          *  for pt to pt we actually specify the remote address as the
570          *  addresss to remove.
571          */
572         for(l = &ifc->lifc; *l != NULL && *l != lifc; l = &(*l)->next)
573                 ;
574         if(*l == NULL)
575                 return "address not on this interface";
576         *l = lifc->next;
577
578         /* disassociate any addresses */
579         while(lifc->link)
580                 remselfcache(f, ifc, lifc, lifc->link->self->a);
581
582         /* remove the route for this logical interface */
583         if(isv4(lifc->local))
584                 v4delroute(f, lifc->remote+IPv4off, lifc->mask+IPv4off, 1);
585         else {
586                 v6delroute(f, lifc->remote, lifc->mask, 1);
587                 if(ipcmp(lifc->local, v6loopback) == 0)
588                         /* remove route for all node multicast */
589                         v6delroute(f, v6allnodesN, v6allnodesNmask, 1);
590                 else if(memcmp(lifc->local, v6linklocal, v6llpreflen) == 0)
591                         /* remove route for all link multicast */
592                         v6delroute(f, v6allnodesL, v6allnodesLmask, 1);
593         }
594
595         kfree(lifc);
596         return NULL;
597
598 }
599
600 /*
601  *  remove an address from an interface.
602  *  called with c locked
603  */
604 char*
605 ipifcrem(struct Ipifc *ifc, char **argv, int argc)
606 {
607         uint8_t ip[IPaddrlen];
608         uint8_t mask[IPaddrlen];
609         uint8_t rem[IPaddrlen];
610         struct Iplifc *lifc;
611         char *rv;
612
613         if(argc < 3)
614                 return Ebadarg;
615
616         parseip(ip, argv[1]);
617         parseipmask(mask, argv[2]);
618         if(argc < 4)
619                 maskip(ip, mask, rem);
620         else
621                 parseip(rem, argv[3]);
622
623         wlock(&ifc->rwlock);
624
625         /*
626          *  find address on this interface and remove from chain.
627          *  for pt to pt we actually specify the remote address as the
628          *  addresss to remove.
629          */
630         for(lifc = ifc->lifc; lifc != NULL; lifc = lifc->next) {
631                 if (memcmp(ip, lifc->local, IPaddrlen) == 0
632                 && memcmp(mask, lifc->mask, IPaddrlen) == 0
633                 && memcmp(rem, lifc->remote, IPaddrlen) == 0)
634                         break;
635         }
636
637         rv = ipifcremlifc(ifc, lifc);
638         wunlock(&ifc->rwlock);
639         return rv;
640 }
641
642 /*
643  * distribute routes to active interfaces like the
644  * TRIP linecards
645  */
646 void
647 ipifcaddroute(struct Fs *f, int vers, uint8_t *addr, uint8_t *mask,
648               uint8_t *gate, int type)
649 {
650         struct medium *m;
651         struct conv **cp, **e;
652         struct Ipifc *ifc;
653
654         e = &f->ipifc->conv[f->ipifc->nc];
655         for(cp = f->ipifc->conv; cp < e; cp++){
656                 if(*cp != NULL) {
657                         ifc = (struct Ipifc*)(*cp)->ptcl;
658                         m = ifc->m;
659                         if(m == NULL)
660                                 continue;
661                         if(m->addroute != NULL)
662                                 m->addroute(ifc, vers, addr, mask, gate, type);
663                 }
664         }
665 }
666
667 void
668 ipifcremroute(struct Fs *f, int vers, uint8_t *addr, uint8_t *mask)
669 {
670         struct medium *m;
671         struct conv **cp, **e;
672         struct Ipifc *ifc;
673
674         e = &f->ipifc->conv[f->ipifc->nc];
675         for(cp = f->ipifc->conv; cp < e; cp++){
676                 if(*cp != NULL) {
677                         ifc = (struct Ipifc*)(*cp)->ptcl;
678                         m = ifc->m;
679                         if(m == NULL)
680                                 continue;
681                         if(m->remroute != NULL)
682                                 m->remroute(ifc, vers, addr, mask);
683                 }
684         }
685 }
686
687 /*
688  *  associate an address with the interface.  This wipes out any previous
689  *  addresses.  This is a macro that means, remove all the old interfaces
690  *  and add a new one.
691  */
692 static char*
693 ipifcconnect(struct conv* c, char **argv, int argc)
694 {
695         ERRSTACK(1);
696         char *err;
697         struct Ipifc *ifc;
698
699         ifc = (struct Ipifc*)c->ptcl;
700
701         if(ifc->m == NULL)
702                  return "ipifc not yet bound to device";
703
704         if(waserror()){
705                 wunlock(&ifc->rwlock);
706                 nexterror();
707         }
708         wlock(&ifc->rwlock);
709         while(ifc->lifc){
710                 err = ipifcremlifc(ifc, ifc->lifc);
711                 if(err)
712                         error(err);
713         }
714         wunlock(&ifc->rwlock);
715         poperror();
716
717         err = ipifcadd(ifc, argv, argc, 0, NULL);
718         if(err)
719                 return err;
720
721         Fsconnected(c, NULL);
722
723         return NULL;
724 }
725
726 char*
727 ipifcsetpar6(struct Ipifc *ifc, char **argv, int argc)
728 {
729         int i, argsleft, vmax = ifc->rp.maxraint, vmin = ifc->rp.minraint;
730
731         argsleft = argc - 1;
732         i = 1;
733
734         if(argsleft % 2 != 0)
735                 return Ebadarg;
736
737         while (argsleft > 1) {
738                 if(strcmp(argv[i],"recvra")==0)
739                         ifc->recvra6 = (atoi(argv[i+1]) != 0);
740                 else if(strcmp(argv[i],"sendra")==0)
741                         ifc->sendra6 = (atoi(argv[i+1]) != 0);
742                 else if(strcmp(argv[i],"mflag")==0)
743                         ifc->rp.mflag = (atoi(argv[i+1]) != 0);
744                 else if(strcmp(argv[i],"oflag")==0)
745                         ifc->rp.oflag = (atoi(argv[i+1]) != 0);
746                 else if(strcmp(argv[i],"maxraint")==0)
747                         ifc->rp.maxraint = atoi(argv[i+1]);
748                 else if(strcmp(argv[i],"minraint")==0)
749                         ifc->rp.minraint = atoi(argv[i+1]);
750                 else if(strcmp(argv[i],"linkmtu")==0)
751                         ifc->rp.linkmtu = atoi(argv[i+1]);
752                 else if(strcmp(argv[i],"reachtime")==0)
753                         ifc->rp.reachtime = atoi(argv[i+1]);
754                 else if(strcmp(argv[i],"rxmitra")==0)
755                         ifc->rp.rxmitra = atoi(argv[i+1]);
756                 else if(strcmp(argv[i],"ttl")==0)
757                         ifc->rp.ttl = atoi(argv[i+1]);
758                 else if(strcmp(argv[i],"routerlt")==0)
759                         ifc->rp.routerlt = atoi(argv[i+1]);
760                 else
761                         return Ebadarg; 
762
763                 argsleft -= 2;
764                 i += 2;
765         }
766
767         // consistency check
768         if(ifc->rp.maxraint < ifc->rp.minraint) {
769                 ifc->rp.maxraint = vmax;
770                 ifc->rp.minraint = vmin;
771                 return Ebadarg;
772         }
773
774         return NULL;
775 }
776
777 char*
778 ipifcsendra6(struct Ipifc *ifc, char **argv, int argc)
779 {
780         int i;
781         
782         i = 0;
783         if(argc > 1)
784                 i = atoi(argv[1]);
785         ifc->sendra6 = (i!=0);
786         return NULL;
787 }
788
789 char*
790 ipifcrecvra6(struct Ipifc *ifc, char **argv, int argc)
791 {
792         int i;
793         
794         i = 0;
795         if(argc > 1)
796                 i = atoi(argv[1]);
797         ifc->recvra6 = (i!=0);  
798         return NULL;
799 }
800
801 /*
802  *  non-standard control messages.
803  *  called with c locked.
804  */
805 static char*
806 ipifcctl(struct conv* c, char**argv, int argc)
807 {
808         struct Ipifc *ifc;
809         int i;
810
811         ifc = (struct Ipifc*)c->ptcl;
812         if(strcmp(argv[0], "add") == 0)
813                 return ipifcadd(ifc, argv, argc, 0, NULL);
814         else if(strcmp(argv[0], "bootp") == 0)
815                 return bootp(ifc);
816         else if(strcmp(argv[0], "try") == 0)
817                 return ipifcadd(ifc, argv, argc, 1, NULL);
818         else if(strcmp(argv[0], "remove") == 0)
819                 return ipifcrem(ifc, argv, argc);
820         else if(strcmp(argv[0], "unbind") == 0)
821                 return ipifcunbind(ifc);
822         else if(strcmp(argv[0], "joinmulti") == 0)
823                 return ipifcjoinmulti(ifc, argv, argc);
824         else if(strcmp(argv[0], "leavemulti") == 0)
825                 return ipifcleavemulti(ifc, argv, argc);
826         else if(strcmp(argv[0], "mtu") == 0)
827                 return ipifcsetmtu(ifc, argv, argc);
828         else if(strcmp(argv[0], "reassemble") == 0){
829                 ifc->reassemble = 1;
830                 return NULL;
831         }
832         else if(strcmp(argv[0], "iprouting") == 0){
833                 i = 1;
834                 if(argc > 1)
835                         i = atoi(argv[1]);
836                 iprouting(c->p->f, i);
837                 return NULL;
838         }
839         else if(strcmp(argv[0], "addpref6") == 0)
840                 return ipifcaddpref6(ifc, argv, argc);
841         else if(strcmp(argv[0], "setpar6") == 0)
842                 return ipifcsetpar6(ifc, argv, argc);
843         else if(strcmp(argv[0], "sendra6") == 0)
844                 return ipifcsendra6(ifc, argv, argc);
845         else if(strcmp(argv[0], "recvra6") == 0)
846                 return ipifcrecvra6(ifc, argv, argc);
847         return "unsupported ctl";
848 }
849
850 int ipifcstats(struct Proto *ipifc, char *buf, int len)
851 {
852         return ipstats(ipifc->f, buf, len);
853 }
854
855 void
856 ipifcinit(struct Fs *f)
857 {
858         struct Proto *ipifc;
859
860         ipifc = kzmalloc(sizeof(struct Proto), 0);
861         ipifc->name = "ipifc";
862         ipifc->connect = ipifcconnect;
863         ipifc->announce = NULL;
864         ipifc->bind = ipifcbind;
865         ipifc->state = ipifcstate;
866         ipifc->create = ipifccreate;
867         ipifc->close = ipifcclose;
868         ipifc->rcv = NULL;
869         ipifc->ctl = ipifcctl;
870         ipifc->advise = NULL;
871         ipifc->stats = ipifcstats;
872         ipifc->inuse = ipifcinuse;
873         ipifc->local = ipifclocal;
874         ipifc->ipproto = -1;
875         ipifc->nc = Maxmedia;
876         ipifc->ptclsize = sizeof(struct Ipifc);
877
878         f->ipifc = ipifc;                       /* hack for ipifcremroute, findipifc, ... */
879         f->self = kzmalloc(sizeof(struct Ipselftab), 0);        /* hack for ipforme */
880         qlock_init(&f->self->qlock);
881
882         Fsproto(f, ipifc);
883 }
884
885 /*
886  *  add to self routing cache
887  *      called with c locked
888  */
889 static void
890 addselfcache(struct Fs *f, struct Ipifc *ifc,
891              struct Iplifc *lifc, uint8_t *a, int type)
892 {
893         struct Ipself *p;
894         struct Iplink *lp;
895         int h;
896
897         qlock(&f->self->qlock);
898
899         /* see if the address already exists */
900         h = hashipa(a);
901         for(p = f->self->hash[h]; p; p = p->next)
902                 if(memcmp(a, p->a, IPaddrlen) == 0)
903                         break;
904
905         /* allocate a local address and add to hash chain */
906         if(p == NULL){
907                 p = kzmalloc(sizeof(*p), 0);
908                 ipmove(p->a, a);
909                 p->type = type;
910                 p->next = f->self->hash[h];
911                 f->self->hash[h] = p;
912
913                 /* if the null address, accept all packets */
914                 if(ipcmp(a, v4prefix) == 0 || ipcmp(a, IPnoaddr) == 0)
915                         f->self->acceptall = 1;
916         }
917
918         /* look for a link for this lifc */
919         for(lp = p->link; lp; lp = lp->selflink)
920                 if(lp->lifc == lifc)
921                         break;
922
923         /* allocate a lifc-to-local link and link to both */
924         if(lp == NULL){
925                 lp = kzmalloc(sizeof(*lp), 0);
926                 kref_init(&lp->ref, fake_release, 1);
927                 lp->lifc = lifc;
928                 lp->self = p;
929                 lp->selflink = p->link;
930                 p->link = lp;
931                 lp->lifclink = lifc->link;
932                 lifc->link = lp;
933
934                 /* add to routing table */
935                 if(isv4(a))
936                         v4addroute(f, tifc, a+IPv4off, IPallbits+IPv4off, a+IPv4off, type);
937                 else
938                         v6addroute(f, tifc, a, IPallbits, a, type);
939
940                 if((type & Rmulti) && ifc->m->addmulti != NULL)
941                         (*ifc->m->addmulti)(ifc, a, lifc->local);
942         } else {
943                 kref_get(&lp->ref, 1);
944         }
945
946         qunlock(&f->self->qlock);
947 }
948
949 /*
950  *  These structures are unlinked from their chains while
951  *  other threads may be using them.  To avoid excessive locking,
952  *  just put them aside for a while before freeing them.
953  *      called with f->self locked
954  */
955 static struct Iplink *freeiplink;
956 static struct Ipself *freeipself;
957
958 static void
959 iplinkfree(struct Iplink *p)
960 {
961         struct Iplink **l, *np;
962         uint32_t now = NOW;
963
964         l = &freeiplink;
965         for(np = *l; np; np = *l){
966                 if(np->expire > now){
967                         *l = np->next;
968                         kfree(np);
969                         continue;
970                 }
971                 l = &np->next;
972         }
973         p->expire = now + 5000;         /* give other threads 5 secs to get out */
974         p->next = NULL;
975         *l = p;
976 }
977 static void
978 ipselffree(struct Ipself *p)
979 {
980         struct Ipself **l, *np;
981         uint32_t now = NOW;
982
983         l = &freeipself;
984         for(np = *l; np; np = *l){
985                 if(np->expire > now){
986                         *l = np->next;
987                         kfree(np);
988                         continue;
989                 }
990                 l = &np->next;
991         }
992         p->expire = now + 5000;         /* give other threads 5 secs to get out */
993         p->next = NULL;
994         *l = p;
995 }
996
997 /*
998  *  Decrement reference for this address on this link.
999  *  Unlink from selftab if this is the last ref.
1000  *      called with c locked
1001  */
1002 static void
1003 remselfcache(struct Fs *f, struct Ipifc *ifc, struct Iplifc *lifc, uint8_t *a)
1004 {
1005         struct Ipself *p, **l;
1006         struct Iplink *link, **l_self, **l_lifc;
1007
1008         qlock(&f->self->qlock);
1009
1010         /* find the unique selftab entry */
1011         l = &f->self->hash[hashipa(a)];
1012         for(p = *l; p; p = *l){
1013                 if(ipcmp(p->a, a) == 0)
1014                         break;
1015                 l = &p->next;
1016         }
1017
1018         if(p == NULL)
1019                 goto out;
1020
1021         /*
1022          *  walk down links from an ifc looking for one
1023          *  that matches the selftab entry
1024          */
1025         l_lifc = &lifc->link;
1026         for(link = *l_lifc; link; link = *l_lifc){
1027                 if(link->self == p)
1028                         break;
1029                 l_lifc = &link->lifclink;
1030         }
1031
1032         if(link == NULL)
1033                 goto out;
1034
1035         /*
1036          *  walk down the links from the selftab looking for
1037          *  the one we just found
1038          */
1039         l_self = &p->link;
1040         for(link = *l_self; link; link = *l_self){
1041                 if(link == *(l_lifc))
1042                         break;
1043                 l_self = &link->selflink;
1044         }
1045
1046         if(link == NULL)
1047                 panic("remselfcache");
1048
1049         if(kref_refcnt(&link->ref) > 1)
1050                 goto out;
1051
1052         if((p->type & Rmulti) && ifc->m->remmulti != NULL)
1053                 (*ifc->m->remmulti)(ifc, a, lifc->local);
1054
1055         /* ref == 0, remove from both chains and free the link */
1056         *l_lifc = link->lifclink;
1057         *l_self = link->selflink;
1058         iplinkfree(link);
1059
1060         if(p->link != NULL)
1061                 goto out;
1062
1063         /* remove from routing table */
1064         if(isv4(a))
1065                 v4delroute(f, a+IPv4off, IPallbits+IPv4off, 1);
1066         else
1067                 v6delroute(f, a, IPallbits, 1);
1068         
1069         /* no more links, remove from hash and free */
1070         *l = p->next;
1071         ipselffree(p);
1072
1073         /* if IPnoaddr, forget */
1074         if(ipcmp(a, v4prefix) == 0 || ipcmp(a, IPnoaddr) == 0)
1075                 f->self->acceptall = 0;
1076
1077 out:
1078         qunlock(&f->self->qlock);
1079 }
1080
1081 static char *stformat = "%-44.44I %2.2d %4.4s\n";
1082 enum
1083 {
1084         Nstformat= 41,
1085 };
1086
1087 long
1088 ipselftabread(struct Fs *f, char *cp, uint32_t offset, int n)
1089 {
1090         int i, m, nifc, off;
1091         struct Ipself *p;
1092         struct Iplink *link;
1093         char state[8];
1094
1095         m = 0;
1096         off = offset;
1097         qlock(&f->self->qlock);
1098         for(i = 0; i < NHASH && m < n; i++){
1099                 for(p = f->self->hash[i]; p != NULL && m < n; p = p->next){
1100                         nifc = 0;
1101                         for(link = p->link; link; link = link->selflink)
1102                                 nifc++;
1103                         routetype(p->type, state);
1104                         m += snprintf(cp + m, n - m, stformat, p->a, nifc, state);
1105                         if(off > 0){
1106                                 off -= m;
1107                                 m = 0;
1108                         }
1109                 }
1110         }
1111         qunlock(&f->self->qlock);
1112         return m;
1113 }
1114
1115 int
1116 iptentative(struct Fs *f, uint8_t *addr)
1117 {
1118         struct Ipself *p;
1119
1120         p = f->self->hash[hashipa(addr)];
1121         for(; p; p = p->next){
1122                 if(ipcmp(addr, p->a) == 0) {
1123                         return p->link->lifc->tentative;
1124                 }
1125         }
1126         return 0;
1127 }
1128
1129 /*
1130  *  returns
1131  *      0               - no match
1132  *      Runi
1133  *      Rbcast
1134  *      Rmcast
1135  */
1136 int
1137 ipforme(struct Fs *f, uint8_t *addr)
1138 {
1139         struct Ipself *p;
1140
1141         p = f->self->hash[hashipa(addr)];
1142         for(; p; p = p->next){
1143                 if(ipcmp(addr, p->a) == 0)
1144                         return p->type;
1145         }
1146
1147         /* hack to say accept anything */
1148         if(f->self->acceptall)
1149                 return Runi;
1150
1151         return 0;
1152 }
1153
1154 /*
1155  *  find the ifc on same net as the remote system.  If none,
1156  *  return NULL.
1157  */
1158 struct Ipifc*
1159 findipifc(struct Fs *f, uint8_t *remote, int type)
1160 {
1161         struct Ipifc *ifc, *x;
1162         struct Iplifc *lifc;
1163         struct conv **cp, **e;
1164         uint8_t gnet[IPaddrlen];
1165         uint8_t xmask[IPaddrlen];
1166
1167         x = NULL; memset(xmask, 0, IPaddrlen);
1168
1169         /* find most specific match */
1170         e = &f->ipifc->conv[f->ipifc->nc];
1171         for(cp = f->ipifc->conv; cp < e; cp++){
1172                 if(*cp == 0)
1173                         continue;
1174
1175                 ifc = (struct Ipifc*)(*cp)->ptcl;
1176
1177                 for(lifc = ifc->lifc; lifc; lifc = lifc->next){
1178                         maskip(remote, lifc->mask, gnet);
1179                         if(ipcmp(gnet, lifc->net) == 0){
1180                                 if(x == NULL || ipcmp(lifc->mask, xmask) > 0){
1181                                         x = ifc;
1182                                         ipmove(xmask, lifc->mask);
1183                                 }
1184                         }
1185                 }
1186         }
1187         if(x != NULL)
1188                 return x;
1189
1190         /* for now for broadcast and multicast, just use first interface */
1191         if(type & (Rbcast|Rmulti)){
1192                 for(cp = f->ipifc->conv; cp < e; cp++){
1193                         if(*cp == 0)
1194                                 continue;
1195                         ifc = (struct Ipifc*)(*cp)->ptcl;
1196                         if(ifc->lifc != NULL)
1197                                 return ifc;
1198                 }
1199         }
1200                 
1201         return NULL;
1202 }
1203
1204 enum {
1205         unknownv6,
1206         multicastv6,
1207         unspecifiedv6,
1208         linklocalv6,
1209         sitelocalv6,
1210         globalv6,
1211 };
1212
1213 int
1214 v6addrtype(uint8_t *addr)
1215 {
1216         if(isv6global(addr))
1217                 return globalv6;
1218         if(islinklocal(addr))
1219                 return linklocalv6;
1220         if(isv6mcast(addr))
1221                 return multicastv6;
1222         if(issitelocal(addr))
1223                 return sitelocalv6;
1224         return unknownv6;
1225 }
1226
1227 #define v6addrcurr(lifc) (( (lifc)->origint + (lifc)->preflt >= (NOW/10^3) ) || ( (lifc)->preflt == 0xffffffff ))
1228
1229 static void
1230 findprimaryipv6(struct Fs *f, uint8_t *local)
1231 {
1232         struct conv **cp, **e;
1233         struct Ipifc *ifc;
1234         struct Iplifc *lifc;
1235         int atype, atypel;
1236
1237         ipmove(local, v6Unspecified);
1238         atype = unspecifiedv6;
1239
1240         /* find "best" (global > sitelocal > link local > unspecified)
1241          * local address; address must be current */
1242
1243         e = &f->ipifc->conv[f->ipifc->nc];
1244         for(cp = f->ipifc->conv; cp < e; cp++){
1245                 if(*cp == 0)
1246                         continue;
1247                 ifc = (struct Ipifc*)(*cp)->ptcl;
1248                 for(lifc = ifc->lifc; lifc; lifc = lifc->next){
1249                         atypel = v6addrtype(lifc->local);
1250                         if(atypel > atype)
1251                         if(v6addrcurr(lifc)) {
1252                                 ipmove(local, lifc->local);
1253                                 atype = atypel;
1254                                 if(atype == globalv6)
1255                                         return;
1256                         }
1257                 }
1258         }
1259 }
1260
1261 /*
1262  *  returns first ip address configured
1263  */
1264 static void
1265 findprimaryipv4(struct Fs *f, uint8_t *local)
1266 {
1267         struct conv **cp, **e;
1268         struct Ipifc *ifc;
1269         struct Iplifc *lifc;
1270
1271         /* find first ifc local address */
1272         e = &f->ipifc->conv[f->ipifc->nc];
1273         for(cp = f->ipifc->conv; cp < e; cp++){
1274                 if(*cp == 0)
1275                         continue;
1276                 ifc = (struct Ipifc*)(*cp)->ptcl;
1277                 if((lifc = ifc->lifc) != NULL){
1278                         ipmove(local, lifc->local);
1279                         return;
1280                 }
1281         }
1282 }
1283
1284 /*
1285  *  find the local address 'closest' to the remote system, copy it to
1286  *  local and return the ifc for that address
1287  */
1288 void
1289 findlocalip(struct Fs *f, uint8_t *local, uint8_t *remote)
1290 {
1291         struct Ipifc *ifc;
1292         struct Iplifc *lifc;
1293         struct route *r;
1294         uint8_t gate[IPaddrlen];
1295         uint8_t gnet[IPaddrlen];
1296         int version;
1297         int atype = unspecifiedv6, atypel = unknownv6;
1298
1299         qlock(&f->ipifc->qlock);
1300         r = v6lookup(f, remote, NULL);
1301         version = (memcmp(remote, v4prefix, IPv4off) == 0) ? V4 : V6;
1302         
1303         if(r != NULL){
1304                 ifc = r->rt.ifc;
1305                 if(r->rt.type & Rv4)
1306                         v4tov6(gate, r->v4.gate);
1307                 else {
1308                         ipmove(gate, r->v6.gate);
1309                         ipmove(local, v6Unspecified);
1310                 }
1311
1312                 /* find ifc address closest to the gateway to use */
1313                 switch(version) {
1314                 case V4:
1315                         for(lifc = ifc->lifc; lifc; lifc = lifc->next){
1316                                 maskip(gate, lifc->mask, gnet);
1317                                 if(ipcmp(gnet, lifc->net) == 0){
1318                                         ipmove(local, lifc->local);
1319                                         goto out;
1320                                 }
1321                         }
1322                         break;
1323                 case V6:
1324                         for(lifc = ifc->lifc; lifc; lifc = lifc->next){
1325                                 atypel = v6addrtype(lifc->local);
1326                                 maskip(gate, lifc->mask, gnet);
1327                                 if(ipcmp(gnet, lifc->net) == 0)
1328                                 if(atypel > atype)
1329                                 if(v6addrcurr(lifc)) {
1330                                         ipmove(local, lifc->local);
1331                                         atype = atypel;
1332                                         if(atype == globalv6)
1333                                                 break;
1334                                 }
1335                         }
1336                         if(atype > unspecifiedv6)
1337                                 goto out;
1338                         break;
1339                 default:
1340                         panic("findlocalip: version %d", version);
1341                 }
1342         }
1343
1344         switch(version){
1345         case V4:
1346                 findprimaryipv4(f, local);
1347                 break;
1348         case V6:
1349                 findprimaryipv6(f, local);
1350                 break;
1351         default:
1352                 panic("findlocalip2: version %d", version);
1353         }
1354
1355 out:
1356         qunlock(&f->ipifc->qlock);
1357 }
1358
1359 /*
1360  *  return first v4 address associated with an interface
1361  */
1362 int
1363 ipv4local(struct Ipifc *ifc, uint8_t *addr)
1364 {
1365         struct Iplifc *lifc;
1366
1367         for(lifc = ifc->lifc; lifc; lifc = lifc->next){
1368                 if(isv4(lifc->local)){
1369                         memmove(addr, lifc->local+IPv4off, IPv4addrlen);
1370                         return 1;
1371                 }
1372         }
1373         return 0;
1374 }
1375
1376 /*
1377  *  return first v6 address associated with an interface
1378  */
1379 int
1380 ipv6local(struct Ipifc *ifc, uint8_t *addr)
1381 {
1382         struct Iplifc *lifc;
1383
1384         for(lifc = ifc->lifc; lifc; lifc = lifc->next){
1385                 if(!isv4(lifc->local) && !(lifc->tentative)){
1386                         ipmove(addr, lifc->local);
1387                         return 1;
1388                 }
1389         }
1390         return 0;
1391 }
1392
1393 int
1394 ipv6anylocal(struct Ipifc *ifc, uint8_t *addr)
1395 {
1396         struct Iplifc *lifc;
1397
1398         for(lifc = ifc->lifc; lifc; lifc = lifc->next){
1399                 if(!isv4(lifc->local)){
1400                         ipmove(addr, lifc->local);
1401                         return SRC_UNI;
1402                 }
1403         }
1404         return SRC_UNSPEC;
1405 }
1406
1407 /*
1408  *  see if this address is bound to the interface
1409  */
1410 struct Iplifc*
1411 iplocalonifc(struct Ipifc *ifc, uint8_t *ip)
1412 {
1413         struct Iplifc *lifc;
1414
1415         for(lifc = ifc->lifc; lifc; lifc = lifc->next)
1416                 if(ipcmp(ip, lifc->local) == 0)
1417                         return lifc;
1418         return NULL;
1419 }
1420
1421
1422 /*
1423  *  See if we're proxying for this address on this interface
1424  */
1425 int
1426 ipproxyifc(struct Fs *f, struct Ipifc *ifc, uint8_t *ip)
1427 {
1428         struct route *r;
1429         uint8_t net[IPaddrlen];
1430         struct Iplifc *lifc;
1431
1432         /* see if this is a direct connected pt to pt address */
1433         r = v6lookup(f, ip, NULL);
1434         if(r == NULL)
1435                 return 0;
1436         if((r->rt.type & (Rifc|Rproxy)) != (Rifc|Rproxy))
1437                 return 0;
1438
1439         /* see if this is on the right interface */
1440         for(lifc = ifc->lifc; lifc; lifc = lifc->next){
1441                 maskip(ip, lifc->mask, net);
1442                 if(ipcmp(net, lifc->remote) == 0)
1443                         return 1;
1444         }
1445
1446         return 0;
1447 }
1448
1449 /*
1450  *  return multicast version if any
1451  */
1452 int
1453 ipismulticast(uint8_t *ip)
1454 {
1455         if(isv4(ip)){
1456                 if(ip[IPv4off] >= 0xe0 && ip[IPv4off] < 0xf0)
1457                         return V4;
1458         } else {
1459                 if(ip[0] == 0xff)
1460                         return V6;
1461         }
1462         return 0;
1463 }
1464
1465 int
1466 ipisbm(uint8_t *ip)
1467 {
1468         if(isv4(ip)){
1469                 if(ip[IPv4off] >= 0xe0 && ip[IPv4off] < 0xf0)
1470                         return V4;
1471                 if(ipcmp(ip, IPv4bcast) == 0)
1472                         return V4;
1473         } else {
1474                 if(ip[0] == 0xff)
1475                         return V6;
1476         }
1477         return 0;
1478 }
1479
1480
1481 /*
1482  *  add a multicast address to an interface, called with c locked
1483  */
1484 void
1485 ipifcaddmulti(struct conv *c, uint8_t *ma, uint8_t *ia)
1486 {
1487         ERRSTACK(1);
1488         struct Ipifc *ifc;
1489         struct Iplifc *lifc;
1490         struct conv **p;
1491         struct Ipmulti *multi, **l;
1492         struct Fs *f;
1493
1494         f = c->p->f;
1495         
1496         for(l = &c->multi; *l; l = &(*l)->next)
1497                 if(ipcmp(ma, (*l)->ma) == 0)
1498                 if(ipcmp(ia, (*l)->ia) == 0)
1499                         return;         /* it's already there */
1500
1501         multi = *l = kzmalloc(sizeof(*multi), 0);
1502         ipmove(multi->ma, ma);
1503         ipmove(multi->ia, ia);
1504         multi->next = NULL;
1505
1506         for(p = f->ipifc->conv; *p; p++){
1507                 if((*p)->inuse == 0)
1508                         continue;
1509                 ifc = (struct Ipifc*)(*p)->ptcl;
1510                 if(waserror()){
1511                         wunlock(&ifc->rwlock);
1512                         nexterror();
1513                 }
1514                 wlock(&ifc->rwlock);
1515                 for(lifc = ifc->lifc; lifc; lifc = lifc->next)
1516                         if(ipcmp(ia, lifc->local) == 0)
1517                                 addselfcache(f, ifc, lifc, ma, Rmulti);
1518                 wunlock(&ifc->rwlock);
1519                 poperror();
1520         }
1521 }
1522
1523
1524 /*
1525  *  remove a multicast address from an interface, called with c locked
1526  */
1527 void
1528 ipifcremmulti(struct conv *c, uint8_t *ma, uint8_t *ia)
1529 {
1530         ERRSTACK(1);
1531         struct Ipmulti *multi, **l;
1532         struct Iplifc *lifc;
1533         struct conv **p;
1534         struct Ipifc *ifc;
1535         struct Fs *f;
1536
1537         f = c->p->f;
1538         
1539         for(l = &c->multi; *l; l = &(*l)->next)
1540                 if(ipcmp(ma, (*l)->ma) == 0)
1541                 if(ipcmp(ia, (*l)->ia) == 0)
1542                         break;
1543
1544         multi = *l;
1545         if(multi == NULL)
1546                 return;         /* we don't have it open */
1547
1548         *l = multi->next;
1549
1550         for(p = f->ipifc->conv; *p; p++){
1551                 if((*p)->inuse == 0)
1552                         continue;
1553
1554                 ifc = (struct Ipifc*)(*p)->ptcl;
1555                 if(waserror()){
1556                         wunlock(&ifc->rwlock);
1557                         nexterror();
1558                 }
1559                 wlock(&ifc->rwlock);
1560                 for(lifc = ifc->lifc; lifc; lifc = lifc->next)
1561                         if(ipcmp(ia, lifc->local) == 0)
1562                                 remselfcache(f, ifc, lifc, ma);
1563                 wunlock(&ifc->rwlock);
1564                 poperror();
1565         }
1566
1567         kfree(multi);
1568 }
1569
1570 /*
1571  *  make lifc's join and leave multicast groups
1572  */
1573 static char*
1574 ipifcjoinmulti(struct Ipifc *ifc, char **argv, int argc)
1575 {
1576         return NULL;
1577 }
1578
1579 static char*
1580 ipifcleavemulti(struct Ipifc *ifc, char **argv, int argc)
1581 {
1582         return NULL;
1583 }
1584
1585 static void
1586 ipifcregisterproxy(struct Fs *f, struct Ipifc *ifc, uint8_t *ip)
1587 {
1588         struct conv **cp, **e;
1589         struct Ipifc *nifc;
1590         struct Iplifc *lifc;
1591         struct medium *m;
1592         uint8_t net[IPaddrlen];
1593
1594         /* register the address on any network that will proxy for us */
1595         e = &f->ipifc->conv[f->ipifc->nc];
1596
1597         if(!isv4(ip)) { // V6
1598                 for(cp = f->ipifc->conv; cp < e; cp++){
1599                         if(*cp == NULL)
1600                                 continue;
1601                         nifc = (struct Ipifc*)(*cp)->ptcl;
1602                         if(nifc == ifc)
1603                                 continue;
1604         
1605                         rlock(&nifc->rwlock);
1606                         m = nifc->m;
1607                         if(m == NULL || m->addmulti == NULL) {
1608                                 runlock(&nifc->rwlock);
1609                                 continue;
1610                         }
1611                         for(lifc = nifc->lifc; lifc; lifc = lifc->next){
1612                                 maskip(ip, lifc->mask, net);
1613                                 if(ipcmp(net, lifc->remote) == 0) { /* add solicited-node multicast address */
1614                                         ipv62smcast(net, ip);
1615                                         addselfcache(f, nifc, lifc, net, Rmulti);
1616                                         arpenter(f, V6, ip, nifc->mac, 6, 0);
1617                                         //(*m->addmulti)(nifc, net, ip);
1618                                         break;
1619                                 }
1620                         }
1621                         runlock(&nifc->rwlock);
1622                 }
1623                 return;
1624         }
1625         else { // V4
1626                 for(cp = f->ipifc->conv; cp < e; cp++){
1627                         if(*cp == NULL)
1628                                 continue;
1629                         nifc = (struct Ipifc*)(*cp)->ptcl;
1630                         if(nifc == ifc)
1631                                 continue;
1632         
1633                         rlock(&nifc->rwlock);
1634                         m = nifc->m;
1635                         if(m == NULL || m->areg == NULL){
1636                                 runlock(&nifc->rwlock);
1637                                 continue;
1638                         }
1639                         for(lifc = nifc->lifc; lifc; lifc = lifc->next){
1640                                 maskip(ip, lifc->mask, net);
1641                                 if(ipcmp(net, lifc->remote) == 0){
1642                                         (*m->areg)(nifc, ip);
1643                                         break;
1644                                 }
1645                         }
1646                         runlock(&nifc->rwlock);
1647                 }
1648         }
1649 }
1650
1651
1652 // added for new v6 mesg types
1653 static void
1654 adddefroute6(struct Fs *f, uint8_t *gate, int force)
1655 {
1656         struct route *r;
1657
1658         r = v6lookup(f, v6Unspecified, NULL);
1659         if(r!=NULL)
1660         if(!(force) && (strcmp(r->rt.tag,"ra")!=0))     // route entries generated
1661                 return;                 // by all other means take
1662                                         // precedence over router annc
1663
1664         v6delroute(f, v6Unspecified, v6Unspecified, 1);
1665         v6addroute(f, "ra", v6Unspecified, v6Unspecified, gate, 0);
1666 }
1667
1668 enum
1669 {
1670         Ngates = 3,
1671 };
1672
1673 char*
1674 ipifcaddpref6(struct Ipifc *ifc, char**argv, int argc)
1675 {
1676         uint8_t onlink = 1;
1677         uint8_t autoflag = 1;
1678         long    validlt = 0xffffffff;
1679         long    preflt = 0xffffffff;
1680         long    origint = NOW / 10^3;
1681         uint8_t prefix[IPaddrlen];
1682         int     plen = 64;
1683         struct Iplifc   *lifc;
1684         char    addr[40], preflen[6];
1685         char    *params[3];
1686
1687         switch(argc) {
1688         case 7:
1689                 preflt = atoi(argv[6]);
1690                 /* fall through */
1691         case 6:
1692                 validlt = atoi(argv[5]);
1693                 /* fall through */
1694         case 5:
1695                 autoflag =  atoi(argv[4]);
1696                 /* fall through */
1697         case 4:
1698                 onlink = atoi(argv[3]);
1699                 /* fall through */
1700         case 3:
1701                 plen = atoi(argv[2]);
1702         case 2:
1703                 break;
1704         default:
1705                 return Ebadarg;
1706         }
1707
1708         if((parseip(prefix, argv[1])!=6) ||
1709                 (validlt < preflt) ||
1710                 (plen < 0) || (plen > 64) ||
1711                 (islinklocal(prefix))
1712         )
1713                 return Ebadarg;
1714
1715         lifc = kzmalloc(sizeof(struct Iplifc), 0);
1716         lifc->onlink = (onlink!=0);
1717         lifc->autoflag = (autoflag!=0);
1718         lifc->validlt = validlt;
1719         lifc->preflt = preflt;
1720         lifc->origint = origint;
1721
1722         if(ifc->m->pref2addr!=NULL)
1723                 ifc->m->pref2addr(prefix, ifc->mac);
1724         else
1725                 return Ebadarg;
1726         
1727         snprintf(addr, sizeof(addr), "%I", prefix);
1728         snprintf(preflen, sizeof(preflen), "/%d", plen);
1729         params[0] = "add";
1730         params[1] = addr;
1731         params[2] = preflen;
1732
1733         return ipifcadd(ifc, params, 3, 0, lifc);
1734 }
1735