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