123166Smckusick /* 229079Smckusick * Copyright (c) 1982, 1986 Regents of the University of California. 323166Smckusick * All rights reserved. The Berkeley software License Agreement 423166Smckusick * specifies the terms and conditions for redistribution. 523166Smckusick * 6*33427Skarels * @(#)if_imp.c 7.3 (Berkeley) 02/03/88 723166Smckusick */ 85640Sroot 95640Sroot #include "imp.h" 105640Sroot #if NIMP > 0 115640Sroot /* 126582Ssam * ARPANET IMP interface driver. 135640Sroot * 145640Sroot * The IMP-host protocol is handled here, leaving 155640Sroot * hardware specifics to the lower level interface driver. 165640Sroot */ 179800Ssam #include "../machine/pte.h" 189800Ssam 1917068Sbloom #include "param.h" 2017068Sbloom #include "systm.h" 2117068Sbloom #include "mbuf.h" 2217068Sbloom #include "buf.h" 2317068Sbloom #include "protosw.h" 2417068Sbloom #include "socket.h" 2517068Sbloom #include "vmmac.h" 2617068Sbloom #include "time.h" 2717068Sbloom #include "kernel.h" 2817068Sbloom #include "errno.h" 2917068Sbloom #include "ioctl.h" 30*33427Skarels #include "syslog.h" 318705Sroot 328705Sroot #include "../vax/cpu.h" 338533Sroot #include "../vax/mtpr.h" 348782Sroot #include "../vaxuba/ubareg.h" 358782Sroot #include "../vaxuba/ubavar.h" 368705Sroot 378705Sroot #include "../net/if.h" 388705Sroot #include "../net/route.h" 3910899Ssam 408705Sroot #include "../net/netisr.h" 418408Swnj #include "../netinet/in.h" 428408Swnj #include "../netinet/in_systm.h" 4318412Skarels #include "../netinet/in_var.h" 448705Sroot #include "../netinet/ip.h" 458705Sroot #include "../netinet/ip_var.h" 46*33427Skarels #define IMPMESSAGES 477199Ssam /* define IMPLEADERS here to get leader printing code */ 48*33427Skarels #define IMPLEADERS 49*33427Skarels #define IMPINIT 5017068Sbloom #include "if_imp.h" 5117068Sbloom #include "if_imphost.h" 525640Sroot 53*33427Skarels struct imp_softc imp_softc[NIMP]; 5428849Skarels struct ifqueue impintrq; 5528849Skarels int impqmaxlen = IFQ_MAXLEN; 56*33427Skarels int imphqlen = 12; /* max packets to queue per host */ 5724777Skarels 58*33427Skarels int imppri = LOG_ERR; 59*33427Skarels #ifdef IMPLEADERS 60*33427Skarels int impprintfs = 0; 61*33427Skarels #endif 62*33427Skarels #ifdef IMPINIT 63*33427Skarels int imptraceinit = 0; 64*33427Skarels #endif 655640Sroot 66*33427Skarels #define HOSTDEADTIMER (30 * PR_SLOWHZ) /* How long to wait when down */ 6718132Skarels 6813067Ssam int impdown(), impinit(), impioctl(), impoutput(); 695771Swnj 705640Sroot /* 715640Sroot * IMP attach routine. Called from hardware device attach routine 72*33427Skarels * at configuration time with a pointer to the device structure. 735640Sroot * Sets up local state and returns pointer to base of ifnet+impcb 745640Sroot * structures. This is then used by the device's attach routine 755640Sroot * set up its back pointers. 765640Sroot */ 77*33427Skarels struct imp_softc * 788815Sroot impattach(ui, reset) 795640Sroot struct uba_device *ui; 808815Sroot int (*reset)(); 815640Sroot { 8224777Skarels struct imp_softc *sc; 8324777Skarels register struct ifnet *ifp; 84*33427Skarels static int impunit; 855640Sroot 8626397Skarels #ifdef lint 8726397Skarels impintr(); 8826397Skarels #endif 89*33427Skarels if (impunit >= NIMP) { 90*33427Skarels printf("imp%d: not configured\n", impunit++); 9124777Skarels return (0); 9224777Skarels } 93*33427Skarels sc = &imp_softc[impunit]; 9424777Skarels ifp = &sc->imp_if; 95*33427Skarels sc->imp_cb.ic_hwunit = ui->ui_unit; 96*33427Skarels sc->imp_cb.ic_hwname = ui->ui_driver->ud_dname; 97*33427Skarels ifp->if_unit = impunit; 985640Sroot ifp->if_name = "imp"; 996271Sroot ifp->if_mtu = IMPMTU - sizeof(struct imp_leader); 1009001Sroot ifp->if_reset = reset; 1015771Swnj ifp->if_init = impinit; 10213067Ssam ifp->if_ioctl = impioctl; 1035771Swnj ifp->if_output = impoutput; 1045640Sroot if_attach(ifp); 105*33427Skarels impunit++; 106*33427Skarels return (sc); 1075640Sroot } 1085640Sroot 1095640Sroot /* 1105640Sroot * IMP initialization routine: call hardware module to 111*33427Skarels * setup resources, init state and get ready for 1125640Sroot * NOOPs the IMP should send us, and that we want to drop. 1135640Sroot */ 1145640Sroot impinit(unit) 1155640Sroot int unit; 1165640Sroot { 11732570Sbostic int s; 1185640Sroot register struct imp_softc *sc = &imp_softc[unit]; 1195640Sroot 12018412Skarels if (sc->imp_if.if_addrlist == 0) 12113067Ssam return; 12232570Sbostic s = splimp(); 123*33427Skarels #ifdef IMPINIT 124*33427Skarels if (imptraceinit) 125*33427Skarels log(imppri, "impinit\n"); 126*33427Skarels #endif 127*33427Skarels sc->imp_state = IMPS_WINIT; 128*33427Skarels if ((*sc->imp_cb.ic_init)(sc->imp_cb.ic_hwunit) == 0) 1296336Ssam sc->imp_if.if_flags &= ~IFF_UP; 130*33427Skarels impintrq.ifq_maxlen = impqmaxlen; 1316500Ssam splx(s); 1325640Sroot } 1335640Sroot 1345640Sroot /* 1355640Sroot * ARPAnet 1822 input routine. 1365640Sroot * Called from hardware input interrupt routine to handle 1822 1375640Sroot * IMP-host messages. Type 0 messages (non-control) are 1385640Sroot * passed to higher level protocol processors on the basis 1395640Sroot * of link number. Other type messages (control) are handled here. 1405640Sroot */ 1415771Swnj impinput(unit, m) 1425640Sroot int unit; 1435771Swnj register struct mbuf *m; 1445640Sroot { 145*33427Skarels register struct control_leader *cp; 146*33427Skarels #define ip ((struct imp_leader *)cp) 1475640Sroot register struct imp_softc *sc = &imp_softc[unit]; 14824777Skarels struct ifnet *ifp; 1495640Sroot register struct host *hp; 1505640Sroot register struct ifqueue *inq; 1515924Sroot struct mbuf *next; 1526336Ssam struct sockaddr_in *sin; 1535640Sroot 15424777Skarels /* 15524777Skarels * Pull the interface pointer out of the mbuf 15624777Skarels * and save for later; adjust mbuf to look at rest of data. 15724777Skarels */ 15824777Skarels ifp = *(mtod(m, struct ifnet **)); 15924777Skarels IF_ADJ(m); 1606257Sroot /* verify leader length. */ 1615771Swnj if (m->m_len < sizeof(struct control_leader) && 1625771Swnj (m = m_pullup(m, sizeof(struct control_leader))) == 0) 1635771Swnj return; 1645771Swnj cp = mtod(m, struct control_leader *); 165*33427Skarels if (cp->dl_mtype == IMPTYPE_DATA && 166*33427Skarels m->m_len < sizeof(struct imp_leader)) { 167*33427Skarels if ((m = m_pullup(m, sizeof(struct imp_leader))) == 0) 1685771Swnj return; 169*33427Skarels cp = mtod(m, struct control_leader *); 170*33427Skarels } 1717199Ssam #ifdef IMPLEADERS 1727170Ssam if (impprintfs) 1737170Ssam printleader("impinput", ip); 1747199Ssam #endif 17528849Skarels inq = &impintrq; 1765640Sroot 1776257Sroot /* check leader type */ 178*33427Skarels if (cp->dl_format != IMP_NFF) { 179*33427Skarels sc->imp_garbage++; 1805771Swnj sc->imp_if.if_collisions++; /* XXX */ 181*33427Skarels } else switch (cp->dl_mtype) { 1825640Sroot 1835640Sroot case IMPTYPE_DATA: 18428849Skarels /* 18528849Skarels * Data for a protocol. Dispatch to the appropriate 18628849Skarels * protocol routine (running at software interrupt). 18728849Skarels * If this isn't a raw interface, advance pointer 18828849Skarels * into mbuf past leader. 18928849Skarels */ 190*33427Skarels switch (cp->dl_link) { 19128849Skarels 19228849Skarels case IMPLINK_IP: 19328849Skarels m->m_len -= sizeof(struct imp_leader); 19428849Skarels m->m_off += sizeof(struct imp_leader); 19528849Skarels schednetisr(NETISR_IP); 19628849Skarels inq = &ipintrq; 19728849Skarels break; 19828849Skarels 19928849Skarels default: 20028849Skarels break; 20128849Skarels } 2025640Sroot break; 2035640Sroot 2045640Sroot /* 2055640Sroot * IMP leader error. Reset the IMP and discard the packet. 2065640Sroot */ 2075640Sroot case IMPTYPE_BADLEADER: 2085647Ssam /* 2095647Ssam * According to 1822 document, this message 2105647Ssam * will be generated in response to the 2115647Ssam * first noop sent to the IMP after 2125647Ssam * the host resets the IMP interface. 2135647Ssam */ 214*33427Skarels #ifdef IMPINIT 215*33427Skarels if (imptraceinit) 216*33427Skarels log(imppri, "badleader\n"); 217*33427Skarels #endif 2185771Swnj if (sc->imp_state != IMPS_INIT) { 2195924Sroot impmsg(sc, "leader error"); 220*33427Skarels hostreset(unit); 2215647Ssam impnoops(sc); 2225647Ssam } 223*33427Skarels sc->imp_garbage++; 22428849Skarels break; 2255640Sroot 2265640Sroot /* 2275640Sroot * IMP going down. Print message, and if not immediate, 2285640Sroot * set off a timer to insure things will be reset at the 2295640Sroot * appropriate time. 2305640Sroot */ 2315640Sroot case IMPTYPE_DOWN: 232*33427Skarels { int type, when; 233*33427Skarels 234*33427Skarels type = cp->dl_link & IMP_DMASK; 235*33427Skarels when = (cp->dl_link & IMPDOWN_WHENMASK) >> IMPDOWN_WHENSHIFT; 236*33427Skarels #ifdef IMPINIT 237*33427Skarels if (imptraceinit) 238*33427Skarels log(imppri, "input DOWN %s %d\n", 239*33427Skarels impmessage[type], when * IMPDOWN_WHENUNIT); 240*33427Skarels #endif 241*33427Skarels if (type != IMPDOWN_GOING && when) 242*33427Skarels impmsg(sc, "going down %s in %d minutes", 243*33427Skarels (u_int)impmessage[type], when * IMPDOWN_WHENUNIT); 244*33427Skarels else 245*33427Skarels impmsg(sc, "going down %s", (u_int)impmessage[type]); 246*33427Skarels if (sc->imp_state != IMPS_UP) 24728849Skarels break; 248*33427Skarels if (type == IMPDOWN_GOING) { 2495640Sroot sc->imp_state = IMPS_GOINGDOWN; 250*33427Skarels timeout(impdown, (caddr_t)sc, IMPTV_DOWN * hz); 251*33427Skarels } else if (when == 0) 252*33427Skarels sc->imp_state = IMPS_WINIT; 253*33427Skarels sc->imp_dropcnt = 0; 25428849Skarels break; 255*33427Skarels } 2565640Sroot 2575640Sroot /* 258*33427Skarels * A NOP, usually seen during the initialization sequence. 2595640Sroot * Compare the local address with that in the message. 2605640Sroot * Reset the local address notion if it doesn't match. 2615640Sroot */ 2626336Ssam case IMPTYPE_NOOP: 263*33427Skarels #ifdef IMPINIT 264*33427Skarels if (imptraceinit) 265*33427Skarels log(imppri, "noop\n"); 266*33427Skarels #endif 267*33427Skarels if (sc->imp_state == IMPS_WINIT) { 268*33427Skarels sc->imp_dropcnt = 0; 269*33427Skarels impnoops(sc); 2705647Ssam sc->imp_state = IMPS_INIT; 2715647Ssam } 272*33427Skarels sc->imp_dropcnt++; 273*33427Skarels if (sc->imp_state == IMPS_INIT && cp->dl_imp != 0) { 27418132Skarels struct in_addr leader_addr; 27528849Skarels 276*33427Skarels sin = (struct sockaddr_in *)&sc->imp_if.if_addrlist->ifa_addr; 277*33427Skarels imp_leader_to_addr(&leader_addr, cp, &sc->imp_if); 27818412Skarels if (sin->sin_addr.s_addr != leader_addr.s_addr) { 27918412Skarels impmsg(sc, "address reset to x%x (%d/%d)", 28028849Skarels ntohl(leader_addr.s_addr), 281*33427Skarels (u_int)cp->dl_host, 282*33427Skarels ntohs(cp->dl_imp)); 28318132Skarels sin->sin_addr.s_addr = leader_addr.s_addr; 28418132Skarels } 2856500Ssam } 28628849Skarels break; 2875640Sroot 2885640Sroot /* 2896582Ssam * RFNM or INCOMPLETE message, send next 2906582Ssam * message on the q. We could pass incomplete's 2916582Ssam * up to the next level, but this currently isn't 2926582Ssam * needed. 2935640Sroot */ 294*33427Skarels case IMPTYPE_INCOMPLETE: 295*33427Skarels sc->imp_incomplete++; 296*33427Skarels /* FALL THROUGH */ 2975640Sroot case IMPTYPE_RFNM: 298*33427Skarels if (hp = hostlookup(cp->dl_imp, cp->dl_host, unit)) { 2996588Ssam if (hp->h_rfnm == 0) 300*33427Skarels sc->imp_badrfnm++; 301*33427Skarels else if (--hp->h_rfnm == 0) { 302*33427Skarels hostfree(hp); 303*33427Skarels hp->h_timer = HOSTTIMER; 304*33427Skarels } else { 305*33427Skarels hp->h_timer = RFNMTIMER; 306*33427Skarels HOST_DEQUE(hp, next); 307*33427Skarels if (next) 308*33427Skarels (void) impsnd(&sc->imp_if, next); 309*33427Skarels } 310*33427Skarels goto drop; 311*33427Skarels } else 312*33427Skarels sc->imp_badrfnm++; 313*33427Skarels break; 3145640Sroot 3155640Sroot /* 3165640Sroot * Host or IMP can't be reached. Flush any packets 3175640Sroot * awaiting transmission and release the host structure. 31824777Skarels * Enqueue for notifying protocols at software interrupt time. 3195640Sroot */ 3205640Sroot case IMPTYPE_HOSTDEAD: 32111230Ssam case IMPTYPE_HOSTUNREACH: 322*33427Skarels if (hp = hostlookup(cp->dl_imp, cp->dl_host, unit)) { 323*33427Skarels hp->h_flags |= (1 << (int)cp->dl_mtype); 324*33427Skarels hp->h_rfnm = 0; 32524777Skarels hostfree(hp); 32624777Skarels hp->h_timer = HOSTDEADTIMER; 32724777Skarels } 32828849Skarels break; 3295640Sroot 3305640Sroot /* 3315640Sroot * Error in data. Clear RFNM status for this host and send 3325640Sroot * noops to the IMP to clear the interface. 3335640Sroot */ 33411230Ssam case IMPTYPE_BADDATA: 3355924Sroot impmsg(sc, "data error"); 336*33427Skarels if ((hp = hostlookup(cp->dl_imp, cp->dl_host, unit)) && 337*33427Skarels hp->h_rfnm) { 3385640Sroot hp->h_rfnm = 0; 339*33427Skarels hostfree(hp); 340*33427Skarels } 341*33427Skarels sc->imp_garbage++; 3425640Sroot impnoops(sc); 34328849Skarels break; 3445640Sroot 3455640Sroot /* 3465647Ssam * Interface reset. 3475640Sroot */ 3485640Sroot case IMPTYPE_RESET: 349*33427Skarels #ifdef IMPINIT 350*33427Skarels if (imptraceinit) 351*33427Skarels log(imppri, "reset complete\n"); 352*33427Skarels #endif 353*33427Skarels if (sc->imp_state != IMPS_INIT) { 354*33427Skarels impmsg(sc, "interface reset"); 355*33427Skarels impnoops(sc); 356*33427Skarels } 35718412Skarels /* clear RFNM counts */ 358*33427Skarels hostreset(unit); 359*33427Skarels if (sc->imp_state != IMPS_DOWN) { 360*33427Skarels sc->imp_state = IMPS_UP; 361*33427Skarels sc->imp_if.if_flags |= IFF_UP; 362*33427Skarels #ifdef IMPINIT 363*33427Skarels if (imptraceinit) 364*33427Skarels log(imppri, "IMP UP\n"); 365*33427Skarels #endif 366*33427Skarels } 36728849Skarels break; 3685640Sroot 3695640Sroot default: 370*33427Skarels sc->imp_garbage++; 3715640Sroot sc->imp_if.if_collisions++; /* XXX */ 37228849Skarels break; 3735640Sroot } 3745640Sroot 37528849Skarels if (inq == &impintrq) 37624777Skarels schednetisr(NETISR_IMP); 37724777Skarels /* 37824777Skarels * Re-insert interface pointer in the mbuf chain 37924777Skarels * for the next protocol up. 38024777Skarels */ 38128849Skarels if (M_HASCL(m) && (mtod(m, int) & CLOFSET) < sizeof(struct ifnet *)) { 38228849Skarels struct mbuf *n; 38328849Skarels 38428849Skarels MGET(n, M_DONTWAIT, MT_HEADER); 38528849Skarels if (n == 0) 38628849Skarels goto drop; 38728849Skarels n->m_next = m; 38828849Skarels m = n; 38928849Skarels m->m_len = 0; 39028849Skarels m->m_off = MMINOFF + sizeof(struct ifnet *); 39128849Skarels } 39224777Skarels m->m_off -= sizeof(struct ifnet *); 39324777Skarels m->m_len += sizeof(struct ifnet *); 39424777Skarels *(mtod(m, struct ifnet **)) = ifp; 39528849Skarels 3966208Swnj if (IF_QFULL(inq)) { 3976208Swnj IF_DROP(inq); 3986208Swnj goto drop; 3996208Swnj } 4005640Sroot IF_ENQUEUE(inq, m); 4015640Sroot return; 4025640Sroot 4035640Sroot drop: 4045640Sroot m_freem(m); 405*33427Skarels #undef ip 4065640Sroot } 4075640Sroot 4085647Ssam /* 409*33427Skarels * Restart output for a host that has timed out 410*33427Skarels * while waiting for a RFNM. 411*33427Skarels */ 412*33427Skarels imprestarthost(hp) 413*33427Skarels register struct host *hp; 414*33427Skarels { 415*33427Skarels struct mbuf *next; 416*33427Skarels 417*33427Skarels hp->h_timer = RFNMTIMER; 418*33427Skarels while (hp->h_rfnm < 8) { 419*33427Skarels HOST_DEQUE(hp, next); 420*33427Skarels if (next == 0) 421*33427Skarels break; 422*33427Skarels (void) impsnd(&imp_softc[hp->h_unit].imp_if, next); 423*33427Skarels } 424*33427Skarels } 425*33427Skarels 426*33427Skarels /* 4275647Ssam * Bring the IMP down after notification. 4285647Ssam */ 4295647Ssam impdown(sc) 4305647Ssam struct imp_softc *sc; 4315647Ssam { 43211230Ssam int s = splimp(); 4336208Swnj 434*33427Skarels if (sc->imp_state == IMPS_GOINGDOWN) { 435*33427Skarels sc->imp_state = IMPS_WINIT; 436*33427Skarels impmsg(sc, "marked down"); 437*33427Skarels hostreset(sc->imp_if.if_unit); 438*33427Skarels if_down(&sc->imp_if); 439*33427Skarels } 440*33427Skarels #ifdef IMPINIT 441*33427Skarels else if (imptraceinit) 442*33427Skarels log(imppri, "impdown, state now %d (ignored)\n", sc->imp_state); 443*33427Skarels #endif 44411230Ssam splx(s); 4455647Ssam } 4465647Ssam 44726397Skarels /*VARARGS2*/ 44818132Skarels impmsg(sc, fmt, a1, a2, a3) 4495640Sroot struct imp_softc *sc; 4505640Sroot char *fmt; 4516160Ssam u_int a1; 4525640Sroot { 4536208Swnj 454*33427Skarels log(imppri, "imp%d: %r\n", sc->imp_if.if_unit, fmt, &a1); 4555640Sroot } 4565640Sroot 45724777Skarels struct sockproto impproto = { PF_IMPLINK }; 45824777Skarels struct sockaddr_in impdst = { AF_IMPLINK }; 45924777Skarels struct sockaddr_in impsrc = { AF_IMPLINK }; 46024777Skarels 4615640Sroot /* 46224777Skarels * Pick up the IMP "error" messages enqueued earlier, 46324777Skarels * passing these up to the higher level protocol 46424777Skarels * and the raw interface. 4656582Ssam */ 46624777Skarels impintr() 4676582Ssam { 46824777Skarels register struct mbuf *m; 46924777Skarels register struct control_leader *cp; 47024777Skarels struct ifnet *ifp; 47124777Skarels int s; 4726582Ssam 47324777Skarels for (;;) { 47424777Skarels s = splimp(); 47524777Skarels IF_DEQUEUEIF(&impintrq, m, ifp); 47624777Skarels splx(s); 47724777Skarels if (m == 0) 47824777Skarels return; 47918132Skarels 48024777Skarels cp = mtod(m, struct control_leader *); 481*33427Skarels imp_leader_to_addr(&impsrc.sin_addr, cp, ifp); 48224777Skarels impproto.sp_protocol = cp->dl_link; 48325409Skarels impdst.sin_addr = IA_SIN(ifp->if_addrlist)->sin_addr; 48424777Skarels 48528849Skarels if (cp->dl_mtype == IMPTYPE_HOSTDEAD || 48628849Skarels cp->dl_mtype == IMPTYPE_HOSTUNREACH) 48728849Skarels switch (cp->dl_link) { 48824777Skarels 48928849Skarels case IMPLINK_IP: 49028849Skarels pfctlinput((int)cp->dl_mtype, 49128849Skarels (struct sockaddr *)&impsrc); 49228849Skarels break; 49328849Skarels default: 49428849Skarels raw_ctlinput((int)cp->dl_mtype, 49528849Skarels (struct sockaddr *)&impsrc); 49628849Skarels break; 49728849Skarels } 49824777Skarels 49924777Skarels raw_input(m, &impproto, (struct sockaddr *)&impsrc, 50024777Skarels (struct sockaddr *)&impdst); 5016588Ssam } 5026582Ssam } 5036582Ssam 5046582Ssam /* 5055640Sroot * ARPAnet 1822 output routine. 5065640Sroot * Called from higher level protocol routines to set up messages for 5075640Sroot * transmission to the imp. Sets up the header and calls impsnd to 5085640Sroot * enqueue the message for this IMP's hardware driver. 5095640Sroot */ 5106336Ssam impoutput(ifp, m0, dst) 5115640Sroot register struct ifnet *ifp; 5125640Sroot struct mbuf *m0; 5136336Ssam struct sockaddr *dst; 5145640Sroot { 5155640Sroot register struct imp_leader *imp; 5165640Sroot register struct mbuf *m = m0; 51718412Skarels int dlink, len; 5186504Ssam int error = 0; 5195640Sroot 5205640Sroot /* 5215640Sroot * Don't even try if the IMP is unavailable. 5225640Sroot */ 523*33427Skarels if (!IMPS_RUNNING(imp_softc[ifp->if_unit].imp_state)) { 5246504Ssam error = ENETDOWN; 5255647Ssam goto drop; 5266504Ssam } 5275640Sroot 5286336Ssam switch (dst->sa_family) { 5295640Sroot 5306336Ssam case AF_INET: { 53124777Skarels struct ip *ip = mtod(m, struct ip *); 5325640Sroot 5335640Sroot dlink = IMPLINK_IP; 5346160Ssam len = ntohs((u_short)ip->ip_len); 5355640Sroot break; 5365640Sroot } 53724777Skarels 5386336Ssam case AF_IMPLINK: 53924777Skarels len = 0; 54024777Skarels do 54124777Skarels len += m->m_len; 54224777Skarels while (m = m->m_next); 54324777Skarels m = m0; 5445640Sroot goto leaderexists; 5455640Sroot 5465640Sroot default: 5476336Ssam printf("imp%d: can't handle af%d\n", ifp->if_unit, 5486336Ssam dst->sa_family); 5496504Ssam error = EAFNOSUPPORT; 5505647Ssam goto drop; 5515640Sroot } 5525640Sroot 5535640Sroot /* 5545640Sroot * Add IMP leader. If there's not enough space in the 5555640Sroot * first mbuf, allocate another. If that should fail, we 5565640Sroot * drop this sucker. 5575640Sroot */ 5585640Sroot if (m->m_off > MMAXOFF || 5595640Sroot MMINOFF + sizeof(struct imp_leader) > m->m_off) { 5609645Ssam m = m_get(M_DONTWAIT, MT_HEADER); 5616504Ssam if (m == 0) { 5626504Ssam error = ENOBUFS; 5635647Ssam goto drop; 5646504Ssam } 5655640Sroot m->m_next = m0; 5665640Sroot m->m_len = sizeof(struct imp_leader); 5675640Sroot } else { 5685640Sroot m->m_off -= sizeof(struct imp_leader); 5695640Sroot m->m_len += sizeof(struct imp_leader); 5705640Sroot } 5715640Sroot imp = mtod(m, struct imp_leader *); 5725640Sroot imp->il_format = IMP_NFF; 5735859Sroot imp->il_mtype = IMPTYPE_DATA; 574*33427Skarels imp_addr_to_leader((struct control_leader *)imp, 57518412Skarels ((struct sockaddr_in *)dst)->sin_addr.s_addr); /* BRL */ 57618412Skarels imp->il_length = htons((u_short)len << 3); /* BRL */ 5775640Sroot imp->il_link = dlink; 5785859Sroot imp->il_flags = imp->il_htype = imp->il_subtype = 0; 5795640Sroot 5805640Sroot leaderexists: 5815640Sroot return (impsnd(ifp, m)); 5825647Ssam drop: 5835647Ssam m_freem(m0); 5846504Ssam return (error); 5855640Sroot } 5865640Sroot 5875640Sroot /* 5885640Sroot * Put a message on an interface's output queue. 5895640Sroot * Perform RFNM counting: no more than 8 message may be 5905640Sroot * in flight to any one host. 5915640Sroot */ 5925640Sroot impsnd(ifp, m) 5935640Sroot struct ifnet *ifp; 5945640Sroot struct mbuf *m; 5955640Sroot { 596*33427Skarels register struct control_leader *imp; 5975640Sroot register struct host *hp; 5985640Sroot struct impcb *icp; 5996588Ssam int s, error; 6005640Sroot 601*33427Skarels imp = mtod(m, struct control_leader *); 6025640Sroot 6035640Sroot /* 6045640Sroot * Do RFNM counting for data messages 6055640Sroot * (no more than 8 outstanding to any host) 6065640Sroot */ 6076588Ssam s = splimp(); 608*33427Skarels if (imp->dl_mtype == IMPTYPE_DATA) { 609*33427Skarels hp = hostenter(imp->dl_imp, imp->dl_host, ifp->if_unit); 6106588Ssam if (hp && (hp->h_flags & (HF_DEAD|HF_UNREACH))) { 6116607Ssam error = hp->h_flags&HF_DEAD ? EHOSTDOWN : EHOSTUNREACH; 6126588Ssam hp->h_flags &= ~HF_INUSE; 6136588Ssam goto bad; 6146588Ssam } 6155640Sroot 6165640Sroot /* 6175647Ssam * If IMP would block, queue until RFNM 6185640Sroot */ 6195640Sroot if (hp) { 620*33427Skarels if (hp->h_rfnm < 8) { 621*33427Skarels if (hp->h_rfnm++ == 0) 622*33427Skarels hp->h_timer = RFNMTIMER; 6235640Sroot goto enque; 6245640Sroot } 625*33427Skarels if (hp->h_qcnt < imphqlen) { /* high water mark */ 6266095Swnj HOST_ENQUE(hp, m); 6276095Swnj goto start; 6286095Swnj } 6295640Sroot } 6306588Ssam error = ENOBUFS; 6316588Ssam goto bad; 6325640Sroot } 6335640Sroot enque: 6346208Swnj if (IF_QFULL(&ifp->if_snd)) { 6356208Swnj IF_DROP(&ifp->if_snd); 6366588Ssam error = ENOBUFS; 637*33427Skarels if (imp->dl_mtype == IMPTYPE_DATA) 63824777Skarels hp->h_rfnm--; 6396588Ssam bad: 6406208Swnj m_freem(m); 6416588Ssam splx(s); 6426588Ssam return (error); 6436208Swnj } 6445640Sroot IF_ENQUEUE(&ifp->if_snd, m); 6456095Swnj start: 6465640Sroot icp = &imp_softc[ifp->if_unit].imp_cb; 6475640Sroot if (icp->ic_oactive == 0) 648*33427Skarels (*icp->ic_start)(icp->ic_hwunit); 6496630Ssam splx(s); 6506504Ssam return (0); 6515640Sroot } 6525640Sroot 6535640Sroot /* 6545640Sroot * Put three 1822 NOOPs at the head of the output queue. 6555640Sroot * Part of host-IMP initialization procedure. 6565640Sroot * (Should return success/failure, but noone knows 6575640Sroot * what to do with this, so why bother?) 6586818Ssam * This routine is always called at splimp, so we don't 6596818Ssam * protect the call to IF_PREPEND. 6605640Sroot */ 6615640Sroot impnoops(sc) 6625640Sroot register struct imp_softc *sc; 6635640Sroot { 6645640Sroot register i; 6655640Sroot register struct mbuf *m; 6665771Swnj register struct control_leader *cp; 6675640Sroot 668*33427Skarels #ifdef IMPINIT 669*33427Skarels if (imptraceinit) 670*33427Skarels log(imppri, "impnoops\n"); 671*33427Skarels #endif 672*33427Skarels for (i = 0; i < IMP_NOOPCNT; i++) { 6739645Ssam if ((m = m_getclr(M_DONTWAIT, MT_HEADER)) == 0) 6745640Sroot return; 6755771Swnj m->m_len = sizeof(struct control_leader); 6765771Swnj cp = mtod(m, struct control_leader *); 6775771Swnj cp->dl_format = IMP_NFF; 678*33427Skarels cp->dl_link = i; 679*33427Skarels cp->dl_mtype = IMPTYPE_NOOP; 6805640Sroot IF_PREPEND(&sc->imp_if.if_snd, m); 6815640Sroot } 6825640Sroot if (sc->imp_cb.ic_oactive == 0) 683*33427Skarels (*sc->imp_cb.ic_start)(sc->imp_cb.ic_hwunit); 6845640Sroot } 6857170Ssam 68613067Ssam /* 68713067Ssam * Process an ioctl request. 68813067Ssam */ 68913067Ssam impioctl(ifp, cmd, data) 69013067Ssam register struct ifnet *ifp; 69113067Ssam int cmd; 69213067Ssam caddr_t data; 69313067Ssam { 69418412Skarels struct ifaddr *ifa = (struct ifaddr *) data; 69513067Ssam int s = splimp(), error = 0; 696*33427Skarels #define sc ((struct imp_softc *)ifp) 69713067Ssam 69813067Ssam switch (cmd) { 69913067Ssam 70013067Ssam case SIOCSIFADDR: 70118412Skarels if (ifa->ifa_addr.sa_family != AF_INET) { 70218412Skarels error = EINVAL; 70318412Skarels break; 70418412Skarels } 705*33427Skarels if ((ifp->if_flags & IFF_UP) == 0) 70613067Ssam impinit(ifp->if_unit); 70713067Ssam break; 70813067Ssam 709*33427Skarels case SIOCSIFFLAGS: 710*33427Skarels if ((ifp->if_flags & IFF_UP) == 0 && 711*33427Skarels sc->imp_state != IMPS_DOWN) { 712*33427Skarels if (sc->imp_cb.ic_stop && 713*33427Skarels (*sc->imp_cb.ic_stop)(sc->imp_cb.ic_hwunit)) 714*33427Skarels sc->imp_state = IMPS_DOWN; 715*33427Skarels } else if (ifp->if_flags & IFF_UP && sc->imp_state == IMPS_DOWN) 716*33427Skarels impinit(ifp->if_unit); 717*33427Skarels break; 718*33427Skarels 71913067Ssam default: 72013067Ssam error = EINVAL; 721*33427Skarels break; 72213067Ssam } 72313067Ssam splx(s); 72413067Ssam return (error); 72513067Ssam } 72613067Ssam 7277170Ssam #ifdef IMPLEADERS 7287170Ssam printleader(routine, ip) 7297170Ssam char *routine; 7307170Ssam register struct imp_leader *ip; 7317170Ssam { 7327170Ssam printf("%s: ", routine); 7337170Ssam printbyte((char *)ip, 12); 7347170Ssam printf("<fmt=%x,net=%x,flags=%x,mtype=", ip->il_format, ip->il_network, 7357170Ssam ip->il_flags); 7367170Ssam if (ip->il_mtype <= IMPTYPE_READY) 7377170Ssam printf("%s,", impleaders[ip->il_mtype]); 7387170Ssam else 7397170Ssam printf("%x,", ip->il_mtype); 7407170Ssam printf("htype=%x,host=%x,imp=%x,link=", ip->il_htype, ip->il_host, 7417170Ssam ntohs(ip->il_imp)); 7427170Ssam if (ip->il_link == IMPLINK_IP) 7437170Ssam printf("ip,"); 7447170Ssam else 7457170Ssam printf("%x,", ip->il_link); 7467170Ssam printf("subtype=%x,len=%x>\n",ip->il_subtype,ntohs(ip->il_length)>>3); 7477170Ssam } 7487170Ssam 7497170Ssam printbyte(cp, n) 7507170Ssam register char *cp; 7517170Ssam int n; 7527170Ssam { 7537170Ssam register i, j, c; 7547170Ssam 7557170Ssam for (i=0; i<n; i++) { 7567170Ssam c = *cp++; 7577170Ssam for (j=0; j<2; j++) 75824777Skarels putchar("0123456789abcdef"[(c>>((1-j)*4))&0xf], 0); 75924777Skarels putchar(' ', 0); 7607170Ssam } 76124777Skarels putchar('\n', 0); 7627170Ssam } 7635640Sroot #endif 76418132Skarels 76518132Skarels /* 76618132Skarels * Routine to convert from IMP Leader to InterNet Address. 76718132Skarels * 76818132Skarels * This procedure is necessary because IMPs may be assigned Class A, B, or C 76918132Skarels * network numbers, but only have 8 bits in the leader to reflect the 77018132Skarels * IMP "network number". The strategy is to take the network number from 77118132Skarels * the ifnet structure, and blend in the host-on-imp and imp-on-net numbers 77218132Skarels * from the leader. 77318132Skarels * 77418132Skarels * There is no support for "Logical Hosts". 77518132Skarels * 77618132Skarels * Class A: Net.Host.0.Imp 77718132Skarels * Class B: Net.net.Host.Imp 77818132Skarels * Class C: Net.net.net.(Host4|Imp4) 77918132Skarels */ 780*33427Skarels imp_leader_to_addr(ap, cp, ifp) 78118412Skarels struct in_addr *ap; 782*33427Skarels register struct control_leader *cp; 78318412Skarels struct ifnet *ifp; 78418132Skarels { 78526397Skarels register u_long final; 78618132Skarels register struct sockaddr_in *sin; 787*33427Skarels int imp = ntohs(cp->dl_imp); 78818132Skarels 78918412Skarels sin = (struct sockaddr_in *)(&ifp->if_addrlist->ifa_addr); 79028849Skarels final = ntohl(sin->sin_addr.s_addr); 79118132Skarels 79218412Skarels if (IN_CLASSA(final)) { 79318132Skarels final &= IN_CLASSA_NET; 794*33427Skarels final |= (imp & 0xFF) | ((cp->dl_host & 0xFF)<<16); 79518412Skarels } else if (IN_CLASSB(final)) { 79618132Skarels final &= IN_CLASSB_NET; 797*33427Skarels final |= (imp & 0xFF) | ((cp->dl_host & 0xFF)<<8); 79818132Skarels } else { 79918132Skarels final &= IN_CLASSC_NET; 800*33427Skarels final |= (imp & 0x0F) | ((cp->dl_host & 0x0F)<<4); 80118132Skarels } 80218412Skarels ap->s_addr = htonl(final); 80318132Skarels } 80418132Skarels 80518132Skarels /* 80618132Skarels * Function to take InterNet address and fill in IMP leader fields. 80718132Skarels */ 80818412Skarels imp_addr_to_leader(imp, a) 809*33427Skarels register struct control_leader *imp; 81026397Skarels u_long a; 81118132Skarels { 81228849Skarels register u_long addr = ntohl(a); 81318132Skarels 814*33427Skarels imp->dl_network = 0; /* !! */ 81518132Skarels 81618412Skarels if (IN_CLASSA(addr)) { 817*33427Skarels imp->dl_host = ((addr>>16) & 0xFF); 818*33427Skarels imp->dl_imp = addr & 0xFF; 81918412Skarels } else if (IN_CLASSB(addr)) { 820*33427Skarels imp->dl_host = ((addr>>8) & 0xFF); 821*33427Skarels imp->dl_imp = addr & 0xFF; 82218132Skarels } else { 823*33427Skarels imp->dl_host = ((addr>>4) & 0xF); 824*33427Skarels imp->dl_imp = addr & 0xF; 82518132Skarels } 826*33427Skarels imp->dl_imp = htons(imp->dl_imp); 82718132Skarels } 8287170Ssam #endif 829