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