rm bbnnet; combine common code in ilwait; use per-host trailer option from ARP;
[unix-history] / usr / src / sys / vax / if / if_ddn.c
CommitLineData
10c3308f 1/* @(#)if_ddn.c 6.3 (Berkeley) %G% */
f0ecc930
MK
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
31File:
32 if_ddn.c
33
34Author:
35 Art Berggreen
36
37Project:
38 4.2 DDN X.25 network driver
39
40Function:
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
45Components:
46
47Revision History:
48 16-May-1985: V1.0 - First release.
49 Art Berggreen.
50
51\************************************************************************/
52\f
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
e43e0f32
MK
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"
f0ecc930
MK
77
78#include "../net/if.h"
79#include "../net/netisr.h"
80#include "../net/route.h"
e43e0f32 81
e43e0f32 82#ifdef INET
f0ecc930
MK
83#include "../netinet/in.h"
84#include "../netinet/in_systm.h"
e43e0f32 85#include "../netinet/in_var.h"
f0ecc930 86#include "../netinet/ip.h"
e43e0f32 87#endif
f0ecc930
MK
88
89#include "../vax/cpu.h"
90#include "../vax/mtpr.h"
e43e0f32
MK
91#include "if_ddnreg.h"
92#include "if_ddnvar.h"
93#include "if_uba.h"
f0ecc930
MK
94#include "../vaxuba/ubareg.h"
95#include "../vaxuba/ubavar.h"
96
97\f
98
99/* declare global functions */
100
101int ddnprobe();
102int ddnattach();
103int ddnreset();
104int ddninit();
105int ddnoutput();
106int ddntimer();
107int ddnioctl();
108int ddnintr();
109
110/* declare local functions */
111
112static void x25_init();
113static struct ddn_cb *locate_x25_lcn();
114static boolean convert_ip_addr();
115static int convert_x25_addr();
116static boolean make_x25_call();
117static void ddn_start();
118static void ddn_iorq();
119static void start_chn();
120static void ddn_data();
121static void ddn_supr();
122static void supr_msg();
123static boolean decode_ring();
124static void clear_lcn();
125static void send_restart();
126static void send_supr();
127#ifdef DDNDEBUG
128static void prt_addr();
129static void prt_bytes();
130#endif DDNDEBUG
131\f
132
133struct uba_device *ddninfo[NDDN]; /* ptrs to device info */
134u_short ddnstd[] = { 0766740, 0 }; /* standard addresses */
135struct 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
146static 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
163u_char cb_cmnd[4] =
164 {
165 CALL,
166 0,
167 0,
168 0
169 };
170
171u_char cb_called_addr[16] = {0};
172
173u_char cb_calling_addr[16] = {0};
174
175u_char cb_facilities[64] = {0};
176
177u_char cb_protocol[5] = {0};
178
179u_char cb_user_data[1] = {0};
180
181#ifdef DDNDEBUG
182int ddn_debug = 1; /* values 0-8 cause increasing verbosity */
183#endif DDNDEBUG
184\f
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
205struct 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
211struct 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
222struct 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
235struct 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 */
e43e0f32 242 struct in_addr ddn_ipaddr; /* local IP address */
f0ecc930
MK
243 } ddn_softc[NDDN];
244\f
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
267static int savevec; /* static variable for vector */
268
269ddnprobe(reg)
270caddr_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;
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\f
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
306ddnattach(ui)
307struct 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 */
e43e0f32 320 if_attach(&ds->ddn_if);
f0ecc930
MK
321 }
322\f
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
333ddnreset(unit, uban)
334int 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\f
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
371ddninit(unit)
372int 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];
f0ecc930
MK
377 int lcn, s;
378
379#ifdef DDNDEBUG
380if (ddn_debug > 0)
381 {
382printf("ddn%d: ddninit()\n", unit);
383 }
384#endif DDNDEBUG
385
e43e0f32 386 if (ds->ddn_if.if_addrlist == 0) /* if we have no internet addr */
f0ecc930
MK
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 */
f0ecc930
MK
448 }
449\f
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
463ddnoutput(ifp, m0, dst)
464struct ifnet *ifp;
465struct mbuf *m0;
466struct 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
494if (ddn_debug > 6)
495 {
496printf("ddnoutput(): dst = ");
497prt_addr(dst->sin_addr.s_addr);
498printf("\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\f
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
545int ddntimer(unit)
546int 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
553if (ddn_debug > 7)
554 {
555printf("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\f
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
595ddnioctl(ifp, cmd, data)
e43e0f32
MK
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 struct endevice *enaddr;
603
604 switch (cmd) {
605
606 case SIOCSIFADDR:
607 if (ifa->ifa_addr.sa_family != AF_INET)
608 return(EINVAL);
609 ifp->if_flags |= IFF_UP;
610 if ((ifp->if_flags & IFF_RUNNING) == 0)
611 ddninit(ifp->if_unit);
612 ddn_softc[ifp->if_unit].ddn_ipaddr = IA_SIN(ifa)->sin_addr;
613 break;
614
615 default:
616 error = EINVAL;
617 break;
618 }
619 splx(s);
620 return (error);
621}
f0ecc930
MK
622\f
623
624/***********************************************************************\
625* ddnintr() *
626*************************************************************************
627* *
628* This is the interrupt handler for UNIBUS interrupts from the *
629* UMC. The interrupting HDX channel and interrupt type are *
630* obtained from the completion comm regs. If the interrupt is *
631* an I/O request acknowledge, the next I/O request is passed *
632* to the UMC. If the interrupt is an I/O completion, the *
633* completion is processed depending on whether it is for the *
634* supervisor or a data channel. *
635* *
636\***********************************************************************/
637
638ddnintr(unit)
639int unit;
640 {
641 register struct ddn_softc *ds = &ddn_softc[unit];
642 register struct hdx_chan *hc;
643 register struct ddnregs *addr = (struct ddnregs *)ddninfo[unit]->ui_addr;
644 int chan, type, cc, cnt;
645
646 /*
647 * Check for hardware errors.
648 */
649 if (addr->csr & DDN_UER)
650 {
651 printf("ddn%d: hard error csr=%b\n", unit, addr->csr, DDN_BITS);
652 addr->csr = 0; /* disable i/f */
653 return;
654 }
655
656 /*
657 * Get logical channel info.
658 */
659 if ((chan = addr->stachn) >= ((NDDNCH+1)*2))
660 {
661 printf("ddn%d: unknown channel, chan=%d\n", unit, chan);
662 return;
663 }
664
665 if (chan & 0x01)
666 hc = &(ds->ddn_cb[chan/2].dc_wchan);
667 else
668 hc = &(ds->ddn_cb[chan/2].dc_rchan);
669
670 type = addr->statyp;
671 cc = addr->stacc;
672 cnt = hc->hc_cnt - addr->stacnt;
673
674 /* Figure out what kind of interrupt it was */
675
676 switch(type)
677 {
678 case DDNSACK: /* start i/o accepted */
679 if (hc != ds->ddn_sioq.sq_head) /* does ack match waiting req? */
680 {
681 printf("ddn%d: STARTIO error chan=%d hc=%x sq=%x\n",
682 unit, chan, hc, ds->ddn_sioq.sq_head);
683 addr->csr = 0; /* disable UMC */
684 return;
685 }
686
687 /* dequeue old request by copying link to queue head */
688 /* and start next I/O request if queue has not gone empty */
689
690 if (ds->ddn_sioq.sq_head = ds->ddn_sioq.sq_head->hc_next)
691 {
692 start_chn(ds);
693 }
694 break;
695
696 case DDNDONE: /* i/o completion */
697 switch (cc)
698 {
699 case DDNIOCABT: /* probably VCN flush */
700 break;
701
702 case DDNIOCERR:
703 printf("ddn%d: program error ", unit);
704 goto daterr;
705
706 case DDNIOCOVR:
707 printf("ddn%d: overrun error ", unit);
708 goto daterr;
709
710 case DDNIOCUBE:
711 printf("ddn%d: NXM timeout or UB parity error ", unit);
712
713 daterr:
714 printf("chan=%d func=%x\n", chan, hc->hc_func);
715 if (hc->hc_func & DDNRDB)
716 ds->ddn_if.if_ierrors++;
717 else
718 ds->ddn_if.if_oerrors++;
719 }
720
721 /* was it supervisor or data traffic? */
722
723 if (chan > 1)
724 ddn_data(unit, chan, cc, cnt);
725 else
726 ddn_supr(unit, chan, cc, cnt);
727
728 }
729
730 /*
731 * Ack the interrupt
732 */
733 addr->staack = 1;
734 if (!(addr->ionmi))
735 {
736 addr->ionmi = 1;
737 addr->csr = DDN_DMA|DDN_WRT|DDN_IEN|DDN_NMI;
738 }
739 }
740\f
741
742/***********************************************************************\
743* x25_init() *
744*************************************************************************
745* *
746* This routine builds and sends an X.25 initialization msg *
747* to the UMC. *
748* *
749\***********************************************************************/
750
751static void x25_init(ds)
752struct ddn_softc *ds;
753 {
754 struct mbuf *m;
755 register u_char *bp;
756
757#ifdef DDNDEBUG
758if (ddn_debug > 0)
759 {
760printf("ddn%d: x25_init()\n", ds->ddn_if.if_unit);
761 }
762#endif DDNDEBUG
763
764 MGET(m, M_DONTWAIT, MT_DATA); /* try to get X25 init buffer */
765 if (m == 0)
766 {
767 printf("ddn%d: couldn't get X25 init buffer\n", ds->ddn_if.if_unit);
768 return;
769 }
770
771 init_msg[3] = sizeof(init_msg) - 4; /* set cmnd ext length */
772
773 bcopy(init_msg, mtod(m, u_char *), sizeof(init_msg));
774
775 m->m_len = sizeof(init_msg); /* set msg length */
776
777 IF_ENQUEUE(&(ds->ddn_cb[0].dc_oq), m);
778 ddn_start(ds, &(ds->ddn_cb[0]));
779 }
780\f
781
782/***********************************************************************\
783* locate_x25_lcn() *
784*************************************************************************
785* *
786* This routine tries to locate an X25 LCN associated with a *
787* remote internet address. A linear search of the LCN table *
788* is made for a matching address. If the search succeeds, the *
789* LCN is returned. If the search fails, the LCN table is *
790* searched for an unused table entry. If an unused table entry *
791* is found, an X25 call is generated to the host specified in *
792* the destination internet address. If no LCN is available, *
793* zero is returned. *
794* *
795\***********************************************************************/
796
797static struct ddn_cb *locate_x25_lcn(ds, ip_addr)
798struct ddn_softc *ds;
799struct in_addr ip_addr;
800 {
801 register int lcn;
802 register struct ddn_cb *dc;
803 struct mbuf *m_callbfr;
804
805#ifdef DDNDEBUG
806if (ddn_debug > 6)
807 {
808printf("locate_x25_lcn()\n");
809 }
810#endif DDNDEBUG
811
f0ecc930
MK
812 dc = &(ds->ddn_cb[1]);
813 for(lcn = 1; lcn <= NDDNCH; lcn++) /* scan LCN table for addr match */
814 {
815 if (dc->dc_inaddr.s_addr == ip_addr.s_addr) /* if found */
816 return(dc); /* return LCN */
817 dc++;
818 }
819
820 dc = &(ds->ddn_cb[1]);
821 for(lcn = 1; lcn <= NDDNCH; lcn++) /* scan LCN table for free entry */
822 {
823 if (dc->dc_state == LC_IDLE)
824 break;
825 dc++;
826 }
827
828 if (lcn > NDDNCH) /* if we didn't find a free entry */
829 return(0); /* return empty handed */
830
831
832 if (convert_ip_addr(ip_addr, cb_called_addr) && make_x25_call(ds, dc))
833 { /* addr can be converted */
834 dc->dc_inaddr.s_addr = ip_addr.s_addr;
835 return(dc); /* and return the LCN */
836 }
837 else
838 {
839 return(0); /* give up */
840 }
841 }
842\f
843
844/***********************************************************************\
845* convert_ip_addr() *
846*************************************************************************
847* *
848* This routine accepts an internet address and attempts to *
849* translate to an equivalent X25 address. For DDN this follows *
850* the guidelines in the DDN X25 interface spec. The resultant *
851* X25 address is stored in the X25 called addr buffer. The *
852* routine returns TRUE if successfull, FALSE otherwise. *
853* *
854* NOTE: Although IF-11/X25 was designed to accept ASCII coded *
855* digits for the address fields, we only supply the binary *
856* values. The front-end only uses the low four bits to extract *
857* the binary value from the ASCII digits, so this works out. *
858* *
859\***********************************************************************/
860
861static boolean convert_ip_addr(ip_addr, x25addr)
862struct in_addr ip_addr;
863u_char x25addr[];
864 {
865 register int temp;
e43e0f32
MK
866 union {
867 struct in_addr ip;
868 struct { /* (assumes Class A network number) */
869 u_char s_net;
870 u_char s_host;
871 u_char s_lh;
872 u_char s_impno;
873 } imp;
874 } imp_addr;
875
876 imp_addr.ip = ip_addr;
f0ecc930
MK
877 x25addr[0] = 14; /* set addr length */
878
879 x25addr[1] = 0; /* clear DNIC */
880 x25addr[2] = 0;
881 x25addr[3] = 0;
882 x25addr[4] = 0;
883
e43e0f32
MK
884 if (imp_addr.imp.s_host < 64) /* Physical: 0000 0 IIIHH00 [SS] */
885 { /* s_impno -> III, s_host -> HH */
f0ecc930 886 x25addr[5] = 0; /* set flag bit */
e43e0f32
MK
887 x25addr[6] = imp_addr.imp.s_impno / 100;
888 x25addr[7] = (imp_addr.imp.s_impno % 100) / 10;
889 x25addr[8] = imp_addr.imp.s_impno % 10;
890 x25addr[9] = imp_addr.imp.s_host / 10;
891 x25addr[10] = imp_addr.imp.s_host % 10;
f0ecc930
MK
892 }
893 else /* Logical: 0000 1 RRRRR00 [SS] */
894 { /* s_host * 256 + s_impno -> RRRRR */
e43e0f32 895 temp = (imp_addr.imp.s_host << 8) + imp_addr.imp.s_impno;
f0ecc930
MK
896 x25addr[5] = 1;
897 x25addr[6] = temp / 10000;
898 x25addr[7] = (temp % 10000) / 1000;
899 x25addr[8] = (temp % 1000) / 100;
900 x25addr[9] = (temp % 100) / 10;
901 x25addr[10] = temp % 10;
902 }
903
904 x25addr[11] = 0; /* clear rest of addr */
905 x25addr[12] = 0;
906 x25addr[13] = 0;
907 x25addr[14] = 0;
908
909#ifdef DDNDEBUG
910if (ddn_debug > 4)
911 {
912printf("convert_ip_addr(): ");
913prt_addr(ip_addr);
914printf(" ==> ");
915prt_bytes(x25addr, 14);
916printf("\n");
917 }
918#endif DDNDEBUG
919
920 return(1);
921 }
922\f
923
924/***********************************************************************\
925* convert_x25_addr() *
926*************************************************************************
927* *
928* This routine accepts an X25 address and attempts to translate *
929* to an equivalent internet address. For DDN this follows the *
930* guidelines in the DDN X25 interface spec. The resultant *
931* internet address is returned to the caller. *
932* *
933\***********************************************************************/
934
935static int convert_x25_addr(x25addr)
936u_char x25addr[];
937 {
938 register int cnt, temp;
e43e0f32
MK
939 union {
940 struct in_addr ip;
941 struct { /* (assumes Class A network number) */
942 u_char s_net;
943 u_char s_host;
944 u_char s_lh;
945 u_char s_impno;
946 } imp;
947 } imp_addr;
f0ecc930
MK
948
949 if (((cnt = x25addr[0]) < 12) || (cnt > 14))
950 {
951 printf("DDN: illegal X25 address length!\n");
952 return(0);
953 }
954
955 switch(x25addr[5] & 0x0f)
956 {
957 case 0: /* Physical: 0000 0 IIIHH00 [SS] */
e43e0f32 958 imp_addr.imp.s_impno =
f0ecc930
MK
959 ((int)(x25addr[6] & 0x0f) * 100) +
960 ((int)(x25addr[7] & 0x0f) * 10) +
961 ((int)(x25addr[8] & 0x0f));
962
963
e43e0f32 964 imp_addr.imp.s_host =
f0ecc930
MK
965 ((int)(x25addr[9] & 0x0f) * 10) +
966 ((int)(x25addr[10] & 0x0f));
967 break;
968 case 1: /* Logical: 0000 1 RRRRR00 [SS] */
969 temp = ((int)(x25addr[6] & 0x0f) * 10000)
970 + ((int)(x25addr[7] & 0x0f) * 1000)
971 + ((int)(x25addr[8] & 0x0f) * 100)
972 + ((int)(x25addr[9] & 0x0f) * 10)
973 + ((int)(x25addr[10] & 0x0f));
974
e43e0f32
MK
975 imp_addr.imp.s_host = temp >> 8;
976 imp_addr.imp.s_impno = temp & 0xff;
f0ecc930
MK
977 break;
978 default:
979 printf("DDN: illegal X25 address format!\n");
980 return(0);
981 }
982
e43e0f32
MK
983 imp_addr.imp.s_lh = 0;
984 imp_addr.imp.s_net = 0;
f0ecc930
MK
985
986#ifdef DDNDEBUG
987if (ddn_debug > 4)
988 {
989printf("convert_x25_addr(): ");
990prt_bytes(&x25addr[1], cnt);
991printf(" ==> ");
e43e0f32 992prt_addr(imp_addr.ip);
f0ecc930
MK
993printf("\n");
994 }
995#endif DDNDEBUG
996
e43e0f32 997 return(imp_addr.ip.s_addr);
f0ecc930
MK
998 }
999\f
1000
1001/***********************************************************************\
1002* make_x25_call() *
1003*************************************************************************
1004* *
1005* This routine places an X25 call using the X25 Call Msg *
1006* buffer. The calling LCN is placed in the appropriate state *
1007* and a timer is started. *
1008* *
1009\***********************************************************************/
1010
1011static boolean make_x25_call(ds, dc)
1012register struct ddn_softc *ds;
1013register struct ddn_cb *dc;
1014 {
1015 register struct mbuf *m_callbfr;
1016 register u_char *cb;
f0ecc930
MK
1017
1018 MGET(m_callbfr, M_DONTWAIT, MT_DATA); /* try to get call cmnd buffer */
1019 if (m_callbfr == 0)
1020 return(0);
1021
1022 cb = mtod(m_callbfr, u_char *);
1023
e43e0f32 1024 convert_ip_addr(ds->ddn_ipaddr, cb_calling_addr);
f0ecc930
MK
1025
1026 cb_protocol[0] = 4;
1027 cb_protocol[1] = X25_PROTO_IP; /* protocol = IP */
1028 cb_protocol[2] = 0;
1029 cb_protocol[3] = 0;
1030 cb_protocol[4] = 0;
1031
1032 cb_facilities[0] = 4; /* number facility bytes */
1033 cb_facilities[1] = 0; /* options marker */
1034 cb_facilities[2] = 0;
1035 cb_facilities[3] = X25_FACIL_DDN; /* DDN standard mode */
1036 cb_facilities[4] = FAC_DDNSTD;
1037
1038 cb_user_data[0] = 0; /* no user data */
1039
1040 cb_cmnd[0] = CALL; /* set command code */
1041 cb_cmnd[1] = dc->dc_lcn << 1; /* set channel id */
1042 cb_cmnd[2] = 0;
1043 cb_cmnd[3] = (cb_called_addr[0] + 1) + /* tally up cmnd ext length */
1044 (cb_calling_addr[0] + 1) +
1045 (cb_protocol[0] + 1) +
1046 (cb_facilities[0] + 1) +
1047 (cb_user_data[0] + 1);
1048
1049 m_callbfr->m_len = cb_cmnd[3] + 4;
1050
1051 /* copy command header */
1052 bcopy(cb_cmnd, cb, 4);
1053 cb += 4;
1054
1055 /* copy called address */
1056 bcopy(cb_called_addr, cb, cb_called_addr[0] + 1);
1057 cb += (cb_called_addr[0] + 1);
1058
1059 /* copy calling address */
1060 bcopy(cb_calling_addr, cb, cb_calling_addr[0] + 1);
1061 cb += (cb_calling_addr[0] + 1);
1062
1063 /* copy protocol */
1064 bcopy(cb_protocol, cb, cb_protocol[0] + 1);
1065 cb += (cb_protocol[0] + 1);
1066
1067 /* copy facilities */
1068 bcopy(cb_facilities, cb, cb_facilities[0] + 1);
1069 cb += (cb_facilities[0] + 1);
1070
1071 /* copy user data */
1072 bcopy(cb_user_data, cb, cb_user_data[0] + 1);
1073 cb += (cb_user_data[0] + 1);
1074
1075 dc->dc_state = LC_CALL_PENDING; /* set state */
1076 dc->dc_timer = TMO_CALL_PENDING; /* start call timeout */
1077
1078#ifdef DDNDEBUG
1079if (ddn_debug > 3)
1080 {
1081printf("make_x25_call(): call_bfr = ");
1082prt_bytes(mtod(m_callbfr, u_char *), m_callbfr->m_len);
1083printf("\n");
1084 }
1085#endif DDNDEBUG
1086
1087 IF_ENQUEUE(&(ds->ddn_cb[0].dc_oq), m_callbfr);
1088 ddn_start(ds, &(ds->ddn_cb[0]));
1089
1090 return(1);
1091 }
1092\f
1093
1094/***********************************************************************\
1095* ddn_start() *
1096*************************************************************************
1097* *
1098* This routine attempts to start output of data queued on a *
1099* specific LCN. If the LCN was not already busy and data is *
1100* available for output, the data is copied into the LCN's I/O *
1101* buffer and an I/O request queued to the UMC. *
1102* *
1103\***********************************************************************/
1104
1105static void ddn_start(ds, dc)
1106register struct ddn_softc *ds;
1107register struct ddn_cb *dc;
1108 {
1109 register struct mbuf *m;
1110 int len;
1111
1112 /*
1113 * If output isn't active, attempt to
1114 * start sending a new packet.
1115 */
1116
1117 if ((dc->dc_flags & DC_OBUSY) ||
1118 (dc->dc_oq.ifq_len == 0) ||
1119 ((dc->dc_lcn != 0) && (dc->dc_state != LC_DATA_IDLE)))
1120 {
1121 return;
1122 }
1123
1124 IF_DEQUEUE(&dc->dc_oq, m);
1125
1126 len = if_wubaput(&dc->dc_ifuba, m); /* copy data to mapped mem */
1127 dc->dc_flags |= DC_OBUSY;
1128
1129 ddn_iorq(ds, dc, len, DDNWRT+DDNEOS);
1130 }
1131\f
1132
1133/***********************************************************************\
1134* ddn_iorq() *
1135*************************************************************************
1136* *
1137* This routine builds UMC I/O requests and queues them for *
1138* delivery to the UMC. If the UMC I/O request comm regs are *
1139* not busy, the I/O request is passed to the UMC. *
1140* *
1141\***********************************************************************/
1142
1143static void ddn_iorq(ds, dc, len, func)
1144struct ddn_softc *ds;
1145struct ddn_cb *dc;
1146int len, func;
1147 {
1148 register struct hdx_chan *hc;
1149 register int info;
1150
1151
1152 /* get appropriate UNIBUS mapping info */
1153
1154 if (func & DDNRDB) /* read or write? */
1155 {
1156 hc = &dc->dc_rchan;
1157 info = dc->dc_ifuba.ifu_r.ifrw_info;
1158 }
1159 else
1160 {
1161 hc = &dc->dc_wchan;
1162 info = dc->dc_ifuba.ifu_w.ifrw_info;
1163 }
1164
1165 /* set channel info */
1166
1167 hc->hc_adx = (u_char)((info & 0x30000) >> 12);
1168 hc->hc_addr = (u_short)(info & 0xffff);
1169 hc->hc_cnt = len;
1170 hc->hc_func = (u_char)func;
1171 hc->hc_sbfc = 0;
1172
1173 /*
1174 * If UMC comm regs busy, queue start i/o for later.
1175 */
1176 if (ds->ddn_sioq.sq_head)
1177 {
1178 (ds->ddn_sioq.sq_tail)->hc_next = hc;
1179 ds->ddn_sioq.sq_tail = hc;
1180 hc->hc_next = 0;
1181 return;
1182 }
1183
1184 /* start i/o on channel now */
1185
1186 ds->ddn_sioq.sq_head = hc;
1187 ds->ddn_sioq.sq_tail = hc;
1188 hc->hc_next = 0;
1189 start_chn(ds);
1190 }
1191\f
1192
1193/***********************************************************************\
1194* start_chn() *
1195*************************************************************************
1196* *
1197* This routine copies UMC I/O requests into the UMC comm regs *
1198* and notifies the UMC. *
1199* *
1200\***********************************************************************/
1201
1202static void start_chn(ds)
1203struct ddn_softc *ds;
1204 {
1205 register struct hdx_chan *hc = ds->ddn_sioq.sq_head;
1206 register struct ddnregs *addr =
1207 (struct ddnregs *)ddninfo[ds->ddn_if.if_unit]->ui_addr;
1208
1209 /*
1210 * Set up comm regs.
1211 */
1212 addr->iochn = hc->hc_chan;
1213 addr->ioadx = hc->hc_adx;
1214 addr->ioadl = hc->hc_addr;
1215 addr->iocnt = hc->hc_cnt;
1216 addr->iofcn = hc->hc_func;
1217 addr->iosbf = hc->hc_sbfc;
1218 addr->ioini = 1;
1219
1220 /* signal UMC if necessary */
1221
1222 if (!(addr->ionmi))
1223 {
1224 addr->ionmi = 1;
1225 addr->csr = DDN_DMA|DDN_WRT|DDN_IEN|DDN_NMI;
1226 }
1227 }
1228\f
1229
1230/***********************************************************************\
1231* ddn_data() *
1232*************************************************************************
1233* *
1234* This routine is called when a data channel I/O completes. *
1235* If the completion was for a write, an attempt is made to *
1236* start output on the next packet waiting for output on that *
1237* LCN. If the completion was for a read, the received packet *
1238* is sent to the IP input queue (if no error) and another read *
1239* is started on the LCN. *
1240* *
1241\***********************************************************************/
1242
1243static void ddn_data(unit, chan, cc, rcnt)
1244int unit, chan, cc, rcnt;
1245{
1246 register struct ddn_softc *ds = &ddn_softc[unit];
1247 register struct ddn_cb *dc = &(ds->ddn_cb[chan/2]);
1248 register struct ifqueue *inq = &ipintrq;
1249 register struct mbuf *m;
1250
1251 if (chan & 0x01) /* was it read or write? */
1252 { /* write, fire up next output */
1253 ds->ddn_if.if_opackets++;
1254 dc->dc_flags &= ~DC_OBUSY;
1255 ddn_start(ds, dc);
1256 }
1257 else /* read, process rcvd packet */
1258 {
1259 if (cc == DDNIOCOK)
1260 { /* Queue good packet for input */
1261 ds->ddn_if.if_ipackets++;
1262 dc->dc_state = LC_DATA_IDLE;
1263 dc->dc_timer = TMO_DATA_IDLE;
e43e0f32 1264 m = if_rubaget(&(dc->dc_ifuba), rcnt, 0, &ds->ddn_if);
f0ecc930
MK
1265 if (m)
1266 {
1267 if (IF_QFULL(inq))
1268 {
1269 IF_DROP(inq);
1270 m_freem(m);
1271 }
1272 else
1273 {
1274 IF_ENQUEUE(inq, m);
1275 schednetisr(NETISR_IP);
1276 }
1277 }
1278 }
1279
1280 /* hang a new data read */
1281
1282 ddn_iorq(ds, dc, DDNMTU, DDNRDB+DDNSTR);
1283
1284 }
1285 }
1286\f
1287
1288/***********************************************************************\
1289* ddn_supr() *
1290*************************************************************************
1291* *
1292* This routine is called when a supervisor I/O completes. *
1293* If the completion was for a write, an attempt is made to *
1294* start output on the next supervisor command waiting for *
1295* output. If the completion was for a read, the received *
1296* supervisor message is processed and another read is started. *
1297* *
1298\***********************************************************************/
1299
1300static void ddn_supr(unit, chan, cc, rcnt)
1301int unit, chan, cc, rcnt;
1302{
1303 register struct ddn_softc *ds = &ddn_softc[unit];
1304 u_char *p;
1305
1306 /* was it read or write? */
1307
1308 if (chan & 0x01)
1309 {
1310 ds->ddn_cb[0].dc_flags &= ~DC_OBUSY;
1311 ddn_start(ds, &(ds->ddn_cb[0]));
1312 }
1313 else
1314 {
1315 if (cc == DDNIOCOK)
1316 {
1317 p = (u_char *)(ds->ddn_cb[0].dc_ifuba.ifu_r.ifrw_addr);
1318
1319 /* process supervisor message */
1320
1321 supr_msg(ds, p);
1322
1323 }
1324
1325 /* hang a new supr read */
1326
1327 ddn_iorq(ds, &(ds->ddn_cb[0]), DDNMTU, DDNRDB+DDNSTR);
1328 }
1329 }
1330\f
1331
1332/***********************************************************************\
1333* supr_msg() *
1334*************************************************************************
1335* *
1336* This routine processes received supervisor messages. *
1337* Depending on the message type, the appropriate action is *
1338* taken.
1339* *
1340\***********************************************************************/
1341
1342static void supr_msg(ds, p)
1343struct ddn_softc *ds;
1344u_char p[];
1345 {
1346 register struct ddn_cb *dc;
1347 register int lcn;
1348 register struct mbuf *m;
1349
1350#ifdef DDNDEBUG
1351if (ddn_debug > 5)
1352 {
1353printf("supr_msg(): ");
1354prt_bytes(p, 4+p[3]);
1355printf("\n");
1356 }
1357#endif DDNDEBUG
1358
1359 switch (p[0])
1360 {
1361 case LINE_STATUS: /* link status msg */
1362 if (p[2] == LINK_UP) /* if link came up */
1363 {
1364 send_restart(ds); /* send restart msg */
1365 }
1366 else /* if link went down */
1367 {
1368 ds->ddn_if.if_flags &= ~IFF_UP;
1369 dc = ds->ddn_cb;
1370 for(lcn = 0; lcn <= NDDNCH; lcn++) /* for all LCN's */
1371 {
1372 dc->dc_state = LC_DOWN; /* set state */
1373 dc->dc_timer = TMO_OFF; /* stop timer */
1374 dc++;
1375 }
1376 }
1377 break;
1378
1379 case RESTART: /* restart received */
1380 if (ds->ddn_cb[0].dc_state != LC_RESTART) /* if not restarting */
1381 send_supr(ds, RSTRT_ACK, 0, 0); /* send restart ack */
1382 /* fall thru */
1383 case RSTRT_ACK: /* restart ack */
1384 ds->ddn_if.if_flags |= IFF_UP;
1385 dc = ds->ddn_cb;
1386 for(lcn = 0; lcn <= NDDNCH; lcn++) /* for all LCN's */
1387 {
1388 dc->dc_state = LC_IDLE; /* set state */
1389 dc->dc_timer = TMO_OFF; /* stop timer */
1390 dc->dc_inaddr.s_addr = 0; /* forget address */
1391 while (dc->dc_oq.ifq_len) /* drop pending data */
1392 {
1393 IF_DEQUEUE(&dc->dc_oq, m);
1394 m_freem(m);
1395 }
1396 dc++;
1397 }
1398 break;
1399
1400 case ANSWER: /* call answered */
1401 lcn = p[1] / 2;
1402 dc = &(ds->ddn_cb[lcn]);
1403 if (dc->dc_state == LC_CALL_PENDING) /* if a call pending */
1404 {
1405 dc->dc_state = LC_DATA_IDLE; /* set state */
1406 dc->dc_timer = TMO_DATA_IDLE; /* start timer */
1407 ddn_start(ds, dc); /* try to send data */
1408 }
1409 break;
1410
1411 case RING: /* incoming call */
1412 for(lcn = NDDNCH; lcn > 0; lcn--) /* search LCN's */
1413 {
1414 if (ds->ddn_cb[lcn].dc_state == LC_IDLE) /* unused? */
1415 break;
1416 }
1417
1418 if (lcn && decode_ring(p)) /* if a free LCN found */
1419 /* and ring looks ok */
1420 {
1421 dc = &(ds->ddn_cb[lcn]);
1422 dc->dc_inaddr.s_addr = convert_x25_addr(cb_calling_addr);
1423 dc->dc_state = LC_DATA_IDLE; /* set state */
1424 dc->dc_timer = TMO_DATA_IDLE; /* start timer */
1425 send_supr(ds, ANSWER, lcn * 2, p[2]); /* send answer */
1426 }
1427 else /* if no free LCN's */
1428 {
1429 send_supr(ds, CLEARVC, p[2], 0); /* clear call */
1430 }
1431 break;
1432
1433 case CLEARLC: /* clear by LCN */
1434 lcn = p[1] / 2; /* get LCN */
1435 dc = &(ds->ddn_cb[lcn]);
1436 if (dc->dc_state != LC_CLR_PENDING) /* if no clear pending */
1437 {
1438 send_supr(ds, CLEARLC, p[1], 0); /* ack the clear */
1439 }
1440 dc->dc_state = LC_IDLE; /* set state */
1441 dc->dc_timer = TMO_OFF; /* stop timer */
1442 dc->dc_inaddr.s_addr = 0; /* forget address */
1443 while (dc->dc_oq.ifq_len) /* drop pending data */
1444 {
1445 IF_DEQUEUE(&dc->dc_oq, m);
1446 m_freem(m);
1447 }
1448 break;
1449
1450 case CLEARVC: /* clear by VCN */
1451 send_supr(ds, CLEARVC, p[1], 0); /* send clear ack */
1452 break;
1453
1454 case RESET: /* X25 reset */
1455 send_supr(ds, RESET_ACK, p[1], 0); /* send reset ack */
1456 printf("X25 RESET on lcn = %d\n", p[1] / 2); /* log it */
1457 break;
1458
1459 case INTERRUPT: /* X25 interrupt */
1460 printf("X25 INTERRUPT on lcn = %d, code = %d\n", /* log it */
1461 p[1] / 2, p[2]);
1462 break;
1463
1464 default:
1465 printf("ddn%d: supervisor error, code=%x\n",
1466 ds->ddn_if.if_unit, p[0]);
1467 }
1468 }
1469\f
1470
1471/***********************************************************************\
1472* decode_ring() *
1473*************************************************************************
1474* *
1475* This routine parses and validates the incoming call msg. *
1476* *
1477\***********************************************************************/
1478
1479static boolean decode_ring(p)
1480register u_char *p;
1481 {
1482 register int cnt;
1483
1484#ifdef DDNDEBUG
1485if (ddn_debug > 3)
1486 {
1487printf("decode_ring()\n");
1488 }
1489#endif DDNDEBUG
1490
1491
1492 p += 3; /* skip to cmnd ext length */
1493 if (*p++ < 5) /* is count appropriate */
1494 return(0); /* return false if not */
1495
1496 /* called address */
1497 if ((cnt = *p + 1) > 16) /* is called addr len legal? */
1498 return(0); /* return false if not */
1499 bcopy(p, cb_called_addr, cnt); /* copy field */
1500 p += cnt;
1501
1502 /* calling address */
1503 if ((cnt = *p + 1) > 16) /* is calling addr len legal? */
1504 return(0); /* return false if not */
1505 bcopy(p, cb_calling_addr, cnt); /* copy field */
1506 p += cnt;
1507
1508 /* protocol part of user data */
1509 if ((cnt = *p + 1) > 5) /* is protocol len legal? */
1510 return(0); /* return false if not */
1511 bcopy(p, cb_protocol, cnt); /* copy field */
1512 p += cnt;
1513
1514 /* facilities */
1515 if ((cnt = *p + 1) > 64) /* is facilities len legal? */
1516 return(0); /* return false if not */
1517 bcopy(p, cb_facilities, cnt); /* copy field */
1518 p += cnt;
1519
1520 /* ignore rest of user data for now */
1521
1522 if ((cb_protocol[0] == 0) || (cb_protocol[1] != X25_PROTO_IP))
1523 return(0); /* bad if not IP */
1524
1525 return(1); /* looks ok */
1526 }
1527\f
1528
1529/***********************************************************************\
1530* clear_lcn() *
1531*************************************************************************
1532* *
1533* This routine clears an X25 circuit and releases any buffers *
1534* queued for transmission. *
1535* *
1536\***********************************************************************/
1537
1538static void clear_lcn(ds, dc)
1539struct ddn_softc *ds;
1540struct ddn_cb *dc;
1541 {
1542 register struct mbuf *m;
1543
1544#ifdef DDNDEBUG
1545if (ddn_debug > 3)
1546 {
1547printf("clear_lcn(%d)\n", dc->dc_lcn);
1548 }
1549#endif DDNDEBUG
1550
1551 dc->dc_state = LC_CLR_PENDING; /* set state */
1552 dc->dc_timer = TMO_CLR_PENDING; /* start clear timer */
1553 dc->dc_inaddr.s_addr = 0; /* clear associated address */
1554 while (dc->dc_oq.ifq_len) /* drop any pending data */
1555 {
1556 IF_DEQUEUE(&dc->dc_oq, m);
1557 m_freem(m);
1558 }
1559 send_supr(ds, CLEARLC, dc->dc_lcn * 2, 0); /* send clear msg */
1560 }
1561\f
1562
1563/***********************************************************************\
1564* send_restart() *
1565*************************************************************************
1566* *
1567* This routine marks all LCNs as being in a restarting state *
1568* and sends a restart command to X25. *
1569* *
1570\***********************************************************************/
1571
1572static void send_restart(ds)
1573struct ddn_softc *ds;
1574 {
1575 register struct ddn_cb *dc;
1576 register int lcn;
1577 struct mbuf *m;
1578
1579#ifdef DDNDEBUG
1580if (ddn_debug > 1)
1581 {
1582printf("send_restart()\n");
1583 }
1584#endif DDNDEBUG
1585 dc = ds->ddn_cb;
1586 for(lcn = 0; lcn <= NDDNCH; lcn++) /* for all LCN's */
1587 {
1588 dc->dc_state = LC_RESTART; /* set state */
1589 dc->dc_timer = TMO_RESTART; /* start restart timeout */
1590 dc->dc_inaddr.s_addr = 0; /* forget address */
1591 while (dc->dc_oq.ifq_len) /* drop any pending data */
1592 {
1593 IF_DEQUEUE(&dc->dc_oq, m);
1594 m_freem(m);
1595 }
1596 dc++;
1597 }
1598
1599 send_supr(ds, RESTART, 0, 0); /* send restart msg */
1600 }
1601\f
1602
1603/***********************************************************************\
1604* send_supr() *
1605*************************************************************************
1606* *
1607* This routine is used to send short (4 bytes only) supervisor *
1608* commands. *
1609* *
1610\***********************************************************************/
1611
1612static void send_supr(ds, cmd, p1, p2)
1613struct ddn_softc *ds;
1614int cmd, p1, p2;
1615 {
1616 struct mbuf *m;
1617 register u_char *cp;
1618
1619#ifdef DDNDEBUG
1620if (ddn_debug > 6)
1621 {
1622printf("send_supr(): %x %x %x\n", cmd, p1, p2);
1623 }
1624#endif DDNDEBUG
1625
1626 MGET(m, M_DONTWAIT, MT_DATA);
1627
1628 if (m == 0)
1629 {
1630 printf("ddn%d: failed to get supr msg bfr!\n", ds->ddn_if.if_unit);
1631 return;
1632 }
1633
1634 cp = mtod(m, u_char *);
1635
1636 /* build supervisor message */
1637
1638 *cp++ = (byte)cmd;
1639 *cp++ = (byte)p1;
1640 *cp++ = (byte)p2;
1641 *cp++ = 0;
1642
1643 m->m_len = 4;
1644
1645 IF_ENQUEUE(&(ds->ddn_cb[0].dc_oq), m);
1646 ddn_start(ds, &(ds->ddn_cb[0]));
1647
1648 }
1649\f
1650
1651#ifdef DDNDEBUG
1652
1653/***********************************************************************\
1654* prt_addr() *
1655*************************************************************************
1656* *
1657* This routine is used to print internet addresses in the *
1658* standard A.B.C.D format. *
1659* *
1660\***********************************************************************/
1661
1662static void prt_addr(addr)
1663struct in_addr addr;
1664 {
1665 printf("%d.%d.%d.%d", addr.s_net, addr.s_host, addr.s_lh, addr.s_impno);
1666 }
1667
1668/***********************************************************************\
1669* prt_bytes() *
1670*************************************************************************
1671* *
1672* This routine is used to print a string of bytes in hex. *
1673* *
1674\***********************************************************************/
1675
1676static void prt_bytes(bp, cnt)
1677u_char *bp;
1678int cnt;
1679 {
1680 while(cnt--)
1681 {
1682 printf(" %x", *bp++ & 0xff);
1683 }
1684 }
1685
1686#endif DDNDEBUG
1687
1688#endif NDDN