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