xref: /csrg-svn/sys/deprecated/netimp/if_imp.c (revision 32570)
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*32570Sbostic  *	@(#)if_imp.c	7.2 (Berkeley) 10/31/87
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"
308705Sroot 
318705Sroot #include "../vax/cpu.h"
328533Sroot #include "../vax/mtpr.h"
338782Sroot #include "../vaxuba/ubareg.h"
348782Sroot #include "../vaxuba/ubavar.h"
358705Sroot 
368705Sroot #include "../net/if.h"
378705Sroot #include "../net/route.h"
3810899Ssam 
398705Sroot #include "../net/netisr.h"
408408Swnj #include "../netinet/in.h"
418408Swnj #include "../netinet/in_systm.h"
4218412Skarels #include "../netinet/in_var.h"
438705Sroot #include "../netinet/ip.h"
448705Sroot #include "../netinet/ip_var.h"
457199Ssam /* define IMPLEADERS here to get leader printing code */
4617068Sbloom #include "if_imp.h"
4717068Sbloom #include "if_imphost.h"
485640Sroot 
495640Sroot /*
505640Sroot  * IMP software status per interface.
515640Sroot  * (partially shared with the hardware specific module)
525640Sroot  *
535640Sroot  * Each interface is referenced by a network interface structure,
545640Sroot  * imp_if, which the routing code uses to locate the interface.
555640Sroot  * This structure contains the output queue for the interface, its
565640Sroot  * address, ...  IMP specific structures used in connecting the
575640Sroot  * IMP software modules to the hardware specific interface routines
585771Swnj  * are stored here.  The common structures are made visible to the
595771Swnj  * interface driver by passing a pointer to the hardware routine
605771Swnj  * at "attach" time.
615640Sroot  *
625640Sroot  * NOTE: imp_if and imp_cb are assumed adjacent in hardware code.
635640Sroot  */
645640Sroot struct imp_softc {
655640Sroot 	struct	ifnet imp_if;		/* network visible interface */
665640Sroot 	struct	impcb imp_cb;		/* hooks to hardware module */
675640Sroot 	u_char	imp_state;		/* current state of IMP */
685640Sroot 	char	imp_dropcnt;		/* used during initialization */
695640Sroot } imp_softc[NIMP];
705640Sroot 
7128849Skarels struct	ifqueue impintrq;
7228849Skarels int	impqmaxlen = IFQ_MAXLEN;
7324777Skarels 
745640Sroot /*
755640Sroot  * Messages from IMP regarding why
765640Sroot  * it's going down.
775640Sroot  */
785924Sroot static char *impmessage[] = {
795640Sroot 	"in 30 seconds",
805640Sroot 	"for hardware PM",
815640Sroot 	"to reload software",
825640Sroot 	"for emergency reset"
835640Sroot };
845640Sroot 
8518132Skarels #define HOSTDEADTIMER	10		/* How long to wait when down */
8618132Skarels 
8713067Ssam int	impdown(), impinit(), impioctl(), impoutput();
885771Swnj 
895640Sroot /*
905640Sroot  * IMP attach routine.  Called from hardware device attach routine
915640Sroot  * at configuration time with a pointer to the UNIBUS device structure.
925640Sroot  * Sets up local state and returns pointer to base of ifnet+impcb
935640Sroot  * structures.  This is then used by the device's attach routine
945640Sroot  * set up its back pointers.
955640Sroot  */
968815Sroot impattach(ui, reset)
975640Sroot 	struct uba_device *ui;
988815Sroot 	int (*reset)();
995640Sroot {
10024777Skarels 	struct imp_softc *sc;
10124777Skarels 	register struct ifnet *ifp;
1025640Sroot 
10326397Skarels #ifdef lint
10426397Skarels 	impintr();
10526397Skarels #endif
10624777Skarels 	if (ui->ui_unit >= NIMP) {
10724777Skarels 		printf("imp%d: not configured\n", ui->ui_unit);
10824777Skarels 		return (0);
10924777Skarels 	}
11024777Skarels 	sc = &imp_softc[ui->ui_unit];
11124777Skarels 	ifp = &sc->imp_if;
1125640Sroot 	/* UNIT COULD BE AMBIGUOUS */
1135640Sroot 	ifp->if_unit = ui->ui_unit;
1145640Sroot 	ifp->if_name = "imp";
1156271Sroot 	ifp->if_mtu = IMPMTU - sizeof(struct imp_leader);
1169001Sroot 	ifp->if_reset = reset;
1175771Swnj 	ifp->if_init = impinit;
11813067Ssam 	ifp->if_ioctl = impioctl;
1195771Swnj 	ifp->if_output = impoutput;
1205771Swnj 	/* reset is handled at the hardware level */
1215640Sroot 	if_attach(ifp);
12224777Skarels 	return ((int)ifp);
1235640Sroot }
1245640Sroot 
1255640Sroot /*
1265640Sroot  * IMP initialization routine: call hardware module to
1275640Sroot  * setup UNIBUS resources, init state and get ready for
1285640Sroot  * NOOPs the IMP should send us, and that we want to drop.
1295640Sroot  */
1305640Sroot impinit(unit)
1315640Sroot 	int unit;
1325640Sroot {
133*32570Sbostic 	int s;
1345640Sroot 	register struct imp_softc *sc = &imp_softc[unit];
1355640Sroot 
13618412Skarels 	if (sc->imp_if.if_addrlist == 0)
13713067Ssam 		return;
138*32570Sbostic 	s = splimp();
1395771Swnj 	if ((*sc->imp_cb.ic_init)(unit) == 0) {
1405771Swnj 		sc->imp_state = IMPS_DOWN;
1416336Ssam 		sc->imp_if.if_flags &= ~IFF_UP;
142*32570Sbostic 	} else {
143*32570Sbostic 		sc->imp_state = IMPS_INIT;
144*32570Sbostic 		impnoops(sc);
145*32570Sbostic 		impintrq.ifq_maxlen = impqmaxlen;
1465771Swnj 	}
1476500Ssam 	splx(s);
1485640Sroot }
1495640Sroot 
1507199Ssam #ifdef IMPLEADERS
1517170Ssam int	impprintfs = 0;
1527199Ssam #endif
1535640Sroot 
1545640Sroot /*
1555640Sroot  * ARPAnet 1822 input routine.
1565640Sroot  * Called from hardware input interrupt routine to handle 1822
1575640Sroot  * IMP-host messages.  Type 0 messages (non-control) are
1585640Sroot  * passed to higher level protocol processors on the basis
1595640Sroot  * of link number.  Other type messages (control) are handled here.
1605640Sroot  */
1615771Swnj impinput(unit, m)
1625640Sroot 	int unit;
1635771Swnj 	register struct mbuf *m;
1645640Sroot {
1655640Sroot 	register struct imp_leader *ip;
1665640Sroot 	register struct imp_softc *sc = &imp_softc[unit];
16724777Skarels 	struct ifnet *ifp;
1685640Sroot 	register struct host *hp;
1695640Sroot 	register struct ifqueue *inq;
1705771Swnj 	struct control_leader *cp;
1715640Sroot 	struct in_addr addr;
1725924Sroot 	struct mbuf *next;
1736336Ssam 	struct sockaddr_in *sin;
1745640Sroot 
17524777Skarels 	/*
17624777Skarels 	 * Pull the interface pointer out of the mbuf
17724777Skarels 	 * and save for later; adjust mbuf to look at rest of data.
17824777Skarels 	 */
17924777Skarels 	ifp = *(mtod(m, struct ifnet **));
18024777Skarels 	IF_ADJ(m);
1816257Sroot 	/* verify leader length. */
1825771Swnj 	if (m->m_len < sizeof(struct control_leader) &&
1835771Swnj 	    (m = m_pullup(m, sizeof(struct control_leader))) == 0)
1845771Swnj 		return;
1855771Swnj 	cp = mtod(m, struct control_leader *);
1865771Swnj 	if (cp->dl_mtype == IMPTYPE_DATA)
1875771Swnj 		if (m->m_len < sizeof(struct imp_leader) &&
1885771Swnj 		    (m = m_pullup(m, sizeof(struct imp_leader))) == 0)
1895771Swnj 			return;
1905640Sroot 	ip = mtod(m, struct imp_leader *);
1917199Ssam #ifdef IMPLEADERS
1927170Ssam 	if (impprintfs)
1937170Ssam 		printleader("impinput", ip);
1947199Ssam #endif
19528849Skarels 	inq = &impintrq;
1965640Sroot 
1976257Sroot 	/* check leader type */
1985771Swnj 	if (ip->il_format != IMP_NFF) {
1995771Swnj 		sc->imp_if.if_collisions++;	/* XXX */
20028849Skarels 		goto rawlinkin;
2015771Swnj 	}
2025640Sroot 
2036588Ssam 	if (ip->il_mtype != IMPTYPE_DATA) {
20418132Skarels 		/* If not data packet, build IP addr from leader (BRL) */
20518412Skarels 		imp_leader_to_addr(&addr, ip, &sc->imp_if);
2065640Sroot 	}
20728849Skarels 
2085640Sroot 	switch (ip->il_mtype) {
2095640Sroot 
2105640Sroot 	case IMPTYPE_DATA:
21128849Skarels 		/*
21228849Skarels 		 * Data for a protocol.  Dispatch to the appropriate
21328849Skarels 		 * protocol routine (running at software interrupt).
21428849Skarels 		 * If this isn't a raw interface, advance pointer
21528849Skarels 		 * into mbuf past leader.
21628849Skarels 		 */
21728849Skarels 		switch (ip->il_link) {
21828849Skarels 
21928849Skarels 		case IMPLINK_IP:
22028849Skarels 			m->m_len -= sizeof(struct imp_leader);
22128849Skarels 			m->m_off += sizeof(struct imp_leader);
22228849Skarels 			schednetisr(NETISR_IP);
22328849Skarels 			inq = &ipintrq;
22428849Skarels 			break;
22528849Skarels 
22628849Skarels 		default:
22728849Skarels 			break;
22828849Skarels 		}
2295640Sroot 		break;
2305640Sroot 
2315640Sroot 	/*
2325640Sroot 	 * IMP leader error.  Reset the IMP and discard the packet.
2335640Sroot 	 */
2345640Sroot 	case IMPTYPE_BADLEADER:
2355647Ssam 		/*
2365647Ssam 		 * According to 1822 document, this message
2375647Ssam 		 * will be generated in response to the
2385647Ssam 		 * first noop sent to the IMP after
2395647Ssam 		 * the host resets the IMP interface.
2405647Ssam 		 */
2415771Swnj 		if (sc->imp_state != IMPS_INIT) {
2425924Sroot 			impmsg(sc, "leader error");
24318412Skarels 			hostreset(((struct in_ifaddr *)&sc->imp_if.if_addrlist)->ia_net);
2445647Ssam 			impnoops(sc);
2455647Ssam 		}
24628849Skarels 		break;
2475640Sroot 
2485640Sroot 	/*
2495640Sroot 	 * IMP going down.  Print message, and if not immediate,
2505640Sroot 	 * set off a timer to insure things will be reset at the
2515640Sroot 	 * appropriate time.
2525640Sroot 	 */
2535640Sroot 	case IMPTYPE_DOWN:
2546599Ssam 		if (sc->imp_state < IMPS_INIT)
25528849Skarels 			break;
2565640Sroot 		if ((ip->il_link & IMP_DMASK) == 0) {
2575640Sroot 			sc->imp_state = IMPS_GOINGDOWN;
2586160Ssam 			timeout(impdown, (caddr_t)sc, 30 * hz);
2595640Sroot 		}
2606160Ssam 		impmsg(sc, "going down %s",
2616160Ssam 			(u_int)impmessage[ip->il_link&IMP_DMASK]);
26228849Skarels 		break;
2635640Sroot 
2645640Sroot 	/*
2655640Sroot 	 * A NOP usually seen during the initialization sequence.
2665640Sroot 	 * Compare the local address with that in the message.
2675640Sroot 	 * Reset the local address notion if it doesn't match.
2685640Sroot 	 */
2696336Ssam 	case IMPTYPE_NOOP:
2705647Ssam 		if (sc->imp_state == IMPS_DOWN) {
2715647Ssam 			sc->imp_state = IMPS_INIT;
2725647Ssam 			sc->imp_dropcnt = IMP_DROPCNT;
2735647Ssam 		}
2746500Ssam 		if (sc->imp_state == IMPS_INIT && --sc->imp_dropcnt > 0)
27528849Skarels 			break;
27618412Skarels 		sin = (struct sockaddr_in *)&sc->imp_if.if_addrlist->ifa_addr;
27728849Skarels 		if (ip->il_imp != 0) {
27818132Skarels 			struct in_addr leader_addr;
27928849Skarels 
28018412Skarels 			imp_leader_to_addr(&leader_addr, ip, &sc->imp_if);
28118412Skarels 			if (sin->sin_addr.s_addr != leader_addr.s_addr) {
28218412Skarels 				impmsg(sc, "address reset to x%x (%d/%d)",
28328849Skarels 					ntohl(leader_addr.s_addr),
28418132Skarels 					(u_int)ip->il_host,
28528849Skarels 					ntohs(ip->il_imp));
28618132Skarels 				sin->sin_addr.s_addr = leader_addr.s_addr;
28718132Skarels 			}
2886500Ssam 		}
2895771Swnj 		sc->imp_state = IMPS_UP;
2906336Ssam 		sc->imp_if.if_flags |= IFF_UP;
29128849Skarels 		break;
2925640Sroot 
2935640Sroot 	/*
2946582Ssam 	 * RFNM or INCOMPLETE message, send next
2956582Ssam 	 * message on the q.  We could pass incomplete's
2966582Ssam 	 * up to the next level, but this currently isn't
2976582Ssam 	 * needed.
2985640Sroot 	 */
2995640Sroot 	case IMPTYPE_RFNM:
3005640Sroot 	case IMPTYPE_INCOMPLETE:
3016588Ssam 		if (hp = hostlookup(addr)) {
30224777Skarels 			hp->h_timer = HOSTTIMER;
3036588Ssam 			if (hp->h_rfnm == 0)
3046588Ssam 				hp->h_flags &= ~HF_INUSE;
3056588Ssam 			else if (next = hostdeque(hp))
3066588Ssam 				(void) impsnd(&sc->imp_if, next);
3076588Ssam 		}
3086271Sroot 		goto drop;
3095640Sroot 
3105640Sroot 	/*
3115640Sroot 	 * Host or IMP can't be reached.  Flush any packets
3125640Sroot 	 * awaiting transmission and release the host structure.
31324777Skarels 	 * Enqueue for notifying protocols at software interrupt time.
3145640Sroot 	 */
3155640Sroot 	case IMPTYPE_HOSTDEAD:
31611230Ssam 	case IMPTYPE_HOSTUNREACH:
31724777Skarels 		if (hp = hostlookup(addr)) {
31824777Skarels 			hp->h_flags |= (1 << (int)ip->il_mtype);
31924777Skarels 			hostfree(hp);
32024777Skarels 			hp->h_timer = HOSTDEADTIMER;
32124777Skarels 		}
32228849Skarels 		break;
3235640Sroot 
3245640Sroot 	/*
3255640Sroot 	 * Error in data.  Clear RFNM status for this host and send
3265640Sroot 	 * noops to the IMP to clear the interface.
3275640Sroot 	 */
32811230Ssam 	case IMPTYPE_BADDATA:
3295924Sroot 		impmsg(sc, "data error");
3306588Ssam 		if (hp = hostlookup(addr))
3315640Sroot 			hp->h_rfnm = 0;
3325640Sroot 		impnoops(sc);
33328849Skarels 		break;
3345640Sroot 
3355640Sroot 	/*
3365647Ssam 	 * Interface reset.
3375640Sroot 	 */
3385640Sroot 	case IMPTYPE_RESET:
3395924Sroot 		impmsg(sc, "interface reset");
34018412Skarels 		/* clear RFNM counts */
34118412Skarels 		hostreset(((struct in_ifaddr *)&sc->imp_if.if_addrlist)->ia_net);
3425647Ssam 		impnoops(sc);
34328849Skarels 		break;
3445640Sroot 
3455640Sroot 	default:
3465640Sroot 		sc->imp_if.if_collisions++;		/* XXX */
34728849Skarels 		break;
3485640Sroot 	}
3495640Sroot 
35028849Skarels rawlinkin:
35128849Skarels 	if (inq == &impintrq)
35224777Skarels 		schednetisr(NETISR_IMP);
35324777Skarels 	/*
35424777Skarels 	 * Re-insert interface pointer in the mbuf chain
35524777Skarels 	 * for the next protocol up.
35624777Skarels 	 */
35728849Skarels 	if (M_HASCL(m) && (mtod(m, int) & CLOFSET) < sizeof(struct ifnet *)) {
35828849Skarels 		struct mbuf *n;
35928849Skarels 
36028849Skarels 		MGET(n, M_DONTWAIT, MT_HEADER);
36128849Skarels 		if (n == 0)
36228849Skarels 			goto drop;
36328849Skarels 		n->m_next = m;
36428849Skarels 		m = n;
36528849Skarels 		m->m_len = 0;
36628849Skarels 		m->m_off = MMINOFF + sizeof(struct ifnet  *);
36728849Skarels 	}
36824777Skarels 	m->m_off -= sizeof(struct ifnet *);
36924777Skarels 	m->m_len += sizeof(struct ifnet *);
37024777Skarels 	*(mtod(m, struct ifnet **)) = ifp;
37128849Skarels 
3726208Swnj 	if (IF_QFULL(inq)) {
3736208Swnj 		IF_DROP(inq);
3746208Swnj 		goto drop;
3756208Swnj 	}
3765640Sroot 	IF_ENQUEUE(inq, m);
3775640Sroot 	return;
3785640Sroot 
3795640Sroot drop:
3805640Sroot 	m_freem(m);
3815640Sroot }
3825640Sroot 
3835647Ssam /*
3845647Ssam  * Bring the IMP down after notification.
3855647Ssam  */
3865647Ssam impdown(sc)
3875647Ssam 	struct imp_softc *sc;
3885647Ssam {
38911230Ssam 	int s = splimp();
3906208Swnj 
3915647Ssam 	sc->imp_state = IMPS_DOWN;
3925924Sroot 	impmsg(sc, "marked down");
39318412Skarels 	hostreset(((struct in_ifaddr *)&sc->imp_if.if_addrlist)->ia_net);
3946582Ssam 	if_down(&sc->imp_if);
39511230Ssam 	splx(s);
3965647Ssam }
3975647Ssam 
39826397Skarels /*VARARGS2*/
39918132Skarels impmsg(sc, fmt, a1, a2, a3)
4005640Sroot 	struct imp_softc *sc;
4015640Sroot 	char *fmt;
4026160Ssam 	u_int a1;
4035640Sroot {
4046208Swnj 
4055640Sroot 	printf("imp%d: ", sc->imp_if.if_unit);
40618132Skarels 	printf(fmt, a1, a2, a3);
4075640Sroot 	printf("\n");
4085640Sroot }
4095640Sroot 
41024777Skarels struct sockproto impproto = { PF_IMPLINK };
41124777Skarels struct sockaddr_in impdst = { AF_IMPLINK };
41224777Skarels struct sockaddr_in impsrc = { AF_IMPLINK };
41324777Skarels 
4145640Sroot /*
41524777Skarels  * Pick up the IMP "error" messages enqueued earlier,
41624777Skarels  * passing these up to the higher level protocol
41724777Skarels  * and the raw interface.
4186582Ssam  */
41924777Skarels impintr()
4206582Ssam {
42124777Skarels 	register struct mbuf *m;
42224777Skarels 	register struct control_leader *cp;
42324777Skarels 	struct ifnet *ifp;
42424777Skarels 	int s;
4256582Ssam 
42624777Skarels 	for (;;) {
42724777Skarels 		s = splimp();
42824777Skarels 		IF_DEQUEUEIF(&impintrq, m, ifp);
42924777Skarels 		splx(s);
43024777Skarels 		if (m == 0)
43124777Skarels 			return;
43218132Skarels 
43324777Skarels 		cp = mtod(m, struct control_leader *);
43424777Skarels 		imp_leader_to_addr(&impsrc.sin_addr, (struct imp_leader *)cp,
43524777Skarels 		    ifp);
43624777Skarels 		impproto.sp_protocol = cp->dl_link;
43725409Skarels 		impdst.sin_addr = IA_SIN(ifp->if_addrlist)->sin_addr;
43824777Skarels 
43928849Skarels 		if (cp->dl_mtype == IMPTYPE_HOSTDEAD ||
44028849Skarels 		    cp->dl_mtype == IMPTYPE_HOSTUNREACH)
44128849Skarels 			switch (cp->dl_link) {
44224777Skarels 
44328849Skarels 			case IMPLINK_IP:
44428849Skarels 				pfctlinput((int)cp->dl_mtype,
44528849Skarels 				    (struct sockaddr *)&impsrc);
44628849Skarels 				break;
44728849Skarels 			default:
44828849Skarels 				raw_ctlinput((int)cp->dl_mtype,
44928849Skarels 				    (struct sockaddr *)&impsrc);
45028849Skarels 				break;
45128849Skarels 			}
45224777Skarels 
45324777Skarels 		raw_input(m, &impproto, (struct sockaddr *)&impsrc,
45424777Skarels 		  (struct sockaddr *)&impdst);
4556588Ssam 	}
4566582Ssam }
4576582Ssam 
4586582Ssam /*
4595640Sroot  * ARPAnet 1822 output routine.
4605640Sroot  * Called from higher level protocol routines to set up messages for
4615640Sroot  * transmission to the imp.  Sets up the header and calls impsnd to
4625640Sroot  * enqueue the message for this IMP's hardware driver.
4635640Sroot  */
4646336Ssam impoutput(ifp, m0, dst)
4655640Sroot 	register struct ifnet *ifp;
4665640Sroot 	struct mbuf *m0;
4676336Ssam 	struct sockaddr *dst;
4685640Sroot {
4695640Sroot 	register struct imp_leader *imp;
4705640Sroot 	register struct mbuf *m = m0;
47118412Skarels 	int dlink, len;
4726504Ssam 	int error = 0;
4735640Sroot 
4745640Sroot 	/*
4755640Sroot 	 * Don't even try if the IMP is unavailable.
4765640Sroot 	 */
4776504Ssam 	if (imp_softc[ifp->if_unit].imp_state != IMPS_UP) {
4786504Ssam 		error = ENETDOWN;
4795647Ssam 		goto drop;
4806504Ssam 	}
4815640Sroot 
4826336Ssam 	switch (dst->sa_family) {
4835640Sroot 
4846336Ssam 	case AF_INET: {
48524777Skarels 		struct ip *ip = mtod(m, struct ip *);
4865640Sroot 
4875640Sroot 		dlink = IMPLINK_IP;
4886160Ssam 		len = ntohs((u_short)ip->ip_len);
4895640Sroot 		break;
4905640Sroot 	}
49124777Skarels 
4926336Ssam 	case AF_IMPLINK:
49324777Skarels 		len = 0;
49424777Skarels 		do
49524777Skarels 			len += m->m_len;
49624777Skarels 		while (m = m->m_next);
49724777Skarels 		m = m0;
4985640Sroot 		goto leaderexists;
4995640Sroot 
5005640Sroot 	default:
5016336Ssam 		printf("imp%d: can't handle af%d\n", ifp->if_unit,
5026336Ssam 			dst->sa_family);
5036504Ssam 		error = EAFNOSUPPORT;
5045647Ssam 		goto drop;
5055640Sroot 	}
5065640Sroot 
5075640Sroot 	/*
5085640Sroot 	 * Add IMP leader.  If there's not enough space in the
5095640Sroot 	 * first mbuf, allocate another.  If that should fail, we
5105640Sroot 	 * drop this sucker.
5115640Sroot 	 */
5125640Sroot 	if (m->m_off > MMAXOFF ||
5135640Sroot 	    MMINOFF + sizeof(struct imp_leader) > m->m_off) {
5149645Ssam 		m = m_get(M_DONTWAIT, MT_HEADER);
5156504Ssam 		if (m == 0) {
5166504Ssam 			error = ENOBUFS;
5175647Ssam 			goto drop;
5186504Ssam 		}
5195640Sroot 		m->m_next = m0;
5205640Sroot 		m->m_len = sizeof(struct imp_leader);
5215640Sroot 	} else {
5225640Sroot 		m->m_off -= sizeof(struct imp_leader);
5235640Sroot 		m->m_len += sizeof(struct imp_leader);
5245640Sroot 	}
5255640Sroot 	imp = mtod(m, struct imp_leader *);
5265640Sroot 	imp->il_format = IMP_NFF;
5275859Sroot 	imp->il_mtype = IMPTYPE_DATA;
52818132Skarels 	imp_addr_to_leader(imp,
52918412Skarels 		((struct sockaddr_in *)dst)->sin_addr.s_addr); /* BRL */
53018412Skarels 	imp->il_length = htons((u_short)len << 3);		/* BRL */
5315640Sroot 	imp->il_link = dlink;
5325859Sroot 	imp->il_flags = imp->il_htype = imp->il_subtype = 0;
5335640Sroot 
5345640Sroot leaderexists:
5355640Sroot 	return (impsnd(ifp, m));
5365647Ssam drop:
5375647Ssam 	m_freem(m0);
5386504Ssam 	return (error);
5395640Sroot }
5405640Sroot 
5415640Sroot /*
5425640Sroot  * Put a message on an interface's output queue.
5435640Sroot  * Perform RFNM counting: no more than 8 message may be
5445640Sroot  * in flight to any one host.
5455640Sroot  */
5465640Sroot impsnd(ifp, m)
5475640Sroot 	struct ifnet *ifp;
5485640Sroot 	struct mbuf *m;
5495640Sroot {
5505640Sroot 	register struct imp_leader *ip;
5515640Sroot 	register struct host *hp;
5525640Sroot 	struct impcb *icp;
5536588Ssam 	int s, error;
5545640Sroot 
5555640Sroot 	ip = mtod(m, struct imp_leader *);
5565640Sroot 
5575640Sroot 	/*
5585640Sroot 	 * Do RFNM counting for data messages
5595640Sroot 	 * (no more than 8 outstanding to any host)
5605640Sroot 	 */
5616588Ssam 	s = splimp();
5625640Sroot 	if (ip->il_mtype == IMPTYPE_DATA) {
5635640Sroot 		struct in_addr addr;
5645640Sroot 
56518412Skarels 		imp_leader_to_addr(&addr, ip, ifp);	/* BRL */
5665771Swnj 		if ((hp = hostlookup(addr)) == 0)
5675771Swnj 			hp = hostenter(addr);
5686588Ssam 		if (hp && (hp->h_flags & (HF_DEAD|HF_UNREACH))) {
5696607Ssam 			error = hp->h_flags&HF_DEAD ? EHOSTDOWN : EHOSTUNREACH;
5706588Ssam 			hp->h_flags &= ~HF_INUSE;
5716588Ssam 			goto bad;
5726588Ssam 		}
5735640Sroot 
5745640Sroot 		/*
5755647Ssam 		 * If IMP would block, queue until RFNM
5765640Sroot 		 */
5775640Sroot 		if (hp) {
57824777Skarels #ifndef NORFNM
57918132Skarels 			if (hp->h_rfnm < 8)
58018132Skarels #endif
58118132Skarels 			{
58224777Skarels 				hp->h_timer = HOSTTIMER;
5835640Sroot 				hp->h_rfnm++;
5845640Sroot 				goto enque;
5855640Sroot 			}
5866095Swnj 			if (hp->h_qcnt < 8) {	/* high water mark */
5876095Swnj 				HOST_ENQUE(hp, m);
5886095Swnj 				goto start;
5896095Swnj 			}
5905640Sroot 		}
5916588Ssam 		error = ENOBUFS;
5926588Ssam 		goto bad;
5935640Sroot 	}
5945640Sroot enque:
5956208Swnj 	if (IF_QFULL(&ifp->if_snd)) {
5966208Swnj 		IF_DROP(&ifp->if_snd);
5976588Ssam 		error = ENOBUFS;
59824777Skarels 		if (ip->il_mtype == IMPTYPE_DATA)
59924777Skarels 			hp->h_rfnm--;
6006588Ssam bad:
6016208Swnj 		m_freem(m);
6026588Ssam 		splx(s);
6036588Ssam 		return (error);
6046208Swnj 	}
6055640Sroot 	IF_ENQUEUE(&ifp->if_snd, m);
6066095Swnj start:
6075640Sroot 	icp = &imp_softc[ifp->if_unit].imp_cb;
6085640Sroot 	if (icp->ic_oactive == 0)
6095640Sroot 		(*icp->ic_start)(ifp->if_unit);
6106630Ssam 	splx(s);
6116504Ssam 	return (0);
6125640Sroot }
6135640Sroot 
6145640Sroot /*
6155640Sroot  * Put three 1822 NOOPs at the head of the output queue.
6165640Sroot  * Part of host-IMP initialization procedure.
6175640Sroot  * (Should return success/failure, but noone knows
6185640Sroot  * what to do with this, so why bother?)
6196818Ssam  * This routine is always called at splimp, so we don't
6206818Ssam  * protect the call to IF_PREPEND.
6215640Sroot  */
6225640Sroot impnoops(sc)
6235640Sroot 	register struct imp_softc *sc;
6245640Sroot {
6255640Sroot 	register i;
6265640Sroot 	register struct mbuf *m;
6275771Swnj 	register struct control_leader *cp;
6285640Sroot 
6295640Sroot 	sc->imp_dropcnt = IMP_DROPCNT;
63018412Skarels 	for (i = 0; i < IMP_DROPCNT + 1; i++) {
6319645Ssam 		if ((m = m_getclr(M_DONTWAIT, MT_HEADER)) == 0)
6325640Sroot 			return;
6335771Swnj 		m->m_len = sizeof(struct control_leader);
6345771Swnj 		cp = mtod(m, struct control_leader *);
6355771Swnj 		cp->dl_format = IMP_NFF;
6365771Swnj                 cp->dl_link = i;
6375771Swnj                 cp->dl_mtype = IMPTYPE_NOOP;
6385640Sroot 		IF_PREPEND(&sc->imp_if.if_snd, m);
6395640Sroot 	}
6405640Sroot 	if (sc->imp_cb.ic_oactive == 0)
6415640Sroot 		(*sc->imp_cb.ic_start)(sc->imp_if.if_unit);
6425640Sroot }
6437170Ssam 
64413067Ssam /*
64513067Ssam  * Process an ioctl request.
64613067Ssam  */
64713067Ssam impioctl(ifp, cmd, data)
64813067Ssam 	register struct ifnet *ifp;
64913067Ssam 	int cmd;
65013067Ssam 	caddr_t data;
65113067Ssam {
65218412Skarels 	struct ifaddr *ifa = (struct ifaddr *) data;
65313067Ssam 	int s = splimp(), error = 0;
65413067Ssam 
65513067Ssam 	switch (cmd) {
65613067Ssam 
65713067Ssam 	case SIOCSIFADDR:
65818412Skarels 		if (ifa->ifa_addr.sa_family != AF_INET) {
65918412Skarels 			error = EINVAL;
66018412Skarels 			break;
66118412Skarels 		}
66218412Skarels 		if ((ifp->if_flags & IFF_RUNNING) == 0)
66313067Ssam 			impinit(ifp->if_unit);
66413067Ssam 		break;
66513067Ssam 
66613067Ssam 	default:
66713067Ssam 		error = EINVAL;
66813067Ssam 	}
66913067Ssam 	splx(s);
67013067Ssam 	return (error);
67113067Ssam }
67213067Ssam 
6737170Ssam #ifdef IMPLEADERS
6747170Ssam printleader(routine, ip)
6757170Ssam 	char *routine;
6767170Ssam 	register struct imp_leader *ip;
6777170Ssam {
6787170Ssam 	printf("%s: ", routine);
6797170Ssam 	printbyte((char *)ip, 12);
6807170Ssam 	printf("<fmt=%x,net=%x,flags=%x,mtype=", ip->il_format, ip->il_network,
6817170Ssam 		ip->il_flags);
6827170Ssam 	if (ip->il_mtype <= IMPTYPE_READY)
6837170Ssam 		printf("%s,", impleaders[ip->il_mtype]);
6847170Ssam 	else
6857170Ssam 		printf("%x,", ip->il_mtype);
6867170Ssam 	printf("htype=%x,host=%x,imp=%x,link=", ip->il_htype, ip->il_host,
6877170Ssam 		ntohs(ip->il_imp));
6887170Ssam 	if (ip->il_link == IMPLINK_IP)
6897170Ssam 		printf("ip,");
6907170Ssam 	else
6917170Ssam 		printf("%x,", ip->il_link);
6927170Ssam 	printf("subtype=%x,len=%x>\n",ip->il_subtype,ntohs(ip->il_length)>>3);
6937170Ssam }
6947170Ssam 
6957170Ssam printbyte(cp, n)
6967170Ssam 	register char *cp;
6977170Ssam 	int n;
6987170Ssam {
6997170Ssam 	register i, j, c;
7007170Ssam 
7017170Ssam 	for (i=0; i<n; i++) {
7027170Ssam 		c = *cp++;
7037170Ssam 		for (j=0; j<2; j++)
70424777Skarels 			putchar("0123456789abcdef"[(c>>((1-j)*4))&0xf], 0);
70524777Skarels 		putchar(' ', 0);
7067170Ssam 	}
70724777Skarels 	putchar('\n', 0);
7087170Ssam }
7095640Sroot #endif
71018132Skarels 
71118132Skarels /*
71218132Skarels  * Routine to convert from IMP Leader to InterNet Address.
71318132Skarels  *
71418132Skarels  * This procedure is necessary because IMPs may be assigned Class A, B, or C
71518132Skarels  * network numbers, but only have 8 bits in the leader to reflect the
71618132Skarels  * IMP "network number".  The strategy is to take the network number from
71718132Skarels  * the ifnet structure, and blend in the host-on-imp and imp-on-net numbers
71818132Skarels  * from the leader.
71918132Skarels  *
72018132Skarels  * There is no support for "Logical Hosts".
72118132Skarels  *
72218132Skarels  * Class A:	Net.Host.0.Imp
72318132Skarels  * Class B:	Net.net.Host.Imp
72418132Skarels  * Class C:	Net.net.net.(Host4|Imp4)
72518132Skarels  */
72618412Skarels imp_leader_to_addr(ap, ip, ifp)
72718412Skarels 	struct in_addr *ap;
72818412Skarels 	register struct imp_leader *ip;
72918412Skarels 	struct ifnet *ifp;
73018132Skarels {
73126397Skarels 	register u_long final;
73218132Skarels 	register struct sockaddr_in *sin;
73328849Skarels 	int imp = ntohs(ip->il_imp);
73418132Skarels 
73518412Skarels 	sin = (struct sockaddr_in *)(&ifp->if_addrlist->ifa_addr);
73628849Skarels 	final = ntohl(sin->sin_addr.s_addr);
73718132Skarels 
73818412Skarels 	if (IN_CLASSA(final)) {
73918132Skarels 		final &= IN_CLASSA_NET;
74018132Skarels 		final |= (imp & 0xFF) | ((ip->il_host & 0xFF)<<16);
74118412Skarels 	} else if (IN_CLASSB(final)) {
74218132Skarels 		final &= IN_CLASSB_NET;
74318132Skarels 		final |= (imp & 0xFF) | ((ip->il_host & 0xFF)<<8);
74418132Skarels 	} else {
74518132Skarels 		final &= IN_CLASSC_NET;
74618132Skarels 		final |= (imp & 0x0F) | ((ip->il_host & 0x0F)<<4);
74718132Skarels 	}
74818412Skarels 	ap->s_addr = htonl(final);
74918132Skarels }
75018132Skarels 
75118132Skarels /*
75218132Skarels  * Function to take InterNet address and fill in IMP leader fields.
75318132Skarels  */
75418412Skarels imp_addr_to_leader(imp, a)
75518412Skarels 	register struct imp_leader *imp;
75626397Skarels 	u_long a;
75718132Skarels {
75828849Skarels 	register u_long addr = ntohl(a);
75918132Skarels 
76018132Skarels 	imp->il_network = 0;	/* !! */
76118132Skarels 
76218412Skarels 	if (IN_CLASSA(addr)) {
76318132Skarels 		imp->il_host = ((addr>>16) & 0xFF);
76418132Skarels 		imp->il_imp = addr & 0xFF;
76518412Skarels 	} else if (IN_CLASSB(addr)) {
76618132Skarels 		imp->il_host = ((addr>>8) & 0xFF);
76718132Skarels 		imp->il_imp = addr & 0xFF;
76818132Skarels 	} else {
76918132Skarels 		imp->il_host = ((addr>>4) & 0xF);
77018132Skarels 		imp->il_imp = addr & 0xF;
77118132Skarels 	}
77226397Skarels 	imp->il_imp = htons(imp->il_imp);
77318132Skarels }
7747170Ssam #endif
775