7797c716aa51e2c493366655ac86f495f44d3a37
[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 %lud pktout %lud errin %lud errout %lud\n";
229
230 char slineformat[] = "  %-40I %-10M %-40I %-12lud %-12lud\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
881         Fsproto(f, ipifc);
882 }
883
884 /*
885  *  add to self routing cache
886  *      called with c locked
887  */
888 static void
889 addselfcache(struct Fs *f, struct Ipifc *ifc,
890              struct Iplifc *lifc, uint8_t *a, int type)
891 {
892         struct Ipself *p;
893         struct Iplink *lp;
894         int h;
895
896         qlock(&f->self->qlock);
897
898         /* see if the address already exists */
899         h = hashipa(a);
900         for(p = f->self->hash[h]; p; p = p->next)
901                 if(memcmp(a, p->a, IPaddrlen) == 0)
902                         break;
903
904         /* allocate a local address and add to hash chain */
905         if(p == NULL){
906                 p = kzmalloc(sizeof(*p), 0);
907                 ipmove(p->a, a);
908                 p->type = type;
909                 p->next = f->self->hash[h];
910                 f->self->hash[h] = p;
911
912                 /* if the null address, accept all packets */
913                 if(ipcmp(a, v4prefix) == 0 || ipcmp(a, IPnoaddr) == 0)
914                         f->self->acceptall = 1;
915         }
916
917         /* look for a link for this lifc */
918         for(lp = p->link; lp; lp = lp->selflink)
919                 if(lp->lifc == lifc)
920                         break;
921
922         /* allocate a lifc-to-local link and link to both */
923         if(lp == NULL){
924                 lp = kzmalloc(sizeof(*lp), 0);
925                 kref_init(&lp->ref, fake_release, 1);
926                 lp->lifc = lifc;
927                 lp->self = p;
928                 lp->selflink = p->link;
929                 p->link = lp;
930                 lp->lifclink = lifc->link;
931                 lifc->link = lp;
932
933                 /* add to routing table */
934                 if(isv4(a))
935                         v4addroute(f, tifc, a+IPv4off, IPallbits+IPv4off, a+IPv4off, type);
936                 else
937                         v6addroute(f, tifc, a, IPallbits, a, type);
938
939                 if((type & Rmulti) && ifc->m->addmulti != NULL)
940                         (*ifc->m->addmulti)(ifc, a, lifc->local);
941         } else {
942                 kref_get(&lp->ref, 1);
943         }
944
945         qunlock(&f->self->qlock);
946 }
947
948 /*
949  *  These structures are unlinked from their chains while
950  *  other threads may be using them.  To avoid excessive locking,
951  *  just put them aside for a while before freeing them.
952  *      called with f->self locked
953  */
954 static struct Iplink *freeiplink;
955 static struct Ipself *freeipself;
956
957 static void
958 iplinkfree(struct Iplink *p)
959 {
960         struct Iplink **l, *np;
961         uint32_t now = NOW;
962
963         l = &freeiplink;
964         for(np = *l; np; np = *l){
965                 if(np->expire > now){
966                         *l = np->next;
967                         kfree(np);
968                         continue;
969                 }
970                 l = &np->next;
971         }
972         p->expire = now + 5000;         /* give other threads 5 secs to get out */
973         p->next = NULL;
974         *l = p;
975 }
976 static void
977 ipselffree(struct Ipself *p)
978 {
979         struct Ipself **l, *np;
980         uint32_t now = NOW;
981
982         l = &freeipself;
983         for(np = *l; np; np = *l){
984                 if(np->expire > now){
985                         *l = np->next;
986                         kfree(np);
987                         continue;
988                 }
989                 l = &np->next;
990         }
991         p->expire = now + 5000;         /* give other threads 5 secs to get out */
992         p->next = NULL;
993         *l = p;
994 }
995
996 /*
997  *  Decrement reference for this address on this link.
998  *  Unlink from selftab if this is the last ref.
999  *      called with c locked
1000  */
1001 static void
1002 remselfcache(struct Fs *f, struct Ipifc *ifc, struct Iplifc *lifc, uint8_t *a)
1003 {
1004         struct Ipself *p, **l;
1005         struct Iplink *link, **l_self, **l_lifc;
1006
1007         qlock(&f->self->qlock);
1008
1009         /* find the unique selftab entry */
1010         l = &f->self->hash[hashipa(a)];
1011         for(p = *l; p; p = *l){
1012                 if(ipcmp(p->a, a) == 0)
1013                         break;
1014                 l = &p->next;
1015         }
1016
1017         if(p == NULL)
1018                 goto out;
1019
1020         /*
1021          *  walk down links from an ifc looking for one
1022          *  that matches the selftab entry
1023          */
1024         l_lifc = &lifc->link;
1025         for(link = *l_lifc; link; link = *l_lifc){
1026                 if(link->self == p)
1027                         break;
1028                 l_lifc = &link->lifclink;
1029         }
1030
1031         if(link == NULL)
1032                 goto out;
1033
1034         /*
1035          *  walk down the links from the selftab looking for
1036          *  the one we just found
1037          */
1038         l_self = &p->link;
1039         for(link = *l_self; link; link = *l_self){
1040                 if(link == *(l_lifc))
1041                         break;
1042                 l_self = &link->selflink;
1043         }
1044
1045         if(link == NULL)
1046                 panic("remselfcache");
1047
1048         if(kref_refcnt(&link->ref) > 1)
1049                 goto out;
1050
1051         if((p->type & Rmulti) && ifc->m->remmulti != NULL)
1052                 (*ifc->m->remmulti)(ifc, a, lifc->local);
1053
1054         /* ref == 0, remove from both chains and free the link */
1055         *l_lifc = link->lifclink;
1056         *l_self = link->selflink;
1057         iplinkfree(link);
1058
1059         if(p->link != NULL)
1060                 goto out;
1061
1062         /* remove from routing table */
1063         if(isv4(a))
1064                 v4delroute(f, a+IPv4off, IPallbits+IPv4off, 1);
1065         else
1066                 v6delroute(f, a, IPallbits, 1);
1067         
1068         /* no more links, remove from hash and free */
1069         *l = p->next;
1070         ipselffree(p);
1071
1072         /* if IPnoaddr, forget */
1073         if(ipcmp(a, v4prefix) == 0 || ipcmp(a, IPnoaddr) == 0)
1074                 f->self->acceptall = 0;
1075
1076 out:
1077         qunlock(&f->self->qlock);
1078 }
1079
1080 static char *stformat = "%-44.44I %2.2d %4.4s\n";
1081 enum
1082 {
1083         Nstformat= 41,
1084 };
1085
1086 long
1087 ipselftabread(struct Fs *f, char *cp, uint32_t offset, int n)
1088 {
1089         int i, m, nifc, off;
1090         struct Ipself *p;
1091         struct Iplink *link;
1092         char state[8];
1093
1094         m = 0;
1095         off = offset;
1096         qlock(&f->self->qlock);
1097         for(i = 0; i < NHASH && m < n; i++){
1098                 for(p = f->self->hash[i]; p != NULL && m < n; p = p->next){
1099                         nifc = 0;
1100                         for(link = p->link; link; link = link->selflink)
1101                                 nifc++;
1102                         routetype(p->type, state);
1103                         m += snprintf(cp + m, n - m, stformat, p->a, nifc, state);
1104                         if(off > 0){
1105                                 off -= m;
1106                                 m = 0;
1107                         }
1108                 }
1109         }
1110         qunlock(&f->self->qlock);
1111         return m;
1112 }
1113
1114 int
1115 iptentative(struct Fs *f, uint8_t *addr)
1116 {
1117         struct Ipself *p;
1118
1119         p = f->self->hash[hashipa(addr)];
1120         for(; p; p = p->next){
1121                 if(ipcmp(addr, p->a) == 0) {
1122                         return p->link->lifc->tentative;
1123                 }
1124         }
1125         return 0;
1126 }
1127
1128 /*
1129  *  returns
1130  *      0               - no match
1131  *      Runi
1132  *      Rbcast
1133  *      Rmcast
1134  */
1135 int
1136 ipforme(struct Fs *f, uint8_t *addr)
1137 {
1138         struct Ipself *p;
1139
1140         p = f->self->hash[hashipa(addr)];
1141         for(; p; p = p->next){
1142                 if(ipcmp(addr, p->a) == 0)
1143                         return p->type;
1144         }
1145
1146         /* hack to say accept anything */
1147         if(f->self->acceptall)
1148                 return Runi;
1149
1150         return 0;
1151 }
1152
1153 /*
1154  *  find the ifc on same net as the remote system.  If none,
1155  *  return NULL.
1156  */
1157 struct Ipifc*
1158 findipifc(struct Fs *f, uint8_t *remote, int type)
1159 {
1160         struct Ipifc *ifc, *x;
1161         struct Iplifc *lifc;
1162         struct conv **cp, **e;
1163         uint8_t gnet[IPaddrlen];
1164         uint8_t xmask[IPaddrlen];
1165
1166         x = NULL; memset(xmask, 0, IPaddrlen);
1167
1168         /* find most specific match */
1169         e = &f->ipifc->conv[f->ipifc->nc];
1170         for(cp = f->ipifc->conv; cp < e; cp++){
1171                 if(*cp == 0)
1172                         continue;
1173
1174                 ifc = (struct Ipifc*)(*cp)->ptcl;
1175
1176                 for(lifc = ifc->lifc; lifc; lifc = lifc->next){
1177                         maskip(remote, lifc->mask, gnet);
1178                         if(ipcmp(gnet, lifc->net) == 0){
1179                                 if(x == NULL || ipcmp(lifc->mask, xmask) > 0){
1180                                         x = ifc;
1181                                         ipmove(xmask, lifc->mask);
1182                                 }
1183                         }
1184                 }
1185         }
1186         if(x != NULL)
1187                 return x;
1188
1189         /* for now for broadcast and multicast, just use first interface */
1190         if(type & (Rbcast|Rmulti)){
1191                 for(cp = f->ipifc->conv; cp < e; cp++){
1192                         if(*cp == 0)
1193                                 continue;
1194                         ifc = (struct Ipifc*)(*cp)->ptcl;
1195                         if(ifc->lifc != NULL)
1196                                 return ifc;
1197                 }
1198         }
1199                 
1200         return NULL;
1201 }
1202
1203 enum {
1204         unknownv6,
1205         multicastv6,
1206         unspecifiedv6,
1207         linklocalv6,
1208         sitelocalv6,
1209         globalv6,
1210 };
1211
1212 int
1213 v6addrtype(uint8_t *addr)
1214 {
1215         if(isv6global(addr))
1216                 return globalv6;
1217         if(islinklocal(addr))
1218                 return linklocalv6;
1219         if(isv6mcast(addr))
1220                 return multicastv6;
1221         if(issitelocal(addr))
1222                 return sitelocalv6;
1223         return unknownv6;
1224 }
1225
1226 #define v6addrcurr(lifc) (( (lifc)->origint + (lifc)->preflt >= (NOW/10^3) ) || ( (lifc)->preflt == 0xffffffff ))
1227
1228 static void
1229 findprimaryipv6(struct Fs *f, uint8_t *local)
1230 {
1231         struct conv **cp, **e;
1232         struct Ipifc *ifc;
1233         struct Iplifc *lifc;
1234         int atype, atypel;
1235
1236         ipmove(local, v6Unspecified);
1237         atype = unspecifiedv6;
1238
1239         /* find "best" (global > sitelocal > link local > unspecified)
1240          * local address; address must be current */
1241
1242         e = &f->ipifc->conv[f->ipifc->nc];
1243         for(cp = f->ipifc->conv; cp < e; cp++){
1244                 if(*cp == 0)
1245                         continue;
1246                 ifc = (struct Ipifc*)(*cp)->ptcl;
1247                 for(lifc = ifc->lifc; lifc; lifc = lifc->next){
1248                         atypel = v6addrtype(lifc->local);
1249                         if(atypel > atype)
1250                         if(v6addrcurr(lifc)) {
1251                                 ipmove(local, lifc->local);
1252                                 atype = atypel;
1253                                 if(atype == globalv6)
1254                                         return;
1255                         }
1256                 }
1257         }
1258 }
1259
1260 /*
1261  *  returns first ip address configured
1262  */
1263 static void
1264 findprimaryipv4(struct Fs *f, uint8_t *local)
1265 {
1266         struct conv **cp, **e;
1267         struct Ipifc *ifc;
1268         struct Iplifc *lifc;
1269
1270         /* find first ifc local address */
1271         e = &f->ipifc->conv[f->ipifc->nc];
1272         for(cp = f->ipifc->conv; cp < e; cp++){
1273                 if(*cp == 0)
1274                         continue;
1275                 ifc = (struct Ipifc*)(*cp)->ptcl;
1276                 if((lifc = ifc->lifc) != NULL){
1277                         ipmove(local, lifc->local);
1278                         return;
1279                 }
1280         }
1281 }
1282
1283 /*
1284  *  find the local address 'closest' to the remote system, copy it to
1285  *  local and return the ifc for that address
1286  */
1287 void
1288 findlocalip(struct Fs *f, uint8_t *local, uint8_t *remote)
1289 {
1290         struct Ipifc *ifc;
1291         struct Iplifc *lifc;
1292         struct route *r;
1293         uint8_t gate[IPaddrlen];
1294         uint8_t gnet[IPaddrlen];
1295         int version;
1296         int atype = unspecifiedv6, atypel = unknownv6;
1297
1298         qlock(&f->ipifc->qlock);
1299         r = v6lookup(f, remote, NULL);
1300         version = (memcmp(remote, v4prefix, IPv4off) == 0) ? V4 : V6;
1301         
1302         if(r != NULL){
1303                 ifc = r->rt.ifc;
1304                 if(r->rt.type & Rv4)
1305                         v4tov6(gate, r->v4.gate);
1306                 else {
1307                         ipmove(gate, r->v6.gate);
1308                         ipmove(local, v6Unspecified);
1309                 }
1310
1311                 /* find ifc address closest to the gateway to use */
1312                 switch(version) {
1313                 case V4:
1314                         for(lifc = ifc->lifc; lifc; lifc = lifc->next){
1315                                 maskip(gate, lifc->mask, gnet);
1316                                 if(ipcmp(gnet, lifc->net) == 0){
1317                                         ipmove(local, lifc->local);
1318                                         goto out;
1319                                 }
1320                         }
1321                         break;
1322                 case V6:
1323                         for(lifc = ifc->lifc; lifc; lifc = lifc->next){
1324                                 atypel = v6addrtype(lifc->local);
1325                                 maskip(gate, lifc->mask, gnet);
1326                                 if(ipcmp(gnet, lifc->net) == 0)
1327                                 if(atypel > atype)
1328                                 if(v6addrcurr(lifc)) {
1329                                         ipmove(local, lifc->local);
1330                                         atype = atypel;
1331                                         if(atype == globalv6)
1332                                                 break;
1333                                 }
1334                         }
1335                         if(atype > unspecifiedv6)
1336                                 goto out;
1337                         break;
1338                 default:
1339                         panic("findlocalip: version %d", version);
1340                 }
1341         }
1342
1343         switch(version){
1344         case V4:
1345                 findprimaryipv4(f, local);
1346                 break;
1347         case V6:
1348                 findprimaryipv6(f, local);
1349                 break;
1350         default:
1351                 panic("findlocalip2: version %d", version);
1352         }
1353
1354 out:
1355         qunlock(&f->ipifc->qlock);
1356 }
1357
1358 /*
1359  *  return first v4 address associated with an interface
1360  */
1361 int
1362 ipv4local(struct Ipifc *ifc, uint8_t *addr)
1363 {
1364         struct Iplifc *lifc;
1365
1366         for(lifc = ifc->lifc; lifc; lifc = lifc->next){
1367                 if(isv4(lifc->local)){
1368                         memmove(addr, lifc->local+IPv4off, IPv4addrlen);
1369                         return 1;
1370                 }
1371         }
1372         return 0;
1373 }
1374
1375 /*
1376  *  return first v6 address associated with an interface
1377  */
1378 int
1379 ipv6local(struct Ipifc *ifc, uint8_t *addr)
1380 {
1381         struct Iplifc *lifc;
1382
1383         for(lifc = ifc->lifc; lifc; lifc = lifc->next){
1384                 if(!isv4(lifc->local) && !(lifc->tentative)){
1385                         ipmove(addr, lifc->local);
1386                         return 1;
1387                 }
1388         }
1389         return 0;
1390 }
1391
1392 int
1393 ipv6anylocal(struct Ipifc *ifc, uint8_t *addr)
1394 {
1395         struct Iplifc *lifc;
1396
1397         for(lifc = ifc->lifc; lifc; lifc = lifc->next){
1398                 if(!isv4(lifc->local)){
1399                         ipmove(addr, lifc->local);
1400                         return SRC_UNI;
1401                 }
1402         }
1403         return SRC_UNSPEC;
1404 }
1405
1406 /*
1407  *  see if this address is bound to the interface
1408  */
1409 struct Iplifc*
1410 iplocalonifc(struct Ipifc *ifc, uint8_t *ip)
1411 {
1412         struct Iplifc *lifc;
1413
1414         for(lifc = ifc->lifc; lifc; lifc = lifc->next)
1415                 if(ipcmp(ip, lifc->local) == 0)
1416                         return lifc;
1417         return NULL;
1418 }
1419
1420
1421 /*
1422  *  See if we're proxying for this address on this interface
1423  */
1424 int
1425 ipproxyifc(struct Fs *f, struct Ipifc *ifc, uint8_t *ip)
1426 {
1427         struct route *r;
1428         uint8_t net[IPaddrlen];
1429         struct Iplifc *lifc;
1430
1431         /* see if this is a direct connected pt to pt address */
1432         r = v6lookup(f, ip, NULL);
1433         if(r == NULL)
1434                 return 0;
1435         if((r->rt.type & (Rifc|Rproxy)) != (Rifc|Rproxy))
1436                 return 0;
1437
1438         /* see if this is on the right interface */
1439         for(lifc = ifc->lifc; lifc; lifc = lifc->next){
1440                 maskip(ip, lifc->mask, net);
1441                 if(ipcmp(net, lifc->remote) == 0)
1442                         return 1;
1443         }
1444
1445         return 0;
1446 }
1447
1448 /*
1449  *  return multicast version if any
1450  */
1451 int
1452 ipismulticast(uint8_t *ip)
1453 {
1454         if(isv4(ip)){
1455                 if(ip[IPv4off] >= 0xe0 && ip[IPv4off] < 0xf0)
1456                         return V4;
1457         } else {
1458                 if(ip[0] == 0xff)
1459                         return V6;
1460         }
1461         return 0;
1462 }
1463
1464 int
1465 ipisbm(uint8_t *ip)
1466 {
1467         if(isv4(ip)){
1468                 if(ip[IPv4off] >= 0xe0 && ip[IPv4off] < 0xf0)
1469                         return V4;
1470                 if(ipcmp(ip, IPv4bcast) == 0)
1471                         return V4;
1472         } else {
1473                 if(ip[0] == 0xff)
1474                         return V6;
1475         }
1476         return 0;
1477 }
1478
1479
1480 /*
1481  *  add a multicast address to an interface, called with c locked
1482  */
1483 void
1484 ipifcaddmulti(struct conv *c, uint8_t *ma, uint8_t *ia)
1485 {
1486         ERRSTACK(1);
1487         struct Ipifc *ifc;
1488         struct Iplifc *lifc;
1489         struct conv **p;
1490         struct Ipmulti *multi, **l;
1491         struct Fs *f;
1492
1493         f = c->p->f;
1494         
1495         for(l = &c->multi; *l; l = &(*l)->next)
1496                 if(ipcmp(ma, (*l)->ma) == 0)
1497                 if(ipcmp(ia, (*l)->ia) == 0)
1498                         return;         /* it's already there */
1499
1500         multi = *l = kzmalloc(sizeof(*multi), 0);
1501         ipmove(multi->ma, ma);
1502         ipmove(multi->ia, ia);
1503         multi->next = NULL;
1504
1505         for(p = f->ipifc->conv; *p; p++){
1506                 if((*p)->inuse == 0)
1507                         continue;
1508                 ifc = (struct Ipifc*)(*p)->ptcl;
1509                 if(waserror()){
1510                         wunlock(&ifc->rwlock);
1511                         nexterror();
1512                 }
1513                 wlock(&ifc->rwlock);
1514                 for(lifc = ifc->lifc; lifc; lifc = lifc->next)
1515                         if(ipcmp(ia, lifc->local) == 0)
1516                                 addselfcache(f, ifc, lifc, ma, Rmulti);
1517                 wunlock(&ifc->rwlock);
1518                 poperror();
1519         }
1520 }
1521
1522
1523 /*
1524  *  remove a multicast address from an interface, called with c locked
1525  */
1526 void
1527 ipifcremmulti(struct conv *c, uint8_t *ma, uint8_t *ia)
1528 {
1529         ERRSTACK(1);
1530         struct Ipmulti *multi, **l;
1531         struct Iplifc *lifc;
1532         struct conv **p;
1533         struct Ipifc *ifc;
1534         struct Fs *f;
1535
1536         f = c->p->f;
1537         
1538         for(l = &c->multi; *l; l = &(*l)->next)
1539                 if(ipcmp(ma, (*l)->ma) == 0)
1540                 if(ipcmp(ia, (*l)->ia) == 0)
1541                         break;
1542
1543         multi = *l;
1544         if(multi == NULL)
1545                 return;         /* we don't have it open */
1546
1547         *l = multi->next;
1548
1549         for(p = f->ipifc->conv; *p; p++){
1550                 if((*p)->inuse == 0)
1551                         continue;
1552
1553                 ifc = (struct Ipifc*)(*p)->ptcl;
1554                 if(waserror()){
1555                         wunlock(&ifc->rwlock);
1556                         nexterror();
1557                 }
1558                 wlock(&ifc->rwlock);
1559                 for(lifc = ifc->lifc; lifc; lifc = lifc->next)
1560                         if(ipcmp(ia, lifc->local) == 0)
1561                                 remselfcache(f, ifc, lifc, ma);
1562                 wunlock(&ifc->rwlock);
1563                 poperror();
1564         }
1565
1566         kfree(multi);
1567 }
1568
1569 /*
1570  *  make lifc's join and leave multicast groups
1571  */
1572 static char*
1573 ipifcjoinmulti(struct Ipifc *ifc, char **argv, int argc)
1574 {
1575         return NULL;
1576 }
1577
1578 static char*
1579 ipifcleavemulti(struct Ipifc *ifc, char **argv, int argc)
1580 {
1581         return NULL;
1582 }
1583
1584 static void
1585 ipifcregisterproxy(struct Fs *f, struct Ipifc *ifc, uint8_t *ip)
1586 {
1587         struct conv **cp, **e;
1588         struct Ipifc *nifc;
1589         struct Iplifc *lifc;
1590         struct medium *m;
1591         uint8_t net[IPaddrlen];
1592
1593         /* register the address on any network that will proxy for us */
1594         e = &f->ipifc->conv[f->ipifc->nc];
1595
1596         if(!isv4(ip)) { // V6
1597                 for(cp = f->ipifc->conv; cp < e; cp++){
1598                         if(*cp == NULL)
1599                                 continue;
1600                         nifc = (struct Ipifc*)(*cp)->ptcl;
1601                         if(nifc == ifc)
1602                                 continue;
1603         
1604                         rlock(&nifc->rwlock);
1605                         m = nifc->m;
1606                         if(m == NULL || m->addmulti == NULL) {
1607                                 runlock(&nifc->rwlock);
1608                                 continue;
1609                         }
1610                         for(lifc = nifc->lifc; lifc; lifc = lifc->next){
1611                                 maskip(ip, lifc->mask, net);
1612                                 if(ipcmp(net, lifc->remote) == 0) { /* add solicited-node multicast address */
1613                                         ipv62smcast(net, ip);
1614                                         addselfcache(f, nifc, lifc, net, Rmulti);
1615                                         arpenter(f, V6, ip, nifc->mac, 6, 0);
1616                                         //(*m->addmulti)(nifc, net, ip);
1617                                         break;
1618                                 }
1619                         }
1620                         runlock(&nifc->rwlock);
1621                 }
1622                 return;
1623         }
1624         else { // V4
1625                 for(cp = f->ipifc->conv; cp < e; cp++){
1626                         if(*cp == NULL)
1627                                 continue;
1628                         nifc = (struct Ipifc*)(*cp)->ptcl;
1629                         if(nifc == ifc)
1630                                 continue;
1631         
1632                         rlock(&nifc->rwlock);
1633                         m = nifc->m;
1634                         if(m == NULL || m->areg == NULL){
1635                                 runlock(&nifc->rwlock);
1636                                 continue;
1637                         }
1638                         for(lifc = nifc->lifc; lifc; lifc = lifc->next){
1639                                 maskip(ip, lifc->mask, net);
1640                                 if(ipcmp(net, lifc->remote) == 0){
1641                                         (*m->areg)(nifc, ip);
1642                                         break;
1643                                 }
1644                         }
1645                         runlock(&nifc->rwlock);
1646                 }
1647         }
1648 }
1649
1650
1651 // added for new v6 mesg types
1652 static void
1653 adddefroute6(struct Fs *f, uint8_t *gate, int force)
1654 {
1655         struct route *r;
1656
1657         r = v6lookup(f, v6Unspecified, NULL);
1658         if(r!=NULL)
1659         if(!(force) && (strcmp(r->rt.tag,"ra")!=0))     // route entries generated
1660                 return;                 // by all other means take
1661                                         // precedence over router annc
1662
1663         v6delroute(f, v6Unspecified, v6Unspecified, 1);
1664         v6addroute(f, "ra", v6Unspecified, v6Unspecified, gate, 0);
1665 }
1666
1667 enum
1668 {
1669         Ngates = 3,
1670 };
1671
1672 char*
1673 ipifcaddpref6(struct Ipifc *ifc, char**argv, int argc)
1674 {
1675         uint8_t onlink = 1;
1676         uint8_t autoflag = 1;
1677         long    validlt = 0xffffffff;
1678         long    preflt = 0xffffffff;
1679         long    origint = NOW / 10^3;
1680         uint8_t prefix[IPaddrlen];
1681         int     plen = 64;
1682         struct Iplifc   *lifc;
1683         char    addr[40], preflen[6];
1684         char    *params[3];
1685
1686         switch(argc) {
1687         case 7:
1688                 preflt = atoi(argv[6]);
1689                 /* fall through */
1690         case 6:
1691                 validlt = atoi(argv[5]);
1692                 /* fall through */
1693         case 5:
1694                 autoflag =  atoi(argv[4]);
1695                 /* fall through */
1696         case 4:
1697                 onlink = atoi(argv[3]);
1698                 /* fall through */
1699         case 3:
1700                 plen = atoi(argv[2]);
1701         case 2:
1702                 break;
1703         default:
1704                 return Ebadarg;
1705         }
1706
1707         if((parseip(prefix, argv[1])!=6) ||
1708                 (validlt < preflt) ||
1709                 (plen < 0) || (plen > 64) ||
1710                 (islinklocal(prefix))
1711         )
1712                 return Ebadarg;
1713
1714         lifc = kzmalloc(sizeof(struct Iplifc), 0);
1715         lifc->onlink = (onlink!=0);
1716         lifc->autoflag = (autoflag!=0);
1717         lifc->validlt = validlt;
1718         lifc->preflt = preflt;
1719         lifc->origint = origint;
1720
1721         if(ifc->m->pref2addr!=NULL)
1722                 ifc->m->pref2addr(prefix, ifc->mac);
1723         else
1724                 return Ebadarg;
1725         
1726         snprintf(addr, sizeof(addr), "%I", prefix);
1727         snprintf(preflen, sizeof(preflen), "/%d", plen);
1728         params[0] = "add";
1729         params[1] = addr;
1730         params[2] = preflen;
1731
1732         return ipifcadd(ifc, params, 3, 0, lifc);
1733 }
1734