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