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 #include "kernel.h" 11 12 typedef struct Etherhdr Etherhdr; 13 struct Etherhdr 14 { 15 uchar d[6]; 16 uchar s[6]; 17 uchar t[2]; 18 }; 19 20 static uchar ipbroadcast[IPaddrlen] = { 21 0xff,0xff,0xff,0xff, 22 0xff,0xff,0xff,0xff, 23 0xff,0xff,0xff,0xff, 24 0xff,0xff,0xff,0xff, 25 }; 26 27 static uchar etherbroadcast[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; 28 29 static void etherread4(void *a); 30 static void etherread6(void *a); 31 static void etherbind(Ipifc *ifc, int argc, char **argv); 32 static void etherunbind(Ipifc *ifc); 33 static void etherbwrite(Ipifc *ifc, Block *bp, int version, uchar *ip); 34 static void etheraddmulti(Ipifc *ifc, uchar *a, uchar *ia); 35 static void etherremmulti(Ipifc *ifc, uchar *a, uchar *ia); 36 static Block* multicastarp(Fs *f, Arpent *a, Medium*, uchar *mac); 37 static void sendarp(Ipifc *ifc, Arpent *a); 38 static void sendgarp(Ipifc *ifc, uchar*); 39 static int multicastea(uchar *ea, uchar *ip); 40 static void recvarpproc(void*); 41 static void resolveaddr6(Ipifc *ifc, Arpent *a); 42 static void etherpref2addr(uchar *pref, uchar *ea); 43 44 Medium ethermedium = 45 { 46 .name= "ether", 47 .hsize= 14, 48 .mintu= 60, 49 .maxtu= 1514, 50 .maclen= 6, 51 .bind= etherbind, 52 .unbind= etherunbind, 53 .bwrite= etherbwrite, 54 .addmulti= etheraddmulti, 55 .remmulti= etherremmulti, 56 .ares= arpenter, 57 .areg= sendgarp, 58 .pref2addr= etherpref2addr, 59 }; 60 61 Medium gbemedium = 62 { 63 .name= "gbe", 64 .hsize= 14, 65 .mintu= 60, 66 .maxtu= 9014, 67 .maclen= 6, 68 .bind= etherbind, 69 .unbind= etherunbind, 70 .bwrite= etherbwrite, 71 .addmulti= etheraddmulti, 72 .remmulti= etherremmulti, 73 .ares= arpenter, 74 .areg= sendgarp, 75 .pref2addr= etherpref2addr, 76 }; 77 78 typedef struct Etherrock Etherrock; 79 struct Etherrock 80 { 81 Fs *f; /* file system we belong to */ 82 Proc *arpp; /* arp process */ 83 Proc *read4p; /* reading process (v4)*/ 84 Proc *read6p; /* reading process (v6)*/ 85 Chan *mchan4; /* Data channel for v4 */ 86 Chan *achan; /* Arp channel */ 87 Chan *cchan4; /* Control channel for v4 */ 88 Chan *mchan6; /* Data channel for v6 */ 89 Chan *cchan6; /* Control channel for v6 */ 90 }; 91 92 /* 93 * ethernet arp request 94 */ 95 enum 96 { 97 ETARP = 0x0806, 98 ETIP4 = 0x0800, 99 ETIP6 = 0x86DD, 100 ARPREQUEST = 1, 101 ARPREPLY = 2, 102 }; 103 104 typedef struct Etherarp Etherarp; 105 struct Etherarp 106 { 107 uchar d[6]; 108 uchar s[6]; 109 uchar type[2]; 110 uchar hrd[2]; 111 uchar pro[2]; 112 uchar hln; 113 uchar pln; 114 uchar op[2]; 115 uchar sha[6]; 116 uchar spa[4]; 117 uchar tha[6]; 118 uchar tpa[4]; 119 }; 120 121 static char *nbmsg = "nonblocking"; 122 123 /* 124 * called to bind an IP ifc to an ethernet device 125 * called with ifc wlock'd 126 */ 127 static void 128 etherbind(Ipifc *ifc, int argc, char **argv) 129 { 130 Chan *mchan4, *cchan4, *achan, *mchan6, *cchan6; 131 char addr[Maxpath]; //char addr[2*KNAMELEN]; 132 char dir[Maxpath]; //char dir[2*KNAMELEN]; 133 char *buf; 134 int fd, cfd, n; 135 char *ptr; 136 Etherrock *er; 137 138 if(argc < 2) 139 error(Ebadarg); 140 141 mchan4 = cchan4 = achan = mchan6 = cchan6 = nil; 142 buf = nil; 143 if(waserror()){ 144 if(mchan4 != nil) 145 cclose(mchan4); 146 if(cchan4 != nil) 147 cclose(cchan4); 148 if(achan != nil) 149 cclose(achan); 150 if(mchan6 != nil) 151 cclose(mchan6); 152 if(cchan6 != nil) 153 cclose(cchan6); 154 if(buf != nil) 155 free(buf); 156 nexterror(); 157 } 158 159 /* 160 * open ip converstation 161 * 162 * the dial will fail if the type is already open on 163 * this device. 164 */ 165 snprint(addr, sizeof(addr), "%s!0x800", argv[2]); 166 fd = kdial(addr, nil, dir, &cfd); 167 if(fd < 0) 168 errorf("dial 0x800 failed: %s", up->env->errstr); 169 mchan4 = commonfdtochan(fd, ORDWR, 0, 1); 170 cchan4 = commonfdtochan(cfd, ORDWR, 0, 1); 171 kclose(fd); 172 kclose(cfd); 173 174 /* 175 * make it non-blocking 176 */ 177 devtab[cchan4->type]->write(cchan4, nbmsg, strlen(nbmsg), 0); 178 179 /* 180 * get mac address and speed 181 */ 182 snprint(addr, sizeof(addr), "%s/stats", dir); 183 fd = kopen(addr, OREAD); 184 if(fd < 0) 185 errorf("can't open ether stats: %s", up->env->errstr); 186 187 buf = smalloc(512); 188 n = kread(fd, buf, 511); 189 kclose(fd); 190 if(n <= 0) 191 error(Eio); 192 buf[n] = 0; 193 194 ptr = strstr(buf, "addr: "); 195 if(!ptr) 196 error(Eio); 197 ptr += 6; 198 parsemac(ifc->mac, ptr, 6); 199 200 ptr = strstr(buf, "mbps: "); 201 if(ptr){ 202 ptr += 6; 203 ifc->mbps = atoi(ptr); 204 } else 205 ifc->mbps = 100; 206 207 /* 208 * open arp conversation 209 */ 210 snprint(addr, sizeof(addr), "%s!0x806", argv[2]); 211 fd = kdial(addr, nil, nil, nil); 212 if(fd < 0) 213 errorf("dial 0x806 failed: %s", up->env->errstr); 214 achan = commonfdtochan(fd, ORDWR, 0, 1); 215 kclose(fd); 216 217 /* 218 * open ip conversation 219 * 220 * the dial will fail if the type is already open on 221 * this device. 222 */ 223 snprint(addr, sizeof(addr), "%s!0x86DD", argv[2]); 224 fd = kdial(addr, nil, dir, &cfd); 225 if(fd < 0) 226 errorf("dial 0x86DD failed: %s", up->env->errstr); 227 mchan6 = commonfdtochan(fd, ORDWR, 0, 1); 228 cchan6 = commonfdtochan(cfd, ORDWR, 0, 1); 229 kclose(fd); 230 kclose(cfd); 231 232 /* 233 * make it non-blocking 234 */ 235 devtab[cchan6->type]->write(cchan6, nbmsg, strlen(nbmsg), 0); 236 237 er = smalloc(sizeof(*er)); 238 er->mchan4 = mchan4; 239 er->cchan4 = cchan4; 240 er->achan = achan; 241 er->mchan6 = mchan6; 242 er->cchan6 = cchan6; 243 er->f = ifc->conv->p->f; 244 ifc->arg = er; 245 246 free(buf); 247 poperror(); 248 249 kproc("etherread4", etherread4, ifc, 0); 250 kproc("recvarpproc", recvarpproc, ifc, 0); 251 kproc("etherread6", etherread6, ifc, 0); 252 } 253 254 /* 255 * called with ifc wlock'd 256 */ 257 static void 258 etherunbind(Ipifc *ifc) 259 { 260 Etherrock *er = ifc->arg; 261 262 if(er->read4p) 263 postnote(er->read4p, 1, "unbind", 0); 264 if(er->read6p) 265 postnote(er->read6p, 1, "unbind", 0); 266 if(er->arpp) 267 postnote(er->arpp, 1, "unbind", 0); 268 269 /* wait for readers to die */ 270 while(er->arpp != 0 || er->read4p != 0 || er->read6p != 0) 271 tsleep(&up->sleep, return0, 0, 300); 272 273 if(er->mchan4 != nil) 274 cclose(er->mchan4); 275 if(er->achan != nil) 276 cclose(er->achan); 277 if(er->cchan4 != nil) 278 cclose(er->cchan4); 279 if(er->mchan6 != nil) 280 cclose(er->mchan6); 281 if(er->cchan6 != nil) 282 cclose(er->cchan6); 283 284 free(er); 285 } 286 287 /* 288 * called by ipoput with a single block to write with ifc rlock'd 289 */ 290 static void 291 etherbwrite(Ipifc *ifc, Block *bp, int version, uchar *ip) 292 { 293 Etherhdr *eh; 294 Arpent *a; 295 uchar mac[6]; 296 Etherrock *er = ifc->arg; 297 298 /* get mac address of destination */ 299 a = arpget(er->f->arp, bp, version, ifc, ip, mac); 300 if(a){ 301 /* check for broadcast or multicast */ 302 bp = multicastarp(er->f, a, ifc->m, mac); 303 if(bp==nil){ 304 switch(version){ 305 case V4: 306 sendarp(ifc, a); 307 break; 308 case V6: 309 resolveaddr6(ifc, a); 310 break; 311 default: 312 panic("etherbwrite: version %d", version); 313 } 314 return; 315 } 316 } 317 318 /* make it a single block with space for the ether header */ 319 bp = padblock(bp, ifc->m->hsize); 320 if(bp->next) 321 bp = concatblock(bp); 322 if(BLEN(bp) < ifc->mintu) 323 bp = adjustblock(bp, ifc->mintu); 324 eh = (Etherhdr*)bp->rp; 325 326 /* copy in mac addresses and ether type */ 327 memmove(eh->s, ifc->mac, sizeof(eh->s)); 328 memmove(eh->d, mac, sizeof(eh->d)); 329 330 switch(version){ 331 case V4: 332 eh->t[0] = 0x08; 333 eh->t[1] = 0x00; 334 devtab[er->mchan4->type]->bwrite(er->mchan4, bp, 0); 335 break; 336 case V6: 337 eh->t[0] = 0x86; 338 eh->t[1] = 0xDD; 339 devtab[er->mchan6->type]->bwrite(er->mchan6, bp, 0); 340 break; 341 default: 342 panic("etherbwrite2: version %d", version); 343 } 344 ifc->out++; 345 } 346 347 348 /* 349 * process to read from the ethernet 350 */ 351 static void 352 etherread4(void *a) 353 { 354 Ipifc *ifc; 355 Block *bp; 356 Etherrock *er; 357 358 ifc = a; 359 er = ifc->arg; 360 er->read4p = up; /* hide identity under a rock for unbind */ 361 if(waserror()){ 362 er->read4p = 0; 363 pexit("hangup", 1); 364 } 365 for(;;){ 366 bp = devtab[er->mchan4->type]->bread(er->mchan4, ifc->maxtu, 0); 367 if(!canrlock(ifc)){ 368 freeb(bp); 369 continue; 370 } 371 if(waserror()){ 372 runlock(ifc); 373 nexterror(); 374 } 375 ifc->in++; 376 bp->rp += ifc->m->hsize; 377 if(ifc->lifc == nil) 378 freeb(bp); 379 else 380 ipiput4(er->f, ifc, bp); 381 runlock(ifc); 382 poperror(); 383 } 384 } 385 386 387 /* 388 * process to read from the ethernet, IPv6 389 */ 390 static void 391 etherread6(void *a) 392 { 393 Ipifc *ifc; 394 Block *bp; 395 Etherrock *er; 396 397 ifc = a; 398 er = ifc->arg; 399 er->read6p = up; /* hide identity under a rock for unbind */ 400 if(waserror()){ 401 er->read6p = 0; 402 pexit("hangup", 1); 403 } 404 for(;;){ 405 bp = devtab[er->mchan6->type]->bread(er->mchan6, ifc->maxtu, 0); 406 if(!canrlock(ifc)){ 407 freeb(bp); 408 continue; 409 } 410 if(waserror()){ 411 runlock(ifc); 412 nexterror(); 413 } 414 ifc->in++; 415 bp->rp += ifc->m->hsize; 416 if(ifc->lifc == nil) 417 freeb(bp); 418 else 419 ipiput6(er->f, ifc, bp); 420 runlock(ifc); 421 poperror(); 422 } 423 } 424 425 static void 426 etheraddmulti(Ipifc *ifc, uchar *a, uchar *) 427 { 428 uchar mac[6]; 429 char buf[64]; 430 Etherrock *er = ifc->arg; 431 int version; 432 433 version = multicastea(mac, a); 434 sprint(buf, "addmulti %E", mac); 435 switch(version){ 436 case V4: 437 devtab[er->cchan4->type]->write(er->cchan4, buf, strlen(buf), 0); 438 break; 439 case V6: 440 devtab[er->cchan6->type]->write(er->cchan6, buf, strlen(buf), 0); 441 break; 442 default: 443 panic("etheraddmulti: version %d", version); 444 } 445 } 446 447 static void 448 etherremmulti(Ipifc *ifc, uchar *a, uchar *) 449 { 450 uchar mac[6]; 451 char buf[64]; 452 Etherrock *er = ifc->arg; 453 int version; 454 455 version = multicastea(mac, a); 456 sprint(buf, "remmulti %E", mac); 457 switch(version){ 458 case V4: 459 devtab[er->cchan4->type]->write(er->cchan4, buf, strlen(buf), 0); 460 break; 461 case V6: 462 devtab[er->cchan6->type]->write(er->cchan6, buf, strlen(buf), 0); 463 break; 464 default: 465 panic("etherremmulti: version %d", version); 466 } 467 } 468 469 /* 470 * send an ethernet arp 471 * (only v4, v6 uses the neighbor discovery, rfc1970) 472 */ 473 static void 474 sendarp(Ipifc *ifc, Arpent *a) 475 { 476 int n; 477 Block *bp; 478 Etherarp *e; 479 Etherrock *er = ifc->arg; 480 481 /* don't do anything if it's been less than a second since the last */ 482 if(NOW - a->ctime < 1000){ 483 arprelease(er->f->arp, a); 484 return; 485 } 486 487 /* remove all but the last message */ 488 while((bp = a->hold) != nil){ 489 if(bp == a->last) 490 break; 491 a->hold = bp->list; 492 freeblist(bp); 493 } 494 495 /* try to keep it around for a second more */ 496 a->ctime = NOW; 497 arprelease(er->f->arp, a); 498 499 n = sizeof(Etherarp); 500 if(n < a->type->mintu) 501 n = a->type->mintu; 502 bp = allocb(n); 503 memset(bp->rp, 0, n); 504 e = (Etherarp*)bp->rp; 505 memmove(e->tpa, a->ip+IPv4off, sizeof(e->tpa)); 506 ipv4local(ifc, e->spa); 507 memmove(e->sha, ifc->mac, sizeof(e->sha)); 508 memset(e->d, 0xff, sizeof(e->d)); /* ethernet broadcast */ 509 memmove(e->s, ifc->mac, sizeof(e->s)); 510 511 hnputs(e->type, ETARP); 512 hnputs(e->hrd, 1); 513 hnputs(e->pro, ETIP4); 514 e->hln = sizeof(e->sha); 515 e->pln = sizeof(e->spa); 516 hnputs(e->op, ARPREQUEST); 517 bp->wp += n; 518 519 n = devtab[er->achan->type]->bwrite(er->achan, bp, 0); 520 if(n < 0) 521 print("arp: send: %r\n"); 522 } 523 524 static void 525 resolveaddr6(Ipifc *ifc, Arpent *a) 526 { 527 int sflag; 528 Block *bp; 529 Etherrock *er = ifc->arg; 530 uchar ipsrc[IPaddrlen]; 531 532 /* don't do anything if it's been less than a second since the last */ 533 if(NOW - a->ctime < ReTransTimer){ 534 arprelease(er->f->arp, a); 535 return; 536 } 537 538 /* remove all but the last message */ 539 while((bp = a->hold) != nil){ 540 if(bp == a->last) 541 break; 542 a->hold = bp->list; 543 freeblist(bp); 544 } 545 546 /* try to keep it around for a second more */ 547 a->ctime = NOW; 548 a->rtime = NOW + ReTransTimer; 549 if(a->rxtsrem <= 0) { 550 arprelease(er->f->arp, a); 551 return; 552 } 553 554 a->rxtsrem--; 555 arprelease(er->f->arp, a); 556 557 if(sflag = ipv6anylocal(ifc, ipsrc)) 558 icmpns(er->f, ipsrc, sflag, a->ip, TARG_MULTI, ifc->mac); 559 } 560 561 /* 562 * send a gratuitous arp to refresh arp caches 563 */ 564 static void 565 sendgarp(Ipifc *ifc, uchar *ip) 566 { 567 int n; 568 Block *bp; 569 Etherarp *e; 570 Etherrock *er = ifc->arg; 571 572 /* don't arp for our initial non address */ 573 if(ipcmp(ip, IPnoaddr) == 0) 574 return; 575 576 n = sizeof(Etherarp); 577 if(n < ifc->m->mintu) 578 n = ifc->m->mintu; 579 bp = allocb(n); 580 memset(bp->rp, 0, n); 581 e = (Etherarp*)bp->rp; 582 memmove(e->tpa, ip+IPv4off, sizeof(e->tpa)); 583 memmove(e->spa, ip+IPv4off, sizeof(e->spa)); 584 memmove(e->sha, ifc->mac, sizeof(e->sha)); 585 memset(e->d, 0xff, sizeof(e->d)); /* ethernet broadcast */ 586 memmove(e->s, ifc->mac, sizeof(e->s)); 587 588 hnputs(e->type, ETARP); 589 hnputs(e->hrd, 1); 590 hnputs(e->pro, ETIP4); 591 e->hln = sizeof(e->sha); 592 e->pln = sizeof(e->spa); 593 hnputs(e->op, ARPREQUEST); 594 bp->wp += n; 595 596 n = devtab[er->achan->type]->bwrite(er->achan, bp, 0); 597 if(n < 0) 598 print("garp: send: %r\n"); 599 } 600 601 static void 602 recvarp(Ipifc *ifc) 603 { 604 int n; 605 Block *ebp, *rbp; 606 Etherarp *e, *r; 607 uchar ip[IPaddrlen]; 608 static uchar eprinted[4]; 609 Etherrock *er = ifc->arg; 610 611 ebp = devtab[er->achan->type]->bread(er->achan, ifc->maxtu, 0); 612 if(ebp == nil) { 613 print("arp: rcv: %r\n"); 614 return; 615 } 616 617 e = (Etherarp*)ebp->rp; 618 switch(nhgets(e->op)) { 619 default: 620 break; 621 622 case ARPREPLY: 623 /* check for machine using my ip address */ 624 v4tov6(ip, e->spa); 625 if(iplocalonifc(ifc, ip) || ipproxyifc(er->f, ifc, ip)){ 626 if(memcmp(e->sha, ifc->mac, sizeof(e->sha)) != 0){ 627 print("arprep: 0x%E/0x%E also has ip addr %V\n", 628 e->s, e->sha, e->spa); 629 break; 630 } 631 } 632 633 /* make sure we're not entering broadcast addresses */ 634 if(ipcmp(ip, ipbroadcast) == 0 || 635 !memcmp(e->sha, etherbroadcast, sizeof(e->sha))){ 636 print("arprep: 0x%E/0x%E cannot register broadcast address %I\n", 637 e->s, e->sha, e->spa); 638 break; 639 } 640 641 arpenter(er->f, V4, e->spa, e->sha, sizeof(e->sha), 0); 642 break; 643 644 case ARPREQUEST: 645 /* don't answer arps till we know who we are */ 646 if(ifc->lifc == 0) 647 break; 648 649 /* check for machine using my ip or ether address */ 650 v4tov6(ip, e->spa); 651 if(iplocalonifc(ifc, ip) || ipproxyifc(er->f, ifc, ip)){ 652 if(memcmp(e->sha, ifc->mac, sizeof(e->sha)) != 0){ 653 if (memcmp(eprinted, e->spa, sizeof(e->spa))){ 654 /* print only once */ 655 print("arpreq: 0x%E also has ip addr %V\n", e->sha, e->spa); 656 memmove(eprinted, e->spa, sizeof(e->spa)); 657 } 658 } 659 } else { 660 if(memcmp(e->sha, ifc->mac, sizeof(e->sha)) == 0){ 661 print("arpreq: %V also has ether addr %E\n", e->spa, e->sha); 662 break; 663 } 664 } 665 666 /* refresh what we know about sender */ 667 arpenter(er->f, V4, e->spa, e->sha, sizeof(e->sha), 1); 668 669 /* answer only requests for our address or systems we're proxying for */ 670 v4tov6(ip, e->tpa); 671 if(!iplocalonifc(ifc, ip)) 672 if(!ipproxyifc(er->f, ifc, ip)) 673 break; 674 675 n = sizeof(Etherarp); 676 if(n < ifc->mintu) 677 n = ifc->mintu; 678 rbp = allocb(n); 679 r = (Etherarp*)rbp->rp; 680 memset(r, 0, sizeof(Etherarp)); 681 hnputs(r->type, ETARP); 682 hnputs(r->hrd, 1); 683 hnputs(r->pro, ETIP4); 684 r->hln = sizeof(r->sha); 685 r->pln = sizeof(r->spa); 686 hnputs(r->op, ARPREPLY); 687 memmove(r->tha, e->sha, sizeof(r->tha)); 688 memmove(r->tpa, e->spa, sizeof(r->tpa)); 689 memmove(r->sha, ifc->mac, sizeof(r->sha)); 690 memmove(r->spa, e->tpa, sizeof(r->spa)); 691 memmove(r->d, e->sha, sizeof(r->d)); 692 memmove(r->s, ifc->mac, sizeof(r->s)); 693 rbp->wp += n; 694 695 n = devtab[er->achan->type]->bwrite(er->achan, rbp, 0); 696 if(n < 0) 697 print("arp: write: %r\n"); 698 } 699 freeb(ebp); 700 } 701 702 static void 703 recvarpproc(void *v) 704 { 705 Ipifc *ifc = v; 706 Etherrock *er = ifc->arg; 707 708 er->arpp = up; 709 if(waserror()){ 710 er->arpp = 0; 711 pexit("hangup", 1); 712 } 713 for(;;) 714 recvarp(ifc); 715 } 716 717 static int 718 multicastea(uchar *ea, uchar *ip) 719 { 720 int x; 721 722 switch(x = ipismulticast(ip)){ 723 case V4: 724 ea[0] = 0x01; 725 ea[1] = 0x00; 726 ea[2] = 0x5e; 727 ea[3] = ip[13] & 0x7f; 728 ea[4] = ip[14]; 729 ea[5] = ip[15]; 730 break; 731 case V6: 732 ea[0] = 0x33; 733 ea[1] = 0x33; 734 ea[2] = ip[12]; 735 ea[3] = ip[13]; 736 ea[4] = ip[14]; 737 ea[5] = ip[15]; 738 break; 739 } 740 return x; 741 } 742 743 /* 744 * fill in an arp entry for broadcast or multicast 745 * addresses. Return the first queued packet for the 746 * IP address. 747 */ 748 static Block* 749 multicastarp(Fs *f, Arpent *a, Medium *medium, uchar *mac) 750 { 751 /* is it broadcast? */ 752 switch(ipforme(f, a->ip)){ 753 case Runi: 754 return nil; 755 case Rbcast: 756 memset(mac, 0xff, 6); 757 return arpresolve(f->arp, a, medium, mac); 758 default: 759 break; 760 } 761 762 /* if multicast, fill in mac */ 763 switch(multicastea(mac, a->ip)){ 764 case V4: 765 case V6: 766 return arpresolve(f->arp, a, medium, mac); 767 } 768 769 /* let arp take care of it */ 770 return nil; 771 } 772 773 void 774 ethermediumlink(void) 775 { 776 addipmedium(ðermedium); 777 addipmedium(&gbemedium); 778 } 779 780 781 static void 782 etherpref2addr(uchar *pref, uchar *ea) 783 { 784 pref[8] = ea[0] | 0x2; 785 pref[9] = ea[1]; 786 pref[10] = ea[2]; 787 pref[11] = 0xFF; 788 pref[12] = 0xFE; 789 pref[13] = ea[3]; 790 pref[14] = ea[4]; 791 pref[15] = ea[5]; 792 } 793