1*19950Sbloom /* if_en.c 6.7 85/05/04 */ 24686Swnj 34686Swnj #include "en.h" 45105Swnj 54686Swnj /* 65105Swnj * Xerox prototype (3 Mb) Ethernet interface driver. 74686Swnj */ 89796Ssam #include "../machine/pte.h" 94686Swnj 1017113Sbloom #include "param.h" 1117113Sbloom #include "systm.h" 1217113Sbloom #include "mbuf.h" 1317113Sbloom #include "buf.h" 1417113Sbloom #include "protosw.h" 1517113Sbloom #include "socket.h" 1617113Sbloom #include "vmmac.h" 1717113Sbloom #include "errno.h" 1817113Sbloom #include "ioctl.h" 198462Sroot 208462Sroot #include "../net/if.h" 218462Sroot #include "../net/netisr.h" 228462Sroot #include "../net/route.h" 238418Swnj #include "../netinet/in.h" 248418Swnj #include "../netinet/in_systm.h" 2519864Skarels #include "../netinet/in_var.h" 268418Swnj #include "../netinet/ip.h" 278418Swnj #include "../netinet/ip_var.h" 28*19950Sbloom #ifdef PUP 298418Swnj #include "../netpup/pup.h" 3013458Ssam #include "../netpup/ether.h" 31*19950Sbloom #endif 324686Swnj 338462Sroot #include "../vax/cpu.h" 348462Sroot #include "../vax/mtpr.h" 3517113Sbloom #include "if_en.h" 3617113Sbloom #include "if_enreg.h" 3717113Sbloom #include "if_uba.h" 388462Sroot #include "../vaxuba/ubareg.h" 398462Sroot #include "../vaxuba/ubavar.h" 408462Sroot 415213Swnj #define ENMTU (1024+512) 426925Swnj #define ENMRU (1024+512+16) /* 16 is enough to receive trailer */ 435083Swnj 444686Swnj int enprobe(), enattach(), enrint(), enxint(), encollide(); 454686Swnj struct uba_device *eninfo[NEN]; 464686Swnj u_short enstd[] = { 0 }; 474686Swnj struct uba_driver endriver = 485171Swnj { enprobe, 0, enattach, 0, enstd, "en", eninfo }; 494686Swnj #define ENUNIT(x) minor(x) 504686Swnj 5113054Ssam int eninit(),enoutput(),enreset(),enioctl(); 525105Swnj 5313293Ssam #ifdef notdef 545105Swnj /* 5513293Ssam * If you need to byte swap IP's in the system, define 5613293Ssam * this and do a SIOCSIFFLAGS at boot time. 5713293Ssam */ 5819864Skarels #define ENF_SWABIPS 0x1000 5913293Ssam #endif 6013293Ssam 6113293Ssam /* 625105Swnj * Ethernet software status per interface. 635105Swnj * 645105Swnj * Each interface is referenced by a network interface structure, 655105Swnj * es_if, which the routing code uses to locate the interface. 665105Swnj * This structure contains the output queue for the interface, its address, ... 675105Swnj * We also have, for each interface, a UBA interface structure, which 685105Swnj * contains information about the UNIBUS resources held by the interface: 695105Swnj * map registers, buffered data paths, etc. Information is cached in this 705105Swnj * structure for use by the if_uba.c routines in running the interface 715105Swnj * efficiently. 725105Swnj */ 735083Swnj struct en_softc { 745105Swnj struct ifnet es_if; /* network-visible interface */ 755105Swnj struct ifuba es_ifuba; /* UNIBUS resources */ 7616380Skarels short es_host; /* hardware host number */ 775105Swnj short es_delay; /* current output delay */ 785105Swnj short es_mask; /* mask for current output delay */ 796471Sroot short es_lastx; /* host last transmitted to */ 805105Swnj short es_oactive; /* is output active? */ 815105Swnj short es_olen; /* length of last output */ 825083Swnj } en_softc[NEN]; 834686Swnj 845105Swnj /* 855105Swnj * Do output DMA to determine interface presence and 865105Swnj * interrupt vector. DMA is too short to disturb other hosts. 875105Swnj */ 884686Swnj enprobe(reg) 894686Swnj caddr_t reg; 904686Swnj { 915171Swnj register int br, cvec; /* r11, r10 value-result */ 924686Swnj register struct endevice *addr = (struct endevice *)reg; 934686Swnj 944686Swnj #ifdef lint 954686Swnj br = 0; cvec = br; br = cvec; 964922Swnj enrint(0); enxint(0); encollide(0); 974686Swnj #endif 984686Swnj addr->en_istat = 0; 994686Swnj addr->en_owc = -1; 1004686Swnj addr->en_oba = 0; 1014771Swnj addr->en_ostat = EN_IEN|EN_GO; 1024686Swnj DELAY(100000); 1034686Swnj addr->en_ostat = 0; 1044686Swnj return (1); 1054686Swnj } 1064686Swnj 1075105Swnj /* 1085105Swnj * Interface exists: make available by filling in network interface 1095105Swnj * record. System will initialize the interface when it is ready 1105105Swnj * to accept packets. 1115105Swnj */ 1124686Swnj enattach(ui) 1134686Swnj struct uba_device *ui; 1144686Swnj { 1155105Swnj register struct en_softc *es = &en_softc[ui->ui_unit]; 1164688Swnj 1175105Swnj es->es_if.if_unit = ui->ui_unit; 1185171Swnj es->es_if.if_name = "en"; 1195105Swnj es->es_if.if_mtu = ENMTU; 12019864Skarels es->es_if.if_flags = IFF_BROADCAST; 1215171Swnj es->es_if.if_init = eninit; 1225105Swnj es->es_if.if_output = enoutput; 12313054Ssam es->es_if.if_ioctl = enioctl; 1248978Sroot es->es_if.if_reset = enreset; 1256554Ssam es->es_ifuba.ifu_flags = UBA_NEEDBDP | UBA_NEED16 | UBA_CANTWAIT; 1269271Ssam #if defined(VAX750) 1279271Ssam /* don't chew up 750 bdp's */ 1289271Ssam if (cpu == VAX_750 && ui->ui_unit > 0) 1299271Ssam es->es_ifuba.ifu_flags &= ~UBA_NEEDBDP; 1309271Ssam #endif 1315160Swnj if_attach(&es->es_if); 1324686Swnj } 1334686Swnj 1345105Swnj /* 1355105Swnj * Reset of interface after UNIBUS reset. 1365105Swnj * If interface is on specified uba, reset its state. 1375105Swnj */ 1385105Swnj enreset(unit, uban) 1395105Swnj int unit, uban; 1405105Swnj { 1415105Swnj register struct uba_device *ui; 1425105Swnj 1435171Swnj if (unit >= NEN || (ui = eninfo[unit]) == 0 || ui->ui_alive == 0 || 1445171Swnj ui->ui_ubanum != uban) 1455105Swnj return; 1465171Swnj printf(" en%d", unit); 1475105Swnj eninit(unit); 1485105Swnj } 1495105Swnj 1505105Swnj /* 1515105Swnj * Initialization of interface; clear recorded pending 1525105Swnj * operations, and reinitialize UNIBUS usage. 1535105Swnj */ 1544688Swnj eninit(unit) 1554686Swnj int unit; 1565083Swnj { 1575171Swnj register struct en_softc *es = &en_softc[unit]; 1585171Swnj register struct uba_device *ui = eninfo[unit]; 1594686Swnj register struct endevice *addr; 16013054Ssam int s; 1614686Swnj 16219864Skarels if (es->es_if.if_addrlist == (struct ifaddr *)0) 16312349Ssam return; 1645105Swnj if (if_ubainit(&es->es_ifuba, ui->ui_ubanum, 1656925Swnj sizeof (struct en_header), (int)btoc(ENMRU)) == 0) { 1665171Swnj printf("en%d: can't initialize\n", unit); 1676335Ssam es->es_if.if_flags &= ~IFF_UP; 1685083Swnj return; 1694686Swnj } 1704686Swnj addr = (struct endevice *)ui->ui_addr; 1715083Swnj addr->en_istat = addr->en_ostat = 0; 1724686Swnj 1735105Swnj /* 1745171Swnj * Hang a receive and start any 1755171Swnj * pending writes by faking a transmit complete. 1765105Swnj */ 1775105Swnj s = splimp(); 1785171Swnj addr->en_iba = es->es_ifuba.ifu_r.ifrw_info; 1796925Swnj addr->en_iwc = -(sizeof (struct en_header) + ENMRU) >> 1; 1805171Swnj addr->en_istat = EN_IEN|EN_GO; 1815171Swnj es->es_oactive = 1; 18219864Skarels es->es_if.if_flags |= IFF_RUNNING; 1835105Swnj enxint(unit); 1845105Swnj splx(s); 1854686Swnj } 1864686Swnj 1876471Sroot int enalldelay = 0; 1886951Swnj int enlastdel = 50; 1896471Sroot int enlastmask = (~0) << 5; 1905083Swnj 1915105Swnj /* 1925105Swnj * Start or restart output on interface. 1935105Swnj * If interface is already active, then this is a retransmit 1945105Swnj * after a collision, and just restuff registers and delay. 1955105Swnj * If interface is not already active, get another datagram 1965105Swnj * to send off of the interface queue, and map it to the interface 1975105Swnj * before starting the output. 1985105Swnj */ 1994688Swnj enstart(dev) 2004686Swnj dev_t dev; 2014686Swnj { 2025171Swnj int unit = ENUNIT(dev); 2035171Swnj struct uba_device *ui = eninfo[unit]; 2045171Swnj register struct en_softc *es = &en_softc[unit]; 2055083Swnj register struct endevice *addr; 20616380Skarels register struct en_header *en; 2075083Swnj struct mbuf *m; 2085083Swnj int dest; 2094686Swnj 2105083Swnj if (es->es_oactive) 2115083Swnj goto restart; 2125105Swnj 2135105Swnj /* 2145105Swnj * Not already active: dequeue another request 2155105Swnj * and map it to the UNIBUS. If no more requests, 2165105Swnj * just return. 2175105Swnj */ 2185105Swnj IF_DEQUEUE(&es->es_if.if_snd, m); 2195083Swnj if (m == 0) { 2205083Swnj es->es_oactive = 0; 2214686Swnj return; 2224686Swnj } 22316380Skarels en = mtod(m, struct en_header *); 22416380Skarels dest = en->en_dhost; 22516380Skarels en->en_shost = es->es_host; 2265105Swnj es->es_olen = if_wubaput(&es->es_ifuba, m); 22713293Ssam #ifdef ENF_SWABIPS 22813293Ssam /* 22913293Ssam * The Xerox interface does word at a time DMA, so 23013293Ssam * someone must do byte swapping of user data if high 23113293Ssam * and low ender machines are to communicate. It doesn't 23213293Ssam * belong here, but certain people depend on it, so... 23313293Ssam * 23413293Ssam * Should swab everybody, but this is a kludge anyway. 23513293Ssam */ 23613293Ssam if (es->es_if.if_flags & ENF_SWABIPS) { 23713293Ssam en = (struct en_header *)es->es_ifuba.ifu_w.ifrw_addr; 23813293Ssam if (en->en_type == ENTYPE_IP) 23913293Ssam enswab((caddr_t)(en + 1), (caddr_t)(en + 1), 24013293Ssam es->es_olen - sizeof (struct en_header) + 1); 24113293Ssam } 24213293Ssam #endif 24313293Ssam 2445105Swnj /* 2455105Swnj * Ethernet cannot take back-to-back packets (no 2466471Sroot * buffering in interface. To help avoid overrunning 2476471Sroot * receivers, enforce a small delay (about 1ms) in interface: 2486471Sroot * * between all packets when enalldelay 2496471Sroot * * whenever last packet was broadcast 2506471Sroot * * whenever this packet is to same host as last packet 2515105Swnj */ 2526471Sroot if (enalldelay || es->es_lastx == 0 || es->es_lastx == dest) { 2535083Swnj es->es_delay = enlastdel; 2546471Sroot es->es_mask = enlastmask; 2556471Sroot } 2566471Sroot es->es_lastx = dest; 2575105Swnj 2585083Swnj restart: 2595105Swnj /* 2605105Swnj * Have request mapped to UNIBUS for transmission. 2615105Swnj * Purge any stale data from this BDP, and start the otput. 2625105Swnj */ 2636335Ssam if (es->es_ifuba.ifu_flags & UBA_NEEDBDP) 2646335Ssam UBAPURGE(es->es_ifuba.ifu_uba, es->es_ifuba.ifu_w.ifrw_bdp); 2654686Swnj addr = (struct endevice *)ui->ui_addr; 2665160Swnj addr->en_oba = (int)es->es_ifuba.ifu_w.ifrw_info; 2675083Swnj addr->en_odelay = es->es_delay; 2685083Swnj addr->en_owc = -((es->es_olen + 1) >> 1); 2694771Swnj addr->en_ostat = EN_IEN|EN_GO; 2705083Swnj es->es_oactive = 1; 2714686Swnj } 2724686Swnj 2735105Swnj /* 2745105Swnj * Ethernet interface transmitter interrupt. 2755105Swnj * Start another output if more data to send. 2765105Swnj */ 2774686Swnj enxint(unit) 2784686Swnj int unit; 2794686Swnj { 2805171Swnj register struct uba_device *ui = eninfo[unit]; 2815171Swnj register struct en_softc *es = &en_softc[unit]; 2826242Sroot register struct endevice *addr = (struct endevice *)ui->ui_addr; 2834686Swnj 2845083Swnj if (es->es_oactive == 0) 2855083Swnj return; 2866242Sroot if (es->es_mask && (addr->en_ostat&EN_OERROR)) { 2876242Sroot es->es_if.if_oerrors++; 2886242Sroot endocoll(unit); 2896242Sroot return; 2906242Sroot } 2915171Swnj es->es_if.if_opackets++; 2925083Swnj es->es_oactive = 0; 2935083Swnj es->es_delay = 0; 2945083Swnj es->es_mask = ~0; 2955696Sroot if (es->es_ifuba.ifu_xtofree) { 2965696Sroot m_freem(es->es_ifuba.ifu_xtofree); 2975696Sroot es->es_ifuba.ifu_xtofree = 0; 2985696Sroot } 2995105Swnj if (es->es_if.if_snd.ifq_head == 0) { 3006471Sroot es->es_lastx = 256; /* putatively illegal */ 3014686Swnj return; 3024686Swnj } 3035083Swnj enstart(unit); 3044686Swnj } 3054686Swnj 3065105Swnj /* 3075105Swnj * Collision on ethernet interface. Do exponential 3085105Swnj * backoff, and retransmit. If have backed off all 3096335Ssam * the way print warning diagnostic, and drop packet. 3105105Swnj */ 3114686Swnj encollide(unit) 3124686Swnj int unit; 3134686Swnj { 3146242Sroot struct en_softc *es = &en_softc[unit]; 3154686Swnj 3165105Swnj es->es_if.if_collisions++; 3175083Swnj if (es->es_oactive == 0) 3184686Swnj return; 3196242Sroot endocoll(unit); 3206242Sroot } 3216242Sroot 3226242Sroot endocoll(unit) 3236242Sroot int unit; 3246242Sroot { 3256242Sroot register struct en_softc *es = &en_softc[unit]; 3266242Sroot 3275171Swnj /* 3285171Swnj * Es_mask is a 16 bit number with n low zero bits, with 3295171Swnj * n the number of backoffs. When es_mask is 0 we have 3305171Swnj * backed off 16 times, and give up. 3315171Swnj */ 3325083Swnj if (es->es_mask == 0) { 3335213Swnj printf("en%d: send error\n", unit); 3345083Swnj enxint(unit); 3355171Swnj return; 3364686Swnj } 3375171Swnj /* 3385171Swnj * Another backoff. Restart with delay based on n low bits 3395171Swnj * of the interval timer. 3405171Swnj */ 3415171Swnj es->es_mask <<= 1; 3425171Swnj es->es_delay = mfpr(ICR) &~ es->es_mask; 3435171Swnj enstart(unit); 3444686Swnj } 3454686Swnj 34613458Ssam #ifdef notdef 34713458Ssam struct sockproto enproto = { AF_ETHERLINK }; 34813458Ssam struct sockaddr_en endst = { AF_ETHERLINK }; 34913458Ssam struct sockaddr_en ensrc = { AF_ETHERLINK }; 35013458Ssam #endif 3515105Swnj /* 3525105Swnj * Ethernet interface receiver interrupt. 3535105Swnj * If input error just drop packet. 3545105Swnj * Otherwise purge input buffered data path and examine 3555105Swnj * packet to determine type. If can't determine length 3565105Swnj * from type, then have to drop packet. Othewise decapsulate 3575105Swnj * packet based on type and pass to type specific higher-level 3585105Swnj * input routine. 3595105Swnj */ 3604686Swnj enrint(unit) 3614686Swnj int unit; 3624686Swnj { 3635171Swnj register struct en_softc *es = &en_softc[unit]; 3645171Swnj struct endevice *addr = (struct endevice *)eninfo[unit]->ui_addr; 3655171Swnj register struct en_header *en; 3665083Swnj struct mbuf *m; 3678603Sroot int len; short resid; 3685171Swnj register struct ifqueue *inq; 36916511Skarels int off, s; 3704686Swnj 3715171Swnj es->es_if.if_ipackets++; 3725105Swnj 3735105Swnj /* 3745171Swnj * Purge BDP; drop if input error indicated. 3755105Swnj */ 3766335Ssam if (es->es_ifuba.ifu_flags & UBA_NEEDBDP) 3776335Ssam UBAPURGE(es->es_ifuba.ifu_uba, es->es_ifuba.ifu_r.ifrw_bdp); 3784771Swnj if (addr->en_istat&EN_IERROR) { 3795105Swnj es->es_if.if_ierrors++; 3805083Swnj goto setup; 3814686Swnj } 3825105Swnj 3835105Swnj /* 3846471Sroot * Calculate input data length. 3855105Swnj * Get pointer to ethernet header (in input buffer). 3865105Swnj * Deal with trailer protocol: if type is PUP trailer 3875105Swnj * get true type from first 16-bit word past data. 3885105Swnj * Remember that type was trailer by setting off. 3895105Swnj */ 3906471Sroot resid = addr->en_iwc; 3916471Sroot if (resid) 3926471Sroot resid |= 0176000; 3936925Swnj len = (((sizeof (struct en_header) + ENMRU) >> 1) + resid) << 1; 3946471Sroot len -= sizeof (struct en_header); 3956925Swnj if (len > ENMRU) 3966471Sroot goto setup; /* sanity */ 3975105Swnj en = (struct en_header *)(es->es_ifuba.ifu_r.ifrw_addr); 39812352Ssam en->en_type = ntohs(en->en_type); 3995083Swnj #define endataaddr(en, off, type) ((type)(((caddr_t)((en)+1)+(off)))) 40012352Ssam if (en->en_type >= ENTYPE_TRAIL && 40112352Ssam en->en_type < ENTYPE_TRAIL+ENTYPE_NTRAILER) { 40212352Ssam off = (en->en_type - ENTYPE_TRAIL) * 512; 4036925Swnj if (off > ENMTU) 4045171Swnj goto setup; /* sanity */ 40512352Ssam en->en_type = ntohs(*endataaddr(en, off, u_short *)); 40612352Ssam resid = ntohs(*(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; 41413293Ssam #ifdef ENF_SWABIPS 41513293Ssam if (es->es_if.if_flags & ENF_SWABIPS && en->en_type == ENTYPE_IP) 41613293Ssam enswab((caddr_t)(en + 1), (caddr_t)(en + 1), len); 41713293Ssam #endif 4185105Swnj /* 4195105Swnj * Pull packet off interface. Off is nonzero if packet 4205105Swnj * has trailing header; if_rubaget will then force this header 4215105Swnj * information to be at the front, but we still have to drop 4226471Sroot * the type and length which are at the front of any trailer data. 4235105Swnj */ 4245105Swnj m = if_rubaget(&es->es_ifuba, len, off); 4255213Swnj if (m == 0) 4265213Swnj goto setup; 4275105Swnj if (off) { 4286471Sroot m->m_off += 2 * sizeof (u_short); 4296471Sroot m->m_len -= 2 * sizeof (u_short); 4305105Swnj } 4316027Ssam switch (en->en_type) { 4326027Ssam 4336027Ssam #ifdef INET 43412352Ssam case ENTYPE_IP: 4356260Swnj schednetisr(NETISR_IP); 4366027Ssam inq = &ipintrq; 4376027Ssam break; 4386027Ssam #endif 4396335Ssam #ifdef PUP 44013458Ssam case ENTYPE_PUP: 44113458Ssam rpup_input(m); 4426027Ssam goto setup; 4436335Ssam #endif 4446476Swnj default: 44513458Ssam #ifdef notdef 44613458Ssam enproto.sp_protocol = en->en_type; 44713458Ssam endst.sen_host = en->en_dhost; 44813458Ssam endst.sen_net = ensrc.sen_net = es->es_if.if_net; 44913458Ssam ensrc.sen_host = en->en_shost; 45013458Ssam raw_input(m, &enproto, 45113458Ssam (struct sockaddr *)&ensrc, (struct sockaddr *)&endst); 45213458Ssam #else 4536476Swnj m_freem(m); 45413458Ssam #endif 4556476Swnj goto setup; 4566335Ssam } 4576335Ssam 45816511Skarels s = splimp(); 4596207Swnj if (IF_QFULL(inq)) { 4606207Swnj IF_DROP(inq); 4616335Ssam m_freem(m); 4626207Swnj } else 4636207Swnj IF_ENQUEUE(inq, m); 46416511Skarels splx(s); 4655105Swnj 4664688Swnj setup: 4675105Swnj /* 4685105Swnj * Reset for next packet. 4695105Swnj */ 4705105Swnj addr->en_iba = es->es_ifuba.ifu_r.ifrw_info; 4716925Swnj addr->en_iwc = -(sizeof (struct en_header) + ENMRU) >> 1; 4724771Swnj addr->en_istat = EN_IEN|EN_GO; 4734688Swnj } 4744686Swnj 4755083Swnj /* 4765083Swnj * Ethernet output routine. 4775083Swnj * Encapsulate a packet of type family for the local net. 4785105Swnj * Use trailer local net encapsulation if enough data in first 4795105Swnj * packet leaves a multiple of 512 bytes of data in remainder. 4805083Swnj */ 4816335Ssam enoutput(ifp, m0, dst) 4825083Swnj struct ifnet *ifp; 4835083Swnj struct mbuf *m0; 4846335Ssam struct sockaddr *dst; 4854686Swnj { 4866503Ssam int type, dest, s, error; 4875105Swnj register struct mbuf *m = m0; 4885083Swnj register struct en_header *en; 4896335Ssam register int off; 4904686Swnj 4916335Ssam switch (dst->sa_family) { 4925083Swnj 4935083Swnj #ifdef INET 4946335Ssam case AF_INET: 49519864Skarels { 49619864Skarels struct in_addr in; 49719864Skarels 49819864Skarels in = ((struct sockaddr_in *)dst)->sin_addr; 49919864Skarels if (in_broadcast(in)) 50019864Skarels dest = EN_BROADCAST; 50119864Skarels else 50219864Skarels dest = in_lnaof(in); 50319864Skarels } 50419864Skarels if (dest >= 0x100) { 5056503Ssam error = EPERM; /* ??? */ 5066486Swnj goto bad; 5076503Ssam } 5086335Ssam off = ntohs((u_short)mtod(m, struct ip *)->ip_len) - m->m_len; 50913054Ssam /* need per host negotiation */ 51013054Ssam if ((ifp->if_flags & IFF_NOTRAILERS) == 0) 5116335Ssam if (off > 0 && (off & 0x1ff) == 0 && 5126471Sroot m->m_off >= MMINOFF + 2 * sizeof (u_short)) { 51312352Ssam type = ENTYPE_TRAIL + (off>>9); 5146471Sroot m->m_off -= 2 * sizeof (u_short); 5156471Sroot m->m_len += 2 * sizeof (u_short); 51612352Ssam *mtod(m, u_short *) = htons((u_short)ENTYPE_IP); 51712352Ssam *(mtod(m, u_short *) + 1) = ntohs((u_short)m->m_len); 5185105Swnj goto gottrailertype; 5195083Swnj } 52012352Ssam type = ENTYPE_IP; 5215105Swnj off = 0; 5225105Swnj goto gottype; 5235083Swnj #endif 5246027Ssam #ifdef PUP 5256335Ssam case AF_PUP: 52612833Ssam dest = ((struct sockaddr_pup *)dst)->spup_host; 52712352Ssam type = ENTYPE_PUP; 5286027Ssam off = 0; 5296027Ssam goto gottype; 5306027Ssam #endif 5316027Ssam 53213458Ssam #ifdef notdef 53313458Ssam case AF_ETHERLINK: 53413458Ssam goto gotheader; 53513458Ssam #endif 53613458Ssam 5375083Swnj default: 5386335Ssam printf("en%d: can't handle af%d\n", ifp->if_unit, 5396335Ssam dst->sa_family); 5406503Ssam error = EAFNOSUPPORT; 5416503Ssam goto bad; 5424686Swnj } 5435105Swnj 5445171Swnj gottrailertype: 5455105Swnj /* 5465105Swnj * Packet to be sent as trailer: move first packet 5475105Swnj * (control information) to end of chain. 5485105Swnj */ 5495105Swnj while (m->m_next) 5505105Swnj m = m->m_next; 5515105Swnj m->m_next = m0; 5525105Swnj m = m0->m_next; 5535105Swnj m0->m_next = 0; 5545171Swnj m0 = m; 5555105Swnj 5565171Swnj gottype: 5575105Swnj /* 5585105Swnj * Add local net header. If no space in first mbuf, 5595105Swnj * allocate another. 5605105Swnj */ 5615213Swnj if (m->m_off > MMAXOFF || 5625213Swnj MMINOFF + sizeof (struct en_header) > m->m_off) { 56317559Skarels MGET(m, M_DONTWAIT, MT_HEADER); 5645083Swnj if (m == 0) { 5656503Ssam error = ENOBUFS; 5666503Ssam goto bad; 5675083Swnj } 5685083Swnj m->m_next = m0; 5695083Swnj m->m_off = MMINOFF; 5705083Swnj m->m_len = sizeof (struct en_header); 5715083Swnj } else { 5725083Swnj m->m_off -= sizeof (struct en_header); 5735083Swnj m->m_len += sizeof (struct en_header); 5745083Swnj } 5755083Swnj en = mtod(m, struct en_header *); 57616380Skarels /* add en_shost later */ 5775083Swnj en->en_dhost = dest; 57812352Ssam en->en_type = htons((u_short)type); 5795105Swnj 58013458Ssam gotheader: 5815105Swnj /* 5825105Swnj * Queue message on interface, and start output if interface 5835105Swnj * not yet active. 5845105Swnj */ 5855083Swnj s = splimp(); 5866207Swnj if (IF_QFULL(&ifp->if_snd)) { 5876207Swnj IF_DROP(&ifp->if_snd); 5886503Ssam error = ENOBUFS; 5896503Ssam goto qfull; 5906207Swnj } 5915083Swnj IF_ENQUEUE(&ifp->if_snd, m); 5925083Swnj if (en_softc[ifp->if_unit].es_oactive == 0) 5935083Swnj enstart(ifp->if_unit); 5945275Swnj splx(s); 5956503Ssam return (0); 5966503Ssam qfull: 5976503Ssam m0 = m; 5986503Ssam splx(s); 5996484Swnj bad: 6006503Ssam m_freem(m0); 6016503Ssam return (error); 6024686Swnj } 60313054Ssam 60413054Ssam /* 60513054Ssam * Process an ioctl request. 60613054Ssam */ 60713054Ssam enioctl(ifp, cmd, data) 60813054Ssam register struct ifnet *ifp; 60913054Ssam int cmd; 61013054Ssam caddr_t data; 61113054Ssam { 61219864Skarels register struct en_softc *es = ((struct en_softc *)ifp); 61319864Skarels struct ifaddr *ifa = (struct ifaddr *) data; 61413054Ssam int s = splimp(), error = 0; 61519864Skarels struct endevice *enaddr; 61613054Ssam 61713054Ssam switch (cmd) { 61813054Ssam 61913054Ssam case SIOCSIFADDR: 62019864Skarels enaddr = (struct endevice *)eninfo[ifp->if_unit]->ui_addr; 62119864Skarels es->es_host = (~enaddr->en_addr) & 0xff; 62219864Skarels /* 62319864Skarels * Attempt to check agreement of protocol address 62419864Skarels * and board address. 62519864Skarels */ 62619864Skarels switch (ifa->ifa_addr.sa_family) { 62719864Skarels case AF_INET: 62819864Skarels if (in_lnaof(IA_SIN(ifa)->sin_addr) != es->es_host) 62919864Skarels return (EADDRNOTAVAIL); 63019864Skarels break; 63119864Skarels } 63219864Skarels ifp->if_flags |= IFF_UP; 63319864Skarels if ((ifp->if_flags & IFF_RUNNING) == 0) 63413054Ssam eninit(ifp->if_unit); 63513054Ssam break; 63613054Ssam 63713054Ssam default: 63813054Ssam error = EINVAL; 63913054Ssam } 64013054Ssam splx(s); 64113054Ssam return (error); 64213054Ssam } 64313054Ssam 64413293Ssam #ifdef ENF_SWABIPS 64513293Ssam /* 64613293Ssam * Swab bytes 64713293Ssam * Jeffrey Mogul, Stanford 64813293Ssam */ 64913293Ssam enswab(from, to, n) 65019864Skarels register unsigned char *from, *to; 65113293Ssam register int n; 65213293Ssam { 65313293Ssam register unsigned long temp; 65419864Skarels 65519864Skarels if ((n <= 0) || (n > 0xFFFF)) { 65619864Skarels printf("enswab: bad len %d\n", n); 65719864Skarels return; 65819864Skarels } 65913293Ssam 66013293Ssam n >>= 1; n++; 66119864Skarels #define STEP {temp = *from++;*to++ = *from++;*to++ = temp;} 66213293Ssam /* round to multiple of 8 */ 66313293Ssam while ((--n) & 07) 66413293Ssam STEP; 66513293Ssam n >>= 3; 66613293Ssam while (--n >= 0) { 66713293Ssam STEP; STEP; STEP; STEP; 66813293Ssam STEP; STEP; STEP; STEP; 66913293Ssam } 67013293Ssam } 67113293Ssam #endif 672