1*7152Swnj /* if_il.c 4.5 82/06/12 */ 26893Sfeldman 36893Sfeldman #include "il.h" 46893Sfeldman #include "imp.h" 56893Sfeldman #include "loop.h" 66893Sfeldman 76893Sfeldman /* 86893Sfeldman * Interlan Ethernet Communications Controller interface 96893Sfeldman */ 106893Sfeldman 116893Sfeldman #include "../h/param.h" 126893Sfeldman #include "../h/systm.h" 136893Sfeldman #include "../h/mbuf.h" 146893Sfeldman #include "../h/pte.h" 156893Sfeldman #include "../h/buf.h" 166893Sfeldman #include "../h/protosw.h" 176893Sfeldman #include "../h/socket.h" 186893Sfeldman #include "../h/ubareg.h" 196893Sfeldman #include "../h/ubavar.h" 206893Sfeldman #include "../h/ilreg.h" 216893Sfeldman #include "../h/cpu.h" 226893Sfeldman #include "../h/mtpr.h" 236893Sfeldman #include "../h/vmmac.h" 246893Sfeldman #include "../net/in.h" 256893Sfeldman #include "../net/in_systm.h" 266893Sfeldman #include "../net/if.h" 276893Sfeldman #include "../net/if_il.h" 286893Sfeldman #include "../net/if_uba.h" 296893Sfeldman #include "../net/ip.h" 306893Sfeldman #include "../net/ip_var.h" 316893Sfeldman #include "../net/pup.h" 326893Sfeldman #include "../net/route.h" 336893Sfeldman #include <errno.h> 346893Sfeldman 356893Sfeldman #define ILMTU 1500 366893Sfeldman 376893Sfeldman int ilprobe(), ilattach(), ilrint(), ilcint(); 386893Sfeldman struct uba_device *ilinfo[NIL]; 396893Sfeldman u_short ilstd[] = { 0 }; 406893Sfeldman struct uba_driver ildriver = 416893Sfeldman { ilprobe, 0, ilattach, 0, ilstd, "il", ilinfo }; 426893Sfeldman u_char il_ectop[3] = { 0x02, 0x60, 0x8c }; 436893Sfeldman #define ILUNIT(x) minor(x) 446893Sfeldman 456893Sfeldman int ilinit(),iloutput(),ilreset(); 466893Sfeldman 476893Sfeldman /* 486893Sfeldman * Ethernet software status per interface. 496893Sfeldman * 506893Sfeldman * Each interface is referenced by a network interface structure, 516893Sfeldman * is_if, which the routing code uses to locate the interface. 526893Sfeldman * This structure contains the output queue for the interface, its address, ... 536893Sfeldman * We also have, for each interface, a UBA interface structure, which 546893Sfeldman * contains information about the UNIBUS resources held by the interface: 556893Sfeldman * map registers, buffered data paths, etc. Information is cached in this 566893Sfeldman * structure for use by the if_uba.c routines in running the interface 576893Sfeldman * efficiently. 586893Sfeldman */ 596893Sfeldman struct il_softc { 606893Sfeldman struct ifnet is_if; /* network-visible interface */ 616893Sfeldman struct ifuba is_ifuba; /* UNIBUS resources */ 626893Sfeldman short is_oactive; /* is output active? */ 636893Sfeldman short is_startrcv; /* hang receive next chance */ 646893Sfeldman u_char is_enaddr[6]; /* board's ethernet address */ 656893Sfeldman } il_softc[NIL]; 666893Sfeldman 676893Sfeldman /* 686893Sfeldman * Do an OFFLINE command. This will cause an interrupt for the 696893Sfeldman * autoconfigure stuff. 706893Sfeldman */ 716893Sfeldman ilprobe(reg) 726893Sfeldman caddr_t reg; 736893Sfeldman { 746893Sfeldman register int br, cvec; /* r11, r10 value-result */ 756893Sfeldman register struct ildevice *addr = (struct ildevice *)reg; 766893Sfeldman register i; 776893Sfeldman 786893Sfeldman COUNT(ILPROBE); 796893Sfeldman #ifdef lint 806893Sfeldman br = 0; cvec = br; br = cvec; 816893Sfeldman ilrint(0); ilcint(0); 826893Sfeldman #endif 836893Sfeldman 846893Sfeldman addr->il_csr = ILC_OFFLINE|IL_CIE; 856893Sfeldman DELAY(100000); 866893Sfeldman i = addr->il_csr; /* Clear CDONE */ 876893Sfeldman if (cvec > 0 && cvec != 0x200) 886893Sfeldman cvec -= 4; 896893Sfeldman return (1); 906893Sfeldman } 916893Sfeldman 926893Sfeldman struct il_stat ilbuf; 936893Sfeldman /* 946893Sfeldman * Interface exists: make available by filling in network interface 956893Sfeldman * record. System will initialize the interface when it is ready 966893Sfeldman * to accept packets. A STATUS command is done to get the ethernet 976893Sfeldman * address and other interesting data. 986893Sfeldman */ 996893Sfeldman ilattach(ui) 1006893Sfeldman struct uba_device *ui; 1016893Sfeldman { 1026893Sfeldman register struct il_softc *is = &il_softc[ui->ui_unit]; 1036893Sfeldman register struct sockaddr_in *sin; 1046893Sfeldman register struct ildevice *addr = (struct ildevice *)ui->ui_addr; 1056893Sfeldman register int i; 1066893Sfeldman int s; 1076893Sfeldman int ubaddr; 1086893Sfeldman COUNT(ILATTACH); 1096893Sfeldman 1106893Sfeldman is->is_if.if_unit = ui->ui_unit; 1116893Sfeldman is->is_if.if_name = "il"; 1126893Sfeldman is->is_if.if_mtu = ILMTU; 1136893Sfeldman is->is_if.if_net = ui->ui_flags & 0xff; 1146893Sfeldman 1156893Sfeldman /* 1166893Sfeldman * Reset the board 1176893Sfeldman */ 1186893Sfeldman s = splimp(); 1196893Sfeldman addr->il_csr = ((ubaddr>>2)&0xc000)|ILC_RESET; 1206893Sfeldman while (!(addr->il_csr & IL_CDONE)) 1216893Sfeldman /* Busy wait */; 1226893Sfeldman if (addr->il_csr & IL_STATUS) 1236893Sfeldman printf("il%d: %s\n", ui->ui_unit, 1246893Sfeldman ildiag[addr->il_csr & IL_STATUS]); 1256893Sfeldman splx(s); 1266893Sfeldman 1276893Sfeldman /* 1286893Sfeldman * Map the status buffer to the Unibus, do the status command, 1296893Sfeldman * and unmap the buffer. 1306893Sfeldman */ 1316893Sfeldman ubaddr = uballoc(ui->ui_ubanum, &ilbuf, sizeof(ilbuf), 0); 1326893Sfeldman s = splimp(); 1336893Sfeldman addr->il_bar = ubaddr & 0xffff; 1346893Sfeldman addr->il_bcr = sizeof(ilbuf); 1356893Sfeldman addr->il_csr = ((ubaddr>>2)&0xc000)|ILC_STAT; 1366893Sfeldman while (!(addr->il_csr & IL_CDONE)) 1376893Sfeldman /* Busy wait */; 1386893Sfeldman if (addr->il_csr & IL_STATUS) 1396893Sfeldman printf("il%d: %s\n", ui->ui_unit, 1406893Sfeldman ilerrs[addr->il_csr & IL_STATUS]); 1416893Sfeldman splx(s); 1426893Sfeldman ubarelse(ui->ui_ubanum, &ubaddr); 1436893Sfeldman /* 1446893Sfeldman * Fill in the Ethernet address from the status buffer 1456893Sfeldman */ 1466893Sfeldman for (i=0; i<6; i++) 1476893Sfeldman is->is_enaddr[i] = ilbuf.ils_addr[i]; 1486893Sfeldman printf("il%d: addr=%x:%x:%x:%x:%x:%x module=%s firmware=%s\n", 1496893Sfeldman ui->ui_unit, 1506893Sfeldman is->is_enaddr[0]&0xff, is->is_enaddr[1]&0xff, 1516893Sfeldman is->is_enaddr[2]&0xff, is->is_enaddr[3]&0xff, 1526893Sfeldman is->is_enaddr[4]&0xff, is->is_enaddr[5]&0xff, 1536893Sfeldman ilbuf.ils_module, ilbuf.ils_firmware); 1546893Sfeldman is->is_if.if_host[0] = ((is->is_enaddr[3]&0xff)<<16) | 0x800000 | 1556893Sfeldman ((is->is_enaddr[4]&0xff)<<8) | (is->is_enaddr[5]&0xff); 1566893Sfeldman sin = (struct sockaddr_in *)&is->is_if.if_addr; 1576893Sfeldman sin->sin_family = AF_INET; 1586893Sfeldman sin->sin_addr = if_makeaddr(is->is_if.if_net, is->is_if.if_host[0]); 1596893Sfeldman 1606893Sfeldman sin = (struct sockaddr_in *)&is->is_if.if_broadaddr; 1616893Sfeldman sin->sin_family = AF_INET; 1626893Sfeldman sin->sin_addr = if_makeaddr(is->is_if.if_net, 0); 1636893Sfeldman is->is_if.if_flags = IFF_BROADCAST; 1646893Sfeldman 1656893Sfeldman is->is_if.if_init = ilinit; 1666893Sfeldman is->is_if.if_output = iloutput; 1676893Sfeldman is->is_if.if_ubareset = ilreset; 1686893Sfeldman is->is_ifuba.ifu_flags = UBA_CANTWAIT; 1696893Sfeldman if_attach(&is->is_if); 1706893Sfeldman #if NIMP == 0 1716893Sfeldman if (ui->ui_flags &~ 0xff) 1726926Swnj illhinit(&is->is_if, (ui->ui_flags &~ 0xff) | 0x0a); 1736893Sfeldman #endif 1746893Sfeldman } 1756893Sfeldman 1766893Sfeldman /* 1776893Sfeldman * Reset of interface after UNIBUS reset. 1786893Sfeldman * If interface is on specified uba, reset its state. 1796893Sfeldman */ 1806893Sfeldman ilreset(unit, uban) 1816893Sfeldman int unit, uban; 1826893Sfeldman { 1836893Sfeldman register struct uba_device *ui; 1846893Sfeldman COUNT(ILRESET); 1856893Sfeldman 1866893Sfeldman if (unit >= NIL || (ui = ilinfo[unit]) == 0 || ui->ui_alive == 0 || 1876893Sfeldman ui->ui_ubanum != uban) 1886893Sfeldman return; 1896893Sfeldman printf(" il%d", unit); 1906893Sfeldman ilinit(unit); 1916893Sfeldman } 1926893Sfeldman 1936893Sfeldman /* 1946893Sfeldman * Initialization of interface; clear recorded pending 1956893Sfeldman * operations, and reinitialize UNIBUS usage. 1966893Sfeldman */ 1976893Sfeldman ilinit(unit) 1986893Sfeldman int unit; 1996893Sfeldman { 2006893Sfeldman register struct il_softc *is = &il_softc[unit]; 2016893Sfeldman register struct uba_device *ui = ilinfo[unit]; 2026893Sfeldman register struct ildevice *addr; 2036893Sfeldman register i; 2046893Sfeldman int s; 2056893Sfeldman 2066893Sfeldman if (if_ubainit(&is->is_ifuba, ui->ui_ubanum, 2076893Sfeldman sizeof (struct il_rheader), (int)btoc(ILMTU)) == 0) { 2086893Sfeldman printf("il%d: can't initialize\n", unit); 2096893Sfeldman is->is_if.if_flags &= ~IFF_UP; 2106893Sfeldman return; 2116893Sfeldman } 2126893Sfeldman addr = (struct ildevice *)ui->ui_addr; 2136893Sfeldman 2146893Sfeldman /* 2156893Sfeldman * Set board online. 2166893Sfeldman * Hang receive buffer and start any pending 2176893Sfeldman * writes by faking a transmit complete. 2186893Sfeldman * Receive bcr is not a muliple of 4 so buffer 2196893Sfeldman * chaining can't happen. 2206893Sfeldman */ 2216893Sfeldman s = splimp(); 2226893Sfeldman addr->il_csr = ILC_ONLINE; 2236893Sfeldman while (!(addr->il_csr & IL_CDONE)) 2246893Sfeldman /* Busy wait */; 2256893Sfeldman addr->il_bar = is->is_ifuba.ifu_r.ifrw_info & 0xffff; 2266893Sfeldman addr->il_bcr = sizeof(struct il_rheader) + ILMTU + 6; 2276893Sfeldman addr->il_csr = ((is->is_ifuba.ifu_r.ifrw_info>>2)&0xc000)| 2286893Sfeldman ILC_RCV|IL_RIE; 2296893Sfeldman while (!(addr->il_csr & IL_CDONE)) 2306893Sfeldman /* Busy wait */; 2316893Sfeldman is->is_startrcv = 0; 2326893Sfeldman is->is_oactive = 1; 2336893Sfeldman is->is_if.if_flags |= IFF_UP; 2346893Sfeldman ilcint(unit); 2356893Sfeldman splx(s); 236*7152Swnj if_rtinit(&is->is_if, RTF_UP); 2376893Sfeldman } 2386893Sfeldman 2396893Sfeldman /* 2406893Sfeldman * Start output on interface. 2416893Sfeldman * Get another datagram to send off of the interface queue, 2426893Sfeldman * and map it to the interface before starting the output. 2436893Sfeldman */ 2446893Sfeldman ilstart(dev) 2456893Sfeldman dev_t dev; 2466893Sfeldman { 2476893Sfeldman int unit = ILUNIT(dev); 2486893Sfeldman struct uba_device *ui = ilinfo[unit]; 2496893Sfeldman register struct il_softc *is = &il_softc[unit]; 2506893Sfeldman register struct ildevice *addr; 2516893Sfeldman register len; 2526893Sfeldman struct mbuf *m; 2536893Sfeldman int dest; 2546893Sfeldman COUNT(ILSTART); 2556893Sfeldman 2566893Sfeldman /* 2576893Sfeldman * Dequeue another request and copy it into the buffer. 2586893Sfeldman * If no more requests, just return. 2596893Sfeldman */ 2606893Sfeldman IF_DEQUEUE(&is->is_if.if_snd, m); 2616893Sfeldman if (m == 0) 2626893Sfeldman return; 2636893Sfeldman len = if_wubaput(&is->is_ifuba, m); 2646893Sfeldman 2656893Sfeldman /* 2666893Sfeldman * Flush BDP, then start the output. 2676893Sfeldman */ 2686893Sfeldman if (is->is_ifuba.ifu_flags & UBA_NEEDBDP) 2696893Sfeldman UBAPURGE(is->is_ifuba.ifu_uba, is->is_ifuba.ifu_w.ifrw_bdp); 2706893Sfeldman addr = (struct ildevice *)ui->ui_addr; 2716893Sfeldman addr->il_bar = is->is_ifuba.ifu_w.ifrw_info & 0xffff; 2726893Sfeldman addr->il_bcr = len; 2736893Sfeldman addr->il_csr = ((is->is_ifuba.ifu_w.ifrw_info>>2)&0xc000)| 2746893Sfeldman ILC_XMIT|IL_CIE|IL_RIE; 2756893Sfeldman is->is_oactive = 1; 2766893Sfeldman } 2776893Sfeldman 2786893Sfeldman /* 2796893Sfeldman * Command done interrupt. 2806893Sfeldman * This should only happen after a transmit command, 2816893Sfeldman * so it is equivalent to a transmit interrupt. 2826893Sfeldman * Start another output if more data to send. 2836893Sfeldman */ 2846893Sfeldman ilcint(unit) 2856893Sfeldman int unit; 2866893Sfeldman { 2876893Sfeldman register struct uba_device *ui = ilinfo[unit]; 2886893Sfeldman register struct il_softc *is = &il_softc[unit]; 2896893Sfeldman register struct ildevice *addr = (struct ildevice *)ui->ui_addr; 2906893Sfeldman register int err; 2916893Sfeldman COUNT(ILCINT); 2926893Sfeldman 2936893Sfeldman if (is->is_oactive == 0) { 2946893Sfeldman printf("il%d: strange xmit interrupt!\n", unit); 2956893Sfeldman return; 2966893Sfeldman } 2976893Sfeldman is->is_if.if_opackets++; 2986893Sfeldman is->is_oactive = 0; 2996893Sfeldman if (err = (addr->il_csr & IL_STATUS)){ 3006893Sfeldman is->is_if.if_oerrors++; 3016893Sfeldman printf("il%d: output error %d\n", unit, err); 3026893Sfeldman } 3036893Sfeldman /* 3046893Sfeldman * Hang receive buffer if it couldn't be done earlier (in ilrint). 3056893Sfeldman */ 3066893Sfeldman if (is->is_startrcv) { 3076893Sfeldman addr->il_bar = is->is_ifuba.ifu_r.ifrw_info & 0xffff; 3086893Sfeldman addr->il_bcr = sizeof(struct il_rheader) + ILMTU + 6; 3096893Sfeldman addr->il_csr = ((is->is_ifuba.ifu_r.ifrw_info>>2)&0xc000)| 3106893Sfeldman ILC_RCV|IL_RIE; 3116893Sfeldman while (!(addr->il_csr & IL_CDONE)) 3126893Sfeldman /* Busy wait */; 3136893Sfeldman is->is_startrcv = 0; 3146893Sfeldman } 3156893Sfeldman if (is->is_ifuba.ifu_xtofree) { 3166893Sfeldman m_freem(is->is_ifuba.ifu_xtofree); 3176893Sfeldman is->is_ifuba.ifu_xtofree = 0; 3186893Sfeldman } 3196893Sfeldman if (is->is_if.if_snd.ifq_head == 0) { 3206893Sfeldman return; 3216893Sfeldman } 3226893Sfeldman ilstart(unit); 3236893Sfeldman } 3246893Sfeldman 3256893Sfeldman /* 3266893Sfeldman * Ethernet interface receiver interrupt. 3276893Sfeldman * If input error just drop packet. 3286893Sfeldman * Otherwise purge input buffered data path and examine 3296893Sfeldman * packet to determine type. If can't determine length 3306893Sfeldman * from type, then have to drop packet. Othewise decapsulate 3316893Sfeldman * packet based on type and pass to type specific higher-level 3326893Sfeldman * input routine. 3336893Sfeldman */ 3346893Sfeldman ilrint(unit) 3356893Sfeldman int unit; 3366893Sfeldman { 3376893Sfeldman register struct il_softc *is = &il_softc[unit]; 3386893Sfeldman struct ildevice *addr = (struct ildevice *)ilinfo[unit]->ui_addr; 3396893Sfeldman register struct il_rheader *il; 3406893Sfeldman struct mbuf *m; 3416893Sfeldman int len, off, resid; 3426893Sfeldman register struct ifqueue *inq; 3436893Sfeldman 3446893Sfeldman COUNT(ILRINT); 3456893Sfeldman is->is_if.if_ipackets++; 3466893Sfeldman if (is->is_ifuba.ifu_flags & UBA_NEEDBDP) 3476893Sfeldman UBAPURGE(is->is_ifuba.ifu_uba, is->is_ifuba.ifu_r.ifrw_bdp); 3486893Sfeldman il = (struct il_rheader *)(is->is_ifuba.ifu_r.ifrw_addr); 3496893Sfeldman len = il->ilr_length - sizeof(struct il_rheader); 3506893Sfeldman if (il->ilr_status&0x3 || len < 46 || len > ILMTU) { 3516893Sfeldman is->is_if.if_ierrors++; 3526893Sfeldman #ifdef notdef 3536893Sfeldman if (is->is_if.if_ierrors % 100 == 0) 3546893Sfeldman printf("il%d: += 100 input errors\n", unit); 3556893Sfeldman #endif 3566893Sfeldman printf("il%d: input error (status=%x, len=%d)\n", unit, 3576893Sfeldman il->ilr_status, len); 3586893Sfeldman goto setup; 3596893Sfeldman } 3606893Sfeldman 3616893Sfeldman /* 3626893Sfeldman * Deal with trailer protocol: if type is PUP trailer 3636893Sfeldman * get true type from first 16-bit word past data. 3646893Sfeldman * Remember that type was trailer by setting off. 3656893Sfeldman */ 3666893Sfeldman #define ildataaddr(il, off, type) ((type)(((caddr_t)((il)+1)+(off)))) 3676893Sfeldman if (il->ilr_type >= ILPUP_TRAIL && 3686893Sfeldman il->ilr_type < ILPUP_TRAIL+ILPUP_NTRAILER) { 3696893Sfeldman off = (il->ilr_type - ILPUP_TRAIL) * 512; 3706893Sfeldman if (off >= ILMTU) 3716893Sfeldman goto setup; /* sanity */ 3726893Sfeldman il->ilr_type = *ildataaddr(il, off, u_short *); 3736893Sfeldman resid = *(ildataaddr(il, off+2, u_short *)); 3746893Sfeldman if (off + resid > len) 3756893Sfeldman goto setup; /* sanity */ 3766893Sfeldman len = off + resid; 3776893Sfeldman } else 3786893Sfeldman off = 0; 3796893Sfeldman if (len == 0) 3806893Sfeldman goto setup; 3816893Sfeldman 3826893Sfeldman /* 3836893Sfeldman * Pull packet off interface. Off is nonzero if packet 3846893Sfeldman * has trailing header; ilget will then force this header 3856893Sfeldman * information to be at the front, but we still have to drop 3866893Sfeldman * the type and length which are at the front of any trailer data. 3876893Sfeldman */ 3886893Sfeldman m = if_rubaget(&is->is_ifuba, len, off); 3896893Sfeldman if (m == 0) 3906893Sfeldman goto setup; 3916893Sfeldman if (off) { 3926893Sfeldman m->m_off += 2 * sizeof (u_short); 3936893Sfeldman m->m_len -= 2 * sizeof (u_short); 3946893Sfeldman } 3956893Sfeldman switch (il->ilr_type) { 3966893Sfeldman 3976893Sfeldman #ifdef INET 3986893Sfeldman case ILPUP_IPTYPE: 3996893Sfeldman schednetisr(NETISR_IP); 4006893Sfeldman inq = &ipintrq; 4016893Sfeldman break; 4026893Sfeldman #endif 4036893Sfeldman default: 4046893Sfeldman m_freem(m); 4056893Sfeldman goto setup; 4066893Sfeldman } 4076893Sfeldman 4086893Sfeldman if (IF_QFULL(inq)) { 4096893Sfeldman IF_DROP(inq); 4106893Sfeldman m_freem(m); 4116893Sfeldman } else 4126893Sfeldman IF_ENQUEUE(inq, m); 4136893Sfeldman 4146893Sfeldman setup: 4156893Sfeldman /* 4166893Sfeldman * Reset for next packet if possible. 4176893Sfeldman * If waiting for transmit command completion, set flag 4186893Sfeldman * and wait until command completes. 4196893Sfeldman */ 4206893Sfeldman if (!is->is_oactive) { 4216893Sfeldman addr->il_bar = is->is_ifuba.ifu_r.ifrw_info & 0xffff; 4226893Sfeldman addr->il_bcr = sizeof(struct il_rheader) + ILMTU + 6; 4236893Sfeldman addr->il_csr = ((is->is_ifuba.ifu_r.ifrw_info>>2)&0xc000)| 4246893Sfeldman ILC_RCV|IL_RIE; 4256893Sfeldman while (!(addr->il_csr & IL_CDONE)) 4266893Sfeldman /* Busy wait */; 4276893Sfeldman } else 4286893Sfeldman is->is_startrcv = 1; 4296893Sfeldman } 4306893Sfeldman 4316893Sfeldman /* 4326893Sfeldman * Ethernet output routine. 4336893Sfeldman * Encapsulate a packet of type family for the local net. 4346893Sfeldman * Use trailer local net encapsulation if enough data in first 4356893Sfeldman * packet leaves a multiple of 512 bytes of data in remainder. 4366893Sfeldman */ 4376893Sfeldman iloutput(ifp, m0, dst) 4386893Sfeldman struct ifnet *ifp; 4396893Sfeldman struct mbuf *m0; 4406893Sfeldman struct sockaddr *dst; 4416893Sfeldman { 4426893Sfeldman int type, dest, s, error; 4436893Sfeldman register struct il_softc *is = &il_softc[ifp->if_unit]; 4446893Sfeldman register struct mbuf *m = m0; 4456893Sfeldman register struct il_xheader *il; 4466893Sfeldman register int off; 4476893Sfeldman register int i; 4486893Sfeldman 4496893Sfeldman COUNT(ILOUTPUT); 4506893Sfeldman switch (dst->sa_family) { 4516893Sfeldman 4526893Sfeldman #ifdef INET 4536893Sfeldman case AF_INET: 4546893Sfeldman dest = ((struct sockaddr_in *)dst)->sin_addr.s_addr; 4556893Sfeldman off = ntohs((u_short)mtod(m, struct ip *)->ip_len) - m->m_len; 4566893Sfeldman if (off > 0 && (off & 0x1ff) == 0 && 4576893Sfeldman m->m_off >= MMINOFF + 2 * sizeof (u_short)) { 4586893Sfeldman type = ILPUP_TRAIL + (off>>9); 4596893Sfeldman m->m_off -= 2 * sizeof (u_short); 4606893Sfeldman m->m_len += 2 * sizeof (u_short); 4616893Sfeldman *mtod(m, u_short *) = ILPUP_IPTYPE; 4626893Sfeldman *(mtod(m, u_short *) + 1) = m->m_len; 4636893Sfeldman goto gottrailertype; 4646893Sfeldman } 4656893Sfeldman type = ILPUP_IPTYPE; 4666893Sfeldman off = 0; 4676893Sfeldman goto gottype; 4686893Sfeldman #endif 4696893Sfeldman 4706893Sfeldman default: 4716893Sfeldman printf("il%d: can't handle af%d\n", ifp->if_unit, 4726893Sfeldman dst->sa_family); 4736893Sfeldman error = EAFNOSUPPORT; 4746893Sfeldman goto bad; 4756893Sfeldman } 4766893Sfeldman 4776893Sfeldman gottrailertype: 4786893Sfeldman /* 4796893Sfeldman * Packet to be sent as trailer: move first packet 4806893Sfeldman * (control information) to end of chain. 4816893Sfeldman */ 4826893Sfeldman while (m->m_next) 4836893Sfeldman m = m->m_next; 4846893Sfeldman m->m_next = m0; 4856893Sfeldman m = m0->m_next; 4866893Sfeldman m0->m_next = 0; 4876893Sfeldman m0 = m; 4886893Sfeldman 4896893Sfeldman gottype: 4906893Sfeldman /* 4916893Sfeldman * Add local net header. If no space in first mbuf, 4926893Sfeldman * allocate another. 4936893Sfeldman */ 4946893Sfeldman if (m->m_off > MMAXOFF || 4956893Sfeldman MMINOFF + sizeof (struct il_xheader) > m->m_off) { 4966893Sfeldman m = m_get(M_DONTWAIT); 4976893Sfeldman if (m == 0) { 4986893Sfeldman error = ENOBUFS; 4996893Sfeldman goto bad; 5006893Sfeldman } 5016893Sfeldman m->m_next = m0; 5026893Sfeldman m->m_off = MMINOFF; 5036893Sfeldman m->m_len = sizeof (struct il_xheader); 5046893Sfeldman } else { 5056893Sfeldman m->m_off -= sizeof (struct il_xheader); 5066893Sfeldman m->m_len += sizeof (struct il_xheader); 5076893Sfeldman } 5086893Sfeldman il = mtod(m, struct il_xheader *); 5096893Sfeldman if ((dest &~ 0xff) == 0) 5106893Sfeldman for (i=0; i<6; i++) 5116893Sfeldman il->ilx_dhost[i] = 0xff; 5126893Sfeldman else { 5136893Sfeldman if (dest & 0x8000) { 5146893Sfeldman il->ilx_dhost[0] = is->is_enaddr[0]; 5156893Sfeldman il->ilx_dhost[1] = is->is_enaddr[1]; 5166893Sfeldman il->ilx_dhost[2] = is->is_enaddr[2]; 5176893Sfeldman } else { 5186893Sfeldman il->ilx_dhost[0] = il_ectop[0]; 5196893Sfeldman il->ilx_dhost[1] = il_ectop[1]; 5206893Sfeldman il->ilx_dhost[2] = il_ectop[2]; 5216893Sfeldman } 5226893Sfeldman il->ilx_dhost[3] = (dest>>8) & 0x7f; 5236893Sfeldman il->ilx_dhost[4] = (dest>>16) & 0xff; 5246893Sfeldman il->ilx_dhost[5] = (dest>>24) & 0xff; 5256893Sfeldman } 5266893Sfeldman il->ilx_type = type; 5276893Sfeldman 5286893Sfeldman /* 5296893Sfeldman * Queue message on interface, and start output if interface 5306893Sfeldman * not yet active. 5316893Sfeldman */ 5326893Sfeldman s = splimp(); 5336893Sfeldman if (IF_QFULL(&ifp->if_snd)) { 5346893Sfeldman IF_DROP(&ifp->if_snd); 5356893Sfeldman error = ENOBUFS; 5366893Sfeldman goto qfull; 5376893Sfeldman } 5386893Sfeldman IF_ENQUEUE(&ifp->if_snd, m); 5396893Sfeldman if (is->is_oactive == 0) 5406893Sfeldman ilstart(ifp->if_unit); 5416893Sfeldman splx(s); 5426893Sfeldman return (0); 5436893Sfeldman qfull: 5446893Sfeldman m0 = m; 5456893Sfeldman splx(s); 5466893Sfeldman bad: 5476893Sfeldman m_freem(m0); 5486893Sfeldman return(error); 5496893Sfeldman } 5506893Sfeldman 5516893Sfeldman #if NIMP == 0 && NIL > 0 5526893Sfeldman /* 5536893Sfeldman * Logical host interface driver. 5546893Sfeldman * Allows host to appear as an ARPAnet 5556893Sfeldman * logical host. Must also have routing 5566893Sfeldman * table entry set up to forward packets 5576893Sfeldman * to appropriate gateway on localnet. 5586893Sfeldman */ 5596893Sfeldman 5606893Sfeldman struct ifnet illhif; 5616926Swnj int looutput(); 5626893Sfeldman 5636893Sfeldman /* 5646893Sfeldman * Called by localnet interface to allow logical 5656893Sfeldman * host interface to "attach". Nothing should ever 5666893Sfeldman * be sent locally to this interface, it's purpose 5676893Sfeldman * is simply to establish the host's arpanet address. 5686893Sfeldman */ 5696926Swnj illhinit(ilifp, addr) 5706926Swnj struct ifnet *ilifp; 5716893Sfeldman int addr; 5726893Sfeldman { 5736893Sfeldman register struct ifnet *ifp = &illhif; 5746893Sfeldman register struct sockaddr_in *sin; 5756893Sfeldman 5766893Sfeldman COUNT(ILLHINIT); 5776893Sfeldman ifp->if_name = "lh"; 5786893Sfeldman ifp->if_mtu = ILMTU; 5796893Sfeldman sin = (struct sockaddr_in *)&ifp->if_addr; 5806893Sfeldman sin->sin_family = AF_INET; 5816893Sfeldman sin->sin_addr.s_addr = addr; 5826957Ssam sin->sin_addr.s_lh = ilifp->if_host[0]; 5836893Sfeldman ifp->if_net = sin->sin_addr.s_net; 5846957Ssam ifp->if_dstaddr = ifp->if_addr; 5856926Swnj ifp->if_flags = IFF_UP|IFF_POINTOPOINT; 5866926Swnj ifp->if_output = looutput; 5876893Sfeldman if_attach(ifp); 588*7152Swnj rtinit(&ifp->if_addr, &ifp->if_addr, RTF_UP|RTF_HOST); 5896893Sfeldman } 5906893Sfeldman #endif 591