xref: /csrg-svn/sys/deprecated/netimp/if_imp.c (revision 33453)
123166Smckusick /*
2*33453Skarels  * Copyright (c) 1982,1986,1988 Regents of the University of California.
3*33453Skarels  * All rights reserved.
423166Smckusick  *
5*33453Skarels  * Redistribution and use in source and binary forms are permitted
6*33453Skarels  * provided that this notice is preserved and that due credit is given
7*33453Skarels  * to the University of California at Berkeley. The name of the University
8*33453Skarels  * may not be used to endorse or promote products derived from this
9*33453Skarels  * software without specific prior written permission. This software
10*33453Skarels  * is provided ``as is'' without express or implied warranty.
11*33453Skarels  *
12*33453Skarels  *	@(#)if_imp.c	7.4 (Berkeley) 02/08/88
1323166Smckusick  */
145640Sroot 
155640Sroot #include "imp.h"
165640Sroot #if NIMP > 0
175640Sroot /*
18*33453Skarels  * ARPANET IMP (PSN) interface driver.
195640Sroot  *
20*33453Skarels  * The IMP-host protocol (AHIP) is handled here, leaving
215640Sroot  * hardware specifics to the lower level interface driver.
225640Sroot  */
2317068Sbloom #include "param.h"
2417068Sbloom #include "systm.h"
2517068Sbloom #include "mbuf.h"
2617068Sbloom #include "buf.h"
2717068Sbloom #include "protosw.h"
2817068Sbloom #include "socket.h"
2917068Sbloom #include "time.h"
3017068Sbloom #include "kernel.h"
3117068Sbloom #include "errno.h"
3217068Sbloom #include "ioctl.h"
3333427Skarels #include "syslog.h"
348705Sroot 
35*33453Skarels #include "../machine/mtpr.h"
36*33453Skarels 
378782Sroot #include "../vaxuba/ubavar.h"
388705Sroot 
398705Sroot #include "../net/if.h"
4010899Ssam 
418705Sroot #include "../net/netisr.h"
428408Swnj #include "../netinet/in.h"
438408Swnj #include "../netinet/in_systm.h"
4418412Skarels #include "../netinet/in_var.h"
458705Sroot #include "../netinet/ip.h"
468705Sroot #include "../netinet/ip_var.h"
4733427Skarels #define IMPMESSAGES
487199Ssam /* define IMPLEADERS here to get leader printing code */
4917068Sbloom #include "if_imp.h"
5017068Sbloom #include "if_imphost.h"
515640Sroot 
5233427Skarels struct	imp_softc imp_softc[NIMP];
53*33453Skarels #ifndef lint
54*33453Skarels int	nimp = NIMP;			/* for netstat */
55*33453Skarels #endif
5628849Skarels struct	ifqueue impintrq;
5728849Skarels int	impqmaxlen = IFQ_MAXLEN;
58*33453Skarels int	imphqlen = 12 + IMP_MAXHOSTMSG;	/* max packets to queue per host */
5924777Skarels 
6033427Skarels int	imppri = LOG_ERR;
6133427Skarels #ifdef IMPLEADERS
6233427Skarels int	impprintfs = 0;
6333427Skarels #endif
6433427Skarels #ifdef IMPINIT
6533427Skarels int	imptraceinit = 0;
6633427Skarels #endif
675640Sroot 
68*33453Skarels 
6933427Skarels #define HOSTDEADTIMER	(30 * PR_SLOWHZ)	/* How long to wait when down */
7018132Skarels 
71*33453Skarels int	impdown(), impinit(), impioctl(), impoutput(), imptimo();
725771Swnj 
735640Sroot /*
745640Sroot  * IMP attach routine.  Called from hardware device attach routine
7533427Skarels  * at configuration time with a pointer to the device structure.
765640Sroot  * Sets up local state and returns pointer to base of ifnet+impcb
775640Sroot  * structures.  This is then used by the device's attach routine
785640Sroot  * set up its back pointers.
795640Sroot  */
8033427Skarels struct imp_softc *
818815Sroot impattach(ui, reset)
825640Sroot 	struct uba_device *ui;
838815Sroot 	int (*reset)();
845640Sroot {
8524777Skarels 	struct imp_softc *sc;
8624777Skarels 	register struct ifnet *ifp;
8733427Skarels 	static int impunit;
885640Sroot 
8926397Skarels #ifdef lint
9026397Skarels 	impintr();
9126397Skarels #endif
9233427Skarels 	if (impunit >= NIMP) {
9333427Skarels 		printf("imp%d: not configured\n", impunit++);
9424777Skarels 		return (0);
9524777Skarels 	}
9633427Skarels 	sc = &imp_softc[impunit];
9724777Skarels 	ifp = &sc->imp_if;
9833427Skarels 	sc->imp_cb.ic_hwunit = ui->ui_unit;
9933427Skarels 	sc->imp_cb.ic_hwname = ui->ui_driver->ud_dname;
10033427Skarels 	ifp->if_unit = impunit;
1015640Sroot 	ifp->if_name = "imp";
1026271Sroot 	ifp->if_mtu = IMPMTU - sizeof(struct imp_leader);
1039001Sroot 	ifp->if_reset = reset;
1045771Swnj 	ifp->if_init = impinit;
10513067Ssam 	ifp->if_ioctl = impioctl;
1065771Swnj 	ifp->if_output = impoutput;
107*33453Skarels 	ifp->if_watchdog = imptimo;
1085640Sroot 	if_attach(ifp);
10933427Skarels 	impunit++;
11033427Skarels 	return (sc);
1115640Sroot }
1125640Sroot 
1135640Sroot /*
1145640Sroot  * IMP initialization routine: call hardware module to
11533427Skarels  * setup resources, init state and get ready for
1165640Sroot  * NOOPs the IMP should send us, and that we want to drop.
1175640Sroot  */
1185640Sroot impinit(unit)
1195640Sroot 	int unit;
1205640Sroot {
12132570Sbostic 	int s;
1225640Sroot 	register struct imp_softc *sc = &imp_softc[unit];
1235640Sroot 
12418412Skarels 	if (sc->imp_if.if_addrlist == 0)
12513067Ssam 		return;
12632570Sbostic 	s = splimp();
12733427Skarels #ifdef IMPINIT
12833427Skarels 	if (imptraceinit)
12933427Skarels 		log(imppri, "impinit\n");
13033427Skarels #endif
13133427Skarels 	sc->imp_state = IMPS_WINIT;
13233427Skarels 	if ((*sc->imp_cb.ic_init)(sc->imp_cb.ic_hwunit) == 0)
1336336Ssam 		sc->imp_if.if_flags &= ~IFF_UP;
13433427Skarels 	impintrq.ifq_maxlen = impqmaxlen;
1356500Ssam 	splx(s);
1365640Sroot }
1375640Sroot 
1385640Sroot /*
139*33453Skarels  * ARPAnet 1822/AHIP input routine.
1405640Sroot  * Called from hardware input interrupt routine to handle 1822
141*33453Skarels  * IMP-host messages.  Data messages are passed to higher-level
142*33453Skarels  * protocol processors on the basis of link number.
143*33453Skarels  * Other type messages (control) are handled here.
1445640Sroot  */
1455771Swnj impinput(unit, m)
1465640Sroot 	int unit;
1475771Swnj 	register struct mbuf *m;
1485640Sroot {
14933427Skarels 	register struct control_leader *cp;
15033427Skarels #define	ip	((struct imp_leader *)cp)
1515640Sroot 	register struct imp_softc *sc = &imp_softc[unit];
15224777Skarels 	struct ifnet *ifp;
1535640Sroot 	register struct host *hp;
1545640Sroot 	register struct ifqueue *inq;
1555924Sroot 	struct mbuf *next;
1566336Ssam 	struct sockaddr_in *sin;
157*33453Skarels 	int s;
1585640Sroot 
15924777Skarels 	/*
16024777Skarels 	 * Pull the interface pointer out of the mbuf
16124777Skarels 	 * and save for later; adjust mbuf to look at rest of data.
16224777Skarels 	 */
16324777Skarels 	ifp = *(mtod(m, struct ifnet **));
16424777Skarels 	IF_ADJ(m);
1656257Sroot 	/* verify leader length. */
1665771Swnj 	if (m->m_len < sizeof(struct control_leader) &&
1675771Swnj 	    (m = m_pullup(m, sizeof(struct control_leader))) == 0)
1685771Swnj 		return;
1695771Swnj 	cp = mtod(m, struct control_leader *);
17033427Skarels 	if (cp->dl_mtype == IMPTYPE_DATA &&
17133427Skarels 	    m->m_len < sizeof(struct imp_leader)) {
17233427Skarels 		if ((m = m_pullup(m, sizeof(struct imp_leader))) == 0)
1735771Swnj 			return;
17433427Skarels 		cp = mtod(m, struct control_leader *);
17533427Skarels 	}
1767199Ssam #ifdef IMPLEADERS
1777170Ssam 	if (impprintfs)
1787170Ssam 		printleader("impinput", ip);
1797199Ssam #endif
18028849Skarels 	inq = &impintrq;
1815640Sroot 
1826257Sroot 	/* check leader type */
18333427Skarels 	if (cp->dl_format != IMP_NFF) {
184*33453Skarels 		/* ignore old-style noops on reset */
185*33453Skarels 		if (cp->dl_mtype != IMPTYPE_NOOP &&
186*33453Skarels 		    cp->dl_mtype != IMPTYPE_RESET) {
187*33453Skarels 			sc->imp_garbage++;
188*33453Skarels 			sc->imp_if.if_collisions++;	/* XXX */
189*33453Skarels 		}
19033427Skarels 	} else switch (cp->dl_mtype) {
1915640Sroot 
1925640Sroot 	case IMPTYPE_DATA:
19328849Skarels 		/*
19428849Skarels 		 * Data for a protocol.  Dispatch to the appropriate
19528849Skarels 		 * protocol routine (running at software interrupt).
19628849Skarels 		 * If this isn't a raw interface, advance pointer
19728849Skarels 		 * into mbuf past leader.
19828849Skarels 		 */
19933427Skarels 		switch (cp->dl_link) {
20028849Skarels 
20128849Skarels 		case IMPLINK_IP:
20228849Skarels 			m->m_len -= sizeof(struct imp_leader);
20328849Skarels 			m->m_off += sizeof(struct imp_leader);
20428849Skarels 			schednetisr(NETISR_IP);
20528849Skarels 			inq = &ipintrq;
20628849Skarels 			break;
20728849Skarels 
20828849Skarels 		default:
20928849Skarels 			break;
21028849Skarels 		}
2115640Sroot 		break;
2125640Sroot 
2135640Sroot 	/*
2145640Sroot 	 * IMP leader error.  Reset the IMP and discard the packet.
2155640Sroot 	 */
2165640Sroot 	case IMPTYPE_BADLEADER:
2175647Ssam 		/*
2185647Ssam 		 * According to 1822 document, this message
2195647Ssam 		 * will be generated in response to the
2205647Ssam 		 * first noop sent to the IMP after
2215647Ssam 		 * the host resets the IMP interface.
2225647Ssam 		 */
22333427Skarels #ifdef IMPINIT
22433427Skarels 		if (imptraceinit)
22533427Skarels 			log(imppri, "badleader\n");
22633427Skarels #endif
2275771Swnj 		if (sc->imp_state != IMPS_INIT) {
2285924Sroot 			impmsg(sc, "leader error");
229*33453Skarels 			sc->imp_msgready = 0;
23033427Skarels 			hostreset(unit);
2315647Ssam 			impnoops(sc);
232*33453Skarels 			sc->imp_garbage++;
2335647Ssam 		}
23428849Skarels 		break;
2355640Sroot 
2365640Sroot 	/*
2375640Sroot 	 * IMP going down.  Print message, and if not immediate,
2385640Sroot 	 * set off a timer to insure things will be reset at the
2395640Sroot 	 * appropriate time.
2405640Sroot 	 */
2415640Sroot 	case IMPTYPE_DOWN:
24233427Skarels 	    {	int type, when;
24333427Skarels 
24433427Skarels 		type = cp->dl_link & IMP_DMASK;
24533427Skarels 		when = (cp->dl_link & IMPDOWN_WHENMASK) >> IMPDOWN_WHENSHIFT;
24633427Skarels #ifdef IMPINIT
24733427Skarels 		if (imptraceinit)
24833427Skarels 			log(imppri, "input DOWN %s %d\n",
24933427Skarels 			    impmessage[type], when * IMPDOWN_WHENUNIT);
25033427Skarels #endif
25133427Skarels 		if (type != IMPDOWN_GOING && when)
25233427Skarels 			impmsg(sc, "going down %s in %d minutes",
25333427Skarels 			    (u_int)impmessage[type], when * IMPDOWN_WHENUNIT);
25433427Skarels 		else
25533427Skarels 			impmsg(sc, "going down %s", (u_int)impmessage[type]);
25633427Skarels 		if (sc->imp_state != IMPS_UP)
25728849Skarels 			break;
25833427Skarels 		if (type == IMPDOWN_GOING) {
2595640Sroot 			sc->imp_state = IMPS_GOINGDOWN;
26033427Skarels 			timeout(impdown, (caddr_t)sc, IMPTV_DOWN * hz);
26133427Skarels 		} else if (when == 0)
26233427Skarels 			sc->imp_state = IMPS_WINIT;
26333427Skarels 		sc->imp_dropcnt = 0;
26428849Skarels 		break;
26533427Skarels 	    }
2665640Sroot 
2675640Sroot 	/*
26833427Skarels 	 * A NOP, usually seen during the initialization sequence.
2695640Sroot 	 * Compare the local address with that in the message.
2705640Sroot 	 * Reset the local address notion if it doesn't match.
2715640Sroot 	 */
2726336Ssam 	case IMPTYPE_NOOP:
27333427Skarels #ifdef IMPINIT
27433427Skarels 		if (imptraceinit)
27533427Skarels 			log(imppri, "noop\n");
27633427Skarels #endif
27733427Skarels 		if (sc->imp_state == IMPS_WINIT) {
27833427Skarels 			sc->imp_dropcnt = 0;
27933427Skarels 			impnoops(sc);
2805647Ssam 			sc->imp_state = IMPS_INIT;
2815647Ssam 		}
28233427Skarels 		sc->imp_dropcnt++;
28333427Skarels 		if (sc->imp_state == IMPS_INIT && cp->dl_imp != 0) {
28418132Skarels 			struct in_addr leader_addr;
28528849Skarels 
28633427Skarels 			sin = (struct sockaddr_in *)&sc->imp_if.if_addrlist->ifa_addr;
28733427Skarels 			imp_leader_to_addr(&leader_addr, cp, &sc->imp_if);
28818412Skarels 			if (sin->sin_addr.s_addr != leader_addr.s_addr) {
28918412Skarels 				impmsg(sc, "address reset to x%x (%d/%d)",
29028849Skarels 					ntohl(leader_addr.s_addr),
29133427Skarels 					(u_int)cp->dl_host,
29233427Skarels 					ntohs(cp->dl_imp));
29318132Skarels 				sin->sin_addr.s_addr = leader_addr.s_addr;
29418132Skarels 			}
2956500Ssam 		}
29628849Skarels 		break;
2975640Sroot 
2985640Sroot 	/*
299*33453Skarels 	 * RFNM or INCOMPLETE message, decrement rfnm count
300*33453Skarels 	 * and prepare to send next message.
301*33453Skarels 	 * We could pass incomplete's up to the next level,
302*33453Skarels 	 * but this currently isn't needed.
303*33453Skarels 	 * Pass "bad" incompletes and rfnms to the log.
3045640Sroot 	 */
30533427Skarels 	case IMPTYPE_INCOMPLETE:
30633427Skarels 		sc->imp_incomplete++;
30733427Skarels 		/* FALL THROUGH */
3085640Sroot 	case IMPTYPE_RFNM:
30933427Skarels 		if (hp = hostlookup(cp->dl_imp, cp->dl_host, unit)) {
310*33453Skarels 			if (hp->h_rfnm == 0) {
31133427Skarels 				sc->imp_badrfnm++;
312*33453Skarels 				break;
313*33453Skarels 			}
314*33453Skarels 			if (--hp->h_rfnm > 0) {
315*33453Skarels 				hp->h_timer = RFNMTIMER;
316*33453Skarels 				if (hp->h_qcnt) {
317*33453Skarels 					/*
318*33453Skarels 					 * If the rfnm allows another queued
319*33453Skarels 					 * message to be sent, bump msgready
320*33453Skarels 					 * and start IMP if idle.
321*33453Skarels 					 */
322*33453Skarels 					if (hp->h_qcnt >
323*33453Skarels 					   IMP_MAXHOSTMSG - 1 - hp->h_rfnm)
324*33453Skarels 						sc->imp_msgready++;
325*33453Skarels 					if (sc->imp_cb.ic_oactive == 0)
326*33453Skarels 						impstarthost(sc, hp);
327*33453Skarels 				}
328*33453Skarels 			} else if (hp->h_qcnt == 0)
32933427Skarels 				hostfree(hp);
330*33453Skarels 			/* else messages on queue waiting their turn */
33133427Skarels 			goto drop;
33233427Skarels 		} else
33333427Skarels 			sc->imp_badrfnm++;
33433427Skarels 		break;
3355640Sroot 
3365640Sroot 	/*
3375640Sroot 	 * Host or IMP can't be reached.  Flush any packets
3385640Sroot 	 * awaiting transmission and release the host structure.
33924777Skarels 	 * Enqueue for notifying protocols at software interrupt time.
3405640Sroot 	 */
3415640Sroot 	case IMPTYPE_HOSTDEAD:
34211230Ssam 	case IMPTYPE_HOSTUNREACH:
34333427Skarels 		if (hp = hostlookup(cp->dl_imp, cp->dl_host, unit)) {
34433427Skarels 			hp->h_flags |= (1 << (int)cp->dl_mtype);
345*33453Skarels 			sc->imp_msgready -=
346*33453Skarels 			   MIN(hp->h_qcnt, IMP_MAXHOSTMSG - hp->h_rfnm);
34733427Skarels 			hp->h_rfnm = 0;
348*33453Skarels 			hostflush(hp);
34924777Skarels 			hp->h_timer = HOSTDEADTIMER;
35024777Skarels 		}
35128849Skarels 		break;
3525640Sroot 
3535640Sroot 	/*
3545640Sroot 	 * Error in data.  Clear RFNM status for this host and send
3555640Sroot 	 * noops to the IMP to clear the interface.
3565640Sroot 	 */
35711230Ssam 	case IMPTYPE_BADDATA:
3585924Sroot 		impmsg(sc, "data error");
35933427Skarels 		if ((hp = hostlookup(cp->dl_imp, cp->dl_host, unit)) &&
36033427Skarels 		    hp->h_rfnm) {
361*33453Skarels 			sc->imp_msgready -=
362*33453Skarels 			   MIN(hp->h_qcnt, IMP_MAXHOSTMSG - hp->h_rfnm);
363*33453Skarels 			hostrelease(hp);
36433427Skarels 		}
3655640Sroot 		impnoops(sc);
36628849Skarels 		break;
3675640Sroot 
3685640Sroot 	/*
3695647Ssam 	 * Interface reset.
3705640Sroot 	 */
3715640Sroot 	case IMPTYPE_RESET:
37233427Skarels #ifdef IMPINIT
37333427Skarels 		if (imptraceinit)
37433427Skarels 			log(imppri, "reset complete\n");
37533427Skarels #endif
37633427Skarels 		if (sc->imp_state != IMPS_INIT) {
37733427Skarels 			impmsg(sc, "interface reset");
37833427Skarels 			impnoops(sc);
37933427Skarels 		}
38018412Skarels 		/* clear RFNM counts */
381*33453Skarels 		sc->imp_msgready = 0;
38233427Skarels 		hostreset(unit);
38333427Skarels 		if (sc->imp_state != IMPS_DOWN) {
38433427Skarels 			sc->imp_state = IMPS_UP;
38533427Skarels 			sc->imp_if.if_flags |= IFF_UP;
38633427Skarels #ifdef IMPINIT
38733427Skarels 			if (imptraceinit)
38833427Skarels 				log(imppri, "IMP UP\n");
38933427Skarels #endif
39033427Skarels 		}
39128849Skarels 		break;
3925640Sroot 
3935640Sroot 	default:
39433427Skarels 		sc->imp_garbage++;
3955640Sroot 		sc->imp_if.if_collisions++;		/* XXX */
39628849Skarels 		break;
3975640Sroot 	}
3985640Sroot 
39928849Skarels 	if (inq == &impintrq)
40024777Skarels 		schednetisr(NETISR_IMP);
40124777Skarels 	/*
40224777Skarels 	 * Re-insert interface pointer in the mbuf chain
40324777Skarels 	 * for the next protocol up.
40424777Skarels 	 */
40528849Skarels 	if (M_HASCL(m) && (mtod(m, int) & CLOFSET) < sizeof(struct ifnet *)) {
40628849Skarels 		struct mbuf *n;
40728849Skarels 
40828849Skarels 		MGET(n, M_DONTWAIT, MT_HEADER);
40928849Skarels 		if (n == 0)
41028849Skarels 			goto drop;
41128849Skarels 		n->m_next = m;
41228849Skarels 		m = n;
41328849Skarels 		m->m_len = 0;
41428849Skarels 		m->m_off = MMINOFF + sizeof(struct ifnet  *);
41528849Skarels 	}
41624777Skarels 	m->m_off -= sizeof(struct ifnet *);
41724777Skarels 	m->m_len += sizeof(struct ifnet *);
41824777Skarels 	*(mtod(m, struct ifnet **)) = ifp;
41928849Skarels 
420*33453Skarels 	s = splimp();
421*33453Skarels 	if (!IF_QFULL(inq)) {
422*33453Skarels 		IF_ENQUEUE(inq, m);
423*33453Skarels 		splx(s);
424*33453Skarels 		return;
4256208Swnj 	}
426*33453Skarels 	splx(s);
4275640Sroot drop:
428*33453Skarels 	IF_DROP(inq);
4295640Sroot 	m_freem(m);
43033427Skarels #undef ip
4315640Sroot }
4325640Sroot 
4335647Ssam /*
4345647Ssam  * Bring the IMP down after notification.
4355647Ssam  */
4365647Ssam impdown(sc)
4375647Ssam 	struct imp_softc *sc;
4385647Ssam {
43911230Ssam 	int s = splimp();
4406208Swnj 
44133427Skarels 	if (sc->imp_state == IMPS_GOINGDOWN) {
44233427Skarels 		sc->imp_state = IMPS_WINIT;
44333427Skarels 		impmsg(sc, "marked down");
44433427Skarels 		hostreset(sc->imp_if.if_unit);
44533427Skarels 		if_down(&sc->imp_if);
44633427Skarels 	}
44733427Skarels #ifdef IMPINIT
44833427Skarels 	else if (imptraceinit)
44933427Skarels 		log(imppri, "impdown, state now %d (ignored)\n", sc->imp_state);
45033427Skarels #endif
45111230Ssam 	splx(s);
4525647Ssam }
4535647Ssam 
45426397Skarels /*VARARGS2*/
45518132Skarels impmsg(sc, fmt, a1, a2, a3)
4565640Sroot 	struct imp_softc *sc;
4575640Sroot 	char *fmt;
4586160Ssam 	u_int a1;
4595640Sroot {
4606208Swnj 
46133427Skarels 	log(imppri, "imp%d: %r\n", sc->imp_if.if_unit, fmt, &a1);
4625640Sroot }
4635640Sroot 
46424777Skarels struct sockproto impproto = { PF_IMPLINK };
46524777Skarels struct sockaddr_in impdst = { AF_IMPLINK };
46624777Skarels struct sockaddr_in impsrc = { AF_IMPLINK };
46724777Skarels 
4685640Sroot /*
46924777Skarels  * Pick up the IMP "error" messages enqueued earlier,
47024777Skarels  * passing these up to the higher level protocol
47124777Skarels  * and the raw interface.
4726582Ssam  */
47324777Skarels impintr()
4746582Ssam {
47524777Skarels 	register struct mbuf *m;
47624777Skarels 	register struct control_leader *cp;
47724777Skarels 	struct ifnet *ifp;
47824777Skarels 	int s;
4796582Ssam 
48024777Skarels 	for (;;) {
48124777Skarels 		s = splimp();
48224777Skarels 		IF_DEQUEUEIF(&impintrq, m, ifp);
48324777Skarels 		splx(s);
48424777Skarels 		if (m == 0)
48524777Skarels 			return;
48618132Skarels 
48724777Skarels 		cp = mtod(m, struct control_leader *);
48833427Skarels 		imp_leader_to_addr(&impsrc.sin_addr, cp, ifp);
48924777Skarels 		impproto.sp_protocol = cp->dl_link;
49025409Skarels 		impdst.sin_addr = IA_SIN(ifp->if_addrlist)->sin_addr;
49124777Skarels 
49228849Skarels 		if (cp->dl_mtype == IMPTYPE_HOSTDEAD ||
49328849Skarels 		    cp->dl_mtype == IMPTYPE_HOSTUNREACH)
49428849Skarels 			switch (cp->dl_link) {
49524777Skarels 
49628849Skarels 			case IMPLINK_IP:
49728849Skarels 				pfctlinput((int)cp->dl_mtype,
49828849Skarels 				    (struct sockaddr *)&impsrc);
49928849Skarels 				break;
50028849Skarels 			default:
50128849Skarels 				raw_ctlinput((int)cp->dl_mtype,
50228849Skarels 				    (struct sockaddr *)&impsrc);
50328849Skarels 				break;
50428849Skarels 			}
50524777Skarels 
50624777Skarels 		raw_input(m, &impproto, (struct sockaddr *)&impsrc,
50724777Skarels 		  (struct sockaddr *)&impdst);
5086588Ssam 	}
5096582Ssam }
5106582Ssam 
5116582Ssam /*
5125640Sroot  * ARPAnet 1822 output routine.
5135640Sroot  * Called from higher level protocol routines to set up messages for
5145640Sroot  * transmission to the imp.  Sets up the header and calls impsnd to
5155640Sroot  * enqueue the message for this IMP's hardware driver.
5165640Sroot  */
5176336Ssam impoutput(ifp, m0, dst)
5185640Sroot 	register struct ifnet *ifp;
5195640Sroot 	struct mbuf *m0;
5206336Ssam 	struct sockaddr *dst;
5215640Sroot {
5225640Sroot 	register struct imp_leader *imp;
5235640Sroot 	register struct mbuf *m = m0;
5246504Ssam 	int error = 0;
5255640Sroot 
5265640Sroot 	/*
5275640Sroot 	 * Don't even try if the IMP is unavailable.
5285640Sroot 	 */
52933427Skarels 	if (!IMPS_RUNNING(imp_softc[ifp->if_unit].imp_state)) {
5306504Ssam 		error = ENETDOWN;
5315647Ssam 		goto drop;
5326504Ssam 	}
5335640Sroot 
534*33453Skarels 	/*
535*33453Skarels 	 * If AF_IMPLINK, leader exists; just send.
536*33453Skarels 	 * Otherwise, construct leader according to address family.
537*33453Skarels 	 */
538*33453Skarels 	if (dst->sa_family != AF_IMPLINK) {
539*33453Skarels 		/*
540*33453Skarels 		 * Add IMP leader.  If there's not enough space in the
541*33453Skarels 		 * first mbuf, allocate another.  If that should fail, we
542*33453Skarels 		 * drop this sucker.
543*33453Skarels 		 */
544*33453Skarels 		if (m->m_off > MMAXOFF ||
545*33453Skarels 		    MMINOFF + sizeof(struct imp_leader) > m->m_off) {
546*33453Skarels 			m = m_get(M_DONTWAIT, MT_HEADER);
547*33453Skarels 			if (m == 0) {
548*33453Skarels 				error = ENOBUFS;
549*33453Skarels 				goto drop;
550*33453Skarels 			}
551*33453Skarels 			m->m_next = m0;
552*33453Skarels 			m->m_len = sizeof(struct imp_leader);
553*33453Skarels 		} else {
554*33453Skarels 			m->m_off -= sizeof(struct imp_leader);
555*33453Skarels 			m->m_len += sizeof(struct imp_leader);
556*33453Skarels 		}
557*33453Skarels 		imp = mtod(m, struct imp_leader *);
558*33453Skarels 		imp->il_format = IMP_NFF;
559*33453Skarels 		imp->il_mtype = IMPTYPE_DATA;
560*33453Skarels 		imp->il_flags = imp->il_htype = imp->il_subtype = 0;
5615640Sroot 
562*33453Skarels 		switch (dst->sa_family) {
5635640Sroot 
564*33453Skarels 		case AF_INET: {
565*33453Skarels 			struct ip *ip = mtod(m, struct ip *);
56624777Skarels 
567*33453Skarels 			imp->il_link = IMPLINK_IP;
568*33453Skarels 			imp_addr_to_leader((struct control_leader *)imp,
569*33453Skarels 				((struct sockaddr_in *)dst)->sin_addr.s_addr);
570*33453Skarels 			imp->il_length = htons(ntohs((u_short)ip->ip_len) << 3);
571*33453Skarels 			break;
572*33453Skarels 		}
5735640Sroot 
574*33453Skarels 		default:
575*33453Skarels 			printf("imp%d: can't handle af%d\n", ifp->if_unit,
576*33453Skarels 				dst->sa_family);
577*33453Skarels 			error = EAFNOSUPPORT;
5785647Ssam 			goto drop;
5796504Ssam 		}
5805640Sroot 	}
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 {
59633427Skarels 	register struct control_leader *imp;
5975640Sroot 	register struct host *hp;
598*33453Skarels 	register struct imp_softc *sc = &imp_softc[ifp->if_unit];
599*33453Skarels 	int s, error = 0;
6005640Sroot 
60133427Skarels 	imp = mtod(m, struct control_leader *);
6025640Sroot 
6035640Sroot 	/*
6045640Sroot 	 * Do RFNM counting for data messages
605*33453Skarels 	 * (no more than 8 outstanding to any host).
606*33453Skarels 	 * Queue data messages per host if 8 are already outstanding
607*33453Skarels 	 * or if the hardware interface is already doing output.
608*33453Skarels 	 * Increment imp_msgready if the message could be sent now,
609*33453Skarels 	 * but must be queued because the imp output is busy.
6105640Sroot 	 */
6116588Ssam 	s = splimp();
61233427Skarels 	if (imp->dl_mtype == IMPTYPE_DATA) {
61333427Skarels 		hp = hostenter(imp->dl_imp, imp->dl_host, ifp->if_unit);
6146588Ssam 		if (hp && (hp->h_flags & (HF_DEAD|HF_UNREACH))) {
6156607Ssam 			error = hp->h_flags&HF_DEAD ? EHOSTDOWN : EHOSTUNREACH;
6166588Ssam 			goto bad;
6176588Ssam 		}
6185640Sroot 
6195640Sroot 		/*
620*33453Skarels 		 * If IMP would block, queue until RFNM;
621*33453Skarels 		 * if IMP is busy, queue until our turn.
6225640Sroot 		 */
6235640Sroot 		if (hp) {
624*33453Skarels 			if (hp->h_rfnm < IMP_MAXHOSTMSG) {
625*33453Skarels 				if (sc->imp_cb.ic_oactive == 0) {
626*33453Skarels 					/*
627*33453Skarels 					 * Send without queuing;
628*33453Skarels 					 * adjust rfnm count and timer.
629*33453Skarels 					 */
630*33453Skarels 					if (hp->h_rfnm++ == 0)
631*33453Skarels 					    hp->h_timer = RFNMTIMER;
632*33453Skarels 					goto send;
633*33453Skarels 				} else {
634*33453Skarels 					sc->imp_msgready++;
635*33453Skarels 					goto q;
636*33453Skarels 				}
637*33453Skarels 			} else if (hp->h_rfnm + hp->h_qcnt < imphqlen) {
638*33453Skarels 		q:
6396095Swnj 				HOST_ENQUE(hp, m);
640*33453Skarels 			} else
641*33453Skarels 				error = ENOBUFS;
642*33453Skarels 		} else
643*33453Skarels 			error = ENOBUFS;
644*33453Skarels 	} else if (sc->imp_cb.ic_oactive == 0)
645*33453Skarels 		goto send;
646*33453Skarels 	else
647*33453Skarels 		IF_ENQUEUE(&ifp->if_snd, m);
648*33453Skarels 	splx(s);
649*33453Skarels 	return (0);
650*33453Skarels 
651*33453Skarels send:
652*33453Skarels 	sc->imp_if.if_timer = IMP_OTIMER;
653*33453Skarels 	(*sc->imp_cb.ic_output)(sc->imp_cb.ic_hwunit, m);
654*33453Skarels 	splx(s);
655*33453Skarels 	return (0);
656*33453Skarels bad:
657*33453Skarels 	m_freem(m);
658*33453Skarels 	splx(s);
659*33453Skarels 	return (error);
660*33453Skarels }
661*33453Skarels 
662*33453Skarels /*
663*33453Skarels  * Start another output operation on IMP; called from hardware
664*33453Skarels  * transmit-complete interrupt routine at splimp or from imp routines
665*33453Skarels  * when output is not in progress and more output is ready.  If any packets
666*33453Skarels  * on shared output queue, send them, otherwise send the next data
667*33453Skarels  * packet for a host.  Host data packets are sent round-robin based
668*33453Skarels  * on destination.
669*33453Skarels  */
670*33453Skarels impstart(sc)
671*33453Skarels 	register struct imp_softc *sc;
672*33453Skarels {
673*33453Skarels 	register struct mbuf *m;
674*33453Skarels 	struct mbuf *m0;
675*33453Skarels 	register struct host *hp;
676*33453Skarels 	int index;
677*33453Skarels 
678*33453Skarels 	IF_DEQUEUE(&sc->imp_if.if_snd, m);
679*33453Skarels 	if (m) {
680*33453Skarels 		sc->imp_if.if_timer = IMP_OTIMER;
681*33453Skarels 		(*sc->imp_cb.ic_output)(sc->imp_cb.ic_hwunit, m);
682*33453Skarels 		return;
683*33453Skarels 	}
684*33453Skarels 	if (sc->imp_msgready) {
685*33453Skarels 		if ((m = sc->imp_hostq) == 0 && (m = sc->imp_hosts) == 0)
686*33453Skarels 			panic ("imp msgready");
687*33453Skarels 		if ((index = sc->imp_hostent) >= HPMBUF)
688*33453Skarels 			index = 0;
689*33453Skarels 		m0 = m;
690*33453Skarels 		for (;;) {
691*33453Skarels 			for (hp = &mtod(m, struct hmbuf *)->hm_hosts[index];
692*33453Skarels 			    index < HPMBUF; hp++, index++) {
693*33453Skarels 				if (hp->h_q && hp->h_rfnm < IMP_MAXHOSTMSG) {
694*33453Skarels 					impstarthost(sc, hp);
695*33453Skarels 					sc->imp_hostq = m;
696*33453Skarels 					sc->imp_hostent = index;
697*33453Skarels 					return;
698*33453Skarels 				}
6996095Swnj 			}
700*33453Skarels 			if ((m = m->m_next) == 0)
701*33453Skarels 				m = sc->imp_hosts;
702*33453Skarels 			if (m == m0) {
703*33453Skarels 				if (sc->imp_hostent != 0)
704*33453Skarels 					sc->imp_hostent = 0;
705*33453Skarels 				else {
706*33453Skarels 					log(LOG_ERR,
707*33453Skarels 					    "imp can't find %d msgready\n",
708*33453Skarels 					    sc->imp_msgready);
709*33453Skarels 					sc->imp_msgready = 0;
710*33453Skarels 					break;
711*33453Skarels 				}
712*33453Skarels 			}
713*33453Skarels 			index = 0;
7145640Sroot 		}
7155640Sroot 	}
716*33453Skarels 	sc->imp_if.if_timer = 0;
717*33453Skarels }
718*33453Skarels 
719*33453Skarels /*
720*33453Skarels  * Restart output for a host that has timed out
721*33453Skarels  * while waiting for a RFNM and has more packets to send.
722*33453Skarels  * Must be called at splimp.
723*33453Skarels  */
724*33453Skarels imprestarthost(unit, hp)
725*33453Skarels 	int unit;
726*33453Skarels 	struct host *hp;
727*33453Skarels {
728*33453Skarels 	register struct imp_softc *sc = &imp_softc[unit];
729*33453Skarels 
730*33453Skarels 	sc->imp_lostrfnm++;
731*33453Skarels 	if (--hp->h_rfnm > 0)
732*33453Skarels 		hp->h_timer = RFNMTIMER;
733*33453Skarels 	if (hp->h_qcnt) {
734*33453Skarels 		/*
735*33453Skarels 		 * If the rfnm allows another queued
736*33453Skarels 		 * message to be sent, bump msgready
737*33453Skarels 		 * and start IMP if idle.
738*33453Skarels 		 */
739*33453Skarels 		if (hp->h_qcnt >
740*33453Skarels 		   IMP_MAXHOSTMSG - 1 - hp->h_rfnm)
741*33453Skarels 			sc->imp_msgready++;
742*33453Skarels 		if (sc->imp_cb.ic_oactive == 0)
743*33453Skarels 			impstarthost(sc, hp);
7446208Swnj 	}
7455640Sroot }
7465640Sroot 
7475640Sroot /*
748*33453Skarels  * Send the next message queued for a host
749*33453Skarels  * when ready to send another message to the IMP.
750*33453Skarels  * Called only when output is not in progress.
751*33453Skarels  * Bump RFNM counter and start RFNM timer
752*33453Skarels  * when we send the message to the IMP.
753*33453Skarels  * Must be called at splimp.
754*33453Skarels  */
755*33453Skarels impstarthost(sc, hp)
756*33453Skarels 	register struct imp_softc *sc;
757*33453Skarels 	register struct host *hp;
758*33453Skarels {
759*33453Skarels 	struct mbuf *m;
760*33453Skarels 
761*33453Skarels 	if (hp->h_rfnm++ == 0)
762*33453Skarels 		hp->h_timer = RFNMTIMER;
763*33453Skarels 	HOST_DEQUE(hp, m);
764*33453Skarels 	sc->imp_if.if_timer = IMP_OTIMER;
765*33453Skarels 	(*sc->imp_cb.ic_output)(sc->imp_cb.ic_hwunit, m);
766*33453Skarels 	sc->imp_msgready--;
767*33453Skarels }
768*33453Skarels 
769*33453Skarels /*
770*33453Skarels  * "Watchdog" timeout.  When the output timer expires,
771*33453Skarels  * we assume we have been blocked by the imp.
772*33453Skarels  * No need to restart, just collect statistics.
773*33453Skarels  */
774*33453Skarels imptimo(unit)
775*33453Skarels 	int unit;
776*33453Skarels {
777*33453Skarels 
778*33453Skarels 	imp_softc[unit].imp_block++;
779*33453Skarels }
780*33453Skarels 
781*33453Skarels /*
7825640Sroot  * Put three 1822 NOOPs at the head of the output queue.
7835640Sroot  * Part of host-IMP initialization procedure.
7845640Sroot  * (Should return success/failure, but noone knows
7855640Sroot  * what to do with this, so why bother?)
7866818Ssam  * This routine is always called at splimp, so we don't
7876818Ssam  * protect the call to IF_PREPEND.
7885640Sroot  */
7895640Sroot impnoops(sc)
7905640Sroot 	register struct imp_softc *sc;
7915640Sroot {
7925640Sroot 	register i;
7935640Sroot 	register struct mbuf *m;
7945771Swnj 	register struct control_leader *cp;
7955640Sroot 
79633427Skarels #ifdef IMPINIT
79733427Skarels 	if (imptraceinit)
79833427Skarels 		log(imppri, "impnoops\n");
79933427Skarels #endif
80033427Skarels 	for (i = 0; i < IMP_NOOPCNT; i++) {
8019645Ssam 		if ((m = m_getclr(M_DONTWAIT, MT_HEADER)) == 0)
8025640Sroot 			return;
8035771Swnj 		m->m_len = sizeof(struct control_leader);
8045771Swnj 		cp = mtod(m, struct control_leader *);
8055771Swnj 		cp->dl_format = IMP_NFF;
80633427Skarels 		cp->dl_link = i;
80733427Skarels 		cp->dl_mtype = IMPTYPE_NOOP;
8085640Sroot 		IF_PREPEND(&sc->imp_if.if_snd, m);
8095640Sroot 	}
8105640Sroot 	if (sc->imp_cb.ic_oactive == 0)
811*33453Skarels 		impstart(sc);
8125640Sroot }
8137170Ssam 
81413067Ssam /*
81513067Ssam  * Process an ioctl request.
81613067Ssam  */
81713067Ssam impioctl(ifp, cmd, data)
81813067Ssam 	register struct ifnet *ifp;
81913067Ssam 	int cmd;
82013067Ssam 	caddr_t data;
82113067Ssam {
82218412Skarels 	struct ifaddr *ifa = (struct ifaddr *) data;
82313067Ssam 	int s = splimp(), error = 0;
82433427Skarels #define sc	((struct imp_softc *)ifp)
82513067Ssam 
82613067Ssam 	switch (cmd) {
82713067Ssam 
82813067Ssam 	case SIOCSIFADDR:
82918412Skarels 		if (ifa->ifa_addr.sa_family != AF_INET) {
83018412Skarels 			error = EINVAL;
83118412Skarels 			break;
83218412Skarels 		}
83333427Skarels 		if ((ifp->if_flags & IFF_UP) == 0)
83413067Ssam 			impinit(ifp->if_unit);
83513067Ssam 		break;
83613067Ssam 
83733427Skarels 	case SIOCSIFFLAGS:
83833427Skarels 		if ((ifp->if_flags & IFF_UP) == 0 &&
83933427Skarels 		    sc->imp_state != IMPS_DOWN) {
840*33453Skarels 			if (sc->imp_cb.ic_down &&
841*33453Skarels 			    (*sc->imp_cb.ic_down)(sc->imp_cb.ic_hwunit))
84233427Skarels 				sc->imp_state = IMPS_DOWN;
84333427Skarels 		} else if (ifp->if_flags & IFF_UP && sc->imp_state == IMPS_DOWN)
84433427Skarels 			impinit(ifp->if_unit);
84533427Skarels 		break;
84633427Skarels 
84713067Ssam 	default:
84813067Ssam 		error = EINVAL;
84933427Skarels 		break;
85013067Ssam 	}
85113067Ssam 	splx(s);
85213067Ssam 	return (error);
85313067Ssam }
85413067Ssam 
8557170Ssam #ifdef IMPLEADERS
8567170Ssam printleader(routine, ip)
8577170Ssam 	char *routine;
8587170Ssam 	register struct imp_leader *ip;
8597170Ssam {
8607170Ssam 	printf("%s: ", routine);
8617170Ssam 	printbyte((char *)ip, 12);
8627170Ssam 	printf("<fmt=%x,net=%x,flags=%x,mtype=", ip->il_format, ip->il_network,
8637170Ssam 		ip->il_flags);
8647170Ssam 	if (ip->il_mtype <= IMPTYPE_READY)
8657170Ssam 		printf("%s,", impleaders[ip->il_mtype]);
8667170Ssam 	else
8677170Ssam 		printf("%x,", ip->il_mtype);
8687170Ssam 	printf("htype=%x,host=%x,imp=%x,link=", ip->il_htype, ip->il_host,
8697170Ssam 		ntohs(ip->il_imp));
8707170Ssam 	if (ip->il_link == IMPLINK_IP)
8717170Ssam 		printf("ip,");
8727170Ssam 	else
8737170Ssam 		printf("%x,", ip->il_link);
8747170Ssam 	printf("subtype=%x,len=%x>\n",ip->il_subtype,ntohs(ip->il_length)>>3);
8757170Ssam }
8767170Ssam 
8777170Ssam printbyte(cp, n)
8787170Ssam 	register char *cp;
8797170Ssam 	int n;
8807170Ssam {
8817170Ssam 	register i, j, c;
8827170Ssam 
8837170Ssam 	for (i=0; i<n; i++) {
8847170Ssam 		c = *cp++;
8857170Ssam 		for (j=0; j<2; j++)
88624777Skarels 			putchar("0123456789abcdef"[(c>>((1-j)*4))&0xf], 0);
88724777Skarels 		putchar(' ', 0);
8887170Ssam 	}
88924777Skarels 	putchar('\n', 0);
8907170Ssam }
8915640Sroot #endif
89218132Skarels 
89318132Skarels /*
89418132Skarels  * Routine to convert from IMP Leader to InterNet Address.
89518132Skarels  *
89618132Skarels  * This procedure is necessary because IMPs may be assigned Class A, B, or C
89718132Skarels  * network numbers, but only have 8 bits in the leader to reflect the
89818132Skarels  * IMP "network number".  The strategy is to take the network number from
89918132Skarels  * the ifnet structure, and blend in the host-on-imp and imp-on-net numbers
90018132Skarels  * from the leader.
90118132Skarels  *
90218132Skarels  * There is no support for "Logical Hosts".
90318132Skarels  *
90418132Skarels  * Class A:	Net.Host.0.Imp
90518132Skarels  * Class B:	Net.net.Host.Imp
90618132Skarels  * Class C:	Net.net.net.(Host4|Imp4)
90718132Skarels  */
90833427Skarels imp_leader_to_addr(ap, cp, ifp)
90918412Skarels 	struct in_addr *ap;
91033427Skarels 	register struct control_leader *cp;
91118412Skarels 	struct ifnet *ifp;
91218132Skarels {
91326397Skarels 	register u_long final;
91418132Skarels 	register struct sockaddr_in *sin;
91533427Skarels 	int imp = ntohs(cp->dl_imp);
91618132Skarels 
91718412Skarels 	sin = (struct sockaddr_in *)(&ifp->if_addrlist->ifa_addr);
91828849Skarels 	final = ntohl(sin->sin_addr.s_addr);
91918132Skarels 
92018412Skarels 	if (IN_CLASSA(final)) {
92118132Skarels 		final &= IN_CLASSA_NET;
92233427Skarels 		final |= (imp & 0xFF) | ((cp->dl_host & 0xFF)<<16);
92318412Skarels 	} else if (IN_CLASSB(final)) {
92418132Skarels 		final &= IN_CLASSB_NET;
92533427Skarels 		final |= (imp & 0xFF) | ((cp->dl_host & 0xFF)<<8);
92618132Skarels 	} else {
92718132Skarels 		final &= IN_CLASSC_NET;
92833427Skarels 		final |= (imp & 0x0F) | ((cp->dl_host & 0x0F)<<4);
92918132Skarels 	}
93018412Skarels 	ap->s_addr = htonl(final);
93118132Skarels }
93218132Skarels 
93318132Skarels /*
93418132Skarels  * Function to take InterNet address and fill in IMP leader fields.
93518132Skarels  */
93618412Skarels imp_addr_to_leader(imp, a)
93733427Skarels 	register struct control_leader *imp;
93826397Skarels 	u_long a;
93918132Skarels {
94028849Skarels 	register u_long addr = ntohl(a);
94118132Skarels 
94233427Skarels 	imp->dl_network = 0;	/* !! */
94318132Skarels 
94418412Skarels 	if (IN_CLASSA(addr)) {
94533427Skarels 		imp->dl_host = ((addr>>16) & 0xFF);
94633427Skarels 		imp->dl_imp = addr & 0xFF;
94718412Skarels 	} else if (IN_CLASSB(addr)) {
94833427Skarels 		imp->dl_host = ((addr>>8) & 0xFF);
94933427Skarels 		imp->dl_imp = addr & 0xFF;
95018132Skarels 	} else {
95133427Skarels 		imp->dl_host = ((addr>>4) & 0xF);
95233427Skarels 		imp->dl_imp = addr & 0xF;
95318132Skarels 	}
95433427Skarels 	imp->dl_imp = htons(imp->dl_imp);
95518132Skarels }
9567170Ssam #endif
957