1 /* if_en.c 4.57 82/04/16 */ 2 3 #include "en.h" 4 #include "imp.h" 5 6 /* 7 * Xerox prototype (3 Mb) Ethernet interface driver. 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/enreg.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_en.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 ENMTU (1024+512) 35 36 int enprobe(), enattach(), enrint(), enxint(), encollide(); 37 struct uba_device *eninfo[NEN]; 38 u_short enstd[] = { 0 }; 39 struct uba_driver endriver = 40 { enprobe, 0, enattach, 0, enstd, "en", eninfo }; 41 #define ENUNIT(x) minor(x) 42 43 int eninit(),enoutput(),enreset(); 44 45 /* 46 * Ethernet software status per interface. 47 * 48 * Each interface is referenced by a network interface structure, 49 * es_if, which the routing code uses to locate the interface. 50 * This structure contains the output queue for the interface, its address, ... 51 * We also have, for each interface, a UBA interface structure, which 52 * contains information about the UNIBUS resources held by the interface: 53 * map registers, buffered data paths, etc. Information is cached in this 54 * structure for use by the if_uba.c routines in running the interface 55 * efficiently. 56 */ 57 struct en_softc { 58 struct ifnet es_if; /* network-visible interface */ 59 struct ifuba es_ifuba; /* UNIBUS resources */ 60 short es_delay; /* current output delay */ 61 short es_mask; /* mask for current output delay */ 62 short es_lastx; /* host last transmitted to */ 63 short es_oactive; /* is output active? */ 64 short es_olen; /* length of last output */ 65 } en_softc[NEN]; 66 67 /* 68 * Do output DMA to determine interface presence and 69 * interrupt vector. DMA is too short to disturb other hosts. 70 */ 71 enprobe(reg) 72 caddr_t reg; 73 { 74 register int br, cvec; /* r11, r10 value-result */ 75 register struct endevice *addr = (struct endevice *)reg; 76 77 COUNT(ENPROBE); 78 #ifdef lint 79 br = 0; cvec = br; br = cvec; 80 enrint(0); enxint(0); encollide(0); 81 #endif 82 addr->en_istat = 0; 83 addr->en_owc = -1; 84 addr->en_oba = 0; 85 addr->en_ostat = EN_IEN|EN_GO; 86 DELAY(100000); 87 addr->en_ostat = 0; 88 br = 0x16; /* temporary ec hack */ 89 return (1); 90 } 91 92 /* 93 * Interface exists: make available by filling in network interface 94 * record. System will initialize the interface when it is ready 95 * to accept packets. 96 */ 97 enattach(ui) 98 struct uba_device *ui; 99 { 100 register struct en_softc *es = &en_softc[ui->ui_unit]; 101 register struct sockaddr_in *sin; 102 COUNT(ENATTACH); 103 104 es->es_if.if_unit = ui->ui_unit; 105 es->es_if.if_name = "en"; 106 es->es_if.if_mtu = ENMTU; 107 es->es_if.if_net = ui->ui_flags & 0xff; 108 es->es_if.if_host[0] = 109 (~(((struct endevice *)eninfo[ui->ui_unit]->ui_addr)->en_addr)) & 0xff; 110 sin = (struct sockaddr_in *)&es->es_if.if_addr; 111 sin->sin_family = AF_INET; 112 sin->sin_addr = if_makeaddr(es->es_if.if_net, es->es_if.if_host[0]); 113 sin = (struct sockaddr_in *)&es->es_if.if_broadaddr; 114 sin->sin_family = AF_INET; 115 sin->sin_addr = if_makeaddr(es->es_if.if_net, 0); 116 es->es_if.if_flags = IFF_BROADCAST; 117 es->es_if.if_init = eninit; 118 es->es_if.if_output = enoutput; 119 es->es_if.if_ubareset = enreset; 120 es->es_ifuba.ifu_flags = UBA_NEEDBDP | UBA_NEED16 | UBA_CANTWAIT; 121 if_attach(&es->es_if); 122 #if NIMP == 0 123 /* here's one for you john baby.... */ 124 enlhinit((ui->ui_flags &~ 0xff) | 0x0a); 125 #endif 126 } 127 128 /* 129 * Reset of interface after UNIBUS reset. 130 * If interface is on specified uba, reset its state. 131 */ 132 enreset(unit, uban) 133 int unit, uban; 134 { 135 register struct uba_device *ui; 136 COUNT(ENRESET); 137 138 if (unit >= NEN || (ui = eninfo[unit]) == 0 || ui->ui_alive == 0 || 139 ui->ui_ubanum != uban) 140 return; 141 printf(" en%d", unit); 142 eninit(unit); 143 } 144 145 /* 146 * Initialization of interface; clear recorded pending 147 * operations, and reinitialize UNIBUS usage. 148 */ 149 eninit(unit) 150 int unit; 151 { 152 register struct en_softc *es = &en_softc[unit]; 153 register struct uba_device *ui = eninfo[unit]; 154 register struct endevice *addr; 155 int s; 156 157 if (if_ubainit(&es->es_ifuba, ui->ui_ubanum, 158 sizeof (struct en_header), (int)btoc(ENMTU)) == 0) { 159 printf("en%d: can't initialize\n", unit); 160 es->es_if.if_flags &= ~IFF_UP; 161 return; 162 } 163 addr = (struct endevice *)ui->ui_addr; 164 addr->en_istat = addr->en_ostat = 0; 165 166 /* 167 * Hang a receive and start any 168 * pending writes by faking a transmit complete. 169 */ 170 s = splimp(); 171 addr->en_iba = es->es_ifuba.ifu_r.ifrw_info; 172 addr->en_iwc = -(sizeof (struct en_header) + ENMTU) >> 1; 173 addr->en_istat = EN_IEN|EN_GO; 174 es->es_oactive = 1; 175 es->es_if.if_flags |= IFF_UP; 176 enxint(unit); 177 splx(s); 178 if_rtinit(&es->es_if, RTF_DIRECT|RTF_UP); 179 } 180 181 int enalldelay = 0; 182 int enlastdel = 25; 183 int enlastmask = (~0) << 5; 184 185 /* 186 * Start or restart output on interface. 187 * If interface is already active, then this is a retransmit 188 * after a collision, and just restuff registers and delay. 189 * If interface is not already active, get another datagram 190 * to send off of the interface queue, and map it to the interface 191 * before starting the output. 192 */ 193 enstart(dev) 194 dev_t dev; 195 { 196 int unit = ENUNIT(dev); 197 struct uba_device *ui = eninfo[unit]; 198 register struct en_softc *es = &en_softc[unit]; 199 register struct endevice *addr; 200 struct mbuf *m; 201 int dest; 202 COUNT(ENSTART); 203 204 if (es->es_oactive) 205 goto restart; 206 207 /* 208 * Not already active: dequeue another request 209 * and map it to the UNIBUS. If no more requests, 210 * just return. 211 */ 212 IF_DEQUEUE(&es->es_if.if_snd, m); 213 if (m == 0) { 214 es->es_oactive = 0; 215 return; 216 } 217 dest = mtod(m, struct en_header *)->en_dhost; 218 es->es_olen = if_wubaput(&es->es_ifuba, m); 219 220 /* 221 * Ethernet cannot take back-to-back packets (no 222 * buffering in interface. To help avoid overrunning 223 * receivers, enforce a small delay (about 1ms) in interface: 224 * * between all packets when enalldelay 225 * * whenever last packet was broadcast 226 * * whenever this packet is to same host as last packet 227 */ 228 if (enalldelay || es->es_lastx == 0 || es->es_lastx == dest) { 229 es->es_delay = enlastdel; 230 es->es_mask = enlastmask; 231 } 232 es->es_lastx = dest; 233 234 restart: 235 /* 236 * Have request mapped to UNIBUS for transmission. 237 * Purge any stale data from this BDP, and start the otput. 238 */ 239 if (es->es_ifuba.ifu_flags & UBA_NEEDBDP) 240 UBAPURGE(es->es_ifuba.ifu_uba, es->es_ifuba.ifu_w.ifrw_bdp); 241 addr = (struct endevice *)ui->ui_addr; 242 addr->en_oba = (int)es->es_ifuba.ifu_w.ifrw_info; 243 addr->en_odelay = es->es_delay; 244 addr->en_owc = -((es->es_olen + 1) >> 1); 245 addr->en_ostat = EN_IEN|EN_GO; 246 es->es_oactive = 1; 247 } 248 249 /* 250 * Ethernet interface transmitter interrupt. 251 * Start another output if more data to send. 252 */ 253 enxint(unit) 254 int unit; 255 { 256 register struct uba_device *ui = eninfo[unit]; 257 register struct en_softc *es = &en_softc[unit]; 258 register struct endevice *addr = (struct endevice *)ui->ui_addr; 259 COUNT(ENXINT); 260 261 if (es->es_oactive == 0) 262 return; 263 if (es->es_mask && (addr->en_ostat&EN_OERROR)) { 264 es->es_if.if_oerrors++; 265 if (es->es_if.if_oerrors % 100 == 0) 266 printf("en%d: += 100 output errors\n", unit); 267 endocoll(unit); 268 return; 269 } 270 es->es_if.if_opackets++; 271 es->es_oactive = 0; 272 es->es_delay = 0; 273 es->es_mask = ~0; 274 if (es->es_ifuba.ifu_xtofree) { 275 m_freem(es->es_ifuba.ifu_xtofree); 276 es->es_ifuba.ifu_xtofree = 0; 277 } 278 if (es->es_if.if_snd.ifq_head == 0) { 279 es->es_lastx = 256; /* putatively illegal */ 280 return; 281 } 282 enstart(unit); 283 } 284 285 /* 286 * Collision on ethernet interface. Do exponential 287 * backoff, and retransmit. If have backed off all 288 * the way print warning diagnostic, and drop packet. 289 */ 290 encollide(unit) 291 int unit; 292 { 293 struct en_softc *es = &en_softc[unit]; 294 COUNT(ENCOLLIDE); 295 296 es->es_if.if_collisions++; 297 if (es->es_oactive == 0) 298 return; 299 endocoll(unit); 300 } 301 302 endocoll(unit) 303 int unit; 304 { 305 register struct en_softc *es = &en_softc[unit]; 306 307 /* 308 * Es_mask is a 16 bit number with n low zero bits, with 309 * n the number of backoffs. When es_mask is 0 we have 310 * backed off 16 times, and give up. 311 */ 312 if (es->es_mask == 0) { 313 printf("en%d: send error\n", unit); 314 enxint(unit); 315 return; 316 } 317 /* 318 * Another backoff. Restart with delay based on n low bits 319 * of the interval timer. 320 */ 321 es->es_mask <<= 1; 322 es->es_delay = mfpr(ICR) &~ es->es_mask; 323 enstart(unit); 324 } 325 326 struct sockaddr_pup pupsrc = { AF_PUP }; 327 struct sockaddr_pup pupdst = { AF_PUP }; 328 struct sockproto pupproto = { PF_PUP }; 329 /* 330 * Ethernet interface receiver interrupt. 331 * If input error just drop packet. 332 * Otherwise purge input buffered data path and examine 333 * packet to determine type. If can't determine length 334 * from type, then have to drop packet. Othewise decapsulate 335 * packet based on type and pass to type specific higher-level 336 * input routine. 337 */ 338 enrint(unit) 339 int unit; 340 { 341 register struct en_softc *es = &en_softc[unit]; 342 struct endevice *addr = (struct endevice *)eninfo[unit]->ui_addr; 343 register struct en_header *en; 344 struct mbuf *m; 345 int len, plen; short resid; 346 register struct ifqueue *inq; 347 int off; 348 COUNT(ENRINT); 349 350 es->es_if.if_ipackets++; 351 352 /* 353 * Purge BDP; drop if input error indicated. 354 */ 355 if (es->es_ifuba.ifu_flags & UBA_NEEDBDP) 356 UBAPURGE(es->es_ifuba.ifu_uba, es->es_ifuba.ifu_r.ifrw_bdp); 357 if (addr->en_istat&EN_IERROR) { 358 es->es_if.if_ierrors++; 359 if (es->es_if.if_ierrors % 100 == 0) 360 printf("en%d: += 100 input errors\n", unit); 361 goto setup; 362 } 363 364 /* 365 * Calculate input data length. 366 * Get pointer to ethernet header (in input buffer). 367 * Deal with trailer protocol: if type is PUP trailer 368 * get true type from first 16-bit word past data. 369 * Remember that type was trailer by setting off. 370 */ 371 resid = addr->en_iwc; 372 if (resid) 373 resid |= 0176000; 374 len = (((sizeof (struct en_header) + ENMTU) >> 1) + resid) << 1; 375 len -= sizeof (struct en_header); 376 if (len >= ENMTU) 377 goto setup; /* sanity */ 378 en = (struct en_header *)(es->es_ifuba.ifu_r.ifrw_addr); 379 #define endataaddr(en, off, type) ((type)(((caddr_t)((en)+1)+(off)))) 380 if (en->en_type >= ENPUP_TRAIL && 381 en->en_type < ENPUP_TRAIL+ENPUP_NTRAILER) { 382 off = (en->en_type - ENPUP_TRAIL) * 512; 383 if (off >= ENMTU) 384 goto setup; /* sanity */ 385 en->en_type = *endataaddr(en, off, u_short *); 386 resid = *(endataaddr(en, off+2, u_short *)); 387 if (off + resid > len) 388 goto setup; /* sanity */ 389 len = off + resid; 390 } else 391 off = 0; 392 if (len == 0) 393 goto setup; 394 /* 395 * Pull packet off interface. Off is nonzero if packet 396 * has trailing header; if_rubaget will then force this header 397 * information to be at the front, but we still have to drop 398 * the type and length which are at the front of any trailer data. 399 */ 400 m = if_rubaget(&es->es_ifuba, len, off); 401 if (m == 0) 402 goto setup; 403 if (off) { 404 m->m_off += 2 * sizeof (u_short); 405 m->m_len -= 2 * sizeof (u_short); 406 } 407 switch (en->en_type) { 408 409 #ifdef INET 410 case ENPUP_IPTYPE: 411 schednetisr(NETISR_IP); 412 inq = &ipintrq; 413 break; 414 #endif 415 #ifdef PUP 416 case ENPUP_PUPTYPE: { 417 struct pup_header *pup = mtod(m, struct pup_header *); 418 419 pupproto.sp_protocol = pup->pup_type; 420 pupdst.spup_addr = pup->pup_dport; 421 pupsrc.spup_addr = pup->pup_sport; 422 raw_input(m, &pupproto, (struct sockaddr *)&pupsrc, 423 (struct sockaddr *)&pupdst); 424 goto setup; 425 } 426 #endif 427 default: 428 m_freem(m); 429 goto setup; 430 } 431 432 if (IF_QFULL(inq)) { 433 IF_DROP(inq); 434 m_freem(m); 435 } else 436 IF_ENQUEUE(inq, m); 437 438 setup: 439 /* 440 * Reset for next packet. 441 */ 442 addr->en_iba = es->es_ifuba.ifu_r.ifrw_info; 443 addr->en_iwc = -(sizeof (struct en_header) + ENMTU) >> 1; 444 addr->en_istat = EN_IEN|EN_GO; 445 } 446 447 /* 448 * Ethernet output routine. 449 * Encapsulate a packet of type family for the local net. 450 * Use trailer local net encapsulation if enough data in first 451 * packet leaves a multiple of 512 bytes of data in remainder. 452 */ 453 enoutput(ifp, m0, dst) 454 struct ifnet *ifp; 455 struct mbuf *m0; 456 struct sockaddr *dst; 457 { 458 int type, dest, s, error; 459 register struct mbuf *m = m0; 460 register struct en_header *en; 461 register int off; 462 463 COUNT(ENOUTPUT); 464 switch (dst->sa_family) { 465 466 #ifdef INET 467 case AF_INET: 468 dest = ((struct sockaddr_in *)dst)->sin_addr.s_addr; 469 if (dest & 0x00ffff00) { 470 error = EPERM; /* ??? */ 471 goto bad; 472 } 473 dest = (dest >> 24) & 0xff; 474 off = ntohs((u_short)mtod(m, struct ip *)->ip_len) - m->m_len; 475 if (off > 0 && (off & 0x1ff) == 0 && 476 m->m_off >= MMINOFF + 2 * sizeof (u_short)) { 477 type = ENPUP_TRAIL + (off>>9); 478 m->m_off -= 2 * sizeof (u_short); 479 m->m_len += 2 * sizeof (u_short); 480 *mtod(m, u_short *) = ENPUP_IPTYPE; 481 *(mtod(m, u_short *) + 1) = m->m_len; 482 goto gottrailertype; 483 } 484 type = ENPUP_IPTYPE; 485 off = 0; 486 goto gottype; 487 #endif 488 #ifdef PUP 489 case AF_PUP: 490 dest = ((struct sockaddr_pup *)dst)->spup_addr.pp_host; 491 type = ENPUP_PUPTYPE; 492 off = 0; 493 goto gottype; 494 #endif 495 496 default: 497 printf("en%d: can't handle af%d\n", ifp->if_unit, 498 dst->sa_family); 499 error = EAFNOSUPPORT; 500 goto bad; 501 } 502 503 gottrailertype: 504 /* 505 * Packet to be sent as trailer: move first packet 506 * (control information) to end of chain. 507 */ 508 while (m->m_next) 509 m = m->m_next; 510 m->m_next = m0; 511 m = m0->m_next; 512 m0->m_next = 0; 513 m0 = m; 514 515 gottype: 516 /* 517 * Add local net header. If no space in first mbuf, 518 * allocate another. 519 */ 520 if (m->m_off > MMAXOFF || 521 MMINOFF + sizeof (struct en_header) > m->m_off) { 522 m = m_get(M_DONTWAIT); 523 if (m == 0) { 524 error = ENOBUFS; 525 goto bad; 526 } 527 m->m_next = m0; 528 m->m_off = MMINOFF; 529 m->m_len = sizeof (struct en_header); 530 } else { 531 m->m_off -= sizeof (struct en_header); 532 m->m_len += sizeof (struct en_header); 533 } 534 en = mtod(m, struct en_header *); 535 en->en_shost = ifp->if_host[0]; 536 en->en_dhost = dest; 537 en->en_type = type; 538 539 /* 540 * Queue message on interface, and start output if interface 541 * not yet active. 542 */ 543 s = splimp(); 544 if (IF_QFULL(&ifp->if_snd)) { 545 IF_DROP(&ifp->if_snd); 546 error = ENOBUFS; 547 goto qfull; 548 } 549 IF_ENQUEUE(&ifp->if_snd, m); 550 if (en_softc[ifp->if_unit].es_oactive == 0) 551 enstart(ifp->if_unit); 552 splx(s); 553 return (0); 554 qfull: 555 m0 = m; 556 splx(s); 557 bad: 558 m_freem(m0); 559 return (error); 560 } 561 562 #if NIMP == 0 && NEN > 0 563 /* 564 * Logical host interface driver. 565 * Allows host to appear as an ARPAnet 566 * logical host. Must also have routing 567 * table entry set up to forward packets 568 * to appropriate gateway on localnet. 569 */ 570 571 struct ifnet enlhif; 572 int enlhoutput(); 573 574 /* 575 * Called by localnet interface to allow logical 576 * host interface to "attach". Nothing should ever 577 * be sent locally to this interface, it's purpose 578 * is simply to establish the host's arpanet address. 579 */ 580 enlhinit(addr) 581 int addr; 582 { 583 register struct ifnet *ifp = &enlhif; 584 register struct sockaddr_in *sin; 585 586 COUNT(ENLHINIT); 587 ifp->if_name = "lh"; 588 ifp->if_mtu = ENMTU; 589 sin = (struct sockaddr_in *)&ifp->if_addr; 590 sin->sin_family = AF_INET; 591 sin->sin_addr.s_addr = addr; 592 ifp->if_net = sin->sin_addr.s_net; 593 ifp->if_flags = IFF_UP; 594 ifp->if_output = enlhoutput; /* should never be used */ 595 if_attach(ifp); 596 } 597 598 enlhoutput(ifp, m0, dst) 599 struct ifnet *ifp; 600 struct mbuf *m0; 601 struct sockaddr *dst; 602 { 603 COUNT(ENLHOUTPUT); 604 ifp->if_oerrors++; 605 m_freem(m0); 606 return (0); 607 } 608 #endif 609