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