if_reset instead of if_ubareset
[unix-history] / usr / src / sys / deprecated / netimp / if_imp.c
CommitLineData
ac697091 1/* if_imp.c 4.44 82/10/31 */
6c73ade6
BJ
2
3#include "imp.h"
4#if NIMP > 0
5/*
72e4f44e 6 * ARPANET IMP interface driver.
6c73ade6
BJ
7 *
8 * The IMP-host protocol is handled here, leaving
9 * hardware specifics to the lower level interface driver.
10 */
11#include "../h/param.h"
12#include "../h/systm.h"
13#include "../h/mbuf.h"
14#include "../h/pte.h"
15#include "../h/buf.h"
16#include "../h/protosw.h"
17#include "../h/socket.h"
6c73ade6 18#include "../h/vmmac.h"
6e7edb25
BJ
19
20#include "../vax/cpu.h"
21#include "../vax/mtpr.h"
39d536e6
BJ
22#include "../vaxuba/ubareg.h"
23#include "../vaxuba/ubavar.h"
6e7edb25 24
6c73ade6 25#include "../net/if.h"
6e7edb25 26#include "../net/route.h"
5e3649c6 27#include "../net/netisr.h"
6e7edb25
BJ
28#include "../netinet/in.h"
29#include "../netinet/in_systm.h"
30#include "../netinet/ip.h"
31#include "../netinet/ip_var.h"
b690198c 32/* define IMPLEADERS here to get leader printing code */
5e3649c6
BJ
33#include "../netimp/if_imp.h"
34#include "../netimp/if_imphost.h"
8a2f82db 35#include <errno.h>
6c73ade6
BJ
36
37/*
38 * IMP software status per interface.
39 * (partially shared with the hardware specific module)
40 *
41 * Each interface is referenced by a network interface structure,
42 * imp_if, which the routing code uses to locate the interface.
43 * This structure contains the output queue for the interface, its
44 * address, ... IMP specific structures used in connecting the
45 * IMP software modules to the hardware specific interface routines
a2cd4df7
BJ
46 * are stored here. The common structures are made visible to the
47 * interface driver by passing a pointer to the hardware routine
48 * at "attach" time.
6c73ade6
BJ
49 *
50 * NOTE: imp_if and imp_cb are assumed adjacent in hardware code.
51 */
52struct imp_softc {
53 struct ifnet imp_if; /* network visible interface */
54 struct impcb imp_cb; /* hooks to hardware module */
55 u_char imp_state; /* current state of IMP */
56 char imp_dropcnt; /* used during initialization */
6c73ade6
BJ
57} imp_softc[NIMP];
58
59/*
60 * Messages from IMP regarding why
61 * it's going down.
62 */
e33b5b1a 63static char *impmessage[] = {
6c73ade6
BJ
64 "in 30 seconds",
65 "for hardware PM",
66 "to reload software",
67 "for emergency reset"
68};
69
a2cd4df7
BJ
70int impdown(), impinit(), impoutput();
71
6c73ade6
BJ
72/*
73 * IMP attach routine. Called from hardware device attach routine
74 * at configuration time with a pointer to the UNIBUS device structure.
75 * Sets up local state and returns pointer to base of ifnet+impcb
76 * structures. This is then used by the device's attach routine
77 * set up its back pointers.
78 */
30c36259 79impattach(ui, reset)
6c73ade6 80 struct uba_device *ui;
30c36259 81 int (*reset)();
6c73ade6
BJ
82{
83 struct imp_softc *sc = &imp_softc[ui->ui_unit];
84 register struct ifnet *ifp = &sc->imp_if;
ee787340 85 struct sockaddr_in *sin;
6c73ade6 86
6c73ade6
BJ
87 /* UNIT COULD BE AMBIGUOUS */
88 ifp->if_unit = ui->ui_unit;
89 ifp->if_name = "imp";
e431883e 90 ifp->if_mtu = IMPMTU - sizeof(struct imp_leader);
6c73ade6 91 ifp->if_net = ui->ui_flags;
ac697091 92 ifp->if_reset = reset;
aee8ddf8 93 /* the host and imp fields will be filled in by the imp */
ee787340
SL
94 sin = (struct sockaddr_in *)&ifp->if_addr;
95 sin->sin_family = AF_INET;
96 sin->sin_addr = if_makeaddr(ifp->if_net, 0);
a2cd4df7
BJ
97 ifp->if_init = impinit;
98 ifp->if_output = impoutput;
99 /* reset is handled at the hardware level */
6c73ade6 100 if_attach(ifp);
6c73ade6
BJ
101 return ((int)&sc->imp_if);
102}
103
104/*
105 * IMP initialization routine: call hardware module to
106 * setup UNIBUS resources, init state and get ready for
107 * NOOPs the IMP should send us, and that we want to drop.
108 */
109impinit(unit)
110 int unit;
111{
98b6195e 112 int s = splimp();
6c73ade6
BJ
113 register struct imp_softc *sc = &imp_softc[unit];
114
a2cd4df7
BJ
115 if ((*sc->imp_cb.ic_init)(unit) == 0) {
116 sc->imp_state = IMPS_DOWN;
ee787340 117 sc->imp_if.if_flags &= ~IFF_UP;
98b6195e 118 splx(s);
a2cd4df7
BJ
119 return;
120 }
6c73ade6 121 sc->imp_state = IMPS_INIT;
a2cd4df7 122 impnoops(sc);
98b6195e 123 splx(s);
6c73ade6
BJ
124}
125
126struct sockproto impproto = { PF_IMPLINK };
faad37c0
SL
127struct sockaddr_in impdst = { AF_IMPLINK };
128struct sockaddr_in impsrc = { AF_IMPLINK };
b690198c 129#ifdef IMPLEADERS
7dfb87a5 130int impprintfs = 0;
b690198c 131#endif
6c73ade6
BJ
132
133/*
134 * ARPAnet 1822 input routine.
135 * Called from hardware input interrupt routine to handle 1822
136 * IMP-host messages. Type 0 messages (non-control) are
137 * passed to higher level protocol processors on the basis
138 * of link number. Other type messages (control) are handled here.
139 */
a2cd4df7 140impinput(unit, m)
6c73ade6 141 int unit;
a2cd4df7 142 register struct mbuf *m;
6c73ade6 143{
6c73ade6
BJ
144 register struct imp_leader *ip;
145 register struct imp_softc *sc = &imp_softc[unit];
146 register struct host *hp;
147 register struct ifqueue *inq;
a2cd4df7 148 struct control_leader *cp;
6c73ade6 149 struct in_addr addr;
e33b5b1a 150 struct mbuf *next;
ee787340 151 struct sockaddr_in *sin;
6c73ade6 152
34c22ab5 153 /* verify leader length. */
a2cd4df7
BJ
154 if (m->m_len < sizeof(struct control_leader) &&
155 (m = m_pullup(m, sizeof(struct control_leader))) == 0)
156 return;
157 cp = mtod(m, struct control_leader *);
158 if (cp->dl_mtype == IMPTYPE_DATA)
159 if (m->m_len < sizeof(struct imp_leader) &&
160 (m = m_pullup(m, sizeof(struct imp_leader))) == 0)
161 return;
6c73ade6 162 ip = mtod(m, struct imp_leader *);
b690198c 163#ifdef IMPLEADERS
7dfb87a5
SL
164 if (impprintfs)
165 printleader("impinput", ip);
b690198c 166#endif
6c73ade6 167
34c22ab5 168 /* check leader type */
a2cd4df7
BJ
169 if (ip->il_format != IMP_NFF) {
170 sc->imp_if.if_collisions++; /* XXX */
6c73ade6 171 goto drop;
a2cd4df7 172 }
6c73ade6 173
ba45553a 174 if (ip->il_mtype != IMPTYPE_DATA) {
41e530c7 175#ifdef notdef
a2cd4df7 176 addr.s_net = ip->il_network;
41e530c7 177#else
ba45553a 178 addr.s_net = sc->imp_if.if_net;
41e530c7 179#endif
a2cd4df7
BJ
180 addr.s_imp = ip->il_imp;
181 addr.s_host = ip->il_host;
6c73ade6 182 }
6c73ade6
BJ
183 switch (ip->il_mtype) {
184
6c73ade6 185 case IMPTYPE_DATA:
6c73ade6
BJ
186 break;
187
188 /*
189 * IMP leader error. Reset the IMP and discard the packet.
190 */
191 case IMPTYPE_BADLEADER:
a0b7c7fb
SL
192 /*
193 * According to 1822 document, this message
194 * will be generated in response to the
195 * first noop sent to the IMP after
196 * the host resets the IMP interface.
197 */
a2cd4df7 198 if (sc->imp_state != IMPS_INIT) {
e33b5b1a 199 impmsg(sc, "leader error");
72e4f44e 200 hostreset(sc->imp_if.if_net);
a0b7c7fb
SL
201 impnoops(sc);
202 }
72e4f44e 203 goto drop;
6c73ade6
BJ
204
205 /*
206 * IMP going down. Print message, and if not immediate,
207 * set off a timer to insure things will be reset at the
208 * appropriate time.
209 */
210 case IMPTYPE_DOWN:
f32a85bb 211 if (sc->imp_state < IMPS_INIT)
47e51140 212 goto drop;
6c73ade6
BJ
213 if ((ip->il_link & IMP_DMASK) == 0) {
214 sc->imp_state = IMPS_GOINGDOWN;
668cc26d 215 timeout(impdown, (caddr_t)sc, 30 * hz);
6c73ade6 216 }
668cc26d
SL
217 impmsg(sc, "going down %s",
218 (u_int)impmessage[ip->il_link&IMP_DMASK]);
72e4f44e 219 goto drop;
6c73ade6
BJ
220
221 /*
222 * A NOP usually seen during the initialization sequence.
223 * Compare the local address with that in the message.
224 * Reset the local address notion if it doesn't match.
225 */
ee787340 226 case IMPTYPE_NOOP:
a0b7c7fb
SL
227 if (sc->imp_state == IMPS_DOWN) {
228 sc->imp_state = IMPS_INIT;
229 sc->imp_dropcnt = IMP_DROPCNT;
230 }
98b6195e 231 if (sc->imp_state == IMPS_INIT && --sc->imp_dropcnt > 0)
e431883e 232 goto drop;
98b6195e
SL
233 sin = (struct sockaddr_in *)&sc->imp_if.if_addr;
234 if (sin->sin_addr.s_host != ip->il_host ||
235 sin->sin_addr.s_imp != ip->il_imp) {
236 sc->imp_if.if_host[0] =
237 sin->sin_addr.s_host = ip->il_host;
238 sin->sin_addr.s_imp = ip->il_imp;
239 impmsg(sc, "reset (host %d/imp %d)", (u_int)ip->il_host,
240 ntohs(ip->il_imp));
241 }
a2cd4df7 242 sc->imp_state = IMPS_UP;
ee787340 243 sc->imp_if.if_flags |= IFF_UP;
88f80700 244 if_rtinit(&sc->imp_if, RTF_UP);
e431883e 245 goto drop;
6c73ade6
BJ
246
247 /*
72e4f44e
SL
248 * RFNM or INCOMPLETE message, send next
249 * message on the q. We could pass incomplete's
250 * up to the next level, but this currently isn't
251 * needed.
6c73ade6
BJ
252 */
253 case IMPTYPE_RFNM:
254 case IMPTYPE_INCOMPLETE:
ba45553a
SL
255 if (hp = hostlookup(addr)) {
256 if (hp->h_rfnm == 0)
257 hp->h_flags &= ~HF_INUSE;
258 else if (next = hostdeque(hp))
259 (void) impsnd(&sc->imp_if, next);
260 }
e431883e 261 goto drop;
6c73ade6
BJ
262
263 /*
264 * Host or IMP can't be reached. Flush any packets
265 * awaiting transmission and release the host structure.
6c73ade6
BJ
266 */
267 case IMPTYPE_HOSTDEAD:
ba45553a
SL
268 case IMPTYPE_HOSTUNREACH: {
269 int s = splnet();
6e7edb25
BJ
270 impnotify((int)ip->il_mtype, (struct control_leader *)ip,
271 hostlookup(addr));
ba45553a 272 splx(s);
41e530c7 273 goto rawlinkin;
ba45553a 274 }
6c73ade6
BJ
275
276 /*
277 * Error in data. Clear RFNM status for this host and send
278 * noops to the IMP to clear the interface.
279 */
ba45553a
SL
280 case IMPTYPE_BADDATA: {
281 int s;
282
e33b5b1a 283 impmsg(sc, "data error");
ba45553a
SL
284 s = splnet();
285 if (hp = hostlookup(addr))
6c73ade6 286 hp->h_rfnm = 0;
ba45553a 287 splx(s);
6c73ade6 288 impnoops(sc);
72e4f44e 289 goto drop;
ba45553a 290 }
6c73ade6
BJ
291
292 /*
a0b7c7fb 293 * Interface reset.
6c73ade6
BJ
294 */
295 case IMPTYPE_RESET:
e33b5b1a 296 impmsg(sc, "interface reset");
a0b7c7fb 297 impnoops(sc);
72e4f44e 298 goto drop;
6c73ade6
BJ
299
300 default:
301 sc->imp_if.if_collisions++; /* XXX */
72e4f44e 302 goto drop;
6c73ade6
BJ
303 }
304
305 /*
34c22ab5
BJ
306 * Data for a protocol. Dispatch to the appropriate
307 * protocol routine (running at software interrupt).
308 * If this isn't a raw interface, advance pointer
309 * into mbuf past leader.
6c73ade6
BJ
310 */
311 switch (ip->il_link) {
312
313#ifdef INET
314 case IMPLINK_IP:
315 m->m_len -= sizeof(struct imp_leader);
316 m->m_off += sizeof(struct imp_leader);
9c8692e9 317 schednetisr(NETISR_IP);
6c73ade6
BJ
318 inq = &ipintrq;
319 break;
320#endif
321
322 default:
654fef96 323 rawlinkin:
6c73ade6 324 impproto.sp_protocol = ip->il_link;
ee787340
SL
325 sin = (struct sockaddr_in *)&sc->imp_if.if_addr;
326 impdst.sin_addr = sin->sin_addr;;
faad37c0
SL
327 impsrc.sin_addr.s_net = ip->il_network;
328 impsrc.sin_addr.s_host = ip->il_host;
329 impsrc.sin_addr.s_imp = ip->il_imp;
57aa3090
SL
330 raw_input(m, &impproto, (struct sockaddr *)&impsrc,
331 (struct sockaddr *)&impdst);
6c73ade6
BJ
332 return;
333 }
1e977657
BJ
334 if (IF_QFULL(inq)) {
335 IF_DROP(inq);
336 goto drop;
337 }
6c73ade6
BJ
338 IF_ENQUEUE(inq, m);
339 return;
340
341drop:
342 m_freem(m);
343}
344
a0b7c7fb
SL
345/*
346 * Bring the IMP down after notification.
347 */
348impdown(sc)
349 struct imp_softc *sc;
350{
1e977657 351
a0b7c7fb 352 sc->imp_state = IMPS_DOWN;
e33b5b1a 353 impmsg(sc, "marked down");
ba45553a 354 hostreset(sc->imp_if.if_net);
72e4f44e 355 if_down(&sc->imp_if);
a0b7c7fb
SL
356}
357
6c73ade6 358/*VARARGS*/
e33b5b1a 359impmsg(sc, fmt, a1, a2)
6c73ade6
BJ
360 struct imp_softc *sc;
361 char *fmt;
668cc26d 362 u_int a1;
6c73ade6 363{
1e977657 364
6c73ade6
BJ
365 printf("imp%d: ", sc->imp_if.if_unit);
366 printf(fmt, a1, a2);
367 printf("\n");
368}
369
72e4f44e
SL
370/*
371 * Process an IMP "error" message, passing this
372 * up to the higher level protocol.
373 */
374impnotify(what, cp, hp)
375 int what;
376 struct control_leader *cp;
377 struct host *hp;
378{
379 struct in_addr in;
380
381#ifdef notdef
382 in.s_net = cp->dl_network;
383#else
ba45553a 384 in.s_net = 10; /* XXX */
72e4f44e
SL
385#endif
386 in.s_host = cp->dl_host;
387 in.s_imp = cp->dl_imp;
388 if (cp->dl_link != IMPLINK_IP)
389 raw_ctlinput(what, (caddr_t)&in);
390 else
391 ip_ctlinput(what, (caddr_t)&in);
ba45553a
SL
392 if (hp) {
393 hp->h_flags |= (1 << what);
72e4f44e 394 hostfree(hp);
ba45553a 395 }
72e4f44e
SL
396}
397
6c73ade6
BJ
398/*
399 * ARPAnet 1822 output routine.
400 * Called from higher level protocol routines to set up messages for
401 * transmission to the imp. Sets up the header and calls impsnd to
402 * enqueue the message for this IMP's hardware driver.
403 */
ee787340 404impoutput(ifp, m0, dst)
6c73ade6
BJ
405 register struct ifnet *ifp;
406 struct mbuf *m0;
ee787340 407 struct sockaddr *dst;
6c73ade6
BJ
408{
409 register struct imp_leader *imp;
410 register struct mbuf *m = m0;
39d536e6 411 int dhost, dimp, dlink, len, dnet;
8a2f82db 412 int error = 0;
6c73ade6
BJ
413
414 /*
415 * Don't even try if the IMP is unavailable.
416 */
8a2f82db
SL
417 if (imp_softc[ifp->if_unit].imp_state != IMPS_UP) {
418 error = ENETDOWN;
a0b7c7fb 419 goto drop;
8a2f82db 420 }
6c73ade6 421
ee787340 422 switch (dst->sa_family) {
6c73ade6
BJ
423
424#ifdef INET
ee787340
SL
425 case AF_INET: {
426 struct ip *ip = mtod(m0, struct ip *);
427 struct sockaddr_in *sin = (struct sockaddr_in *)dst;
6c73ade6 428
ee787340
SL
429 dhost = sin->sin_addr.s_host;
430 dimp = sin->sin_addr.s_impno;
6c73ade6 431 dlink = IMPLINK_IP;
1e63a6ab 432 dnet = 0;
668cc26d 433 len = ntohs((u_short)ip->ip_len);
6c73ade6
BJ
434 break;
435 }
436#endif
ee787340 437 case AF_IMPLINK:
6c73ade6
BJ
438 goto leaderexists;
439
440 default:
ee787340
SL
441 printf("imp%d: can't handle af%d\n", ifp->if_unit,
442 dst->sa_family);
8a2f82db 443 error = EAFNOSUPPORT;
a0b7c7fb 444 goto drop;
6c73ade6
BJ
445 }
446
447 /*
448 * Add IMP leader. If there's not enough space in the
449 * first mbuf, allocate another. If that should fail, we
450 * drop this sucker.
451 */
452 if (m->m_off > MMAXOFF ||
453 MMINOFF + sizeof(struct imp_leader) > m->m_off) {
454 m = m_get(M_DONTWAIT);
8a2f82db
SL
455 if (m == 0) {
456 error = ENOBUFS;
a0b7c7fb 457 goto drop;
8a2f82db 458 }
6c73ade6 459 m->m_next = m0;
6c73ade6
BJ
460 m->m_len = sizeof(struct imp_leader);
461 } else {
462 m->m_off -= sizeof(struct imp_leader);
463 m->m_len += sizeof(struct imp_leader);
464 }
465 imp = mtod(m, struct imp_leader *);
466 imp->il_format = IMP_NFF;
41e530c7 467 imp->il_mtype = IMPTYPE_DATA;
1e63a6ab 468 imp->il_network = dnet;
6c73ade6 469 imp->il_host = dhost;
1e63a6ab 470 imp->il_imp = htons((u_short)dimp);
668cc26d
SL
471 imp->il_length =
472 htons((u_short)(len + sizeof(struct imp_leader)) << 3);
6c73ade6 473 imp->il_link = dlink;
41e530c7 474 imp->il_flags = imp->il_htype = imp->il_subtype = 0;
6c73ade6
BJ
475
476leaderexists:
6c73ade6 477 return (impsnd(ifp, m));
a0b7c7fb
SL
478drop:
479 m_freem(m0);
8a2f82db 480 return (error);
6c73ade6
BJ
481}
482
483/*
484 * Put a message on an interface's output queue.
485 * Perform RFNM counting: no more than 8 message may be
486 * in flight to any one host.
487 */
488impsnd(ifp, m)
489 struct ifnet *ifp;
490 struct mbuf *m;
491{
492 register struct imp_leader *ip;
493 register struct host *hp;
494 struct impcb *icp;
ba45553a 495 int s, error;
6c73ade6
BJ
496
497 ip = mtod(m, struct imp_leader *);
498
499 /*
500 * Do RFNM counting for data messages
501 * (no more than 8 outstanding to any host)
502 */
ba45553a 503 s = splimp();
6c73ade6
BJ
504 if (ip->il_mtype == IMPTYPE_DATA) {
505 struct in_addr addr;
506
41e530c7 507#ifdef notdef
a2cd4df7 508 addr.s_net = ip->il_network;
41e530c7 509#else
ba45553a 510 addr.s_net = ifp->if_net; /* XXX */
41e530c7 511#endif
6c73ade6
BJ
512 addr.s_host = ip->il_host;
513 addr.s_imp = ip->il_imp;
a2cd4df7
BJ
514 if ((hp = hostlookup(addr)) == 0)
515 hp = hostenter(addr);
ba45553a 516 if (hp && (hp->h_flags & (HF_DEAD|HF_UNREACH))) {
67387c9c 517 error = hp->h_flags&HF_DEAD ? EHOSTDOWN : EHOSTUNREACH;
ba45553a
SL
518 hp->h_timer = HOSTTIMER;
519 hp->h_flags &= ~HF_INUSE;
520 goto bad;
ba45553a 521 }
6c73ade6
BJ
522
523 /*
a0b7c7fb 524 * If IMP would block, queue until RFNM
6c73ade6
BJ
525 */
526 if (hp) {
6c73ade6
BJ
527 if (hp->h_rfnm < 8) {
528 hp->h_rfnm++;
529 goto enque;
530 }
fcd78660
BJ
531 if (hp->h_qcnt < 8) { /* high water mark */
532 HOST_ENQUE(hp, m);
533 goto start;
534 }
6c73ade6 535 }
ba45553a
SL
536 error = ENOBUFS;
537 goto bad;
6c73ade6
BJ
538 }
539enque:
1e977657
BJ
540 if (IF_QFULL(&ifp->if_snd)) {
541 IF_DROP(&ifp->if_snd);
ba45553a
SL
542 error = ENOBUFS;
543bad:
1e977657 544 m_freem(m);
ba45553a
SL
545 splx(s);
546 return (error);
1e977657 547 }
6c73ade6 548 IF_ENQUEUE(&ifp->if_snd, m);
6c73ade6
BJ
549start:
550 icp = &imp_softc[ifp->if_unit].imp_cb;
551 if (icp->ic_oactive == 0)
552 (*icp->ic_start)(ifp->if_unit);
70e3101c 553 splx(s);
8a2f82db 554 return (0);
6c73ade6
BJ
555}
556
557/*
558 * Put three 1822 NOOPs at the head of the output queue.
559 * Part of host-IMP initialization procedure.
560 * (Should return success/failure, but noone knows
561 * what to do with this, so why bother?)
0dc78444
SL
562 * This routine is always called at splimp, so we don't
563 * protect the call to IF_PREPEND.
6c73ade6
BJ
564 */
565impnoops(sc)
566 register struct imp_softc *sc;
567{
568 register i;
569 register struct mbuf *m;
a2cd4df7 570 register struct control_leader *cp;
6c73ade6 571
6c73ade6 572 sc->imp_dropcnt = IMP_DROPCNT;
a2cd4df7 573 for (i = 0; i < IMP_DROPCNT + 1; i++ ) {
6c73ade6
BJ
574 if ((m = m_getclr(M_DONTWAIT)) == 0)
575 return;
a2cd4df7
BJ
576 m->m_len = sizeof(struct control_leader);
577 cp = mtod(m, struct control_leader *);
578 cp->dl_format = IMP_NFF;
579 cp->dl_link = i;
580 cp->dl_mtype = IMPTYPE_NOOP;
6c73ade6 581 IF_PREPEND(&sc->imp_if.if_snd, m);
6c73ade6
BJ
582 }
583 if (sc->imp_cb.ic_oactive == 0)
584 (*sc->imp_cb.ic_start)(sc->imp_if.if_unit);
585}
7dfb87a5
SL
586
587#ifdef IMPLEADERS
588printleader(routine, ip)
589 char *routine;
590 register struct imp_leader *ip;
591{
592 printf("%s: ", routine);
593 printbyte((char *)ip, 12);
594 printf("<fmt=%x,net=%x,flags=%x,mtype=", ip->il_format, ip->il_network,
595 ip->il_flags);
596 if (ip->il_mtype <= IMPTYPE_READY)
597 printf("%s,", impleaders[ip->il_mtype]);
598 else
599 printf("%x,", ip->il_mtype);
600 printf("htype=%x,host=%x,imp=%x,link=", ip->il_htype, ip->il_host,
601 ntohs(ip->il_imp));
602 if (ip->il_link == IMPLINK_IP)
603 printf("ip,");
604 else
605 printf("%x,", ip->il_link);
606 printf("subtype=%x,len=%x>\n",ip->il_subtype,ntohs(ip->il_length)>>3);
607}
608
609printbyte(cp, n)
610 register char *cp;
611 int n;
612{
613 register i, j, c;
614
615 for (i=0; i<n; i++) {
616 c = *cp++;
617 for (j=0; j<2; j++)
618 putchar("0123456789abcdef"[(c>>((1-j)*4))&0xf]);
619 putchar(' ');
620 }
621 putchar('\n');
622}
623#endif
41e530c7 624#endif