1 /* if_en.c 4.46 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 break; 380 #endif 381 #ifdef PUP 382 case ENPUP_PUPTYPE: 383 len = endataaddr(en, off ? off + sizeof (u_short) : 0, 384 struct pup_header *)->pup_length; 385 break; 386 #endif 387 388 default: 389 printf("en%d: unknown pkt type 0x%x\n", unit, en->en_type); 390 goto setup; 391 } 392 if (off) 393 len += sizeof (u_short); 394 if (len == 0) 395 goto setup; 396 397 /* 398 * Pull packet off interface. Off is nonzero if packet 399 * has trailing header; if_rubaget will then force this header 400 * information to be at the front, but we still have to drop 401 * the two-byte type which is at the front of any trailer data. 402 */ 403 m = if_rubaget(&es->es_ifuba, len, off); 404 if (m == 0) 405 goto setup; 406 if (off) { 407 m->m_off += sizeof (u_short); 408 m->m_len -= sizeof (u_short); 409 } 410 switch (en->en_type) { 411 412 #ifdef INET 413 case ENPUP_IPTYPE: 414 schednetisr(NETISR_IP); 415 inq = &ipintrq; 416 break; 417 #endif 418 #ifdef PUP 419 case ENPUP_PUPTYPE: { 420 struct pup_header *pup = mtod(m, struct pup_header *); 421 422 pupproto.sp_protocol = pup->pup_type; 423 pupdst.spup_addr = pup->pup_dport; 424 pupsrc.spup_addr = pup->pup_sport; 425 raw_input(m, &pupproto, (struct sockaddr *)&pupdst, 426 (struct sockaddr *)&pupsrc); 427 goto setup; 428 } 429 #endif 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; 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 >> 24; 469 off = ntohs((u_short)mtod(m, struct ip *)->ip_len) - m->m_len; 470 if (off > 0 && (off & 0x1ff) == 0 && 471 m->m_off >= MMINOFF + sizeof (u_short)) { 472 type = ENPUP_TRAIL + (off>>9); 473 m->m_off -= sizeof (u_short); 474 m->m_len += sizeof (u_short); 475 *mtod(m, u_short *) = ENPUP_IPTYPE; 476 goto gottrailertype; 477 } 478 type = ENPUP_IPTYPE; 479 off = 0; 480 goto gottype; 481 #endif 482 #ifdef PUP 483 case AF_PUP: 484 dest = ((struct sockaddr_pup *)dst)->spup_addr.pp_host; 485 off = mtod(m, struct pup_header *)->pup_length - m->m_len; 486 if (off > 0 && (off & 0x1ff) == 0 && 487 m->m_off >= MMINOFF + sizeof (u_short)) { 488 type = ENPUP_TRAIL + (off>>9); 489 m->m_off -= sizeof (u_short); 490 m->m_len += sizeof (u_short); 491 *mtod(m, u_short *) = ENPUP_PUPTYPE; 492 goto gottrailertype; 493 } 494 type = ENPUP_PUPTYPE; 495 off = 0; 496 goto gottype; 497 #endif 498 499 default: 500 printf("en%d: can't handle af%d\n", ifp->if_unit, 501 dst->sa_family); 502 m_freem(m0); 503 return (0); 504 } 505 506 gottrailertype: 507 /* 508 * Packet to be sent as trailer: move first packet 509 * (control information) to end of chain. 510 */ 511 while (m->m_next) 512 m = m->m_next; 513 m->m_next = m0; 514 m = m0->m_next; 515 m0->m_next = 0; 516 m0 = m; 517 518 gottype: 519 /* 520 * Add local net header. If no space in first mbuf, 521 * allocate another. 522 */ 523 if (m->m_off > MMAXOFF || 524 MMINOFF + sizeof (struct en_header) > m->m_off) { 525 m = m_get(M_DONTWAIT); 526 if (m == 0) { 527 m_freem(m0); 528 return (0); 529 } 530 m->m_next = m0; 531 m->m_off = MMINOFF; 532 m->m_len = sizeof (struct en_header); 533 } else { 534 m->m_off -= sizeof (struct en_header); 535 m->m_len += sizeof (struct en_header); 536 } 537 en = mtod(m, struct en_header *); 538 en->en_shost = ifp->if_host[0]; 539 en->en_dhost = dest; 540 en->en_type = type; 541 542 /* 543 * Queue message on interface, and start output if interface 544 * not yet active. 545 */ 546 s = splimp(); 547 if (IF_QFULL(&ifp->if_snd)) { 548 IF_DROP(&ifp->if_snd); 549 m_freem(m); 550 splx(s); 551 return (0); 552 } 553 IF_ENQUEUE(&ifp->if_snd, m); 554 if (en_softc[ifp->if_unit].es_oactive == 0) 555 enstart(ifp->if_unit); 556 splx(s); 557 return (1); 558 } 559