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