xref: /csrg-svn/sys/deprecated/netimp/if_imp.c (revision 26397)
123166Smckusick /*
223166Smckusick  * Copyright (c) 1982 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*26397Skarels  *	@(#)if_imp.c	6.9 (Berkeley) 02/23/86
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 
7124777Skarels struct ifqueue impintrq;
7224777Skarels 
735640Sroot /*
745640Sroot  * Messages from IMP regarding why
755640Sroot  * it's going down.
765640Sroot  */
775924Sroot static char *impmessage[] = {
785640Sroot 	"in 30 seconds",
795640Sroot 	"for hardware PM",
805640Sroot 	"to reload software",
815640Sroot 	"for emergency reset"
825640Sroot };
835640Sroot 
8418132Skarels #define HOSTDEADTIMER	10		/* How long to wait when down */
8518132Skarels 
8613067Ssam int	impdown(), impinit(), impioctl(), impoutput();
875771Swnj 
885640Sroot /*
895640Sroot  * IMP attach routine.  Called from hardware device attach routine
905640Sroot  * at configuration time with a pointer to the UNIBUS device structure.
915640Sroot  * Sets up local state and returns pointer to base of ifnet+impcb
925640Sroot  * structures.  This is then used by the device's attach routine
935640Sroot  * set up its back pointers.
945640Sroot  */
958815Sroot impattach(ui, reset)
965640Sroot 	struct uba_device *ui;
978815Sroot 	int (*reset)();
985640Sroot {
9924777Skarels 	struct imp_softc *sc;
10024777Skarels 	register struct ifnet *ifp;
1015640Sroot 
102*26397Skarels #ifdef lint
103*26397Skarels 	impintr();
104*26397Skarels #endif
10524777Skarels 	if (ui->ui_unit >= NIMP) {
10624777Skarels 		printf("imp%d: not configured\n", ui->ui_unit);
10724777Skarels 		return (0);
10824777Skarels 	}
10924777Skarels 	sc = &imp_softc[ui->ui_unit];
11024777Skarels 	ifp = &sc->imp_if;
1115640Sroot 	/* UNIT COULD BE AMBIGUOUS */
1125640Sroot 	ifp->if_unit = ui->ui_unit;
1135640Sroot 	ifp->if_name = "imp";
1146271Sroot 	ifp->if_mtu = IMPMTU - sizeof(struct imp_leader);
1159001Sroot 	ifp->if_reset = reset;
1165771Swnj 	ifp->if_init = impinit;
11713067Ssam 	ifp->if_ioctl = impioctl;
1185771Swnj 	ifp->if_output = impoutput;
1195771Swnj 	/* reset is handled at the hardware level */
1205640Sroot 	if_attach(ifp);
12124777Skarels 	return ((int)ifp);
1225640Sroot }
1235640Sroot 
1245640Sroot /*
1255640Sroot  * IMP initialization routine: call hardware module to
1265640Sroot  * setup UNIBUS resources, init state and get ready for
1275640Sroot  * NOOPs the IMP should send us, and that we want to drop.
1285640Sroot  */
1295640Sroot impinit(unit)
1305640Sroot 	int unit;
1315640Sroot {
1326500Ssam 	int s = splimp();
1335640Sroot 	register struct imp_softc *sc = &imp_softc[unit];
1345640Sroot 
13518412Skarels 	if (sc->imp_if.if_addrlist == 0)
13613067Ssam 		return;
1375771Swnj 	if ((*sc->imp_cb.ic_init)(unit) == 0) {
1385771Swnj 		sc->imp_state = IMPS_DOWN;
1396336Ssam 		sc->imp_if.if_flags &= ~IFF_UP;
1406500Ssam 		splx(s);
1415771Swnj 		return;
1425771Swnj 	}
1435640Sroot 	sc->imp_state = IMPS_INIT;
1445771Swnj 	impnoops(sc);
1456500Ssam 	splx(s);
1465640Sroot }
1475640Sroot 
1487199Ssam #ifdef IMPLEADERS
1497170Ssam int	impprintfs = 0;
1507199Ssam #endif
1515640Sroot 
1525640Sroot /*
1535640Sroot  * ARPAnet 1822 input routine.
1545640Sroot  * Called from hardware input interrupt routine to handle 1822
1555640Sroot  * IMP-host messages.  Type 0 messages (non-control) are
1565640Sroot  * passed to higher level protocol processors on the basis
1575640Sroot  * of link number.  Other type messages (control) are handled here.
1585640Sroot  */
1595771Swnj impinput(unit, m)
1605640Sroot 	int unit;
1615771Swnj 	register struct mbuf *m;
1625640Sroot {
1635640Sroot 	register struct imp_leader *ip;
1645640Sroot 	register struct imp_softc *sc = &imp_softc[unit];
16524777Skarels 	struct ifnet *ifp;
1665640Sroot 	register struct host *hp;
1675640Sroot 	register struct ifqueue *inq;
1685771Swnj 	struct control_leader *cp;
1695640Sroot 	struct in_addr addr;
1705924Sroot 	struct mbuf *next;
1716336Ssam 	struct sockaddr_in *sin;
1725640Sroot 
17324777Skarels 	/*
17424777Skarels 	 * Pull the interface pointer out of the mbuf
17524777Skarels 	 * and save for later; adjust mbuf to look at rest of data.
17624777Skarels 	 */
17724777Skarels 	ifp = *(mtod(m, struct ifnet **));
17824777Skarels 	IF_ADJ(m);
1796257Sroot 	/* verify leader length. */
1805771Swnj 	if (m->m_len < sizeof(struct control_leader) &&
1815771Swnj 	    (m = m_pullup(m, sizeof(struct control_leader))) == 0)
1825771Swnj 		return;
1835771Swnj 	cp = mtod(m, struct control_leader *);
1845771Swnj 	if (cp->dl_mtype == IMPTYPE_DATA)
1855771Swnj 		if (m->m_len < sizeof(struct imp_leader) &&
1865771Swnj 		    (m = m_pullup(m, sizeof(struct imp_leader))) == 0)
1875771Swnj 			return;
1885640Sroot 	ip = mtod(m, struct imp_leader *);
1897199Ssam #ifdef IMPLEADERS
1907170Ssam 	if (impprintfs)
1917170Ssam 		printleader("impinput", ip);
1927199Ssam #endif
1935640Sroot 
1946257Sroot 	/* check leader type */
1955771Swnj 	if (ip->il_format != IMP_NFF) {
1965771Swnj 		sc->imp_if.if_collisions++;	/* XXX */
1975640Sroot 		goto drop;
1985771Swnj 	}
1995640Sroot 
2006588Ssam 	if (ip->il_mtype != IMPTYPE_DATA) {
20118132Skarels 		/* If not data packet, build IP addr from leader (BRL) */
20218412Skarels 		imp_leader_to_addr(&addr, ip, &sc->imp_if);
2035640Sroot 	}
2045640Sroot 	switch (ip->il_mtype) {
2055640Sroot 
2065640Sroot 	case IMPTYPE_DATA:
2075640Sroot 		break;
2085640Sroot 
2095640Sroot 	/*
2105640Sroot 	 * IMP leader error.  Reset the IMP and discard the packet.
2115640Sroot 	 */
2125640Sroot 	case IMPTYPE_BADLEADER:
2135647Ssam 		/*
2145647Ssam 		 * According to 1822 document, this message
2155647Ssam 		 * will be generated in response to the
2165647Ssam 		 * first noop sent to the IMP after
2175647Ssam 		 * the host resets the IMP interface.
2185647Ssam 		 */
2195771Swnj 		if (sc->imp_state != IMPS_INIT) {
2205924Sroot 			impmsg(sc, "leader error");
22118412Skarels 			hostreset(((struct in_ifaddr *)&sc->imp_if.if_addrlist)->ia_net);
2225647Ssam 			impnoops(sc);
2235647Ssam 		}
2246582Ssam 		goto drop;
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:
2326599Ssam 		if (sc->imp_state < IMPS_INIT)
2336598Ssam 			goto drop;
2345640Sroot 		if ((ip->il_link & IMP_DMASK) == 0) {
2355640Sroot 			sc->imp_state = IMPS_GOINGDOWN;
2366160Ssam 			timeout(impdown, (caddr_t)sc, 30 * hz);
2375640Sroot 		}
2386160Ssam 		impmsg(sc, "going down %s",
2396160Ssam 			(u_int)impmessage[ip->il_link&IMP_DMASK]);
2406582Ssam 		goto drop;
2415640Sroot 
2425640Sroot 	/*
2435640Sroot 	 * A NOP usually seen during the initialization sequence.
2445640Sroot 	 * Compare the local address with that in the message.
2455640Sroot 	 * Reset the local address notion if it doesn't match.
2465640Sroot 	 */
2476336Ssam 	case IMPTYPE_NOOP:
2485647Ssam 		if (sc->imp_state == IMPS_DOWN) {
2495647Ssam 			sc->imp_state = IMPS_INIT;
2505647Ssam 			sc->imp_dropcnt = IMP_DROPCNT;
2515647Ssam 		}
2526500Ssam 		if (sc->imp_state == IMPS_INIT && --sc->imp_dropcnt > 0)
2536271Sroot 			goto drop;
25418412Skarels 		sin = (struct sockaddr_in *)&sc->imp_if.if_addrlist->ifa_addr;
25518412Skarels 		if (ip->il_imp != 0) {	/* BRL */
25618132Skarels 			struct in_addr leader_addr;
25718412Skarels 			imp_leader_to_addr(&leader_addr, ip, &sc->imp_if);
25818412Skarels 			if (sin->sin_addr.s_addr != leader_addr.s_addr) {
25918412Skarels 				impmsg(sc, "address reset to x%x (%d/%d)",
26018412Skarels 					htonl(leader_addr.s_addr),
26118132Skarels 					(u_int)ip->il_host,
26218412Skarels 					htons(ip->il_imp));
26318132Skarels 				sin->sin_addr.s_addr = leader_addr.s_addr;
26418132Skarels 			}
2656500Ssam 		}
2665771Swnj 		sc->imp_state = IMPS_UP;
2676336Ssam 		sc->imp_if.if_flags |= IFF_UP;
2686271Sroot 		goto drop;
2695640Sroot 
2705640Sroot 	/*
2716582Ssam 	 * RFNM or INCOMPLETE message, send next
2726582Ssam 	 * message on the q.  We could pass incomplete's
2736582Ssam 	 * up to the next level, but this currently isn't
2746582Ssam 	 * needed.
2755640Sroot 	 */
2765640Sroot 	case IMPTYPE_RFNM:
2775640Sroot 	case IMPTYPE_INCOMPLETE:
2786588Ssam 		if (hp = hostlookup(addr)) {
27924777Skarels 			hp->h_timer = HOSTTIMER;
2806588Ssam 			if (hp->h_rfnm == 0)
2816588Ssam 				hp->h_flags &= ~HF_INUSE;
2826588Ssam 			else if (next = hostdeque(hp))
2836588Ssam 				(void) impsnd(&sc->imp_if, next);
2846588Ssam 		}
2856271Sroot 		goto drop;
2865640Sroot 
2875640Sroot 	/*
2885640Sroot 	 * Host or IMP can't be reached.  Flush any packets
2895640Sroot 	 * awaiting transmission and release the host structure.
29024777Skarels 	 * Enqueue for notifying protocols at software interrupt time.
2915640Sroot 	 */
2925640Sroot 	case IMPTYPE_HOSTDEAD:
29311230Ssam 	case IMPTYPE_HOSTUNREACH:
29424777Skarels 		if (hp = hostlookup(addr)) {
29524777Skarels 			hp->h_flags |= (1 << (int)ip->il_mtype);
29624777Skarels 			hostfree(hp);
29724777Skarels 			hp->h_timer = HOSTDEADTIMER;
29824777Skarels 		}
2995859Sroot 		goto rawlinkin;
3005640Sroot 
3015640Sroot 	/*
3025640Sroot 	 * Error in data.  Clear RFNM status for this host and send
3035640Sroot 	 * noops to the IMP to clear the interface.
3045640Sroot 	 */
30511230Ssam 	case IMPTYPE_BADDATA:
3065924Sroot 		impmsg(sc, "data error");
3076588Ssam 		if (hp = hostlookup(addr))
3085640Sroot 			hp->h_rfnm = 0;
3095640Sroot 		impnoops(sc);
3106582Ssam 		goto drop;
3115640Sroot 
3125640Sroot 	/*
3135647Ssam 	 * Interface reset.
3145640Sroot 	 */
3155640Sroot 	case IMPTYPE_RESET:
3165924Sroot 		impmsg(sc, "interface reset");
31718412Skarels 		/* clear RFNM counts */
31818412Skarels 		hostreset(((struct in_ifaddr *)&sc->imp_if.if_addrlist)->ia_net);
3195647Ssam 		impnoops(sc);
3206582Ssam 		goto drop;
3215640Sroot 
3225640Sroot 	default:
3235640Sroot 		sc->imp_if.if_collisions++;		/* XXX */
3246582Ssam 		goto drop;
3255640Sroot 	}
3265640Sroot 
3275640Sroot 	/*
3286257Sroot 	 * Data for a protocol.  Dispatch to the appropriate
3296257Sroot 	 * protocol routine (running at software interrupt).
3306257Sroot 	 * If this isn't a raw interface, advance pointer
3316257Sroot 	 * into mbuf past leader.
3325640Sroot 	 */
3335640Sroot 	switch (ip->il_link) {
3345640Sroot 
3355640Sroot 	case IMPLINK_IP:
3365640Sroot 		m->m_len -= sizeof(struct imp_leader);
3375640Sroot 		m->m_off += sizeof(struct imp_leader);
3386261Swnj 		schednetisr(NETISR_IP);
3395640Sroot 		inq = &ipintrq;
3405640Sroot 		break;
3415640Sroot 
3425640Sroot 	default:
3435868Sroot 	rawlinkin:
34424777Skarels 		schednetisr(NETISR_IMP);
34524777Skarels 		inq = &impintrq;
34624777Skarels 		break;
3475640Sroot 	}
34824777Skarels 	/*
34924777Skarels 	 * Re-insert interface pointer in the mbuf chain
35024777Skarels 	 * for the next protocol up.
35124777Skarels 	 */
35224777Skarels 	m->m_off -= sizeof(struct ifnet *);
35324777Skarels 	m->m_len += sizeof(struct ifnet *);
35424777Skarels 	*(mtod(m, struct ifnet **)) = ifp;
3556208Swnj 	if (IF_QFULL(inq)) {
3566208Swnj 		IF_DROP(inq);
3576208Swnj 		goto drop;
3586208Swnj 	}
3595640Sroot 	IF_ENQUEUE(inq, m);
3605640Sroot 	return;
3615640Sroot 
3625640Sroot drop:
3635640Sroot 	m_freem(m);
3645640Sroot }
3655640Sroot 
3665647Ssam /*
3675647Ssam  * Bring the IMP down after notification.
3685647Ssam  */
3695647Ssam impdown(sc)
3705647Ssam 	struct imp_softc *sc;
3715647Ssam {
37211230Ssam 	int s = splimp();
3736208Swnj 
3745647Ssam 	sc->imp_state = IMPS_DOWN;
3755924Sroot 	impmsg(sc, "marked down");
37618412Skarels 	hostreset(((struct in_ifaddr *)&sc->imp_if.if_addrlist)->ia_net);
3776582Ssam 	if_down(&sc->imp_if);
37811230Ssam 	splx(s);
3795647Ssam }
3805647Ssam 
381*26397Skarels /*VARARGS2*/
38218132Skarels impmsg(sc, fmt, a1, a2, a3)
3835640Sroot 	struct imp_softc *sc;
3845640Sroot 	char *fmt;
3856160Ssam 	u_int a1;
3865640Sroot {
3876208Swnj 
3885640Sroot 	printf("imp%d: ", sc->imp_if.if_unit);
38918132Skarels 	printf(fmt, a1, a2, a3);
3905640Sroot 	printf("\n");
3915640Sroot }
3925640Sroot 
39324777Skarels struct sockproto impproto = { PF_IMPLINK };
39424777Skarels struct sockaddr_in impdst = { AF_IMPLINK };
39524777Skarels struct sockaddr_in impsrc = { AF_IMPLINK };
39624777Skarels 
3975640Sroot /*
39824777Skarels  * Pick up the IMP "error" messages enqueued earlier,
39924777Skarels  * passing these up to the higher level protocol
40024777Skarels  * and the raw interface.
4016582Ssam  */
40224777Skarels impintr()
4036582Ssam {
40424777Skarels 	register struct mbuf *m;
40524777Skarels 	register struct control_leader *cp;
40624777Skarels 	struct ifnet *ifp;
40724777Skarels 	int s;
4086582Ssam 
40924777Skarels 	for (;;) {
41024777Skarels 		s = splimp();
41124777Skarels 		IF_DEQUEUEIF(&impintrq, m, ifp);
41224777Skarels 		splx(s);
41324777Skarels 		if (m == 0)
41424777Skarels 			return;
41518132Skarels 
41624777Skarels 		cp = mtod(m, struct control_leader *);
41724777Skarels 		imp_leader_to_addr(&impsrc.sin_addr, (struct imp_leader *)cp,
41824777Skarels 		    ifp);
41924777Skarels 		impproto.sp_protocol = cp->dl_link;
42025409Skarels 		impdst.sin_addr = IA_SIN(ifp->if_addrlist)->sin_addr;
42124777Skarels 
42224777Skarels 		switch (cp->dl_link) {
42324777Skarels 
42424777Skarels 		case IMPLINK_IP:
425*26397Skarels 			pfctlinput((int)cp->dl_mtype,
426*26397Skarels 			    (struct sockaddr *)&impsrc);
42724777Skarels 			break;
42824777Skarels 		default:
429*26397Skarels 			raw_ctlinput((int)cp->dl_mtype,
430*26397Skarels 			    (struct sockaddr *)&impsrc);
43124777Skarels 			break;
43224777Skarels 		}
43324777Skarels 
43424777Skarels 		raw_input(m, &impproto, (struct sockaddr *)&impsrc,
43524777Skarels 		  (struct sockaddr *)&impdst);
4366588Ssam 	}
4376582Ssam }
4386582Ssam 
4396582Ssam /*
4405640Sroot  * ARPAnet 1822 output routine.
4415640Sroot  * Called from higher level protocol routines to set up messages for
4425640Sroot  * transmission to the imp.  Sets up the header and calls impsnd to
4435640Sroot  * enqueue the message for this IMP's hardware driver.
4445640Sroot  */
4456336Ssam impoutput(ifp, m0, dst)
4465640Sroot 	register struct ifnet *ifp;
4475640Sroot 	struct mbuf *m0;
4486336Ssam 	struct sockaddr *dst;
4495640Sroot {
4505640Sroot 	register struct imp_leader *imp;
4515640Sroot 	register struct mbuf *m = m0;
45218412Skarels 	int dlink, len;
4536504Ssam 	int error = 0;
4545640Sroot 
4555640Sroot 	/*
4565640Sroot 	 * Don't even try if the IMP is unavailable.
4575640Sroot 	 */
4586504Ssam 	if (imp_softc[ifp->if_unit].imp_state != IMPS_UP) {
4596504Ssam 		error = ENETDOWN;
4605647Ssam 		goto drop;
4616504Ssam 	}
4625640Sroot 
4636336Ssam 	switch (dst->sa_family) {
4645640Sroot 
4656336Ssam 	case AF_INET: {
46624777Skarels 		struct ip *ip = mtod(m, struct ip *);
4675640Sroot 
4685640Sroot 		dlink = IMPLINK_IP;
4696160Ssam 		len = ntohs((u_short)ip->ip_len);
4705640Sroot 		break;
4715640Sroot 	}
47224777Skarels 
4736336Ssam 	case AF_IMPLINK:
47424777Skarels 		len = 0;
47524777Skarels 		do
47624777Skarels 			len += m->m_len;
47724777Skarels 		while (m = m->m_next);
47824777Skarels 		m = m0;
4795640Sroot 		goto leaderexists;
4805640Sroot 
4815640Sroot 	default:
4826336Ssam 		printf("imp%d: can't handle af%d\n", ifp->if_unit,
4836336Ssam 			dst->sa_family);
4846504Ssam 		error = EAFNOSUPPORT;
4855647Ssam 		goto drop;
4865640Sroot 	}
4875640Sroot 
4885640Sroot 	/*
4895640Sroot 	 * Add IMP leader.  If there's not enough space in the
4905640Sroot 	 * first mbuf, allocate another.  If that should fail, we
4915640Sroot 	 * drop this sucker.
4925640Sroot 	 */
4935640Sroot 	if (m->m_off > MMAXOFF ||
4945640Sroot 	    MMINOFF + sizeof(struct imp_leader) > m->m_off) {
4959645Ssam 		m = m_get(M_DONTWAIT, MT_HEADER);
4966504Ssam 		if (m == 0) {
4976504Ssam 			error = ENOBUFS;
4985647Ssam 			goto drop;
4996504Ssam 		}
5005640Sroot 		m->m_next = m0;
5015640Sroot 		m->m_len = sizeof(struct imp_leader);
5025640Sroot 	} else {
5035640Sroot 		m->m_off -= sizeof(struct imp_leader);
5045640Sroot 		m->m_len += sizeof(struct imp_leader);
5055640Sroot 	}
5065640Sroot 	imp = mtod(m, struct imp_leader *);
5075640Sroot 	imp->il_format = IMP_NFF;
5085859Sroot 	imp->il_mtype = IMPTYPE_DATA;
50918132Skarels 	imp_addr_to_leader(imp,
51018412Skarels 		((struct sockaddr_in *)dst)->sin_addr.s_addr); /* BRL */
51118412Skarels 	imp->il_length = htons((u_short)len << 3);		/* BRL */
5125640Sroot 	imp->il_link = dlink;
5135859Sroot 	imp->il_flags = imp->il_htype = imp->il_subtype = 0;
5145640Sroot 
5155640Sroot leaderexists:
5165640Sroot 	return (impsnd(ifp, m));
5175647Ssam drop:
5185647Ssam 	m_freem(m0);
5196504Ssam 	return (error);
5205640Sroot }
5215640Sroot 
5225640Sroot /*
5235640Sroot  * Put a message on an interface's output queue.
5245640Sroot  * Perform RFNM counting: no more than 8 message may be
5255640Sroot  * in flight to any one host.
5265640Sroot  */
5275640Sroot impsnd(ifp, m)
5285640Sroot 	struct ifnet *ifp;
5295640Sroot 	struct mbuf *m;
5305640Sroot {
5315640Sroot 	register struct imp_leader *ip;
5325640Sroot 	register struct host *hp;
5335640Sroot 	struct impcb *icp;
5346588Ssam 	int s, error;
5355640Sroot 
5365640Sroot 	ip = mtod(m, struct imp_leader *);
5375640Sroot 
5385640Sroot 	/*
5395640Sroot 	 * Do RFNM counting for data messages
5405640Sroot 	 * (no more than 8 outstanding to any host)
5415640Sroot 	 */
5426588Ssam 	s = splimp();
5435640Sroot 	if (ip->il_mtype == IMPTYPE_DATA) {
5445640Sroot 		struct in_addr addr;
5455640Sroot 
54618412Skarels 		imp_leader_to_addr(&addr, ip, ifp);	/* BRL */
5475771Swnj 		if ((hp = hostlookup(addr)) == 0)
5485771Swnj 			hp = hostenter(addr);
5496588Ssam 		if (hp && (hp->h_flags & (HF_DEAD|HF_UNREACH))) {
5506607Ssam 			error = hp->h_flags&HF_DEAD ? EHOSTDOWN : EHOSTUNREACH;
5516588Ssam 			hp->h_flags &= ~HF_INUSE;
5526588Ssam 			goto bad;
5536588Ssam 		}
5545640Sroot 
5555640Sroot 		/*
5565647Ssam 		 * If IMP would block, queue until RFNM
5575640Sroot 		 */
5585640Sroot 		if (hp) {
55924777Skarels #ifndef NORFNM
56018132Skarels 			if (hp->h_rfnm < 8)
56118132Skarels #endif
56218132Skarels 			{
56324777Skarels 				hp->h_timer = HOSTTIMER;
5645640Sroot 				hp->h_rfnm++;
5655640Sroot 				goto enque;
5665640Sroot 			}
5676095Swnj 			if (hp->h_qcnt < 8) {	/* high water mark */
5686095Swnj 				HOST_ENQUE(hp, m);
5696095Swnj 				goto start;
5706095Swnj 			}
5715640Sroot 		}
5726588Ssam 		error = ENOBUFS;
5736588Ssam 		goto bad;
5745640Sroot 	}
5755640Sroot enque:
5766208Swnj 	if (IF_QFULL(&ifp->if_snd)) {
5776208Swnj 		IF_DROP(&ifp->if_snd);
5786588Ssam 		error = ENOBUFS;
57924777Skarels 		if (ip->il_mtype == IMPTYPE_DATA)
58024777Skarels 			hp->h_rfnm--;
5816588Ssam bad:
5826208Swnj 		m_freem(m);
5836588Ssam 		splx(s);
5846588Ssam 		return (error);
5856208Swnj 	}
5865640Sroot 	IF_ENQUEUE(&ifp->if_snd, m);
5876095Swnj start:
5885640Sroot 	icp = &imp_softc[ifp->if_unit].imp_cb;
5895640Sroot 	if (icp->ic_oactive == 0)
5905640Sroot 		(*icp->ic_start)(ifp->if_unit);
5916630Ssam 	splx(s);
5926504Ssam 	return (0);
5935640Sroot }
5945640Sroot 
5955640Sroot /*
5965640Sroot  * Put three 1822 NOOPs at the head of the output queue.
5975640Sroot  * Part of host-IMP initialization procedure.
5985640Sroot  * (Should return success/failure, but noone knows
5995640Sroot  * what to do with this, so why bother?)
6006818Ssam  * This routine is always called at splimp, so we don't
6016818Ssam  * protect the call to IF_PREPEND.
6025640Sroot  */
6035640Sroot impnoops(sc)
6045640Sroot 	register struct imp_softc *sc;
6055640Sroot {
6065640Sroot 	register i;
6075640Sroot 	register struct mbuf *m;
6085771Swnj 	register struct control_leader *cp;
6095640Sroot 
6105640Sroot 	sc->imp_dropcnt = IMP_DROPCNT;
61118412Skarels 	for (i = 0; i < IMP_DROPCNT + 1; i++) {
6129645Ssam 		if ((m = m_getclr(M_DONTWAIT, MT_HEADER)) == 0)
6135640Sroot 			return;
6145771Swnj 		m->m_len = sizeof(struct control_leader);
6155771Swnj 		cp = mtod(m, struct control_leader *);
6165771Swnj 		cp->dl_format = IMP_NFF;
6175771Swnj                 cp->dl_link = i;
6185771Swnj                 cp->dl_mtype = IMPTYPE_NOOP;
6195640Sroot 		IF_PREPEND(&sc->imp_if.if_snd, m);
6205640Sroot 	}
6215640Sroot 	if (sc->imp_cb.ic_oactive == 0)
6225640Sroot 		(*sc->imp_cb.ic_start)(sc->imp_if.if_unit);
6235640Sroot }
6247170Ssam 
62513067Ssam /*
62613067Ssam  * Process an ioctl request.
62713067Ssam  */
62813067Ssam impioctl(ifp, cmd, data)
62913067Ssam 	register struct ifnet *ifp;
63013067Ssam 	int cmd;
63113067Ssam 	caddr_t data;
63213067Ssam {
63318412Skarels 	struct ifaddr *ifa = (struct ifaddr *) data;
63413067Ssam 	int s = splimp(), error = 0;
63513067Ssam 
63613067Ssam 	switch (cmd) {
63713067Ssam 
63813067Ssam 	case SIOCSIFADDR:
63918412Skarels 		if (ifa->ifa_addr.sa_family != AF_INET) {
64018412Skarels 			error = EINVAL;
64118412Skarels 			break;
64218412Skarels 		}
64318412Skarels 		if ((ifp->if_flags & IFF_RUNNING) == 0)
64413067Ssam 			impinit(ifp->if_unit);
64513067Ssam 		break;
64613067Ssam 
64713067Ssam 	default:
64813067Ssam 		error = EINVAL;
64913067Ssam 	}
65013067Ssam 	splx(s);
65113067Ssam 	return (error);
65213067Ssam }
65313067Ssam 
6547170Ssam #ifdef IMPLEADERS
6557170Ssam printleader(routine, ip)
6567170Ssam 	char *routine;
6577170Ssam 	register struct imp_leader *ip;
6587170Ssam {
6597170Ssam 	printf("%s: ", routine);
6607170Ssam 	printbyte((char *)ip, 12);
6617170Ssam 	printf("<fmt=%x,net=%x,flags=%x,mtype=", ip->il_format, ip->il_network,
6627170Ssam 		ip->il_flags);
6637170Ssam 	if (ip->il_mtype <= IMPTYPE_READY)
6647170Ssam 		printf("%s,", impleaders[ip->il_mtype]);
6657170Ssam 	else
6667170Ssam 		printf("%x,", ip->il_mtype);
6677170Ssam 	printf("htype=%x,host=%x,imp=%x,link=", ip->il_htype, ip->il_host,
6687170Ssam 		ntohs(ip->il_imp));
6697170Ssam 	if (ip->il_link == IMPLINK_IP)
6707170Ssam 		printf("ip,");
6717170Ssam 	else
6727170Ssam 		printf("%x,", ip->il_link);
6737170Ssam 	printf("subtype=%x,len=%x>\n",ip->il_subtype,ntohs(ip->il_length)>>3);
6747170Ssam }
6757170Ssam 
6767170Ssam printbyte(cp, n)
6777170Ssam 	register char *cp;
6787170Ssam 	int n;
6797170Ssam {
6807170Ssam 	register i, j, c;
6817170Ssam 
6827170Ssam 	for (i=0; i<n; i++) {
6837170Ssam 		c = *cp++;
6847170Ssam 		for (j=0; j<2; j++)
68524777Skarels 			putchar("0123456789abcdef"[(c>>((1-j)*4))&0xf], 0);
68624777Skarels 		putchar(' ', 0);
6877170Ssam 	}
68824777Skarels 	putchar('\n', 0);
6897170Ssam }
6905640Sroot #endif
69118132Skarels 
69218132Skarels /*
69318132Skarels  * Routine to convert from IMP Leader to InterNet Address.
69418132Skarels  *
69518132Skarels  * This procedure is necessary because IMPs may be assigned Class A, B, or C
69618132Skarels  * network numbers, but only have 8 bits in the leader to reflect the
69718132Skarels  * IMP "network number".  The strategy is to take the network number from
69818132Skarels  * the ifnet structure, and blend in the host-on-imp and imp-on-net numbers
69918132Skarels  * from the leader.
70018132Skarels  *
70118132Skarels  * There is no support for "Logical Hosts".
70218132Skarels  *
70318132Skarels  * Class A:	Net.Host.0.Imp
70418132Skarels  * Class B:	Net.net.Host.Imp
70518132Skarels  * Class C:	Net.net.net.(Host4|Imp4)
70618132Skarels  */
70718412Skarels imp_leader_to_addr(ap, ip, ifp)
70818412Skarels 	struct in_addr *ap;
70918412Skarels 	register struct imp_leader *ip;
71018412Skarels 	struct ifnet *ifp;
71118132Skarels {
712*26397Skarels 	register u_long final;
71318132Skarels 	register struct sockaddr_in *sin;
71418132Skarels 	int imp = htons(ip->il_imp);
71518132Skarels 
71618412Skarels 	sin = (struct sockaddr_in *)(&ifp->if_addrlist->ifa_addr);
71718412Skarels 	final = htonl(sin->sin_addr.s_addr);
71818132Skarels 
71918412Skarels 	if (IN_CLASSA(final)) {
72018132Skarels 		final &= IN_CLASSA_NET;
72118132Skarels 		final |= (imp & 0xFF) | ((ip->il_host & 0xFF)<<16);
72218412Skarels 	} else if (IN_CLASSB(final)) {
72318132Skarels 		final &= IN_CLASSB_NET;
72418132Skarels 		final |= (imp & 0xFF) | ((ip->il_host & 0xFF)<<8);
72518132Skarels 	} else {
72618132Skarels 		final &= IN_CLASSC_NET;
72718132Skarels 		final |= (imp & 0x0F) | ((ip->il_host & 0x0F)<<4);
72818132Skarels 	}
72918412Skarels 	ap->s_addr = htonl(final);
73018132Skarels }
73118132Skarels 
73218132Skarels /*
73318132Skarels  * Function to take InterNet address and fill in IMP leader fields.
73418132Skarels  */
73518412Skarels imp_addr_to_leader(imp, a)
73618412Skarels 	register struct imp_leader *imp;
737*26397Skarels 	u_long a;
73818132Skarels {
739*26397Skarels 	register u_long addr = htonl(a);
74018132Skarels 
74118132Skarels 	imp->il_network = 0;	/* !! */
74218132Skarels 
74318412Skarels 	if (IN_CLASSA(addr)) {
74418132Skarels 		imp->il_host = ((addr>>16) & 0xFF);
74518132Skarels 		imp->il_imp = addr & 0xFF;
74618412Skarels 	} else if (IN_CLASSB(addr)) {
74718132Skarels 		imp->il_host = ((addr>>8) & 0xFF);
74818132Skarels 		imp->il_imp = addr & 0xFF;
74918132Skarels 	} else {
75018132Skarels 		imp->il_host = ((addr>>4) & 0xF);
75118132Skarels 		imp->il_imp = addr & 0xF;
75218132Skarels 	}
753*26397Skarels 	imp->il_imp = htons(imp->il_imp);
75418132Skarels }
7557170Ssam #endif
756