1*39729Ssklower /*************************************************************************/
2*39729Ssklower /* */
3*39729Ssklower /* */
4*39729Ssklower /* ________________________________________________________ */
5*39729Ssklower /* / \ */
6*39729Ssklower /* | AAA CCCCCCCCCCCCCC CCCCCCCCCCCCCC | */
7*39729Ssklower /* | AAAAA CCCCCCCCCCCCCCCC CCCCCCCCCCCCCCCC | */
8*39729Ssklower /* | AAAAAAA CCCCCCCCCCCCCCCCC CCCCCCCCCCCCCCCCC | */
9*39729Ssklower /* | AAAA AAAA CCCC CCCC | */
10*39729Ssklower /* | AAAA AAAA CCCC CCCC | */
11*39729Ssklower /* | AAAA AAAA CCCC CCCC | */
12*39729Ssklower /* | AAAA AAAA CCCC CCCC | */
13*39729Ssklower /* | AAAA AAAAAAAAAAA CCCCCCCCCCCCCCCCC CCCCCCCCCCCCCCCCC | */
14*39729Ssklower /* | AAAA AAAAAAAAAAA CCCCCCCCCCCCCCCC CCCCCCCCCCCCCCCC | */
15*39729Ssklower /* | AAAA AAAAAAAAA CCCCCCCCCCCCCC CCCCCCCCCCCCCC | */
16*39729Ssklower /* \________________________________________________________/ */
17*39729Ssklower /* */
18*39729Ssklower /* Copyright (c) 1986 by Advanced Computer Communications */
19*39729Ssklower /* 720 Santa Barbara Street, Santa Barbara, California 93101 */
20*39729Ssklower /* (805) 963-9431 */
21*39729Ssklower /* */
22*39729Ssklower /* */
23*39729Ssklower /* File: if_dda.c */
24*39729Ssklower /* */
25*39729Ssklower /* Project: DDN-X.25 Network Interface Driver for ACP 5250 */
26*39729Ssklower /* and ACP 6250 */
27*39729Ssklower /* */
28*39729Ssklower /* Function: This is a network interface driver supporting */
29*39729Ssklower /* the ACP5250/6250 under UNIX versions 4.2, 4.3, */
30*39729Ssklower /* 4.3-tahoe, Ultrix versions 1.2 and 2.0, and */
31*39729Ssklower /* under VMS, TWG WIN/VX and TGV Multinet. */
32*39729Ssklower /* */
33*39729Ssklower /* Components: required: if_dda.c, if_ddareg.h, if_ddavar.h, */
34*39729Ssklower /* and one of: if_dda_uqbus.c if_dda_bibus.c */
35*39729Ssklower /* optional: if_pi.c, if_pivar.h, if_x29.c, */
36*39729Ssklower /* if_vmsx29.c */
37*39729Ssklower /* */
38*39729Ssklower /*************************************************************************/
39*39729Ssklower
40*39729Ssklower
41*39729Ssklower #include "dda.h"
42*39729Ssklower
43*39729Ssklower #if NDDA > 0
44*39729Ssklower
45*39729Ssklower /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
46*39729Ssklower /*%% %%*/
47*39729Ssklower /*%% SYSTEM CONFIGURATION %%*/
48*39729Ssklower /*%% %%*/
49*39729Ssklower /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
50*39729Ssklower
51*39729Ssklower #if !defined(ACC_ULTRIX) && !defined(ACC_BSD) && !defined(ACC_VMS)
52*39729Ssklower ERROR
53*39729Ssklower an ACC OS specific option must be defined in your config file
54*39729Ssklower ERROR
55*39729Ssklower #endif
56*39729Ssklower
57*39729Ssklower /*
58*39729Ssklower * now define the un-set options to zero
59*39729Ssklower */
60*39729Ssklower #if !defined(ACC_ULTRIX)
61*39729Ssklower #define ACC_ULTRIX 00
62*39729Ssklower #endif
63*39729Ssklower
64*39729Ssklower #if !defined(ACC_BSD)
65*39729Ssklower #define ACC_BSD 00
66*39729Ssklower #endif
67*39729Ssklower
68*39729Ssklower #if !defined(ACC_VMS)
69*39729Ssklower #define ACC_VMS 00
70*39729Ssklower #endif
71*39729Ssklower
72*39729Ssklower /*
73*39729Ssklower * the define DDA_MSGQ enables the message queue. this adds 2k to the
74*39729Ssklower * data size of the driver. It should only be used during driver development
75*39729Ssklower */
76*39729Ssklower
77*39729Ssklower /*#define DDA_MSGQ /* uncomment this to enable message queue */
78*39729Ssklower
79*39729Ssklower /*
80*39729Ssklower * The following line disables the use of the histogram facilities. This
81*39729Ssklower * value (DDA_HISTOGRAM) is automatically undefined for all 4.2 and ULTRIX
82*39729Ssklower * 1.2 systems which do not support the histogram facilities.
83*39729Ssklower */
84*39729Ssklower
85*39729Ssklower #define DDA_HISTOGRAM /* comment this out to disable histogram */
86*39729Ssklower
87*39729Ssklower /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
88*39729Ssklower /*%% %%*/
89*39729Ssklower /*%% INCLUDE FILES %%*/
90*39729Ssklower /*%% %%*/
91*39729Ssklower /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
92*39729Ssklower
93*39729Ssklower #ifndef SIMULATION /* real unix system */
94*39729Ssklower #include "../machine/pte.h" /* page table entries */
95*39729Ssklower #include "../h/param.h"
96*39729Ssklower #include "../h/systm.h"
97*39729Ssklower #include "../h/mbuf.h"
98*39729Ssklower #include "../h/buf.h"
99*39729Ssklower #include "../h/protosw.h"
100*39729Ssklower #include "../h/socket.h"
101*39729Ssklower #include "../h/vmmac.h"
102*39729Ssklower #include "../h/errno.h"
103*39729Ssklower #include "../h/dir.h"
104*39729Ssklower #include "../h/user.h"
105*39729Ssklower #include "../h/kernel.h"
106*39729Ssklower #include "../h/ioctl.h"
107*39729Ssklower
108*39729Ssklower #include "../vax/cpu.h"
109*39729Ssklower #include "../vax/mtpr.h"
110*39729Ssklower
111*39729Ssklower #include "../net/if.h"
112*39729Ssklower #include "../net/netisr.h"
113*39729Ssklower #include "../net/route.h"
114*39729Ssklower #include "../netinet/in.h"
115*39729Ssklower #include "../netinet/in_systm.h"
116*39729Ssklower # if ACC_BSD > 42 || ACC_ULTRIX > 12
117*39729Ssklower # include "../netinet/in_var.h"
118*39729Ssklower # endif
119*39729Ssklower #include "../netinet/ip.h"
120*39729Ssklower #include "../netinet/ip_var.h"
121*39729Ssklower
122*39729Ssklower #include "../vaxif/if_ddareg.h"
123*39729Ssklower #include "../vaxif/if_ddavar.h"
124*39729Ssklower
125*39729Ssklower #else SIMULATION
126*39729Ssklower #include "machine/pte.h" /* page table entries */
127*39729Ssklower
128*39729Ssklower #include "h/param.h"
129*39729Ssklower #include "h/systm.h"
130*39729Ssklower #include "h/mbuf.h"
131*39729Ssklower #include "h/buf.h"
132*39729Ssklower #include "h/protosw.h"
133*39729Ssklower #include "h/socket.h"
134*39729Ssklower #include "h/vmmac.h"
135*39729Ssklower #include "h/errno.h"
136*39729Ssklower #include "h/dir.h"
137*39729Ssklower #include "h/user.h"
138*39729Ssklower #include "h/kernel.h"
139*39729Ssklower #include "h/ioctl.h"
140*39729Ssklower
141*39729Ssklower #include "vax/cpu.h"
142*39729Ssklower #include "vax/mtpr.h"
143*39729Ssklower
144*39729Ssklower #include "net/if.h"
145*39729Ssklower #include "net/netisr.h"
146*39729Ssklower #include "net/route.h"
147*39729Ssklower #include "netinet/in.h"
148*39729Ssklower #include "netinet/in_systm.h"
149*39729Ssklower # if ACC_BSD > 42 || ACC_ULTRIX > 12
150*39729Ssklower # include "netinet/in_var.h"
151*39729Ssklower # endif
152*39729Ssklower #include "netinet/ip.h"
153*39729Ssklower #include "netinet/ip_var.h"
154*39729Ssklower #include "if_ddareg.h"
155*39729Ssklower #include "if_ddavar.h"
156*39729Ssklower
157*39729Ssklower # ifndef SIOCACPCONFIG
158*39729Ssklower # define SIOCACPCONFIG _IOWR(i,40,struct ifreq)
159*39729Ssklower # endif
160*39729Ssklower # ifndef INET
161*39729Ssklower # define INET 1
162*39729Ssklower # endif
163*39729Ssklower
164*39729Ssklower extern struct ifqueue ipintrq; /* IP input queue */
165*39729Ssklower #endif SIMULATION
166*39729Ssklower
167*39729Ssklower #if ACC_VMS > 00
168*39729Ssklower # ifdef eunice
169*39729Ssklower # define WINS
170*39729Ssklower # else
171*39729Ssklower # define MULTINET
172*39729Ssklower # endif
173*39729Ssklower #endif
174*39729Ssklower
175*39729Ssklower #if ACC_VMS > 00
176*39729Ssklower # ifdef WINS
177*39729Ssklower # include <vms/adpdef.h> /* Define Adapters */
178*39729Ssklower # include <vms/dcdef.h> /* Define AT$_UBA, adapter type */
179*39729Ssklower # else MULTINET
180*39729Ssklower # include "../vaxif/if_ddaioctl.h" /* not in ioctl.h */
181*39729Ssklower # endif
182*39729Ssklower #endif
183*39729Ssklower
184*39729Ssklower /* disable histogram functions for BSD 4.2 and ULTRIX 1.2 */
185*39729Ssklower
186*39729Ssklower #if ACC_BSD == 42 || ACC_ULTRIX == 12
187*39729Ssklower # undef DDA_HISTOGRAM
188*39729Ssklower #endif
189*39729Ssklower
190*39729Ssklower /* Ultrix doesn't have syslog, so use printf instead. Since the two
191*39729Ssklower * functions take different arg list formats, embed the open paren in
192*39729Ssklower * the defined symbol; provide DDAELOG to close the call while keeping
193*39729Ssklower * parentheses matched. The argument to DDALOG is ignored for printf;
194*39729Ssklower * for log(), debugging messages use LOG_DEBUG, all others use LOG_ERR.
195*39729Ssklower */
196*39729Ssklower #if (ACC_BSD > 42 || ACC_VMS > 00) && !defined(SIMULATION)
197*39729Ssklower # include "syslog.h"
198*39729Ssklower # define DDALOG(s) log( s,
199*39729Ssklower #else
200*39729Ssklower # define DDALOG(s) printf(
201*39729Ssklower #endif
202*39729Ssklower #define DDAELOG )
203*39729Ssklower
204*39729Ssklower #ifndef DDADEBUG
205*39729Ssklower #define PRIVATE static /* hide our internal functions */
206*39729Ssklower #else
207*39729Ssklower #define PRIVATE /* let the world see them */
208*39729Ssklower #endif
209*39729Ssklower
210*39729Ssklower /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
211*39729Ssklower /*%% %%*/
212*39729Ssklower /*%% GLOBAL FUNCTIONS %%*/
213*39729Ssklower /*%% %%*/
214*39729Ssklower /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
215*39729Ssklower
216*39729Ssklower int ddaprobe();
217*39729Ssklower int ddaattach();
218*39729Ssklower int ddareset();
219*39729Ssklower int ddainit();
220*39729Ssklower int ddaoutput();
221*39729Ssklower int ddatimer();
222*39729Ssklower int ddaioctl();
223*39729Ssklower int ddainta(); /* service interrupt "a" from front end */
224*39729Ssklower int ddaintb(); /* service interrupt "b" from front end */
225*39729Ssklower
226*39729Ssklower
227*39729Ssklower /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
228*39729Ssklower /*%% %%*/
229*39729Ssklower /*%% LOCAL FUNCTIONS %%*/
230*39729Ssklower /*%% %%*/
231*39729Ssklower /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
232*39729Ssklower
233*39729Ssklower PRIVATE void send_config();
234*39729Ssklower PRIVATE struct dda_cb *locate_x25_lcn();
235*39729Ssklower PRIVATE struct dda_cb *find_free_lcn();
236*39729Ssklower PRIVATE boolean convert_ip_addr();
237*39729Ssklower PRIVATE u_long convert_x25_addr();
238*39729Ssklower PRIVATE boolean make_x25_call();
239*39729Ssklower PRIVATE void dda_start();
240*39729Ssklower PRIVATE void dda_rrq();
241*39729Ssklower PRIVATE void dda_wrq();
242*39729Ssklower PRIVATE int start_chn();
243*39729Ssklower PRIVATE void dda_data();
244*39729Ssklower PRIVATE void dda_supr();
245*39729Ssklower PRIVATE void supr_msg();
246*39729Ssklower PRIVATE boolean decode_ring();
247*39729Ssklower PRIVATE void decode_answer();
248*39729Ssklower PRIVATE void clear_lcn();
249*39729Ssklower PRIVATE void send_restart();
250*39729Ssklower PRIVATE void send_supr();
251*39729Ssklower PRIVATE void start_supr();
252*39729Ssklower PRIVATE void abort_io();
253*39729Ssklower PRIVATE void prt_addr();
254*39729Ssklower
255*39729Ssklower #ifdef DDA_PAD_OR_RAW
256*39729Ssklower PRIVATE int dda_decode_type();
257*39729Ssklower #endif
258*39729Ssklower
259*39729Ssklower #ifdef DDA_PADOPT
260*39729Ssklower PRIVATE void x29_data();
261*39729Ssklower PRIVATE void x29_supr();
262*39729Ssklower PRIVATE void x29_init();
263*39729Ssklower #endif DDA_PADOPT
264*39729Ssklower
265*39729Ssklower #ifdef DDA_RAWOPT
266*39729Ssklower PRIVATE void pi_data();
267*39729Ssklower PRIVATE void pi_supr();
268*39729Ssklower PRIVATE void pi_init();
269*39729Ssklower PRIVATE int pi_circuit_to_handle_protocol();
270*39729Ssklower #endif DDA_RAWOPT
271*39729Ssklower
272*39729Ssklower #ifdef DDADEBUG
273*39729Ssklower PRIVATE void prt_bytes();
274*39729Ssklower #endif
275*39729Ssklower
276*39729Ssklower PRIVATE char *fmt_x25();
277*39729Ssklower
278*39729Ssklower #ifdef DDA_HISTOGRAM
279*39729Ssklower PRIVATE void hist_init(); /* histogram functions */
280*39729Ssklower PRIVATE void hist_lcn_state();
281*39729Ssklower PRIVATE void hist_all_lcns();
282*39729Ssklower PRIVATE void hist_link_state();
283*39729Ssklower PRIVATE void hist_read();
284*39729Ssklower PRIVATE int hist_copyout();
285*39729Ssklower
286*39729Ssklower #else DDA_HISTOGRAM /* make all histogram functions no-op's */
287*39729Ssklower #define hist_init(a,b)
288*39729Ssklower #define hist_lcn_state(a,b,c)
289*39729Ssklower #define hist_all_lcns(a,b)
290*39729Ssklower #define hist_link_state(a,b,c)
291*39729Ssklower #define hist_read(a)
292*39729Ssklower #define hist_copyout(a,b)
293*39729Ssklower #endif DDA_HISTOGRAM
294*39729Ssklower
295*39729Ssklower
296*39729Ssklower /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
297*39729Ssklower /*%% %%*/
298*39729Ssklower /*%% LOCAL VARIABLES %%*/
299*39729Ssklower /*%% %%*/
300*39729Ssklower /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
301*39729Ssklower
302*39729Ssklower PRIVATE int tmo_data_idle = TMO_DATA_IDLE; /* idle circuit timeout for
303*39729Ssklower * all boards */
304*39729Ssklower
305*39729Ssklower PRIVATE int nddach[4] = { /* number of channels currently in use */
306*39729Ssklower NDDACH_DEFAULT, NDDACH_DEFAULT,
307*39729Ssklower NDDACH_DEFAULT, NDDACH_DEFAULT };
308*39729Ssklower
309*39729Ssklower PRIVATE char *dda_product; /* name of product, like "ACP5250" */
310*39729Ssklower PRIVATE int dda_hasmaint; /* do we have a maintenance board? */
311*39729Ssklower
312*39729Ssklower /* the message bits are used in the DMESG macros defined in if_ddavar.h */
313*39729Ssklower /* word 1 and 2 (msgs 0 - 63) are reserved for the IP interface */
314*39729Ssklower /* word 3 (msgs 64 - 95) are reserved for the PI interface */
315*39729Ssklower /* word 4 (msgs 96 - 127) are reserved for the X.29 interface */
316*39729Ssklower /* word 5 and 6 (msgs 128 - 191) are reserved for debugging main module*/
317*39729Ssklower /* word 7 (msgs 192 - 223) are reserved for debugging the PI */
318*39729Ssklower /* word 8 (msgs 224 - 255) are reserved for debugging X29 */
319*39729Ssklower /* word 9 (msgs 256 - 287) are reserved for call logging */
320*39729Ssklower #define NDMESGWORDS 9
321*39729Ssklower #define MAXDMSGS (NDMESGWORDS * 32)
322*39729Ssklower PRIVATE long ddamsgs[NDDA][NDMESGWORDS];
323*39729Ssklower /* | | | | | | | | |
324*39729Ssklower * default: all informational messages on, /--/--/--/ | | | | |
325*39729Ssklower * all debug messages off, --------------------/---/---/---/ |
326*39729Ssklower * log busys, but not calls or I/O aborts ---------------------/
327*39729Ssklower */
328*39729Ssklower
329*39729Ssklower /* Must be as large as the larger of (trtab, ddactl, dnload): */
330*39729Ssklower char dda_iobuf[sizeof(struct ddactl)];
331*39729Ssklower
332*39729Ssklower struct dda_softc dda_softc[NDDA]; /* per device infomation */
333*39729Ssklower
334*39729Ssklower /* header for building command to be sent to the front end in */
335*39729Ssklower /* response to ACPCONFIG user command */
336*39729Ssklower
337*39729Ssklower PRIVATE u_char acpconfig_msg[] = {
338*39729Ssklower LINE_CNTL, /* set command code */
339*39729Ssklower 0x00, /* not used */
340*39729Ssklower 0x00, /* not used */
341*39729Ssklower 0x00, /* extension length (set at runtime) */
342*39729Ssklower 0x00, /* cmd space */
343*39729Ssklower 0x00,
344*39729Ssklower 0x00,
345*39729Ssklower 0x00,
346*39729Ssklower 0x00
347*39729Ssklower };
348*39729Ssklower
349*39729Ssklower PRIVATE u_char bfr_size_msg[] =
350*39729Ssklower {
351*39729Ssklower SET_BFR_SIZE, /* set command code */
352*39729Ssklower 0x00, /* not used */
353*39729Ssklower 0x00, /* not used */
354*39729Ssklower 0x01, /* extension length */
355*39729Ssklower 0x00, /* cmd space */
356*39729Ssklower 0x00,
357*39729Ssklower 0x00,
358*39729Ssklower 0x00,
359*39729Ssklower 0x00
360*39729Ssklower };
361*39729Ssklower
362*39729Ssklower PRIVATE u_char ddacb_cmnd[4] = { CALL, 0, 0, 0 };
363*39729Ssklower PRIVATE u_char ddacb_called_addr[16] = {0};
364*39729Ssklower PRIVATE u_char ddacb_calling_addr[16] = {0};
365*39729Ssklower PRIVATE u_char ddacb_facilities[64] = {0};
366*39729Ssklower PRIVATE u_char ddacb_protocol[5] = {0};
367*39729Ssklower PRIVATE u_char ddacb_user_data[64] = {0};
368*39729Ssklower
369*39729Ssklower #ifdef DDADEBUG
370*39729Ssklower u_char dda_silo_counter;
371*39729Ssklower u_char dda_debug_silo[256];
372*39729Ssklower #endif
373*39729Ssklower
374*39729Ssklower /* Table of baud rate values and the associated parameter for the Set */
375*39729Ssklower /* System Parameters message, ddainit_msg. The 'parameter1' is nonzero */
376*39729Ssklower /* for valid baud rate divisors. These are nominal baud rates. */
377*39729Ssklower
378*39729Ssklower PRIVATE struct baud {
379*39729Ssklower char b_value;
380*39729Ssklower u_char parameter1; /* first byte of baud rate setting */
381*39729Ssklower u_char parameter2; /* second byte of baud rate setting */
382*39729Ssklower } ddabaud_rate[] = {
383*39729Ssklower { 1, 0x02, 0x00 }, /* 2.00M */
384*39729Ssklower { 2, 0x03, 0x00 }, /* 1.33M */
385*39729Ssklower { 3, 0x04, 0x00 }, /* 1.00M */
386*39729Ssklower { 4, 0x08, 0x00 }, /* 500K */
387*39729Ssklower { 5, 0x10, 0x00 }, /* 250K */
388*39729Ssklower { 6, 0x28, 0x00 }, /* 100K */
389*39729Ssklower { 7, 0x3e, 0x00 }, /* 64K */
390*39729Ssklower { 8, 0x47, 0x00 }, /* 56K */
391*39729Ssklower { 9, 0x85, 0x00 }, /* 30K */
392*39729Ssklower { 10, 0xd0, 0x00 }, /* 19.2K */
393*39729Ssklower { 11, 0xa1, 0x01 }, /* 9600 */
394*39729Ssklower { 12, 0x41, 0x03 }, /* 4800 */
395*39729Ssklower { 13, 0x83, 0x06 }, /* 2400 */
396*39729Ssklower { 14, 0x05, 0x0d }, /* 1200 */
397*39729Ssklower { 0, 0, 0 }
398*39729Ssklower };
399*39729Ssklower
400*39729Ssklower /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
401*39729Ssklower /*%% %%*/
402*39729Ssklower /*%% Address Translation Table for Internet <-> X.25 addresses %%*/
403*39729Ssklower /*%% %%*/
404*39729Ssklower /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
405*39729Ssklower
406*39729Ssklower #define DDANATT 32 /* number of addr translation table entries */
407*39729Ssklower PRIVATE int dda_num_addr_tr[NDDA] = {0}; /* number of address
408*39729Ssklower * translations */
409*39729Ssklower
410*39729Ssklower /* currently stored */
411*39729Ssklower PRIVATE struct dda_addr_tr { /* X.25 PDN address translation table */
412*39729Ssklower u_long ip_addr; /* internet address */
413*39729Ssklower u_char x25_addr[MAXADDRLEN]; /* X.25 address */
414*39729Ssklower } dda_addr_tr[NDDA][DDANATT] = {{ 0L, ""}}; /* null */
415*39729Ssklower
416*39729Ssklower /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
417*39729Ssklower /*%% %%*/
418*39729Ssklower /*%% Aliasing of IP address for 4.2 ==> 4.3 compatibility %%*/
419*39729Ssklower /*%% Note: this union is not required in 4.2, since the s_net %%*/
420*39729Ssklower /*%% field and its friends are in an include file. We use it to %%*/
421*39729Ssklower /*%% minimize the number of #ifdef dependencies in the code. %%*/
422*39729Ssklower /*%% %%*/
423*39729Ssklower /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
424*39729Ssklower
425*39729Ssklower #ifdef s_net /* 4.2 */
426*39729Ssklower # undef s_net
427*39729Ssklower # undef s_host
428*39729Ssklower # undef s_lh
429*39729Ssklower # undef s_impno
430*39729Ssklower #endif
431*39729Ssklower
432*39729Ssklower union imp_addr {
433*39729Ssklower struct in_addr ip;
434*39729Ssklower struct imp {
435*39729Ssklower u_char s_net;
436*39729Ssklower u_char s_host;
437*39729Ssklower u_char s_lh;
438*39729Ssklower u_char s_impno;
439*39729Ssklower } imp;
440*39729Ssklower };
441*39729Ssklower
442*39729Ssklower /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
443*39729Ssklower /*%% %%*/
444*39729Ssklower /*%% GLOBAL ROUTINES %%*/
445*39729Ssklower /*%% %%*/
446*39729Ssklower /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
447*39729Ssklower
448*39729Ssklower #ifdef ACP_BI
449*39729Ssklower #include "if_dda_bibus.c"
450*39729Ssklower #else
451*39729Ssklower #include "if_dda_uqbus.c"
452*39729Ssklower #endif
453*39729Ssklower
454*39729Ssklower /*@@%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
455*39729Ssklower /*%% DDAIOCTL() %%*/
456*39729Ssklower /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
457*39729Ssklower /* */
458*39729Ssklower /* Purpose: */
459*39729Ssklower /* */
460*39729Ssklower /* This routine processes device dependent ioctl's. Supported */
461*39729Ssklower /* ioctls set the host's internet address for this network */
462*39729Ssklower /* interface, or send Set System Parameters Message to the ACP. */
463*39729Ssklower /* The logic for setting the interface address must remain */
464*39729Ssklower /* compatible with both ifconfig and acpconfig programs. */
465*39729Ssklower /* If the ioctl comes from the acpconfig program, the front end */
466*39729Ssklower /* is not initialized because the user will specify explicitly */
467*39729Ssklower /* what parameters are desired. If the ioctl comes from the */
468*39729Ssklower /* ifconfig program, the fron end is initialized with default */
469*39729Ssklower /* parameters in the ddainit_msg array. */
470*39729Ssklower /* */
471*39729Ssklower /* Call: ddaioctl(ifp, cmd, data) */
472*39729Ssklower /* Argument: ifp: pointer to the network interface data */
473*39729Ssklower /* structure, ifnet */
474*39729Ssklower /* cmd: identifies the type of ioctl */
475*39729Ssklower /* data: information for the ioctl */
476*39729Ssklower /* Returns: 0 for success, or the nonzero error value: */
477*39729Ssklower /* EINVAL invalid ioctl request */
478*39729Ssklower /* Called by: network software, address of this routine is */
479*39729Ssklower /* defined in af_inet network interface struct */
480*39729Ssklower /* Calls to: splimp() */
481*39729Ssklower /* if_rtinit() */
482*39729Ssklower /* in_netof() */
483*39729Ssklower /* in_lnaof() */
484*39729Ssklower /* ddainit() */
485*39729Ssklower /* send_config() */
486*39729Ssklower /* DDALOG() */
487*39729Ssklower /* splx() */
488*39729Ssklower /* */
489*39729Ssklower /*##%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
490*39729Ssklower
491*39729Ssklower #ifdef MULTINET
492*39729Ssklower volatile int StatQuery_Completed; /* Polled for board stat ioctl */
493*39729Ssklower #endif
494*39729Ssklower
ddaioctl(ifp,cmd,data)495*39729Ssklower ddaioctl(ifp, cmd, data)
496*39729Ssklower register struct ifnet *ifp;
497*39729Ssklower int cmd;
498*39729Ssklower caddr_t data;
499*39729Ssklower {
500*39729Ssklower register struct dda_softc *ds = &dda_softc[ifp->if_unit];
501*39729Ssklower struct ifreq *ifr = (struct ifreq *) data;
502*39729Ssklower
503*39729Ssklower #if defined(DDA_PADOPT) && defined(WINS)
504*39729Ssklower int prealloc_x29(); /* Preallocate UCBs for X29 */
505*39729Ssklower #endif
506*39729Ssklower
507*39729Ssklower #if ACC_BSD == 42 || ACC_ULTRIX == 12
508*39729Ssklower struct sockaddr_in *sin = (struct sockaddr_in *) & ifr->ifr_addr;
509*39729Ssklower #else
510*39729Ssklower struct ifaddr *ifa = ds->dda_if.if_addrlist;
511*39729Ssklower #endif
512*39729Ssklower
513*39729Ssklower int s;
514*39729Ssklower int error = 0;
515*39729Ssklower int i;
516*39729Ssklower register struct dda_addr_tr *atp, *btp;
517*39729Ssklower struct trtab *tr;
518*39729Ssklower struct ddactl *da;
519*39729Ssklower char arg2[MAXADDRLEN], code;
520*39729Ssklower
521*39729Ssklower #ifdef DDADEBUG
522*39729Ssklower if (DDADBCH(4, ifp->if_unit)) {
523*39729Ssklower DDALOG(LOG_DEBUG) "dda%d: ioctl()\n", ifp->if_unit DDAELOG;
524*39729Ssklower }
525*39729Ssklower #endif DDADEBUG
526*39729Ssklower
527*39729Ssklower /*
528*39729Ssklower * This may not be necessary here, but under some flavors of BSDish
529*39729Ssklower * systems (2.0ULTRIX) this routine is apparently called at splimp(). In
530*39729Ssklower * the case that we are currently processing ioctls issued from acpconfig
531*39729Ssklower * in /etc/rc, the board may not have come on line yet - so we need to be
532*39729Ssklower * able to process the B interrupt while in the delay loop below.
533*39729Ssklower */
534*39729Ssklower #ifndef MULTINET
535*39729Ssklower s = spl0();
536*39729Ssklower #endif
537*39729Ssklower
538*39729Ssklower switch (cmd) {
539*39729Ssklower case SIOCSIFADDR:
540*39729Ssklower if (!suser())
541*39729Ssklower return EACCES;
542*39729Ssklower
543*39729Ssklower #if ACC_BSD == 42 || ACC_ULTRIX == 12
544*39729Ssklower if (ifp->if_flags & IFF_RUNNING)
545*39729Ssklower if_rtinit(ifp, -1); /* delete previous route */
546*39729Ssklower ifp->if_addr = *(struct sockaddr *) sin;
547*39729Ssklower ifp->if_net = in_netof(sin->sin_addr);
548*39729Ssklower ifp->if_host[0] = in_lnaof(sin->sin_addr);
549*39729Ssklower if (ifp->if_flags & IFF_RUNNING)
550*39729Ssklower if_rtinit(ifp, RTF_UP);
551*39729Ssklower else
552*39729Ssklower ddainit(ifp->if_unit);
553*39729Ssklower ds->dda_ipaddr.s_addr = ((struct sockaddr_in *) & ifp->if_addr)->sin_addr.s_addr;
554*39729Ssklower #else /* 4.3 networking */
555*39729Ssklower if (ifa->ifa_addr.sa_family != AF_INET)
556*39729Ssklower return (EINVAL);
557*39729Ssklower if ((ifp->if_flags & IFF_RUNNING) == 0)
558*39729Ssklower ddainit(ifp->if_unit);
559*39729Ssklower ds->dda_ipaddr = IA_SIN(ifa)->sin_addr;
560*39729Ssklower #endif /* 4.3 networking */
561*39729Ssklower break;
562*39729Ssklower
563*39729Ssklower case SIOCACPCONFIG:
564*39729Ssklower /* process ioctl from acpconfig program */
565*39729Ssklower
566*39729Ssklower code = *(ifr->ifr_data);
567*39729Ssklower
568*39729Ssklower /*********************************************************
569*39729Ssklower * *
570*39729Ssklower * Commands n, h, q, and r are non-privileged *
571*39729Ssklower * *
572*39729Ssklower *********************************************************/
573*39729Ssklower
574*39729Ssklower if (!suser() && code != 'n' && code != 'h' && code != 'q' && code != 'r')
575*39729Ssklower return EACCES;
576*39729Ssklower
577*39729Ssklower #if ACC_BSD == 42 || ACC_ULTRIX == 12
578*39729Ssklower sin = (struct sockaddr_in *) & ds->dda_if.if_addr;
579*39729Ssklower if (in_netof(sin->sin_addr) == 0)
580*39729Ssklower #else
581*39729Ssklower if (ds->dda_if.if_addrlist == 0)
582*39729Ssklower #endif
583*39729Ssklower {
584*39729Ssklower error = EDESTADDRREQ; /* error, no internet address */
585*39729Ssklower goto exit;
586*39729Ssklower }
587*39729Ssklower /* for command to set baud rate, look up the value for the */
588*39729Ssklower /* baud rate divisor in the ddabaud_rate table, put value */
589*39729Ssklower /* in the Set System Parameters message, ddainit_msg */
590*39729Ssklower
591*39729Ssklower if (code >= 1 && code <= 14) {
592*39729Ssklower register struct baud *p;
593*39729Ssklower
594*39729Ssklower if (error = diags_completed(ds))
595*39729Ssklower goto exit;
596*39729Ssklower for (p = ddabaud_rate; p->b_value; p++) {
597*39729Ssklower if ((*(ifr->ifr_data) - p->b_value) == 0)
598*39729Ssklower break;
599*39729Ssklower }
600*39729Ssklower /* if internal clock not set, do so */
601*39729Ssklower if ((ds->dda_init & DDA_INTCLOCK) == 0) {
602*39729Ssklower ds->dda_init |= DDA_INTCLOCK;
603*39729Ssklower acpconfig_msg[MSG_OFFSET] = CLOCK_CNTL;
604*39729Ssklower acpconfig_msg[MSG_OFFSET + 1] = INTERNAL_CLOCK;
605*39729Ssklower acpconfig_msg[MSG_OFFSET + 2] = BAUD_CNTL;
606*39729Ssklower acpconfig_msg[MSG_OFFSET + 3] = p->parameter1;
607*39729Ssklower acpconfig_msg[MSG_OFFSET + 4] = p->parameter2;
608*39729Ssklower acpconfig_msg[MSG_LENGTH] = 5;
609*39729Ssklower } else {
610*39729Ssklower acpconfig_msg[MSG_OFFSET] = BAUD_CNTL;
611*39729Ssklower acpconfig_msg[MSG_OFFSET + 1] = p->parameter1;
612*39729Ssklower acpconfig_msg[MSG_OFFSET + 2] = p->parameter2;
613*39729Ssklower acpconfig_msg[MSG_LENGTH] = 3;
614*39729Ssklower }
615*39729Ssklower
616*39729Ssklower if ((p->b_value == 0) || (p->parameter1 == 0))
617*39729Ssklower error = EINVAL; /* baud rate value invalid */
618*39729Ssklower else
619*39729Ssklower send_config(ds, acpconfig_msg); /* send message to front end */
620*39729Ssklower goto exit;
621*39729Ssklower }
622*39729Ssklower switch (code) {
623*39729Ssklower case 'a': /* Add address translation table entry */
624*39729Ssklower if (error = diags_completed(ds))
625*39729Ssklower goto exit;
626*39729Ssklower if (dda_num_addr_tr[ifp->if_unit] >= DDANATT) { /* table already full */
627*39729Ssklower error = ENOMEM;
628*39729Ssklower goto exit;
629*39729Ssklower }
630*39729Ssklower
631*39729Ssklower /*
632*39729Ssklower * Copy in user arguments and point "tr" at them. Then scan the
633*39729Ssklower * translation table and either find location to insert or flag
634*39729Ssklower * error
635*39729Ssklower */
636*39729Ssklower if (copyin(ifr->ifr_data, dda_iobuf, sizeof(struct trtab))) {
637*39729Ssklower error = EFAULT;
638*39729Ssklower goto exit;
639*39729Ssklower }
640*39729Ssklower tr = (struct trtab *) dda_iobuf;
641*39729Ssklower for (i = 0, atp = &dda_addr_tr[ifp->if_unit][0];
642*39729Ssklower i < dda_num_addr_tr[ifp->if_unit]; i++, atp++) {
643*39729Ssklower if (atp->ip_addr == tr->ipaddr) {
644*39729Ssklower if (bcmp((char *) atp->x25_addr,
645*39729Ssklower (char *) tr->x25addr, MAXADDRLEN)) {
646*39729Ssklower error = EADDRINUSE;
647*39729Ssklower goto exit;
648*39729Ssklower } else /* addresses are the same, just ignore ioctl */
649*39729Ssklower goto exit;
650*39729Ssklower }
651*39729Ssklower if (atp->ip_addr > tr->ipaddr) /* insert entry here */
652*39729Ssklower break;
653*39729Ssklower }
654*39729Ssklower for (btp = &dda_addr_tr[ifp->if_unit][dda_num_addr_tr[ifp->if_unit]];
655*39729Ssklower btp > atp; btp--) { /* open up space for a new entry */
656*39729Ssklower btp->ip_addr = (btp - 1)->ip_addr;
657*39729Ssklower bcopy((btp - 1)->x25_addr, btp->x25_addr, MAXADDRLEN);
658*39729Ssklower }
659*39729Ssklower atp->ip_addr = tr->ipaddr;
660*39729Ssklower bcopy(tr->x25addr, atp->x25_addr, MAXADDRLEN);
661*39729Ssklower dda_num_addr_tr[ifp->if_unit]++; /* one more table entry */
662*39729Ssklower goto exit;
663*39729Ssklower
664*39729Ssklower case 'D':
665*39729Ssklower if (error = diags_completed(ds))
666*39729Ssklower goto exit;
667*39729Ssklower /* clear table for use by 'r' flag of acpconfig */
668*39729Ssklower for (i = 0, atp = &dda_addr_tr[ifp->if_unit][0];
669*39729Ssklower i < dda_num_addr_tr[ifp->if_unit]; i++, atp++) {
670*39729Ssklower atp->ip_addr = 0L;
671*39729Ssklower atp->x25_addr[0] = 0;
672*39729Ssklower }
673*39729Ssklower dda_num_addr_tr[ifp->if_unit] = 0;
674*39729Ssklower goto exit;
675*39729Ssklower
676*39729Ssklower case 'd': /* Delete address translation table entry */
677*39729Ssklower if (error = diags_completed(ds))
678*39729Ssklower goto exit;
679*39729Ssklower if (copyin(ifr->ifr_data, dda_iobuf, sizeof(struct trtab))) {
680*39729Ssklower error = EFAULT;
681*39729Ssklower goto exit;
682*39729Ssklower }
683*39729Ssklower tr = (struct trtab *) dda_iobuf;
684*39729Ssklower error = EFAULT; /* in case inet address not in table */
685*39729Ssklower for (i = 0, atp = &dda_addr_tr[ifp->if_unit][0];
686*39729Ssklower i < dda_num_addr_tr[ifp->if_unit]; i++, atp++) {
687*39729Ssklower if (atp->ip_addr == tr->ipaddr) {
688*39729Ssklower error = 0; /* found it: cancel error */
689*39729Ssklower for (; i < dda_num_addr_tr[ifp->if_unit] - 1; i++, atp++) {
690*39729Ssklower atp->ip_addr = (atp + 1)->ip_addr;
691*39729Ssklower bcopy((atp + 1)->x25_addr, atp->x25_addr, MAXADDRLEN);
692*39729Ssklower }
693*39729Ssklower atp->ip_addr = 0L; /* clear last vacated entry */
694*39729Ssklower atp->x25_addr[0] = 0;
695*39729Ssklower dda_num_addr_tr[ifp->if_unit]--; /* one fewer table
696*39729Ssklower * entries */
697*39729Ssklower break;
698*39729Ssklower }
699*39729Ssklower }
700*39729Ssklower goto exit;
701*39729Ssklower
702*39729Ssklower
703*39729Ssklower case 'f': /* -f facility status */
704*39729Ssklower
705*39729Ssklower /*
706*39729Ssklower * The first byte of the "msg" selects the flow control parameter
707*39729Ssklower * and the "drval" field holds the status (on or off).
708*39729Ssklower */
709*39729Ssklower if (error = diags_completed(ds))
710*39729Ssklower goto exit;
711*39729Ssklower if (copyin(ifr->ifr_data, dda_iobuf, sizeof(struct ddactl))) {
712*39729Ssklower error = EFAULT;
713*39729Ssklower goto exit;
714*39729Ssklower }
715*39729Ssklower if (ds->dda_firmrev < 0x21) { /* need 2.0 or above ROMs */
716*39729Ssklower error = ENOPROTOOPT;
717*39729Ssklower goto exit;
718*39729Ssklower }
719*39729Ssklower da = (struct ddactl *) dda_iobuf;
720*39729Ssklower switch (da->msg[0]) {
721*39729Ssklower case 0: /* packet */
722*39729Ssklower if (da->drval)
723*39729Ssklower ds->dda_init |= DDA_PKTNEG;
724*39729Ssklower else
725*39729Ssklower ds->dda_init &= ~DDA_PKTNEG;
726*39729Ssklower break;
727*39729Ssklower case 1: /* window */
728*39729Ssklower if (da->drval)
729*39729Ssklower ds->dda_init |= DDA_WNDNEG;
730*39729Ssklower else
731*39729Ssklower ds->dda_init &= ~DDA_WNDNEG;
732*39729Ssklower break;
733*39729Ssklower }
734*39729Ssklower goto exit;
735*39729Ssklower
736*39729Ssklower case 'o': /* Set options */
737*39729Ssklower if (error = diags_completed(ds))
738*39729Ssklower goto exit;
739*39729Ssklower if (ds->dda_firmrev < 0x21) { /* need 2.1 or above ROMs */
740*39729Ssklower error = ENOPROTOOPT;
741*39729Ssklower goto exit;
742*39729Ssklower }
743*39729Ssklower if (ds->dda_state != S_DISABLED) { /* must bring link down */
744*39729Ssklower error = EINPROGRESS;
745*39729Ssklower goto exit;
746*39729Ssklower }
747*39729Ssklower if (copyin(ifr->ifr_data, dda_iobuf, sizeof(struct ddactl))) {
748*39729Ssklower error = EFAULT;
749*39729Ssklower goto exit;
750*39729Ssklower }
751*39729Ssklower da = (struct ddactl *) dda_iobuf;
752*39729Ssklower acpconfig_msg[MSG_OFFSET] = PKT_OPTIONS;
753*39729Ssklower acpconfig_msg[MSG_OFFSET + 1] = da->msg[0];
754*39729Ssklower acpconfig_msg[MSG_LENGTH] = 2;
755*39729Ssklower #ifdef DDADEBUG
756*39729Ssklower if (DDADBCH(4, ifp->if_unit)) {
757*39729Ssklower DDALOG(LOG_DEBUG) "dda%d: acpconfig_msg is %x %x %x\n",
758*39729Ssklower ifp->if_unit, acpconfig_msg[MSG_LENGTH],
759*39729Ssklower acpconfig_msg[MSG_OFFSET], acpconfig_msg[MSG_OFFSET + 1] DDAELOG;
760*39729Ssklower }
761*39729Ssklower #endif DDADEBUG
762*39729Ssklower
763*39729Ssklower send_config(ds, acpconfig_msg);
764*39729Ssklower goto exit;
765*39729Ssklower
766*39729Ssklower case 'N': /* read network id */
767*39729Ssklower if (copyin(ifr->ifr_data, dda_iobuf, sizeof(struct ddactl))) {
768*39729Ssklower error = EFAULT;
769*39729Ssklower goto exit;
770*39729Ssklower }
771*39729Ssklower da = (struct ddactl *) dda_iobuf;
772*39729Ssklower ds->dda_net_id = da->drval;
773*39729Ssklower goto exit;
774*39729Ssklower
775*39729Ssklower case 'r': /* Read address translation table entry */
776*39729Ssklower
777*39729Ssklower /*
778*39729Ssklower * The value stored in "ipaddr" is not an address, but an index
779*39729Ssklower * of a translation table entry to read out. The x25_addr field
780*39729Ssklower * in the input structure is not used.
781*39729Ssklower */
782*39729Ssklower if (error = diags_completed(ds))
783*39729Ssklower goto exit;
784*39729Ssklower if (copyin(ifr->ifr_data, dda_iobuf, sizeof(struct trtab))) {
785*39729Ssklower error = EFAULT;
786*39729Ssklower goto exit;
787*39729Ssklower }
788*39729Ssklower tr = (struct trtab *) dda_iobuf;
789*39729Ssklower i = tr->ipaddr;
790*39729Ssklower if (i >= DDANATT) { /* scanned the whole table */
791*39729Ssklower error = EFAULT;
792*39729Ssklower goto exit;
793*39729Ssklower }
794*39729Ssklower tr->ipaddr = dda_addr_tr[ifp->if_unit][i].ip_addr;
795*39729Ssklower bcopy(dda_addr_tr[ifp->if_unit][i].x25_addr, tr->x25addr, MAXADDRLEN);
796*39729Ssklower if (copyout(tr, ifr->ifr_data, sizeof(struct trtab)))
797*39729Ssklower error = EFAULT;
798*39729Ssklower goto exit;
799*39729Ssklower
800*39729Ssklower #ifdef DDA_HISTOGRAM
801*39729Ssklower case 'h': /* read histogram */
802*39729Ssklower if (error = diags_completed(ds))
803*39729Ssklower goto exit;
804*39729Ssklower hist_read(ifp->if_unit);
805*39729Ssklower if (hist_copyout(ifp->if_unit, ifr->ifr_data))
806*39729Ssklower error = EFAULT;
807*39729Ssklower goto exit;
808*39729Ssklower
809*39729Ssklower case 'H': /* read and reset histogram */
810*39729Ssklower if (error = diags_completed(ds))
811*39729Ssklower goto exit;
812*39729Ssklower hist_read(ifp->if_unit);
813*39729Ssklower if (hist_copyout(ifp->if_unit, ifr->ifr_data))
814*39729Ssklower error = EFAULT;
815*39729Ssklower else
816*39729Ssklower hist_init(ifp->if_unit, 1);
817*39729Ssklower goto exit;
818*39729Ssklower #endif DDA_HISTOGRAM
819*39729Ssklower
820*39729Ssklower case 'v': /* -v variable value */
821*39729Ssklower
822*39729Ssklower /*
823*39729Ssklower * There are two "variables" in the driver which can be set via
824*39729Ssklower * ioctl: packet size, and window size. The "drval" field holds
825*39729Ssklower * the value and the first byte of the "msg" selects the variable.
826*39729Ssklower * Note that the selector is another little undocumented piece of
827*39729Ssklower * the interface between here and the acpconfig program. It is
828*39729Ssklower * coupled to the ordering of a little string table inside that
829*39729Ssklower * program; new parameters should be added at the end, not the
830*39729Ssklower * middle!
831*39729Ssklower */
832*39729Ssklower /* No check to see if powerup diags are completed */
833*39729Ssklower if (copyin(ifr->ifr_data, dda_iobuf, sizeof(struct ddactl))) {
834*39729Ssklower error = EFAULT;
835*39729Ssklower goto exit;
836*39729Ssklower }
837*39729Ssklower da = (struct ddactl *) dda_iobuf;
838*39729Ssklower switch (da->msg[0]) {
839*39729Ssklower case 0: /* set logging (obsolete) */
840*39729Ssklower case 1: /* set debug (obsolete) */
841*39729Ssklower case 2: /* set debug unit (obsolete) */
842*39729Ssklower error = EINVAL;
843*39729Ssklower break;
844*39729Ssklower
845*39729Ssklower /*
846*39729Ssklower * For both packet and window sizes, we check that the link
847*39729Ssklower * is currently down. The new parameters will be sent to the
848*39729Ssklower * FEP when the link is next brought up. See processing for
849*39729Ssklower * -u flag.
850*39729Ssklower */
851*39729Ssklower case 3: /* set packetsize */
852*39729Ssklower if (error = diags_completed(ds))
853*39729Ssklower goto exit;
854*39729Ssklower if (ds->dda_firmrev < 0x21) { /* need 2.1 or above ROMs */
855*39729Ssklower error = ENOPROTOOPT;
856*39729Ssklower goto exit;
857*39729Ssklower }
858*39729Ssklower if (ds->dda_state != S_DISABLED) { /* must bring link down */
859*39729Ssklower error = EINPROGRESS;
860*39729Ssklower goto exit;
861*39729Ssklower }
862*39729Ssklower
863*39729Ssklower /*
864*39729Ssklower * X.25 (1984) section 7.2.2.1.1 says 12 (4096 byte packets)
865*39729Ssklower * BBN report 5760 (September 1984) 14.2.1.2 says 10. We just
866*39729Ssklower * check for 12.
867*39729Ssklower */
868*39729Ssklower if (da->drval < 4 || da->drval > 12)
869*39729Ssklower error = EINVAL;
870*39729Ssklower else {
871*39729Ssklower int packetsize = 1 << da->drval;
872*39729Ssklower
873*39729Ssklower acpconfig_msg[MSG_LENGTH] = 3;
874*39729Ssklower acpconfig_msg[MSG_OFFSET] = MAX_PKT_SZ; /* Max negotiable */
875*39729Ssklower /* pkt size */
876*39729Ssklower acpconfig_msg[MSG_OFFSET + 1] = packetsize & 0xFF;
877*39729Ssklower acpconfig_msg[MSG_OFFSET + 2] = (packetsize >> 8) & 0xFF;
878*39729Ssklower send_config(ds, acpconfig_msg);
879*39729Ssklower }
880*39729Ssklower break;
881*39729Ssklower
882*39729Ssklower case 4: /* set windowsize */
883*39729Ssklower if (error = diags_completed(ds))
884*39729Ssklower goto exit;
885*39729Ssklower if (ds->dda_firmrev < 0x21) { /* need 2.0 or above ROMs */
886*39729Ssklower error = ENOPROTOOPT;
887*39729Ssklower goto exit;
888*39729Ssklower }
889*39729Ssklower if (ds->dda_state != S_DISABLED) { /* must bring link down */
890*39729Ssklower error = EINPROGRESS;
891*39729Ssklower goto exit;
892*39729Ssklower }
893*39729Ssklower if (da->drval < 1 || da->drval > 127)
894*39729Ssklower error = EINVAL;
895*39729Ssklower else {
896*39729Ssklower acpconfig_msg[MSG_LENGTH] = 2;
897*39729Ssklower acpconfig_msg[MSG_OFFSET] = MAX_PKT_WN; /* Max negotiable */
898*39729Ssklower /* pkt window */
899*39729Ssklower acpconfig_msg[MSG_OFFSET + 1] = da->drval;
900*39729Ssklower send_config(ds, acpconfig_msg);
901*39729Ssklower }
902*39729Ssklower break;
903*39729Ssklower }
904*39729Ssklower goto exit;
905*39729Ssklower
906*39729Ssklower case 'm': /* -m message */
907*39729Ssklower if (error = diags_completed(ds))
908*39729Ssklower goto exit;
909*39729Ssklower if (copyin(ifr->ifr_data, dda_iobuf, sizeof(struct ddactl))) {
910*39729Ssklower error = EFAULT;
911*39729Ssklower goto exit;
912*39729Ssklower }
913*39729Ssklower da = (struct ddactl *) dda_iobuf;
914*39729Ssklower send_config(ds, da->msg);
915*39729Ssklower goto exit;
916*39729Ssklower
917*39729Ssklower case 'n': /* -n svc_count */
918*39729Ssklower if (error = diags_completed(ds))
919*39729Ssklower goto exit;
920*39729Ssklower if (copyin(ifr->ifr_data, dda_iobuf, sizeof(struct ddactl))) {
921*39729Ssklower error = EFAULT;
922*39729Ssklower goto exit;
923*39729Ssklower }
924*39729Ssklower if (ds->dda_firmrev < 0x21) { /* need 2.1 or above ROMs */
925*39729Ssklower error = ENOPROTOOPT;
926*39729Ssklower goto exit;
927*39729Ssklower }
928*39729Ssklower da = (struct ddactl *) dda_iobuf;
929*39729Ssklower i = 0; /* i holds the return value */
930*39729Ssklower if (da->drval == 0)
931*39729Ssklower i = nddach[ifp->if_unit];
932*39729Ssklower else if (ds->dda_state != S_DISABLED) { /* must bring link down */
933*39729Ssklower error = EINPROGRESS;
934*39729Ssklower goto exit;
935*39729Ssklower } else {
936*39729Ssklower if (!suser()) {
937*39729Ssklower error = EACCES;
938*39729Ssklower goto exit;
939*39729Ssklower }
940*39729Ssklower if (da->drval < 1 || da->drval > NDDACH)
941*39729Ssklower error = EINVAL;
942*39729Ssklower else {
943*39729Ssklower acpconfig_msg[MSG_LENGTH] = 2;
944*39729Ssklower acpconfig_msg[MSG_OFFSET] = SVC_LIMIT;
945*39729Ssklower acpconfig_msg[MSG_OFFSET + 1] = da->drval;
946*39729Ssklower nddach[ifp->if_unit] = da->drval;
947*39729Ssklower send_config(ds, acpconfig_msg);
948*39729Ssklower }
949*39729Ssklower }
950*39729Ssklower if (copyout(&i, ifr->ifr_data, sizeof(int)))
951*39729Ssklower error = EFAULT;
952*39729Ssklower goto exit;
953*39729Ssklower
954*39729Ssklower case 'c': /* -c msgnum -- dis/enable driver mesg */
955*39729Ssklower if (copyin(ifr->ifr_data, dda_iobuf, sizeof(struct ddactl))) {
956*39729Ssklower error = EFAULT;
957*39729Ssklower goto exit;
958*39729Ssklower }
959*39729Ssklower da = (struct ddactl *) dda_iobuf;
960*39729Ssklower if (da->drval < 0 || da->drval >= MAXDMSGS)
961*39729Ssklower error = EINVAL;
962*39729Ssklower else {
963*39729Ssklower u_char new_val;
964*39729Ssklower
965*39729Ssklower DMESGTOG(ifp->if_unit, da->drval);
966*39729Ssklower new_val = DMESGVAL(ifp->if_unit, da->drval) ? 1 : 0;
967*39729Ssklower /* 1 means disabled, 0 means enabled */
968*39729Ssklower if (copyout(&new_val, ifr->ifr_data, sizeof(u_char)))
969*39729Ssklower error = EFAULT;
970*39729Ssklower }
971*39729Ssklower goto exit;
972*39729Ssklower
973*39729Ssklower case 't': /* -t sec -- set data idle timeout */
974*39729Ssklower if (copyin(ifr->ifr_data, dda_iobuf, sizeof(struct ddactl))) {
975*39729Ssklower error = EFAULT;
976*39729Ssklower goto exit;
977*39729Ssklower }
978*39729Ssklower da = (struct ddactl *) dda_iobuf;
979*39729Ssklower if (da->drval < 1)
980*39729Ssklower error = EINVAL;
981*39729Ssklower else
982*39729Ssklower tmo_data_idle = da->drval / DDA_TIMEOUT;
983*39729Ssklower goto exit;
984*39729Ssklower
985*39729Ssklower case 'q': /* driver/FE/shm/silo state queries */
986*39729Ssklower if (copyin(ifr->ifr_data, dda_iobuf, sizeof(struct ddactl))) {
987*39729Ssklower error = EFAULT;
988*39729Ssklower goto exit;
989*39729Ssklower }
990*39729Ssklower da = (struct ddactl *) dda_iobuf;
991*39729Ssklower switch (da->msg[0]) {
992*39729Ssklower case 0: /* front end state query */
993*39729Ssklower if ((error = diags_completed(ds)) == 0) {
994*39729Ssklower int s2 = splimp();
995*39729Ssklower
996*39729Ssklower /* need 2.0 or above ROMs */
997*39729Ssklower if (ds->dda_firmrev < 0x21) {
998*39729Ssklower error = ENOPROTOOPT;
999*39729Ssklower splx(s2); /* We got it and woke up */
1000*39729Ssklower break;
1001*39729Ssklower }
1002*39729Ssklower #ifdef MULTINET
1003*39729Ssklower StatQuery_Completed = 0;
1004*39729Ssklower send_supr(ds, STATQUERY, 0, 0);
1005*39729Ssklower splx(s2); /* drop ioctl so we can be scheduled */
1006*39729Ssklower while (!StatQuery_Completed);
1007*39729Ssklower #else MULTINET
1008*39729Ssklower send_supr(ds, STATQUERY, 0, 0);
1009*39729Ssklower sleep(dda_iobuf, PSLEP); /* Interruptible with ^C */
1010*39729Ssklower splx(s2); /* We got it and woke up */
1011*39729Ssklower #endif MULTINET
1012*39729Ssklower
1013*39729Ssklower if (copyout(dda_iobuf, ifr->ifr_data,
1014*39729Ssklower sizeof(struct ddactl)))
1015*39729Ssklower error = EFAULT;
1016*39729Ssklower }
1017*39729Ssklower break;
1018*39729Ssklower case 1: /* driver state query */
1019*39729Ssklower da->msg[0] = ds->dda_state;
1020*39729Ssklower da->msg[1] = ds->dda_init;
1021*39729Ssklower da->msg[2] = ds->dda_flags;
1022*39729Ssklower da->msg[3] = ds->dda_firmrev;
1023*39729Ssklower if (copyout(dda_iobuf, ifr->ifr_data,
1024*39729Ssklower sizeof(struct ddactl)))
1025*39729Ssklower error = EFAULT;
1026*39729Ssklower break;
1027*39729Ssklower #ifdef DDADEBUG
1028*39729Ssklower case 2: /* debug query */
1029*39729Ssklower if (copyout(dda_debug_silo, ifr->ifr_data, 256))
1030*39729Ssklower error = EFAULT;
1031*39729Ssklower break;
1032*39729Ssklower #endif
1033*39729Ssklower #if defined(DDADEBUG) && defined(ACP_BI)
1034*39729Ssklower case 3: /* shm/biic query (temporary) */
1035*39729Ssklower {
1036*39729Ssklower register struct uba_device *ui = ddainfo[ifp->if_unit];
1037*39729Ssklower dda_dump_shm((SYSGEN_BLOCK *) ds->dda_mapreg);
1038*39729Ssklower dda_dump_biic_regs((struct biic_regs *) ui->ui_addr);
1039*39729Ssklower }
1040*39729Ssklower break;
1041*39729Ssklower #endif
1042*39729Ssklower default:
1043*39729Ssklower error = EINVAL;
1044*39729Ssklower }
1045*39729Ssklower goto exit;
1046*39729Ssklower
1047*39729Ssklower case '0': /* -u 0 */
1048*39729Ssklower if (error = diags_completed(ds))
1049*39729Ssklower goto exit;
1050*39729Ssklower acpconfig_msg[MSG_OFFSET] = LINK_DISABLE;
1051*39729Ssklower acpconfig_msg[MSG_LENGTH] = 1;
1052*39729Ssklower hist_link_state(ifp->if_unit, ds->dda_state, S_GOING_DOWN);
1053*39729Ssklower ds->dda_state = S_GOING_DOWN;
1054*39729Ssklower break;
1055*39729Ssklower case '1': /* -u 1 */
1056*39729Ssklower if (error = diags_completed(ds))
1057*39729Ssklower goto exit;
1058*39729Ssklower acpconfig_msg[MSG_OFFSET] = LINK_LOOPBACK;
1059*39729Ssklower acpconfig_msg[MSG_OFFSET + 1] = LOOP_NONE;
1060*39729Ssklower acpconfig_msg[MSG_OFFSET + 2] = DTE_DCE_MODE;
1061*39729Ssklower acpconfig_msg[MSG_OFFSET + 3] = DTE;
1062*39729Ssklower acpconfig_msg[MSG_OFFSET + 4] = LINK_ENABLE;
1063*39729Ssklower acpconfig_msg[MSG_LENGTH] = 5;
1064*39729Ssklower ds->dda_state = S_COMING_UP;
1065*39729Ssklower hist_init(ifp->if_unit, 0);
1066*39729Ssklower break;
1067*39729Ssklower case '2': /* -u 2 */
1068*39729Ssklower if (error = diags_completed(ds))
1069*39729Ssklower goto exit;
1070*39729Ssklower acpconfig_msg[MSG_OFFSET] = LINK_LOOPBACK;
1071*39729Ssklower acpconfig_msg[MSG_OFFSET + 1] = LOOP_NONE;
1072*39729Ssklower acpconfig_msg[MSG_OFFSET + 2] = DTE_DCE_MODE;
1073*39729Ssklower acpconfig_msg[MSG_OFFSET + 3] = DCE;
1074*39729Ssklower acpconfig_msg[MSG_OFFSET + 4] = LINK_ENABLE;
1075*39729Ssklower acpconfig_msg[MSG_LENGTH] = 5;
1076*39729Ssklower ds->dda_state = S_COMING_UP;
1077*39729Ssklower hist_init(ifp->if_unit, 0);
1078*39729Ssklower break;
1079*39729Ssklower case '3': /* -u 3 */
1080*39729Ssklower if (error = diags_completed(ds))
1081*39729Ssklower goto exit;
1082*39729Ssklower acpconfig_msg[MSG_OFFSET] = LINK_LOOPBACK;
1083*39729Ssklower acpconfig_msg[MSG_OFFSET + 1] = LOOP_EXTERNAL;
1084*39729Ssklower acpconfig_msg[MSG_OFFSET + 2] = LINK_ENABLE;
1085*39729Ssklower acpconfig_msg[MSG_LENGTH] = 3;
1086*39729Ssklower ds->dda_state = S_COMING_UP;
1087*39729Ssklower hist_init(ifp->if_unit, 0);
1088*39729Ssklower break;
1089*39729Ssklower case '4': /* -u 4 */
1090*39729Ssklower if (error = diags_completed(ds))
1091*39729Ssklower goto exit;
1092*39729Ssklower acpconfig_msg[MSG_OFFSET] = LINK_LOOPBACK;
1093*39729Ssklower acpconfig_msg[MSG_OFFSET + 1] = LOOP_INTERNAL;
1094*39729Ssklower acpconfig_msg[MSG_OFFSET + 2] = LINK_ENABLE;
1095*39729Ssklower acpconfig_msg[MSG_LENGTH] = 3;
1096*39729Ssklower ds->dda_state = S_COMING_UP;
1097*39729Ssklower hist_init(ifp->if_unit, 0);
1098*39729Ssklower break;
1099*39729Ssklower case 'b': /* -b 0 */
1100*39729Ssklower if (error = diags_completed(ds))
1101*39729Ssklower goto exit;
1102*39729Ssklower acpconfig_msg[MSG_OFFSET] = CLOCK_CNTL;
1103*39729Ssklower acpconfig_msg[MSG_OFFSET + 1] = EXTERNAL_CLOCK;
1104*39729Ssklower acpconfig_msg[MSG_LENGTH] = 2;
1105*39729Ssklower ds->dda_init &= ~DDA_INTCLOCK;
1106*39729Ssklower break;
1107*39729Ssklower case 'S': /* select DDN standard X.25 service */
1108*39729Ssklower /* -s 0 or -s standard */
1109*39729Ssklower if (error = diags_completed(ds))
1110*39729Ssklower goto exit;
1111*39729Ssklower if (ds->dda_if.if_flags & IFF_UP && ds->dda_init & DDA_PDN) {
1112*39729Ssklower error = EALREADY;
1113*39729Ssklower goto exit; /* no PDN->DDN mode change if running */
1114*39729Ssklower }
1115*39729Ssklower ds->dda_init &= ~(DDA_BASIC | DDA_PDN);
1116*39729Ssklower ds->dda_init |= DDA_STANDARD;
1117*39729Ssklower goto exit;
1118*39729Ssklower case 'T': /* select DDN basic X.25 service */
1119*39729Ssklower /* -s 1 or -s basic */
1120*39729Ssklower if (error = diags_completed(ds))
1121*39729Ssklower goto exit;
1122*39729Ssklower if (ds->dda_if.if_flags & IFF_UP && ds->dda_init & DDA_PDN) {
1123*39729Ssklower error = EALREADY;
1124*39729Ssklower goto exit; /* no PDN->DDN mode change if running */
1125*39729Ssklower }
1126*39729Ssklower ds->dda_init &= ~(DDA_PDN | DDA_STANDARD);
1127*39729Ssklower ds->dda_init |= DDA_BASIC;
1128*39729Ssklower goto exit;
1129*39729Ssklower case 'U': /* select X.25 Public Data Network service */
1130*39729Ssklower /* -s 2 or -s pdn */
1131*39729Ssklower if (error = diags_completed(ds))
1132*39729Ssklower goto exit;
1133*39729Ssklower if (ds->dda_if.if_flags & IFF_UP && (ds->dda_init &
1134*39729Ssklower (DDA_BASIC | DDA_STANDARD))) {
1135*39729Ssklower error = EALREADY;
1136*39729Ssklower goto exit; /* no DDN->PDN mode change if running */
1137*39729Ssklower }
1138*39729Ssklower ds->dda_init &= ~(DDA_BASIC | DDA_STANDARD);
1139*39729Ssklower ds->dda_init |= DDA_PDN;
1140*39729Ssklower goto exit;
1141*39729Ssklower
1142*39729Ssklower case 'e': /* set buffer size */
1143*39729Ssklower /* -e size size is encoded in second byte */
1144*39729Ssklower if (error = diags_completed(ds))
1145*39729Ssklower goto exit;
1146*39729Ssklower
1147*39729Ssklower /*
1148*39729Ssklower * check to see if we have newer at least version 2.2 roms.
1149*39729Ssklower */
1150*39729Ssklower if (ds->dda_firmrev < 0x22) {
1151*39729Ssklower error = ENOPROTOOPT;
1152*39729Ssklower goto exit;
1153*39729Ssklower }
1154*39729Ssklower if (ds->dda_if.if_flags & IFF_UP) {
1155*39729Ssklower error = EALREADY;
1156*39729Ssklower goto exit; /* no PDN->DDN mode change if running */
1157*39729Ssklower }
1158*39729Ssklower bfr_size_msg[MSG_OFFSET] = ifr->ifr_data[1];
1159*39729Ssklower send_config(ds, bfr_size_msg);
1160*39729Ssklower bufreset(ifp->if_unit);
1161*39729Ssklower goto exit;
1162*39729Ssklower
1163*39729Ssklower #ifdef ACP_BI
1164*39729Ssklower case 'L':
1165*39729Ssklower { struct dda_dnload dl;
1166*39729Ssklower if (copyin(ifr->ifr_data, &dl, sizeof(struct dda_dnload))) {
1167*39729Ssklower error = EFAULT;
1168*39729Ssklower goto exit;
1169*39729Ssklower }
1170*39729Ssklower error = dda_dload(ifp->if_unit, &dl);
1171*39729Ssklower goto exit;
1172*39729Ssklower }
1173*39729Ssklower #endif
1174*39729Ssklower
1175*39729Ssklower #if defined(DDA_PADOPT) && defined(WINS)
1176*39729Ssklower case 'x': /* Preallocate UCBs for X29 -- VMS only */
1177*39729Ssklower printf("Preallocated %d PTYs for X29\n", prealloc_x29());
1178*39729Ssklower goto exit;
1179*39729Ssklower #endif
1180*39729Ssklower
1181*39729Ssklower case 'z': /* reset specified front-end device, -z */
1182*39729Ssklower /* second parm is supposed to be uban, but ddareset doesn't care about it */
1183*39729Ssklower ddareset(ifp->if_unit, 0);
1184*39729Ssklower goto exit;
1185*39729Ssklower default:
1186*39729Ssklower error = EINVAL;
1187*39729Ssklower goto exit;
1188*39729Ssklower }
1189*39729Ssklower if ((*(ifr->ifr_data) != '0') && (ds->dda_init & DDA_PDN) &&
1190*39729Ssklower #if ACC_BSD == 42 || ACC_ULTRIX == 12
1191*39729Ssklower (convert_ip_addr(sin->sin_addr, (u_char *) arg2, ds) == 0)
1192*39729Ssklower #else
1193*39729Ssklower (convert_ip_addr(ds->dda_ipaddr, (u_char *) arg2, ds) == 0)
1194*39729Ssklower #endif
1195*39729Ssklower ) {
1196*39729Ssklower error = EADDRNOTAVAIL;
1197*39729Ssklower goto exit;
1198*39729Ssklower }
1199*39729Ssklower send_config(ds, acpconfig_msg);
1200*39729Ssklower break;
1201*39729Ssklower
1202*39729Ssklower default:
1203*39729Ssklower error = EINVAL;
1204*39729Ssklower }
1205*39729Ssklower
1206*39729Ssklower exit:
1207*39729Ssklower #ifndef MULTINET
1208*39729Ssklower splx(s);
1209*39729Ssklower #endif
1210*39729Ssklower return (error);
1211*39729Ssklower }
1212*39729Ssklower
1213*39729Ssklower
1214*39729Ssklower /*@@%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
1215*39729Ssklower /*%% DDAOUTPUT() %%*/
1216*39729Ssklower /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
1217*39729Ssklower /* */
1218*39729Ssklower /* Purpose: */
1219*39729Ssklower /* */
1220*39729Ssklower /* This routine is called by the network software when it has an */
1221*39729Ssklower /* IP datagram to send out this interface. An attempt is made */
1222*39729Ssklower /* to find a LCN which has a virtual circuit open to the */
1223*39729Ssklower /* indicated host. If an LCN is found the packet is queued for */
1224*39729Ssklower /* output on that LCN. */
1225*39729Ssklower /* */
1226*39729Ssklower /* Call: ddaoutput(ifp, m0, dst) */
1227*39729Ssklower /* Arguments: ifp: locates the network interface, ifnet */
1228*39729Ssklower /* m0: locates an mbuf buffer */
1229*39729Ssklower /* dst: is the socket destination address */
1230*39729Ssklower /* Returns: 0 for success, or one of following nonzero */
1231*39729Ssklower /* error indications: */
1232*39729Ssklower /* ENETDOWN */
1233*39729Ssklower /* EAFNOSUPPORT */
1234*39729Ssklower /* ENOBUFS */
1235*39729Ssklower /* Called by: network software, address of this routine is */
1236*39729Ssklower /* defined in the dda_if network interface struct */
1237*39729Ssklower /* Calls to: DDALOG() */
1238*39729Ssklower /* m_freem() */
1239*39729Ssklower /* splimp() */
1240*39729Ssklower /* locate_x25_lcn() */
1241*39729Ssklower /* IF_QFULL() */
1242*39729Ssklower /* IF_DROP() */
1243*39729Ssklower /* splx() */
1244*39729Ssklower /* IF_ENQUEUE() */
1245*39729Ssklower /* dda_start() */
1246*39729Ssklower /* */
1247*39729Ssklower /*##%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
1248*39729Ssklower
1249*39729Ssklower ddaoutput(ifp, m0, dst)
1250*39729Ssklower struct ifnet *ifp;
1251*39729Ssklower struct mbuf *m0;
1252*39729Ssklower struct sockaddr_in *dst;
1253*39729Ssklower {
1254*39729Ssklower register struct mbuf *m = m0;
1255*39729Ssklower register struct dda_softc *ds = &dda_softc[ifp->if_unit];
1256*39729Ssklower register struct dda_cb *dc;
1257*39729Ssklower register struct ifqueue *oq;
1258*39729Ssklower struct mbuf *prev;
1259*39729Ssklower int s;
1260*39729Ssklower union imp_addr imp_addr;
1261*39729Ssklower
1262*39729Ssklower #ifdef DDADEBUG
1263*39729Ssklower if (DDADBCH(1, ifp->if_unit)) {
1264*39729Ssklower imp_addr.ip = dst->sin_addr;
1265*39729Ssklower DDALOG(LOG_DEBUG) "dda%d: ddaoutput: dst = %d.%d.%d.%d\n",
1266*39729Ssklower ifp->if_unit, imp_addr.imp.s_net, imp_addr.imp.s_host,
1267*39729Ssklower imp_addr.imp.s_lh, imp_addr.imp.s_impno DDAELOG;
1268*39729Ssklower }
1269*39729Ssklower #endif DDADEBUG
1270*39729Ssklower
1271*39729Ssklower if ((ds->dda_if.if_flags & IFF_UP) == 0)
1272*39729Ssklower return (ENETDOWN);
1273*39729Ssklower
1274*39729Ssklower switch (dst->sin_family) {
1275*39729Ssklower
1276*39729Ssklower #ifdef INET
1277*39729Ssklower case AF_INET:
1278*39729Ssklower break;
1279*39729Ssklower #endif INET
1280*39729Ssklower
1281*39729Ssklower default:
1282*39729Ssklower DMESG(ifp->if_unit, 2,
1283*39729Ssklower (DDALOG(LOG_ERR) "dda%d: can't handle af%d\n", ifp->if_unit,
1284*39729Ssklower dst->sin_family DDAELOG));
1285*39729Ssklower m_freem(m0);
1286*39729Ssklower return (EAFNOSUPPORT);
1287*39729Ssklower }
1288*39729Ssklower
1289*39729Ssklower #ifdef DDADEBUG
1290*39729Ssklower if (DDADBCH(2, ifp->if_unit)) {
1291*39729Ssklower imp_addr.ip = dst->sin_addr;
1292*39729Ssklower DDALOG(LOG_DEBUG) "dda%d: ddaoutput: dst = %d.%d.%d.%d\n",
1293*39729Ssklower ifp->if_unit, imp_addr.imp.s_net, imp_addr.imp.s_host,
1294*39729Ssklower imp_addr.imp.s_lh, imp_addr.imp.s_impno DDAELOG;
1295*39729Ssklower }
1296*39729Ssklower #endif DDADEBUG
1297*39729Ssklower
1298*39729Ssklower /* Mod to V1.5b ==> V1.5b1 */
1299*39729Ssklower /* In 4.3, the IP code may pass mbuf chains with 0-length mbufs */
1300*39729Ssklower /* This causes "transfer count = 0" messages and might even */
1301*39729Ssklower /* cause actual garbage data transmission if the mbuf is at the */
1302*39729Ssklower /* end of the chain (we don't think it ever will be, but one */
1303*39729Ssklower /* can't be too sure...so we scan the chain first). */
1304*39729Ssklower /* WE DO ASSUME that there is at least one nonempty mbuf! */
1305*39729Ssklower /* (ULTRIX: we don't know, but the code is at worst harmless) */
1306*39729Ssklower
1307*39729Ssklower while (m0->m_len == 0) {
1308*39729Ssklower m = m0;
1309*39729Ssklower m0 = m0->m_next;
1310*39729Ssklower m->m_next = 0;
1311*39729Ssklower m_freem(m);
1312*39729Ssklower }
1313*39729Ssklower /* Now we know the first mbuf (at m0) is not zero length */
1314*39729Ssklower prev = m0;
1315*39729Ssklower m = m0->m_next;
1316*39729Ssklower while (m) {
1317*39729Ssklower if (m->m_len == 0) {
1318*39729Ssklower prev->m_next = m->m_next;
1319*39729Ssklower m->m_next = 0;
1320*39729Ssklower m_freem(m);
1321*39729Ssklower m = prev->m_next;
1322*39729Ssklower } else {
1323*39729Ssklower prev = m;
1324*39729Ssklower m = m->m_next;
1325*39729Ssklower }
1326*39729Ssklower }
1327*39729Ssklower m = m0; /* reset m to beginning of modified chain */
1328*39729Ssklower
1329*39729Ssklower s = splimp(); /* disable interrrupts */
1330*39729Ssklower
1331*39729Ssklower /* try to find an LCN */
1332*39729Ssklower
1333*39729Ssklower if (dc = locate_x25_lcn(ds, dst->sin_addr)) { /* if found */
1334*39729Ssklower #ifdef DDADEBUG
1335*39729Ssklower if (DDADBCH(2, ifp->if_unit)) {
1336*39729Ssklower DDALOG(LOG_DEBUG) "dda%d: ddaoutput: lcn found = %d\n", ifp->if_unit,
1337*39729Ssklower dc->dc_lcn DDAELOG;
1338*39729Ssklower }
1339*39729Ssklower #endif DDADEBUG
1340*39729Ssklower oq = &(dc->dc_oq); /* point to output queue */
1341*39729Ssklower if (IF_QFULL(oq)) { /* if q full */
1342*39729Ssklower IF_DROP(oq); /* drop the data */
1343*39729Ssklower m_freem(m);
1344*39729Ssklower ds->dda_if.if_collisions++; /* for netstat display */
1345*39729Ssklower splx(s);
1346*39729Ssklower return (ENOBUFS);
1347*39729Ssklower }
1348*39729Ssklower IF_ENQUEUE(oq, m); /* otherwise queue it */
1349*39729Ssklower dda_start(ds, dc); /* and try to output */
1350*39729Ssklower splx(s);
1351*39729Ssklower return (0);
1352*39729Ssklower } else { /* if no circuit available */
1353*39729Ssklower IF_DROP(&ifp->if_snd); /* drop the data */
1354*39729Ssklower m_freem(m);
1355*39729Ssklower splx(s);
1356*39729Ssklower return (EHOSTUNREACH);
1357*39729Ssklower }
1358*39729Ssklower
1359*39729Ssklower }
1360*39729Ssklower
1361*39729Ssklower
1362*39729Ssklower
1363*39729Ssklower /*@@%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
1364*39729Ssklower /*%% DDATIMER() %%*/
1365*39729Ssklower /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
1366*39729Ssklower /* */
1367*39729Ssklower /* Purpose: */
1368*39729Ssklower /* */
1369*39729Ssklower /* This routine is entered to perform timer management. The */
1370*39729Ssklower /* LCN table is scanned for active timers (nonzero) which are */
1371*39729Ssklower /* decremented. If a timer expires (becomes zero), the proper */
1372*39729Ssklower /* action is taken. */
1373*39729Ssklower /* */
1374*39729Ssklower /* */
1375*39729Ssklower /* Call: ddatimer(unit) */
1376*39729Ssklower /* Arguments: unit: ACP device unit number */
1377*39729Ssklower /* Returns: nothing */
1378*39729Ssklower /* Called by: ddainit() */
1379*39729Ssklower /* Calls to: splimp() */
1380*39729Ssklower /* send_restart() */
1381*39729Ssklower /* clear_lcn() */
1382*39729Ssklower /* splx() */
1383*39729Ssklower /* */
1384*39729Ssklower /*##%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
1385*39729Ssklower
1386*39729Ssklower int
ddatimer(unit)1387*39729Ssklower ddatimer(unit)
1388*39729Ssklower int unit;
1389*39729Ssklower {
1390*39729Ssklower register struct dda_softc *ds = &dda_softc[unit];
1391*39729Ssklower register struct dda_cb *dc;
1392*39729Ssklower register int s, lcn;
1393*39729Ssklower
1394*39729Ssklower #ifdef DDADEBUG
1395*39729Ssklower if (DDADBCH(3, unit)) {
1396*39729Ssklower DDALOG(LOG_DEBUG) "dda%d: ddatimer()\n", unit DDAELOG;
1397*39729Ssklower }
1398*39729Ssklower #endif DDADEBUG
1399*39729Ssklower
1400*39729Ssklower ds->dda_if.if_timer = DDA_TIMEOUT; /* restart timer */
1401*39729Ssklower
1402*39729Ssklower dc = ds->dda_cb;
1403*39729Ssklower
1404*39729Ssklower s = splimp();
1405*39729Ssklower
1406*39729Ssklower /* LCNLINK */
1407*39729Ssklower for (lcn = 0; lcn <= nddach[unit]; lcn++) { /* scan all LCN's */
1408*39729Ssklower #ifdef DDADEBUG
1409*39729Ssklower if (dc->dc_out_t && lcn > 0 && (--(dc->dc_out_t) == 0)) {
1410*39729Ssklower DDALOG(LOG_DEBUG) "dda%d: write completion timeout lcn %d\n",
1411*39729Ssklower unit, lcn DDAELOG;
1412*39729Ssklower }
1413*39729Ssklower #endif
1414*39729Ssklower if (dc->dc_timer && (--(dc->dc_timer) == 0)) { /* if a timer expired */
1415*39729Ssklower if (dc->dc_state == LC_RESTART) { /* if a restart was out */
1416*39729Ssklower send_restart(ds); /* send another one */
1417*39729Ssklower break;
1418*39729Ssklower } else { /* otherwise */
1419*39729Ssklower #ifdef DDA_PAD_OR_RAW
1420*39729Ssklower /* if it is not an X.29 connection */
1421*39729Ssklower if ((dc->dc_flags & (DC_X29W | DC_X29 | DC_RAW)) == 0)
1422*39729Ssklower #endif
1423*39729Ssklower clear_lcn(ds, dc); /* clear the LCN */
1424*39729Ssklower }
1425*39729Ssklower }
1426*39729Ssklower dc++;
1427*39729Ssklower }
1428*39729Ssklower splx(s);
1429*39729Ssklower }
1430*39729Ssklower
1431*39729Ssklower
1432*39729Ssklower /*@@%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
1433*39729Ssklower /*%% DIAGS_COMPLETED() %%*/
1434*39729Ssklower /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
1435*39729Ssklower /* */
1436*39729Ssklower /* Purpose: */
1437*39729Ssklower /* */
1438*39729Ssklower /* This routine checks to see that power up diagnostics have completed*/
1439*39729Ssklower /* It waits for a while if necessary. */
1440*39729Ssklower /* Call: diags_completed(ds) */
1441*39729Ssklower /* Argument: ds - pointer to softc structure; */
1442*39729Ssklower /* Returns: 0 if board is up, EINTR if it never came on line. */
1443*39729Ssklower /* Called by: ddaioctl() */
1444*39729Ssklower /* Calls to: */
1445*39729Ssklower /* */
1446*39729Ssklower /*##%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
1447*39729Ssklower
1448*39729Ssklower diags_completed(ds)
1449*39729Ssklower struct dda_softc *ds;
1450*39729Ssklower {
1451*39729Ssklower int nretries = 10;
1452*39729Ssklower
1453*39729Ssklower /*
1454*39729Ssklower * It's overkill to check this on EVERY ioctl, because it only matters if
1455*39729Ssklower * we are going to touch the board. But the driver has had repeated
1456*39729Ssklower * problems with not checking it when it should have - overkill is
1457*39729Ssklower * preferred. The delays are here rather then in the acpconfig program
1458*39729Ssklower * due to a bug in acpconfig. They will only be executed during
1459*39729Ssklower * /etc/rc.local when the board has not had a chance to do the "B"
1460*39729Ssklower * interrupt yet. At that time the machine will be running essentially
1461*39729Ssklower * single thread so it won't really matter where the delays are. (ie, if
1462*39729Ssklower * we put the delay into acpconfig and kept calling here 10 times, the
1463*39729Ssklower * machine would not do anything else useful in the meantime - might as
1464*39729Ssklower * well loop here).
1465*39729Ssklower */
1466*39729Ssklower while (((ds->dda_flags & DDAF_OK) == 0) && nretries-- > 0)
1467*39729Ssklower DELAY(3000000);
1468*39729Ssklower if ((ds->dda_flags & DDAF_OK) == 0) /* never came on line... */
1469*39729Ssklower return (EINTR);
1470*39729Ssklower else
1471*39729Ssklower return (0);
1472*39729Ssklower }
1473*39729Ssklower
1474*39729Ssklower
1475*39729Ssklower
1476*39729Ssklower /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
1477*39729Ssklower /*%% %%*/
1478*39729Ssklower /*%% LOCAL FUNCTIONS %%*/
1479*39729Ssklower /*%% %%*/
1480*39729Ssklower /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
1481*39729Ssklower
1482*39729Ssklower /*@@%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
1483*39729Ssklower /*%% SEND_CONFIG() %%*/
1484*39729Ssklower /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
1485*39729Ssklower /* */
1486*39729Ssklower /* Purpose: */
1487*39729Ssklower /* */
1488*39729Ssklower /* Send a Set System Parameters Message to the front end in */
1489*39729Ssklower /* response to an ACPCONFIG command from the user. */
1490*39729Ssklower /* */
1491*39729Ssklower /* Call: send_config(ds, p) */
1492*39729Ssklower /* Argument: ds: pointer to ACP device control structure */
1493*39729Ssklower /* p: pointer to the message */
1494*39729Ssklower /* Returns: nothing */
1495*39729Ssklower /* Called by: ddaioctl() */
1496*39729Ssklower /* Calls to: MGET() */
1497*39729Ssklower /* DDALOG() */
1498*39729Ssklower /* mtod() */
1499*39729Ssklower /* bcopy() */
1500*39729Ssklower /* sizeof() */
1501*39729Ssklower /* start_supr() */
1502*39729Ssklower /* */
1503*39729Ssklower /*##%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
1504*39729Ssklower
1505*39729Ssklower PRIVATE void
send_config(ds,p)1506*39729Ssklower send_config(ds, p)
1507*39729Ssklower struct dda_softc *ds;
1508*39729Ssklower u_char *p;
1509*39729Ssklower {
1510*39729Ssklower struct mbuf *m;
1511*39729Ssklower register u_char *bp;
1512*39729Ssklower int length;
1513*39729Ssklower
1514*39729Ssklower #ifdef DDADEBUG
1515*39729Ssklower if (DDADBCH(7, ds->dda_if.if_unit)) {
1516*39729Ssklower DDALOG(LOG_DEBUG) "dda%d: send_config()\n", ds->dda_if.if_unit DDAELOG;
1517*39729Ssklower }
1518*39729Ssklower #endif DDADEBUG
1519*39729Ssklower
1520*39729Ssklower MGET(m, M_DONTWAIT, MT_DATA);
1521*39729Ssklower if (m == 0) {
1522*39729Ssklower DMESG(ds->dda_if.if_unit, 18,
1523*39729Ssklower (DDALOG(LOG_ERR) "dda%d: can't get bfr for acpconfig msg\n",
1524*39729Ssklower ds->dda_if.if_unit DDAELOG));
1525*39729Ssklower return;
1526*39729Ssklower }
1527*39729Ssklower bp = mtod(m, u_char *); /* point to data section of mbuf */
1528*39729Ssklower
1529*39729Ssklower length = p[MSG_LENGTH] + MSG_OFFSET; /* msg length */
1530*39729Ssklower if (length > MLEN - 1) {
1531*39729Ssklower
1532*39729Ssklower /*
1533*39729Ssklower * Supervisory messages have to fit in a small mbuf. The driver
1534*39729Ssklower * itself is careful never to get in trouble this way, but now that
1535*39729Ssklower * we have "-m" the user could. Dropping such a message is not
1536*39729Ssklower * likely to cause any big problems, and the user can rephrase the
1537*39729Ssklower * request.
1538*39729Ssklower */
1539*39729Ssklower DMESG(ds->dda_if.if_unit, 19,
1540*39729Ssklower (DDALOG(LOG_ERR) "dda%d: supervisor message too long\n",
1541*39729Ssklower ds->dda_if.if_unit DDAELOG));
1542*39729Ssklower m->m_next = 0;
1543*39729Ssklower m_freem(m);
1544*39729Ssklower return;
1545*39729Ssklower }
1546*39729Ssklower bcopy(p, bp, length);
1547*39729Ssklower m->m_len = length; /* set msg length */
1548*39729Ssklower
1549*39729Ssklower #ifdef DDADEBUG
1550*39729Ssklower if (DDADBCH(8, ds->dda_if.if_unit)) {
1551*39729Ssklower prt_bytes(ds->dda_if.if_unit, "send_config", bp, length);
1552*39729Ssklower }
1553*39729Ssklower #endif DDADEBUG
1554*39729Ssklower
1555*39729Ssklower start_supr(ds, m);
1556*39729Ssklower }
1557*39729Ssklower
1558*39729Ssklower
1559*39729Ssklower
1560*39729Ssklower /*@@%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
1561*39729Ssklower /*%% LOCATE_X25_LCN() %%*/
1562*39729Ssklower /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
1563*39729Ssklower /* */
1564*39729Ssklower /* Purpose: */
1565*39729Ssklower /* */
1566*39729Ssklower /* This routine tries to locate an X25 LCN associated with a */
1567*39729Ssklower /* remote internet address. A linear search of the LCN table */
1568*39729Ssklower /* is made for a matching address. If the search succeeds, the */
1569*39729Ssklower /* LCN is returned. If the search fails, the LCN table is */
1570*39729Ssklower /* searched for an unused table entry. If an unused table */
1571*39729Ssklower /* entry is found, an X25 call is generated to the host */
1572*39729Ssklower /* specified in the destination internet address. If no LCN is */
1573*39729Ssklower /* available, zero is returned. */
1574*39729Ssklower /* */
1575*39729Ssklower /* Call: locate_x25_lcn(ds, ip_addr) */
1576*39729Ssklower /* Argument: ds: pointer to dev control block struct */
1577*39729Ssklower /* ip_addr: IP address */
1578*39729Ssklower /* Returns: pointer to the dda control block which */
1579*39729Ssklower /* contains LCN, else zero for failure */
1580*39729Ssklower /* Called by: ddaoutput() */
1581*39729Ssklower /* Calls to: convert_ip_addr() */
1582*39729Ssklower /* make_x25_call() */
1583*39729Ssklower /* */
1584*39729Ssklower /*##%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
1585*39729Ssklower
1586*39729Ssklower PRIVATE struct dda_cb *
locate_x25_lcn(ds,ip_addr)1587*39729Ssklower locate_x25_lcn(ds, ip_addr)
1588*39729Ssklower struct dda_softc *ds;
1589*39729Ssklower struct in_addr ip_addr;
1590*39729Ssklower {
1591*39729Ssklower register int lcn, maxlcn;
1592*39729Ssklower register struct dda_cb *dc;
1593*39729Ssklower union imp_addr imp_addr;
1594*39729Ssklower
1595*39729Ssklower #ifdef DDADEBUG
1596*39729Ssklower if (DDADBCH(9, ds->dda_if.if_unit)) {
1597*39729Ssklower DDALOG(LOG_DEBUG) "dda%d: locate_x25_lcn()\n",
1598*39729Ssklower ds->dda_if.if_unit DDAELOG;
1599*39729Ssklower }
1600*39729Ssklower #endif DDADEBUG
1601*39729Ssklower
1602*39729Ssklower imp_addr.ip = ip_addr; /* DDN X.25 doesn't know net number */
1603*39729Ssklower
1604*39729Ssklower if (!(ds->dda_init & DDA_PDN)) {
1605*39729Ssklower if ((imp_addr.imp.s_net & 0x80) == 0x00) { /* class A */
1606*39729Ssklower imp_addr.imp.s_net = 0;
1607*39729Ssklower imp_addr.imp.s_lh = 0;
1608*39729Ssklower } else if ((imp_addr.imp.s_net & 0xc0) == 0x80) { /* class B */
1609*39729Ssklower imp_addr.imp.s_net = 0;
1610*39729Ssklower imp_addr.imp.s_host = 0;
1611*39729Ssklower } else { /* class C, should check for class C */
1612*39729Ssklower imp_addr.imp.s_net = 0;
1613*39729Ssklower imp_addr.imp.s_host = 0;
1614*39729Ssklower imp_addr.imp.s_lh = 0;
1615*39729Ssklower }
1616*39729Ssklower }
1617*39729Ssklower /* LCNLINK */
1618*39729Ssklower maxlcn = nddach[ds->dda_if.if_unit];
1619*39729Ssklower dc = &(ds->dda_cb[1]); /* scan LCN table for addr match */
1620*39729Ssklower for (lcn = 1; lcn <= maxlcn; lcn++) {
1621*39729Ssklower if ((dc->dc_key.key_addr.s_addr == imp_addr.ip.s_addr)
1622*39729Ssklower && (dc->dc_state == LC_CALL_PENDING || dc->dc_state == LC_DATA_IDLE))
1623*39729Ssklower return (dc); /* return LCN */
1624*39729Ssklower dc++;
1625*39729Ssklower }
1626*39729Ssklower
1627*39729Ssklower if ((dc = find_free_lcn(ds)) == 0)
1628*39729Ssklower return (0);
1629*39729Ssklower
1630*39729Ssklower ddacb_user_data[0] = (u_char) 0; /* we have no user data */
1631*39729Ssklower
1632*39729Ssklower if (convert_ip_addr(ip_addr, ddacb_called_addr, ds)
1633*39729Ssklower && make_x25_call(ds, dc, ip_addr, X25_PROTO_IP)) {
1634*39729Ssklower /* addr can be converted */
1635*39729Ssklower dc->dc_inaddr = ip_addr; /* store dest ip addr */
1636*39729Ssklower dc->dc_key.key_addr.s_addr = imp_addr.ip.s_addr;
1637*39729Ssklower /* store match key */
1638*39729Ssklower #ifdef DDADEBUG
1639*39729Ssklower if (DDADBCH(9, ds->dda_if.if_unit)) {
1640*39729Ssklower imp_addr.ip = ip_addr;
1641*39729Ssklower DDALOG(LOG_DEBUG)
1642*39729Ssklower "dda%d: locate_x25_lcn: made call to %d.%d.%d.%d\n",
1643*39729Ssklower ds->dda_if.if_unit, imp_addr.imp.s_net, imp_addr.imp.s_host,
1644*39729Ssklower imp_addr.imp.s_lh, imp_addr.imp.s_impno DDAELOG;
1645*39729Ssklower
1646*39729Ssklower }
1647*39729Ssklower #endif DDADEBUG
1648*39729Ssklower return (dc); /* and return the LCN */
1649*39729Ssklower } else {
1650*39729Ssklower return (0); /* give up */
1651*39729Ssklower }
1652*39729Ssklower }
1653*39729Ssklower
1654*39729Ssklower
1655*39729Ssklower
1656*39729Ssklower /*@@%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
1657*39729Ssklower /*%% FIND_FREE_LCN() %%*/
1658*39729Ssklower /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
1659*39729Ssklower /* */
1660*39729Ssklower /* Purpose: */
1661*39729Ssklower /* */
1662*39729Ssklower /* This routine tries to locate a free X25 LCN. */
1663*39729Ssklower /* The LCN table is searched for an unused entry. */
1664*39729Ssklower /* If no LCN is available, zero is returned. */
1665*39729Ssklower /* */
1666*39729Ssklower /* Call: find_free_lcn(ds) */
1667*39729Ssklower /* Argument: ds: pointer to dev control block struct */
1668*39729Ssklower /* Returns: pointer to the dda control block which */
1669*39729Ssklower /* contains LCN, else zero for failure */
1670*39729Ssklower /* Called by: locate_x25_lcn() */
1671*39729Ssklower /* supr_msg() */
1672*39729Ssklower /* xxcntl() */
1673*39729Ssklower /* Calls to: DDALOG() */
1674*39729Ssklower /* */
1675*39729Ssklower /*##%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
1676*39729Ssklower
1677*39729Ssklower PRIVATE struct dda_cb *
find_free_lcn(ds)1678*39729Ssklower find_free_lcn(ds)
1679*39729Ssklower struct dda_softc *ds;
1680*39729Ssklower {
1681*39729Ssklower struct dda_cb *dc;
1682*39729Ssklower register int lcn, maxlcn, dwnflg = 0;
1683*39729Ssklower
1684*39729Ssklower /* LCNLINK */
1685*39729Ssklower dc = &(ds->dda_cb[1]); /* scan LCN table for free entry */
1686*39729Ssklower maxlcn = nddach[ds->dda_if.if_unit];
1687*39729Ssklower for (lcn = 1; lcn <= maxlcn; lcn++) {
1688*39729Ssklower #ifdef DDA_PAD_OR_RAW
1689*39729Ssklower if (dc->dc_state == LC_IDLE && (dc->dc_flags & (DC_X29W | DC_X29 | DC_RAW)) == 0)
1690*39729Ssklower #else
1691*39729Ssklower if (dc->dc_state == LC_IDLE)
1692*39729Ssklower #endif DDA_PAD_OR_RAW
1693*39729Ssklower break;
1694*39729Ssklower else if (dc->dc_state == LC_RESTART || dc->dc_state == LC_DOWN)
1695*39729Ssklower dwnflg = 1;
1696*39729Ssklower dc++;
1697*39729Ssklower }
1698*39729Ssklower
1699*39729Ssklower /* LCNLINK */
1700*39729Ssklower if (lcn > maxlcn) { /* if we didn't find a free entry */
1701*39729Ssklower if (LOG_BUSY) {
1702*39729Ssklower if (dwnflg)
1703*39729Ssklower DDALOG(LOG_ERR) "dda%d: no circuits available (link not up)\n",
1704*39729Ssklower ds->dda_if.if_unit DDAELOG;
1705*39729Ssklower else
1706*39729Ssklower DDALOG(LOG_ERR) "dda%d: all circuits in use\n",
1707*39729Ssklower ds->dda_if.if_unit DDAELOG;
1708*39729Ssklower }
1709*39729Ssklower return (0); /* return empty handed */
1710*39729Ssklower }
1711*39729Ssklower return (dc);
1712*39729Ssklower }
1713*39729Ssklower
1714*39729Ssklower
1715*39729Ssklower
1716*39729Ssklower /*@@%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
1717*39729Ssklower /*%% CONVERT_IP_ADDR() %%*/
1718*39729Ssklower /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
1719*39729Ssklower /* */
1720*39729Ssklower /* Purpose: */
1721*39729Ssklower /* */
1722*39729Ssklower /* Based on the type of X.25 service, this routine performs */
1723*39729Ssklower /* one of two functions. For PDN X.25 service, the address */
1724*39729Ssklower /* translation table is searched for presence of local X.25 */
1725*39729Ssklower /* address (which was entered by the user via acpconfig). */
1726*39729Ssklower /* */
1727*39729Ssklower /* For DDN X.25 service, this routine accepts an internet */
1728*39729Ssklower /* address and attempts to translate to an equivalent X25 */
1729*39729Ssklower /* address. This follows the guidelines in the DDN X25 */
1730*39729Ssklower /* interface spec. The resultant X25 address is stored in the */
1731*39729Ssklower /* X25 called addr buffer. */
1732*39729Ssklower /* */
1733*39729Ssklower /* NOTE: Although front end was designed to accept ASCII coded */
1734*39729Ssklower /* digits for the address fields, we only supply the binary */
1735*39729Ssklower /* values. The front end only uses low four bits to extract */
1736*39729Ssklower /* the binary value from the ASCII digits, so this works out. */
1737*39729Ssklower /* */
1738*39729Ssklower /* */
1739*39729Ssklower /* */
1740*39729Ssklower /* */
1741*39729Ssklower /* */
1742*39729Ssklower /* */
1743*39729Ssklower /* Call: convert_ip_addr(ip_addr, x25addr, ds) */
1744*39729Ssklower /* Argument: ip_addr: IP address */
1745*39729Ssklower /* x25addr: X.25 address */
1746*39729Ssklower /* ds: &dda_softc[unit] */
1747*39729Ssklower /* Returns: 1 for success */
1748*39729Ssklower /* Called by: locate_x25_lcn() */
1749*39729Ssklower /* make_x25_call() */
1750*39729Ssklower /* ddaioctl() */
1751*39729Ssklower /* Calls to: bcopy() */
1752*39729Ssklower /* */
1753*39729Ssklower /*##%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
1754*39729Ssklower
1755*39729Ssklower PRIVATE boolean
convert_ip_addr(ip_addr,x25addr,ds)1756*39729Ssklower convert_ip_addr(ip_addr, x25addr, ds)
1757*39729Ssklower struct in_addr ip_addr;
1758*39729Ssklower u_char x25addr[];
1759*39729Ssklower struct dda_softc *ds;
1760*39729Ssklower
1761*39729Ssklower {
1762*39729Ssklower register struct dda_addr_tr *atp, *hip, *lop;
1763*39729Ssklower register int temp;
1764*39729Ssklower union imp_addr imp_addr;
1765*39729Ssklower
1766*39729Ssklower /****************************************************************/
1767*39729Ssklower /* processing for Public Data Network (PDN) X.25 service */
1768*39729Ssklower /* search address translation table for local address */
1769*39729Ssklower /****************************************************************/
1770*39729Ssklower
1771*39729Ssklower if (ds->dda_init & DDA_PDN) {
1772*39729Ssklower x25addr[0] = 0; /* clear result X.25 address length */
1773*39729Ssklower lop = &dda_addr_tr[ds->dda_if.if_unit][0]; /* set up for binary
1774*39729Ssklower * search */
1775*39729Ssklower hip = &dda_addr_tr[ds->dda_if.if_unit][dda_num_addr_tr[ds->dda_if.if_unit]];
1776*39729Ssklower while (lop < hip - 1) { /* binary search loop */
1777*39729Ssklower atp = lop + (hip - lop) / 2;
1778*39729Ssklower if (atp->ip_addr > ip_addr.s_addr)
1779*39729Ssklower hip = atp;
1780*39729Ssklower else
1781*39729Ssklower lop = atp;
1782*39729Ssklower }
1783*39729Ssklower if (lop->ip_addr == ip_addr.s_addr)
1784*39729Ssklower bcopy(lop->x25_addr, x25addr, MAXADDRLEN);
1785*39729Ssklower }
1786*39729Ssklower /****************************************************************/
1787*39729Ssklower /* processing for DDN Standard or Basic X.25 service */
1788*39729Ssklower /* convert IP address to X.25 address */
1789*39729Ssklower /****************************************************************/
1790*39729Ssklower
1791*39729Ssklower else {
1792*39729Ssklower int imp_no, imp_port;
1793*39729Ssklower
1794*39729Ssklower
1795*39729Ssklower imp_addr.ip = ip_addr;
1796*39729Ssklower if ((imp_addr.imp.s_net & 0x80) == 0x00) { /* class A */
1797*39729Ssklower imp_no = imp_addr.imp.s_impno;
1798*39729Ssklower imp_port = imp_addr.imp.s_host;
1799*39729Ssklower } else if ((imp_addr.imp.s_net & 0xc0) == 0x80) { /* class B */
1800*39729Ssklower imp_no = imp_addr.imp.s_impno;
1801*39729Ssklower imp_port = imp_addr.imp.s_lh;
1802*39729Ssklower } else { /* class C */
1803*39729Ssklower imp_no = imp_addr.imp.s_impno / 32;
1804*39729Ssklower imp_port = imp_addr.imp.s_impno % 32;
1805*39729Ssklower }
1806*39729Ssklower
1807*39729Ssklower x25addr[0] = 12; /* set addr length */
1808*39729Ssklower x25addr[1] = 0; /* clear DNIC */
1809*39729Ssklower x25addr[2] = 0;
1810*39729Ssklower x25addr[3] = 0;
1811*39729Ssklower x25addr[4] = 0;
1812*39729Ssklower
1813*39729Ssklower if (imp_port < 64) { /* Physical: 0000 0 IIIHH00 [SS] *//* s_impno
1814*39729Ssklower * -> III, s_host -> HH */
1815*39729Ssklower x25addr[5] = 0; /* set flag bit */
1816*39729Ssklower x25addr[6] = imp_no / 100;
1817*39729Ssklower x25addr[7] = (imp_no % 100) / 10;
1818*39729Ssklower x25addr[8] = imp_no % 10;
1819*39729Ssklower x25addr[9] = imp_port / 10;
1820*39729Ssklower x25addr[10] = imp_port % 10;
1821*39729Ssklower } else { /* Logical: 0000 1 RRRRR00 [SS] *//* s
1822*39729Ssklower * _host * 256 + s_impno -> RRRRR */
1823*39729Ssklower temp = (imp_port << 8) + imp_no;
1824*39729Ssklower x25addr[5] = 1;
1825*39729Ssklower x25addr[6] = temp / 10000;
1826*39729Ssklower x25addr[7] = (temp % 10000) / 1000;
1827*39729Ssklower x25addr[8] = (temp % 1000) / 100;
1828*39729Ssklower x25addr[9] = (temp % 100) / 10;
1829*39729Ssklower x25addr[10] = temp % 10;
1830*39729Ssklower }
1831*39729Ssklower
1832*39729Ssklower x25addr[11] = 0; /* clear rest of addr */
1833*39729Ssklower x25addr[12] = 0;
1834*39729Ssklower }
1835*39729Ssklower
1836*39729Ssklower #ifdef DDADEBUG
1837*39729Ssklower if (DDADBCH(11, ds->dda_if.if_unit)) {
1838*39729Ssklower imp_addr.ip = ip_addr;
1839*39729Ssklower DDALOG(LOG_DEBUG) "dda%d: convert_ip_addr: %d.%d.%d.%d ==> %s\n",
1840*39729Ssklower ds->dda_if.if_unit, imp_addr.imp.s_net, imp_addr.imp.s_host,
1841*39729Ssklower imp_addr.imp.s_lh, imp_addr.imp.s_impno,
1842*39729Ssklower fmt_x25(&x25addr[1], (int) x25addr[0]) DDAELOG;
1843*39729Ssklower }
1844*39729Ssklower #endif DDADEBUG
1845*39729Ssklower
1846*39729Ssklower return (x25addr[0] ? 1 : 0);
1847*39729Ssklower }
1848*39729Ssklower
1849*39729Ssklower
1850*39729Ssklower
1851*39729Ssklower
1852*39729Ssklower /*@@%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
1853*39729Ssklower /*%% CONVERT_X25_ADDR() %%*/
1854*39729Ssklower /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
1855*39729Ssklower /* */
1856*39729Ssklower /* Purpose: */
1857*39729Ssklower /* */
1858*39729Ssklower /* This routine accepts an X25 address and attempts to */
1859*39729Ssklower /* translate to an equivalent internet address. For DDA this */
1860*39729Ssklower /* follows the guidelines in the DDA X25 interface spec. The */
1861*39729Ssklower /* resultant internet address is returned to the caller. */
1862*39729Ssklower /* */
1863*39729Ssklower /* Call: convert_x25_addr(x25addr, ds) */
1864*39729Ssklower /* Argument: x25addr: X.25 address */
1865*39729Ssklower /* ds: &dda_softc[unit] */
1866*39729Ssklower /* dc: pointer to allocated dda_cb structure */
1867*39729Ssklower /* Returns: IP address for success, else zero for fail */
1868*39729Ssklower /* Called by: supr_msg() */
1869*39729Ssklower /* Calls to: DDALOG() */
1870*39729Ssklower /* */
1871*39729Ssklower /*##%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
1872*39729Ssklower
1873*39729Ssklower PRIVATE u_long
convert_x25_addr(x25addr,ds,dc)1874*39729Ssklower convert_x25_addr(x25addr, ds, dc)
1875*39729Ssklower u_char x25addr[];
1876*39729Ssklower struct dda_softc *ds;
1877*39729Ssklower struct dda_cb *dc;
1878*39729Ssklower
1879*39729Ssklower {
1880*39729Ssklower register int cnt, temp;
1881*39729Ssklower union imp_addr imp_addr;
1882*39729Ssklower register struct dda_addr_tr *atp;
1883*39729Ssklower
1884*39729Ssklower dc->dc_inaddr.s_addr = imp_addr.ip.s_addr = 0L;
1885*39729Ssklower if (ds->dda_init & DDA_PDN) {
1886*39729Ssklower for (atp = &dda_addr_tr[ds->dda_if.if_unit][0];
1887*39729Ssklower atp < &dda_addr_tr[ds->dda_if.if_unit][dda_num_addr_tr[ds->dda_if.if_unit]]; atp++) {
1888*39729Ssklower if (bcmp((char *) atp->x25_addr, (char *) x25addr, x25addr[0] + 1) == 0) {
1889*39729Ssklower /* set key address and print address up */
1890*39729Ssklower dc->dc_inaddr.s_addr = imp_addr.ip.s_addr = atp->ip_addr;
1891*39729Ssklower break;
1892*39729Ssklower }
1893*39729Ssklower }
1894*39729Ssklower } else {
1895*39729Ssklower int imp_no, imp_port;
1896*39729Ssklower struct in_addr my_addr;
1897*39729Ssklower
1898*39729Ssklower my_addr = ds->dda_ipaddr;
1899*39729Ssklower if (((cnt = x25addr[0]) < MINADDRLEN - 1) || (cnt > MAXADDRLEN - 1)) {
1900*39729Ssklower DMESG(ds->dda_if.if_unit, 20,
1901*39729Ssklower (DDALOG(LOG_ERR) "dda%d: illegal X25 address length!\n",
1902*39729Ssklower ds->dda_if.if_unit DDAELOG));
1903*39729Ssklower return (0L);
1904*39729Ssklower }
1905*39729Ssklower switch (x25addr[5] & 0x0f) {
1906*39729Ssklower case 0: /* Physical: 0000 0 IIIHH00 [SS] */
1907*39729Ssklower imp_no =
1908*39729Ssklower ((int) (x25addr[6] & 0x0f) * 100) +
1909*39729Ssklower ((int) (x25addr[7] & 0x0f) * 10) +
1910*39729Ssklower ((int) (x25addr[8] & 0x0f));
1911*39729Ssklower
1912*39729Ssklower
1913*39729Ssklower imp_port =
1914*39729Ssklower ((int) (x25addr[9] & 0x0f) * 10) +
1915*39729Ssklower ((int) (x25addr[10] & 0x0f));
1916*39729Ssklower break;
1917*39729Ssklower case 1: /* Logical: 0000 1 RRRRR00 [SS] */
1918*39729Ssklower temp = ((int) (x25addr[6] & 0x0f) * 10000)
1919*39729Ssklower + ((int) (x25addr[7] & 0x0f) * 1000)
1920*39729Ssklower + ((int) (x25addr[8] & 0x0f) * 100)
1921*39729Ssklower + ((int) (x25addr[9] & 0x0f) * 10)
1922*39729Ssklower + ((int) (x25addr[10] & 0x0f));
1923*39729Ssklower
1924*39729Ssklower imp_port = temp >> 8;
1925*39729Ssklower imp_no = temp & 0xff;
1926*39729Ssklower break;
1927*39729Ssklower default:
1928*39729Ssklower DMESG(ds->dda_if.if_unit, 21,
1929*39729Ssklower (DDALOG(LOG_ERR) "dda%d: illegal X25 address format!\n",
1930*39729Ssklower ds->dda_if.if_unit DDAELOG));
1931*39729Ssklower return (0L);
1932*39729Ssklower }
1933*39729Ssklower
1934*39729Ssklower dc->dc_inaddr = imp_addr.ip = my_addr; /* use local net number */
1935*39729Ssklower if ((imp_addr.imp.s_net & 0x80) == 0x00) { /* class A */
1936*39729Ssklower imp_addr.imp.s_net = 0; /* mask net number */
1937*39729Ssklower imp_addr.imp.s_lh = 0; /* mask logical host */
1938*39729Ssklower imp_addr.imp.s_host = imp_port;
1939*39729Ssklower ((union imp_addr *) & dc->dc_inaddr.s_addr)->imp.s_host = imp_port;
1940*39729Ssklower imp_addr.imp.s_impno = imp_no;
1941*39729Ssklower ((union imp_addr *) & dc->dc_inaddr.s_addr)->imp.s_impno = imp_no;
1942*39729Ssklower } else if ((imp_addr.imp.s_net & 0xc0) == 0x80) { /* class B */
1943*39729Ssklower imp_addr.imp.s_net = 0;
1944*39729Ssklower imp_addr.imp.s_lh = imp_port;
1945*39729Ssklower ((union imp_addr *) & dc->dc_inaddr.s_addr)->imp.s_lh = imp_port;
1946*39729Ssklower imp_addr.imp.s_host = 0;
1947*39729Ssklower imp_addr.imp.s_impno = imp_no;
1948*39729Ssklower ((union imp_addr *) & dc->dc_inaddr.s_addr)->imp.s_impno = imp_no;
1949*39729Ssklower } else { /* class C */
1950*39729Ssklower imp_addr.imp.s_impno = (imp_no << 5) + imp_port;
1951*39729Ssklower ((union imp_addr *) & dc->dc_inaddr.s_addr)->imp.s_impno = imp_addr.imp.s_impno;
1952*39729Ssklower imp_addr.imp.s_lh = 0;
1953*39729Ssklower imp_addr.imp.s_host = 0;
1954*39729Ssklower imp_addr.imp.s_net = 0;
1955*39729Ssklower }
1956*39729Ssklower }
1957*39729Ssklower
1958*39729Ssklower #ifdef DDADEBUG
1959*39729Ssklower if (DDADBCH(12, ds->dda_if.if_unit)) {
1960*39729Ssklower DDALOG(LOG_DEBUG) "dda%d: convert_x25_addr: %s ==> %d.%d.%d.%d\n",
1961*39729Ssklower ds->dda_if.if_unit, fmt_x25(&x25addr[1], (int) x25addr[0]),
1962*39729Ssklower imp_addr.imp.s_net, imp_addr.imp.s_host, imp_addr.imp.s_lh,
1963*39729Ssklower imp_addr.imp.s_impno DDAELOG;
1964*39729Ssklower }
1965*39729Ssklower #endif DDADEBUG
1966*39729Ssklower
1967*39729Ssklower return (imp_addr.ip.s_addr);
1968*39729Ssklower }
1969*39729Ssklower
1970*39729Ssklower
1971*39729Ssklower
1972*39729Ssklower /*@@%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
1973*39729Ssklower /*%% MAKE_X25_CALL() %%*/
1974*39729Ssklower /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
1975*39729Ssklower /* */
1976*39729Ssklower /* Purpose: */
1977*39729Ssklower /* */
1978*39729Ssklower /* This routine places an X25 call using the X25 Call Msg */
1979*39729Ssklower /* buffer. The calling LCN is placed in the appropriate state */
1980*39729Ssklower /* and a timer is started. Based on dda_init flag, implement */
1981*39729Ssklower /* DDN standard or basic service. (If PDN mode is set, then */
1982*39729Ssklower /* the logic for basic service is followed.) */
1983*39729Ssklower /* */
1984*39729Ssklower /* Call: make_x25_call(ds, dc, ip_addr, proto */
1985*39729Ssklower /* udlen, ud) */
1986*39729Ssklower /* Arguments: ds: pointer to device control structure */
1987*39729Ssklower /* dc: pointer to the Logical Channel control */
1988*39729Ssklower /* block structure */
1989*39729Ssklower /* ip_addr: callee's ip address */
1990*39729Ssklower /* proto: protocol identifier byte */
1991*39729Ssklower /* udlen: user data length */
1992*39729Ssklower /* ud: user data */
1993*39729Ssklower /* Returns: one for success, zero for failure */
1994*39729Ssklower /* Called by: locate_x25_lcn() */
1995*39729Ssklower /* Calls to: MGET() */
1996*39729Ssklower /* mtod() */
1997*39729Ssklower /* convert_ip_addr() */
1998*39729Ssklower /* bcopy() */
1999*39729Ssklower /* IF_ENQUEUE() */
2000*39729Ssklower /* start_supr() */
2001*39729Ssklower /* */
2002*39729Ssklower /*##%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
2003*39729Ssklower
2004*39729Ssklower PRIVATE boolean
make_x25_call(ds,dc,ip_addr,proto,udlen,ud)2005*39729Ssklower make_x25_call(ds, dc, ip_addr, proto, udlen, ud)
2006*39729Ssklower register struct dda_softc *ds;
2007*39729Ssklower register struct dda_cb *dc;
2008*39729Ssklower struct in_addr ip_addr;
2009*39729Ssklower u_char proto;
2010*39729Ssklower u_char udlen;
2011*39729Ssklower u_char *ud;
2012*39729Ssklower {
2013*39729Ssklower register struct mbuf *m_callbfr;
2014*39729Ssklower register u_char *cb;
2015*39729Ssklower union imp_addr imp_addr;
2016*39729Ssklower
2017*39729Ssklower #if ACC_BSD == 42 || ACC_ULTRIX == 12
2018*39729Ssklower struct sockaddr_in *our_addr;
2019*39729Ssklower #endif
2020*39729Ssklower
2021*39729Ssklower #ifdef DDADEBUG
2022*39729Ssklower if (DDADBCH(13, ds->dda_if.if_unit)) {
2023*39729Ssklower DDALOG(LOG_DEBUG) "dda%d: make_x25_call: lcn used = %d\n",
2024*39729Ssklower ds->dda_if.if_unit, dc->dc_lcn DDAELOG;
2025*39729Ssklower }
2026*39729Ssklower #endif DDADEBUG
2027*39729Ssklower
2028*39729Ssklower MGET(m_callbfr, M_DONTWAIT, MT_DATA); /* try to get call cmnd
2029*39729Ssklower * buffer */
2030*39729Ssklower if (m_callbfr == 0) {
2031*39729Ssklower DMESG(ds->dda_if.if_unit, 22,
2032*39729Ssklower (DDALOG(LOG_ERR) "dda%d: couldn't get mbuf for call command\n",
2033*39729Ssklower ds->dda_if.if_unit DDAELOG));
2034*39729Ssklower return (0);
2035*39729Ssklower }
2036*39729Ssklower cb = mtod(m_callbfr, u_char *);
2037*39729Ssklower
2038*39729Ssklower if (ds->dda_net_id == TRANSPAC) {
2039*39729Ssklower ddacb_calling_addr[0] = 0; /* send a 0 length calling address */
2040*39729Ssklower } else {
2041*39729Ssklower #if ACC_BSD == 42 || ACC_ULTRIX == 12
2042*39729Ssklower our_addr = (struct sockaddr_in *) & (ds->dda_if.if_addr);
2043*39729Ssklower (void) convert_ip_addr(our_addr->sin_addr, ddacb_calling_addr, ds);
2044*39729Ssklower #else
2045*39729Ssklower (void) convert_ip_addr(ds->dda_ipaddr, ddacb_calling_addr, ds);
2046*39729Ssklower #endif
2047*39729Ssklower }
2048*39729Ssklower
2049*39729Ssklower ddacb_protocol[0] = 4;
2050*39729Ssklower ddacb_protocol[1] = proto; /* protocol type */
2051*39729Ssklower ddacb_protocol[2] = 0;
2052*39729Ssklower ddacb_protocol[3] = 0;
2053*39729Ssklower ddacb_protocol[4] = 0;
2054*39729Ssklower
2055*39729Ssklower /*
2056*39729Ssklower * CCITT standard facilities must precede DDN specific facilities See BBN
2057*39729Ssklower * report 5476 section 2.1.2. Firmware preceding rev 0x20 does not
2058*39729Ssklower * support packet size / window negotiation.
2059*39729Ssklower */
2060*39729Ssklower ddacb_facilities[0] = 0; /* initialize facilities length */
2061*39729Ssklower if (ds->dda_firmrev >= 0x21) {
2062*39729Ssklower ddacb_facilities[0] = 0;
2063*39729Ssklower if (ds->dda_init & DDA_PKTNEG) {
2064*39729Ssklower int n = ddacb_facilities[0]; /* length so far */
2065*39729Ssklower
2066*39729Ssklower ddacb_facilities[n + 1] = X25_FACIL_PKTSIZE;
2067*39729Ssklower ddacb_facilities[n + 2] = PKTSIZE_LARGE;
2068*39729Ssklower ddacb_facilities[n + 3] = PKTSIZE_LARGE;
2069*39729Ssklower ddacb_facilities[0] += 3;
2070*39729Ssklower }
2071*39729Ssklower if (ds->dda_init & DDA_WNDNEG) {
2072*39729Ssklower int n = ddacb_facilities[0]; /* length so far */
2073*39729Ssklower
2074*39729Ssklower ddacb_facilities[n + 1] = X25_FACIL_WINSIZE;
2075*39729Ssklower ddacb_facilities[n + 2] = WINSIZE_LARGE;
2076*39729Ssklower ddacb_facilities[n + 3] = WINSIZE_LARGE;
2077*39729Ssklower ddacb_facilities[0] += 3;
2078*39729Ssklower }
2079*39729Ssklower }
2080*39729Ssklower if ((ds->dda_init & (DDA_BASIC | DDA_PDN)) == 0) { /* DDN standard mode,
2081*39729Ssklower * tell callee */
2082*39729Ssklower int n = ddacb_facilities[0]; /* length so far */
2083*39729Ssklower
2084*39729Ssklower ddacb_facilities[0] += 4; /* additional facility bytes */
2085*39729Ssklower ddacb_facilities[n + 1] = DDN_FACIL_MARKER; /* end of CCITT stuff, */
2086*39729Ssklower ddacb_facilities[n + 2] = DDN_FACIL_MARKER; /* and start DDN local */
2087*39729Ssklower ddacb_facilities[n + 3] = X25_FACIL_DDA; /* DDA standard mode */
2088*39729Ssklower ddacb_facilities[n + 4] = FAC_DDASTD;
2089*39729Ssklower }
2090*39729Ssklower
2091*39729Ssklower ddacb_cmnd[0] = CALL; /* set command code */
2092*39729Ssklower ddacb_cmnd[1] = dc->dc_lcn << 1; /* set channel id */
2093*39729Ssklower ddacb_cmnd[2] = 0;
2094*39729Ssklower ddacb_cmnd[3] = (ddacb_called_addr[0] + 1) + /* tally cmnd ext len */
2095*39729Ssklower (ddacb_calling_addr[0] + 1) +
2096*39729Ssklower (ddacb_protocol[0] + 1) +
2097*39729Ssklower (ddacb_facilities[0] + 1) +
2098*39729Ssklower (ddacb_user_data[0] + 1);
2099*39729Ssklower
2100*39729Ssklower if ((unsigned) ddacb_cmnd[3] + 4 > MLEN) {
2101*39729Ssklower DMESG(ds->dda_if.if_unit, 38, (DDALOG(LOG_ERR)
2102*39729Ssklower "dda%d: make_x25_call message too large for mbuf (%d bytes)\n",
2103*39729Ssklower ds->dda_if.if_unit, (unsigned) ddacb_cmnd[3] + 4 DDAELOG));
2104*39729Ssklower return 0; /* failure */
2105*39729Ssklower }
2106*39729Ssklower
2107*39729Ssklower m_callbfr->m_len = ddacb_cmnd[3] + 4;
2108*39729Ssklower
2109*39729Ssklower /* copy command header */
2110*39729Ssklower bcopy(ddacb_cmnd, cb, 4);
2111*39729Ssklower cb += 4;
2112*39729Ssklower
2113*39729Ssklower /* copy called address */
2114*39729Ssklower bcopy(ddacb_called_addr, cb, ddacb_called_addr[0] + 1);
2115*39729Ssklower cb += (ddacb_called_addr[0] + 1);
2116*39729Ssklower
2117*39729Ssklower /* copy calling address */
2118*39729Ssklower bcopy(ddacb_calling_addr, cb, ddacb_calling_addr[0] + 1);
2119*39729Ssklower cb += (ddacb_calling_addr[0] + 1);
2120*39729Ssklower
2121*39729Ssklower /* copy protocol */
2122*39729Ssklower bcopy(ddacb_protocol, cb, ddacb_protocol[0] + 1);
2123*39729Ssklower cb += (ddacb_protocol[0] + 1);
2124*39729Ssklower
2125*39729Ssklower /* copy facilities */
2126*39729Ssklower bcopy(ddacb_facilities, cb, ddacb_facilities[0] + 1);
2127*39729Ssklower cb += (ddacb_facilities[0] + 1);
2128*39729Ssklower
2129*39729Ssklower /* copy user data */
2130*39729Ssklower bcopy(ddacb_user_data, cb, ddacb_user_data[0] + 1);
2131*39729Ssklower cb += (ddacb_user_data[0] + 1);
2132*39729Ssklower
2133*39729Ssklower hist_lcn_state(ds->dda_if.if_unit, dc->dc_state, LC_CALL_PENDING);
2134*39729Ssklower dc->dc_state = LC_CALL_PENDING; /* set state */
2135*39729Ssklower dc->dc_timer = TMO_CALL_PENDING; /* start call timeout */
2136*39729Ssklower
2137*39729Ssklower #ifdef DDADEBUG
2138*39729Ssklower if (DDADBCH(13, ds->dda_if.if_unit)) {
2139*39729Ssklower prt_bytes(ds->dda_if.if_unit, "make_x25_call: call_bfr",
2140*39729Ssklower mtod(m_callbfr, u_char *), m_callbfr->m_len);
2141*39729Ssklower }
2142*39729Ssklower #endif DDADEBUG
2143*39729Ssklower if (LOG_CALLS) {
2144*39729Ssklower imp_addr.ip = ip_addr;
2145*39729Ssklower DDALOG(LOG_ERR) "dda%d: Calling %d.%d.%d.%d (%s) on lcn %d\n",
2146*39729Ssklower ds->dda_if.if_unit, imp_addr.imp.s_net, imp_addr.imp.s_host,
2147*39729Ssklower imp_addr.imp.s_lh, imp_addr.imp.s_impno,
2148*39729Ssklower fmt_x25(&ddacb_called_addr[1], (int) ddacb_called_addr[0]),
2149*39729Ssklower dc->dc_lcn
2150*39729Ssklower DDAELOG;
2151*39729Ssklower }
2152*39729Ssklower start_supr(ds, m_callbfr);
2153*39729Ssklower return (1);
2154*39729Ssklower }
2155*39729Ssklower
2156*39729Ssklower
2157*39729Ssklower
2158*39729Ssklower /*@@%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
2159*39729Ssklower /*%% DDA_START() %%*/
2160*39729Ssklower /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
2161*39729Ssklower /* */
2162*39729Ssklower /* Purpose: */
2163*39729Ssklower /* */
2164*39729Ssklower /* This routine attempts to start output of data queued on a */
2165*39729Ssklower /* specific LCN. If the LCN was not already busy and data is */
2166*39729Ssklower /* available for output, the data is copied into the LCN's I/O */
2167*39729Ssklower /* buffer and a write request queued to the ACP device. Data */
2168*39729Ssklower /* is passed in mbuf(s) from IP to ddaoutput(), ddaoutput() */
2169*39729Ssklower /* queues the data, and the data is dequeued here. */
2170*39729Ssklower /* */
2171*39729Ssklower /* Call: dda_start(ds, dc) */
2172*39729Ssklower /* Arguments: ds: pointer to device control structure */
2173*39729Ssklower /* dc: pointer to the Logical Channel control */
2174*39729Ssklower /* block structure */
2175*39729Ssklower /* Returns: nothing */
2176*39729Ssklower /* Called by: ddaoutput() */
2177*39729Ssklower /* x25_init() */
2178*39729Ssklower /* make_x25_call() */
2179*39729Ssklower /* supr_msg() */
2180*39729Ssklower /* send_supr() */
2181*39729Ssklower /* dda_data() */
2182*39729Ssklower /* dda_supr() */
2183*39729Ssklower /* Calls to: IF_DEQUEUE() */
2184*39729Ssklower /* dda_wrq() */
2185*39729Ssklower /* */
2186*39729Ssklower /*##%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
2187*39729Ssklower
2188*39729Ssklower PRIVATE void
dda_start(ds,dc)2189*39729Ssklower dda_start(ds, dc)
2190*39729Ssklower register struct dda_softc *ds;
2191*39729Ssklower register struct dda_cb *dc;
2192*39729Ssklower {
2193*39729Ssklower register struct mbuf *m;
2194*39729Ssklower register struct hdx_chan *hc = &dc->dc_wchan;
2195*39729Ssklower register int s;
2196*39729Ssklower
2197*39729Ssklower #ifdef DDADEBUG
2198*39729Ssklower if (DDADBCH(14, ds->dda_if.if_unit)) {
2199*39729Ssklower DDALOG(LOG_DEBUG) "dda%d: dda_start()\n", ds->dda_if.if_unit DDAELOG;
2200*39729Ssklower }
2201*39729Ssklower #endif DDADEBUG
2202*39729Ssklower
2203*39729Ssklower /*
2204*39729Ssklower * If output isn't active, attempt to start sending a new packet.
2205*39729Ssklower */
2206*39729Ssklower
2207*39729Ssklower if ((dc->dc_flags & DC_OBUSY) || (dc->dc_oq.ifq_len == 0) ||
2208*39729Ssklower ((dc->dc_lcn != 0) && (dc->dc_state != LC_DATA_IDLE))) {
2209*39729Ssklower return;
2210*39729Ssklower }
2211*39729Ssklower if (dc->dc_lcn != 0)
2212*39729Ssklower dc->dc_timer = tmo_data_idle;
2213*39729Ssklower /*
2214*39729Ssklower * Raise priority whenever touching dc_oq because
2215*39729Ssklower * the mbufs on this queue may be asynchronously
2216*39729Ssklower * freed upon receipt of a line status msg, restart,
2217*39729Ssklower * clear, or reset.
2218*39729Ssklower */
2219*39729Ssklower s = splimp();
2220*39729Ssklower IF_DEQUEUE(&dc->dc_oq, m);
2221*39729Ssklower splx(s);
2222*39729Ssklower if (m == 0) { /* XXX this is a bug catcher XXX */
2223*39729Ssklower
2224*39729Ssklower DMESG(ds->dda_if.if_unit, 24,
2225*39729Ssklower (DDALOG(LOG_ERR) "dda%d: dequeued NULL mbuf in IP output chain!\n",
2226*39729Ssklower ds->dda_if.if_unit DDAELOG));
2227*39729Ssklower DMESG(ds->dda_if.if_unit, 24,
2228*39729Ssklower (DDALOG(LOG_ERR) "RESET dda%d MANUALLY: use /etc/acpconfig dda%d -z\n",
2229*39729Ssklower ds->dda_if.if_unit, ds->dda_if.if_unit DDAELOG));
2230*39729Ssklower
2231*39729Ssklower ds->dda_if.if_flags &= ~(IFF_RUNNING | IFF_UP);
2232*39729Ssklower hist_link_state(ds->dda_if.if_unit, ds->dda_state, S_DISABLED);
2233*39729Ssklower ds->dda_state = S_DISABLED;
2234*39729Ssklower dda_disable(ds->dda_if.if_unit);
2235*39729Ssklower return;
2236*39729Ssklower }
2237*39729Ssklower s = splimp();
2238*39729Ssklower hc->hc_mbuf = m;
2239*39729Ssklower hc->hc_curr = m;
2240*39729Ssklower #ifdef DDA_PAD_OR_RAW /* crufty kludge to get the Qbit */
2241*39729Ssklower if (dc->dc_flags & (DC_X29 | DC_X29W | DC_RAW)) { /* raw or x29? */
2242*39729Ssklower if (m->m_len < (MLEN - 1)) /* small mbuf? */
2243*39729Ssklower hc->hc_sbfc = m->m_dat[MLEN - 1]; /* ok, get the subfunc byte */
2244*39729Ssklower else
2245*39729Ssklower hc->hc_sbfc = 0; /* subfunc must be zero for large buffers */
2246*39729Ssklower } else
2247*39729Ssklower hc->hc_sbfc = 0; /* subfunc must be zero for ip buffers */
2248*39729Ssklower #else
2249*39729Ssklower hc->hc_sbfc = 0;
2250*39729Ssklower #endif
2251*39729Ssklower splx(s);
2252*39729Ssklower dc->dc_flags |= DC_OBUSY;
2253*39729Ssklower dda_wrq(ds, hc, 0); /* write request to ACP */
2254*39729Ssklower }
2255*39729Ssklower
2256*39729Ssklower /*@@%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
2257*39729Ssklower /*%% DDA_DATA() %%*/
2258*39729Ssklower /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
2259*39729Ssklower /* */
2260*39729Ssklower /* Purpose: */
2261*39729Ssklower /* */
2262*39729Ssklower /* This routine is called when a data channel I/O completes. */
2263*39729Ssklower /* If the completion was for a write, an attempt is made to */
2264*39729Ssklower /* start output on the next packet waiting for output on that */
2265*39729Ssklower /* LCN. If the completion was for a read, the received packet */
2266*39729Ssklower /* is sent to the IP input queue (if no error) and another read */
2267*39729Ssklower /* is started on the LCN. */
2268*39729Ssklower /* */
2269*39729Ssklower /* Call: dda_data(ds, hc, cc, cnt) */
2270*39729Ssklower /* Argument: ds: device control block */
2271*39729Ssklower /* hc: half duplex channel control block */
2272*39729Ssklower /* cc: Mailbox I/O completion status */
2273*39729Ssklower /* cnt: byte count */
2274*39729Ssklower /* Returns: nothing */
2275*39729Ssklower /* Called by: ddainta() */
2276*39729Ssklower /* Calls to: m_freem() */
2277*39729Ssklower /* dda_start() */
2278*39729Ssklower /* IF_QFULL() */
2279*39729Ssklower /* IF_DROP() */
2280*39729Ssklower /* IF_ENQUEUE() */
2281*39729Ssklower /* schednetisr() */
2282*39729Ssklower /* dda_rrq() */
2283*39729Ssklower /* dda_wrq() */
2284*39729Ssklower /* */
2285*39729Ssklower /*##%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
2286*39729Ssklower
2287*39729Ssklower PRIVATE void
dda_data(ds,hc,cc,cnt)2288*39729Ssklower dda_data(ds, hc, cc, cnt)
2289*39729Ssklower register struct dda_softc *ds;
2290*39729Ssklower register struct hdx_chan *hc;
2291*39729Ssklower int cc, cnt;
2292*39729Ssklower {
2293*39729Ssklower register struct dda_cb *dc = &(ds->dda_cb[hc->hc_chan / 2]);
2294*39729Ssklower struct ifqueue *inq = &ipintrq; /* IP input queue */
2295*39729Ssklower
2296*39729Ssklower /* note that this routine is a weird case in which Ultrix 2.0 behaves like
2297*39729Ssklower * a 4.2 system rather than a 4.3 system. This is reflected in the structure
2298*39729Ssklower * of conditional compilation segments.
2299*39729Ssklower */
2300*39729Ssklower #if ACC_BSD > 42 /* 4.3bsd or newer */
2301*39729Ssklower register struct mbuf *m, *mb;
2302*39729Ssklower struct ifnet *ifp;
2303*39729Ssklower #else /* 4.2, or all flavors of Ultrix */
2304*39729Ssklower register struct mbuf *m;
2305*39729Ssklower #endif
2306*39729Ssklower
2307*39729Ssklower #ifdef DDADEBUG
2308*39729Ssklower if (DDADBCH(18, ds->dda_if.if_unit)) {
2309*39729Ssklower DDALOG(LOG_DEBUG) "dda%d: dda_data: chan=%d cc=%x cnt=%x\n",
2310*39729Ssklower ds->dda_if.if_unit, hc->hc_chan, cc, cnt DDAELOG;
2311*39729Ssklower }
2312*39729Ssklower #endif DDADEBUG
2313*39729Ssklower
2314*39729Ssklower #if ACC_BSD > 42
2315*39729Ssklower ifp = &ds->dda_if;
2316*39729Ssklower #endif
2317*39729Ssklower
2318*39729Ssklower if (hc->hc_chan & 0x01) { /* was it read or write? *//* write, fire up
2319*39729Ssklower * next output */
2320*39729Ssklower #ifdef DDADEBUG
2321*39729Ssklower dc->dc_out_t = TMO_OFF; /* turn off output completion timer */
2322*39729Ssklower #endif
2323*39729Ssklower hc = &dc->dc_wchan;
2324*39729Ssklower if ((hc->hc_func != DDAABT) && (hc->hc_curr = hc->hc_curr->m_next))
2325*39729Ssklower dda_wrq(ds, hc, 0);
2326*39729Ssklower else {
2327*39729Ssklower m_freem(hc->hc_mbuf);
2328*39729Ssklower hc->hc_mbuf = hc->hc_curr = (struct mbuf *) 0;
2329*39729Ssklower if (hc->hc_func == DDAABT) {
2330*39729Ssklower hc->hc_func &= ~DDAABT;
2331*39729Ssklower hc->hc_inv &= ~INVALID_MBUF;
2332*39729Ssklower } else
2333*39729Ssklower ds->dda_if.if_opackets++;
2334*39729Ssklower dc->dc_flags &= ~DC_OBUSY;
2335*39729Ssklower dda_start(ds, dc);
2336*39729Ssklower }
2337*39729Ssklower } else { /* read, process rcvd packet */
2338*39729Ssklower hc = &dc->dc_rchan;
2339*39729Ssklower
2340*39729Ssklower #ifdef DDADEBUG
2341*39729Ssklower if (DDADBCH(19, ds->dda_if.if_unit)) {
2342*39729Ssklower u_char *p;
2343*39729Ssklower
2344*39729Ssklower p = mtod(hc->hc_curr, u_char *);
2345*39729Ssklower prt_bytes(ds->dda_if.if_unit, "received data", p, (cnt < 64 ? cnt : 64));
2346*39729Ssklower }
2347*39729Ssklower #endif DDADEBUG
2348*39729Ssklower
2349*39729Ssklower if (cc == DDAIOCOK) { /* Queue good packet for input */
2350*39729Ssklower #ifdef DDADEBUG
2351*39729Ssklower if (DDADBCH(19, ds->dda_if.if_unit)) {
2352*39729Ssklower DDALOG(LOG_DEBUG) "dda%d: dda_data: chan=%d DDAIOCOK\n",
2353*39729Ssklower ds->dda_if.if_unit, hc->hc_chan DDAELOG;
2354*39729Ssklower }
2355*39729Ssklower #endif DDADEBUG
2356*39729Ssklower ds->dda_if.if_ipackets++;
2357*39729Ssklower hist_lcn_state(ds->dda_if.if_unit, dc->dc_state, LC_DATA_IDLE);
2358*39729Ssklower if (dc->dc_state == LC_DATA_IDLE)
2359*39729Ssklower dc->dc_timer = tmo_data_idle;
2360*39729Ssklower hc->hc_curr->m_len += cnt; /* update byte count */
2361*39729Ssklower m = hc->hc_mbuf; /* que mbuf chain */
2362*39729Ssklower
2363*39729Ssklower #if ACC_BSD > 42
2364*39729Ssklower /* Prepend ifp pointer for 4.3 */
2365*39729Ssklower MGET(mb, M_DONTWAIT, MT_DATA);
2366*39729Ssklower if (mb == 0) {
2367*39729Ssklower DMESG(ds->dda_if.if_unit, 26,
2368*39729Ssklower (DDALOG(LOG_ERR) "dda%d: couldn't get mbuf for ifp header\n",
2369*39729Ssklower ds->dda_if.if_unit DDAELOG));
2370*39729Ssklower m_freem(m);
2371*39729Ssklower return;
2372*39729Ssklower }
2373*39729Ssklower *(mtod(mb, struct ifnet **)) = ifp;
2374*39729Ssklower mb->m_len = sizeof(ifp);
2375*39729Ssklower mb->m_next = m;
2376*39729Ssklower
2377*39729Ssklower if (IF_QFULL(inq)) {
2378*39729Ssklower IF_DROP(inq);
2379*39729Ssklower m_freem(mb);
2380*39729Ssklower } else {
2381*39729Ssklower IF_ENQUEUE(inq, mb);
2382*39729Ssklower schednetisr(NETISR_IP);
2383*39729Ssklower }
2384*39729Ssklower #else
2385*39729Ssklower if (IF_QFULL(inq)) {
2386*39729Ssklower IF_DROP(inq);
2387*39729Ssklower m_freem(m);
2388*39729Ssklower } else {
2389*39729Ssklower IF_ENQUEUE(inq, m);
2390*39729Ssklower schednetisr(NETISR_IP);
2391*39729Ssklower }
2392*39729Ssklower #endif
2393*39729Ssklower hc->hc_mbuf = hc->hc_curr = (struct mbuf *) 0;
2394*39729Ssklower } else if (cc == DDAIOCOKP) { /* good completion, more data pending */
2395*39729Ssklower hc->hc_curr->m_len += cnt;
2396*39729Ssklower } else {
2397*39729Ssklower m_freem(hc->hc_mbuf);
2398*39729Ssklower hc->hc_mbuf = hc->hc_curr = (struct mbuf *) 0;
2399*39729Ssklower }
2400*39729Ssklower /* hang a new data read */
2401*39729Ssklower dda_rrq(ds, hc);
2402*39729Ssklower }
2403*39729Ssklower }
2404*39729Ssklower
2405*39729Ssklower
2406*39729Ssklower
2407*39729Ssklower /*@@%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
2408*39729Ssklower /*%% DDA_SUPR() %%*/
2409*39729Ssklower /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
2410*39729Ssklower /* */
2411*39729Ssklower /* Purpose: */
2412*39729Ssklower /* */
2413*39729Ssklower /* This routine is called when a supervisor I/O completes. */
2414*39729Ssklower /* If the completion was for a write, an attempt is made to */
2415*39729Ssklower /* start output on the next supervisor command waiting for */
2416*39729Ssklower /* output. If the completion was for a read, the received */
2417*39729Ssklower /* supervisor message is processed and another read is started. */
2418*39729Ssklower /* */
2419*39729Ssklower /* Call: dda_supr(ds, hc, cc) */
2420*39729Ssklower /* Argument: ds: device control block */
2421*39729Ssklower /* hc: half duplex channel control block */
2422*39729Ssklower /* cc: Mailbox I/O completion status */
2423*39729Ssklower /* Returns: nothing */
2424*39729Ssklower /* Called by: ddainta() */
2425*39729Ssklower /* Calls to: dda_start() */
2426*39729Ssklower /* mtod() */
2427*39729Ssklower /* supr_msg() */
2428*39729Ssklower /* m_free() */
2429*39729Ssklower /* dda_rrq() */
2430*39729Ssklower /* */
2431*39729Ssklower /*##%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
2432*39729Ssklower
2433*39729Ssklower PRIVATE void
dda_supr(ds,hc,cc,cnt)2434*39729Ssklower dda_supr(ds, hc, cc, cnt)
2435*39729Ssklower register struct dda_softc *ds;
2436*39729Ssklower struct hdx_chan *hc;
2437*39729Ssklower int cc;
2438*39729Ssklower int cnt;
2439*39729Ssklower {
2440*39729Ssklower register struct dda_cb *dc = &(ds->dda_cb[hc->hc_chan / 2]);
2441*39729Ssklower u_char *p;
2442*39729Ssklower
2443*39729Ssklower #ifdef DDADEBUG
2444*39729Ssklower if (DDADBCH(20, ds->dda_if.if_unit)) {
2445*39729Ssklower DDALOG(LOG_DEBUG) "dda%d: dda_supr: chan=%d cc=%x\n",
2446*39729Ssklower ds->dda_if.if_unit, hc->hc_chan, cc DDAELOG;
2447*39729Ssklower }
2448*39729Ssklower #endif DDADEBUG
2449*39729Ssklower
2450*39729Ssklower /* an odd-numbered channel indicates a write */
2451*39729Ssklower /* the supr msg is assumed to be in 1 mbuf */
2452*39729Ssklower
2453*39729Ssklower if (hc->hc_chan & 0x01) {
2454*39729Ssklower m_freem(hc->hc_mbuf);
2455*39729Ssklower hc->hc_mbuf = hc->hc_curr = (struct mbuf *) 0;
2456*39729Ssklower dc->dc_flags &= ~DC_OBUSY;
2457*39729Ssklower dda_start(ds, dc);
2458*39729Ssklower }
2459*39729Ssklower /* otherwise, process the read */
2460*39729Ssklower
2461*39729Ssklower else {
2462*39729Ssklower if (cc == DDAIOCOK) {
2463*39729Ssklower p = mtod(hc->hc_curr, u_char *); /* point to data in mbuf */
2464*39729Ssklower #ifdef DDA_PAD_OR_RAW
2465*39729Ssklower switch (dda_decode_type(ds, p)) {
2466*39729Ssklower # ifdef DDA_PADOPT
2467*39729Ssklower case 1:
2468*39729Ssklower # ifdef DDADEBUG
2469*39729Ssklower if (DDADBCH(20, ds->dda_if.if_unit)) {
2470*39729Ssklower printf("dda%d: dda_supr(): case 1: chan = %x, p = %x\n",
2471*39729Ssklower ds->dda_if.if_unit, hc->hc_chan, *p);
2472*39729Ssklower }
2473*39729Ssklower # endif DDADEBUG
2474*39729Ssklower x29_supr(ds, p);
2475*39729Ssklower break;
2476*39729Ssklower # endif
2477*39729Ssklower # ifdef DDA_RAWOPT
2478*39729Ssklower case 2:
2479*39729Ssklower # ifdef DDADEBUG
2480*39729Ssklower if (DDADBCH(20, ds->dda_if.if_unit)) {
2481*39729Ssklower printf("dda%d: dda_supr(): case 2: chan = %x, p = %x\n",
2482*39729Ssklower ds->dda_if.if_unit, hc->hc_chan, *p);
2483*39729Ssklower }
2484*39729Ssklower # endif DDADEBUG
2485*39729Ssklower hc->hc_curr->m_len += cnt;
2486*39729Ssklower pi_supr(ds, hc->hc_curr);
2487*39729Ssklower /* don't free mbuf here */
2488*39729Ssklower hc->hc_mbuf = hc->hc_curr = (struct mbuf *) 0;
2489*39729Ssklower dda_rrq(ds, hc);/* hang a new supr read */
2490*39729Ssklower return;
2491*39729Ssklower # endif
2492*39729Ssklower default:
2493*39729Ssklower supr_msg(ds, p);/* process supervisor message */
2494*39729Ssklower break;
2495*39729Ssklower }
2496*39729Ssklower #else DDA_PAD_OR_RAW
2497*39729Ssklower supr_msg(ds, p); /* process supervisor message */
2498*39729Ssklower #endif DDA_PAD_OR_RAW
2499*39729Ssklower } else if (cc == DDAIOCOKP) {
2500*39729Ssklower DMESG(ds->dda_if.if_unit, 28,
2501*39729Ssklower (DDALOG(LOG_ERR) "dda%d: truncated supervisor message\n",
2502*39729Ssklower ds->dda_if.if_unit DDAELOG));
2503*39729Ssklower }
2504*39729Ssklower m_freem(hc->hc_mbuf);
2505*39729Ssklower hc->hc_mbuf = hc->hc_curr = (struct mbuf *) 0;
2506*39729Ssklower dda_rrq(ds, hc); /* hang a new supr read */
2507*39729Ssklower }
2508*39729Ssklower }
2509*39729Ssklower
2510*39729Ssklower
2511*39729Ssklower
2512*39729Ssklower /*@@%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
2513*39729Ssklower /*%% SUPR_MSG() %%*/
2514*39729Ssklower /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
2515*39729Ssklower /* */
2516*39729Ssklower /* Purpose: */
2517*39729Ssklower /* */
2518*39729Ssklower /* This routine processes received supervisor messages. */
2519*39729Ssklower /* Depending on the message type, the appropriate action is */
2520*39729Ssklower /* taken. */
2521*39729Ssklower /* */
2522*39729Ssklower /* Call: supr_msg(ds, p) */
2523*39729Ssklower /* Arguments: ds: pointer to dev control block struct */
2524*39729Ssklower /* p: pointer to a character array */
2525*39729Ssklower /* containing the supervisor message */
2526*39729Ssklower /* Returns: nothing */
2527*39729Ssklower /* Called by: dda_supr() */
2528*39729Ssklower /* Calls to: DDALOG() */
2529*39729Ssklower /* IF_DEQUEUE() */
2530*39729Ssklower /* m_freem() */
2531*39729Ssklower /* send_restart() */
2532*39729Ssklower /* send_supr() */
2533*39729Ssklower /* dda_start() */
2534*39729Ssklower /* decode_ring() */
2535*39729Ssklower /* decode_answer() */
2536*39729Ssklower /* convert_x25_addr() */
2537*39729Ssklower /* */
2538*39729Ssklower /*##%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
2539*39729Ssklower
2540*39729Ssklower PRIVATE void
supr_msg(ds,p)2541*39729Ssklower supr_msg(ds, p)
2542*39729Ssklower struct dda_softc *ds;
2543*39729Ssklower u_char p[];
2544*39729Ssklower
2545*39729Ssklower {
2546*39729Ssklower register struct dda_cb *dc;
2547*39729Ssklower register int lcn;
2548*39729Ssklower register int maxlcn;
2549*39729Ssklower union imp_addr imp_addr;
2550*39729Ssklower
2551*39729Ssklower #ifdef DDADEBUG
2552*39729Ssklower if (DDADBCH(21, ds->dda_if.if_unit)) {
2553*39729Ssklower prt_bytes(ds->dda_if.if_unit, "supr_msg", p, (int) (4 + p[3]));
2554*39729Ssklower }
2555*39729Ssklower #endif DDADEBUG
2556*39729Ssklower
2557*39729Ssklower maxlcn = nddach[ds->dda_if.if_unit]; /* obtain SVC limit */
2558*39729Ssklower switch (p[0]) {
2559*39729Ssklower case LINE_STATUS: /* link status msg */
2560*39729Ssklower if (p[2] == LINK_UP) { /* if link came up */
2561*39729Ssklower #ifdef DDADEBUG
2562*39729Ssklower if (DDADBCH(21, ds->dda_if.if_unit)) {
2563*39729Ssklower DDALOG(LOG_DEBUG) "dda%d: supr_msg: HDLC link up\n",
2564*39729Ssklower ds->dda_if.if_unit DDAELOG;
2565*39729Ssklower }
2566*39729Ssklower #endif DDADEBUG
2567*39729Ssklower send_restart(ds); /* send restart msg */
2568*39729Ssklower ds->dda_state = S_COMING_UP;
2569*39729Ssklower } else { /* if link went down */
2570*39729Ssklower ds->dda_if.if_flags &= ~IFF_UP; /* ? should call if_down() ? */
2571*39729Ssklower hist_link_state(ds->dda_if.if_unit, ds->dda_state, S_DISABLED);
2572*39729Ssklower ds->dda_state = S_DISABLED;
2573*39729Ssklower dc = ds->dda_cb;
2574*39729Ssklower /* LCNLINK */
2575*39729Ssklower for (lcn = 0; lcn <= maxlcn; lcn++) { /* for all LCN's */
2576*39729Ssklower dc->dc_inaddr.s_addr = 0; /* forget dest address */
2577*39729Ssklower dc->dc_key.key_addr.s_addr = 0;
2578*39729Ssklower dc->dc_wsizein = dc->dc_wsizeout = 0;
2579*39729Ssklower dc->dc_pktsizein = dc->dc_pktsizeout = 0;
2580*39729Ssklower dc->dc_state = LC_DOWN; /* set state */
2581*39729Ssklower dc->dc_timer = TMO_OFF; /* stop timer */
2582*39729Ssklower dc++;
2583*39729Ssklower }
2584*39729Ssklower hist_all_lcns(ds->dda_if.if_unit, LC_DOWN);
2585*39729Ssklower abort_io(ds->dda_if.if_unit, ALL_CHANS);
2586*39729Ssklower #ifdef DDA_PADOPT
2587*39729Ssklower x29_init(ds->dda_if.if_unit, 1);
2588*39729Ssklower #endif
2589*39729Ssklower if (p[2] == LINK_DISABLED) /* link disabled */
2590*39729Ssklower DMESG(ds->dda_if.if_unit, 29,
2591*39729Ssklower (DDALOG(LOG_ERR) "dda%d: link disabled\n",
2592*39729Ssklower ds->dda_if.if_unit DDAELOG));
2593*39729Ssklower else
2594*39729Ssklower DMESG(ds->dda_if.if_unit, 30,
2595*39729Ssklower (DDALOG(LOG_ERR) "dda%d: link down\n", ds->dda_if.if_unit DDAELOG));
2596*39729Ssklower }
2597*39729Ssklower break;
2598*39729Ssklower
2599*39729Ssklower case RESTART: /* restart received */
2600*39729Ssklower if (ds->dda_cb[0].dc_state != LC_RESTART) { /* if not restarting */
2601*39729Ssklower
2602*39729Ssklower #ifdef DDADEBUG
2603*39729Ssklower if (DDADBCH(21, ds->dda_if.if_unit)) {
2604*39729Ssklower DDALOG(LOG_DEBUG)
2605*39729Ssklower "dda%d: supr_msg: RESTART rcvd, no RESTART pending\n",
2606*39729Ssklower ds->dda_if.if_unit DDAELOG;
2607*39729Ssklower }
2608*39729Ssklower #endif DDADEBUG
2609*39729Ssklower send_supr(ds, RSTRT_ACK, 0, 0); /* send restart ack */
2610*39729Ssklower }
2611*39729Ssklower /* fall thru */
2612*39729Ssklower case RSTRT_ACK: /* restart ack */
2613*39729Ssklower if ((ds->dda_state == S_COMING_UP) || (ds->dda_state == S_LINK_UP)) {
2614*39729Ssklower if (p[0] == RSTRT_ACK) {
2615*39729Ssklower DMESG(ds->dda_if.if_unit, 31,
2616*39729Ssklower (DDALOG(LOG_ERR) "dda%d: Restart Ack received\n",
2617*39729Ssklower ds->dda_if.if_unit DDAELOG));
2618*39729Ssklower } else { /* restart. print cause and diagnostic. */
2619*39729Ssklower DMESG(ds->dda_if.if_unit, 31,
2620*39729Ssklower (DDALOG(LOG_ERR) "dda%d: Restart (%x %x) received\n",
2621*39729Ssklower ds->dda_if.if_unit, p[2], p[3] ? p[4] : 0 DDAELOG));
2622*39729Ssklower }
2623*39729Ssklower
2624*39729Ssklower ds->dda_if.if_flags |= IFF_UP;
2625*39729Ssklower hist_link_state(ds->dda_if.if_unit, ds->dda_state, S_LINK_UP);
2626*39729Ssklower ds->dda_state = S_LINK_UP;
2627*39729Ssklower dc = ds->dda_cb;
2628*39729Ssklower /* LCNLINK */
2629*39729Ssklower for (lcn = 0; lcn <= maxlcn; lcn++) { /* for all LCN's */
2630*39729Ssklower dc->dc_state = LC_IDLE; /* set state */
2631*39729Ssklower dc->dc_timer = TMO_OFF; /* stop timer */
2632*39729Ssklower dc->dc_inaddr.s_addr = 0; /* forget address */
2633*39729Ssklower dc->dc_key.key_addr.s_addr = 0;
2634*39729Ssklower dc->dc_wsizein = dc->dc_wsizeout = 0;
2635*39729Ssklower dc->dc_pktsizein = dc->dc_pktsizeout = 0;
2636*39729Ssklower dc++;
2637*39729Ssklower }
2638*39729Ssklower hist_all_lcns(ds->dda_if.if_unit, LC_IDLE);
2639*39729Ssklower abort_io(ds->dda_if.if_unit, ALL_CHANS);
2640*39729Ssklower DMESG(ds->dda_if.if_unit, 32,
2641*39729Ssklower (DDALOG(LOG_ERR) "dda%d: (%s rev %d.%d) link up\n",
2642*39729Ssklower ds->dda_if.if_unit, dda_product,
2643*39729Ssklower (ds->dda_firmrev >> 4) & 0xF, ds->dda_firmrev & 0xF DDAELOG));
2644*39729Ssklower #ifdef DDA_PAD_OR_RAW
2645*39729Ssklower x29_init(ds->dda_if.if_unit, 1);
2646*39729Ssklower
2647*39729Ssklower /*
2648*39729Ssklower * wake up all processes that tried to open a x29 device but
2649*39729Ssklower * slept because the board was not up
2650*39729Ssklower */
2651*39729Ssklower wakeup(&ds->dda_state);
2652*39729Ssklower #endif DDA_PAD_OR_RAW
2653*39729Ssklower } else
2654*39729Ssklower #ifdef DDADEBUG
2655*39729Ssklower if (DDADBCH(21, ds->dda_if.if_unit)) {
2656*39729Ssklower DDALOG(LOG_ERR) "dda%d: Unexpected RESTART in state %x\n",
2657*39729Ssklower ds->dda_if.if_unit, ds->dda_state DDAELOG;
2658*39729Ssklower }
2659*39729Ssklower #endif DDADEBUG
2660*39729Ssklower break;
2661*39729Ssklower
2662*39729Ssklower case ANSWER: /* call answered */
2663*39729Ssklower lcn = p[1] / 2;
2664*39729Ssklower dc = &(ds->dda_cb[lcn]);
2665*39729Ssklower if (dc->dc_state == LC_CALL_PENDING) { /* if a call pending */
2666*39729Ssklower hist_lcn_state(ds->dda_if.if_unit, dc->dc_state, LC_DATA_IDLE);
2667*39729Ssklower decode_answer(p, dc);
2668*39729Ssklower dc->dc_state = LC_DATA_IDLE; /* set state */
2669*39729Ssklower dc->dc_timer = tmo_data_idle; /* start timer */
2670*39729Ssklower dda_start(ds, dc); /* try to send data */
2671*39729Ssklower }
2672*39729Ssklower if (LOG_CALLS) {
2673*39729Ssklower DDALOG(LOG_ERR) "dda%d: lcn %d connected\n",
2674*39729Ssklower ds->dda_if.if_unit, lcn DDAELOG;
2675*39729Ssklower }
2676*39729Ssklower break;
2677*39729Ssklower
2678*39729Ssklower case RING: /* incoming call */
2679*39729Ssklower /* if ring looks ok, and we find a free LCN to assign */
2680*39729Ssklower if (decode_ring(p) && (dc = find_free_lcn(ds))) {
2681*39729Ssklower dc->dc_key.key_addr.s_addr =
2682*39729Ssklower convert_x25_addr(ddacb_calling_addr, ds, dc);
2683*39729Ssklower #ifdef DDADEBUG
2684*39729Ssklower if (DDADBCH(21, ds->dda_if.if_unit)) {
2685*39729Ssklower imp_addr.ip = dc->dc_inaddr;
2686*39729Ssklower DDALOG(LOG_DEBUG)
2687*39729Ssklower "dda%d: supr_msg: got call from %d.%d.%d.%d\n",
2688*39729Ssklower ds->dda_if.if_unit, imp_addr.imp.s_net, imp_addr.imp.s_host,
2689*39729Ssklower imp_addr.imp.s_lh, imp_addr.imp.s_impno DDAELOG;
2690*39729Ssklower }
2691*39729Ssklower #endif DDADEBUG
2692*39729Ssklower hist_lcn_state(ds->dda_if.if_unit, dc->dc_state, LC_DATA_IDLE);
2693*39729Ssklower dc->dc_state = LC_DATA_IDLE; /* set state */
2694*39729Ssklower dc->dc_timer = tmo_data_idle; /* start timer */
2695*39729Ssklower dc->dc_pktsizein = 0;
2696*39729Ssklower dc->dc_pktsizeout = 0;
2697*39729Ssklower dc->dc_wsizein = 0;
2698*39729Ssklower dc->dc_wsizeout = 0;
2699*39729Ssklower send_supr(ds, ANSWER, (int) dc->dc_lcn * 2,
2700*39729Ssklower (int) p[2]); /* send answer */
2701*39729Ssklower if (LOG_CALLS) {
2702*39729Ssklower imp_addr.ip = dc->dc_inaddr;
2703*39729Ssklower DDALOG(LOG_ERR)
2704*39729Ssklower "dda%d: Accepting call from %d.%d.%d.%d (%s) on lcn %d\n",
2705*39729Ssklower ds->dda_if.if_unit, imp_addr.imp.s_net, imp_addr.imp.s_host,
2706*39729Ssklower imp_addr.imp.s_lh, imp_addr.imp.s_impno,
2707*39729Ssklower fmt_x25(&ddacb_calling_addr[1],
2708*39729Ssklower (int) ddacb_calling_addr[0]), dc->dc_lcn DDAELOG;
2709*39729Ssklower }
2710*39729Ssklower } else { /* if no free LCN's */
2711*39729Ssklower send_supr(ds, CLEARVC, p[2], 0); /* clear call */
2712*39729Ssklower if (LOG_CALLS) {
2713*39729Ssklower DDALOG(LOG_ERR) "dda%d: Rejecting call from %s on VC 0x%x\n",
2714*39729Ssklower ds->dda_if.if_unit,
2715*39729Ssklower fmt_x25(&ddacb_calling_addr[1], ddacb_calling_addr[0]),
2716*39729Ssklower p[1] DDAELOG;
2717*39729Ssklower }
2718*39729Ssklower }
2719*39729Ssklower break;
2720*39729Ssklower
2721*39729Ssklower case CLEARLC: /* clear by LCN */
2722*39729Ssklower
2723*39729Ssklower /*
2724*39729Ssklower * This could mean one of three things: If we have a call request
2725*39729Ssklower * outstanding, this message means the call has failed. If we have a
2726*39729Ssklower * clear request outstanding, this message completes the cleanup; the
2727*39729Ssklower * channel is now available for reuse. If we have a call active, this
2728*39729Ssklower * message means the other side is closing the circuit.
2729*39729Ssklower */
2730*39729Ssklower lcn = p[1] / 2; /* get LCN */
2731*39729Ssklower dc = &(ds->dda_cb[lcn]);
2732*39729Ssklower if (dc->dc_state != LC_CLR_PENDING) { /* if no clear pending */
2733*39729Ssklower send_supr(ds, CLEARLC, p[1], 0); /* ack the clear */
2734*39729Ssklower }
2735*39729Ssklower if (dc->dc_state == LC_CALL_PENDING /* if call is cleared */
2736*39729Ssklower && (LOG_CALLS || DMESGVAL(ds->dda_if.if_unit, 33) == 0)) {
2737*39729Ssklower imp_addr.ip = dc->dc_inaddr;
2738*39729Ssklower DDALOG(LOG_ERR)
2739*39729Ssklower "dda%d: Call to %d.%d.%d.%d on lcn %d failed (%x %x)\n",
2740*39729Ssklower ds->dda_if.if_unit, imp_addr.imp.s_net, imp_addr.imp.s_host,
2741*39729Ssklower imp_addr.imp.s_lh, imp_addr.imp.s_impno, dc->dc_lcn, p[2], p[4]
2742*39729Ssklower DDAELOG;
2743*39729Ssklower
2744*39729Ssklower } else if (LOG_CALLS) {
2745*39729Ssklower if (dc->dc_state == LC_CLR_PENDING) { /* did we clear it? *//* y
2746*39729Ssklower * es, IP address is
2747*39729Ssklower * already gone. Say
2748*39729Ssklower * channel is free. */
2749*39729Ssklower DDALOG(LOG_ERR) "dda%d: Cleared lcn %d\n",
2750*39729Ssklower ds->dda_if.if_unit, dc->dc_lcn DDAELOG;
2751*39729Ssklower } else { /* cleared by net, print more info */
2752*39729Ssklower imp_addr.ip = dc->dc_inaddr;
2753*39729Ssklower DDALOG(LOG_ERR)
2754*39729Ssklower "dda%d: Cleared lcn %d to %d.%d.%d.%d (%x %x)\n",
2755*39729Ssklower ds->dda_if.if_unit, dc->dc_lcn, imp_addr.imp.s_net,
2756*39729Ssklower imp_addr.imp.s_host, imp_addr.imp.s_lh, imp_addr.imp.s_impno,
2757*39729Ssklower p[2], p[4] DDAELOG;
2758*39729Ssklower }
2759*39729Ssklower }
2760*39729Ssklower hist_lcn_state(ds->dda_if.if_unit, dc->dc_state, LC_IDLE);
2761*39729Ssklower /* LCNLINK delete */
2762*39729Ssklower dc->dc_state = LC_IDLE; /* set state */
2763*39729Ssklower dc->dc_timer = TMO_OFF; /* stop timer */
2764*39729Ssklower dc->dc_inaddr.s_addr = 0; /* forget address */
2765*39729Ssklower dc->dc_key.key_addr.s_addr = 0;
2766*39729Ssklower dc->dc_wsizein = dc->dc_wsizeout = 0;
2767*39729Ssklower dc->dc_pktsizein = dc->dc_pktsizeout = 0;
2768*39729Ssklower abort_io(ds->dda_if.if_unit, lcn);
2769*39729Ssklower if (LOG_CALLS) {
2770*39729Ssklower printf("dda%d: Cleared LCN %d cause code %x diag code %x\n",
2771*39729Ssklower ds->dda_if.if_unit, dc->dc_lcn, p[2], p[4]);
2772*39729Ssklower }
2773*39729Ssklower break;
2774*39729Ssklower
2775*39729Ssklower case CLEARVC: /* clear by VCN */
2776*39729Ssklower
2777*39729Ssklower send_supr(ds, CLEARVC, p[1], 0); /* send clear ack */
2778*39729Ssklower if (LOG_CALLS) {
2779*39729Ssklower DDALOG(LOG_ERR) "dda%d: Network cleared VC %x (%x %x)\n",
2780*39729Ssklower ds->dda_if.if_unit, p[1], p[2], p[4] DDAELOG;
2781*39729Ssklower }
2782*39729Ssklower #ifdef DDADEBUG
2783*39729Ssklower else if (DDADBCH(21, ds->dda_if.if_unit)) {
2784*39729Ssklower DDALOG(LOG_DEBUG) "dda%d: supr_msg: CLEARVC VCN=%x\n",
2785*39729Ssklower ds->dda_if.if_unit, p[1] DDAELOG;
2786*39729Ssklower }
2787*39729Ssklower #endif DDADEBUG
2788*39729Ssklower break;
2789*39729Ssklower
2790*39729Ssklower case RESET: /* X25 reset */
2791*39729Ssklower lcn = p[1] / 2; /* get LCN */
2792*39729Ssklower dc = &(ds->dda_cb[lcn]);
2793*39729Ssklower send_supr(ds, RESET_ACK, p[1], 0); /* send reset ack */
2794*39729Ssklower abort_io(ds->dda_if.if_unit, lcn);
2795*39729Ssklower imp_addr.ip = dc->dc_inaddr;
2796*39729Ssklower DMESG(ds->dda_if.if_unit, 34,
2797*39729Ssklower (DDALOG(LOG_ERR)
2798*39729Ssklower "dda%d: X25 RESET (%x %x) on lcn %d: %d.%d.%d.%d\n",
2799*39729Ssklower ds->dda_if.if_unit, p[2], p[4], lcn, imp_addr.imp.s_net,
2800*39729Ssklower imp_addr.imp.s_host, imp_addr.imp.s_lh, imp_addr.imp.s_impno
2801*39729Ssklower DDAELOG));
2802*39729Ssklower break;
2803*39729Ssklower
2804*39729Ssklower case INTERRUPT: /* X25 interrupt */
2805*39729Ssklower lcn = p[1] / 2; /* get LCN */
2806*39729Ssklower dc = &(ds->dda_cb[lcn]);
2807*39729Ssklower imp_addr.ip = dc->dc_inaddr;
2808*39729Ssklower DMESG(ds->dda_if.if_unit, 35,
2809*39729Ssklower (DDALOG(LOG_ERR)
2810*39729Ssklower "dda%d: X25 INTERRUPT (%x) on lcn %d: %d.%d.%d.%d\n",
2811*39729Ssklower ds->dda_if.if_unit, p[2], lcn, imp_addr.imp.s_net,
2812*39729Ssklower imp_addr.imp.s_host, imp_addr.imp.s_lh, imp_addr.imp.s_impno
2813*39729Ssklower DDAELOG));
2814*39729Ssklower break;
2815*39729Ssklower
2816*39729Ssklower case STATRESP: /* Statistics Response from FEP */
2817*39729Ssklower
2818*39729Ssklower /*
2819*39729Ssklower * Copy the whole message into a static buffer, dda_iobuf. The buffer
2820*39729Ssklower * is viewed as a (struct ddactl). Wake up the ioctl thread which
2821*39729Ssklower * will copy the message out for acpconfig.
2822*39729Ssklower */
2823*39729Ssklower {
2824*39729Ssklower struct ddactl *da = (struct ddactl *) dda_iobuf;
2825*39729Ssklower
2826*39729Ssklower bcopy(p, da->msg, max(4 + p[3], sizeof(da->msg)));
2827*39729Ssklower #ifdef MULTINET
2828*39729Ssklower StatQuery_Completed = 1;
2829*39729Ssklower #else
2830*39729Ssklower wakeup(dda_iobuf);
2831*39729Ssklower #endif
2832*39729Ssklower break;
2833*39729Ssklower }
2834*39729Ssklower
2835*39729Ssklower default:
2836*39729Ssklower DMESG(ds->dda_if.if_unit, 36,
2837*39729Ssklower (DDALOG(LOG_ERR) "dda%d: supervisor error (%x %x %x %x)\n",
2838*39729Ssklower ds->dda_if.if_unit, p[0], p[1], p[2], p[3] DDAELOG));
2839*39729Ssklower }
2840*39729Ssklower }
2841*39729Ssklower
2842*39729Ssklower
2843*39729Ssklower
2844*39729Ssklower /*@@%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
2845*39729Ssklower /*%% DECODE_ANSWER() %%*/
2846*39729Ssklower /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
2847*39729Ssklower /* */
2848*39729Ssklower /* Purpose: */
2849*39729Ssklower /* This routine looks at the answer message from the FE */
2850*39729Ssklower /* and decodes it to find the negtiated packet and window sizes */
2851*39729Ssklower /* if they are present. */
2852*39729Ssklower /* */
2853*39729Ssklower /* Call: decode_answer(p, dc) */
2854*39729Ssklower /* Argument: p: pointer to mbuf data for ANSWER message */
2855*39729Ssklower /* dc: pointer to relavant lcn structure */
2856*39729Ssklower /* Returns: nothing */
2857*39729Ssklower /* Called by: supr_msg() */
2858*39729Ssklower /* Calls to: */
2859*39729Ssklower /* DDALOG() */
2860*39729Ssklower /* */
2861*39729Ssklower /*##%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
2862*39729Ssklower
2863*39729Ssklower PRIVATE void
decode_answer(p,dc)2864*39729Ssklower decode_answer(p, dc)
2865*39729Ssklower u_char *p;
2866*39729Ssklower struct dda_cb *dc;
2867*39729Ssklower {
2868*39729Ssklower register u_char *cp;
2869*39729Ssklower int i, faclen;
2870*39729Ssklower
2871*39729Ssklower dc->dc_pktsizein = 0;
2872*39729Ssklower dc->dc_pktsizeout = 0;
2873*39729Ssklower dc->dc_wsizein = 0;
2874*39729Ssklower dc->dc_wsizeout = 0;
2875*39729Ssklower cp = p + 4; /* skip over code, lcn, vcn and count in
2876*39729Ssklower * answer message */
2877*39729Ssklower /* cp now points to length of called address */
2878*39729Ssklower cp += *cp + 1; /* skip over called address and length byte */
2879*39729Ssklower /* cp now points to length of calling address */
2880*39729Ssklower cp += *cp + 1; /* skip over calling address and length byte */
2881*39729Ssklower /* cp now points to length of protocol */
2882*39729Ssklower cp += *cp + 1; /* skip over protocol and protocol length
2883*39729Ssklower * byte */
2884*39729Ssklower /* cp now points to the facilities length */
2885*39729Ssklower
2886*39729Ssklower faclen = *cp++;
2887*39729Ssklower /* cp now points to start of facilities */
2888*39729Ssklower for (i = 0; i < faclen;) {
2889*39729Ssklower switch (*cp & 0xc0) {
2890*39729Ssklower case 0x00: /* single octet parameter field */
2891*39729Ssklower i += 2;
2892*39729Ssklower cp += 2;
2893*39729Ssklower break;
2894*39729Ssklower case 0x40: /* double octet parameter field */
2895*39729Ssklower switch (*cp) {
2896*39729Ssklower case X25_FACIL_PKTSIZE: /* 0x42, packet size */
2897*39729Ssklower dc->dc_pktsizein = *(cp + 1);
2898*39729Ssklower dc->dc_pktsizeout = *(cp + 2);
2899*39729Ssklower break;
2900*39729Ssklower case X25_FACIL_WINSIZE: /* 0x43, window size */
2901*39729Ssklower dc->dc_wsizein = *(cp + 1);
2902*39729Ssklower dc->dc_wsizeout = *(cp + 2);
2903*39729Ssklower break;
2904*39729Ssklower }
2905*39729Ssklower i += 3;
2906*39729Ssklower cp += 3;
2907*39729Ssklower break;
2908*39729Ssklower case 0x80: /* triple octet parameter field */
2909*39729Ssklower i += 4;
2910*39729Ssklower cp += 4;
2911*39729Ssklower break;
2912*39729Ssklower case 0xc0: /* variable-length parameter field */
2913*39729Ssklower cp++;
2914*39729Ssklower i += 2 + *cp;
2915*39729Ssklower cp += 1 + *cp;
2916*39729Ssklower break;
2917*39729Ssklower /* Note: No other cases (i.e., default) possible */
2918*39729Ssklower }
2919*39729Ssklower }
2920*39729Ssklower }
2921*39729Ssklower
2922*39729Ssklower
2923*39729Ssklower
2924*39729Ssklower /*@@%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
2925*39729Ssklower /*%% DECODE_RING() %%*/
2926*39729Ssklower /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
2927*39729Ssklower /* */
2928*39729Ssklower /* Purpose: */
2929*39729Ssklower /* */
2930*39729Ssklower /* This routine parses and validates the incoming call message. */
2931*39729Ssklower /* */
2932*39729Ssklower /* Call: decode_ring(p) */
2933*39729Ssklower /* Argument: p: pointer to the message */
2934*39729Ssklower /* Returns: 1 for success, else 0 for failure */
2935*39729Ssklower /* Called by: supr_msg() */
2936*39729Ssklower /* Calls to: bcopy() */
2937*39729Ssklower /* */
2938*39729Ssklower /*##%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
2939*39729Ssklower
2940*39729Ssklower PRIVATE boolean
decode_ring(p)2941*39729Ssklower decode_ring(p)
2942*39729Ssklower register u_char *p;
2943*39729Ssklower {
2944*39729Ssklower register int cnt;
2945*39729Ssklower
2946*39729Ssklower #ifdef DDADEBUG
2947*39729Ssklower if (DDADBCH(22, 0)) { /* no easy access to unit, assume unit 0 */
2948*39729Ssklower DDALOG(LOG_DEBUG) "dda: decode_ring()\n" DDAELOG;
2949*39729Ssklower }
2950*39729Ssklower #endif DDADEBUG
2951*39729Ssklower
2952*39729Ssklower p += 3; /* skip to cmnd ext length */
2953*39729Ssklower if (*p++ < 5) /* is count appropriate */
2954*39729Ssklower return (0); /* return false if not */
2955*39729Ssklower
2956*39729Ssklower /* called address */
2957*39729Ssklower if ((cnt = *p + 1) > 16) /* is called addr len legal? */
2958*39729Ssklower return (0); /* return false if not */
2959*39729Ssklower bcopy(p, ddacb_called_addr, cnt); /* copy field */
2960*39729Ssklower p += cnt;
2961*39729Ssklower
2962*39729Ssklower /* calling address */
2963*39729Ssklower if ((cnt = *p + 1) > 16) /* is calling addr len legal? */
2964*39729Ssklower return (0); /* return false if not */
2965*39729Ssklower bcopy(p, ddacb_calling_addr, cnt); /* copy field */
2966*39729Ssklower p += cnt;
2967*39729Ssklower
2968*39729Ssklower /* protocol part of user data */
2969*39729Ssklower if ((cnt = *p + 1) > 5) /* is protocol len legal? */
2970*39729Ssklower return (0); /* return false if not */
2971*39729Ssklower bcopy(p, ddacb_protocol, cnt); /* copy field */
2972*39729Ssklower p += cnt;
2973*39729Ssklower
2974*39729Ssklower /* facilities */
2975*39729Ssklower if ((cnt = *p + 1) > 64) /* is facilities len legal? */
2976*39729Ssklower return (0); /* return false if not */
2977*39729Ssklower bcopy(p, ddacb_facilities, cnt); /* copy field */
2978*39729Ssklower p += cnt;
2979*39729Ssklower
2980*39729Ssklower /* ignore rest of user data for now */
2981*39729Ssklower
2982*39729Ssklower #ifdef DDA_PAD_OR_RAW
2983*39729Ssklower if (ddacb_protocol[0] == 0)
2984*39729Ssklower return (0);
2985*39729Ssklower #else DDA_PAD_OR_RAW
2986*39729Ssklower if ((ddacb_protocol[0] == 0) || (ddacb_protocol[1] != X25_PROTO_IP))
2987*39729Ssklower return (0); /* bad if not IP */
2988*39729Ssklower #endif DDA_PAD_OR_RAW
2989*39729Ssklower
2990*39729Ssklower #ifndef DDA_PAD_OR_RAW
2991*39729Ssklower return (1); /* looks ok */
2992*39729Ssklower #else
2993*39729Ssklower # ifdef DDA_RAWOPT
2994*39729Ssklower return (1); /* anything is ok if we're PI interface */
2995*39729Ssklower # else
2996*39729Ssklower if (ddacb_protocol[1] == X25_PROTO_IP || ddacb_protocol[1] == X25_PROTO_X29)
2997*39729Ssklower return (1); /* looks ok */
2998*39729Ssklower else
2999*39729Ssklower return (0); /* bad if not IP or X29 */
3000*39729Ssklower # endif
3001*39729Ssklower #endif DDA_PAD_OR_RAW
3002*39729Ssklower }
3003*39729Ssklower
3004*39729Ssklower
3005*39729Ssklower
3006*39729Ssklower /*@@%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
3007*39729Ssklower /*%% CLEAR_LCN() %%*/
3008*39729Ssklower /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
3009*39729Ssklower /* */
3010*39729Ssklower /* Purpose: */
3011*39729Ssklower /* */
3012*39729Ssklower /* This routine clears an X25 circuit and releases any buffers */
3013*39729Ssklower /* queued for transmission. */
3014*39729Ssklower /* */
3015*39729Ssklower /* Call: clear_lcn(ds, dc) */
3016*39729Ssklower /* Argument: ds: pointer to dev control block struct */
3017*39729Ssklower /* dc: pointer to the Logical Channel control */
3018*39729Ssklower /* block structure */
3019*39729Ssklower /* Returns: nothing */
3020*39729Ssklower /* Called by: ddatimer() */
3021*39729Ssklower /* Calls to: IF_DEQUEUE() */
3022*39729Ssklower /* m_freem() */
3023*39729Ssklower /* send_supr() */
3024*39729Ssklower /* */
3025*39729Ssklower /*##%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
3026*39729Ssklower
3027*39729Ssklower PRIVATE void
clear_lcn(ds,dc)3028*39729Ssklower clear_lcn(ds, dc)
3029*39729Ssklower struct dda_softc *ds;
3030*39729Ssklower struct dda_cb *dc;
3031*39729Ssklower {
3032*39729Ssklower register struct mbuf *m;
3033*39729Ssklower register int s;
3034*39729Ssklower
3035*39729Ssklower #ifdef DDADEBUG
3036*39729Ssklower if (DDADBCH(23, ds->dda_if.if_unit)) {
3037*39729Ssklower DDALOG(LOG_DEBUG) "dda%d: clear_lcn(%d)\n", ds->dda_if.if_unit,
3038*39729Ssklower dc->dc_lcn DDAELOG;
3039*39729Ssklower }
3040*39729Ssklower #endif DDADEBUG
3041*39729Ssklower
3042*39729Ssklower if (dc->dc_state == LC_CLR_PENDING) { /* Unfortunately, we can't
3043*39729Ssklower * display the destination's
3044*39729Ssklower * IP address, as we cleared
3045*39729Ssklower * it when we entered
3046*39729Ssklower * clear-pending state (to
3047*39729Ssklower * prevent new data from
3048*39729Ssklower * being queued to this
3049*39729Ssklower * channel). */
3050*39729Ssklower DMESG(ds->dda_if.if_unit, 37,
3051*39729Ssklower (DDALOG(LOG_ERR) "dda%d: Clear request lost -- lcn %d\n",
3052*39729Ssklower ds->dda_if.if_unit, dc->dc_lcn DDAELOG));
3053*39729Ssklower return;
3054*39729Ssklower }
3055*39729Ssklower hist_lcn_state(ds->dda_if.if_unit, dc->dc_state, LC_CLR_PENDING);
3056*39729Ssklower dc->dc_state = LC_CLR_PENDING; /* set state */
3057*39729Ssklower dc->dc_timer = TMO_CLR_PENDING; /* start clear timer */
3058*39729Ssklower dc->dc_inaddr.s_addr = 0; /* clear associated address */
3059*39729Ssklower dc->dc_key.key_addr.s_addr = 0;
3060*39729Ssklower dc->dc_wsizein = dc->dc_wsizeout = 0;
3061*39729Ssklower dc->dc_pktsizein = dc->dc_pktsizeout = 0;
3062*39729Ssklower /*
3063*39729Ssklower * Raise priority whenever dc_oq is touched.
3064*39729Ssklower */
3065*39729Ssklower s = splimp();
3066*39729Ssklower while (dc->dc_oq.ifq_len) { /* drop any pending data */
3067*39729Ssklower IF_DEQUEUE(&dc->dc_oq, m);
3068*39729Ssklower m_freem(m);
3069*39729Ssklower }
3070*39729Ssklower splx(s);
3071*39729Ssklower send_supr(ds, CLEARLC, (int) dc->dc_lcn * 2, 0); /* send clear msg */
3072*39729Ssklower }
3073*39729Ssklower
3074*39729Ssklower
3075*39729Ssklower
3076*39729Ssklower /*@@%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
3077*39729Ssklower /*%% SEND_RESTART() %%*/
3078*39729Ssklower /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
3079*39729Ssklower /* */
3080*39729Ssklower /* Purpose: */
3081*39729Ssklower /* */
3082*39729Ssklower /* This routine marks all LCNs as being in a restarting state */
3083*39729Ssklower /* and sends a restart command to X25. */
3084*39729Ssklower /* */
3085*39729Ssklower /* Call: send_restart(ds) */
3086*39729Ssklower /* Argument: ds: pointer to dev control block struct */
3087*39729Ssklower /* Returns: nothing */
3088*39729Ssklower /* Called by: ddatimer() */
3089*39729Ssklower /* supr_msg() */
3090*39729Ssklower /* Calls to: IF_DEQUEUE() */
3091*39729Ssklower /* m_freem() */
3092*39729Ssklower /* send_supr() */
3093*39729Ssklower /* */
3094*39729Ssklower /*##%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
3095*39729Ssklower
3096*39729Ssklower PRIVATE void
send_restart(ds)3097*39729Ssklower send_restart(ds)
3098*39729Ssklower struct dda_softc *ds;
3099*39729Ssklower {
3100*39729Ssklower register struct dda_cb *dc;
3101*39729Ssklower register int lcn;
3102*39729Ssklower register int maxlcn;
3103*39729Ssklower
3104*39729Ssklower #ifdef DDADEBUG
3105*39729Ssklower if (DDADBCH(24, ds->dda_if.if_unit)) {
3106*39729Ssklower DDALOG(LOG_DEBUG) "dda%d: send_restart()\n", ds->dda_if.if_unit DDAELOG;
3107*39729Ssklower }
3108*39729Ssklower #endif DDADEBUG
3109*39729Ssklower
3110*39729Ssklower dc = ds->dda_cb;
3111*39729Ssklower /* LCNLINK */
3112*39729Ssklower maxlcn = nddach[ds->dda_if.if_unit];
3113*39729Ssklower for (lcn = 0; lcn <= maxlcn; lcn++) { /* for all LCN's */
3114*39729Ssklower dc->dc_state = LC_RESTART; /* set state */
3115*39729Ssklower dc->dc_timer = TMO_RESTART; /* start restart timeout */
3116*39729Ssklower dc->dc_inaddr.s_addr = 0; /* forget address */
3117*39729Ssklower dc->dc_key.key_addr.s_addr = 0;
3118*39729Ssklower dc->dc_wsizein = dc->dc_wsizeout = 0;
3119*39729Ssklower dc->dc_pktsizein = dc->dc_pktsizeout = 0;
3120*39729Ssklower dc++;
3121*39729Ssklower }
3122*39729Ssklower hist_all_lcns(ds->dda_if.if_unit, LC_RESTART);
3123*39729Ssklower abort_io(ds->dda_if.if_unit, ALL_CHANS);
3124*39729Ssklower send_supr(ds, RESTART, 0, 0); /* send restart msg */
3125*39729Ssklower }
3126*39729Ssklower
3127*39729Ssklower
3128*39729Ssklower
3129*39729Ssklower /*@@%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
3130*39729Ssklower /*%% SEND_SUPR() %%*/
3131*39729Ssklower /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
3132*39729Ssklower /* */
3133*39729Ssklower /* Purpose: */
3134*39729Ssklower /* */
3135*39729Ssklower /* This routine is used to send short (4 bytes only) supervisor */
3136*39729Ssklower /* commands, except that longer ANSWER messages may be sent. */
3137*39729Ssklower /* */
3138*39729Ssklower /* Call: send_supr(ds, cmd, p1, p2) */
3139*39729Ssklower /* Argument: ds: pointer to dev control block struct */
3140*39729Ssklower /* cmd: type of command */
3141*39729Ssklower /* p1: 2nd byte of supervisor message */
3142*39729Ssklower /* p2: 3rd byte of supervisor message */
3143*39729Ssklower /* Returns: nothing */
3144*39729Ssklower /* Called by: supr_msg() */
3145*39729Ssklower /* clear_lcn() */
3146*39729Ssklower /* send_restart() */
3147*39729Ssklower /* Calls to: MGET() */
3148*39729Ssklower /* DDALOG() */
3149*39729Ssklower /* mtod() */
3150*39729Ssklower /* IF_ENQUEUE() */
3151*39729Ssklower /* dda_start() */
3152*39729Ssklower /* */
3153*39729Ssklower /*##%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
3154*39729Ssklower
3155*39729Ssklower PRIVATE void
send_supr(ds,cmd,p1,p2)3156*39729Ssklower send_supr(ds, cmd, p1, p2)
3157*39729Ssklower struct dda_softc *ds;
3158*39729Ssklower int cmd, p1, p2;
3159*39729Ssklower {
3160*39729Ssklower struct mbuf *m;
3161*39729Ssklower register u_char *cp;
3162*39729Ssklower u_char *savcp, *fp, *svcp;
3163*39729Ssklower int i, faclen;
3164*39729Ssklower
3165*39729Ssklower MGET(m, M_DONTWAIT, MT_DATA);
3166*39729Ssklower
3167*39729Ssklower if (m == 0) {
3168*39729Ssklower DMESG(ds->dda_if.if_unit, 23,
3169*39729Ssklower (DDALOG(LOG_ERR) "dda%d: failed to get supr msg bfr!\n",
3170*39729Ssklower ds->dda_if.if_unit DDAELOG));
3171*39729Ssklower return;
3172*39729Ssklower }
3173*39729Ssklower cp = savcp = mtod(m, u_char *);
3174*39729Ssklower
3175*39729Ssklower /* build supervisor message */
3176*39729Ssklower
3177*39729Ssklower *cp++ = (u_char) cmd;
3178*39729Ssklower *cp++ = (u_char) p1;
3179*39729Ssklower *cp++ = (u_char) p2;
3180*39729Ssklower *cp++ = 0;
3181*39729Ssklower
3182*39729Ssklower m->m_len = 4;
3183*39729Ssklower
3184*39729Ssklower if (cmd == ANSWER) {
3185*39729Ssklower register struct dda_cb *dc;
3186*39729Ssklower
3187*39729Ssklower /* for answer messages p1 is (lcn * 2) */
3188*39729Ssklower dc = &(ds->dda_cb[p1 / 2]);
3189*39729Ssklower *cp++ = 0; /* zero length called address */
3190*39729Ssklower *cp++ = 0; /* zero length calling address */
3191*39729Ssklower *cp++ = 0; /* zero length protocol */
3192*39729Ssklower
3193*39729Ssklower /* check and copy facilities */
3194*39729Ssklower faclen = 0;
3195*39729Ssklower svcp = cp++;
3196*39729Ssklower for (i = 0, fp = &ddacb_facilities[1]; i < ddacb_facilities[0];) {
3197*39729Ssklower switch (*fp & 0xc0) {
3198*39729Ssklower case 0x00: /* single octet parameter field */
3199*39729Ssklower i += 2;
3200*39729Ssklower fp += 2;
3201*39729Ssklower break;
3202*39729Ssklower case 0x40: /* double octet parameter field */
3203*39729Ssklower
3204*39729Ssklower /*
3205*39729Ssklower * Note that this code can in some cases attempt to negotiate
3206*39729Ssklower * the packet size or window away from the default, which
3207*39729Ssklower * appears to violate the X.25 spec. In fact, the FEP
3208*39729Ssklower * examines these values and bounds them between the
3209*39729Ssklower * requested value and the default value thus satisfying X.25
3210*39729Ssklower */
3211*39729Ssklower switch (*fp) {
3212*39729Ssklower case X25_FACIL_PKTSIZE: /* 0x42, packet size */
3213*39729Ssklower *cp++ = X25_FACIL_PKTSIZE;
3214*39729Ssklower if (ds->dda_firmrev < 0x21) {
3215*39729Ssklower *cp++ = PKTSIZE_DEF; /* Set incoming and outgoing */
3216*39729Ssklower *cp++ = PKTSIZE_DEF; /* packet size to default */
3217*39729Ssklower dc->dc_pktsizein = dc->dc_pktsizeout = PKTSIZE_DEF;
3218*39729Ssklower } else {
3219*39729Ssklower *cp++ = *(fp + 1); /* Answer with requested */
3220*39729Ssklower *cp++ = *(fp + 2); /* facilities */
3221*39729Ssklower dc->dc_pktsizeout = *(fp + 1);
3222*39729Ssklower dc->dc_pktsizein = *(fp + 2);
3223*39729Ssklower }
3224*39729Ssklower faclen += 3;
3225*39729Ssklower break;
3226*39729Ssklower case X25_FACIL_WINSIZE: /* 0x43, window size */
3227*39729Ssklower *cp++ = X25_FACIL_WINSIZE;
3228*39729Ssklower if (ds->dda_firmrev < 0x21) {
3229*39729Ssklower *cp++ = WINSIZE_DEF; /* Set incoming and outgoing */
3230*39729Ssklower *cp++ = WINSIZE_DEF; /* window size to default */
3231*39729Ssklower dc->dc_wsizein = dc->dc_wsizeout = WINSIZE_DEF;
3232*39729Ssklower } else {
3233*39729Ssklower *cp++ = *(fp + 1); /* Answer with requested */
3234*39729Ssklower *cp++ = *(fp + 2); /* facilities */
3235*39729Ssklower dc->dc_wsizeout = *(fp + 1);
3236*39729Ssklower dc->dc_wsizein = *(fp + 2);
3237*39729Ssklower }
3238*39729Ssklower faclen += 3;
3239*39729Ssklower break;
3240*39729Ssklower }
3241*39729Ssklower i += 3;
3242*39729Ssklower fp += 3;
3243*39729Ssklower break;
3244*39729Ssklower case 0x80: /* triple octet parameter field */
3245*39729Ssklower i += 4;
3246*39729Ssklower fp += 4;
3247*39729Ssklower break;
3248*39729Ssklower case 0xc0: /* variable-length parameter field */
3249*39729Ssklower fp++;
3250*39729Ssklower i += 2 + *fp;
3251*39729Ssklower fp += 1 + *fp;
3252*39729Ssklower break;
3253*39729Ssklower /* Note: No other cases (i.e., default) possible */
3254*39729Ssklower }
3255*39729Ssklower }
3256*39729Ssklower
3257*39729Ssklower if (faclen) { /* Found facilities to negotiate! */
3258*39729Ssklower *svcp = faclen; /* facility length <- faclen */
3259*39729Ssklower *cp++ = 0; /* user data length <- 0 */
3260*39729Ssklower *(savcp + 3) = cp - savcp - 4; /* set supv message length */
3261*39729Ssklower m->m_len = cp - savcp; /* set mbuf message length */
3262*39729Ssklower }
3263*39729Ssklower } /* (end of answer message case) */
3264*39729Ssklower # ifdef DDADEBUG
3265*39729Ssklower if (DDADBCH(25, ds->dda_if.if_unit)) {
3266*39729Ssklower prt_bytes(ds->dda_if.if_unit, "send_supr", savcp, m->m_len);
3267*39729Ssklower }
3268*39729Ssklower #endif DDADEBUG
3269*39729Ssklower start_supr(ds, m);
3270*39729Ssklower }
3271*39729Ssklower
3272*39729Ssklower
3273*39729Ssklower
3274*39729Ssklower /*@@%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
3275*39729Ssklower /*%% START_SUPR() %%*/
3276*39729Ssklower /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
3277*39729Ssklower /* */
3278*39729Ssklower /* Purpose: */
3279*39729Ssklower /* */
3280*39729Ssklower /* Start i/o on the supervisor channel, checking for queue full. */
3281*39729Ssklower /* Added to revision 2.0 so that "queue full" checking would be */
3282*39729Ssklower /* applied uniformly to all supervisory channel output. */
3283*39729Ssklower /* */
3284*39729Ssklower /* Call: start_supr(ds, m) */
3285*39729Ssklower /* Argument: ds: softc structure for board */
3286*39729Ssklower /* m: mbuf holding message */
3287*39729Ssklower /* Returns: nothing */
3288*39729Ssklower /* Called by: send_supr(), send_config(), make_x25_call() */
3289*39729Ssklower /* Calls to: DDALOG(), dda_start(), IF_ENQUEUE() */
3290*39729Ssklower /* */
3291*39729Ssklower /*##%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
3292*39729Ssklower
3293*39729Ssklower PRIVATE void
start_supr(ds,m)3294*39729Ssklower start_supr(ds, m)
3295*39729Ssklower struct dda_softc *ds;
3296*39729Ssklower struct mbuf *m;
3297*39729Ssklower {
3298*39729Ssklower register int s;
3299*39729Ssklower
3300*39729Ssklower
3301*39729Ssklower #ifdef DDADEBUG
3302*39729Ssklower if (DDADBCH(27, ds->dda_if.if_unit))
3303*39729Ssklower DDALOG(LOG_DEBUG) "dda%d: start_supr\n", ds->dda_if.if_unit DDAELOG;
3304*39729Ssklower #endif DDADEBUG
3305*39729Ssklower
3306*39729Ssklower if (IF_QFULL(&(ds->dda_cb[0].dc_oq))) {
3307*39729Ssklower DMESG(ds->dda_if.if_unit, 27,
3308*39729Ssklower (DDALOG(LOG_ERR) "dda%d: supervisory channel overflow (maxlen=%d)\n",
3309*39729Ssklower ds->dda_if.if_unit, ds->dda_cb[0].dc_oq.ifq_maxlen DDAELOG));
3310*39729Ssklower ds->dda_cb[0].dc_oq.ifq_maxlen += ds->dda_cb[0].dc_oq.ifq_maxlen;
3311*39729Ssklower }
3312*39729Ssklower /*
3313*39729Ssklower * Raise priority whenever you touch dc_oq.
3314*39729Ssklower * We do not want to be interrupted in the middle of adding
3315*39729Ssklower * an mbuf to the output queue because the interrupt may indicate
3316*39729Ssklower * a condition that will cause the mbuf to be freed.
3317*39729Ssklower * (The mbufs are freed on receipt of a line status msg, restart,
3318*39729Ssklower * clear, or reset.)
3319*39729Ssklower */
3320*39729Ssklower s = splimp();
3321*39729Ssklower #ifdef DDA_PAD_OR_RAW
3322*39729Ssklower m->m_dat[MLEN - 1] = 0;
3323*39729Ssklower #endif
3324*39729Ssklower IF_ENQUEUE(&(ds->dda_cb[0].dc_oq), m);
3325*39729Ssklower splx(s);
3326*39729Ssklower dda_start(ds, &(ds->dda_cb[0]));
3327*39729Ssklower }
3328*39729Ssklower
3329*39729Ssklower
3330*39729Ssklower /*@@%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
3331*39729Ssklower /*%% ABORT_IO() %%*/
3332*39729Ssklower /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
3333*39729Ssklower /* */
3334*39729Ssklower /* Purpose: */
3335*39729Ssklower /* */
3336*39729Ssklower /* Abort outstanding I/O upon receipt of a line status message, */
3337*39729Ssklower /* restart, clear, or reset. */
3338*39729Ssklower /* The contents of the output queue (dc_oq) is cleared for each */
3339*39729Ssklower /* lcn; all I/O queued on either the read or write queue */
3340*39729Ssklower /* (dc_rchan and dc_wchan) is marked invalid; all I/O queued on */
3341*39729Ssklower /* the sioq is marked invalid; */
3342*39729Ssklower /* */
3343*39729Ssklower /* Call: abort_io() */
3344*39729Ssklower /* Argument: none */
3345*39729Ssklower /* Returns: nothing */
3346*39729Ssklower /* Called by: */
3347*39729Ssklower /* Calls to: IF_DEQUEUE() */
3348*39729Ssklower /* */
3349*39729Ssklower /*##%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
3350*39729Ssklower PRIVATE void
abort_io(unit,lcn)3351*39729Ssklower abort_io(unit, lcn)
3352*39729Ssklower int unit, lcn;
3353*39729Ssklower {
3354*39729Ssklower register struct dda_cb *dc;
3355*39729Ssklower register struct dda_softc *ds = &dda_softc[unit];
3356*39729Ssklower register struct hdx_chan *hc;
3357*39729Ssklower register struct mbuf *m;
3358*39729Ssklower register int lchan;
3359*39729Ssklower register int s;
3360*39729Ssklower register struct hdx_chan *ptr;
3361*39729Ssklower int start, end;
3362*39729Ssklower
3363*39729Ssklower /* set up range of lcns affected */
3364*39729Ssklower if (lcn == ALL_CHANS) {
3365*39729Ssklower start = 1;
3366*39729Ssklower end = nddach[unit];
3367*39729Ssklower } else
3368*39729Ssklower start = end = lcn;
3369*39729Ssklower #ifdef DDADEBUG
3370*39729Ssklower if (DDADBCH(28, unit))
3371*39729Ssklower DDALOG(LOG_DEBUG) "dda%d: abort_io on lcn's %d - %d\n",
3372*39729Ssklower unit, start, end DDAELOG;
3373*39729Ssklower #endif DDADEBUG
3374*39729Ssklower s = splimp();
3375*39729Ssklower /*
3376*39729Ssklower * Invalidate writes on the sioq for specified channel(s)
3377*39729Ssklower */
3378*39729Ssklower if (ptr = ds->dda_sioq.sq_head)
3379*39729Ssklower for (; ptr; ptr = ptr->hc_next) /* scan sioq */
3380*39729Ssklower if ((ptr->hc_chan & 0x01) &&
3381*39729Ssklower ((lcn == ALL_CHANS) || (lcn == ptr->hc_chan >> 1))
3382*39729Ssklower && (ptr->hc_chan != 1)) {
3383*39729Ssklower #ifdef DDADEBUG
3384*39729Ssklower if (DDADBCH(28, unit))
3385*39729Ssklower DDALOG(LOG_DEBUG)
3386*39729Ssklower "dda%d: abort_io--invalidating sioq lcn %d\n",
3387*39729Ssklower unit, ptr->hc_chan >> 1 DDAELOG;
3388*39729Ssklower #endif DDADEBUG
3389*39729Ssklower ptr->hc_inv |= INVALID_MBUF;
3390*39729Ssklower }
3391*39729Ssklower /*
3392*39729Ssklower * For each selected lcn, clear the output queue and
3393*39729Ssklower * add an hdx struct to the sioq that will generate an
3394*39729Ssklower * abort.
3395*39729Ssklower */
3396*39729Ssklower for (lchan = start; lchan <= end; lchan++) { /* for selected LCNs */
3397*39729Ssklower dc = &dda_softc[unit].dda_cb[lchan];
3398*39729Ssklower hc = &dc->dc_wchan;
3399*39729Ssklower while (dc->dc_oq.ifq_len) {
3400*39729Ssklower IF_DEQUEUE(&dc->dc_oq, m);
3401*39729Ssklower m_freem(m);
3402*39729Ssklower }
3403*39729Ssklower
3404*39729Ssklower if (hc->hc_mbuf && !(hc->hc_inv & INVALID_MBUF)) {
3405*39729Ssklower if (dc->dc_flags & DC_OBUSY) { /* output pending */
3406*39729Ssklower #ifdef DDADEBUG
3407*39729Ssklower if (DDADBCH(28, unit))
3408*39729Ssklower DDALOG(LOG_DEBUG)
3409*39729Ssklower "dda%d: abort_io--queueing abort: lcn %d\n",
3410*39729Ssklower unit, lchan DDAELOG;
3411*39729Ssklower #endif DDADEBUG
3412*39729Ssklower
3413*39729Ssklower hc->hc_inv |= INVALID_MBUF;
3414*39729Ssklower hc->hc_func = DDAABT;
3415*39729Ssklower /*
3416*39729Ssklower * Add to the sioq
3417*39729Ssklower */
3418*39729Ssklower dda_wrq(ds, hc, DDAABT);
3419*39729Ssklower }
3420*39729Ssklower }
3421*39729Ssklower }
3422*39729Ssklower splx(s);
3423*39729Ssklower }
3424*39729Ssklower
3425*39729Ssklower #ifdef DDADEBUG
3426*39729Ssklower
3427*39729Ssklower
3428*39729Ssklower /*@@%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
3429*39729Ssklower /*%% PRT_BYTES() %%*/
3430*39729Ssklower /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
3431*39729Ssklower /* */
3432*39729Ssklower /* Purpose: */
3433*39729Ssklower /* */
3434*39729Ssklower /* This routine is used to print a label, followed by the contents of */
3435*39729Ssklower /* a buffer in hex, 16 bytes per line. Each line is preceded by */
3436*39729Ssklower /* the device name and unit number. */
3437*39729Ssklower /* */
3438*39729Ssklower /* Call: prt_bytes(unit, label, bp, cnt) */
3439*39729Ssklower /* Argument: unit: dda unit number to be displayed */
3440*39729Ssklower /* label: pointer to string to be displayed */
3441*39729Ssklower /* bp: pointer to the buffer to be dumped */
3442*39729Ssklower /* cnt: number of bytes in buffer */
3443*39729Ssklower /* Returns: nothing */
3444*39729Ssklower /* Called by: dda_data() */
3445*39729Ssklower /* dda_supr() */
3446*39729Ssklower /* supr_msg() */
3447*39729Ssklower /* Calls to: DDALOG() */
3448*39729Ssklower /* */
3449*39729Ssklower /*##%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
3450*39729Ssklower PRIVATE void
prt_bytes(unit,label,bp,cnt)3451*39729Ssklower prt_bytes(unit, label, bp, cnt)
3452*39729Ssklower int unit;
3453*39729Ssklower char *label;
3454*39729Ssklower u_char *bp;
3455*39729Ssklower int cnt;
3456*39729Ssklower {
3457*39729Ssklower char hexbuf[50]; /* (worst case: 3 * 16 + 1 = 49 bytes) */
3458*39729Ssklower char *p;
3459*39729Ssklower int i;
3460*39729Ssklower static char hex[] = "0123456789abcdef";
3461*39729Ssklower
3462*39729Ssklower DDALOG(LOG_DEBUG) "dda%d: %s\n", unit, label DDAELOG;
3463*39729Ssklower while (cnt > 0) {
3464*39729Ssklower i = (cnt > 16) ? 16 : cnt;
3465*39729Ssklower cnt -= i;
3466*39729Ssklower p = hexbuf;
3467*39729Ssklower while (--i >= 0) {
3468*39729Ssklower *p++ = ' ';
3469*39729Ssklower *p++ = hex[*bp >> 4];
3470*39729Ssklower *p++ = hex[*bp++ & 0x0f];
3471*39729Ssklower }
3472*39729Ssklower *p++ = '\0';
3473*39729Ssklower DDALOG(LOG_DEBUG) "dda%d: %s\n", unit, hexbuf DDAELOG;
3474*39729Ssklower }
3475*39729Ssklower }
3476*39729Ssklower
3477*39729Ssklower #endif
3478*39729Ssklower
3479*39729Ssklower
3480*39729Ssklower
3481*39729Ssklower /*@@%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
3482*39729Ssklower /*%% FMT_X25() %%*/
3483*39729Ssklower /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
3484*39729Ssklower /* */
3485*39729Ssklower /* Purpose: */
3486*39729Ssklower /* */
3487*39729Ssklower /* This routine is used to format an X.25 address for inclusion in */
3488*39729Ssklower /* an error message. The previous return value is invalidated each */
3489*39729Ssklower /* time the function is called, as it is stored in a static buffer */
3490*39729Ssklower /* Note: The X.25 address is apparently sometimes stored in */
3491*39729Ssklower /* BCD, and other times (PDN mode) in ASCII. So we mask */
3492*39729Ssklower /* off the high order bits to make ourselves immune. */
3493*39729Ssklower /* Call: fmt_x25(bp, cnt) */
3494*39729Ssklower /* Argument: bp: pointer to the string */
3495*39729Ssklower /* cnt: number of bytes (usually from address[0]) */
3496*39729Ssklower /* Returns: pointer to an internal buffer containing the string; */
3497*39729Ssklower /* string is 1 to 15 digits, null-terminated. */
3498*39729Ssklower /* Called by: make_x25_call() */
3499*39729Ssklower /* supr_msg() */
3500*39729Ssklower /* convert_x25_addr() */
3501*39729Ssklower /* Calls to: none */
3502*39729Ssklower /* */
3503*39729Ssklower /*##%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
3504*39729Ssklower PRIVATE char *
fmt_x25(bp,cnt)3505*39729Ssklower fmt_x25(bp, cnt)
3506*39729Ssklower register u_char *bp;
3507*39729Ssklower register int cnt;
3508*39729Ssklower {
3509*39729Ssklower char *p;
3510*39729Ssklower static char x25buf[20]; /* worst case is 15 digits plus trailing null */
3511*39729Ssklower
3512*39729Ssklower /* (Don't put this on the stack!) */
3513*39729Ssklower p = x25buf;
3514*39729Ssklower if (cnt >= sizeof(x25buf))
3515*39729Ssklower cnt = sizeof(x25buf) - 1; /* (oops!) */
3516*39729Ssklower while (cnt--)
3517*39729Ssklower *p++ = (*bp++ & 0x0f) + '0';
3518*39729Ssklower *p++ = '\0';
3519*39729Ssklower return (x25buf);
3520*39729Ssklower }
3521*39729Ssklower
3522*39729Ssklower #ifdef DDA_HISTOGRAM
3523*39729Ssklower /*----------------------- HISTOGRAM SUPPORT ---------------------------------*/
3524*39729Ssklower
3525*39729Ssklower
3526*39729Ssklower /* the histogram array */
3527*39729Ssklower struct timeval histogram[NDDA][HISTSIZE];
3528*39729Ssklower
3529*39729Ssklower /* these two structures save the time of the last change in the state of the
3530*39729Ssklower * lcn table or the board status.
3531*39729Ssklower */
3532*39729Ssklower
3533*39729Ssklower struct timeval last_lcn_time[NDDA] = {0L, 0L};
3534*39729Ssklower struct timeval last_brd_time[NDDA] = {0L, 0L};
3535*39729Ssklower
3536*39729Ssklower /* h_lcn_level: the current number of active lcns */
3537*39729Ssklower int h_lcn_level[NDDA] = {0};
3538*39729Ssklower
3539*39729Ssklower /*#define DDA_HIST_DEBUG 1 /* set this to debug history features */
3540*39729Ssklower
3541*39729Ssklower
3542*39729Ssklower /*@@%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
3543*39729Ssklower /*%% HIST_INIT() %%*/
3544*39729Ssklower /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
3545*39729Ssklower /* */
3546*39729Ssklower /* Purpose: */
3547*39729Ssklower /* */
3548*39729Ssklower /* This routine initializes the histogram facility when coming up or */
3549*39729Ssklower /* after a reset. */
3550*39729Ssklower /* Call: hist_init(unit,reset) */
3551*39729Ssklower /* Argument: unit - board number to initialize. */
3552*39729Ssklower /* reset - set to 1 to force an init. */
3553*39729Ssklower /* Returns: nothing. */
3554*39729Ssklower /* Called by: ddaioctl() */
3555*39729Ssklower /* Calls to: microtime() */
3556*39729Ssklower /* */
3557*39729Ssklower /*##%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
3558*39729Ssklower
3559*39729Ssklower PRIVATE void
hist_init(unit,reset)3560*39729Ssklower hist_init(unit, reset)
3561*39729Ssklower int unit;
3562*39729Ssklower int reset;
3563*39729Ssklower {
3564*39729Ssklower int s;
3565*39729Ssklower register int i;
3566*39729Ssklower struct dda_cb *dc;
3567*39729Ssklower
3568*39729Ssklower if (last_lcn_time[unit].tv_sec != 0L && !reset)
3569*39729Ssklower return; /* histogram for this unit already enabled */
3570*39729Ssklower bzero(histogram[unit], sizeof(struct timeval) * HISTSIZE);
3571*39729Ssklower h_lcn_level[unit] = 0;
3572*39729Ssklower dc = dda_softc[unit].dda_cb;
3573*39729Ssklower s = splimp();
3574*39729Ssklower for (i = 0; i < NDDACH + 1; i++) {
3575*39729Ssklower if (dc++->dc_state == LC_DATA_IDLE)
3576*39729Ssklower h_lcn_level[unit]++;
3577*39729Ssklower }
3578*39729Ssklower splx(s);
3579*39729Ssklower microtime(&histogram[unit][H_START]);
3580*39729Ssklower #ifdef DDA_HIST_DEBUG
3581*39729Ssklower DDALOG(LOG_DEBUG) "hist_init: starting at level %d\n",
3582*39729Ssklower h_lcn_level[unit] DDAELOG;
3583*39729Ssklower #endif
3584*39729Ssklower }
3585*39729Ssklower
3586*39729Ssklower
3587*39729Ssklower
3588*39729Ssklower /*@@%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
3589*39729Ssklower /*%% HIST_LCN_STATE() %%*/
3590*39729Ssklower /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
3591*39729Ssklower /* */
3592*39729Ssklower /* Purpose: */
3593*39729Ssklower /* */
3594*39729Ssklower /* This routine changes the histogram depending on how the state of */
3595*39729Ssklower /* a channel has changed. */
3596*39729Ssklower /* Call: hist_lcn_state(unit, old_state, new_state) */
3597*39729Ssklower /* Argument: old_state: the old state of the lcn. */
3598*39729Ssklower /* new_state: the state the lcn is changing to. */
3599*39729Ssklower /* unit: unit this applies to */
3600*39729Ssklower /* Returns: nothing. */
3601*39729Ssklower /* Called by: */
3602*39729Ssklower /* Calls to: timevalsub(), timevaladd(), microtime() */
3603*39729Ssklower /* */
3604*39729Ssklower /*##%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
3605*39729Ssklower
3606*39729Ssklower PRIVATE void
hist_lcn_state(unit,old_state,new_state)3607*39729Ssklower hist_lcn_state(unit, old_state, new_state)
3608*39729Ssklower int unit;
3609*39729Ssklower u_char old_state;
3610*39729Ssklower u_char new_state;
3611*39729Ssklower {
3612*39729Ssklower struct timeval tv, tmpv;
3613*39729Ssklower
3614*39729Ssklower /*
3615*39729Ssklower * this structure for determining state transitions is much more general
3616*39729Ssklower * than is necessary right now. However it allows easy changes to the
3617*39729Ssklower * state transition table for the histogram so I will leave it in until
3618*39729Ssklower * it settles down
3619*39729Ssklower */
3620*39729Ssklower switch (old_state) {
3621*39729Ssklower case LC_DATA_IDLE:
3622*39729Ssklower switch (new_state) {
3623*39729Ssklower case LC_DATA_IDLE:
3624*39729Ssklower break;
3625*39729Ssklower default: /* all other states */
3626*39729Ssklower microtime(&tv);
3627*39729Ssklower tmpv = tv;
3628*39729Ssklower timevalsub(&tv, &last_lcn_time[unit]);
3629*39729Ssklower #ifdef DDA_HIST_DEBUG
3630*39729Ssklower DDALOG(LOG_DEBUG) "hist_lcn_state: adding %ld.%ld to level %d--\n",
3631*39729Ssklower tv.tv_sec, tv.tv_usec, h_lcn_level[unit] DDAELOG;
3632*39729Ssklower #endif
3633*39729Ssklower timevaladd(&histogram[unit][h_lcn_level[unit]], &tv);
3634*39729Ssklower last_lcn_time[unit] = tmpv;
3635*39729Ssklower if (--h_lcn_level[unit] < 0) /* safety net for driver
3636*39729Ssklower * errors */
3637*39729Ssklower h_lcn_level[unit] = 0;
3638*39729Ssklower break;
3639*39729Ssklower }
3640*39729Ssklower break;
3641*39729Ssklower default:
3642*39729Ssklower switch (new_state) {
3643*39729Ssklower case LC_DATA_IDLE:
3644*39729Ssklower microtime(&tv);
3645*39729Ssklower tmpv = tv;
3646*39729Ssklower timevalsub(&tv, &last_lcn_time[unit]);
3647*39729Ssklower #ifdef DDA_HIST_DEBUG
3648*39729Ssklower DDALOG(LOG_DEBUG) "hist_lcn_state: adding %ld.%ld to level %d++\n",
3649*39729Ssklower tv.tv_sec, tv.tv_usec, h_lcn_level[unit] DDAELOG;
3650*39729Ssklower #endif
3651*39729Ssklower timevaladd(&histogram[unit][h_lcn_level[unit]], &tv);
3652*39729Ssklower last_lcn_time[unit] = tmpv;
3653*39729Ssklower if (++h_lcn_level[unit] > NDDACH) /* safety net for driver
3654*39729Ssklower * errors */
3655*39729Ssklower h_lcn_level[unit] = NDDACH;
3656*39729Ssklower break;
3657*39729Ssklower default: /* all other states */
3658*39729Ssklower break;
3659*39729Ssklower }
3660*39729Ssklower break;
3661*39729Ssklower }
3662*39729Ssklower }
3663*39729Ssklower
3664*39729Ssklower
3665*39729Ssklower
3666*39729Ssklower /*@@%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
3667*39729Ssklower /*%% HIST_ALL_LCNS() %%*/
3668*39729Ssklower /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
3669*39729Ssklower /* */
3670*39729Ssklower /* Purpose: */
3671*39729Ssklower /* */
3672*39729Ssklower /* This routine changes the histogram when the state of all the lcns */
3673*39729Ssklower /* are changed as a group. */
3674*39729Ssklower /* Call: hist_lcn_state(unit, state) */
3675*39729Ssklower /* Argument: state: state that all lcn are going to. Currently not*/
3676*39729Ssklower /* used. */
3677*39729Ssklower /* unit: unit this applies to */
3678*39729Ssklower /* Returns: nothing. */
3679*39729Ssklower /* Called by: */
3680*39729Ssklower /* Calls to: timevalsub(), timevaladd(), microtime() */
3681*39729Ssklower /* */
3682*39729Ssklower /*##%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
3683*39729Ssklower
3684*39729Ssklower PRIVATE void
hist_all_lcns(unit,state)3685*39729Ssklower hist_all_lcns(unit, state)
3686*39729Ssklower int unit, state;
3687*39729Ssklower {
3688*39729Ssklower struct timeval tmpv, tv;
3689*39729Ssklower
3690*39729Ssklower #ifdef lint
3691*39729Ssklower state = state;
3692*39729Ssklower #endif
3693*39729Ssklower if (last_brd_time[unit].tv_sec == 0L
3694*39729Ssklower || last_lcn_time[unit].tv_sec == 0L)
3695*39729Ssklower return; /* see if we have initialized yet */
3696*39729Ssklower microtime(&tv);
3697*39729Ssklower tmpv = tv;
3698*39729Ssklower timevalsub(&tv, &last_lcn_time[unit]);
3699*39729Ssklower #ifdef DDA_HIST_DEBUG
3700*39729Ssklower DDALOG(LOG_DEBUG) "hist_all_lcns: adding %ld.%ld to level %d\n",
3701*39729Ssklower tv.tv_sec, tv.tv_usec, h_lcn_level[unit] DDAELOG;
3702*39729Ssklower #endif
3703*39729Ssklower timevaladd(&histogram[unit][h_lcn_level[unit]], &tv);
3704*39729Ssklower last_lcn_time[unit] = tmpv;
3705*39729Ssklower h_lcn_level[unit] = 0;
3706*39729Ssklower }
3707*39729Ssklower
3708*39729Ssklower
3709*39729Ssklower
3710*39729Ssklower /*@@%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
3711*39729Ssklower /*%% HIST_LINK_STATE() %%*/
3712*39729Ssklower /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
3713*39729Ssklower /* */
3714*39729Ssklower /* Purpose: */
3715*39729Ssklower /* */
3716*39729Ssklower /* This routine changes the histogram depending on how the state of */
3717*39729Ssklower /* the link has changed. */
3718*39729Ssklower /* Call: hist_link_state(old_state, new_state) */
3719*39729Ssklower /* Argument: old_state: the old state of the link. */
3720*39729Ssklower /* new_state: the state the link is changing to. */
3721*39729Ssklower /* unit: unit this applies to */
3722*39729Ssklower /* Returns: nothing. */
3723*39729Ssklower /* Called by: */
3724*39729Ssklower /* Calls to: timevalsub(), timevaladd(), microtime() */
3725*39729Ssklower /* */
3726*39729Ssklower /*##%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
3727*39729Ssklower
3728*39729Ssklower PRIVATE void
hist_link_state(unit,old_state,new_state)3729*39729Ssklower hist_link_state(unit, old_state, new_state)
3730*39729Ssklower int unit;
3731*39729Ssklower u_char old_state;
3732*39729Ssklower u_char new_state;
3733*39729Ssklower {
3734*39729Ssklower struct timeval tv, tmpv;
3735*39729Ssklower
3736*39729Ssklower /*
3737*39729Ssklower * this structure for determining state transitions is much more general
3738*39729Ssklower * than is necessary right now. However it allows easy changes to the
3739*39729Ssklower * state transition table for the histogram so I will leave it in until
3740*39729Ssklower * it settles down
3741*39729Ssklower */
3742*39729Ssklower switch (old_state) {
3743*39729Ssklower case S_LINK_UP:
3744*39729Ssklower switch (new_state) {
3745*39729Ssklower case S_LINK_UP:
3746*39729Ssklower break;
3747*39729Ssklower default: /* all other states */
3748*39729Ssklower #ifdef DDA_HIST_DEBUG
3749*39729Ssklower DDALOG(LOG_DEBUG) "hist_link_state: link down\n" DDAELOG;
3750*39729Ssklower #endif
3751*39729Ssklower microtime(&tv);
3752*39729Ssklower tmpv = tv;
3753*39729Ssklower timevalsub(&tv, &last_lcn_time[unit]);
3754*39729Ssklower timevaladd(&histogram[unit][h_lcn_level[unit]], &tv);
3755*39729Ssklower tv = tmpv;
3756*39729Ssklower timevalsub(&tv, &last_brd_time[unit]);
3757*39729Ssklower timevaladd(&histogram[unit][H_LINK_UP], &tv);
3758*39729Ssklower last_brd_time[unit].tv_sec = 0L;
3759*39729Ssklower break;
3760*39729Ssklower }
3761*39729Ssklower break;
3762*39729Ssklower default: /* all other states */
3763*39729Ssklower switch (new_state) {
3764*39729Ssklower case S_LINK_UP:
3765*39729Ssklower #ifdef DDA_HIST_DEBUG
3766*39729Ssklower DDALOG(LOG_DEBUG) "hist_link_state: link up\n" DDAELOG;
3767*39729Ssklower #endif
3768*39729Ssklower microtime(&last_brd_time[unit]);
3769*39729Ssklower
3770*39729Ssklower /*
3771*39729Ssklower * reset last_lcn_time so 0 entry will not accumulate the time
3772*39729Ssklower * that we were down
3773*39729Ssklower */
3774*39729Ssklower last_lcn_time[unit] = last_brd_time[unit];
3775*39729Ssklower break;
3776*39729Ssklower default:
3777*39729Ssklower break;
3778*39729Ssklower }
3779*39729Ssklower break;
3780*39729Ssklower }
3781*39729Ssklower }
3782*39729Ssklower
3783*39729Ssklower
3784*39729Ssklower
3785*39729Ssklower /*@@%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
3786*39729Ssklower /*%% HIST_READ() %%*/
3787*39729Ssklower /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
3788*39729Ssklower /* */
3789*39729Ssklower /* Purpose: */
3790*39729Ssklower /* */
3791*39729Ssklower /* This routine prepares the histogram table for reading by making */
3792*39729Ssklower /* all entries current. */
3793*39729Ssklower /* Call: hist_read(unit) */
3794*39729Ssklower /* Argument: unit : board to use. */
3795*39729Ssklower /* Returns: nothing */
3796*39729Ssklower /* Called by: ddaioctl() */
3797*39729Ssklower /* Calls to: timevalsub(), timevaladd(), microtime() */
3798*39729Ssklower /* */
3799*39729Ssklower /*##%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
3800*39729Ssklower
3801*39729Ssklower PRIVATE void
hist_read(unit)3802*39729Ssklower hist_read(unit)
3803*39729Ssklower int unit;
3804*39729Ssklower {
3805*39729Ssklower struct timeval tmpv, tv;
3806*39729Ssklower
3807*39729Ssklower microtime(&tv);
3808*39729Ssklower tmpv = tv;
3809*39729Ssklower histogram[unit][H_END] = tmpv;
3810*39729Ssklower histogram[unit][H_TMO].tv_sec = tmo_data_idle * DDA_TIMEOUT;
3811*39729Ssklower histogram[unit][H_TMO].tv_usec = 0L;
3812*39729Ssklower if (last_brd_time[unit].tv_sec) {
3813*39729Ssklower timevalsub(&tv, &last_lcn_time[unit]);
3814*39729Ssklower #ifdef DDA_HIST_DEBUG
3815*39729Ssklower DDALOG(LOG_DEBUG) "hist_read: adding %ld.%ld to level %d\n",
3816*39729Ssklower tv.tv_sec, tv.tv_usec, h_lcn_level[unit] DDAELOG;
3817*39729Ssklower #endif
3818*39729Ssklower timevaladd(&histogram[unit][h_lcn_level[unit]], &tv);
3819*39729Ssklower last_lcn_time[unit] = tmpv;
3820*39729Ssklower tv = tmpv;
3821*39729Ssklower timevalsub(&tv, &last_brd_time[unit]);
3822*39729Ssklower timevaladd(&histogram[unit][H_LINK_UP], &tv);
3823*39729Ssklower last_brd_time[unit] = tmpv;
3824*39729Ssklower }
3825*39729Ssklower }
3826*39729Ssklower
3827*39729Ssklower
3828*39729Ssklower
3829*39729Ssklower /*@@%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
3830*39729Ssklower /*%% HIST_COPYOUT() %%*/
3831*39729Ssklower /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
3832*39729Ssklower /* */
3833*39729Ssklower /* Purpose: */
3834*39729Ssklower /* */
3835*39729Ssklower /* This routine prepares the histogram table for reading by making */
3836*39729Ssklower /* all entries current. */
3837*39729Ssklower /* Call: hist_copyout(unit, to) */
3838*39729Ssklower /* Argument: unit : board to use. */
3839*39729Ssklower /* to : address in user space to copy to. */
3840*39729Ssklower /* Returns: return value from copyout */
3841*39729Ssklower /* Called by: ddaioctl() */
3842*39729Ssklower /* Calls to: copyout() */
3843*39729Ssklower /* */
3844*39729Ssklower /*##%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
3845*39729Ssklower
3846*39729Ssklower PRIVATE int
hist_copyout(unit,to)3847*39729Ssklower hist_copyout(unit, to)
3848*39729Ssklower int unit;
3849*39729Ssklower caddr_t to;
3850*39729Ssklower {
3851*39729Ssklower return ((copyout(histogram[unit], to, sizeof(struct timeval) * HISTSIZE)));
3852*39729Ssklower }
3853*39729Ssklower
3854*39729Ssklower #endif DDA_HISTOGRAM
3855*39729Ssklower
3856*39729Ssklower #ifdef DDA_PAD_OR_RAW
3857*39729Ssklower
3858*39729Ssklower #if ACC_BSD > 42
3859*39729Ssklower # include "uba.h"
3860*39729Ssklower # include "bk.h"
3861*39729Ssklower # include "conf.h"
3862*39729Ssklower # include "proc.h"
3863*39729Ssklower # include "tty.h"
3864*39729Ssklower # include "map.h"
3865*39729Ssklower # include "vm.h"
3866*39729Ssklower # include "bkmac.h"
3867*39729Ssklower # include "clist.h"
3868*39729Ssklower # include "file.h"
3869*39729Ssklower # include "uio.h"
3870*39729Ssklower #endif
3871*39729Ssklower
3872*39729Ssklower #if ACC_BSD == 42 || ACC_ULTRIX > 00
3873*39729Ssklower # include "bk.h"
3874*39729Ssklower # include "../h/conf.h"
3875*39729Ssklower # include "../h/proc.h"
3876*39729Ssklower # include "../h/tty.h"
3877*39729Ssklower # include "../h/map.h"
3878*39729Ssklower # include "../h/vm.h"
3879*39729Ssklower # if ACC_ULTRIX > 12
3880*39729Ssklower # include "uba.h"
3881*39729Ssklower # endif
3882*39729Ssklower # include "../h/bk.h"
3883*39729Ssklower # ifdef SIMULATION
3884*39729Ssklower # include "Clist.h"
3885*39729Ssklower # else
3886*39729Ssklower # include "../h/clist.h"
3887*39729Ssklower # endif
3888*39729Ssklower # include "../h/file.h"
3889*39729Ssklower # include "../h/uio.h"
3890*39729Ssklower #endif
3891*39729Ssklower
3892*39729Ssklower PRIVATE int
dda_decode_type(ds,p)3893*39729Ssklower dda_decode_type(ds, p)
3894*39729Ssklower struct dda_softc *ds;
3895*39729Ssklower u_char *p;
3896*39729Ssklower {
3897*39729Ssklower register u_char *cp;
3898*39729Ssklower int i, usrlen;
3899*39729Ssklower
3900*39729Ssklower #ifdef DDADEBUG
3901*39729Ssklower if (DDADBCH(20, ds->dda_if.if_unit)) {
3902*39729Ssklower printf(" dda_decode_type(): p[0]= %x ", *p);
3903*39729Ssklower }
3904*39729Ssklower #endif DDADEBUG
3905*39729Ssklower
3906*39729Ssklower switch (p[0]) {
3907*39729Ssklower case LINE_STATUS: /* link status msg */
3908*39729Ssklower case RESTART: /* restart received */
3909*39729Ssklower case RSTRT_ACK: /* restart ack */
3910*39729Ssklower case STATRESP: /* Statistics Response from FEP */
3911*39729Ssklower case CLEARVC: /* clear by VCN */
3912*39729Ssklower return (0);
3913*39729Ssklower case RESET: /* X25 reset */
3914*39729Ssklower return (1);
3915*39729Ssklower case ANSWER:
3916*39729Ssklower case CLEARLC:
3917*39729Ssklower case INTERRUPT:
3918*39729Ssklower case INTR_ACK:
3919*39729Ssklower i = p[1] / 2; /* get lcn */
3920*39729Ssklower if (ds->dda_cb[i].dc_flags & (DC_X29 | DC_X29W))
3921*39729Ssklower return (1);
3922*39729Ssklower else if (ds->dda_cb[i].dc_flags & (DC_RAW))
3923*39729Ssklower return (2);
3924*39729Ssklower else
3925*39729Ssklower return (0);
3926*39729Ssklower }
3927*39729Ssklower if (p[0] != RING) { /* let standard dda handle it */
3928*39729Ssklower return (0);
3929*39729Ssklower }
3930*39729Ssklower cp = p + 4; /* skip over code, lcn, vcn and count in
3931*39729Ssklower * (ring?) answer message */
3932*39729Ssklower /* cp now points to length of called address */
3933*39729Ssklower cp += *cp + 1; /* skip over called address and length byte */
3934*39729Ssklower /* cp now points to length of calling address */
3935*39729Ssklower cp += *cp + 1; /* skip over calling address and length byte */
3936*39729Ssklower /* cp now points to length of protocol */
3937*39729Ssklower if (*cp == 0)
3938*39729Ssklower return (0);
3939*39729Ssklower
3940*39729Ssklower usrlen = *cp++;
3941*39729Ssklower if (usrlen) {
3942*39729Ssklower #ifdef DDA_RAWOPT
3943*39729Ssklower if (pi_circuit_to_handle_protocol(*cp))
3944*39729Ssklower return (2);
3945*39729Ssklower #endif
3946*39729Ssklower #ifdef DDADEBUG
3947*39729Ssklower if (DDADBCH(20, ds->dda_if.if_unit)) {
3948*39729Ssklower printf(" dda_decode_type(): return value = %x ", *cp);
3949*39729Ssklower }
3950*39729Ssklower #endif DDADEBUG
3951*39729Ssklower switch (*cp) {
3952*39729Ssklower case X25_PROTO_IP:
3953*39729Ssklower return (0);
3954*39729Ssklower case X25_PROTO_X29:
3955*39729Ssklower return (1);
3956*39729Ssklower default:
3957*39729Ssklower return (2);
3958*39729Ssklower }
3959*39729Ssklower } else
3960*39729Ssklower return (0);
3961*39729Ssklower }
3962*39729Ssklower #endif DDA_PAD_OR_RAW
3963*39729Ssklower
3964*39729Ssklower #ifdef SIMULATION
3965*39729Ssklower # ifdef DDA_PADOPT
3966*39729Ssklower # include "if_x29.c"
3967*39729Ssklower # endif
3968*39729Ssklower # ifdef DDA_RAWOPT
3969*39729Ssklower # include "if_pi.c"
3970*39729Ssklower # endif
3971*39729Ssklower #else
3972*39729Ssklower # ifdef DDA_PADOPT
3973*39729Ssklower # if ACC_VMS > 00
3974*39729Ssklower # include "../vaxif/if_vmsx29.c"
3975*39729Ssklower # else
3976*39729Ssklower # include "../vaxif/if_x29.c"
3977*39729Ssklower # endif
3978*39729Ssklower # endif
3979*39729Ssklower # ifdef DDA_RAWOPT
3980*39729Ssklower # include "../vaxif/if_pi.c"
3981*39729Ssklower # endif
3982*39729Ssklower #endif
3983*39729Ssklower
3984*39729Ssklower #ifdef DDA_MSGQ
3985*39729Ssklower u_char ddamsgq[MSGQSIZE];
3986*39729Ssklower PRIVATE u_char *mqptr = 0;
3987*39729Ssklower
3988*39729Ssklower #define MSGQEND (ddamsgq+MSGQSIZE)
3989*39729Ssklower
dda_mqstr(s)3990*39729Ssklower dda_mqstr(s)
3991*39729Ssklower char *s;
3992*39729Ssklower {
3993*39729Ssklower if (mqptr == 0)
3994*39729Ssklower mqptr = ddamsgq;
3995*39729Ssklower while (*s) {
3996*39729Ssklower *mqptr++ = *s++;
3997*39729Ssklower if (mqptr >= MSGQEND)
3998*39729Ssklower mqptr = ddamsgq;
3999*39729Ssklower }
4000*39729Ssklower *mqptr = '\0';
4001*39729Ssklower }
4002*39729Ssklower
dda_mqnum(num,type)4003*39729Ssklower dda_mqnum(num, type)
4004*39729Ssklower int num, type;
4005*39729Ssklower {
4006*39729Ssklower if (mqptr == 0)
4007*39729Ssklower mqptr = ddamsgq;
4008*39729Ssklower if ((mqptr + sizeof(int) + 2) >= MSGQEND)
4009*39729Ssklower mqptr = ddamsgq;
4010*39729Ssklower *mqptr++ = type;
4011*39729Ssklower *((int *) mqptr) = num;
4012*39729Ssklower mqptr += sizeof(int);
4013*39729Ssklower *mqptr = '\0';
4014*39729Ssklower }
4015*39729Ssklower
4016*39729Ssklower #endif DDA_MSGQ
4017*39729Ssklower
4018*39729Ssklower /* link in support for steve's test-jig */
4019*39729Ssklower #ifdef SIMULATION
4020*39729Ssklower #include "if_dda_sim.c"
4021*39729Ssklower #endif
4022*39729Ssklower
4023*39729Ssklower /*
4024*39729Ssklower Revision History:
4025*39729Ssklower
4026*39729Ssklower 18-Dec-87: V3.0 - Brad Engstrom
4027*39729Ssklower Added the -t flag to acpconfig and the 't' case in ddaioctl to allow
4028*39729Ssklower setting of the idle circuit timeout.
4029*39729Ssklower The constant TMO_DATA_IDLE was changed to a variable called
4030*39729Ssklower tmo_data_idle.
4031*39729Ssklower 11-Mar-88: V3.0 - Brad Engstrom
4032*39729Ssklower Modified the history routine to return the current value of the
4033*39729Ssklower timeout. Also fixed bug so that level 0 records amount of time 0
4034*39729Ssklower circuits were in use only when link is up.
4035*39729Ssklower 11-Mar-88: V3.0 - Brad Engstrom
4036*39729Ssklower Changed handling of supervisor channel overflows to double the max q
4037*39729Ssklower length each time it overflows. This Will prevent a flood of console
4038*39729Ssklower messages while still notifying the user that there has been an
4039*39729Ssklower overflow.
4040*39729Ssklower 21-Mar-88: V3.0 - Brad Engstrom
4041*39729Ssklower Fixed bug in writing the facilities field for packet and window size
4042*39729Ssklower negotiation. This was in the routine make X.25 call. Previously
4043*39729Ssklower constants were used to index into the facilities buffer now offsets
4044*39729Ssklower from the current facilities length are used.
4045*39729Ssklower 12-Apr-88: V3.0 - Brad Engstrom
4046*39729Ssklower Added ability to handle class b and class c addressing. The changes
4047*39729Ssklower affect locate_x25_lcn, convert_x25_addr, and convert_ip_addr. The
4048*39729Ssklower modifications came from fixes sent to Wollongong by Lars Poulson.
4049*39729Ssklower 12-Apr-88: V3.0 - Brad Engstrom
4050*39729Ssklower Made modifications so the driver will work under Ultrix or BSD. In
4051*39729Ssklower cases where there are differences between 4.3 and 4.2 bsd (shown by
4052*39729Ssklower #ifdef BSD4_3) Ultrix 1.2 is exactly like a 4.2 system. Ultrix 2.0 is
4053*39729Ssklower like 4.3 in most cases. New macros were added to distinquish between
4054*39729Ssklower systems. These are BSD4_2 and BSD43_OR_ULTRIX20.
4055*39729Ssklower 13-Apr-88: V3.0 - Brad Engstrom
4056*39729Ssklower ddareset() was called from ddaintb without arguments. This could
4057*39729Ssklower cause ddareset to return without doing anything. Proper arguments were
4058*39729Ssklower inserted. In ddaioctl the priority level s may be used without being
4059*39729Ssklower set. This was fixed.
4060*39729Ssklower 18-Apr-88: V3.0 - Brad Engstrom
4061*39729Ssklower Added the use of a key field in the dda_cb structure. Previously the
4062*39729Ssklower dc_inaddr field was used both for printing the ip address (-l command)
4063*39729Ssklower and for searching for circuits that were open to a destination. Using
4064*39729Ssklower this for a cicuit matching address means that the network and local
4065*39729Ssklower host fields needed to be masked off, thus making this field less
4066*39729Ssklower usefull for printing. Now two fields are used dc_inaddr is used for
4067*39729Ssklower printing. dc_key is used for circuit matching. In PDN mode the
4068*39729Ssklower full ip address is used as the key. In DDN mode just the imp number
4069*39729Ssklower and host(port) number are used.
4070*39729Ssklower 18-Apr-88: V3.0 - Brad Engstrom
4071*39729Ssklower Made histogram facilities a compile time option. The histogram is
4072*39729Ssklower enabled if DDA_HISTOGRAM is defined. The facilities are always
4073*39729Ssklower disabled when using 4.2 or ULTRIX 1.2 as the kernel does not have the
4074*39729Ssklower proper support routines available.
4075*39729Ssklower 22-Apr-88: V3.0 - Brad Engstrom
4076*39729Ssklower Added new option to -v command to set the dda_db_unit variable.
4077*39729Ssklower 22-Apr-88: V3.0 - Brad Engstrom
4078*39729Ssklower Added the DMESG macro and the msgbits array to allow selective
4079*39729Ssklower disabling of driver error messages. To enable or disable an error
4080*39729Ssklower message the -c command of acpconfig is used. The msgbits array holds
4081*39729Ssklower info about whether each message is enabled or disabled. Setting a bit
4082*39729Ssklower to 1 disables a message. Clearing a bit to 0 enables a message.
4083*39729Ssklower All messages start as enabled.
4084*39729Ssklower 22-Apr-88: V3.0 - Brad Engstrom
4085*39729Ssklower Added check for DDAMAINT_BRD in probe routine. If DDAMAINT_BRD is
4086*39729Ssklower defined then assume we are using a maintenence board so don't try to
4087*39729Ssklower find the firmware id because it won't be there. Fake info that was
4088*39729Ssklower supposed to be contained in the firmware id.
4089*39729Ssklower 25-Apr-88: V3.0 - Brad Engstrom
4090*39729Ssklower Added check in locate_x25_lcn to see if state of lc is LC_CALL_PENDING
4091*39729Ssklower or LC_DATA_IDLE in the loop that looks for an already open lc. This
4092*39729Ssklower will prevent an address of 0.0.0.0 from matching a circuit that is not
4093*39729Ssklower in use. If the address is invalid then the imp will kick it out.
4094*39729Ssklower 26-Apr-88: V3.0 - Brad Engstrom
4095*39729Ssklower Changed the -n command case so that a command of the form "-n 0" will
4096*39729Ssklower return the number of channels currently available. This will be used
4097*39729Ssklower by the -l command and possible by the -h command to determine the
4098*39729Ssklower number of available circuits.
4099*39729Ssklower 10-May-88: V3.0 - Brad Engstrom
4100*39729Ssklower Made all occurences of the length of and X.25 address refer to the
4101*39729Ssklower constants MAXADDRLEN and MINADDRLEN defined in if_ddavar.h. These
4102*39729Ssklower constants include the 1 byte for encoding the length.
4103*39729Ssklower 02-Jun-88: V3.0 - Brad Engstrom
4104*39729Ssklower Change the check for the firmware revision level to 2.2 for the -e
4105*39729Ssklower command. This command will crash [56]250s that don't have at least
4106*39729Ssklower v2.2 firmware.
4107*39729Ssklower 12-Jul-88: V3.0 - Brad Engstrom
4108*39729Ssklower Deleted case for class_b_c addressing.
4109*39729Ssklower 20-Jul-88: V3.0 - Brad Engstrom
4110*39729Ssklower Fixed bug in parsing facilities that would cause the kernel to hang.
4111*39729Ssklower The bug was not incrmenting pointers when an urecognized 2 octet
4112*39729Ssklower facility was seen. Fixes were applied to send_supr() and
4113*39729Ssklower decode_answer()
4114*39729Ssklower 30-Aug-88: V4.0 - Brad Engstrom
4115*39729Ssklower Modified driver to support X.29 and a programmers interface. Includes
4116*39729Ssklower files if_x29.c, if_pi.c, and if_pivar.h
4117*39729Ssklower 30-Aug-88: V4.0 - Brad Engstrom
4118*39729Ssklower Added support for debug logging under the control of the DDA_MSGQ
4119*39729Ssklower define. Information is extracted using the new -p command of
4120*39729Ssklower acpconfig.
4121*39729Ssklower 30-Aug-88: V4.0 - Brad Engstrom
4122*39729Ssklower Modified start_chan to check the ready bit before touching the
4123*39729Ssklower comregs. Also modified dda_rrq and dda_wrq to raise ipl before
4124*39729Ssklower touching the sioq. These changes fixed a bug where the FE was losing
4125*39729Ssklower I/O requests.
4126*39729Ssklower 20-Oct-88: V4.0 - Steve Johnson
4127*39729Ssklower Added SIMULATION #ifdef for simulation support
4128*39729Ssklower 08-Jan-89: V4.1 - Steve Johnson
4129*39729Ssklower MERGE 4.0 and 3.1
4130*39729Ssklower 10-Oct-88: V3.1 - Charles Carvalho
4131*39729Ssklower Replace prt_x25 with fmt_x25, which returns a pointer to a formatted
4132*39729Ssklower message instead of printing its data; this allows error messages to be
4133*39729Ssklower output with a single call to DDALOG (or syslog). Move prt_addr
4134*39729Ssklower inline, for same reason. Add IP address to some error messages;
4135*39729Ssklower trim excess text from some error messages. Allocate channels
4136*39729Ssklower for incoming calls from lowest channel up; we do linear searches of
4137*39729Ssklower the lcn table, so it's to our advantage to use the lowest numbers for
4138*39729Ssklower all active circuits. (The lcn is not related to the virtual circuit
4139*39729Ssklower number, so there is no need to allocate incoming channels from the
4140*39729Ssklower top down.) Modify prt_bytes to take unit number and descriptive
4141*39729Ssklower string to be printed along with the buffer and byte count; it now
4142*39729Ssklower formats up to 16 bytes at a time and prints a full line with each call
4143*39729Ssklower to DDALOG rather than calling DDALOG for each byte.
4144*39729Ssklower 17-Oct-88: V3.1 - Charles Carvalho
4145*39729Ssklower Add definitions for DDALOG and DDAELOG, which translate into a call to
4146*39729Ssklower DDALOG() or log().
4147*39729Ssklower 26-Oct-88: V3.1 - Charles Carvalho
4148*39729Ssklower Change index for 'v' ioctl to preserve compatibility with previous
4149*39729Ssklower versions. Restrict maximum window size to 127, not 128.
4150*39729Ssklower 7-Nov-88: V3.2 - Charles Carvalho
4151*39729Ssklower Fix check for no free circuits when processing RING
4152*39729Ssklower 17-Feb-89: V4.3.0 - Paul Traina
4153*39729Ssklower Added TGV changes for Multinet.
4154*39729Ssklower 8-Mar-89: V4.3.1 - Steve Johnson
4155*39729Ssklower Installed 'Q' ioctl to support obtaining an internal trace log used
4156*39729Ssklower for debugging only -- not documented for general user. acpconfig
4157*39729Ssklower dda0 -q 2 dumps 256 bytes from the dda_debug_silo[] array
4158*39729Ssklower 13-Mar-89: V4.3.2 - Paul Traina
4159*39729Ssklower Updated Multinet support.
4160*39729Ssklower 17-Apr-89: V4.3.3 - Steve Johnson
4161*39729Ssklower Split bus and simulation related code out to included files for first
4162*39729Ssklower shot at 7000 and tahoe design. Don't reset timeout counter in
4163*39729Ssklower dda_data() unless link really is in idle state.
4164*39729Ssklower 28-Apr-89: V4.3.4 - Paul Traina
4165*39729Ssklower Modified changes of 17-Apr-89, added minimal tahoe support until
4166*39729Ssklower driver modified to use 4.3uba transfers.
4167*39729Ssklower Fixed timeout fix of 17-Apr-89 to do what was intended.
4168*39729Ssklower Fixed code dealing with maintenance board, reformatted with indent
4169*39729Ssklower to repair readablility.
4170*39729Ssklower 09-May-89: V4.3.5 - Paul Traina
4171*39729Ssklower Minimal tahoe support completed, based on BSD4_3TAHOE define which
4172*39729Ssklower must be uncommented manually. Finalizing for ECO.
4173*39729Ssklower 24-May-89: V4.3.6 - Paul Traina
4174*39729Ssklower Ultrix 3.0 support added. Revised 4.3 tahoe support for automatic
4175*39729Ssklower invocation.
4176*39729Ssklower *** NOTE: one of the three OS defines (ACC_BSD, ACC_ULTRIX, ACC_VMS)
4177*39729Ssklower in if_dda.c must be set to a non-zero value for the driver to
4178*39729Ssklower compile.
4179*39729Ssklower Attempting multiple-os support based upon weird variables from include
4180*39729Ssklower files is not acceptable with the latest proliferation of OS versions.
4181*39729Ssklower 20-Jun-89: V4.3.7 - Paul Traina
4182*39729Ssklower Removed crufty old debug stuff and integrated it with the log-message
4183*39729Ssklower code. Now X29 and PI modules can be debuged properly (no #if 0's!).
4184*39729Ssklower 22-Jun-89: - Paul Traina
4185*39729Ssklower Diddled ring-decode logic to check for proper ring packet decoding
4186*39729Ssklower before attempting to find a free lcn. This will make it easier to deal
4187*39729Ssklower with the race condition with find_free_lcn().
4188*39729Ssklower Modified ACC os specific equates to be set as options in the config
4189*39729Ssklower file. This way, most users won't ever edit if_dda.c.
4190*39729Ssklower 18-Jul-89: - Paul Traina
4191*39729Ssklower Driver will no longer return errors if duplicate address-translation
4192*39729Ssklower entries are made. Errors will only happen if a redefiniton is
4193*39729Ssklower attempted.
4194*39729Ssklower Moved dc_key.ttyline out of union, creating dc_line.
4195*39729Ssklower 26-Jul-89: - Paul Traina f/Brad Engstrom
4196*39729Ssklower Added support for called user-data field (two new params to
4197*39729Ssklower make_x25_call) to support extended pad mode in the X.29 module.
4198*39729Ssklower 01-Aug-89: - Paul Traina
4199*39729Ssklower Made ddamsgs uninitialized -- it gets inited in ddaattach now.
4200*39729Ssklower 03-Aug-89: - Paul Traina
4201*39729Ssklower Changed hist_copyout definition to PRIVATE.
4202*39729Ssklower 15-Aug-89: - Paul Traina
4203*39729Ssklower Made dda_softc and dda_iobuf non-private.
4204*39729Ssklower 18-Aug-89: - Paul Traina
4205*39729Ssklower Somehow, ddareset was removed from the 'z' ioctl.
4206*39729Ssklower 28-Aug-89: - Paul Traina
4207*39729Ssklower Changed make_x25_call so that it checks length of data to be stuffed
4208*39729Ssklower into the mbuf before actually copying data in. Removed udlen and
4209*39729Ssklower ud parameters to the routine, as the public areas will be plugged
4210*39729Ssklower with data before being called. (May need to splimp()).
4211*39729Ssklower 22-Sep-89: - Paul Traina
4212*39729Ssklower The order of the 'v' ioctl parameters was screwed up. This caused
4213*39729Ssklower window and packet size setting to fail.
4214*39729Ssklower 23-Oct-89: - Paul Traina
4215*39729Ssklower Added further support for Steve's yetchy simulation. Updated main
4216*39729Ssklower module to work with BI version of dda board.
4217*39729Ssklower 29-Oct-89: - Paul Traina
4218*39729Ssklower Acpconfig inconsistancy (again): removed the 'p', and 'Q' ioctls.
4219*39729Ssklower Since all of these are queries, I placed them under the 'q' ioctl
4220*39729Ssklower with a new switch. Some day we should just scrap the whole mess
4221*39729Ssklower and design a proper ioctl interface.
4222*39729Ssklower 11-Nov-89: - Paul Traina
4223*39729Ssklower Moved rrq/wrq routines into bus modules because we can do several
4224*39729Ssklower queue reads and writes when working with the BI.
4225*39729Ssklower */
4226*39729Ssklower #endif NDDA > 0
4227