cleanup before start of testing
[unix-history] / usr / src / sys / deprecated / netimp / if_imp.c
CommitLineData
a0b7c7fb 1/* if_imp.c 4.3 82/02/01 */
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.
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"
27#include "../net/host.h"
28#include "../net/ip.h"
29#include "../net/ip_var.h"
30
31/*
32 * IMP software status per interface.
33 * (partially shared with the hardware specific module)
34 *
35 * Each interface is referenced by a network interface structure,
36 * imp_if, which the routing code uses to locate the interface.
37 * This structure contains the output queue for the interface, its
38 * address, ... IMP specific structures used in connecting the
39 * IMP software modules to the hardware specific interface routines
40 * are also stored here. These structures are visible in the interface
41 * driver through back pointers set up in the hardware's attach routine.
42 *
43 * NOTE: imp_if and imp_cb are assumed adjacent in hardware code.
44 */
45struct imp_softc {
46 struct ifnet imp_if; /* network visible interface */
47 struct impcb imp_cb; /* hooks to hardware module */
48 u_char imp_state; /* current state of IMP */
49 char imp_dropcnt; /* used during initialization */
50 short imp_timer; /* going down timer */
51} imp_softc[NIMP];
52
53/*
54 * Messages from IMP regarding why
55 * it's going down.
56 */
57static char *impmsg[] = {
58 "in 30 seconds",
59 "for hardware PM",
60 "to reload software",
61 "for emergency reset"
62};
63
64/*
65 * IMP attach routine. Called from hardware device attach routine
66 * at configuration time with a pointer to the UNIBUS device structure.
67 * Sets up local state and returns pointer to base of ifnet+impcb
68 * structures. This is then used by the device's attach routine
69 * set up its back pointers.
70 */
71impattach(ui)
72 struct uba_device *ui;
73{
74 struct imp_softc *sc = &imp_softc[ui->ui_unit];
75 register struct ifnet *ifp = &sc->imp_if;
76
77COUNT(IMPATTACH);
78 /* UNIT COULD BE AMBIGUOUS */
79 ifp->if_unit = ui->ui_unit;
80 ifp->if_name = "imp";
81 ifp->if_mtu = IMP_MTU;
82 ifp->if_net = ui->ui_flags;
83/* ifp->if_host = ... */
84/* ifp->if_addr = if_makeaddr(ifp->if_net, ifp->if_host); */
85 if_attach(ifp);
86 /* kludge to hand pointers back to hardware attach routine */
87 return ((int)&sc->imp_if);
88}
89
90/*
91 * IMP initialization routine: call hardware module to
92 * setup UNIBUS resources, init state and get ready for
93 * NOOPs the IMP should send us, and that we want to drop.
94 */
95impinit(unit)
96 int unit;
97{
98 register struct imp_softc *sc = &imp_softc[unit];
99
100 (*sc->imp_cb.ic_init)(unit);
101 sc->imp_state = IMPS_INIT;
102 sc->imp_dropcnt = IMP_DROPCNT;
103}
104
105struct sockproto impproto = { PF_IMPLINK };
faad37c0
SL
106struct sockaddr_in impdst = { AF_IMPLINK };
107struct sockaddr_in impsrc = { AF_IMPLINK };
6c73ade6
BJ
108
109/*
110 * ARPAnet 1822 input routine.
111 * Called from hardware input interrupt routine to handle 1822
112 * IMP-host messages. Type 0 messages (non-control) are
113 * passed to higher level protocol processors on the basis
114 * of link number. Other type messages (control) are handled here.
115 */
116impinput(unit, m0)
117 int unit;
118 struct mbuf *m0;
119{
120 int s;
121 register struct mbuf *m;
122 register struct imp_leader *ip;
123 register struct imp_softc *sc = &imp_softc[unit];
124 register struct host *hp;
125 register struct ifqueue *inq;
126 struct in_addr addr;
127
128COUNT(IMP_INPUT);
129 m = m0;
a0b7c7fb
SL
130
131 /*
132 * We should generate a "bad leader" message
133 * to the IMP about messages too short.
134 */
6c73ade6
BJ
135 if (m->m_len < sizeof(struct imp_leader) &&
136 m_pullup(m, sizeof(struct imp_leader)) == 0)
137 goto drop;
138 ip = mtod(m, struct imp_leader *);
139
a0b7c7fb
SL
140 /*
141 * Check leader type -- should notify IMP
142 * in case of failure...
143 */
6c73ade6
BJ
144 if (ip->il_format != IMP_NFF)
145 goto drop;
146
147 /*
148 * Certain messages require a host structure.
149 * Do this in one shot here.
150 */
151 switch (ip->il_mtype) {
152
153 case IMPTYPE_RFNM:
154 case IMPTYPE_INCOMPLETE:
155 case IMPTYPE_HOSTDEAD:
156 case IMPTYPE_HOSTUNREACH:
157 case IMPTYPE_BADDATA:
a0b7c7fb 158 addr.s_host = ntohs(ip->il_host); /* XXX */
6c73ade6
BJ
159 hp = h_lookup(addr);
160 break;
161 }
162
163 switch (ip->il_mtype) {
164
165 /*
166 * Data for a protocol. Dispatch to the appropriate
167 * protocol routine (running at software interrupt).
168 * If this isn't a raw interface, advance pointer
a0b7c7fb 169 * into mbuf past leader (done below).
6c73ade6
BJ
170 */
171 case IMPTYPE_DATA:
172 ip->il_length = ntohs(ip->il_length) >> 3;
173 break;
174
175 /*
176 * IMP leader error. Reset the IMP and discard the packet.
177 */
178 case IMPTYPE_BADLEADER:
a0b7c7fb
SL
179 /*
180 * According to 1822 document, this message
181 * will be generated in response to the
182 * first noop sent to the IMP after
183 * the host resets the IMP interface.
184 */
185 if (sc->imp_state != IMPS_RESET) {
186 imperr(sc, "leader error");
187 h_reset(sc->imp_if.if_net); /* XXX */
188 impnoops(sc);
189 }
6c73ade6
BJ
190 goto drop;
191
192 /*
193 * IMP going down. Print message, and if not immediate,
194 * set off a timer to insure things will be reset at the
195 * appropriate time.
196 */
197 case IMPTYPE_DOWN:
198 if ((ip->il_link & IMP_DMASK) == 0) {
199 sc->imp_state = IMPS_GOINGDOWN;
a0b7c7fb 200 timeout(impdown, sc, 30 * 60 * HZ);
6c73ade6
BJ
201 }
202 imperr(sc, "going down %s", impmsg[ip->il_link & IMP_DMASK]);
203 goto drop;
204
205 /*
206 * A NOP usually seen during the initialization sequence.
207 * Compare the local address with that in the message.
208 * Reset the local address notion if it doesn't match.
209 */
210 case IMPTYPE_NOOP:
a0b7c7fb
SL
211 if (sc->imp_state == IMPS_DOWN) {
212 sc->imp_state = IMPS_INIT;
213 sc->imp_dropcnt = IMP_DROPCNT;
214 }
6c73ade6
BJ
215 if (sc->imp_state == IMPS_INIT && --sc->imp_dropcnt == 0) {
216 sc->imp_state = IMPS_UP;
217 /* restart output in case something was q'd */
218 (*sc->imp_cb.ic_start)(sc->imp_if.if_unit);
219 }
220 if (ip->il_host != sc->imp_if.if_addr.s_host ||
221 ip->il_impno != sc->imp_if.if_addr.s_imp) {
222 sc->imp_if.if_addr.s_host = ip->il_host;
223 sc->imp_if.if_addr.s_imp = ip->il_imp;
224 imperr(sc, "imp%d: address set to %d/%d\n",
225 ip->il_host, ip->il_impno);
226 }
227 goto drop;
228
229 /*
230 * RFNM or INCOMPLETE message, record in
231 * host table and prime output routine.
232 *
a0b7c7fb 233 * SHOULD NOTIFY PROTOCOL ABOUT INCOMPLETES.
6c73ade6
BJ
234 */
235 case IMPTYPE_RFNM:
236 case IMPTYPE_INCOMPLETE:
237 if (hp && hp->h_rfnm) {
238 register struct mbuf *n;
239
240 hp->h_rfnm--;
241 /* poke holding queue */
242 if (n = hp->h_q) {
243 if (n->m_act == n)
244 hp->h_q = 0;
245 else {
246 n = n->m_act;
247 hp->h_q->m_act = n->m_act;
248 }
249 (void) impsnd(n, sc);
250 }
251 }
252 break;
253
254 /*
255 * Host or IMP can't be reached. Flush any packets
256 * awaiting transmission and release the host structure.
257 *
258 * HOW DO WE NOTIFY THE PROTOCOL?
259 * HOW DO WE AGE THE HOST STRUCTURE TO SAVE STATUS?
260 */
261 case IMPTYPE_HOSTDEAD:
262 case IMPTYPE_HOSTUNREACH:
263 if (hp)
264 h_free(hp); /* won't work right */
265 break;
266
267 /*
268 * Error in data. Clear RFNM status for this host and send
269 * noops to the IMP to clear the interface.
270 */
271 case IMPTYPE_BADDATA:
272 imperr(sc, "data error");
273 if (hp)
274 hp->h_rfnm = 0;
275 impnoops(sc);
276 break;
277
278 /*
a0b7c7fb 279 * Interface reset.
6c73ade6
BJ
280 */
281 case IMPTYPE_RESET:
a0b7c7fb
SL
282 imperr(sc, "interface reset");
283 sc->imp_state = IMPS_RESET;
284 impnoops(sc);
6c73ade6
BJ
285 goto drop;
286
287 default:
288 sc->imp_if.if_collisions++; /* XXX */
289 goto drop;
290 }
291
292 /*
293 * Queue on protocol's input queue.
294 */
295 switch (ip->il_link) {
296
297#ifdef INET
298 case IMPLINK_IP:
299 m->m_len -= sizeof(struct imp_leader);
300 m->m_off += sizeof(struct imp_leader);
301 setipintr();
302 inq = &ipintrq;
303 break;
304#endif
305
306 default:
307 impproto.sp_protocol = ip->il_link;
faad37c0
SL
308 impdst.sin_addr = sc->imp_if.if_addr;
309 impsrc.sin_addr.s_net = ip->il_network;
310 impsrc.sin_addr.s_host = ip->il_host;
311 impsrc.sin_addr.s_imp = ip->il_imp;
312 raw_input(m, impproto, impdst, impsrc);
6c73ade6
BJ
313 return;
314 }
315 IF_ENQUEUE(inq, m);
316 return;
317
318drop:
319 m_freem(m);
320}
321
a0b7c7fb
SL
322/*
323 * Bring the IMP down after notification.
324 */
325impdown(sc)
326 struct imp_softc *sc;
327{
328 sc->imp_state = IMPS_DOWN;
329 /* notify protocols with messages waiting? */
330}
331
6c73ade6
BJ
332/*VARARGS*/
333imperr(sc, fmt, a1, a2)
334 struct imp_softc *sc;
335 char *fmt;
336{
337 printf("imp%d: ", sc->imp_if.if_unit);
338 printf(fmt, a1, a2);
339 printf("\n");
340}
341
342/*
343 * ARPAnet 1822 output routine.
344 * Called from higher level protocol routines to set up messages for
345 * transmission to the imp. Sets up the header and calls impsnd to
346 * enqueue the message for this IMP's hardware driver.
347 */
348impoutput(ifp, m0, pf)
349 register struct ifnet *ifp;
350 struct mbuf *m0;
351{
352 register struct imp_leader *imp;
353 register struct mbuf *m = m0;
354 int x, dhost, dimp, dlink, len;
355
356 /*
357 * Don't even try if the IMP is unavailable.
358 */
a0b7c7fb
SL
359 x = imp_softc[ifp->if_unit].imp_state;
360 if (x == IMPS_DOWN || x == IMPS_GOINGDOWN)
361 goto drop;
6c73ade6
BJ
362
363 switch (pf) {
364
365#ifdef INET
366 case PF_INET: {
367 register struct ip *ip = mtod(m0, struct ip *);
368
369 dhost = ip->ip_dst.s_host;
370 dimp = ip->ip_dst.s_imp;
371 dlink = IMPLINK_IP;
372 len = ntohs(ip->ip_len);
373 break;
374 }
375#endif
376 case PF_IMPLINK:
377 goto leaderexists;
378
379 default:
380 printf("imp%d: can't encapsulate pf%d\n", ifp->if_unit, pf);
a0b7c7fb 381 goto drop;
6c73ade6
BJ
382 }
383
384 /*
385 * Add IMP leader. If there's not enough space in the
386 * first mbuf, allocate another. If that should fail, we
387 * drop this sucker.
388 */
389 if (m->m_off > MMAXOFF ||
390 MMINOFF + sizeof(struct imp_leader) > m->m_off) {
391 m = m_get(M_DONTWAIT);
a0b7c7fb
SL
392 if (m == 0)
393 goto drop;
6c73ade6
BJ
394 m->m_next = m0;
395 m->m_off = MMINOFF;
396 m->m_len = sizeof(struct imp_leader);
397 } else {
398 m->m_off -= sizeof(struct imp_leader);
399 m->m_len += sizeof(struct imp_leader);
400 }
401 imp = mtod(m, struct imp_leader *);
402 imp->il_format = IMP_NFF;
403 imp->il_host = dhost;
404 imp->il_impno = dimp;
405 imp->il_length = (len + sizeof(struct imp_leader)) << 3;
406 imp->il_link = dlink;
407
408leaderexists:
409 /*
410 * Hand message to impsnd to perform RFNM counting
411 * and eventual transmission.
412 */
413 return (impsnd(ifp, m));
a0b7c7fb
SL
414drop:
415 m_freem(m0);
416 return (0);
6c73ade6
BJ
417}
418
419/*
420 * Put a message on an interface's output queue.
421 * Perform RFNM counting: no more than 8 message may be
422 * in flight to any one host.
423 */
424impsnd(ifp, m)
425 struct ifnet *ifp;
426 struct mbuf *m;
427{
428 register struct imp_leader *ip;
429 register struct host *hp;
430 struct impcb *icp;
431 int x;
432
433 ip = mtod(m, struct imp_leader *);
434
435 /*
436 * Do RFNM counting for data messages
437 * (no more than 8 outstanding to any host)
438 */
439 if (ip->il_mtype == IMPTYPE_DATA) {
440 struct in_addr addr;
441
442 addr.s_net = ifp->if_net;
443 addr.s_host = ip->il_host;
444 addr.s_imp = ip->il_imp;
445 hp = h_enter(addr);
446
447 /*
a0b7c7fb 448 * If IMP would block, queue until RFNM
6c73ade6
BJ
449 */
450 if (hp) {
451 register struct mbuf *n;
452 int cnt;
453
454 if (hp->h_rfnm < 8) {
455 hp->h_rfnm++;
456 goto enque;
457 }
458 /*
459 * Keeping the count in the host structure
460 * causes the packing scheme to lose too much.
461 */
462 cnt = 0, n = hp->h_q;
463 for (; n != (struct mbuf *)hp; n = n->m_act)
464 cnt++;
465 if (cnt >= 8)
466 goto drop;
a0b7c7fb
SL
467
468 /*
469 * Q is kept as circulare list with h_q
470 * (head) pointing to the last entry.
471 */
6c73ade6
BJ
472 if ((n = hp->h_q) == 0)
473 hp->h_q = m->m_act = m;
474 else {
475 m->m_act = n->m_act;
476 hp->h_q = n->m_act = m;
477 }
478 goto start;
479 }
480drop:
481 m_freem(m);
482 return (0);
483 }
484enque:
485 x = splimp();
486 IF_ENQUEUE(&ifp->if_snd, m);
487 splx(x);
488
489start:
490 icp = &imp_softc[ifp->if_unit].imp_cb;
491 if (icp->ic_oactive == 0)
492 (*icp->ic_start)(ifp->if_unit);
493 return (1);
494}
495
496/*
497 * Put three 1822 NOOPs at the head of the output queue.
498 * Part of host-IMP initialization procedure.
499 * (Should return success/failure, but noone knows
500 * what to do with this, so why bother?)
501 */
502impnoops(sc)
503 register struct imp_softc *sc;
504{
505 register i;
506 register struct mbuf *m;
507 register struct imp_leader *ip;
508 int x;
509
510 sc->imp_state = IMPS_INIT;
511 sc->imp_dropcnt = IMP_DROPCNT;
512 for (i = 0; i < IMP_DROPCNT; i++ ) {
513 if ((m = m_getclr(M_DONTWAIT)) == 0)
514 return;
515 m->m_off = MMINOFF;
516 m->m_len = sizeof(struct imp_leader);
517 ip = mtod(m, struct imp_leader *);
518 ip->il_format = IMP_NFF;
519 ip->il_link = i;
520 ip->il_mtype = IMPTYPE_NOOP;
521 x = splimp();
522 IF_PREPEND(&sc->imp_if.if_snd, m);
523 splx(x);
524 }
525 if (sc->imp_cb.ic_oactive == 0)
526 (*sc->imp_cb.ic_start)(sc->imp_if.if_unit);
527}
528#endif