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