123290Smckusick /* 223290Smckusick * Copyright (c) 1982 Regents of the University of California. 323290Smckusick * All rights reserved. The Berkeley software License Agreement 423290Smckusick * specifies the terms and conditions for redistribution. 523290Smckusick * 6*25610Ssklower * @(#)if_en.c 6.12 (Berkeley) 12/17/85 723290Smckusick */ 84686Swnj 94686Swnj #include "en.h" 1025272Sbloom #if NEN > 0 115105Swnj 124686Swnj /* 135105Swnj * Xerox prototype (3 Mb) Ethernet interface driver. 144686Swnj */ 159796Ssam #include "../machine/pte.h" 164686Swnj 1717113Sbloom #include "param.h" 1817113Sbloom #include "systm.h" 1917113Sbloom #include "mbuf.h" 2017113Sbloom #include "buf.h" 2117113Sbloom #include "protosw.h" 2217113Sbloom #include "socket.h" 2317113Sbloom #include "vmmac.h" 2417113Sbloom #include "errno.h" 2517113Sbloom #include "ioctl.h" 268462Sroot 278462Sroot #include "../net/if.h" 288462Sroot #include "../net/netisr.h" 298462Sroot #include "../net/route.h" 3024790Skarels 3124790Skarels #ifdef BBNNET 3224790Skarels #define INET 3324790Skarels #endif 3424790Skarels #ifdef INET 358418Swnj #include "../netinet/in.h" 368418Swnj #include "../netinet/in_systm.h" 3719864Skarels #include "../netinet/in_var.h" 388418Swnj #include "../netinet/ip.h" 3924790Skarels #endif 4024790Skarels 4119950Sbloom #ifdef PUP 428418Swnj #include "../netpup/pup.h" 4313458Ssam #include "../netpup/ether.h" 4419950Sbloom #endif 454686Swnj 46*25610Ssklower #ifdef NS 47*25610Ssklower #include "../netns/ns.h" 48*25610Ssklower #include "../netns/ns_if.h" 49*25610Ssklower #endif 50*25610Ssklower 518462Sroot #include "../vax/cpu.h" 528462Sroot #include "../vax/mtpr.h" 5317113Sbloom #include "if_en.h" 5417113Sbloom #include "if_enreg.h" 5517113Sbloom #include "if_uba.h" 568462Sroot #include "../vaxuba/ubareg.h" 578462Sroot #include "../vaxuba/ubavar.h" 588462Sroot 595213Swnj #define ENMTU (1024+512) 606925Swnj #define ENMRU (1024+512+16) /* 16 is enough to receive trailer */ 615083Swnj 624686Swnj int enprobe(), enattach(), enrint(), enxint(), encollide(); 634686Swnj struct uba_device *eninfo[NEN]; 644686Swnj u_short enstd[] = { 0 }; 654686Swnj struct uba_driver endriver = 665171Swnj { enprobe, 0, enattach, 0, enstd, "en", eninfo }; 674686Swnj #define ENUNIT(x) minor(x) 684686Swnj 6913054Ssam int eninit(),enoutput(),enreset(),enioctl(); 705105Swnj 7113293Ssam #ifdef notdef 725105Swnj /* 7313293Ssam * If you need to byte swap IP's in the system, define 7413293Ssam * this and do a SIOCSIFFLAGS at boot time. 7513293Ssam */ 7619864Skarels #define ENF_SWABIPS 0x1000 7713293Ssam #endif 7813293Ssam 7913293Ssam /* 805105Swnj * Ethernet software status per interface. 815105Swnj * 825105Swnj * Each interface is referenced by a network interface structure, 835105Swnj * es_if, which the routing code uses to locate the interface. 845105Swnj * This structure contains the output queue for the interface, its address, ... 855105Swnj * We also have, for each interface, a UBA interface structure, which 865105Swnj * contains information about the UNIBUS resources held by the interface: 875105Swnj * map registers, buffered data paths, etc. Information is cached in this 885105Swnj * structure for use by the if_uba.c routines in running the interface 895105Swnj * efficiently. 905105Swnj */ 915083Swnj struct en_softc { 925105Swnj struct ifnet es_if; /* network-visible interface */ 935105Swnj struct ifuba es_ifuba; /* UNIBUS resources */ 9416380Skarels short es_host; /* hardware host number */ 955105Swnj short es_delay; /* current output delay */ 965105Swnj short es_mask; /* mask for current output delay */ 976471Sroot short es_lastx; /* host last transmitted to */ 985105Swnj short es_oactive; /* is output active? */ 995105Swnj short es_olen; /* length of last output */ 100*25610Ssklower short es_nsactive; /* is interface enabled for ns? */ 1015083Swnj } en_softc[NEN]; 1024686Swnj 1035105Swnj /* 1045105Swnj * Do output DMA to determine interface presence and 1055105Swnj * interrupt vector. DMA is too short to disturb other hosts. 1065105Swnj */ 1074686Swnj enprobe(reg) 1084686Swnj caddr_t reg; 1094686Swnj { 1105171Swnj register int br, cvec; /* r11, r10 value-result */ 1114686Swnj register struct endevice *addr = (struct endevice *)reg; 1124686Swnj 1134686Swnj #ifdef lint 1144686Swnj br = 0; cvec = br; br = cvec; 1154922Swnj enrint(0); enxint(0); encollide(0); 1164686Swnj #endif 1174686Swnj addr->en_istat = 0; 1184686Swnj addr->en_owc = -1; 1194686Swnj addr->en_oba = 0; 1204771Swnj addr->en_ostat = EN_IEN|EN_GO; 1214686Swnj DELAY(100000); 1224686Swnj addr->en_ostat = 0; 1234686Swnj return (1); 1244686Swnj } 1254686Swnj 1265105Swnj /* 1275105Swnj * Interface exists: make available by filling in network interface 1285105Swnj * record. System will initialize the interface when it is ready 1295105Swnj * to accept packets. 1305105Swnj */ 1314686Swnj enattach(ui) 1324686Swnj struct uba_device *ui; 1334686Swnj { 1345105Swnj register struct en_softc *es = &en_softc[ui->ui_unit]; 1354688Swnj 1365105Swnj es->es_if.if_unit = ui->ui_unit; 1375171Swnj es->es_if.if_name = "en"; 1385105Swnj es->es_if.if_mtu = ENMTU; 13919864Skarels es->es_if.if_flags = IFF_BROADCAST; 1405171Swnj es->es_if.if_init = eninit; 1415105Swnj es->es_if.if_output = enoutput; 14213054Ssam es->es_if.if_ioctl = enioctl; 1438978Sroot es->es_if.if_reset = enreset; 1446554Ssam es->es_ifuba.ifu_flags = UBA_NEEDBDP | UBA_NEED16 | UBA_CANTWAIT; 1459271Ssam #if defined(VAX750) 1469271Ssam /* don't chew up 750 bdp's */ 1479271Ssam if (cpu == VAX_750 && ui->ui_unit > 0) 1489271Ssam es->es_ifuba.ifu_flags &= ~UBA_NEEDBDP; 1499271Ssam #endif 1505160Swnj if_attach(&es->es_if); 1514686Swnj } 1524686Swnj 1535105Swnj /* 1545105Swnj * Reset of interface after UNIBUS reset. 1555105Swnj * If interface is on specified uba, reset its state. 1565105Swnj */ 1575105Swnj enreset(unit, uban) 1585105Swnj int unit, uban; 1595105Swnj { 1605105Swnj register struct uba_device *ui; 1615105Swnj 1625171Swnj if (unit >= NEN || (ui = eninfo[unit]) == 0 || ui->ui_alive == 0 || 1635171Swnj ui->ui_ubanum != uban) 1645105Swnj return; 1655171Swnj printf(" en%d", unit); 1665105Swnj eninit(unit); 1675105Swnj } 1685105Swnj 1695105Swnj /* 1705105Swnj * Initialization of interface; clear recorded pending 1715105Swnj * operations, and reinitialize UNIBUS usage. 1725105Swnj */ 1734688Swnj eninit(unit) 1744686Swnj int unit; 1755083Swnj { 1765171Swnj register struct en_softc *es = &en_softc[unit]; 1775171Swnj register struct uba_device *ui = eninfo[unit]; 1784686Swnj register struct endevice *addr; 17913054Ssam int s; 1804686Swnj 18119864Skarels if (es->es_if.if_addrlist == (struct ifaddr *)0) 18212349Ssam return; 1835105Swnj if (if_ubainit(&es->es_ifuba, ui->ui_ubanum, 1846925Swnj sizeof (struct en_header), (int)btoc(ENMRU)) == 0) { 1855171Swnj printf("en%d: can't initialize\n", unit); 1866335Ssam es->es_if.if_flags &= ~IFF_UP; 1875083Swnj return; 1884686Swnj } 1894686Swnj addr = (struct endevice *)ui->ui_addr; 1905083Swnj addr->en_istat = addr->en_ostat = 0; 1914686Swnj 1925105Swnj /* 1935171Swnj * Hang a receive and start any 1945171Swnj * pending writes by faking a transmit complete. 1955105Swnj */ 1965105Swnj s = splimp(); 1975171Swnj addr->en_iba = es->es_ifuba.ifu_r.ifrw_info; 1986925Swnj addr->en_iwc = -(sizeof (struct en_header) + ENMRU) >> 1; 1995171Swnj addr->en_istat = EN_IEN|EN_GO; 2005171Swnj es->es_oactive = 1; 20119864Skarels es->es_if.if_flags |= IFF_RUNNING; 2025105Swnj enxint(unit); 2035105Swnj splx(s); 2044686Swnj } 2054686Swnj 2066471Sroot int enalldelay = 0; 2076951Swnj int enlastdel = 50; 2086471Sroot int enlastmask = (~0) << 5; 2095083Swnj 2105105Swnj /* 2115105Swnj * Start or restart output on interface. 2125105Swnj * If interface is already active, then this is a retransmit 2135105Swnj * after a collision, and just restuff registers and delay. 2145105Swnj * If interface is not already active, get another datagram 2155105Swnj * to send off of the interface queue, and map it to the interface 2165105Swnj * before starting the output. 2175105Swnj */ 2184688Swnj enstart(dev) 2194686Swnj dev_t dev; 2204686Swnj { 2215171Swnj int unit = ENUNIT(dev); 2225171Swnj struct uba_device *ui = eninfo[unit]; 2235171Swnj register struct en_softc *es = &en_softc[unit]; 2245083Swnj register struct endevice *addr; 22516380Skarels register struct en_header *en; 2265083Swnj struct mbuf *m; 2275083Swnj int dest; 2284686Swnj 2295083Swnj if (es->es_oactive) 2305083Swnj goto restart; 2315105Swnj 2325105Swnj /* 2335105Swnj * Not already active: dequeue another request 2345105Swnj * and map it to the UNIBUS. If no more requests, 2355105Swnj * just return. 2365105Swnj */ 2375105Swnj IF_DEQUEUE(&es->es_if.if_snd, m); 2385083Swnj if (m == 0) { 2395083Swnj es->es_oactive = 0; 2404686Swnj return; 2414686Swnj } 24216380Skarels en = mtod(m, struct en_header *); 24316380Skarels dest = en->en_dhost; 24416380Skarels en->en_shost = es->es_host; 2455105Swnj es->es_olen = if_wubaput(&es->es_ifuba, m); 24613293Ssam #ifdef ENF_SWABIPS 24713293Ssam /* 24813293Ssam * The Xerox interface does word at a time DMA, so 24913293Ssam * someone must do byte swapping of user data if high 25013293Ssam * and low ender machines are to communicate. It doesn't 25113293Ssam * belong here, but certain people depend on it, so... 25213293Ssam * 25313293Ssam * Should swab everybody, but this is a kludge anyway. 25413293Ssam */ 25513293Ssam if (es->es_if.if_flags & ENF_SWABIPS) { 25613293Ssam en = (struct en_header *)es->es_ifuba.ifu_w.ifrw_addr; 25713293Ssam if (en->en_type == ENTYPE_IP) 25813293Ssam enswab((caddr_t)(en + 1), (caddr_t)(en + 1), 25913293Ssam es->es_olen - sizeof (struct en_header) + 1); 26013293Ssam } 26113293Ssam #endif 26213293Ssam 2635105Swnj /* 2645105Swnj * Ethernet cannot take back-to-back packets (no 2656471Sroot * buffering in interface. To help avoid overrunning 2666471Sroot * receivers, enforce a small delay (about 1ms) in interface: 2676471Sroot * * between all packets when enalldelay 2686471Sroot * * whenever last packet was broadcast 2696471Sroot * * whenever this packet is to same host as last packet 2705105Swnj */ 2716471Sroot if (enalldelay || es->es_lastx == 0 || es->es_lastx == dest) { 2725083Swnj es->es_delay = enlastdel; 2736471Sroot es->es_mask = enlastmask; 2746471Sroot } 2756471Sroot es->es_lastx = dest; 2765105Swnj 2775083Swnj restart: 2785105Swnj /* 2795105Swnj * Have request mapped to UNIBUS for transmission. 2805105Swnj * Purge any stale data from this BDP, and start the otput. 2815105Swnj */ 2826335Ssam if (es->es_ifuba.ifu_flags & UBA_NEEDBDP) 2836335Ssam UBAPURGE(es->es_ifuba.ifu_uba, es->es_ifuba.ifu_w.ifrw_bdp); 2844686Swnj addr = (struct endevice *)ui->ui_addr; 2855160Swnj addr->en_oba = (int)es->es_ifuba.ifu_w.ifrw_info; 2865083Swnj addr->en_odelay = es->es_delay; 2875083Swnj addr->en_owc = -((es->es_olen + 1) >> 1); 2884771Swnj addr->en_ostat = EN_IEN|EN_GO; 2895083Swnj es->es_oactive = 1; 2904686Swnj } 2914686Swnj 2925105Swnj /* 2935105Swnj * Ethernet interface transmitter interrupt. 2945105Swnj * Start another output if more data to send. 2955105Swnj */ 2964686Swnj enxint(unit) 2974686Swnj int unit; 2984686Swnj { 2995171Swnj register struct uba_device *ui = eninfo[unit]; 3005171Swnj register struct en_softc *es = &en_softc[unit]; 3016242Sroot register struct endevice *addr = (struct endevice *)ui->ui_addr; 3024686Swnj 3035083Swnj if (es->es_oactive == 0) 3045083Swnj return; 3056242Sroot if (es->es_mask && (addr->en_ostat&EN_OERROR)) { 3066242Sroot es->es_if.if_oerrors++; 3076242Sroot endocoll(unit); 3086242Sroot return; 3096242Sroot } 3105171Swnj es->es_if.if_opackets++; 3115083Swnj es->es_oactive = 0; 3125083Swnj es->es_delay = 0; 3135083Swnj es->es_mask = ~0; 3145696Sroot if (es->es_ifuba.ifu_xtofree) { 3155696Sroot m_freem(es->es_ifuba.ifu_xtofree); 3165696Sroot es->es_ifuba.ifu_xtofree = 0; 3175696Sroot } 3185105Swnj if (es->es_if.if_snd.ifq_head == 0) { 3196471Sroot es->es_lastx = 256; /* putatively illegal */ 3204686Swnj return; 3214686Swnj } 3225083Swnj enstart(unit); 3234686Swnj } 3244686Swnj 3255105Swnj /* 3265105Swnj * Collision on ethernet interface. Do exponential 3275105Swnj * backoff, and retransmit. If have backed off all 3286335Ssam * the way print warning diagnostic, and drop packet. 3295105Swnj */ 3304686Swnj encollide(unit) 3314686Swnj int unit; 3324686Swnj { 3336242Sroot struct en_softc *es = &en_softc[unit]; 3344686Swnj 3355105Swnj es->es_if.if_collisions++; 3365083Swnj if (es->es_oactive == 0) 3374686Swnj return; 3386242Sroot endocoll(unit); 3396242Sroot } 3406242Sroot 3416242Sroot endocoll(unit) 3426242Sroot int unit; 3436242Sroot { 3446242Sroot register struct en_softc *es = &en_softc[unit]; 3456242Sroot 3465171Swnj /* 3475171Swnj * Es_mask is a 16 bit number with n low zero bits, with 3485171Swnj * n the number of backoffs. When es_mask is 0 we have 3495171Swnj * backed off 16 times, and give up. 3505171Swnj */ 3515083Swnj if (es->es_mask == 0) { 3525213Swnj printf("en%d: send error\n", unit); 3535083Swnj enxint(unit); 3545171Swnj return; 3554686Swnj } 3565171Swnj /* 3575171Swnj * Another backoff. Restart with delay based on n low bits 3585171Swnj * of the interval timer. 3595171Swnj */ 3605171Swnj es->es_mask <<= 1; 3615171Swnj es->es_delay = mfpr(ICR) &~ es->es_mask; 3625171Swnj enstart(unit); 3634686Swnj } 3644686Swnj 36513458Ssam #ifdef notdef 36613458Ssam struct sockproto enproto = { AF_ETHERLINK }; 36713458Ssam struct sockaddr_en endst = { AF_ETHERLINK }; 36813458Ssam struct sockaddr_en ensrc = { AF_ETHERLINK }; 36913458Ssam #endif 3705105Swnj /* 3715105Swnj * Ethernet interface receiver interrupt. 3725105Swnj * If input error just drop packet. 3735105Swnj * Otherwise purge input buffered data path and examine 3745105Swnj * packet to determine type. If can't determine length 3755105Swnj * from type, then have to drop packet. Othewise decapsulate 3765105Swnj * packet based on type and pass to type specific higher-level 3775105Swnj * input routine. 3785105Swnj */ 3794686Swnj enrint(unit) 3804686Swnj int unit; 3814686Swnj { 3825171Swnj register struct en_softc *es = &en_softc[unit]; 3835171Swnj struct endevice *addr = (struct endevice *)eninfo[unit]->ui_addr; 3845171Swnj register struct en_header *en; 3855083Swnj struct mbuf *m; 3868603Sroot int len; short resid; 3875171Swnj register struct ifqueue *inq; 38816511Skarels int off, s; 3894686Swnj 3905171Swnj es->es_if.if_ipackets++; 3915105Swnj 3925105Swnj /* 3935171Swnj * Purge BDP; drop if input error indicated. 3945105Swnj */ 3956335Ssam if (es->es_ifuba.ifu_flags & UBA_NEEDBDP) 3966335Ssam UBAPURGE(es->es_ifuba.ifu_uba, es->es_ifuba.ifu_r.ifrw_bdp); 3974771Swnj if (addr->en_istat&EN_IERROR) { 3985105Swnj es->es_if.if_ierrors++; 3995083Swnj goto setup; 4004686Swnj } 4015105Swnj 4025105Swnj /* 4036471Sroot * Calculate input data length. 4045105Swnj * Get pointer to ethernet header (in input buffer). 4055105Swnj * Deal with trailer protocol: if type is PUP trailer 4065105Swnj * get true type from first 16-bit word past data. 4075105Swnj * Remember that type was trailer by setting off. 4085105Swnj */ 4096471Sroot resid = addr->en_iwc; 4106471Sroot if (resid) 4116471Sroot resid |= 0176000; 4126925Swnj len = (((sizeof (struct en_header) + ENMRU) >> 1) + resid) << 1; 4136471Sroot len -= sizeof (struct en_header); 4146925Swnj if (len > ENMRU) 4156471Sroot goto setup; /* sanity */ 4165105Swnj en = (struct en_header *)(es->es_ifuba.ifu_r.ifrw_addr); 41712352Ssam en->en_type = ntohs(en->en_type); 4185083Swnj #define endataaddr(en, off, type) ((type)(((caddr_t)((en)+1)+(off)))) 41912352Ssam if (en->en_type >= ENTYPE_TRAIL && 42012352Ssam en->en_type < ENTYPE_TRAIL+ENTYPE_NTRAILER) { 42112352Ssam off = (en->en_type - ENTYPE_TRAIL) * 512; 4226925Swnj if (off > ENMTU) 4235171Swnj goto setup; /* sanity */ 42412352Ssam en->en_type = ntohs(*endataaddr(en, off, u_short *)); 42512352Ssam resid = ntohs(*(endataaddr(en, off+2, u_short *))); 4266471Sroot if (off + resid > len) 4276471Sroot goto setup; /* sanity */ 4286471Sroot len = off + resid; 4295083Swnj } else 4305083Swnj off = 0; 4315083Swnj if (len == 0) 4325083Swnj goto setup; 43313293Ssam #ifdef ENF_SWABIPS 43413293Ssam if (es->es_if.if_flags & ENF_SWABIPS && en->en_type == ENTYPE_IP) 43513293Ssam enswab((caddr_t)(en + 1), (caddr_t)(en + 1), len); 43613293Ssam #endif 4375105Swnj /* 4385105Swnj * Pull packet off interface. Off is nonzero if packet 4395105Swnj * has trailing header; if_rubaget will then force this header 4405105Swnj * information to be at the front, but we still have to drop 4416471Sroot * the type and length which are at the front of any trailer data. 4425105Swnj */ 44324790Skarels m = if_rubaget(&es->es_ifuba, len, off, &es->es_if); 4445213Swnj if (m == 0) 4455213Swnj goto setup; 4465105Swnj if (off) { 44724790Skarels struct ifnet *ifp; 44824790Skarels 44924790Skarels ifp = *(mtod(m, struct ifnet **)); 4506471Sroot m->m_off += 2 * sizeof (u_short); 4516471Sroot m->m_len -= 2 * sizeof (u_short); 45224790Skarels *(mtod(m, struct ifnet **)) = ifp; 4535105Swnj } 4546027Ssam switch (en->en_type) { 4556027Ssam 4566027Ssam #ifdef INET 45712352Ssam case ENTYPE_IP: 4586260Swnj schednetisr(NETISR_IP); 4596027Ssam inq = &ipintrq; 4606027Ssam break; 4616027Ssam #endif 4626335Ssam #ifdef PUP 46313458Ssam case ENTYPE_PUP: 46413458Ssam rpup_input(m); 4656027Ssam goto setup; 4666335Ssam #endif 467*25610Ssklower #ifdef NS 468*25610Ssklower case ETHERTYPE_NS: 469*25610Ssklower if (es->es_nsactive) { 470*25610Ssklower schednetisr(NETISR_NS); 471*25610Ssklower inq = &nsintrq; 472*25610Ssklower } else { 473*25610Ssklower m_freem(m); 474*25610Ssklower goto setup; 475*25610Ssklower } 476*25610Ssklower break; 477*25610Ssklower #endif 478*25610Ssklower 4796476Swnj default: 48013458Ssam #ifdef notdef 48113458Ssam enproto.sp_protocol = en->en_type; 48213458Ssam endst.sen_host = en->en_dhost; 48313458Ssam endst.sen_net = ensrc.sen_net = es->es_if.if_net; 48413458Ssam ensrc.sen_host = en->en_shost; 48513458Ssam raw_input(m, &enproto, 48613458Ssam (struct sockaddr *)&ensrc, (struct sockaddr *)&endst); 48713458Ssam #else 4886476Swnj m_freem(m); 48913458Ssam #endif 4906476Swnj goto setup; 4916335Ssam } 4926335Ssam 49316511Skarels s = splimp(); 4946207Swnj if (IF_QFULL(inq)) { 4956207Swnj IF_DROP(inq); 4966335Ssam m_freem(m); 4976207Swnj } else 4986207Swnj IF_ENQUEUE(inq, m); 49916511Skarels splx(s); 5005105Swnj 5014688Swnj setup: 5025105Swnj /* 5035105Swnj * Reset for next packet. 5045105Swnj */ 5055105Swnj addr->en_iba = es->es_ifuba.ifu_r.ifrw_info; 5066925Swnj addr->en_iwc = -(sizeof (struct en_header) + ENMRU) >> 1; 5074771Swnj addr->en_istat = EN_IEN|EN_GO; 5084688Swnj } 5094686Swnj 5105083Swnj /* 5115083Swnj * Ethernet output routine. 5125083Swnj * Encapsulate a packet of type family for the local net. 5135105Swnj * Use trailer local net encapsulation if enough data in first 5145105Swnj * packet leaves a multiple of 512 bytes of data in remainder. 5155083Swnj */ 5166335Ssam enoutput(ifp, m0, dst) 5175083Swnj struct ifnet *ifp; 5185083Swnj struct mbuf *m0; 5196335Ssam struct sockaddr *dst; 5204686Swnj { 5216503Ssam int type, dest, s, error; 5225105Swnj register struct mbuf *m = m0; 5235083Swnj register struct en_header *en; 5246335Ssam register int off; 5254686Swnj 52625446Skarels if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING)) { 52725446Skarels error = ENETDOWN; 52825446Skarels goto bad; 52925446Skarels } 5306335Ssam switch (dst->sa_family) { 5315083Swnj 5325083Swnj #ifdef INET 5336335Ssam case AF_INET: 53419864Skarels { 53519864Skarels struct in_addr in; 53619864Skarels 53719864Skarels in = ((struct sockaddr_in *)dst)->sin_addr; 53819864Skarels if (in_broadcast(in)) 53919864Skarels dest = EN_BROADCAST; 54019864Skarels else 54119864Skarels dest = in_lnaof(in); 54219864Skarels } 54319864Skarels if (dest >= 0x100) { 5446503Ssam error = EPERM; /* ??? */ 5456486Swnj goto bad; 5466503Ssam } 5476335Ssam off = ntohs((u_short)mtod(m, struct ip *)->ip_len) - m->m_len; 54813054Ssam /* need per host negotiation */ 54913054Ssam if ((ifp->if_flags & IFF_NOTRAILERS) == 0) 5506335Ssam if (off > 0 && (off & 0x1ff) == 0 && 5516471Sroot m->m_off >= MMINOFF + 2 * sizeof (u_short)) { 55212352Ssam type = ENTYPE_TRAIL + (off>>9); 5536471Sroot m->m_off -= 2 * sizeof (u_short); 5546471Sroot m->m_len += 2 * sizeof (u_short); 55512352Ssam *mtod(m, u_short *) = htons((u_short)ENTYPE_IP); 55612352Ssam *(mtod(m, u_short *) + 1) = ntohs((u_short)m->m_len); 5575105Swnj goto gottrailertype; 5585083Swnj } 55912352Ssam type = ENTYPE_IP; 5605105Swnj off = 0; 5615105Swnj goto gottype; 5625083Swnj #endif 563*25610Ssklower #ifdef NS 564*25610Ssklower case AF_NS: 565*25610Ssklower { 566*25610Ssklower u_char *up; 567*25610Ssklower 568*25610Ssklower type = ETHERTYPE_NS; 569*25610Ssklower up = ((struct sockaddr_ns *)dst)->sns_addr.x_host.c_host; 570*25610Ssklower if (*up & 1) 571*25610Ssklower dest = EN_BROADCAST; 572*25610Ssklower else 573*25610Ssklower dest = up[5]; 574*25610Ssklower 575*25610Ssklower off = 0; 576*25610Ssklower goto gottype; 577*25610Ssklower } 578*25610Ssklower #endif 5796027Ssam #ifdef PUP 5806335Ssam case AF_PUP: 58112833Ssam dest = ((struct sockaddr_pup *)dst)->spup_host; 58212352Ssam type = ENTYPE_PUP; 5836027Ssam off = 0; 5846027Ssam goto gottype; 5856027Ssam #endif 5866027Ssam 58713458Ssam #ifdef notdef 58813458Ssam case AF_ETHERLINK: 58913458Ssam goto gotheader; 59013458Ssam #endif 59113458Ssam 5925083Swnj default: 5936335Ssam printf("en%d: can't handle af%d\n", ifp->if_unit, 5946335Ssam dst->sa_family); 5956503Ssam error = EAFNOSUPPORT; 5966503Ssam goto bad; 5974686Swnj } 5985105Swnj 5995171Swnj gottrailertype: 6005105Swnj /* 6015105Swnj * Packet to be sent as trailer: move first packet 6025105Swnj * (control information) to end of chain. 6035105Swnj */ 6045105Swnj while (m->m_next) 6055105Swnj m = m->m_next; 6065105Swnj m->m_next = m0; 6075105Swnj m = m0->m_next; 6085105Swnj m0->m_next = 0; 6095171Swnj m0 = m; 6105105Swnj 6115171Swnj gottype: 6125105Swnj /* 6135105Swnj * Add local net header. If no space in first mbuf, 6145105Swnj * allocate another. 6155105Swnj */ 6165213Swnj if (m->m_off > MMAXOFF || 6175213Swnj MMINOFF + sizeof (struct en_header) > m->m_off) { 61817559Skarels MGET(m, M_DONTWAIT, MT_HEADER); 6195083Swnj if (m == 0) { 6206503Ssam error = ENOBUFS; 6216503Ssam goto bad; 6225083Swnj } 6235083Swnj m->m_next = m0; 6245083Swnj m->m_off = MMINOFF; 6255083Swnj m->m_len = sizeof (struct en_header); 6265083Swnj } else { 6275083Swnj m->m_off -= sizeof (struct en_header); 6285083Swnj m->m_len += sizeof (struct en_header); 6295083Swnj } 6305083Swnj en = mtod(m, struct en_header *); 63116380Skarels /* add en_shost later */ 6325083Swnj en->en_dhost = dest; 63312352Ssam en->en_type = htons((u_short)type); 6345105Swnj 63524790Skarels #ifdef notdef 63613458Ssam gotheader: 63724790Skarels #endif 6385105Swnj /* 6395105Swnj * Queue message on interface, and start output if interface 6405105Swnj * not yet active. 6415105Swnj */ 6425083Swnj s = splimp(); 6436207Swnj if (IF_QFULL(&ifp->if_snd)) { 6446207Swnj IF_DROP(&ifp->if_snd); 6456503Ssam error = ENOBUFS; 6466503Ssam goto qfull; 6476207Swnj } 6485083Swnj IF_ENQUEUE(&ifp->if_snd, m); 6495083Swnj if (en_softc[ifp->if_unit].es_oactive == 0) 6505083Swnj enstart(ifp->if_unit); 6515275Swnj splx(s); 6526503Ssam return (0); 6536503Ssam qfull: 6546503Ssam m0 = m; 6556503Ssam splx(s); 6566484Swnj bad: 6576503Ssam m_freem(m0); 6586503Ssam return (error); 6594686Swnj } 66013054Ssam 66113054Ssam /* 66213054Ssam * Process an ioctl request. 66313054Ssam */ 66413054Ssam enioctl(ifp, cmd, data) 66513054Ssam register struct ifnet *ifp; 66613054Ssam int cmd; 66713054Ssam caddr_t data; 66813054Ssam { 66919864Skarels register struct en_softc *es = ((struct en_softc *)ifp); 67019864Skarels struct ifaddr *ifa = (struct ifaddr *) data; 67113054Ssam int s = splimp(), error = 0; 67219864Skarels struct endevice *enaddr; 67313054Ssam 67413054Ssam switch (cmd) { 67513054Ssam 67613054Ssam case SIOCSIFADDR: 67719864Skarels enaddr = (struct endevice *)eninfo[ifp->if_unit]->ui_addr; 67819864Skarels es->es_host = (~enaddr->en_addr) & 0xff; 67919864Skarels /* 68019864Skarels * Attempt to check agreement of protocol address 68119864Skarels * and board address. 68219864Skarels */ 68319864Skarels switch (ifa->ifa_addr.sa_family) { 68419864Skarels case AF_INET: 68519864Skarels if (in_lnaof(IA_SIN(ifa)->sin_addr) != es->es_host) 68619864Skarels return (EADDRNOTAVAIL); 68719864Skarels break; 688*25610Ssklower #ifdef NS 689*25610Ssklower case AF_NS: 690*25610Ssklower if (IA_SNS(ifa)->sns_addr.x_host.c_host[5] 691*25610Ssklower != es->es_host) 692*25610Ssklower return (EADDRNOTAVAIL); 693*25610Ssklower es->es_nsactive = 1; 694*25610Ssklower break; 695*25610Ssklower #endif 69619864Skarels } 69719864Skarels ifp->if_flags |= IFF_UP; 69819864Skarels if ((ifp->if_flags & IFF_RUNNING) == 0) 69913054Ssam eninit(ifp->if_unit); 70013054Ssam break; 70113054Ssam 70213054Ssam default: 70313054Ssam error = EINVAL; 70424790Skarels break; 70513054Ssam } 70613054Ssam splx(s); 70713054Ssam return (error); 70813054Ssam } 70913054Ssam 71013293Ssam #ifdef ENF_SWABIPS 71113293Ssam /* 71213293Ssam * Swab bytes 71313293Ssam * Jeffrey Mogul, Stanford 71413293Ssam */ 71513293Ssam enswab(from, to, n) 71619864Skarels register unsigned char *from, *to; 71713293Ssam register int n; 71813293Ssam { 71913293Ssam register unsigned long temp; 72019864Skarels 72119864Skarels if ((n <= 0) || (n > 0xFFFF)) { 72219864Skarels printf("enswab: bad len %d\n", n); 72319864Skarels return; 72419864Skarels } 72513293Ssam 72613293Ssam n >>= 1; n++; 72719864Skarels #define STEP {temp = *from++;*to++ = *from++;*to++ = temp;} 72813293Ssam /* round to multiple of 8 */ 72913293Ssam while ((--n) & 07) 73013293Ssam STEP; 73113293Ssam n >>= 3; 73213293Ssam while (--n >= 0) { 73313293Ssam STEP; STEP; STEP; STEP; 73413293Ssam STEP; STEP; STEP; STEP; 73513293Ssam } 73613293Ssam } 73713293Ssam #endif 73825272Sbloom #endif 739