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