1*12349Ssam /* if_en.c 4.76 83/05/10 */ 24686Swnj 34686Swnj #include "en.h" 45105Swnj 54686Swnj /* 65105Swnj * Xerox prototype (3 Mb) Ethernet interface driver. 74686Swnj */ 89796Ssam #include "../machine/pte.h" 94686Swnj 104686Swnj #include "../h/param.h" 114686Swnj #include "../h/systm.h" 124686Swnj #include "../h/mbuf.h" 134686Swnj #include "../h/buf.h" 145083Swnj #include "../h/protosw.h" 155083Swnj #include "../h/socket.h" 165083Swnj #include "../h/vmmac.h" 178462Sroot #include <errno.h> 188462Sroot 198462Sroot #include "../net/if.h" 208462Sroot #include "../net/netisr.h" 218462Sroot #include "../net/route.h" 228418Swnj #include "../netinet/in.h" 238418Swnj #include "../netinet/in_systm.h" 248418Swnj #include "../netinet/ip.h" 258418Swnj #include "../netinet/ip_var.h" 268418Swnj #include "../netpup/pup.h" 274686Swnj 288462Sroot #include "../vax/cpu.h" 298462Sroot #include "../vax/mtpr.h" 308462Sroot #include "../vaxif/if_en.h" 318462Sroot #include "../vaxif/if_enreg.h" 328462Sroot #include "../vaxif/if_uba.h" 338462Sroot #include "../vaxuba/ubareg.h" 348462Sroot #include "../vaxuba/ubavar.h" 358462Sroot 365213Swnj #define ENMTU (1024+512) 376925Swnj #define ENMRU (1024+512+16) /* 16 is enough to receive trailer */ 385083Swnj 394686Swnj int enprobe(), enattach(), enrint(), enxint(), encollide(); 404686Swnj struct uba_device *eninfo[NEN]; 414686Swnj u_short enstd[] = { 0 }; 424686Swnj struct uba_driver endriver = 435171Swnj { enprobe, 0, enattach, 0, enstd, "en", eninfo }; 444686Swnj #define ENUNIT(x) minor(x) 454686Swnj 465105Swnj int eninit(),enoutput(),enreset(); 475105Swnj 485105Swnj /* 495105Swnj * Ethernet software status per interface. 505105Swnj * 515105Swnj * Each interface is referenced by a network interface structure, 525105Swnj * es_if, which the routing code uses to locate the interface. 535105Swnj * This structure contains the output queue for the interface, its address, ... 545105Swnj * We also have, for each interface, a UBA interface structure, which 555105Swnj * contains information about the UNIBUS resources held by the interface: 565105Swnj * map registers, buffered data paths, etc. Information is cached in this 575105Swnj * structure for use by the if_uba.c routines in running the interface 585105Swnj * efficiently. 595105Swnj */ 605083Swnj struct en_softc { 615105Swnj struct ifnet es_if; /* network-visible interface */ 625105Swnj struct ifuba es_ifuba; /* UNIBUS resources */ 635105Swnj short es_delay; /* current output delay */ 645105Swnj short es_mask; /* mask for current output delay */ 656471Sroot short es_lastx; /* host last transmitted to */ 665105Swnj short es_oactive; /* is output active? */ 675105Swnj short es_olen; /* length of last output */ 685083Swnj } en_softc[NEN]; 694686Swnj 705105Swnj /* 715105Swnj * Do output DMA to determine interface presence and 725105Swnj * interrupt vector. DMA is too short to disturb other hosts. 735105Swnj */ 744686Swnj enprobe(reg) 754686Swnj caddr_t reg; 764686Swnj { 775171Swnj register int br, cvec; /* r11, r10 value-result */ 784686Swnj register struct endevice *addr = (struct endevice *)reg; 794686Swnj 804686Swnj #ifdef lint 814686Swnj br = 0; cvec = br; br = cvec; 824922Swnj enrint(0); enxint(0); encollide(0); 834686Swnj #endif 844686Swnj addr->en_istat = 0; 854686Swnj addr->en_owc = -1; 864686Swnj addr->en_oba = 0; 874771Swnj addr->en_ostat = EN_IEN|EN_GO; 884686Swnj DELAY(100000); 894686Swnj addr->en_ostat = 0; 906575Ssam #ifdef ECHACK 916575Ssam br = 0x16; 926575Ssam #endif 934686Swnj return (1); 944686Swnj } 954686Swnj 965105Swnj /* 975105Swnj * Interface exists: make available by filling in network interface 985105Swnj * record. System will initialize the interface when it is ready 995105Swnj * to accept packets. 1005105Swnj */ 1014686Swnj enattach(ui) 1024686Swnj struct uba_device *ui; 1034686Swnj { 1045105Swnj register struct en_softc *es = &en_softc[ui->ui_unit]; 1054688Swnj 1065105Swnj es->es_if.if_unit = ui->ui_unit; 1075171Swnj es->es_if.if_name = "en"; 1085105Swnj es->es_if.if_mtu = ENMTU; 109*12349Ssam if (ui->ui_flags) 110*12349Ssam ensetaddr(es, ui->ui_flags); 1115171Swnj es->es_if.if_init = eninit; 1125105Swnj es->es_if.if_output = enoutput; 1138978Sroot es->es_if.if_reset = enreset; 1146554Ssam es->es_ifuba.ifu_flags = UBA_NEEDBDP | UBA_NEED16 | UBA_CANTWAIT; 1159271Ssam #if defined(VAX750) 1169271Ssam /* don't chew up 750 bdp's */ 1179271Ssam if (cpu == VAX_750 && ui->ui_unit > 0) 1189271Ssam es->es_ifuba.ifu_flags &= ~UBA_NEEDBDP; 1199271Ssam #endif 1205160Swnj if_attach(&es->es_if); 1214686Swnj } 1224686Swnj 1235105Swnj /* 124*12349Ssam * Set interface's Internet address 125*12349Ssam * given the network number. The station 126*12349Ssam * number, taken from the on-board register, 127*12349Ssam * is used as the local part. 128*12349Ssam */ 129*12349Ssam ensetaddr(es, net) 130*12349Ssam register struct en_softc *es; 131*12349Ssam int net; 132*12349Ssam { 133*12349Ssam struct endevice *enaddr; 134*12349Ssam register struct sockaddr_in *sin; 135*12349Ssam 136*12349Ssam es->es_if.if_net = net; 137*12349Ssam enaddr = (struct endevice *)eninfo[es->es_if.if_unit]->ui_addr; 138*12349Ssam es->es_if.if_host[0] = (~enaddr->en_addr) & 0xff; 139*12349Ssam sin = (struct sockaddr_in *)&es->es_if.if_addr; 140*12349Ssam sin->sin_family = AF_INET; 141*12349Ssam sin->sin_addr = if_makeaddr(net, es->es_if.if_host[0]); 142*12349Ssam sin = (struct sockaddr_in *)&es->es_if.if_broadaddr; 143*12349Ssam sin->sin_family = AF_INET; 144*12349Ssam sin->sin_addr = if_makeaddr(net, INADDR_ANY); 145*12349Ssam es->es_if.if_flags |= IFF_BROADCAST; 146*12349Ssam } 147*12349Ssam 148*12349Ssam /* 1495105Swnj * Reset of interface after UNIBUS reset. 1505105Swnj * If interface is on specified uba, reset its state. 1515105Swnj */ 1525105Swnj enreset(unit, uban) 1535105Swnj int unit, uban; 1545105Swnj { 1555105Swnj register struct uba_device *ui; 1565105Swnj 1575171Swnj if (unit >= NEN || (ui = eninfo[unit]) == 0 || ui->ui_alive == 0 || 1585171Swnj ui->ui_ubanum != uban) 1595105Swnj return; 1605171Swnj printf(" en%d", unit); 1615105Swnj eninit(unit); 1625105Swnj } 1635105Swnj 1645105Swnj /* 1655105Swnj * Initialization of interface; clear recorded pending 1665105Swnj * operations, and reinitialize UNIBUS usage. 1675105Swnj */ 1684688Swnj eninit(unit) 1694686Swnj int unit; 1705083Swnj { 1715171Swnj register struct en_softc *es = &en_softc[unit]; 1725171Swnj register struct uba_device *ui = eninfo[unit]; 1734686Swnj register struct endevice *addr; 174*12349Ssam struct sockaddr_in *sin = (struct sockaddr_in *)&es->es_if.if_addr; 175*12349Ssam int net, s; 1764686Swnj 177*12349Ssam net = in_netof(sin->sin_addr); 178*12349Ssam if (net == 0) 179*12349Ssam return; 180*12349Ssam ensetaddr(es, net); 181*12349Ssam #ifdef notdef 182*12349Ssam if (es->es_if.if_flags & IFF_UP) 183*12349Ssam return; 184*12349Ssam #endif 1855105Swnj if (if_ubainit(&es->es_ifuba, ui->ui_ubanum, 1866925Swnj sizeof (struct en_header), (int)btoc(ENMRU)) == 0) { 1875171Swnj printf("en%d: can't initialize\n", unit); 1886335Ssam es->es_if.if_flags &= ~IFF_UP; 1895083Swnj return; 1904686Swnj } 1914686Swnj addr = (struct endevice *)ui->ui_addr; 1925083Swnj addr->en_istat = addr->en_ostat = 0; 1934686Swnj 1945105Swnj /* 1955171Swnj * Hang a receive and start any 1965171Swnj * pending writes by faking a transmit complete. 1975105Swnj */ 1985105Swnj s = splimp(); 1995171Swnj addr->en_iba = es->es_ifuba.ifu_r.ifrw_info; 2006925Swnj addr->en_iwc = -(sizeof (struct en_header) + ENMRU) >> 1; 2015171Swnj addr->en_istat = EN_IEN|EN_GO; 2025171Swnj es->es_oactive = 1; 2036335Ssam es->es_if.if_flags |= IFF_UP; 2045105Swnj enxint(unit); 2055105Swnj splx(s); 2067151Swnj if_rtinit(&es->es_if, RTF_UP); 2074686Swnj } 2084686Swnj 2096471Sroot int enalldelay = 0; 2106951Swnj int enlastdel = 50; 2116471Sroot int enlastmask = (~0) << 5; 2125083Swnj 2135105Swnj /* 2145105Swnj * Start or restart output on interface. 2155105Swnj * If interface is already active, then this is a retransmit 2165105Swnj * after a collision, and just restuff registers and delay. 2175105Swnj * If interface is not already active, get another datagram 2185105Swnj * to send off of the interface queue, and map it to the interface 2195105Swnj * before starting the output. 2205105Swnj */ 2214688Swnj enstart(dev) 2224686Swnj dev_t dev; 2234686Swnj { 2245171Swnj int unit = ENUNIT(dev); 2255171Swnj struct uba_device *ui = eninfo[unit]; 2265171Swnj register struct en_softc *es = &en_softc[unit]; 2275083Swnj register struct endevice *addr; 2285083Swnj struct mbuf *m; 2295083Swnj int dest; 2304686Swnj 2315083Swnj if (es->es_oactive) 2325083Swnj goto restart; 2335105Swnj 2345105Swnj /* 2355105Swnj * Not already active: dequeue another request 2365105Swnj * and map it to the UNIBUS. If no more requests, 2375105Swnj * just return. 2385105Swnj */ 2395105Swnj IF_DEQUEUE(&es->es_if.if_snd, m); 2405083Swnj if (m == 0) { 2415083Swnj es->es_oactive = 0; 2424686Swnj return; 2434686Swnj } 2445213Swnj dest = mtod(m, struct en_header *)->en_dhost; 2455105Swnj es->es_olen = if_wubaput(&es->es_ifuba, m); 2465105Swnj 2475105Swnj /* 2485105Swnj * Ethernet cannot take back-to-back packets (no 2496471Sroot * buffering in interface. To help avoid overrunning 2506471Sroot * receivers, enforce a small delay (about 1ms) in interface: 2516471Sroot * * between all packets when enalldelay 2526471Sroot * * whenever last packet was broadcast 2536471Sroot * * whenever this packet is to same host as last packet 2545105Swnj */ 2556471Sroot if (enalldelay || es->es_lastx == 0 || es->es_lastx == dest) { 2565083Swnj es->es_delay = enlastdel; 2576471Sroot es->es_mask = enlastmask; 2586471Sroot } 2596471Sroot es->es_lastx = dest; 2605105Swnj 2615083Swnj restart: 2625105Swnj /* 2635105Swnj * Have request mapped to UNIBUS for transmission. 2645105Swnj * Purge any stale data from this BDP, and start the otput. 2655105Swnj */ 2666335Ssam if (es->es_ifuba.ifu_flags & UBA_NEEDBDP) 2676335Ssam UBAPURGE(es->es_ifuba.ifu_uba, es->es_ifuba.ifu_w.ifrw_bdp); 2684686Swnj addr = (struct endevice *)ui->ui_addr; 2695160Swnj addr->en_oba = (int)es->es_ifuba.ifu_w.ifrw_info; 2705083Swnj addr->en_odelay = es->es_delay; 2715083Swnj addr->en_owc = -((es->es_olen + 1) >> 1); 2724771Swnj addr->en_ostat = EN_IEN|EN_GO; 2735083Swnj es->es_oactive = 1; 2744686Swnj } 2754686Swnj 2765105Swnj /* 2775105Swnj * Ethernet interface transmitter interrupt. 2785105Swnj * Start another output if more data to send. 2795105Swnj */ 2804686Swnj enxint(unit) 2814686Swnj int unit; 2824686Swnj { 2835171Swnj register struct uba_device *ui = eninfo[unit]; 2845171Swnj register struct en_softc *es = &en_softc[unit]; 2856242Sroot register struct endevice *addr = (struct endevice *)ui->ui_addr; 2864686Swnj 2875083Swnj if (es->es_oactive == 0) 2885083Swnj return; 2896242Sroot if (es->es_mask && (addr->en_ostat&EN_OERROR)) { 2906242Sroot es->es_if.if_oerrors++; 2916242Sroot endocoll(unit); 2926242Sroot return; 2936242Sroot } 2945171Swnj es->es_if.if_opackets++; 2955083Swnj es->es_oactive = 0; 2965083Swnj es->es_delay = 0; 2975083Swnj es->es_mask = ~0; 2985696Sroot if (es->es_ifuba.ifu_xtofree) { 2995696Sroot m_freem(es->es_ifuba.ifu_xtofree); 3005696Sroot es->es_ifuba.ifu_xtofree = 0; 3015696Sroot } 3025105Swnj if (es->es_if.if_snd.ifq_head == 0) { 3036471Sroot es->es_lastx = 256; /* putatively illegal */ 3044686Swnj return; 3054686Swnj } 3065083Swnj enstart(unit); 3074686Swnj } 3084686Swnj 3095105Swnj /* 3105105Swnj * Collision on ethernet interface. Do exponential 3115105Swnj * backoff, and retransmit. If have backed off all 3126335Ssam * the way print warning diagnostic, and drop packet. 3135105Swnj */ 3144686Swnj encollide(unit) 3154686Swnj int unit; 3164686Swnj { 3176242Sroot struct en_softc *es = &en_softc[unit]; 3184686Swnj 3195105Swnj es->es_if.if_collisions++; 3205083Swnj if (es->es_oactive == 0) 3214686Swnj return; 3226242Sroot endocoll(unit); 3236242Sroot } 3246242Sroot 3256242Sroot endocoll(unit) 3266242Sroot int unit; 3276242Sroot { 3286242Sroot register struct en_softc *es = &en_softc[unit]; 3296242Sroot 3305171Swnj /* 3315171Swnj * Es_mask is a 16 bit number with n low zero bits, with 3325171Swnj * n the number of backoffs. When es_mask is 0 we have 3335171Swnj * backed off 16 times, and give up. 3345171Swnj */ 3355083Swnj if (es->es_mask == 0) { 3365213Swnj printf("en%d: send error\n", unit); 3375083Swnj enxint(unit); 3385171Swnj return; 3394686Swnj } 3405171Swnj /* 3415171Swnj * Another backoff. Restart with delay based on n low bits 3425171Swnj * of the interval timer. 3435171Swnj */ 3445171Swnj es->es_mask <<= 1; 3455171Swnj es->es_delay = mfpr(ICR) &~ es->es_mask; 3465171Swnj enstart(unit); 3474686Swnj } 3484686Swnj 3496027Ssam struct sockaddr_pup pupsrc = { AF_PUP }; 3506027Ssam struct sockaddr_pup pupdst = { AF_PUP }; 3516027Ssam struct sockproto pupproto = { PF_PUP }; 3525105Swnj /* 3535105Swnj * Ethernet interface receiver interrupt. 3545105Swnj * If input error just drop packet. 3555105Swnj * Otherwise purge input buffered data path and examine 3565105Swnj * packet to determine type. If can't determine length 3575105Swnj * from type, then have to drop packet. Othewise decapsulate 3585105Swnj * packet based on type and pass to type specific higher-level 3595105Swnj * input routine. 3605105Swnj */ 3614686Swnj enrint(unit) 3624686Swnj int unit; 3634686Swnj { 3645171Swnj register struct en_softc *es = &en_softc[unit]; 3655171Swnj struct endevice *addr = (struct endevice *)eninfo[unit]->ui_addr; 3665171Swnj register struct en_header *en; 3675083Swnj struct mbuf *m; 3688603Sroot int len; short resid; 3695171Swnj register struct ifqueue *inq; 3705083Swnj int off; 3714686Swnj 3725171Swnj es->es_if.if_ipackets++; 3735105Swnj 3745105Swnj /* 3755171Swnj * Purge BDP; drop if input error indicated. 3765105Swnj */ 3776335Ssam if (es->es_ifuba.ifu_flags & UBA_NEEDBDP) 3786335Ssam UBAPURGE(es->es_ifuba.ifu_uba, es->es_ifuba.ifu_r.ifrw_bdp); 3794771Swnj if (addr->en_istat&EN_IERROR) { 3805105Swnj es->es_if.if_ierrors++; 3815083Swnj goto setup; 3824686Swnj } 3835105Swnj 3845105Swnj /* 3856471Sroot * Calculate input data length. 3865105Swnj * Get pointer to ethernet header (in input buffer). 3875105Swnj * Deal with trailer protocol: if type is PUP trailer 3885105Swnj * get true type from first 16-bit word past data. 3895105Swnj * Remember that type was trailer by setting off. 3905105Swnj */ 3916471Sroot resid = addr->en_iwc; 3926471Sroot if (resid) 3936471Sroot resid |= 0176000; 3946925Swnj len = (((sizeof (struct en_header) + ENMRU) >> 1) + resid) << 1; 3956471Sroot len -= sizeof (struct en_header); 3966925Swnj if (len > ENMRU) 3976471Sroot goto setup; /* sanity */ 3985105Swnj en = (struct en_header *)(es->es_ifuba.ifu_r.ifrw_addr); 3995083Swnj #define endataaddr(en, off, type) ((type)(((caddr_t)((en)+1)+(off)))) 4005083Swnj if (en->en_type >= ENPUP_TRAIL && 4015083Swnj en->en_type < ENPUP_TRAIL+ENPUP_NTRAILER) { 4025083Swnj off = (en->en_type - ENPUP_TRAIL) * 512; 4036925Swnj if (off > ENMTU) 4045171Swnj goto setup; /* sanity */ 4055083Swnj en->en_type = *endataaddr(en, off, u_short *); 4066471Sroot resid = *(endataaddr(en, off+2, u_short *)); 4076471Sroot if (off + resid > len) 4086471Sroot goto setup; /* sanity */ 4096471Sroot len = off + resid; 4105083Swnj } else 4115083Swnj off = 0; 4125083Swnj if (len == 0) 4135083Swnj goto setup; 4145105Swnj /* 4155105Swnj * Pull packet off interface. Off is nonzero if packet 4165105Swnj * has trailing header; if_rubaget will then force this header 4175105Swnj * information to be at the front, but we still have to drop 4186471Sroot * the type and length which are at the front of any trailer data. 4195105Swnj */ 4205105Swnj m = if_rubaget(&es->es_ifuba, len, off); 4215213Swnj if (m == 0) 4225213Swnj goto setup; 4235105Swnj if (off) { 4246471Sroot m->m_off += 2 * sizeof (u_short); 4256471Sroot m->m_len -= 2 * sizeof (u_short); 4265105Swnj } 4276027Ssam switch (en->en_type) { 4286027Ssam 4296027Ssam #ifdef INET 4306027Ssam case ENPUP_IPTYPE: 4316260Swnj schednetisr(NETISR_IP); 4326027Ssam inq = &ipintrq; 4336027Ssam break; 4346027Ssam #endif 4356335Ssam #ifdef PUP 4366027Ssam case ENPUP_PUPTYPE: { 4376027Ssam struct pup_header *pup = mtod(m, struct pup_header *); 4386027Ssam 4396027Ssam pupproto.sp_protocol = pup->pup_type; 4406027Ssam pupdst.spup_addr = pup->pup_dport; 4416027Ssam pupsrc.spup_addr = pup->pup_sport; 4426526Ssam raw_input(m, &pupproto, (struct sockaddr *)&pupsrc, 4436526Ssam (struct sockaddr *)&pupdst); 4446027Ssam goto setup; 4456027Ssam } 4466335Ssam #endif 4476476Swnj default: 4486476Swnj m_freem(m); 4496476Swnj goto setup; 4506335Ssam } 4516335Ssam 4526207Swnj if (IF_QFULL(inq)) { 4536207Swnj IF_DROP(inq); 4546335Ssam m_freem(m); 4556207Swnj } else 4566207Swnj IF_ENQUEUE(inq, m); 4575105Swnj 4584688Swnj setup: 4595105Swnj /* 4605105Swnj * Reset for next packet. 4615105Swnj */ 4625105Swnj addr->en_iba = es->es_ifuba.ifu_r.ifrw_info; 4636925Swnj addr->en_iwc = -(sizeof (struct en_header) + ENMRU) >> 1; 4644771Swnj addr->en_istat = EN_IEN|EN_GO; 4654688Swnj } 4664686Swnj 4675083Swnj /* 4685083Swnj * Ethernet output routine. 4695083Swnj * Encapsulate a packet of type family for the local net. 4705105Swnj * Use trailer local net encapsulation if enough data in first 4715105Swnj * packet leaves a multiple of 512 bytes of data in remainder. 4725083Swnj */ 4736335Ssam enoutput(ifp, m0, dst) 4745083Swnj struct ifnet *ifp; 4755083Swnj struct mbuf *m0; 4766335Ssam struct sockaddr *dst; 4774686Swnj { 4786503Ssam int type, dest, s, error; 4795105Swnj register struct mbuf *m = m0; 4805083Swnj register struct en_header *en; 4816335Ssam register int off; 4824686Swnj 4836335Ssam switch (dst->sa_family) { 4845083Swnj 4855083Swnj #ifdef INET 4866335Ssam case AF_INET: 4876484Swnj dest = ((struct sockaddr_in *)dst)->sin_addr.s_addr; 4889178Ssam if (in_lnaof(*((struct in_addr *)&dest)) >= 0x100) { 4896503Ssam error = EPERM; /* ??? */ 4906486Swnj goto bad; 4916503Ssam } 4926484Swnj dest = (dest >> 24) & 0xff; 4936335Ssam off = ntohs((u_short)mtod(m, struct ip *)->ip_len) - m->m_len; 4946335Ssam if (off > 0 && (off & 0x1ff) == 0 && 4956471Sroot m->m_off >= MMINOFF + 2 * sizeof (u_short)) { 4965083Swnj type = ENPUP_TRAIL + (off>>9); 4976471Sroot m->m_off -= 2 * sizeof (u_short); 4986471Sroot m->m_len += 2 * sizeof (u_short); 4995105Swnj *mtod(m, u_short *) = ENPUP_IPTYPE; 5006471Sroot *(mtod(m, u_short *) + 1) = m->m_len; 5015105Swnj goto gottrailertype; 5025083Swnj } 5035105Swnj type = ENPUP_IPTYPE; 5045105Swnj off = 0; 5055105Swnj goto gottype; 5065083Swnj #endif 5076027Ssam #ifdef PUP 5086335Ssam case AF_PUP: 5096335Ssam dest = ((struct sockaddr_pup *)dst)->spup_addr.pp_host; 5106027Ssam type = ENPUP_PUPTYPE; 5116027Ssam off = 0; 5126027Ssam goto gottype; 5136027Ssam #endif 5146027Ssam 5155083Swnj default: 5166335Ssam printf("en%d: can't handle af%d\n", ifp->if_unit, 5176335Ssam dst->sa_family); 5186503Ssam error = EAFNOSUPPORT; 5196503Ssam goto bad; 5204686Swnj } 5215105Swnj 5225171Swnj gottrailertype: 5235105Swnj /* 5245105Swnj * Packet to be sent as trailer: move first packet 5255105Swnj * (control information) to end of chain. 5265105Swnj */ 5275105Swnj while (m->m_next) 5285105Swnj m = m->m_next; 5295105Swnj m->m_next = m0; 5305105Swnj m = m0->m_next; 5315105Swnj m0->m_next = 0; 5325171Swnj m0 = m; 5335105Swnj 5345171Swnj gottype: 5355105Swnj /* 5365105Swnj * Add local net header. If no space in first mbuf, 5375105Swnj * allocate another. 5385105Swnj */ 5395213Swnj if (m->m_off > MMAXOFF || 5405213Swnj MMINOFF + sizeof (struct en_header) > m->m_off) { 5419649Ssam m = m_get(M_DONTWAIT, MT_HEADER); 5425083Swnj if (m == 0) { 5436503Ssam error = ENOBUFS; 5446503Ssam goto bad; 5455083Swnj } 5465083Swnj m->m_next = m0; 5475083Swnj m->m_off = MMINOFF; 5485083Swnj m->m_len = sizeof (struct en_header); 5495083Swnj } else { 5505083Swnj m->m_off -= sizeof (struct en_header); 5515083Swnj m->m_len += sizeof (struct en_header); 5525083Swnj } 5535083Swnj en = mtod(m, struct en_header *); 5545083Swnj en->en_shost = ifp->if_host[0]; 5555083Swnj en->en_dhost = dest; 5565083Swnj en->en_type = type; 5575105Swnj 5585105Swnj /* 5595105Swnj * Queue message on interface, and start output if interface 5605105Swnj * not yet active. 5615105Swnj */ 5625083Swnj s = splimp(); 5636207Swnj if (IF_QFULL(&ifp->if_snd)) { 5646207Swnj IF_DROP(&ifp->if_snd); 5656503Ssam error = ENOBUFS; 5666503Ssam goto qfull; 5676207Swnj } 5685083Swnj IF_ENQUEUE(&ifp->if_snd, m); 5695083Swnj if (en_softc[ifp->if_unit].es_oactive == 0) 5705083Swnj enstart(ifp->if_unit); 5715275Swnj splx(s); 5726503Ssam return (0); 5736503Ssam qfull: 5746503Ssam m0 = m; 5756503Ssam splx(s); 5766484Swnj bad: 5776503Ssam m_freem(m0); 5786503Ssam return (error); 5794686Swnj } 580