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