|
|
1.1 root 1: /* @(#)if_ddn.c 7.1 (Berkeley) 6/5/86 */
2:
3:
4: /************************************************************************\
5:
6: ________________________________________________________
7: / \
8: | AAA CCCCCCCCCCCCCC CCCCCCCCCCCCCC |
9: | AAAAA CCCCCCCCCCCCCCCC CCCCCCCCCCCCCCCC |
10: | AAAAAAA CCCCCCCCCCCCCCCCC CCCCCCCCCCCCCCCCC |
11: | AAAA AAAA CCCC CCCC |
12: | AAAA AAAA CCCC CCCC |
13: | AAAA AAAA CCCC CCCC |
14: | AAAA AAAA CCCC CCCC |
15: | AAAA AAAAAAAAAAA CCCCCCCCCCCCCCCCC CCCCCCCCCCCCCCCCC |
16: | AAAA AAAAAAAAAAA CCCCCCCCCCCCCCCC CCCCCCCCCCCCCCCC |
17: | AAAA AAAAAAAAA CCCCCCCCCCCCCC CCCCCCCCCCCCCC |
18: \________________________________________________________/
19:
20: Copyright (c) 1985 by Advanced Computer Communications
21: 720 Santa Barbara Street, Santa Barbara, California 93101
22: (805) 963-9431
23:
24: This software may be duplicated and used on systems
25: which are licensed to run U.C. Berkeley versions of
26: the UNIX operating system. Any duplication of any
27: part of this software must include a copy of ACC's
28: copyright notice.
29:
30:
31: File:
32: if_ddn.c
33:
34: Author:
35: Art Berggreen
36:
37: Project:
38: 4.2 DDN X.25 network driver
39:
40: Function:
41: This is a network device driver for BSD 4.2 UNIX which
42: provides an interface between IP and ACC's ACP625
43: (IF-11/X25) for connecting to the Defense Data Network.
44:
45: Components:
46:
47: Revision History:
48: 16-May-1985: V1.0 - First release.
49: Art Berggreen.
50:
51: \************************************************************************/
52:
53:
54: /* if_ddn.c V1.0 5/16/85 */
55:
56: /*
57: * ACC ACP625 DDN/X.25 Network device driver
58: */
59:
60: /* #define DDNDEBUG 1 /* Enable definition for Debug code */
61:
62: #include "ddn.h"
63: #if NDDN > 0
64: #include "../machine/pte.h"
65:
66: #include "param.h"
67: #include "systm.h"
68: #include "mbuf.h"
69: #include "buf.h"
70: #include "protosw.h"
71: #include "socket.h"
72: #include "vmmac.h"
73: #include "errno.h"
74: #include "time.h"
75: #include "kernel.h"
76: #include "ioctl.h"
77:
78: #include "../net/if.h"
79: #include "../net/netisr.h"
80: #include "../net/route.h"
81:
82: #ifdef INET
83: #include "../netinet/in.h"
84: #include "../netinet/in_systm.h"
85: #include "../netinet/in_var.h"
86: #include "../netinet/ip.h"
87: #endif
88:
89: #include "../vax/cpu.h"
90: #include "../vax/mtpr.h"
91: #include "if_ddnreg.h"
92: #include "if_ddnvar.h"
93: #include "if_uba.h"
94: #include "../vaxuba/ubareg.h"
95: #include "../vaxuba/ubavar.h"
96:
97:
98:
99: /* declare global functions */
100:
101: int ddnprobe();
102: int ddnattach();
103: int ddnreset();
104: int ddninit();
105: int ddnoutput();
106: int ddntimer();
107: int ddnioctl();
108: int ddnintr();
109:
110: /* declare local functions */
111:
112: static void x25_init();
113: static struct ddn_cb *locate_x25_lcn();
114: static boolean convert_ip_addr();
115: static int convert_x25_addr();
116: static boolean make_x25_call();
117: static void ddn_start();
118: static void ddn_iorq();
119: static void start_chn();
120: static void ddn_data();
121: static void ddn_supr();
122: static void supr_msg();
123: static boolean decode_ring();
124: static void clear_lcn();
125: static void send_restart();
126: static void send_supr();
127: #ifdef DDNDEBUG
128: static void prt_addr();
129: static void prt_bytes();
130: #endif DDNDEBUG
131:
132:
133: struct uba_device *ddninfo[NDDN]; /* ptrs to device info */
134: u_short ddnstd[] = { 0766740, 0 }; /* standard addresses */
135: struct uba_driver ddndriver = /* device driver info */
136: {
137: ddnprobe, /* device probe routine */
138: 0, /* slave probe routine */
139: ddnattach, /* device attach routine */
140: 0, /* "dmago" routine */
141: ddnstd, /* device address */
142: "ddn", /* device name */
143: ddninfo /* ptr to device info ptrs */
144: };
145:
146: static u_char init_msg[] =
147: {
148: LINE_CNTL, /* set command code */
149: 0x00, /* not used */
150: 0x00, /* not used */
151: 0x00, /* extension length (set at runtime) */
152: LINK_DISABLE, /* link disable */
153: /* LINK_LOOPBACK, /* loopback mode */
154: /* LOOP_INTERNAL, /* = internal loopback */
155: PKT_SIZE, /* packet size */
156: 0x80, /* 128 - LSB */
157: 0x00, /* 128 - MSB */
158: PKT_WINDOW, /* packet window */
159: 0x02, /* = 2 */
160: LINK_ENABLE /* link enable */
161: };
162:
163: u_char cb_cmnd[4] =
164: {
165: CALL,
166: 0,
167: 0,
168: 0
169: };
170:
171: u_char cb_called_addr[16] = {0};
172:
173: u_char cb_calling_addr[16] = {0};
174:
175: u_char cb_facilities[64] = {0};
176:
177: u_char cb_protocol[5] = {0};
178:
179: u_char cb_user_data[1] = {0};
180:
181: #ifdef DDNDEBUG
182: int ddn_debug = 1; /* values 0-8 cause increasing verbosity */
183: #endif DDNDEBUG
184:
185:
186: /***********************************************************************\
187: * *
188: * Information for each device unit is maintained in an array *
189: * of structures named ddn_softc[]. The array is indexed by *
190: * unit number. Each entry includes the network interface *
191: * structure (ddn_if) used by the routing code to locate the *
192: * interface, an array of Logical Channel control blocks which *
193: * maintain information about each of the Logical Channels (LCNs) *
194: * through which X.25 virtual calls are established, a queue of *
195: * I/O requests pending for the UMC, the UNIBUS interrupt vector *
196: * for the unit and misc flags. The Logical Channel Control *
197: * blocks maintain information about the state of each LCN, *
198: * a queue of outbound data, Half Duplex Channel (HDX) blocks *
199: * used for queuing I/O requests to the UMC and an ifuba *
200: * structure which records the UNIBUS resources being held by *
201: * the LCN. *
202: * *
203: \***********************************************************************/
204:
205: struct sioq /* Start I/O queue head */
206: {
207: struct hdx_chan *sq_head; /* queue head */
208: struct hdx_chan *sq_tail; /* queue tail */
209: };
210:
211: struct hdx_chan /* HDX channel block */
212: {
213: struct hdx_chan *hc_next; /* link to next HDX channel */
214: u_char hc_chan; /* HDX channel number */
215: u_char hc_adx; /* address bits 17-16 */
216: u_short hc_addr; /* address bits 15-00 */
217: u_short hc_cnt; /* byte count */
218: u_char hc_func; /* I/O function */
219: u_char hc_sbfc; /* I/O subfunction */
220: };
221:
222: struct ddn_cb /* Logical Channel control block */
223: {
224: struct in_addr dc_inaddr; /* remote Internet address */
225: u_char dc_lcn; /* LCN number */
226: u_char dc_state; /* LCN state */
227: u_short dc_timer; /* LCN timer */
228: struct ifqueue dc_oq; /* LCN output queue */
229: struct hdx_chan dc_rchan; /* LCN read HDX channel */
230: struct hdx_chan dc_wchan; /* LCN write HDX channel */
231: struct ifuba dc_ifuba; /* UNIBUS resources */
232: u_short dc_flags; /* misc flags */
233: };
234:
235: struct ddn_softc /* device control structure */
236: {
237: struct ifnet ddn_if; /* network-visible interface */
238: struct ddn_cb ddn_cb[NDDNCH+1]; /* Logical Channel cntl blks */
239: struct sioq ddn_sioq; /* start I/O queue */
240: int ddn_vector; /* UNIBUS interrupt vector */
241: u_short ddn_flags; /* misc flags */
242: struct in_addr ddn_ipaddr; /* local IP address */
243: } ddn_softc[NDDN];
244:
245:
246: /***********************************************************************\
247: * ddnprobe() *
248: *************************************************************************
249: * *
250: * This routine probes the device to obtain the UNIBUS interrupt *
251: * vector. Since the UMC is a soft vector device, we obtain *
252: * an unused vector from the uba structure and return that. *
253: * The UMC is given the vector and the board is reset. *
254: * In order to save the vector in the device info structure, we *
255: * place it in a static temporary where the attach routine can *
256: * find it and save it in the device info structure. This is *
257: * necessary because probe only provides a pointer to the device *
258: * and we have no idea which unit is being referenced. This *
259: * works in 4.2 because the attach routine is called immediately *
260: * after a successful probe. *
261: * *
262: \***********************************************************************/
263:
264: #define INIT_DELAY (100 * 2) /* time for board initialization */
265: /* ( in 10 millisecond ticks) */
266:
267: static int savevec; /* static variable for vector */
268:
269: ddnprobe(reg)
270: caddr_t reg;
271: {
272: register int br, cvec; /* r11, r10 value-result */
273: register struct ddnregs *addr = (struct ddnregs *)reg;
274: register int delay_time;
275:
276: #ifdef lint
277: br = 0; cvec = br; br = cvec; ddnintr(0);
278: #endif
279:
280: cvec = savevec = (uba_hd[numuba].uh_lastiv -= 4); /* return vector */
281: br = 0x15; /* return bus level */
282:
283: addr->ioini = 0; /* clear handshake flags */
284: addr->ionmi = 0;
285: addr->staack = 0;
286: addr->xfrgnt = 0;
287: addr->iovect = cvec >> 2; /* pass vector to UMC */
288: addr->csr = DDN_RST; /* reset the board */
289: delay_time = mfpr(TODR) + INIT_DELAY;
290: while(delay_time > mfpr(TODR)) /* wait */ ;
291:
292: return (sizeof(struct ddnregs));
293: }
294:
295:
296: /***********************************************************************\
297: * ddnattach *
298: *************************************************************************
299: * *
300: * This routine attaches the device to the network software. *
301: * The network interface structure is filled in. The device *
302: * will be initialized when the system is ready to accept packets. *
303: * *
304: \***********************************************************************/
305:
306: ddnattach(ui)
307: struct uba_device *ui;
308: {
309: register struct ddn_softc *ds = &ddn_softc[ui->ui_unit];
310:
311: ds->ddn_vector = savevec; /* save vector from probe() */
312: ds->ddn_if.if_unit = ui->ui_unit; /* set unit number */
313: ds->ddn_if.if_name = "ddn"; /* set device name */
314: ds->ddn_if.if_mtu = DDNMTU; /* set max msg size */
315: ds->ddn_if.if_init = ddninit; /* set init routine addr */
316: ds->ddn_if.if_ioctl = ddnioctl; /* set ioctl routine addr */
317: ds->ddn_if.if_output = ddnoutput; /* set output routine addr */
318: ds->ddn_if.if_reset = ddnreset; /* set reset routine addr */
319: ds->ddn_if.if_watchdog = ddntimer; /* set timer routine addr */
320: if_attach(&ds->ddn_if);
321: }
322:
323:
324: /***********************************************************************\
325: * ddnreset() *
326: *************************************************************************
327: * *
328: * Reset of interface after UNIBUS reset. *
329: * If interface is on specified uba, reset its state. *
330: * *
331: \***********************************************************************/
332:
333: ddnreset(unit, uban)
334: int unit, uban;
335: {
336: register struct uba_device *ui;
337: register struct ddnregs *addr;
338: register int delay_time;
339:
340: if (unit >= NDDN || (ui = ddninfo[unit]) == 0 || ui->ui_alive == 0 ||
341: ui->ui_ubanum != uban)
342: return;
343:
344: printf(" ddn%d", unit);
345:
346: addr = (struct ddnregs *)ui->ui_addr;
347: addr->ioini = 0; /* clear handshake flags */
348: addr->ionmi = 0;
349: addr->staack = 0;
350: addr->xfrgnt = 0;
351: addr->iovect = ddn_softc[unit].ddn_vector >> 2; /* pass vector to UMC */
352: addr->csr = DDN_RST; /* reset the board */
353: delay_time = mfpr(TODR) + INIT_DELAY;
354: while(delay_time > mfpr(TODR)) /* wait */ ;
355:
356: ddninit(unit);
357: }
358:
359:
360: /***********************************************************************\
361: * ddninit() *
362: *************************************************************************
363: * *
364: * This routine initializes the interface for operation. The *
365: * device control blocks are initialized, UNIBUS resources are *
366: * allocated and an X.25 initialization message is sent to the *
367: * UMC. *
368: * *
369: \***********************************************************************/
370:
371: ddninit(unit)
372: int unit;
373: {
374: register struct ddn_softc *ds = &ddn_softc[unit];
375: register struct ddn_cb *dc;
376: register struct uba_device *ui = ddninfo[unit];
377: int lcn, s;
378:
379: #ifdef DDNDEBUG
380: if (ddn_debug > 0)
381: {
382: printf("ddn%d: ddninit()\n", unit);
383: }
384: #endif DDNDEBUG
385:
386: if (ds->ddn_if.if_addrlist == 0) /* if we have no internet addr */
387: return; /* don't init yet */
388:
389: dc = ds->ddn_cb; /* setup ptr to first LCN cntl block */
390:
391: for(lcn = 0; lcn <= NDDNCH; lcn++) /* for all LCN's ... */
392: {
393: dc->dc_lcn = lcn; /* record LCN */
394: dc->dc_inaddr.s_addr = 0; /* clear remote internet addr */
395: dc->dc_state = LC_DOWN; /* init LCN state */
396: dc->dc_timer = TMO_OFF; /* turn LCN timer off */
397:
398: /* init LCN output queue */
399:
400: dc->dc_oq.ifq_head = (struct mbuf *)0;
401: dc->dc_oq.ifq_tail = (struct mbuf *)0;
402: dc->dc_oq.ifq_len = 0;
403: dc->dc_oq.ifq_maxlen = DDN_OQMAX;
404: dc->dc_oq.ifq_drops = 0;
405:
406: /* init HDX channels */
407:
408: dc->dc_rchan.hc_next = (struct hdx_chan *)0;
409: dc->dc_rchan.hc_chan = lcn * 2;
410: dc->dc_wchan.hc_next = (struct hdx_chan *)0;
411: dc->dc_wchan.hc_chan = (lcn * 2) + 1;
412:
413: /* init UNIBUS resources */
414:
415: if (if_ubainit(&dc->dc_ifuba, ui->ui_ubanum,
416: 0, (int)btoc(DDNMTU)) == 0)
417: {
418: printf("ddn%d: failed getting UBA resources for lcn %d\n",
419: unit, lcn);
420: ds->ddn_if.if_flags &= ~(IFF_RUNNING | IFF_UP);
421: return;
422: }
423:
424: dc->dc_flags = 0; /* initialize flags */
425:
426: dc++; /* point at next cntl blk */
427: }
428:
429: ds->ddn_sioq.sq_head = (struct hdx_chan *)0;
430: ds->ddn_sioq.sq_tail = (struct hdx_chan *)0;
431: ds->ddn_if.if_flags |= IFF_RUNNING;
432:
433: s = splimp();
434:
435: dc = ds->ddn_cb; /* setup ptr to first LCN cntl block */
436:
437: for(lcn = 0; lcn <= NDDNCH; lcn++) /* issue reads on all LCNs */
438: {
439: ddn_iorq(ds, dc, DDNMTU, DDNRDB+DDNSTR);
440: dc++;
441: }
442:
443: x25_init(ds); /* init the X.25 board */
444:
445: splx(s);
446:
447: ddntimer(unit); /* start timers */
448: }
449:
450:
451: /***********************************************************************\
452: * ddnoutput() *
453: *************************************************************************
454: * *
455: * This routine is called by the network software when it has *
456: * an IP datagram to send out this interface. An attempt is *
457: * made to find a LCN which has a virtual circuit open to the *
458: * indicated host. If an LCN is found the packet is queued for *
459: * output on that LCN. *
460: * *
461: \***********************************************************************/
462:
463: ddnoutput(ifp, m0, dst)
464: struct ifnet *ifp;
465: struct mbuf *m0;
466: struct sockaddr_in *dst;
467: {
468: register struct mbuf *m = m0;
469: register struct ddn_softc *ds = &ddn_softc[ifp->if_unit];
470: register struct ddn_cb *dc;
471: register struct ifqueue *oq;
472: int s;
473:
474: if ((ds->ddn_if.if_flags & IFF_UP) == 0)
475: return (ENETDOWN);
476:
477: switch (dst->sin_family)
478: {
479:
480: #ifdef INET
481: case AF_INET:
482: break;
483: #endif INET
484:
485: default:
486: printf("ddn%d: can't handle af%d\n", ifp->if_unit,
487: dst->sin_family);
488: m_freem(m0);
489: return (EAFNOSUPPORT);
490: }
491:
492:
493: #ifdef DDNDEBUG
494: if (ddn_debug > 6)
495: {
496: printf("ddnoutput(): dst = ");
497: prt_addr(dst->sin_addr.s_addr);
498: printf("\n");
499: }
500: #endif DDNDEBUG
501:
502: s = splimp();
503:
504: /* try to find an LCN */
505:
506: if (dc = locate_x25_lcn(ds, dst->sin_addr))
507: { /* if found */
508: oq = &(dc->dc_oq); /* point to output queue */
509: dc->dc_state = LC_DATA_IDLE;
510: dc->dc_timer = TMO_DATA_IDLE;
511: if (IF_QFULL(oq)) /* if q full */
512: {
513: IF_DROP(oq); /* drop the data */
514: m_freem(m);
515: splx(s);
516: return (ENOBUFS);
517: }
518: IF_ENQUEUE(oq, m); /* otherwise queue it */
519: ddn_start(ds, dc); /* and try to output */
520: splx(s);
521: return (0);
522: }
523: else /* if no circuit available */
524: {
525: IF_DROP(&ifp->if_snd); /* drop the data */
526: m_freem(m);
527: splx(s);
528: return (EHOSTUNREACH);
529: }
530:
531: }
532:
533:
534: /***********************************************************************\
535: * ddntimer() *
536: *************************************************************************
537: * *
538: * This routine is entered once a second to perform timer *
539: * managment. The LCN table is scanned for active timers, *
540: * (nonzero) which are decremented. If a timer expires *
541: * (becomes zero), the proper action is taken. *
542: * *
543: \***********************************************************************/
544:
545: int ddntimer(unit)
546: int unit;
547: {
548: register struct ddn_softc *ds = &ddn_softc[unit];
549: register struct ddn_cb *dc;
550: register int s, lcn;
551:
552: #ifdef DDNDEBUG
553: if (ddn_debug > 7)
554: {
555: printf("ddntimer()\n");
556: }
557: #endif DDNDEBUG
558:
559: ds->ddn_if.if_timer = DDN_TIMEOUT; /* restart timer */
560:
561: dc = ds->ddn_cb;
562:
563: s = splimp();
564:
565: for(lcn = 0; lcn <= NDDNCH; lcn++) /* scan all LCN's */
566: {
567: if (dc->dc_timer && (--(dc->dc_timer) == 0))
568: { /* if a timer expired */
569: if (dc->dc_state == LC_RESTART)
570: { /* if a restart was out */
571: send_restart(ds); /* send another one */
572: break;
573: }
574: else /* otherwise */
575: {
576: clear_lcn(ds, dc); /* clear the LCN */
577: }
578: }
579: dc++;
580: }
581: splx(s);
582: }
583:
584:
585: /***********************************************************************\
586: * ddnioctl() *
587: *************************************************************************
588: * *
589: * This routine processes device dependent ioctl's. Currently, *
590: * the only ioctl supported is used to set the host's internet *
591: * address for this network interface. *
592: * *
593: \***********************************************************************/
594:
595: ddnioctl(ifp, cmd, data)
596: register struct ifnet *ifp;
597: int cmd;
598: caddr_t data;
599: {
600: struct ifaddr *ifa = (struct ifaddr *) data;
601: int s = splimp(), error = 0;
602:
603: switch (cmd) {
604:
605: case SIOCSIFADDR:
606: if (ifa->ifa_addr.sa_family != AF_INET)
607: return(EINVAL);
608: ifp->if_flags |= IFF_UP;
609: if ((ifp->if_flags & IFF_RUNNING) == 0)
610: ddninit(ifp->if_unit);
611: ddn_softc[ifp->if_unit].ddn_ipaddr = IA_SIN(ifa)->sin_addr;
612: break;
613:
614: default:
615: error = EINVAL;
616: break;
617: }
618: splx(s);
619: return (error);
620: }
621:
622:
623: /***********************************************************************\
624: * ddnintr() *
625: *************************************************************************
626: * *
627: * This is the interrupt handler for UNIBUS interrupts from the *
628: * UMC. The interrupting HDX channel and interrupt type are *
629: * obtained from the completion comm regs. If the interrupt is *
630: * an I/O request acknowledge, the next I/O request is passed *
631: * to the UMC. If the interrupt is an I/O completion, the *
632: * completion is processed depending on whether it is for the *
633: * supervisor or a data channel. *
634: * *
635: \***********************************************************************/
636:
637: ddnintr(unit)
638: int unit;
639: {
640: register struct ddn_softc *ds = &ddn_softc[unit];
641: register struct hdx_chan *hc;
642: register struct ddnregs *addr = (struct ddnregs *)ddninfo[unit]->ui_addr;
643: int chan, type, cc, cnt;
644:
645: /*
646: * Check for hardware errors.
647: */
648: if (addr->csr & DDN_UER)
649: {
650: printf("ddn%d: hard error csr=%b\n", unit, addr->csr, DDN_BITS);
651: addr->csr = 0; /* disable i/f */
652: return;
653: }
654:
655: /*
656: * Get logical channel info.
657: */
658: if ((chan = addr->stachn) >= ((NDDNCH+1)*2))
659: {
660: printf("ddn%d: unknown channel, chan=%d\n", unit, chan);
661: return;
662: }
663:
664: if (chan & 0x01)
665: hc = &(ds->ddn_cb[chan/2].dc_wchan);
666: else
667: hc = &(ds->ddn_cb[chan/2].dc_rchan);
668:
669: type = addr->statyp;
670: cc = addr->stacc;
671: cnt = hc->hc_cnt - addr->stacnt;
672:
673: /* Figure out what kind of interrupt it was */
674:
675: switch(type)
676: {
677: case DDNSACK: /* start i/o accepted */
678: if (hc != ds->ddn_sioq.sq_head) /* does ack match waiting req? */
679: {
680: printf("ddn%d: STARTIO error chan=%d hc=%x sq=%x\n",
681: unit, chan, hc, ds->ddn_sioq.sq_head);
682: addr->csr = 0; /* disable UMC */
683: return;
684: }
685:
686: /* dequeue old request by copying link to queue head */
687: /* and start next I/O request if queue has not gone empty */
688:
689: if (ds->ddn_sioq.sq_head = ds->ddn_sioq.sq_head->hc_next)
690: {
691: start_chn(ds);
692: }
693: break;
694:
695: case DDNDONE: /* i/o completion */
696: switch (cc)
697: {
698: case DDNIOCABT: /* probably VCN flush */
699: break;
700:
701: case DDNIOCERR:
702: printf("ddn%d: program error ", unit);
703: goto daterr;
704:
705: case DDNIOCOVR:
706: printf("ddn%d: overrun error ", unit);
707: goto daterr;
708:
709: case DDNIOCUBE:
710: printf("ddn%d: NXM timeout or UB parity error ", unit);
711:
712: daterr:
713: printf("chan=%d func=%x\n", chan, hc->hc_func);
714: if (hc->hc_func & DDNRDB)
715: ds->ddn_if.if_ierrors++;
716: else
717: ds->ddn_if.if_oerrors++;
718: }
719:
720: /* was it supervisor or data traffic? */
721:
722: if (chan > 1)
723: ddn_data(unit, chan, cc, cnt);
724: else
725: ddn_supr(unit, chan, cc);
726:
727: }
728:
729: /*
730: * Ack the interrupt
731: */
732: addr->staack = 1;
733: if (!(addr->ionmi))
734: {
735: addr->ionmi = 1;
736: addr->csr = DDN_DMA|DDN_WRT|DDN_IEN|DDN_NMI;
737: }
738: }
739:
740:
741: /***********************************************************************\
742: * x25_init() *
743: *************************************************************************
744: * *
745: * This routine builds and sends an X.25 initialization msg *
746: * to the UMC. *
747: * *
748: \***********************************************************************/
749:
750: static void x25_init(ds)
751: struct ddn_softc *ds;
752: {
753: struct mbuf *m;
754:
755: #ifdef DDNDEBUG
756: if (ddn_debug > 0)
757: {
758: printf("ddn%d: x25_init()\n", ds->ddn_if.if_unit);
759: }
760: #endif DDNDEBUG
761:
762: MGET(m, M_DONTWAIT, MT_DATA); /* try to get X25 init buffer */
763: if (m == 0)
764: {
765: printf("ddn%d: couldn't get X25 init buffer\n", ds->ddn_if.if_unit);
766: return;
767: }
768:
769: init_msg[3] = sizeof(init_msg) - 4; /* set cmnd ext length */
770:
771: bcopy((caddr_t)init_msg, mtod(m, caddr_t), sizeof(init_msg));
772:
773: m->m_len = sizeof(init_msg); /* set msg length */
774:
775: IF_ENQUEUE(&(ds->ddn_cb[0].dc_oq), m);
776: ddn_start(ds, &(ds->ddn_cb[0]));
777: }
778:
779:
780: /***********************************************************************\
781: * locate_x25_lcn() *
782: *************************************************************************
783: * *
784: * This routine tries to locate an X25 LCN associated with a *
785: * remote internet address. A linear search of the LCN table *
786: * is made for a matching address. If the search succeeds, the *
787: * LCN is returned. If the search fails, the LCN table is *
788: * searched for an unused table entry. If an unused table entry *
789: * is found, an X25 call is generated to the host specified in *
790: * the destination internet address. If no LCN is available, *
791: * zero is returned. *
792: * *
793: \***********************************************************************/
794:
795: static struct ddn_cb *locate_x25_lcn(ds, ip_addr)
796: struct ddn_softc *ds;
797: struct in_addr ip_addr;
798: {
799: register int lcn;
800: register struct ddn_cb *dc;
801:
802: #ifdef DDNDEBUG
803: if (ddn_debug > 6)
804: {
805: printf("locate_x25_lcn()\n");
806: }
807: #endif DDNDEBUG
808:
809: dc = &(ds->ddn_cb[1]);
810: for(lcn = 1; lcn <= NDDNCH; lcn++) /* scan LCN table for addr match */
811: {
812: if (dc->dc_inaddr.s_addr == ip_addr.s_addr) /* if found */
813: return(dc); /* return LCN */
814: dc++;
815: }
816:
817: dc = &(ds->ddn_cb[1]);
818: for(lcn = 1; lcn <= NDDNCH; lcn++) /* scan LCN table for free entry */
819: {
820: if (dc->dc_state == LC_IDLE)
821: break;
822: dc++;
823: }
824:
825: if (lcn > NDDNCH) /* if we didn't find a free entry */
826: return(0); /* return empty handed */
827:
828:
829: if (convert_ip_addr(ip_addr, cb_called_addr) && make_x25_call(ds, dc))
830: { /* addr can be converted */
831: dc->dc_inaddr.s_addr = ip_addr.s_addr;
832: return(dc); /* and return the LCN */
833: }
834: else
835: {
836: return(0); /* give up */
837: }
838: }
839:
840:
841: /***********************************************************************\
842: * convert_ip_addr() *
843: *************************************************************************
844: * *
845: * This routine accepts an internet address and attempts to *
846: * translate to an equivalent X25 address. For DDN this follows *
847: * the guidelines in the DDN X25 interface spec. The resultant *
848: * X25 address is stored in the X25 called addr buffer. The *
849: * routine returns TRUE if successfull, FALSE otherwise. *
850: * *
851: * NOTE: Although IF-11/X25 was designed to accept ASCII coded *
852: * digits for the address fields, we only supply the binary *
853: * values. The front-end only uses the low four bits to extract *
854: * the binary value from the ASCII digits, so this works out. *
855: * *
856: \***********************************************************************/
857:
858: static boolean convert_ip_addr(ip_addr, x25addr)
859: struct in_addr ip_addr;
860: u_char x25addr[];
861: {
862: register int temp;
863: union {
864: struct in_addr ip;
865: struct { /* (assumes Class A network number) */
866: u_char s_net;
867: u_char s_host;
868: u_char s_lh;
869: u_char s_impno;
870: } imp;
871: } imp_addr;
872:
873: imp_addr.ip = ip_addr;
874: x25addr[0] = 14; /* set addr length */
875:
876: x25addr[1] = 0; /* clear DNIC */
877: x25addr[2] = 0;
878: x25addr[3] = 0;
879: x25addr[4] = 0;
880:
881: if (imp_addr.imp.s_host < 64) /* Physical: 0000 0 IIIHH00 [SS] */
882: { /* s_impno -> III, s_host -> HH */
883: x25addr[5] = 0; /* set flag bit */
884: x25addr[6] = imp_addr.imp.s_impno / 100;
885: x25addr[7] = (imp_addr.imp.s_impno % 100) / 10;
886: x25addr[8] = imp_addr.imp.s_impno % 10;
887: x25addr[9] = imp_addr.imp.s_host / 10;
888: x25addr[10] = imp_addr.imp.s_host % 10;
889: }
890: else /* Logical: 0000 1 RRRRR00 [SS] */
891: { /* s_host * 256 + s_impno -> RRRRR */
892: temp = (imp_addr.imp.s_host << 8) + imp_addr.imp.s_impno;
893: x25addr[5] = 1;
894: x25addr[6] = temp / 10000;
895: x25addr[7] = (temp % 10000) / 1000;
896: x25addr[8] = (temp % 1000) / 100;
897: x25addr[9] = (temp % 100) / 10;
898: x25addr[10] = temp % 10;
899: }
900:
901: x25addr[11] = 0; /* clear rest of addr */
902: x25addr[12] = 0;
903: x25addr[13] = 0;
904: x25addr[14] = 0;
905:
906: #ifdef DDNDEBUG
907: if (ddn_debug > 4)
908: {
909: printf("convert_ip_addr(): ");
910: prt_addr(ip_addr);
911: printf(" ==> ");
912: prt_bytes(x25addr, 14);
913: printf("\n");
914: }
915: #endif DDNDEBUG
916:
917: return(1);
918: }
919:
920:
921: /***********************************************************************\
922: * convert_x25_addr() *
923: *************************************************************************
924: * *
925: * This routine accepts an X25 address and attempts to translate *
926: * to an equivalent internet address. For DDN this follows the *
927: * guidelines in the DDN X25 interface spec. The resultant *
928: * internet address is returned to the caller. *
929: * *
930: \***********************************************************************/
931:
932: static int convert_x25_addr(x25addr)
933: u_char x25addr[];
934: {
935: register int cnt, temp;
936: union {
937: struct in_addr ip;
938: struct { /* (assumes Class A network number) */
939: u_char s_net;
940: u_char s_host;
941: u_char s_lh;
942: u_char s_impno;
943: } imp;
944: } imp_addr;
945:
946: if (((cnt = x25addr[0]) < 12) || (cnt > 14))
947: {
948: printf("DDN: illegal X25 address length!\n");
949: return(0);
950: }
951:
952: switch(x25addr[5] & 0x0f)
953: {
954: case 0: /* Physical: 0000 0 IIIHH00 [SS] */
955: imp_addr.imp.s_impno =
956: ((int)(x25addr[6] & 0x0f) * 100) +
957: ((int)(x25addr[7] & 0x0f) * 10) +
958: ((int)(x25addr[8] & 0x0f));
959:
960:
961: imp_addr.imp.s_host =
962: ((int)(x25addr[9] & 0x0f) * 10) +
963: ((int)(x25addr[10] & 0x0f));
964: break;
965: case 1: /* Logical: 0000 1 RRRRR00 [SS] */
966: temp = ((int)(x25addr[6] & 0x0f) * 10000)
967: + ((int)(x25addr[7] & 0x0f) * 1000)
968: + ((int)(x25addr[8] & 0x0f) * 100)
969: + ((int)(x25addr[9] & 0x0f) * 10)
970: + ((int)(x25addr[10] & 0x0f));
971:
972: imp_addr.imp.s_host = temp >> 8;
973: imp_addr.imp.s_impno = temp & 0xff;
974: break;
975: default:
976: printf("DDN: illegal X25 address format!\n");
977: return(0);
978: }
979:
980: imp_addr.imp.s_lh = 0;
981: imp_addr.imp.s_net = 0;
982:
983: #ifdef DDNDEBUG
984: if (ddn_debug > 4)
985: {
986: printf("convert_x25_addr(): ");
987: prt_bytes(&x25addr[1], cnt);
988: printf(" ==> ");
989: prt_addr(imp_addr.ip);
990: printf("\n");
991: }
992: #endif DDNDEBUG
993:
994: return(imp_addr.ip.s_addr);
995: }
996:
997:
998: /***********************************************************************\
999: * make_x25_call() *
1000: *************************************************************************
1001: * *
1002: * This routine places an X25 call using the X25 Call Msg *
1003: * buffer. The calling LCN is placed in the appropriate state *
1004: * and a timer is started. *
1005: * *
1006: \***********************************************************************/
1007:
1008: static boolean make_x25_call(ds, dc)
1009: register struct ddn_softc *ds;
1010: register struct ddn_cb *dc;
1011: {
1012: register struct mbuf *m_callbfr;
1013: register caddr_t cb;
1014:
1015: MGET(m_callbfr, M_DONTWAIT, MT_DATA); /* try to get call cmnd buffer */
1016: if (m_callbfr == 0)
1017: return(0);
1018:
1019: cb = mtod(m_callbfr, caddr_t);
1020:
1021: (void)convert_ip_addr(ds->ddn_ipaddr, cb_calling_addr);
1022:
1023: cb_protocol[0] = 4;
1024: cb_protocol[1] = X25_PROTO_IP; /* protocol = IP */
1025: cb_protocol[2] = 0;
1026: cb_protocol[3] = 0;
1027: cb_protocol[4] = 0;
1028:
1029: cb_facilities[0] = 4; /* number facility bytes */
1030: cb_facilities[1] = 0; /* options marker */
1031: cb_facilities[2] = 0;
1032: cb_facilities[3] = X25_FACIL_DDN; /* DDN standard mode */
1033: cb_facilities[4] = FAC_DDNSTD;
1034:
1035: cb_user_data[0] = 0; /* no user data */
1036:
1037: cb_cmnd[0] = CALL; /* set command code */
1038: cb_cmnd[1] = dc->dc_lcn << 1; /* set channel id */
1039: cb_cmnd[2] = 0;
1040: cb_cmnd[3] = (cb_called_addr[0] + 1) + /* tally up cmnd ext length */
1041: (cb_calling_addr[0] + 1) +
1042: (cb_protocol[0] + 1) +
1043: (cb_facilities[0] + 1) +
1044: (cb_user_data[0] + 1);
1045:
1046: m_callbfr->m_len = cb_cmnd[3] + 4;
1047:
1048: /* copy command header */
1049: bcopy((caddr_t)cb_cmnd, cb, 4);
1050: cb += 4;
1051:
1052: /* copy called address */
1053: bcopy((caddr_t)cb_called_addr, cb, cb_called_addr[0] + 1);
1054: cb += (cb_called_addr[0] + 1);
1055:
1056: /* copy calling address */
1057: bcopy((caddr_t)cb_calling_addr, cb, cb_calling_addr[0] + 1);
1058: cb += (cb_calling_addr[0] + 1);
1059:
1060: /* copy protocol */
1061: bcopy((caddr_t)cb_protocol, cb, cb_protocol[0] + 1);
1062: cb += (cb_protocol[0] + 1);
1063:
1064: /* copy facilities */
1065: bcopy((caddr_t)cb_facilities, cb, cb_facilities[0] + 1);
1066: cb += (cb_facilities[0] + 1);
1067:
1068: /* copy user data */
1069: bcopy((caddr_t)cb_user_data, cb, cb_user_data[0] + 1);
1070: cb += (cb_user_data[0] + 1);
1071:
1072: dc->dc_state = LC_CALL_PENDING; /* set state */
1073: dc->dc_timer = TMO_CALL_PENDING; /* start call timeout */
1074:
1075: #ifdef DDNDEBUG
1076: if (ddn_debug > 3)
1077: {
1078: printf("make_x25_call(): call_bfr = ");
1079: prt_bytes(mtod(m_callbfr, u_char *), m_callbfr->m_len);
1080: printf("\n");
1081: }
1082: #endif DDNDEBUG
1083:
1084: IF_ENQUEUE(&(ds->ddn_cb[0].dc_oq), m_callbfr);
1085: ddn_start(ds, &(ds->ddn_cb[0]));
1086:
1087: return(1);
1088: }
1089:
1090:
1091: /***********************************************************************\
1092: * ddn_start() *
1093: *************************************************************************
1094: * *
1095: * This routine attempts to start output of data queued on a *
1096: * specific LCN. If the LCN was not already busy and data is *
1097: * available for output, the data is copied into the LCN's I/O *
1098: * buffer and an I/O request queued to the UMC. *
1099: * *
1100: \***********************************************************************/
1101:
1102: static void ddn_start(ds, dc)
1103: register struct ddn_softc *ds;
1104: register struct ddn_cb *dc;
1105: {
1106: register struct mbuf *m;
1107: int len;
1108:
1109: /*
1110: * If output isn't active, attempt to
1111: * start sending a new packet.
1112: */
1113:
1114: if ((dc->dc_flags & DC_OBUSY) ||
1115: (dc->dc_oq.ifq_len == 0) ||
1116: ((dc->dc_lcn != 0) && (dc->dc_state != LC_DATA_IDLE)))
1117: {
1118: return;
1119: }
1120:
1121: IF_DEQUEUE(&dc->dc_oq, m);
1122:
1123: len = if_wubaput(&dc->dc_ifuba, m); /* copy data to mapped mem */
1124: dc->dc_flags |= DC_OBUSY;
1125:
1126: ddn_iorq(ds, dc, len, DDNWRT+DDNEOS);
1127: }
1128:
1129:
1130: /***********************************************************************\
1131: * ddn_iorq() *
1132: *************************************************************************
1133: * *
1134: * This routine builds UMC I/O requests and queues them for *
1135: * delivery to the UMC. If the UMC I/O request comm regs are *
1136: * not busy, the I/O request is passed to the UMC. *
1137: * *
1138: \***********************************************************************/
1139:
1140: static void ddn_iorq(ds, dc, len, func)
1141: struct ddn_softc *ds;
1142: struct ddn_cb *dc;
1143: int len, func;
1144: {
1145: register struct hdx_chan *hc;
1146: register int info;
1147:
1148:
1149: /* get appropriate UNIBUS mapping info */
1150:
1151: if (func & DDNRDB) /* read or write? */
1152: {
1153: hc = &dc->dc_rchan;
1154: info = dc->dc_ifuba.ifu_r.ifrw_info;
1155: }
1156: else
1157: {
1158: hc = &dc->dc_wchan;
1159: info = dc->dc_ifuba.ifu_w.ifrw_info;
1160: }
1161:
1162: /* set channel info */
1163:
1164: hc->hc_adx = (u_char)((info & 0x30000) >> 12);
1165: hc->hc_addr = (u_short)(info & 0xffff);
1166: hc->hc_cnt = len;
1167: hc->hc_func = (u_char)func;
1168: hc->hc_sbfc = 0;
1169:
1170: /*
1171: * If UMC comm regs busy, queue start i/o for later.
1172: */
1173: if (ds->ddn_sioq.sq_head)
1174: {
1175: (ds->ddn_sioq.sq_tail)->hc_next = hc;
1176: ds->ddn_sioq.sq_tail = hc;
1177: hc->hc_next = 0;
1178: return;
1179: }
1180:
1181: /* start i/o on channel now */
1182:
1183: ds->ddn_sioq.sq_head = hc;
1184: ds->ddn_sioq.sq_tail = hc;
1185: hc->hc_next = 0;
1186: start_chn(ds);
1187: }
1188:
1189:
1190: /***********************************************************************\
1191: * start_chn() *
1192: *************************************************************************
1193: * *
1194: * This routine copies UMC I/O requests into the UMC comm regs *
1195: * and notifies the UMC. *
1196: * *
1197: \***********************************************************************/
1198:
1199: static void start_chn(ds)
1200: struct ddn_softc *ds;
1201: {
1202: register struct hdx_chan *hc = ds->ddn_sioq.sq_head;
1203: register struct ddnregs *addr =
1204: (struct ddnregs *)ddninfo[ds->ddn_if.if_unit]->ui_addr;
1205:
1206: /*
1207: * Set up comm regs.
1208: */
1209: addr->iochn = hc->hc_chan;
1210: addr->ioadx = hc->hc_adx;
1211: addr->ioadl = hc->hc_addr;
1212: addr->iocnt = hc->hc_cnt;
1213: addr->iofcn = hc->hc_func;
1214: addr->iosbf = hc->hc_sbfc;
1215: addr->ioini = 1;
1216:
1217: /* signal UMC if necessary */
1218:
1219: if (!(addr->ionmi))
1220: {
1221: addr->ionmi = 1;
1222: addr->csr = DDN_DMA|DDN_WRT|DDN_IEN|DDN_NMI;
1223: }
1224: }
1225:
1226:
1227: /***********************************************************************\
1228: * ddn_data() *
1229: *************************************************************************
1230: * *
1231: * This routine is called when a data channel I/O completes. *
1232: * If the completion was for a write, an attempt is made to *
1233: * start output on the next packet waiting for output on that *
1234: * LCN. If the completion was for a read, the received packet *
1235: * is sent to the IP input queue (if no error) and another read *
1236: * is started on the LCN. *
1237: * *
1238: \***********************************************************************/
1239:
1240: static void ddn_data(unit, chan, cc, rcnt)
1241: int unit, chan, cc, rcnt;
1242: {
1243: register struct ddn_softc *ds = &ddn_softc[unit];
1244: register struct ddn_cb *dc = &(ds->ddn_cb[chan/2]);
1245: register struct ifqueue *inq = &ipintrq;
1246: register struct mbuf *m;
1247:
1248: if (chan & 0x01) /* was it read or write? */
1249: { /* write, fire up next output */
1250: ds->ddn_if.if_opackets++;
1251: dc->dc_flags &= ~DC_OBUSY;
1252: ddn_start(ds, dc);
1253: }
1254: else /* read, process rcvd packet */
1255: {
1256: if (cc == DDNIOCOK)
1257: { /* Queue good packet for input */
1258: ds->ddn_if.if_ipackets++;
1259: dc->dc_state = LC_DATA_IDLE;
1260: dc->dc_timer = TMO_DATA_IDLE;
1261: m = if_rubaget(&(dc->dc_ifuba), rcnt, 0, &ds->ddn_if);
1262: if (m)
1263: {
1264: if (IF_QFULL(inq))
1265: {
1266: IF_DROP(inq);
1267: m_freem(m);
1268: }
1269: else
1270: {
1271: IF_ENQUEUE(inq, m);
1272: schednetisr(NETISR_IP);
1273: }
1274: }
1275: }
1276:
1277: /* hang a new data read */
1278:
1279: ddn_iorq(ds, dc, DDNMTU, DDNRDB+DDNSTR);
1280:
1281: }
1282: }
1283:
1284:
1285: /***********************************************************************\
1286: * ddn_supr() *
1287: *************************************************************************
1288: * *
1289: * This routine is called when a supervisor I/O completes. *
1290: * If the completion was for a write, an attempt is made to *
1291: * start output on the next supervisor command waiting for *
1292: * output. If the completion was for a read, the received *
1293: * supervisor message is processed and another read is started. *
1294: * *
1295: \***********************************************************************/
1296:
1297: static void ddn_supr(unit, chan, cc)
1298: int unit, chan, cc;
1299: {
1300: register struct ddn_softc *ds = &ddn_softc[unit];
1301: u_char *p;
1302:
1303: /* was it read or write? */
1304:
1305: if (chan & 0x01)
1306: {
1307: ds->ddn_cb[0].dc_flags &= ~DC_OBUSY;
1308: ddn_start(ds, &(ds->ddn_cb[0]));
1309: }
1310: else
1311: {
1312: if (cc == DDNIOCOK)
1313: {
1314: p = (u_char *)(ds->ddn_cb[0].dc_ifuba.ifu_r.ifrw_addr);
1315:
1316: /* process supervisor message */
1317:
1318: supr_msg(ds, p);
1319:
1320: }
1321:
1322: /* hang a new supr read */
1323:
1324: ddn_iorq(ds, &(ds->ddn_cb[0]), DDNMTU, DDNRDB+DDNSTR);
1325: }
1326: }
1327:
1328:
1329: /***********************************************************************\
1330: * supr_msg() *
1331: *************************************************************************
1332: * *
1333: * This routine processes received supervisor messages. *
1334: * Depending on the message type, the appropriate action is *
1335: * taken.
1336: * *
1337: \***********************************************************************/
1338:
1339: static void supr_msg(ds, p)
1340: struct ddn_softc *ds;
1341: u_char p[];
1342: {
1343: register struct ddn_cb *dc;
1344: register int lcn;
1345: register struct mbuf *m;
1346:
1347: #ifdef DDNDEBUG
1348: if (ddn_debug > 5)
1349: {
1350: printf("supr_msg(): ");
1351: prt_bytes(p, 4+p[3]);
1352: printf("\n");
1353: }
1354: #endif DDNDEBUG
1355:
1356: switch (p[0])
1357: {
1358: case LINE_STATUS: /* link status msg */
1359: if (p[2] == LINK_UP) /* if link came up */
1360: {
1361: send_restart(ds); /* send restart msg */
1362: }
1363: else /* if link went down */
1364: {
1365: ds->ddn_if.if_flags &= ~IFF_UP;
1366: dc = ds->ddn_cb;
1367: for(lcn = 0; lcn <= NDDNCH; lcn++) /* for all LCN's */
1368: {
1369: dc->dc_state = LC_DOWN; /* set state */
1370: dc->dc_timer = TMO_OFF; /* stop timer */
1371: dc++;
1372: }
1373: }
1374: break;
1375:
1376: case RESTART: /* restart received */
1377: if (ds->ddn_cb[0].dc_state != LC_RESTART) /* if not restarting */
1378: send_supr(ds, RSTRT_ACK, 0, 0); /* send restart ack */
1379: /* fall thru */
1380: case RSTRT_ACK: /* restart ack */
1381: ds->ddn_if.if_flags |= IFF_UP;
1382: dc = ds->ddn_cb;
1383: for(lcn = 0; lcn <= NDDNCH; lcn++) /* for all LCN's */
1384: {
1385: dc->dc_state = LC_IDLE; /* set state */
1386: dc->dc_timer = TMO_OFF; /* stop timer */
1387: dc->dc_inaddr.s_addr = 0; /* forget address */
1388: while (dc->dc_oq.ifq_len) /* drop pending data */
1389: {
1390: IF_DEQUEUE(&dc->dc_oq, m);
1391: m_freem(m);
1392: }
1393: dc++;
1394: }
1395: break;
1396:
1397: case ANSWER: /* call answered */
1398: lcn = p[1] / 2;
1399: dc = &(ds->ddn_cb[lcn]);
1400: if (dc->dc_state == LC_CALL_PENDING) /* if a call pending */
1401: {
1402: dc->dc_state = LC_DATA_IDLE; /* set state */
1403: dc->dc_timer = TMO_DATA_IDLE; /* start timer */
1404: ddn_start(ds, dc); /* try to send data */
1405: }
1406: break;
1407:
1408: case RING: /* incoming call */
1409: for(lcn = NDDNCH; lcn > 0; lcn--) /* search LCN's */
1410: {
1411: if (ds->ddn_cb[lcn].dc_state == LC_IDLE) /* unused? */
1412: break;
1413: }
1414:
1415: if (lcn && decode_ring(p)) /* if a free LCN found */
1416: /* and ring looks ok */
1417: {
1418: dc = &(ds->ddn_cb[lcn]);
1419: dc->dc_inaddr.s_addr = convert_x25_addr(cb_calling_addr);
1420: dc->dc_state = LC_DATA_IDLE; /* set state */
1421: dc->dc_timer = TMO_DATA_IDLE; /* start timer */
1422: send_supr(ds, ANSWER, lcn * 2, (int)p[2]); /* send answer */
1423: }
1424: else /* if no free LCN's */
1425: {
1426: send_supr(ds, CLEARVC, (int)p[2], 0); /* clear call */
1427: }
1428: break;
1429:
1430: case CLEARLC: /* clear by LCN */
1431: lcn = p[1] / 2; /* get LCN */
1432: dc = &(ds->ddn_cb[lcn]);
1433: if (dc->dc_state != LC_CLR_PENDING) /* if no clear pending */
1434: {
1435: send_supr(ds, CLEARLC, (int)p[1], 0); /* ack the clear */
1436: }
1437: dc->dc_state = LC_IDLE; /* set state */
1438: dc->dc_timer = TMO_OFF; /* stop timer */
1439: dc->dc_inaddr.s_addr = 0; /* forget address */
1440: while (dc->dc_oq.ifq_len) /* drop pending data */
1441: {
1442: IF_DEQUEUE(&dc->dc_oq, m);
1443: m_freem(m);
1444: }
1445: break;
1446:
1447: case CLEARVC: /* clear by VCN */
1448: send_supr(ds, CLEARVC, (int)p[1], 0); /* send clear ack */
1449: break;
1450:
1451: case RESET: /* X25 reset */
1452: send_supr(ds, RESET_ACK, (int)p[1], 0); /* send reset ack */
1453: printf("X25 RESET on lcn = %d\n", p[1] / 2); /* log it */
1454: break;
1455:
1456: case INTERRUPT: /* X25 interrupt */
1457: printf("X25 INTERRUPT on lcn = %d, code = %d\n", /* log it */
1458: p[1] / 2, p[2]);
1459: break;
1460:
1461: default:
1462: printf("ddn%d: supervisor error, code=%x\n",
1463: ds->ddn_if.if_unit, p[0]);
1464: }
1465: }
1466:
1467:
1468: /***********************************************************************\
1469: * decode_ring() *
1470: *************************************************************************
1471: * *
1472: * This routine parses and validates the incoming call msg. *
1473: * *
1474: \***********************************************************************/
1475:
1476: static boolean decode_ring(p)
1477: register u_char *p;
1478: {
1479: register int cnt;
1480:
1481: #ifdef DDNDEBUG
1482: if (ddn_debug > 3)
1483: {
1484: printf("decode_ring()\n");
1485: }
1486: #endif DDNDEBUG
1487:
1488:
1489: p += 3; /* skip to cmnd ext length */
1490: if (*p++ < 5) /* is count appropriate */
1491: return(0); /* return false if not */
1492:
1493: /* called address */
1494: if ((cnt = *p + 1) > 16) /* is called addr len legal? */
1495: return(0); /* return false if not */
1496: bcopy((caddr_t)p, (caddr_t)cb_called_addr, (unsigned)cnt); /* copy field */
1497: p += cnt;
1498:
1499: /* calling address */
1500: if ((cnt = *p + 1) > 16) /* is calling addr len legal? */
1501: return(0); /* return false if not */
1502: bcopy((caddr_t)p, (caddr_t)cb_calling_addr, (unsigned)cnt); /* copy field */
1503: p += cnt;
1504:
1505: /* protocol part of user data */
1506: if ((cnt = *p + 1) > 5) /* is protocol len legal? */
1507: return(0); /* return false if not */
1508: bcopy((caddr_t)p, (caddr_t)cb_protocol, (unsigned)cnt); /* copy field */
1509: p += cnt;
1510:
1511: /* facilities */
1512: if ((cnt = *p + 1) > 64) /* is facilities len legal? */
1513: return(0); /* return false if not */
1514: bcopy((caddr_t)p, (caddr_t)cb_facilities, (unsigned)cnt); /* copy field */
1515: p += cnt;
1516:
1517: /* ignore rest of user data for now */
1518:
1519: if ((cb_protocol[0] == 0) || (cb_protocol[1] != X25_PROTO_IP))
1520: return(0); /* bad if not IP */
1521:
1522: return(1); /* looks ok */
1523: }
1524:
1525:
1526: /***********************************************************************\
1527: * clear_lcn() *
1528: *************************************************************************
1529: * *
1530: * This routine clears an X25 circuit and releases any buffers *
1531: * queued for transmission. *
1532: * *
1533: \***********************************************************************/
1534:
1535: static void clear_lcn(ds, dc)
1536: struct ddn_softc *ds;
1537: struct ddn_cb *dc;
1538: {
1539: register struct mbuf *m;
1540:
1541: #ifdef DDNDEBUG
1542: if (ddn_debug > 3)
1543: {
1544: printf("clear_lcn(%d)\n", dc->dc_lcn);
1545: }
1546: #endif DDNDEBUG
1547:
1548: dc->dc_state = LC_CLR_PENDING; /* set state */
1549: dc->dc_timer = TMO_CLR_PENDING; /* start clear timer */
1550: dc->dc_inaddr.s_addr = 0; /* clear associated address */
1551: while (dc->dc_oq.ifq_len) /* drop any pending data */
1552: {
1553: IF_DEQUEUE(&dc->dc_oq, m);
1554: m_freem(m);
1555: }
1556: send_supr(ds, CLEARLC, (int)dc->dc_lcn * 2, 0); /* send clear msg */
1557: }
1558:
1559:
1560: /***********************************************************************\
1561: * send_restart() *
1562: *************************************************************************
1563: * *
1564: * This routine marks all LCNs as being in a restarting state *
1565: * and sends a restart command to X25. *
1566: * *
1567: \***********************************************************************/
1568:
1569: static void send_restart(ds)
1570: struct ddn_softc *ds;
1571: {
1572: register struct ddn_cb *dc;
1573: register int lcn;
1574: struct mbuf *m;
1575:
1576: #ifdef DDNDEBUG
1577: if (ddn_debug > 1)
1578: {
1579: printf("send_restart()\n");
1580: }
1581: #endif DDNDEBUG
1582: dc = ds->ddn_cb;
1583: for(lcn = 0; lcn <= NDDNCH; lcn++) /* for all LCN's */
1584: {
1585: dc->dc_state = LC_RESTART; /* set state */
1586: dc->dc_timer = TMO_RESTART; /* start restart timeout */
1587: dc->dc_inaddr.s_addr = 0; /* forget address */
1588: while (dc->dc_oq.ifq_len) /* drop any pending data */
1589: {
1590: IF_DEQUEUE(&dc->dc_oq, m);
1591: m_freem(m);
1592: }
1593: dc++;
1594: }
1595:
1596: send_supr(ds, RESTART, 0, 0); /* send restart msg */
1597: }
1598:
1599:
1600: /***********************************************************************\
1601: * send_supr() *
1602: *************************************************************************
1603: * *
1604: * This routine is used to send short (4 bytes only) supervisor *
1605: * commands. *
1606: * *
1607: \***********************************************************************/
1608:
1609: static void send_supr(ds, cmd, p1, p2)
1610: struct ddn_softc *ds;
1611: int cmd, p1, p2;
1612: {
1613: struct mbuf *m;
1614: register u_char *cp;
1615:
1616: #ifdef DDNDEBUG
1617: if (ddn_debug > 6)
1618: {
1619: printf("send_supr(): %x %x %x\n", cmd, p1, p2);
1620: }
1621: #endif DDNDEBUG
1622:
1623: MGET(m, M_DONTWAIT, MT_DATA);
1624:
1625: if (m == 0)
1626: {
1627: printf("ddn%d: failed to get supr msg bfr!\n", ds->ddn_if.if_unit);
1628: return;
1629: }
1630:
1631: cp = mtod(m, u_char *);
1632:
1633: /* build supervisor message */
1634:
1635: *cp++ = (byte)cmd;
1636: *cp++ = (byte)p1;
1637: *cp++ = (byte)p2;
1638: *cp++ = 0;
1639:
1640: m->m_len = 4;
1641:
1642: IF_ENQUEUE(&(ds->ddn_cb[0].dc_oq), m);
1643: ddn_start(ds, &(ds->ddn_cb[0]));
1644:
1645: }
1646:
1647:
1648: #ifdef DDNDEBUG
1649:
1650: /***********************************************************************\
1651: * prt_addr() *
1652: *************************************************************************
1653: * *
1654: * This routine is used to print internet addresses in the *
1655: * standard A.B.C.D format. *
1656: * *
1657: \***********************************************************************/
1658:
1659: static void prt_addr(addr)
1660: struct in_addr addr;
1661: {
1662: printf("%d.%d.%d.%d", addr.s_net, addr.s_host, addr.s_lh, addr.s_impno);
1663: }
1664:
1665: /***********************************************************************\
1666: * prt_bytes() *
1667: *************************************************************************
1668: * *
1669: * This routine is used to print a string of bytes in hex. *
1670: * *
1671: \***********************************************************************/
1672:
1673: static void prt_bytes(bp, cnt)
1674: u_char *bp;
1675: int cnt;
1676: {
1677: while(cnt--)
1678: {
1679: printf(" %x", *bp++ & 0xff);
1680: }
1681: }
1682:
1683: #endif DDNDEBUG
1684:
1685: #endif NDDN
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.