1 /* if_ec.c 4.4 82/04/12 */ 2 3 #include "ec.h" 4 #include "imp.h" 5 6 /* 7 * 3Com Ethernet Controller interface 8 */ 9 10 #include "../h/param.h" 11 #include "../h/systm.h" 12 #include "../h/mbuf.h" 13 #include "../h/pte.h" 14 #include "../h/buf.h" 15 #include "../h/protosw.h" 16 #include "../h/socket.h" 17 #include "../h/ubareg.h" 18 #include "../h/ubavar.h" 19 #include "../h/ecreg.h" 20 #include "../h/cpu.h" 21 #include "../h/mtpr.h" 22 #include "../h/vmmac.h" 23 #include "../net/in.h" 24 #include "../net/in_systm.h" 25 #include "../net/if.h" 26 #include "../net/if_ec.h" 27 #include "../net/if_uba.h" 28 #include "../net/ip.h" 29 #include "../net/ip_var.h" 30 #include "../net/pup.h" 31 #include "../net/route.h" 32 #include <errno.h> 33 34 #define ECMTU 1500 35 36 int ecprobe(), ecattach(), ecrint(), ecxint(), eccollide(); 37 struct uba_device *ecinfo[NEC]; 38 u_short ecstd[] = { 0 }; 39 struct uba_driver ecdriver = 40 { ecprobe, 0, ecattach, 0, ecstd, "ec", ecinfo }; 41 #define ECUNIT(x) minor(x) 42 43 int ecinit(),ecoutput(),ecreset(); 44 struct mbuf *ecget(); 45 46 /* 47 * Ethernet software status per interface. 48 * 49 * Each interface is referenced by a network interface structure, 50 * es_if, which the routing code uses to locate the interface. 51 * This structure contains the output queue for the interface, its address, ... 52 * We also have, for each interface, a UBA interface structure, which 53 * contains information about the UNIBUS resources held by the interface: 54 * map registers, buffered data paths, etc. Information is cached in this 55 * structure for use by the if_uba.c routines in running the interface 56 * efficiently. 57 */ 58 struct ec_softc { 59 struct ifnet es_if; /* network-visible interface */ 60 struct ifuba es_ifuba; /* UNIBUS resources */ 61 short es_delay; /* current output delay */ 62 short es_mask; /* mask for current output delay */ 63 #ifdef notdef 64 long es_lastx; /* host last transmitted to */ 65 #endif 66 short es_oactive; /* is output active? */ 67 caddr_t es_buf[16]; /* virtual addresses of buffers */ 68 u_char es_enaddr[6]; /* board's ethernet address */ 69 } ec_softc[NEC]; 70 71 /* 72 * Do output DMA to determine interface presence and 73 * interrupt vector. DMA is too short to disturb other hosts. 74 */ 75 ecprobe(reg) 76 caddr_t reg; 77 { 78 register int br, cvec; /* r11, r10 value-result */ 79 register struct ecdevice *addr = (struct ecdevice *)reg; 80 register caddr_t ecbuf = (caddr_t) &umem[0][0600000]; 81 82 COUNT(ECPROBE); 83 #ifdef lint 84 br = 0; cvec = br; br = cvec; 85 ecrint(0); ecxint(0); eccollide(0); 86 #endif 87 /* 88 * Check for existence of buffers on Unibus. 89 * This won't work on a 780 until more work is done. 90 */ 91 if (badaddr((caddr_t) ecbuf, 2)) { 92 printf("ec: buffer mem not found"); 93 return (0); 94 } 95 96 /* 97 * Tell the system that the board has memory here, so it won't 98 * attempt to allocate the addresses later. 99 */ 100 ubamem(0, 0600000, 32*2); 101 102 /* 103 * Make a one byte packet in what should be buffer #0. 104 * Submit it for sending. This whould cause an xmit interrupt. 105 * The xmit interrupt vector is 8 bytes after the receive vector, 106 * so adjust for this before returning. 107 */ 108 *(u_short *)ecbuf = (u_short) 03777; 109 ecbuf[03777] = '\0'; 110 addr->ec_xcr = EC_XINTEN|EC_XWBN; 111 DELAY(100000); 112 addr->ec_xcr = EC_XCLR; 113 if (cvec > 0 && cvec != 0x200) 114 cvec -= 010; 115 br += 2; 116 return (1); 117 } 118 119 /* 120 * Interface exists: make available by filling in network interface 121 * record. System will initialize the interface when it is ready 122 * to accept packets. 123 */ 124 ecattach(ui) 125 struct uba_device *ui; 126 { 127 register struct ec_softc *es = &ec_softc[ui->ui_unit]; 128 register struct sockaddr_in *sin; 129 register struct ecdevice *addr = (struct ecdevice *)ui->ui_addr; 130 register int i, j; 131 register u_char *cp; 132 COUNT(ECATTACH); 133 134 es->es_if.if_unit = ui->ui_unit; 135 es->es_if.if_name = "ec"; 136 es->es_if.if_mtu = ECMTU; 137 es->es_if.if_net = ui->ui_flags & 0xff; 138 139 /* 140 * Read the ethernet address off the board, 141 * one nibble at a time! 142 */ 143 addr->ec_xcr = EC_UECLR; 144 addr->ec_rcr = EC_AROM; 145 cp = es->es_enaddr; 146 for (i=0; i<6; i++) { 147 *cp = 0; 148 for (j=0; j<=4; j+=4) { 149 *cp |= ((addr->ec_rcr >> 8) & 0xf) << j; 150 addr->ec_rcr = EC_AROM|EC_ASTEP; 151 addr->ec_rcr = EC_AROM; 152 addr->ec_rcr = EC_AROM|EC_ASTEP; 153 addr->ec_rcr = EC_AROM; 154 addr->ec_rcr = EC_AROM|EC_ASTEP; 155 addr->ec_rcr = EC_AROM; 156 addr->ec_rcr = EC_AROM|EC_ASTEP; 157 addr->ec_rcr = EC_AROM; 158 } 159 cp++; 160 } 161 printf("ec%d: addr=%x:%x:%x:%x:%x:%x\n", ui->ui_unit, 162 es->es_enaddr[0]&0xff, es->es_enaddr[1]&0xff, 163 es->es_enaddr[2]&0xff, es->es_enaddr[3]&0xff, 164 es->es_enaddr[4]&0xff, es->es_enaddr[5]&0xff); 165 es->es_if.if_host[0] = ((es->es_enaddr[3]&0xff)<<16) | 166 ((es->es_enaddr[4]&0xff)<<8) | (es->es_enaddr[5]&0xff); 167 sin = (struct sockaddr_in *)&es->es_if.if_addr; 168 sin->sin_family = AF_INET; 169 sin->sin_addr = if_makeaddr(es->es_if.if_net, es->es_if.if_host[0]); 170 171 sin = (struct sockaddr_in *)&es->es_if.if_broadaddr; 172 sin->sin_family = AF_INET; 173 sin->sin_addr = if_makeaddr(es->es_if.if_net, 0); 174 es->es_if.if_flags = IFF_BROADCAST; 175 176 es->es_if.if_init = ecinit; 177 es->es_if.if_output = ecoutput; 178 es->es_if.if_ubareset = ecreset; 179 for (i=0; i<16; i++) 180 es->es_buf[i] = &umem[ui->ui_ubanum][0600000+2048*i]; 181 if_attach(&es->es_if); 182 #if NIMP == 0 183 /* here's one for you john baby.... */ 184 if (ui->ui_flags &~ 0xff) 185 eclhinit((ui->ui_flags &~ 0xff) | 0x0a); 186 #endif 187 } 188 189 /* 190 * Reset of interface after UNIBUS reset. 191 * If interface is on specified uba, reset its state. 192 */ 193 ecreset(unit, uban) 194 int unit, uban; 195 { 196 register struct uba_device *ui; 197 COUNT(ECRESET); 198 199 if (unit >= NEC || (ui = ecinfo[unit]) == 0 || ui->ui_alive == 0 || 200 ui->ui_ubanum != uban) 201 return; 202 printf(" ec%d", unit); 203 ecinit(unit); 204 } 205 206 /* 207 * Initialization of interface; clear recorded pending 208 * operations, and reinitialize UNIBUS usage. 209 */ 210 ecinit(unit) 211 int unit; 212 { 213 register struct ec_softc *es = &ec_softc[unit]; 214 register struct uba_device *ui = ecinfo[unit]; 215 register struct ecdevice *addr; 216 register i; 217 int s; 218 219 #ifdef notdef 220 if (if_ubainit(&es->es_ifuba, ui->ui_ubanum, 221 sizeof (struct ec_header), (int)btoc(ECMTU)) == 0) { 222 printf("ec%d: can't initialize\n", unit); 223 es->es_if.if_flags &= ~IFF_UP; 224 return; 225 } 226 #endif 227 addr = (struct ecdevice *)ui->ui_addr; 228 229 /* 230 * Hang receive buffers and start any pending 231 * writes by faking a transmit complete. 232 */ 233 s = splimp(); 234 for (i=ECRHBF; i>=ECRLBF; i--) 235 addr->ec_rcr = EC_READ|i; 236 es->es_oactive = 1; 237 es->es_if.if_flags |= IFF_UP; 238 ecxint(unit); 239 splx(s); 240 if_rtinit(&es->es_if, RTF_DIRECT|RTF_UP); 241 } 242 243 #ifdef notdef 244 int enalldelay = 0; 245 int eclastdel = 25; 246 int enlastmask = (~0) << 5; 247 #endif 248 249 /* 250 * Start or restart output on interface. 251 * If interface is already active, then this is a retransmit 252 * after a collision, and just restuff registers and delay. 253 * If interface is not already active, get another datagram 254 * to send off of the interface queue, and map it to the interface 255 * before starting the output. 256 */ 257 ecstart(dev) 258 dev_t dev; 259 { 260 int unit = ECUNIT(dev); 261 struct uba_device *ui = ecinfo[unit]; 262 register struct ec_softc *es = &ec_softc[unit]; 263 register struct ecdevice *addr; 264 struct mbuf *m; 265 caddr_t ecbuf; 266 int dest; 267 COUNT(ECSTART); 268 269 if (es->es_oactive) 270 goto restart; 271 272 /* 273 * Not already active: dequeue another request 274 * and copy it into the buffer. If no more requests, 275 * just return. 276 */ 277 IF_DEQUEUE(&es->es_if.if_snd, m); 278 if (m == 0) { 279 es->es_oactive = 0; 280 return; 281 } 282 #ifdef notdef 283 dest = mtod(m, struct ec_header *)->ec_dhost; /* wrong! */ 284 #endif 285 ecput(es->es_buf[ECTBF], m); 286 287 #ifdef notdef 288 /* 289 * Ethernet cannot take back-to-back packets (no 290 * buffering in interface). To avoid overrunning 291 * receivers, enforce a small delay (about 1ms) in interface: 292 * * between all packets when ecalldelay 293 * * whenever last packet was broadcast 294 * * whenever this packet is to same host as last packet 295 */ 296 if (enalldelay || es->es_lastx == 0 || es->es_lastx == dest) { 297 es->es_delay = eclastdel; 298 es->es_mask = eclastmask; 299 } 300 es->es_lastx = dest; 301 #endif 302 303 restart: 304 /* 305 * Start the output. 306 */ 307 addr = (struct ecdevice *)ui->ui_addr; 308 addr->ec_xcr = EC_WRITE|ECTBF; 309 es->es_oactive = 1; 310 } 311 312 /* 313 * Ethernet interface transmitter interrupt. 314 * Start another output if more data to send. 315 */ 316 ecxint(unit) 317 int unit; 318 { 319 register struct uba_device *ui = ecinfo[unit]; 320 register struct ec_softc *es = &ec_softc[unit]; 321 register struct ecdevice *addr = (struct ecdevice *)ui->ui_addr; 322 COUNT(ECXINT); 323 324 if (es->es_oactive == 0) 325 return; 326 if (addr->ec_xcr&EC_XDONE == 0 || addr->ec_xcr&EC_XBN != ECTBF) 327 printf("ec%d: strange xmit interrupt!\n", unit); 328 es->es_if.if_opackets++; 329 es->es_oactive = 0; 330 es->es_delay = 0; 331 es->es_mask = ~0; 332 addr->ec_xcr = EC_XCLR; 333 /* 334 * There shouldn't ever be any mbuf's to free, but just in case... 335 */ 336 if (es->es_ifuba.ifu_xtofree) { 337 m_freem(es->es_ifuba.ifu_xtofree); 338 es->es_ifuba.ifu_xtofree = 0; 339 } 340 if (es->es_if.if_snd.ifq_head == 0) { 341 #ifdef notdef 342 es->es_lastx = 0; /* ? */ 343 #endif 344 return; 345 } 346 ecstart(unit); 347 } 348 349 /* 350 * Collision on ethernet interface. Do exponential 351 * backoff, and retransmit. If have backed off all 352 * the way print warning diagnostic, and drop packet. 353 */ 354 eccollide(unit) 355 int unit; 356 { 357 struct ec_softc *es = &ec_softc[unit]; 358 COUNT(ECCOLLIDE); 359 360 printf("ec%d: eccollide\n", unit); 361 es->es_if.if_collisions++; 362 if (es->es_oactive == 0) 363 return; 364 ecdocoll(unit); 365 } 366 367 ecdocoll(unit) 368 int unit; 369 { 370 register struct ec_softc *es = &ec_softc[unit]; 371 372 /* 373 * Es_mask is a 16 bit number with n low zero bits, with 374 * n the number of backoffs. When es_mask is 0 we have 375 * backed off 16 times, and give up. 376 */ 377 if (es->es_mask == 0) { 378 printf("ec%d: send error\n", unit); 379 /* 380 * this makes enxint wrong. fix later. 381 */ 382 ecxint(unit); 383 return; 384 } 385 /* 386 * Another backoff. Restart with delay based on n low bits 387 * of the interval timer. 388 */ 389 es->es_mask <<= 1; 390 es->es_delay = mfpr(ICR) &~ es->es_mask; 391 /* 392 * This should do some sort of delay before calling ecstart. 393 * I'll figure this out later. 394 */ 395 ecstart(unit); 396 } 397 398 #ifdef notdef 399 struct sockaddr_pup pupsrc = { AF_PUP }; 400 struct sockaddr_pup pupdst = { AF_PUP }; 401 struct sockproto pupproto = { PF_PUP }; 402 #endif 403 /* 404 * Ethernet interface receiver interrupt. 405 * If input error just drop packet. 406 * Otherwise purge input buffered data path and examine 407 * packet to determine type. If can't determine length 408 * from type, then have to drop packet. Othewise decapsulate 409 * packet based on type and pass to type specific higher-level 410 * input routine. 411 */ 412 ecrint(unit) 413 int unit; 414 { 415 struct ecdevice *addr = (struct ecdevice *)ecinfo[unit]->ui_addr; 416 COUNT(ECRINT); 417 418 #ifdef notdef 419 printf("ec%d: ecrint:%d\n", unit, addr->ec_rcr & 0xf); 420 #endif 421 while (addr->ec_rcr & EC_RDONE) 422 ecread(unit); 423 } 424 425 ecread(unit) 426 int unit; 427 { 428 register struct ec_softc *es = &ec_softc[unit]; 429 struct ecdevice *addr = (struct ecdevice *)ecinfo[unit]->ui_addr; 430 register struct ec_header *ec; 431 struct mbuf *m; 432 int len, off, resid; 433 register struct ifqueue *inq; 434 caddr_t ecbuf; 435 int ecoff; 436 int buf; 437 COUNT(ECREAD); 438 439 es->es_if.if_ipackets++; 440 buf = addr->ec_rcr & EC_RBN; 441 if (buf < ECRLBF || buf > ECRHBF) 442 panic("ecrint"); 443 ecbuf = es->es_buf[buf]; 444 ecoff = *(short *)ecbuf; 445 if (ecoff <= ECRDOFF || ecoff > ECMTU+ECRDOFF) { 446 es->es_if.if_ierrors++; 447 #ifdef notdef 448 if (es->es_if.if_ierrors % 100 == 0) 449 printf("ec%d: += 100 input errors\n", unit); 450 #endif 451 printf("ec%d: input error (offset=%d)\n", unit, ecoff); 452 goto setup; 453 } 454 455 /* 456 * Get input data length. 457 * Get pointer to ethernet header (in input buffer). 458 * Deal with trailer protocol: if type is PUP trailer 459 * get true type from first 16-bit word past data. 460 * Remember that type was trailer by setting off. 461 */ 462 len = ecoff - ECRDOFF - sizeof (struct ec_header); 463 ec = (struct ec_header *)(ecbuf + ECRDOFF); 464 #define ecdataaddr(ec, off, type) ((type)(((caddr_t)((ec)+1)+(off)))) 465 if (ec->ec_type >= ECPUP_TRAIL && 466 ec->ec_type < ECPUP_TRAIL+ECPUP_NTRAILER) { 467 off = (ec->ec_type - ECPUP_TRAIL) * 512; 468 if (off >= ECMTU) 469 goto setup; /* sanity */ 470 ec->ec_type = *ecdataaddr(ec, off, u_short *); 471 resid = *(ecdataaddr(ec, off+2, u_short *)); 472 if (off + resid > len) 473 goto setup; /* sanity */ 474 len = off + resid; 475 } else 476 off = 0; 477 if (len == 0) 478 goto setup; 479 480 /* 481 * Pull packet off interface. Off is nonzero if packet 482 * has trailing header; ecget will then force this header 483 * information to be at the front, but we still have to drop 484 * the type and length which are at the front of any trailer data. 485 */ 486 m = ecget(ecbuf, len, off); 487 if (m == 0) 488 goto setup; 489 if (off) { 490 m->m_off += 2 * sizeof (u_short); 491 m->m_len -= 2 * sizeof (u_short); 492 } 493 switch (ec->ec_type) { 494 495 #ifdef INET 496 case ECPUP_IPTYPE: 497 schednetisr(NETISR_IP); 498 inq = &ipintrq; 499 break; 500 #endif 501 #ifdef notdef 502 #ifdef PUP 503 case ECPUP_PUPTYPE: { 504 struct pup_header *pup = mtod(m, struct pup_header *); 505 506 pupproto.sp_protocol = pup->pup_type; 507 pupdst.spup_addr = pup->pup_dport; 508 pupsrc.spup_addr = pup->pup_sport; 509 raw_input(m, &pupproto, (struct sockaddr *)&pupsrc, 510 (struct sockaddr *)&pupdst); 511 goto setup; 512 } 513 #endif 514 #endif 515 default: 516 m_freem(m); 517 goto setup; 518 } 519 520 if (IF_QFULL(inq)) { 521 IF_DROP(inq); 522 m_freem(m); 523 } else 524 IF_ENQUEUE(inq, m); 525 526 setup: 527 /* 528 * Reset for next packet. 529 */ 530 addr->ec_rcr = EC_READ|EC_RCLR|buf; 531 } 532 533 /* 534 * Ethernet output routine. 535 * Encapsulate a packet of type family for the local net. 536 * Use trailer local net encapsulation if enough data in first 537 * packet leaves a multiple of 512 bytes of data in remainder. 538 */ 539 ecoutput(ifp, m0, dst) 540 struct ifnet *ifp; 541 struct mbuf *m0; 542 struct sockaddr *dst; 543 { 544 int type, dest, s, error; 545 register struct ec_softc *es = &ec_softc[ifp->if_unit]; 546 register struct mbuf *m = m0; 547 register struct ec_header *ec; 548 register int off; 549 register int i; 550 551 COUNT(ECOUTPUT); 552 switch (dst->sa_family) { 553 554 #ifdef INET 555 case AF_INET: 556 dest = ((struct sockaddr_in *)dst)->sin_addr.s_addr; 557 off = ntohs((u_short)mtod(m, struct ip *)->ip_len) - m->m_len; 558 if (off > 0 && (off & 0x1ff) == 0 && 559 m->m_off >= MMINOFF + 2 * sizeof (u_short)) { 560 type = ECPUP_TRAIL + (off>>9); 561 m->m_off -= 2 * sizeof (u_short); 562 m->m_len += 2 * sizeof (u_short); 563 *mtod(m, u_short *) = ECPUP_IPTYPE; 564 *(mtod(m, u_short *) + 1) = m->m_len; 565 goto gottrailertype; 566 } 567 type = ECPUP_IPTYPE; 568 off = 0; 569 goto gottype; 570 #endif 571 #ifdef notdef 572 #ifdef PUP 573 case AF_PUP: 574 dest = ((struct sockaddr_pup *)dst)->spup_addr.pp_host; 575 type = ECPUP_PUPTYPE; 576 off = 0; 577 goto gottype; 578 #endif 579 #endif 580 581 default: 582 printf("ec%d: can't handle af%d\n", ifp->if_unit, 583 dst->sa_family); 584 error = EAFNOSUPPORT; 585 goto bad; 586 } 587 588 gottrailertype: 589 /* 590 * Packet to be sent as trailer: move first packet 591 * (control information) to end of chain. 592 */ 593 while (m->m_next) 594 m = m->m_next; 595 m->m_next = m0; 596 m = m0->m_next; 597 m0->m_next = 0; 598 m0 = m; 599 600 gottype: 601 /* 602 * Add local net header. If no space in first mbuf, 603 * allocate another. 604 */ 605 if (m->m_off > MMAXOFF || 606 MMINOFF + sizeof (struct ec_header) > m->m_off) { 607 m = m_get(M_DONTWAIT); 608 if (m == 0) { 609 error = ENOBUFS; 610 goto bad; 611 } 612 m->m_next = m0; 613 m->m_off = MMINOFF; 614 m->m_len = sizeof (struct ec_header); 615 } else { 616 m->m_off -= sizeof (struct ec_header); 617 m->m_len += sizeof (struct ec_header); 618 } 619 ec = mtod(m, struct ec_header *); 620 for (i=0; i<6; i++) 621 ec->ec_shost[i] = es->es_enaddr[i]; 622 if ((dest &~ 0xff) == 0) 623 for (i=0; i<6; i++) 624 ec->ec_dhost[i] = 0xff; 625 else { 626 ec->ec_dhost[0] = es->es_enaddr[0]; 627 ec->ec_dhost[1] = es->es_enaddr[1]; 628 ec->ec_dhost[2] = es->es_enaddr[2]; 629 ec->ec_dhost[3] = (dest>>8) & 0xff; 630 ec->ec_dhost[4] = (dest>>16) & 0xff; 631 ec->ec_dhost[5] = (dest>>24) & 0xff; 632 } 633 ec->ec_type = type; 634 635 /* 636 * Queue message on interface, and start output if interface 637 * not yet active. 638 */ 639 s = splimp(); 640 if (IF_QFULL(&ifp->if_snd)) { 641 IF_DROP(&ifp->if_snd); 642 error = ENOBUFS; 643 goto qfull; 644 } 645 IF_ENQUEUE(&ifp->if_snd, m); 646 if (es->es_oactive == 0) 647 ecstart(ifp->if_unit); 648 splx(s); 649 return (0); 650 qfull: 651 m0 = m; 652 splx(s); 653 bad: 654 m_freem(m0); 655 return(error); 656 } 657 658 /* 659 * Routine to copy from mbufs to UNIBUS memory. 660 * Similar in spirit to if_wubaput. 661 */ 662 ecput(ecbuf, m) 663 char *ecbuf; 664 struct mbuf *m; 665 { 666 register int len; 667 register struct mbuf *mp; 668 register char *bp, *mcp; 669 register int i; 670 671 COUNT(ECPUT); 672 len = 0; 673 for (mp=m; mp; mp=mp->m_next) 674 len += mp->m_len; 675 *(u_short *)ecbuf = 2048 - len; 676 bp = ecbuf + 2048 - len; 677 mp = m; 678 while (mp) { 679 mcp = mtod(mp, char *); 680 for (i=0; i<mp->m_len; i++) 681 *bp++ = *mcp++; 682 mp = m_free(mp); 683 } 684 if (bp != ecbuf+2048) 685 printf("ec: bad ecput!\n"); 686 } 687 688 /* 689 * Routine to copy from UNIBUS memory into mbufs. 690 * Similar in spirit to if_rubaget. 691 */ 692 struct mbuf * 693 ecget(ecbuf, totlen, off0) 694 char *ecbuf; 695 int totlen, off0; 696 { 697 struct mbuf *top, **mp, *m; 698 int off = off0; 699 int len; 700 register char *cp = ecbuf + ECRDOFF + sizeof (struct ec_header); 701 register char *mcp; 702 register int i; 703 704 COUNT(ECGET); 705 top = 0; 706 mp = ⊤ 707 while (totlen > 0) { 708 MGET(m, 0); 709 if (m == 0) 710 goto bad; 711 if (off) { 712 len = totlen - off; 713 cp = ecbuf + ECRDOFF + sizeof (struct ec_header) + off; 714 } else 715 len = totlen; 716 if (len >= CLBYTES) { 717 struct mbuf *p; 718 719 MCLGET(p, 1); 720 if (p != 0) { 721 m->m_len = len = CLBYTES; 722 m->m_off = (int)p - (int)m; 723 } else { 724 m->m_len = len = MIN(MLEN, len); 725 m->m_off = MMINOFF; 726 } 727 } else { 728 m->m_len = len = MIN(MLEN, len); 729 m->m_off = MMINOFF; 730 } 731 mcp = mtod(m, char *); 732 for (i=0; i<len; i++) 733 *mcp++ = *cp++; 734 *mp = m; 735 mp = &m->m_next; 736 if (off) { 737 off += len; 738 if (off == totlen) { 739 cp = ecbuf + ECRDOFF + 740 sizeof (struct ec_header); 741 off = 0; 742 totlen = off0; 743 } 744 } else 745 totlen -= len; 746 } 747 return (top); 748 bad: 749 m_freem(top); 750 return (0); 751 } 752 753 #if NIMP == 0 && NEC > 0 754 /* 755 * Logical host interface driver. 756 * Allows host to appear as an ARPAnet 757 * logical host. Must also have routing 758 * table entry set up to forward packets 759 * to appropriate gateway on localnet. 760 */ 761 762 struct ifnet eclhif; 763 int eclhoutput(); 764 765 /* 766 * Called by localnet interface to allow logical 767 * host interface to "attach". Nothing should ever 768 * be sent locally to this interface, it's purpose 769 * is simply to establish the host's arpanet address. 770 */ 771 eclhinit(addr) 772 int addr; 773 { 774 register struct ifnet *ifp = &eclhif; 775 register struct sockaddr_in *sin; 776 777 COUNT(ECLHINIT); 778 ifp->if_name = "lh"; 779 ifp->if_mtu = ECMTU; 780 sin = (struct sockaddr_in *)&ifp->if_addr; 781 sin->sin_family = AF_INET; 782 sin->sin_addr.s_addr = addr; 783 ifp->if_net = sin->sin_addr.s_net; 784 ifp->if_flags = IFF_UP; 785 ifp->if_output = eclhoutput; /* should never be used */ 786 if_attach(ifp); 787 } 788 789 eclhoutput(ifp, m0, dst) 790 struct ifnet *ifp; 791 struct mbuf *m0; 792 struct sockaddr *dst; 793 { 794 COUNT(ECLHOUTPUT); 795 ifp->if_oerrors++; 796 m_freem(m0); 797 return (0); 798 } 799 #endif 800