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