|
|
1.1 root 1: /*
2: * C H R O U T E L D
3: *
4: * Chaosnet packet routing line discipline.
5: *
6: *
7: * (c) Copyright 1985 Nirvonics, Inc.
8: *
9: * Written by Kurt Gollhardt
10: * Last update Tue Mar 12 04:21:35 1985
11: *
12: * This software is the property of Nirvonics, Inc.
13: * All rights reserved.
14: *
15: */
16:
17: #include "chroute.h"
18: #if NCHROUTE > 0
19: #include "../h/param.h"
20: #include "../h/systm.h"
21: #include "../h/stream.h"
22: #include "../h/ioctl.h"
23: #include "../h/ttyld.h"
24: #include "../h/conf.h"
25: #include "../h/order.h"
26: #include "../h/ethernet.h"
27: #include "../chaosld/types.h"
28: #include "../chaosld/constants.h"
29: #include "../chaosld/chrouteld.h"
30:
31:
32: struct chif Chif[NCHROUTE];
33: struct chroute Chroute[CHNSUBNET];
34:
35: static struct chif *primary;
36:
37: int NChropen;
38: int NChroute = NCHROUTE;
39: int NChsubnet = CHNSUBNET;
40:
41: int Chrtimer; /* Routing timer running */
42:
43: int chroute_open(), chroute_close(), chroute_put(), chroute_srv();
44: static struct qinit chroute_init = {
45: chroute_put, chroute_srv, chroute_open, chroute_close, 512, 64
46: };
47: struct streamtab chrouteinfo = { &chroute_init, &chroute_init };
48:
49: #define DEBUG
50:
51: #ifdef DEBUG
52: int Chrdebug = 0;
53: # define debug(x) if (Chrdebug) x
54: #else
55: # define debug(x)
56: #endif
57:
58: static struct statxcvr zstat;
59:
60:
61: chroute_open(q, dev)
62: register struct queue *q;
63: dev_t dev;
64: {
65: register int i;
66: register struct chif *ifp;
67:
68: if (q->ptr) /* If this stream is already open, don't do anything */
69: return 1;
70:
71: /* Look for a free interface structure */
72:
73: if (NChropen++ == NCHROUTE)
74: return 0; /* If there are none left, the open fails */
75: for (i = 0, ifp = Chif; ifp->rdq != 0; ++ifp)
76: ;
77:
78: ifp->rdq = q;
79: ifp->my_addr.ch_addr = 0;
80: ifp->arp = -1;
81: ifp->if_dev = dev;
82: ifp->if_cost = HIGH_COST / 4; /* We expect this to be set by an ioctl,
83: but just in case ... */
84: ifp->if_stat = zstat;
85:
86: q->flag |= QDELIM|QNOENB;
87: WR(q)->flag |= QDELIM|QNOENB;
88: q->ptr = WR(q)->ptr = (caddr_t)ifp;
89:
90: if (!Chrtimer)
91: ch_rtimer();
92:
93: return 1;
94: }
95:
96:
97: chroute_close(q)
98: register struct queue *q;
99: {
100: register struct chif *ifp;
101:
102: --NChropen;
103: ifp = (struct chif *)q->ptr;
104: Chroute[ifp->my_addr.ch_subnet].rt_type = CHNOPATH;
105: arp_disable(ifp->arp);
106: ifp->rdq = (struct queue *)0;
107: ifp->my_addr.ch_addr = 0;
108: if (ifp == primary)
109: primary = (struct chif *)0;
110: q->ptr = 0;
111: }
112:
113:
114: chroute_put(q, bp)
115: register struct queue *q;
116: register struct block *bp;
117: {
118: debug(printf("chroute_put(%s, %d)\n",
119: ((q->flag & QREADR)? "RD" : "WR"), bp->type));
120:
121: switch (bp->type) {
122: case M_DATA:
123: putq(q, bp);
124: break;
125: case M_DELIM:
126: putq(q, bp);
127: qenable(q);
128: break;
129: case M_IOCTL:
130: /* Process an ioctl only if it's going towards the device */
131: if (!(q->flag & QREADR) && chroute_ioctl(q, bp))
132: break;
133: default: /* Anything else, just pass on to the next guy */
134: (*q->next->qinfo->putp)(q->next, bp);
135: }
136: }
137:
138:
139: chroute_srv(q)
140: register struct queue *q;
141: {
142: register struct block *bp;
143: register struct chif *ifp;
144: register struct chroute *r;
145: int minsize;
146:
147: /* We have a complete packet in the queue, composed of some number
148: of M_DATA's followed by an M_DELIM.
149: We know there are no other block types, because chroute_put()
150: won't give us anything else. */
151:
152: debug(printf("chroute_srv(%s)\n", ((q->flag & QREADR)? "RD" : "WR")));
153:
154: if (bp = q->first) {
155: if (bp->type == M_DELIM) {
156: printf("chroute: delimiter without data\n");
157: flush_packet(q);
158: return;
159: }
160: minsize = sizeof(struct pkt_header);
161: if (q->flag & QREADR) {
162: /* The packet is coming from the device */
163: minsize += sizeof(struct ether_in);
164: }
165: if (block_pullup(q, minsize) == 0) {
166: flush_packet(q);
167: return;
168: }
169: if (q->flag & QREADR) {
170: /* Packet is from device; strip off ethernet header */
171: q->first->rptr += sizeof(struct ether_in);
172: ifp = (struct chif *)q->ptr;
173: ifp->ist_rcvd++;
174: if (ifp->my_addr.ch_addr != 0) {
175: r = &Chroute[ifp->my_addr.ch_subnet];
176: r->rt_type = CHDIRECT;
177: r->rt_cost = ifp->if_cost;
178: r->rt_path.ifp = ifp;
179: }
180: }
181: chroute_dispatch(q);
182:
183: /* See if there's another packet on the queue */
184: for (bp = q->first; bp != NOBLOCK; bp = bp->next)
185: if (bp->type == M_DELIM) {
186: qenable(q); /* re-enable queue for the next packet */
187: break;
188: }
189: }
190: }
191:
192:
193: /* Handle an ioctl */
194:
195: chroute_ioctl(q, bp)
196: register struct queue *q;
197: register struct block *bp;
198: {
199: register union stmsg *sp;
200: register struct chif *ifp;
201: register struct chroute *rt;
202: register struct chaddr_pair *chp;
203:
204: ifp = (struct chif *)q->ptr;
205: sp = (union stmsg *)bp->rptr;
206: switch (sp->iocx.com) {
207: case CHIOCADDR:
208: bp->wptr = bp->rptr;
209: if (ifp->my_addr.ch_addr != 0) {
210: Chroute[ifp->my_addr.ch_subnet].rt_type = CHNOPATH;
211: arp_disable(ifp->arp);
212: }
213: ifp->my_addr.ch_addr = *(int *)(sp->iocx.xxx);
214: if (ifp->my_addr.ch_subnet >= CHNSUBNET
215: || ifp->my_addr.ch_subnet == 0) {
216: ifp->my_addr.ch_addr = 0;
217: bp->type = M_IOCNAK;
218: break;
219: }
220: rt = &Chroute[ifp->my_addr.ch_subnet];
221: rt->rt_type = CHDIRECT;
222: rt->rt_cost = ifp->if_cost;
223: rt->rt_path.ifp = ifp;
224: /* Should we check if this fails? */
225: ifp->arp = arp_enable(ifp->if_dev, ETHERPUP_CHAOSTYPE,
226: sizeof(chaddr), 0, &ifp->my_addr);
227: bp->type = M_IOCACK;
228: break;
229: case CRIOCOST:
230: ifp->if_cost = *(u_short *)(sp->iocx.xxx);
231: bp->wptr = bp->rptr;
232: bp->type = M_IOCACK;
233: break;
234: case CRIOPRIMARY:
235: primary = ifp;
236: bp->wptr = bp->rptr;
237: bp->type = M_IOCACK;
238: break;
239: default:
240: return 0; /* Let someone else deal with it */
241: }
242:
243: qreply(q, bp);
244: return 1;
245: }
246:
247:
248: /* We've got a packet to send (or receive); send it to the right place */
249:
250: chroute_dispatch(q)
251: register struct queue *q;
252: {
253: register struct block *bp;
254: register struct pkt_header *ph;
255: register struct chroute *rt;
256: register struct chif *ifp;
257: register int len, isdelim;
258: struct ether_out *ep;
259: chaddr dest;
260:
261: ph = (struct pkt_header *)q->first->rptr;
262: ifp = (struct chif *)q->ptr;
263: debug(printf("chroute_dispatch: op 0%o len %d\n", ph->ph_op, ph->ph_len));
264:
265: if (q->flag & QREADR && ph->ph_op == RUTOP) {
266: if (block_pullup(q, ph->ph_len + sizeof(*ph)) == 0) {
267: ifp->ist_rej++;
268: flush_packet(q);
269: return;
270: }
271: chroute_rcvrut(q->first->rptr);
272: flush_packet(q);
273: return;
274: }
275:
276: if (primary && (ph->ph_daddr.ch_addr == primary->my_addr.ch_addr
277: || (q->flag & QREADR && ph->ph_daddr.ch_addr == 0))) {
278: ph->ph_daddr = primary->my_addr;
279: if (ph->ph_len > CHMAXDATA) {
280: ifp->ist_len++;
281: flush_packet(q);
282: return;
283: }
284: len = sizeof(struct pkt_header) + ph->ph_len;
285: while (bp = getq(q)) {
286: if (bp->type == M_DATA) {
287: if (bp->wptr - bp->rptr > len)
288: bp->wptr = bp->rptr + len;
289: len -= bp->wptr - bp->rptr;
290: if (bp->wptr <= bp->rptr) {
291: freeb(bp);
292: continue;
293: }
294: }
295: debug(print_buf(bp, "rcvd:"));
296: isdelim = (bp->type == M_DELIM);
297: (*primary->rdq->next->qinfo->putp)(primary->rdq->next, bp);
298: if (isdelim)
299: break;
300: }
301: if (len != 0)
302: ifp->ist_len++;
303: return;
304: }
305:
306: if (q->flag & QREADR) {
307: if (ph->ph_daddr.ch_host == 0) {
308: ifp->ist_rej++;
309: flush_packet(q);
310: return;
311: } else if (++ph->ph_fc == 0) {
312: /* Overforwarded packet */
313: flush_packet(q);
314: return;
315: }
316: }
317:
318: dest = ph->ph_daddr;
319: if (ph->ph_daddr.ch_host == 0)
320: ph->ph_daddr.ch_subnet = 0;
321: if (dest.ch_subnet >= CHNSUBNET
322: || (rt = &Chroute[dest.ch_subnet])->rt_type == CHNOPATH) {
323: flush_packet(q);
324: return;
325: }
326:
327: if (rt->rt_type == CHFIXED || rt->rt_type == CHBRIDGE)
328: dest = rt->rt_path.bridge;
329: ifp = Chroute[dest.ch_subnet].rt_path.ifp;
330:
331: if ((bp = allocb(sizeof(struct ether_out))) == 0) {
332: ifp->ist_abrt++;
333: flush_packet(q);
334: return;
335: }
336: ep = (struct ether_out *)bp->wptr;
337: bp->wptr += sizeof(struct ether_out);
338: ep->type = hfirst_short(ETHERPUP_CHAOSTYPE);
339:
340: if (dest.ch_host == 0) /* If address is 0, broadcast to everyone */
341: arp_broadcast(ep->dhost);
342: else if (arp_getaddr(ifp->arp, &dest, ep->dhost) == -1) {
343: ifp->ist_abrt++;
344: flush_packet(q);
345: return;
346: }
347:
348: do {
349: debug(print_buf(bp, "xmit:"));
350: isdelim = (bp->type == M_DELIM);
351: (*(WR(ifp->rdq)->next->qinfo->putp)) (WR(ifp->rdq)->next, bp);
352: if (isdelim)
353: break;
354: } while (bp = getq(q));
355:
356: ifp->ist_xmit++;
357: }
358:
359:
360: /* Handle RUT (Routing) Packets */
361: chroute_rcvrut(ph)
362: register struct pkt_header *ph;
363: {
364: register struct rut_data *rd;
365: register struct chroute *rt;
366: register int i;
367:
368: if ((i = ph->ph_saddr.ch_subnet) >= CHNSUBNET) {
369: printf("CHAOS: Bad subnet (%d) in RUT packet\n", i);
370: return;
371: }
372: if (Chroute[i].rt_type != CHDIRECT) {
373: printf("CHAOS: RUT packet from unconnected subnet %d\n", i);
374: return;
375: }
376:
377: debug(printf("chroute_rcvrut(%d)\n", i));
378:
379: rd = (struct rut_data *)((char *)ph + sizeof(struct pkt_header));
380: for (i = ph->ph_len; i > 0; i -= sizeof(struct rut_data), ++rd) {
381: if (rd->rd_subnet >= CHNSUBNET)
382: continue;
383: rt = &Chroute[rd->rd_subnet];
384: switch (rt->rt_type) {
385: case CHBRIDGE:
386: if (rd->rd_cost > rt->rt_cost)
387: break;
388: case CHNOPATH:
389: rt->rt_cost = rd->rd_cost;
390: rt->rt_type = CHBRIDGE;
391: rt->rt_path.bridge = ph->ph_saddr;
392: break;
393: case CHDIRECT:
394: case CHFIXED:
395: break;
396: default:
397: printf("CHAOS: Bad entry in routing table, type = %d\n",
398: rt->rt_type);
399: }
400: }
401: }
402:
403:
404: #ifdef DEBUG
405:
406: print_buf(bp, s)
407: register struct block *bp;
408: register char *s;
409: {
410: register u_char *p;
411: register int i;
412:
413: printf("%s msg type %d len %d", s, bp->type, bp->wptr - bp->rptr);
414: for (i = 0, p = bp->rptr; p < bp->wptr; ++i, ++p) {
415: if ((i & 31) == 0)
416: printf("\n%s", s);
417: printf(" %x", *p);
418: }
419: printf("\n");
420: }
421:
422: #endif DEBUG
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.