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