ipifc.c (34075B)
1 #include "u.h" 2 #include "lib.h" 3 #include "mem.h" 4 #include "dat.h" 5 #include "fns.h" 6 #include "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 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) ( (ulong)(((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 QLOCK(f->ipifc); 1233 r = v6lookup(f, remote, nil); 1234 version = (memcmp(remote, v4prefix, IPv4off) == 0)? V4: V6; 1235 1236 if(r != nil){ 1237 ifc = r->ifc; 1238 if(r->type & Rv4) 1239 v4tov6(gate, r->v4.gate); 1240 else { 1241 ipmove(gate, r->v6.gate); 1242 ipmove(local, v6Unspecified); 1243 } 1244 1245 switch(version) { 1246 case V4: 1247 /* find ifc address closest to the gateway to use */ 1248 for(lifc = ifc->lifc; lifc; lifc = lifc->next){ 1249 maskip(gate, lifc->mask, gnet); 1250 if(ipcmp(gnet, lifc->net) == 0){ 1251 ipmove(local, lifc->local); 1252 goto out; 1253 } 1254 } 1255 break; 1256 case V6: 1257 /* find ifc address with scope matching the destination */ 1258 atyper = v6addrtype(remote); 1259 deprecated = 0; 1260 for(lifc = ifc->lifc; lifc; lifc = lifc->next){ 1261 atypel = v6addrtype(lifc->local); 1262 /* prefer appropriate scope */ 1263 if((atypel > atype && atype < atyper) || 1264 (atypel < atype && atype > atyper)){ 1265 ipmove(local, lifc->local); 1266 deprecated = !v6addrcurr(lifc); 1267 atype = atypel; 1268 } else if(atypel == atype){ 1269 /* avoid deprecated addresses */ 1270 if(deprecated && v6addrcurr(lifc)){ 1271 ipmove(local, lifc->local); 1272 atype = atypel; 1273 deprecated = 0; 1274 } 1275 } 1276 if(atype == atyper && !deprecated) 1277 goto out; 1278 } 1279 if(atype >= atyper) 1280 goto out; 1281 break; 1282 default: 1283 panic("findlocalip: version %d", version); 1284 } 1285 } 1286 1287 switch(version){ 1288 case V4: 1289 findprimaryipv4(f, local); 1290 break; 1291 case V6: 1292 findprimaryipv6(f, local); 1293 break; 1294 default: 1295 panic("findlocalip2: version %d", version); 1296 } 1297 1298 out: 1299 QUNLOCK(f->ipifc); 1300 } 1301 1302 /* 1303 * return first v4 address associated with an interface 1304 */ 1305 int 1306 ipv4local(Ipifc *ifc, uchar *addr) 1307 { 1308 Iplifc *lifc; 1309 1310 for(lifc = ifc->lifc; lifc; lifc = lifc->next){ 1311 if(isv4(lifc->local)){ 1312 memmove(addr, lifc->local+IPv4off, IPv4addrlen); 1313 return 1; 1314 } 1315 } 1316 return 0; 1317 } 1318 1319 /* 1320 * return first v6 address associated with an interface 1321 */ 1322 int 1323 ipv6local(Ipifc *ifc, uchar *addr) 1324 { 1325 Iplifc *lifc; 1326 1327 for(lifc = ifc->lifc; lifc; lifc = lifc->next){ 1328 if(!isv4(lifc->local) && !(lifc->tentative)){ 1329 ipmove(addr, lifc->local); 1330 return 1; 1331 } 1332 } 1333 return 0; 1334 } 1335 1336 int 1337 ipv6anylocal(Ipifc *ifc, uchar *addr) 1338 { 1339 Iplifc *lifc; 1340 1341 for(lifc = ifc->lifc; lifc; lifc = lifc->next){ 1342 if(!isv4(lifc->local)){ 1343 ipmove(addr, lifc->local); 1344 return SRC_UNI; 1345 } 1346 } 1347 return SRC_UNSPEC; 1348 } 1349 1350 /* 1351 * see if this address is bound to the interface 1352 */ 1353 Iplifc* 1354 iplocalonifc(Ipifc *ifc, uchar *ip) 1355 { 1356 Iplifc *lifc; 1357 1358 for(lifc = ifc->lifc; lifc; lifc = lifc->next) 1359 if(ipcmp(ip, lifc->local) == 0) 1360 return lifc; 1361 return nil; 1362 } 1363 1364 1365 /* 1366 * See if we're proxying for this address on this interface 1367 */ 1368 int 1369 ipproxyifc(Fs *f, Ipifc *ifc, uchar *ip) 1370 { 1371 Route *r; 1372 uchar net[IPaddrlen]; 1373 Iplifc *lifc; 1374 1375 /* see if this is a direct connected pt to pt address */ 1376 r = v6lookup(f, ip, nil); 1377 if(r == nil || (r->type & (Rifc|Rproxy)) != (Rifc|Rproxy)) 1378 return 0; 1379 1380 /* see if this is on the right interface */ 1381 for(lifc = ifc->lifc; lifc; lifc = lifc->next){ 1382 maskip(ip, lifc->mask, net); 1383 if(ipcmp(net, lifc->remote) == 0) 1384 return 1; 1385 } 1386 return 0; 1387 } 1388 1389 /* 1390 * return multicast version if any 1391 */ 1392 int 1393 ipismulticast(uchar *ip) 1394 { 1395 if(isv4(ip)){ 1396 if(ip[IPv4off] >= 0xe0 && ip[IPv4off] < 0xf0) 1397 return V4; 1398 } 1399 else if(ip[0] == 0xff) 1400 return V6; 1401 return 0; 1402 } 1403 int 1404 ipisbm(uchar *ip) 1405 { 1406 if(isv4(ip)){ 1407 if(ip[IPv4off] >= 0xe0 && ip[IPv4off] < 0xf0) 1408 return V4; 1409 else if(ipcmp(ip, IPv4bcast) == 0) 1410 return V4; 1411 } 1412 else if(ip[0] == 0xff) 1413 return V6; 1414 return 0; 1415 } 1416 1417 1418 /* 1419 * add a multicast address to an interface, called with c->car locked 1420 */ 1421 void 1422 ipifcaddmulti(Conv *c, uchar *ma, uchar *ia) 1423 { 1424 Ipifc *ifc; 1425 Iplifc *lifc; 1426 Conv **p; 1427 Ipmulti *multi, **l; 1428 Fs *f; 1429 1430 f = c->p->f; 1431 1432 for(l = &c->multi; *l; l = &(*l)->next) 1433 if(ipcmp(ma, (*l)->ma) == 0 && ipcmp(ia, (*l)->ia) == 0) 1434 return; /* it's already there */ 1435 1436 multi = *l = smalloc(sizeof(*multi)); 1437 ipmove(multi->ma, ma); 1438 ipmove(multi->ia, ia); 1439 multi->next = nil; 1440 1441 for(p = f->ipifc->conv; *p; p++){ 1442 if((*p)->inuse == 0) 1443 continue; 1444 ifc = (Ipifc*)(*p)->ptcl; 1445 if(waserror()){ 1446 WUNLOCK(ifc); 1447 nexterror(); 1448 } 1449 WLOCK(ifc); 1450 for(lifc = ifc->lifc; lifc; lifc = lifc->next) 1451 if(ipcmp(ia, lifc->local) == 0) 1452 addselfcache(f, ifc, lifc, ma, Rmulti); 1453 WUNLOCK(ifc); 1454 poperror(); 1455 } 1456 } 1457 1458 1459 /* 1460 * remove a multicast address from an interface, called with c->car locked 1461 */ 1462 void 1463 ipifcremmulti(Conv *c, uchar *ma, uchar *ia) 1464 { 1465 Ipmulti *multi, **l; 1466 Iplifc *lifc; 1467 Conv **p; 1468 Ipifc *ifc; 1469 Fs *f; 1470 1471 f = c->p->f; 1472 1473 for(l = &c->multi; *l; l = &(*l)->next) 1474 if(ipcmp(ma, (*l)->ma) == 0 && ipcmp(ia, (*l)->ia) == 0) 1475 break; 1476 1477 multi = *l; 1478 if(multi == nil) 1479 return; /* we don't have it open */ 1480 1481 *l = multi->next; 1482 1483 for(p = f->ipifc->conv; *p; p++){ 1484 if((*p)->inuse == 0) 1485 continue; 1486 1487 ifc = (Ipifc*)(*p)->ptcl; 1488 if(waserror()){ 1489 WUNLOCK(ifc); 1490 nexterror(); 1491 } 1492 WLOCK(ifc); 1493 for(lifc = ifc->lifc; lifc; lifc = lifc->next) 1494 if(ipcmp(ia, lifc->local) == 0) 1495 remselfcache(f, ifc, lifc, ma); 1496 WUNLOCK(ifc); 1497 poperror(); 1498 } 1499 1500 free(multi); 1501 } 1502 1503 /* 1504 * make lifc's join and leave multicast groups 1505 */ 1506 static char* 1507 ipifcjoinmulti(Ipifc *ifc, char **argv, int argc) 1508 { 1509 return nil; 1510 } 1511 1512 static char* 1513 ipifcleavemulti(Ipifc *ifc, char **argv, int argc) 1514 { 1515 return nil; 1516 } 1517 1518 static void 1519 ipifcregisterproxy(Fs *f, Ipifc *ifc, uchar *ip) 1520 { 1521 Conv **cp, **e; 1522 Ipifc *nifc; 1523 Iplifc *lifc; 1524 Medium *m; 1525 uchar net[IPaddrlen]; 1526 1527 /* register the address on any network that will proxy for us */ 1528 e = &f->ipifc->conv[f->ipifc->nc]; 1529 1530 if(!isv4(ip)) { /* V6 */ 1531 for(cp = f->ipifc->conv; cp < e; cp++){ 1532 if(*cp == nil || (nifc = (Ipifc*)(*cp)->ptcl) == ifc) 1533 continue; 1534 RLOCK(nifc); 1535 m = nifc->m; 1536 if(m == nil || m->addmulti == nil) { 1537 RUNLOCK(nifc); 1538 continue; 1539 } 1540 for(lifc = nifc->lifc; lifc; lifc = lifc->next){ 1541 maskip(ip, lifc->mask, net); 1542 if(ipcmp(net, lifc->remote) == 0) { 1543 /* add solicited-node multicast addr */ 1544 ipv62smcast(net, ip); 1545 addselfcache(f, nifc, lifc, net, Rmulti); 1546 arpenter(f, V6, ip, nifc->mac, 6, 0); 1547 // (*m->addmulti)(nifc, net, ip); 1548 break; 1549 } 1550 } 1551 RUNLOCK(nifc); 1552 } 1553 } 1554 else { /* V4 */ 1555 for(cp = f->ipifc->conv; cp < e; cp++){ 1556 if(*cp == nil || (nifc = (Ipifc*)(*cp)->ptcl) == ifc) 1557 continue; 1558 RLOCK(nifc); 1559 m = nifc->m; 1560 if(m == nil || m->areg == nil){ 1561 RUNLOCK(nifc); 1562 continue; 1563 } 1564 for(lifc = nifc->lifc; lifc; lifc = lifc->next){ 1565 maskip(ip, lifc->mask, net); 1566 if(ipcmp(net, lifc->remote) == 0){ 1567 (*m->areg)(nifc, ip); 1568 break; 1569 } 1570 } 1571 RUNLOCK(nifc); 1572 } 1573 } 1574 } 1575 1576 1577 /* added for new v6 mesg types */ 1578 static void 1579 adddefroute6(Fs *f, uchar *gate, int force) 1580 { 1581 Route *r; 1582 1583 r = v6lookup(f, v6Unspecified, nil); 1584 /* 1585 * route entries generated by all other means take precedence 1586 * over router announcements. 1587 */ 1588 if (r && !force && strcmp(r->tag, "ra") != 0) 1589 return; 1590 1591 v6delroute(f, v6Unspecified, v6Unspecified, 1); 1592 v6addroute(f, "ra", v6Unspecified, v6Unspecified, gate, 0); 1593 } 1594 1595 enum { 1596 Ngates = 3, 1597 }; 1598 1599 char* 1600 ipifcadd6(Ipifc *ifc, char**argv, int argc) 1601 { 1602 int plen = 64; 1603 long origint = NOW / 1000, preflt = ~0L, validlt = ~0L; 1604 char addr[40], preflen[6]; 1605 char *params[3]; 1606 uchar autoflag = 1, onlink = 1; 1607 uchar prefix[IPaddrlen]; 1608 Iplifc *lifc; 1609 1610 switch(argc) { 1611 case 7: 1612 preflt = atoi(argv[6]); 1613 /* fall through */ 1614 case 6: 1615 validlt = atoi(argv[5]); 1616 /* fall through */ 1617 case 5: 1618 autoflag = atoi(argv[4]); 1619 /* fall through */ 1620 case 4: 1621 onlink = atoi(argv[3]); 1622 /* fall through */ 1623 case 3: 1624 plen = atoi(argv[2]); 1625 /* fall through */ 1626 case 2: 1627 break; 1628 default: 1629 return Ebadarg; 1630 } 1631 1632 if (parseip(prefix, argv[1]) != 6 || validlt < preflt || plen < 0 || 1633 plen > 64 || islinklocal(prefix)) 1634 return Ebadarg; 1635 1636 lifc = smalloc(sizeof(Iplifc)); 1637 lifc->onlink = (onlink != 0); 1638 lifc->autoflag = (autoflag != 0); 1639 lifc->validlt = validlt; 1640 lifc->preflt = preflt; 1641 lifc->origint = origint; 1642 1643 /* issue "add" ctl msg for v6 link-local addr and prefix len */ 1644 if(!ifc->m->pref2addr) 1645 return Ebadarg; 1646 ifc->m->pref2addr(prefix, ifc->mac); /* mac → v6 link-local addr */ 1647 sprint(addr, "%I", prefix); 1648 sprint(preflen, "/%d", plen); 1649 params[0] = "add"; 1650 params[1] = addr; 1651 params[2] = preflen; 1652 1653 return ipifcadd(ifc, params, 3, 0, lifc); 1654 }