xref: /csrg-svn/sys/deprecated/netimp/if_imp.c (revision 33427)
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