xref: /original-bsd/sys/deprecated/netimp/if_imp.c (revision a9c19d04)
1 /*
2  * Copyright (c) 1982, 1986 Regents of the University of California.
3  * All rights reserved.  The Berkeley software License Agreement
4  * specifies the terms and conditions for redistribution.
5  *
6  *	@(#)if_imp.c	7.1 (Berkeley) 06/04/86
7  */
8 
9 #include "imp.h"
10 #if NIMP > 0
11 /*
12  * ARPANET IMP interface driver.
13  *
14  * The IMP-host protocol is handled here, leaving
15  * hardware specifics to the lower level interface driver.
16  */
17 #include "../machine/pte.h"
18 
19 #include "param.h"
20 #include "systm.h"
21 #include "mbuf.h"
22 #include "buf.h"
23 #include "protosw.h"
24 #include "socket.h"
25 #include "vmmac.h"
26 #include "time.h"
27 #include "kernel.h"
28 #include "errno.h"
29 #include "ioctl.h"
30 
31 #include "../vax/cpu.h"
32 #include "../vax/mtpr.h"
33 #include "../vaxuba/ubareg.h"
34 #include "../vaxuba/ubavar.h"
35 
36 #include "../net/if.h"
37 #include "../net/route.h"
38 
39 #include "../net/netisr.h"
40 #include "../netinet/in.h"
41 #include "../netinet/in_systm.h"
42 #include "../netinet/in_var.h"
43 #include "../netinet/ip.h"
44 #include "../netinet/ip_var.h"
45 /* define IMPLEADERS here to get leader printing code */
46 #include "if_imp.h"
47 #include "if_imphost.h"
48 
49 /*
50  * IMP software status per interface.
51  * (partially shared with the hardware specific module)
52  *
53  * Each interface is referenced by a network interface structure,
54  * imp_if, which the routing code uses to locate the interface.
55  * This structure contains the output queue for the interface, its
56  * address, ...  IMP specific structures used in connecting the
57  * IMP software modules to the hardware specific interface routines
58  * are stored here.  The common structures are made visible to the
59  * interface driver by passing a pointer to the hardware routine
60  * at "attach" time.
61  *
62  * NOTE: imp_if and imp_cb are assumed adjacent in hardware code.
63  */
64 struct imp_softc {
65 	struct	ifnet imp_if;		/* network visible interface */
66 	struct	impcb imp_cb;		/* hooks to hardware module */
67 	u_char	imp_state;		/* current state of IMP */
68 	char	imp_dropcnt;		/* used during initialization */
69 } imp_softc[NIMP];
70 
71 struct	ifqueue impintrq;
72 int	impqmaxlen = IFQ_MAXLEN;
73 
74 /*
75  * Messages from IMP regarding why
76  * it's going down.
77  */
78 static char *impmessage[] = {
79 	"in 30 seconds",
80 	"for hardware PM",
81 	"to reload software",
82 	"for emergency reset"
83 };
84 
85 #define HOSTDEADTIMER	10		/* How long to wait when down */
86 
87 int	impdown(), impinit(), impioctl(), impoutput();
88 
89 /*
90  * IMP attach routine.  Called from hardware device attach routine
91  * at configuration time with a pointer to the UNIBUS device structure.
92  * Sets up local state and returns pointer to base of ifnet+impcb
93  * structures.  This is then used by the device's attach routine
94  * set up its back pointers.
95  */
96 impattach(ui, reset)
97 	struct uba_device *ui;
98 	int (*reset)();
99 {
100 	struct imp_softc *sc;
101 	register struct ifnet *ifp;
102 
103 #ifdef lint
104 	impintr();
105 #endif
106 	if (ui->ui_unit >= NIMP) {
107 		printf("imp%d: not configured\n", ui->ui_unit);
108 		return (0);
109 	}
110 	sc = &imp_softc[ui->ui_unit];
111 	ifp = &sc->imp_if;
112 	/* UNIT COULD BE AMBIGUOUS */
113 	ifp->if_unit = ui->ui_unit;
114 	ifp->if_name = "imp";
115 	ifp->if_mtu = IMPMTU - sizeof(struct imp_leader);
116 	ifp->if_reset = reset;
117 	ifp->if_init = impinit;
118 	ifp->if_ioctl = impioctl;
119 	ifp->if_output = impoutput;
120 	/* reset is handled at the hardware level */
121 	if_attach(ifp);
122 	return ((int)ifp);
123 }
124 
125 /*
126  * IMP initialization routine: call hardware module to
127  * setup UNIBUS resources, init state and get ready for
128  * NOOPs the IMP should send us, and that we want to drop.
129  */
130 impinit(unit)
131 	int unit;
132 {
133 	int s = splimp();
134 	register struct imp_softc *sc = &imp_softc[unit];
135 
136 	if (sc->imp_if.if_addrlist == 0)
137 		return;
138 	if ((*sc->imp_cb.ic_init)(unit) == 0) {
139 		sc->imp_state = IMPS_DOWN;
140 		sc->imp_if.if_flags &= ~IFF_UP;
141 		splx(s);
142 		return;
143 	}
144 	sc->imp_state = IMPS_INIT;
145 	impnoops(sc);
146 	impintrq.ifq_maxlen = impqmaxlen;
147 	splx(s);
148 }
149 
150 #ifdef IMPLEADERS
151 int	impprintfs = 0;
152 #endif
153 
154 /*
155  * ARPAnet 1822 input routine.
156  * Called from hardware input interrupt routine to handle 1822
157  * IMP-host messages.  Type 0 messages (non-control) are
158  * passed to higher level protocol processors on the basis
159  * of link number.  Other type messages (control) are handled here.
160  */
161 impinput(unit, m)
162 	int unit;
163 	register struct mbuf *m;
164 {
165 	register struct imp_leader *ip;
166 	register struct imp_softc *sc = &imp_softc[unit];
167 	struct ifnet *ifp;
168 	register struct host *hp;
169 	register struct ifqueue *inq;
170 	struct control_leader *cp;
171 	struct in_addr addr;
172 	struct mbuf *next;
173 	struct sockaddr_in *sin;
174 
175 	/*
176 	 * Pull the interface pointer out of the mbuf
177 	 * and save for later; adjust mbuf to look at rest of data.
178 	 */
179 	ifp = *(mtod(m, struct ifnet **));
180 	IF_ADJ(m);
181 	/* verify leader length. */
182 	if (m->m_len < sizeof(struct control_leader) &&
183 	    (m = m_pullup(m, sizeof(struct control_leader))) == 0)
184 		return;
185 	cp = mtod(m, struct control_leader *);
186 	if (cp->dl_mtype == IMPTYPE_DATA)
187 		if (m->m_len < sizeof(struct imp_leader) &&
188 		    (m = m_pullup(m, sizeof(struct imp_leader))) == 0)
189 			return;
190 	ip = mtod(m, struct imp_leader *);
191 #ifdef IMPLEADERS
192 	if (impprintfs)
193 		printleader("impinput", ip);
194 #endif
195 	inq = &impintrq;
196 
197 	/* check leader type */
198 	if (ip->il_format != IMP_NFF) {
199 		sc->imp_if.if_collisions++;	/* XXX */
200 		goto rawlinkin;
201 	}
202 
203 	if (ip->il_mtype != IMPTYPE_DATA) {
204 		/* If not data packet, build IP addr from leader (BRL) */
205 		imp_leader_to_addr(&addr, ip, &sc->imp_if);
206 	}
207 
208 	switch (ip->il_mtype) {
209 
210 	case IMPTYPE_DATA:
211 		/*
212 		 * Data for a protocol.  Dispatch to the appropriate
213 		 * protocol routine (running at software interrupt).
214 		 * If this isn't a raw interface, advance pointer
215 		 * into mbuf past leader.
216 		 */
217 		switch (ip->il_link) {
218 
219 		case IMPLINK_IP:
220 			m->m_len -= sizeof(struct imp_leader);
221 			m->m_off += sizeof(struct imp_leader);
222 			schednetisr(NETISR_IP);
223 			inq = &ipintrq;
224 			break;
225 
226 		default:
227 			break;
228 		}
229 		break;
230 
231 	/*
232 	 * IMP leader error.  Reset the IMP and discard the packet.
233 	 */
234 	case IMPTYPE_BADLEADER:
235 		/*
236 		 * According to 1822 document, this message
237 		 * will be generated in response to the
238 		 * first noop sent to the IMP after
239 		 * the host resets the IMP interface.
240 		 */
241 		if (sc->imp_state != IMPS_INIT) {
242 			impmsg(sc, "leader error");
243 			hostreset(((struct in_ifaddr *)&sc->imp_if.if_addrlist)->ia_net);
244 			impnoops(sc);
245 		}
246 		break;
247 
248 	/*
249 	 * IMP going down.  Print message, and if not immediate,
250 	 * set off a timer to insure things will be reset at the
251 	 * appropriate time.
252 	 */
253 	case IMPTYPE_DOWN:
254 		if (sc->imp_state < IMPS_INIT)
255 			break;
256 		if ((ip->il_link & IMP_DMASK) == 0) {
257 			sc->imp_state = IMPS_GOINGDOWN;
258 			timeout(impdown, (caddr_t)sc, 30 * hz);
259 		}
260 		impmsg(sc, "going down %s",
261 			(u_int)impmessage[ip->il_link&IMP_DMASK]);
262 		break;
263 
264 	/*
265 	 * A NOP usually seen during the initialization sequence.
266 	 * Compare the local address with that in the message.
267 	 * Reset the local address notion if it doesn't match.
268 	 */
269 	case IMPTYPE_NOOP:
270 		if (sc->imp_state == IMPS_DOWN) {
271 			sc->imp_state = IMPS_INIT;
272 			sc->imp_dropcnt = IMP_DROPCNT;
273 		}
274 		if (sc->imp_state == IMPS_INIT && --sc->imp_dropcnt > 0)
275 			break;
276 		sin = (struct sockaddr_in *)&sc->imp_if.if_addrlist->ifa_addr;
277 		if (ip->il_imp != 0) {
278 			struct in_addr leader_addr;
279 
280 			imp_leader_to_addr(&leader_addr, ip, &sc->imp_if);
281 			if (sin->sin_addr.s_addr != leader_addr.s_addr) {
282 				impmsg(sc, "address reset to x%x (%d/%d)",
283 					ntohl(leader_addr.s_addr),
284 					(u_int)ip->il_host,
285 					ntohs(ip->il_imp));
286 				sin->sin_addr.s_addr = leader_addr.s_addr;
287 			}
288 		}
289 		sc->imp_state = IMPS_UP;
290 		sc->imp_if.if_flags |= IFF_UP;
291 		break;
292 
293 	/*
294 	 * RFNM or INCOMPLETE message, send next
295 	 * message on the q.  We could pass incomplete's
296 	 * up to the next level, but this currently isn't
297 	 * needed.
298 	 */
299 	case IMPTYPE_RFNM:
300 	case IMPTYPE_INCOMPLETE:
301 		if (hp = hostlookup(addr)) {
302 			hp->h_timer = HOSTTIMER;
303 			if (hp->h_rfnm == 0)
304 				hp->h_flags &= ~HF_INUSE;
305 			else if (next = hostdeque(hp))
306 				(void) impsnd(&sc->imp_if, next);
307 		}
308 		goto drop;
309 
310 	/*
311 	 * Host or IMP can't be reached.  Flush any packets
312 	 * awaiting transmission and release the host structure.
313 	 * Enqueue for notifying protocols at software interrupt time.
314 	 */
315 	case IMPTYPE_HOSTDEAD:
316 	case IMPTYPE_HOSTUNREACH:
317 		if (hp = hostlookup(addr)) {
318 			hp->h_flags |= (1 << (int)ip->il_mtype);
319 			hostfree(hp);
320 			hp->h_timer = HOSTDEADTIMER;
321 		}
322 		break;
323 
324 	/*
325 	 * Error in data.  Clear RFNM status for this host and send
326 	 * noops to the IMP to clear the interface.
327 	 */
328 	case IMPTYPE_BADDATA:
329 		impmsg(sc, "data error");
330 		if (hp = hostlookup(addr))
331 			hp->h_rfnm = 0;
332 		impnoops(sc);
333 		break;
334 
335 	/*
336 	 * Interface reset.
337 	 */
338 	case IMPTYPE_RESET:
339 		impmsg(sc, "interface reset");
340 		/* clear RFNM counts */
341 		hostreset(((struct in_ifaddr *)&sc->imp_if.if_addrlist)->ia_net);
342 		impnoops(sc);
343 		break;
344 
345 	default:
346 		sc->imp_if.if_collisions++;		/* XXX */
347 		break;
348 	}
349 
350 rawlinkin:
351 	if (inq == &impintrq)
352 		schednetisr(NETISR_IMP);
353 	/*
354 	 * Re-insert interface pointer in the mbuf chain
355 	 * for the next protocol up.
356 	 */
357 	if (M_HASCL(m) && (mtod(m, int) & CLOFSET) < sizeof(struct ifnet *)) {
358 		struct mbuf *n;
359 
360 		MGET(n, M_DONTWAIT, MT_HEADER);
361 		if (n == 0)
362 			goto drop;
363 		n->m_next = m;
364 		m = n;
365 		m->m_len = 0;
366 		m->m_off = MMINOFF + sizeof(struct ifnet  *);
367 	}
368 	m->m_off -= sizeof(struct ifnet *);
369 	m->m_len += sizeof(struct ifnet *);
370 	*(mtod(m, struct ifnet **)) = ifp;
371 
372 	if (IF_QFULL(inq)) {
373 		IF_DROP(inq);
374 		goto drop;
375 	}
376 	IF_ENQUEUE(inq, m);
377 	return;
378 
379 drop:
380 	m_freem(m);
381 }
382 
383 /*
384  * Bring the IMP down after notification.
385  */
386 impdown(sc)
387 	struct imp_softc *sc;
388 {
389 	int s = splimp();
390 
391 	sc->imp_state = IMPS_DOWN;
392 	impmsg(sc, "marked down");
393 	hostreset(((struct in_ifaddr *)&sc->imp_if.if_addrlist)->ia_net);
394 	if_down(&sc->imp_if);
395 	splx(s);
396 }
397 
398 /*VARARGS2*/
399 impmsg(sc, fmt, a1, a2, a3)
400 	struct imp_softc *sc;
401 	char *fmt;
402 	u_int a1;
403 {
404 
405 	printf("imp%d: ", sc->imp_if.if_unit);
406 	printf(fmt, a1, a2, a3);
407 	printf("\n");
408 }
409 
410 struct sockproto impproto = { PF_IMPLINK };
411 struct sockaddr_in impdst = { AF_IMPLINK };
412 struct sockaddr_in impsrc = { AF_IMPLINK };
413 
414 /*
415  * Pick up the IMP "error" messages enqueued earlier,
416  * passing these up to the higher level protocol
417  * and the raw interface.
418  */
419 impintr()
420 {
421 	register struct mbuf *m;
422 	register struct control_leader *cp;
423 	struct ifnet *ifp;
424 	int s;
425 
426 	for (;;) {
427 		s = splimp();
428 		IF_DEQUEUEIF(&impintrq, m, ifp);
429 		splx(s);
430 		if (m == 0)
431 			return;
432 
433 		cp = mtod(m, struct control_leader *);
434 		imp_leader_to_addr(&impsrc.sin_addr, (struct imp_leader *)cp,
435 		    ifp);
436 		impproto.sp_protocol = cp->dl_link;
437 		impdst.sin_addr = IA_SIN(ifp->if_addrlist)->sin_addr;
438 
439 		if (cp->dl_mtype == IMPTYPE_HOSTDEAD ||
440 		    cp->dl_mtype == IMPTYPE_HOSTUNREACH)
441 			switch (cp->dl_link) {
442 
443 			case IMPLINK_IP:
444 				pfctlinput((int)cp->dl_mtype,
445 				    (struct sockaddr *)&impsrc);
446 				break;
447 			default:
448 				raw_ctlinput((int)cp->dl_mtype,
449 				    (struct sockaddr *)&impsrc);
450 				break;
451 			}
452 
453 		raw_input(m, &impproto, (struct sockaddr *)&impsrc,
454 		  (struct sockaddr *)&impdst);
455 	}
456 }
457 
458 /*
459  * ARPAnet 1822 output routine.
460  * Called from higher level protocol routines to set up messages for
461  * transmission to the imp.  Sets up the header and calls impsnd to
462  * enqueue the message for this IMP's hardware driver.
463  */
464 impoutput(ifp, m0, dst)
465 	register struct ifnet *ifp;
466 	struct mbuf *m0;
467 	struct sockaddr *dst;
468 {
469 	register struct imp_leader *imp;
470 	register struct mbuf *m = m0;
471 	int dlink, len;
472 	int error = 0;
473 
474 	/*
475 	 * Don't even try if the IMP is unavailable.
476 	 */
477 	if (imp_softc[ifp->if_unit].imp_state != IMPS_UP) {
478 		error = ENETDOWN;
479 		goto drop;
480 	}
481 
482 	switch (dst->sa_family) {
483 
484 	case AF_INET: {
485 		struct ip *ip = mtod(m, struct ip *);
486 
487 		dlink = IMPLINK_IP;
488 		len = ntohs((u_short)ip->ip_len);
489 		break;
490 	}
491 
492 	case AF_IMPLINK:
493 		len = 0;
494 		do
495 			len += m->m_len;
496 		while (m = m->m_next);
497 		m = m0;
498 		goto leaderexists;
499 
500 	default:
501 		printf("imp%d: can't handle af%d\n", ifp->if_unit,
502 			dst->sa_family);
503 		error = EAFNOSUPPORT;
504 		goto drop;
505 	}
506 
507 	/*
508 	 * Add IMP leader.  If there's not enough space in the
509 	 * first mbuf, allocate another.  If that should fail, we
510 	 * drop this sucker.
511 	 */
512 	if (m->m_off > MMAXOFF ||
513 	    MMINOFF + sizeof(struct imp_leader) > m->m_off) {
514 		m = m_get(M_DONTWAIT, MT_HEADER);
515 		if (m == 0) {
516 			error = ENOBUFS;
517 			goto drop;
518 		}
519 		m->m_next = m0;
520 		m->m_len = sizeof(struct imp_leader);
521 	} else {
522 		m->m_off -= sizeof(struct imp_leader);
523 		m->m_len += sizeof(struct imp_leader);
524 	}
525 	imp = mtod(m, struct imp_leader *);
526 	imp->il_format = IMP_NFF;
527 	imp->il_mtype = IMPTYPE_DATA;
528 	imp_addr_to_leader(imp,
529 		((struct sockaddr_in *)dst)->sin_addr.s_addr); /* BRL */
530 	imp->il_length = htons((u_short)len << 3);		/* BRL */
531 	imp->il_link = dlink;
532 	imp->il_flags = imp->il_htype = imp->il_subtype = 0;
533 
534 leaderexists:
535 	return (impsnd(ifp, m));
536 drop:
537 	m_freem(m0);
538 	return (error);
539 }
540 
541 /*
542  * Put a message on an interface's output queue.
543  * Perform RFNM counting: no more than 8 message may be
544  * in flight to any one host.
545  */
546 impsnd(ifp, m)
547 	struct ifnet *ifp;
548 	struct mbuf *m;
549 {
550 	register struct imp_leader *ip;
551 	register struct host *hp;
552 	struct impcb *icp;
553 	int s, error;
554 
555 	ip = mtod(m, struct imp_leader *);
556 
557 	/*
558 	 * Do RFNM counting for data messages
559 	 * (no more than 8 outstanding to any host)
560 	 */
561 	s = splimp();
562 	if (ip->il_mtype == IMPTYPE_DATA) {
563 		struct in_addr addr;
564 
565 		imp_leader_to_addr(&addr, ip, ifp);	/* BRL */
566 		if ((hp = hostlookup(addr)) == 0)
567 			hp = hostenter(addr);
568 		if (hp && (hp->h_flags & (HF_DEAD|HF_UNREACH))) {
569 			error = hp->h_flags&HF_DEAD ? EHOSTDOWN : EHOSTUNREACH;
570 			hp->h_flags &= ~HF_INUSE;
571 			goto bad;
572 		}
573 
574 		/*
575 		 * If IMP would block, queue until RFNM
576 		 */
577 		if (hp) {
578 #ifndef NORFNM
579 			if (hp->h_rfnm < 8)
580 #endif
581 			{
582 				hp->h_timer = HOSTTIMER;
583 				hp->h_rfnm++;
584 				goto enque;
585 			}
586 			if (hp->h_qcnt < 8) {	/* high water mark */
587 				HOST_ENQUE(hp, m);
588 				goto start;
589 			}
590 		}
591 		error = ENOBUFS;
592 		goto bad;
593 	}
594 enque:
595 	if (IF_QFULL(&ifp->if_snd)) {
596 		IF_DROP(&ifp->if_snd);
597 		error = ENOBUFS;
598 		if (ip->il_mtype == IMPTYPE_DATA)
599 			hp->h_rfnm--;
600 bad:
601 		m_freem(m);
602 		splx(s);
603 		return (error);
604 	}
605 	IF_ENQUEUE(&ifp->if_snd, m);
606 start:
607 	icp = &imp_softc[ifp->if_unit].imp_cb;
608 	if (icp->ic_oactive == 0)
609 		(*icp->ic_start)(ifp->if_unit);
610 	splx(s);
611 	return (0);
612 }
613 
614 /*
615  * Put three 1822 NOOPs at the head of the output queue.
616  * Part of host-IMP initialization procedure.
617  * (Should return success/failure, but noone knows
618  * what to do with this, so why bother?)
619  * This routine is always called at splimp, so we don't
620  * protect the call to IF_PREPEND.
621  */
622 impnoops(sc)
623 	register struct imp_softc *sc;
624 {
625 	register i;
626 	register struct mbuf *m;
627 	register struct control_leader *cp;
628 
629 	sc->imp_dropcnt = IMP_DROPCNT;
630 	for (i = 0; i < IMP_DROPCNT + 1; i++) {
631 		if ((m = m_getclr(M_DONTWAIT, MT_HEADER)) == 0)
632 			return;
633 		m->m_len = sizeof(struct control_leader);
634 		cp = mtod(m, struct control_leader *);
635 		cp->dl_format = IMP_NFF;
636                 cp->dl_link = i;
637                 cp->dl_mtype = IMPTYPE_NOOP;
638 		IF_PREPEND(&sc->imp_if.if_snd, m);
639 	}
640 	if (sc->imp_cb.ic_oactive == 0)
641 		(*sc->imp_cb.ic_start)(sc->imp_if.if_unit);
642 }
643 
644 /*
645  * Process an ioctl request.
646  */
647 impioctl(ifp, cmd, data)
648 	register struct ifnet *ifp;
649 	int cmd;
650 	caddr_t data;
651 {
652 	struct ifaddr *ifa = (struct ifaddr *) data;
653 	int s = splimp(), error = 0;
654 
655 	switch (cmd) {
656 
657 	case SIOCSIFADDR:
658 		if (ifa->ifa_addr.sa_family != AF_INET) {
659 			error = EINVAL;
660 			break;
661 		}
662 		if ((ifp->if_flags & IFF_RUNNING) == 0)
663 			impinit(ifp->if_unit);
664 		break;
665 
666 	default:
667 		error = EINVAL;
668 	}
669 	splx(s);
670 	return (error);
671 }
672 
673 #ifdef IMPLEADERS
674 printleader(routine, ip)
675 	char *routine;
676 	register struct imp_leader *ip;
677 {
678 	printf("%s: ", routine);
679 	printbyte((char *)ip, 12);
680 	printf("<fmt=%x,net=%x,flags=%x,mtype=", ip->il_format, ip->il_network,
681 		ip->il_flags);
682 	if (ip->il_mtype <= IMPTYPE_READY)
683 		printf("%s,", impleaders[ip->il_mtype]);
684 	else
685 		printf("%x,", ip->il_mtype);
686 	printf("htype=%x,host=%x,imp=%x,link=", ip->il_htype, ip->il_host,
687 		ntohs(ip->il_imp));
688 	if (ip->il_link == IMPLINK_IP)
689 		printf("ip,");
690 	else
691 		printf("%x,", ip->il_link);
692 	printf("subtype=%x,len=%x>\n",ip->il_subtype,ntohs(ip->il_length)>>3);
693 }
694 
695 printbyte(cp, n)
696 	register char *cp;
697 	int n;
698 {
699 	register i, j, c;
700 
701 	for (i=0; i<n; i++) {
702 		c = *cp++;
703 		for (j=0; j<2; j++)
704 			putchar("0123456789abcdef"[(c>>((1-j)*4))&0xf], 0);
705 		putchar(' ', 0);
706 	}
707 	putchar('\n', 0);
708 }
709 #endif
710 
711 /*
712  * Routine to convert from IMP Leader to InterNet Address.
713  *
714  * This procedure is necessary because IMPs may be assigned Class A, B, or C
715  * network numbers, but only have 8 bits in the leader to reflect the
716  * IMP "network number".  The strategy is to take the network number from
717  * the ifnet structure, and blend in the host-on-imp and imp-on-net numbers
718  * from the leader.
719  *
720  * There is no support for "Logical Hosts".
721  *
722  * Class A:	Net.Host.0.Imp
723  * Class B:	Net.net.Host.Imp
724  * Class C:	Net.net.net.(Host4|Imp4)
725  */
726 imp_leader_to_addr(ap, ip, ifp)
727 	struct in_addr *ap;
728 	register struct imp_leader *ip;
729 	struct ifnet *ifp;
730 {
731 	register u_long final;
732 	register struct sockaddr_in *sin;
733 	int imp = ntohs(ip->il_imp);
734 
735 	sin = (struct sockaddr_in *)(&ifp->if_addrlist->ifa_addr);
736 	final = ntohl(sin->sin_addr.s_addr);
737 
738 	if (IN_CLASSA(final)) {
739 		final &= IN_CLASSA_NET;
740 		final |= (imp & 0xFF) | ((ip->il_host & 0xFF)<<16);
741 	} else if (IN_CLASSB(final)) {
742 		final &= IN_CLASSB_NET;
743 		final |= (imp & 0xFF) | ((ip->il_host & 0xFF)<<8);
744 	} else {
745 		final &= IN_CLASSC_NET;
746 		final |= (imp & 0x0F) | ((ip->il_host & 0x0F)<<4);
747 	}
748 	ap->s_addr = htonl(final);
749 }
750 
751 /*
752  * Function to take InterNet address and fill in IMP leader fields.
753  */
754 imp_addr_to_leader(imp, a)
755 	register struct imp_leader *imp;
756 	u_long a;
757 {
758 	register u_long addr = ntohl(a);
759 
760 	imp->il_network = 0;	/* !! */
761 
762 	if (IN_CLASSA(addr)) {
763 		imp->il_host = ((addr>>16) & 0xFF);
764 		imp->il_imp = addr & 0xFF;
765 	} else if (IN_CLASSB(addr)) {
766 		imp->il_host = ((addr>>8) & 0xFF);
767 		imp->il_imp = addr & 0xFF;
768 	} else {
769 		imp->il_host = ((addr>>4) & 0xF);
770 		imp->il_imp = addr & 0xF;
771 	}
772 	imp->il_imp = htons(imp->il_imp);
773 }
774 #endif
775