Commit | Line | Data |
---|---|---|
51386eb2 KS |
1 | /* |
2 | * Copyright (c) University of British Columbia, 1984 | |
a130a8be KS |
3 | * Copyright (C) Computer Science Department IV, |
4 | * University of Erlangen-Nuremberg, Germany, 1992 | |
5 | * Copyright (c) 1991, 1992 The Regents of the University of California. | |
51386eb2 KS |
6 | * All rights reserved. |
7 | * | |
a130a8be KS |
8 | * This code is derived from software contributed to Berkeley by the |
9 | * Laboratory for Computation Vision and the Computer Science Department | |
10 | * of the the University of British Columbia and the Computer Science | |
11 | * Department (IV) of the University of Erlangen-Nuremberg, Germany. | |
51386eb2 KS |
12 | * |
13 | * %sccs.include.redist.c% | |
14 | * | |
45a83555 | 15 | * @(#)pk_subr.c 7.26 (Berkeley) %G% |
51386eb2 | 16 | */ |
6567c660 | 17 | |
5548a02f KB |
18 | #include <sys/param.h> |
19 | #include <sys/systm.h> | |
20 | #include <sys/mbuf.h> | |
21 | #include <sys/socket.h> | |
22 | #include <sys/protosw.h> | |
23 | #include <sys/socketvar.h> | |
24 | #include <sys/errno.h> | |
25 | #include <sys/time.h> | |
26 | #include <sys/kernel.h> | |
039be508 | 27 | |
5548a02f | 28 | #include <net/if.h> |
3773afb6 | 29 | #include <net/route.h> |
ffababe5 | 30 | |
a130a8be | 31 | #include <netccitt/dll.h> |
5548a02f | 32 | #include <netccitt/x25.h> |
a130a8be | 33 | #include <netccitt/x25err.h> |
5548a02f KB |
34 | #include <netccitt/pk.h> |
35 | #include <netccitt/pk_var.h> | |
6567c660 KS |
36 | |
37 | int pk_sendspace = 1024 * 2 + 8; | |
38 | int pk_recvspace = 1024 * 2 + 8; | |
39 | ||
32f30cd6 KS |
40 | struct pklcd_q pklcd_q = {&pklcd_q, &pklcd_q}; |
41 | ||
a130a8be KS |
42 | struct x25bitslice x25_bitslice[] = { |
43 | /* mask, shift value */ | |
44 | { 0xf0, 0x4 }, | |
45 | { 0xf, 0x0 }, | |
46 | { 0x80, 0x7 }, | |
47 | { 0x40, 0x6 }, | |
48 | { 0x30, 0x4 }, | |
49 | { 0xe0, 0x5 }, | |
50 | { 0x10, 0x4 }, | |
51 | { 0xe, 0x1 }, | |
52 | { 0x1, 0x0 } | |
53 | }; | |
54 | ||
55 | ||
6567c660 KS |
56 | /* |
57 | * Attach X.25 protocol to socket, allocate logical channel descripter | |
58 | * and buffer space, and enter LISTEN state if we are to accept | |
59 | * IN-COMMING CALL packets. | |
60 | * | |
61 | */ | |
62 | ||
ffababe5 | 63 | struct pklcd * |
6567c660 KS |
64 | pk_attach (so) |
65 | struct socket *so; | |
66 | { | |
67 | register struct pklcd *lcp; | |
ffababe5 | 68 | register int error = ENOBUFS; |
2418950a | 69 | int pk_output (); |
6567c660 | 70 | |
32f30cd6 | 71 | MALLOC(lcp, struct pklcd *, sizeof (*lcp), M_PCB, M_NOWAIT); |
ffababe5 | 72 | if (lcp) { |
32f30cd6 KS |
73 | bzero ((caddr_t)lcp, sizeof (*lcp)); |
74 | insque (&lcp -> lcd_q, &pklcd_q); | |
822e810c KS |
75 | lcp -> lcd_state = READY; |
76 | lcp -> lcd_send = pk_output; | |
ffababe5 KS |
77 | if (so) { |
78 | error = soreserve (so, pk_sendspace, pk_recvspace); | |
ffababe5 KS |
79 | lcp -> lcd_so = so; |
80 | if (so -> so_options & SO_ACCEPTCONN) | |
81 | lcp -> lcd_state = LISTEN; | |
b84e7ca8 | 82 | } else |
4507dea2 | 83 | sbreserve (&lcp -> lcd_sb, pk_sendspace); |
ffababe5 KS |
84 | } |
85 | if (so) { | |
86 | so -> so_pcb = (caddr_t) lcp; | |
87 | so -> so_error = error; | |
88 | } | |
89 | return (lcp); | |
6567c660 KS |
90 | } |
91 | ||
92 | /* | |
93 | * Disconnect X.25 protocol from socket. | |
94 | */ | |
95 | ||
96 | pk_disconnect (lcp) | |
97 | register struct pklcd *lcp; | |
98 | { | |
99 | register struct socket *so = lcp -> lcd_so; | |
100 | register struct pklcd *l, *p; | |
101 | ||
102 | switch (lcp -> lcd_state) { | |
103 | case LISTEN: | |
104 | for (p = 0, l = pk_listenhead; l && l != lcp; p = l, l = l -> lcd_listen); | |
105 | if (p == 0) { | |
106 | if (l != 0) | |
107 | pk_listenhead = l -> lcd_listen; | |
108 | } | |
109 | else | |
110 | if (l != 0) | |
111 | p -> lcd_listen = l -> lcd_listen; | |
112 | pk_close (lcp); | |
113 | break; | |
114 | ||
115 | case READY: | |
116 | pk_acct (lcp); | |
117 | pk_close (lcp); | |
118 | break; | |
119 | ||
120 | case SENT_CLEAR: | |
121 | case RECEIVED_CLEAR: | |
122 | break; | |
123 | ||
124 | default: | |
125 | pk_acct (lcp); | |
039be508 KS |
126 | if (so) { |
127 | soisdisconnecting (so); | |
128 | sbflush (&so -> so_rcv); | |
129 | } | |
c4b47c42 | 130 | pk_clear (lcp, 241, 0); /* Normal Disconnect */ |
6567c660 KS |
131 | |
132 | } | |
133 | } | |
134 | ||
135 | /* | |
136 | * Close an X.25 Logical Channel. Discard all space held by the | |
137 | * connection and internal descriptors. Wake up any sleepers. | |
138 | */ | |
139 | ||
140 | pk_close (lcp) | |
141 | struct pklcd *lcp; | |
142 | { | |
143 | register struct socket *so = lcp -> lcd_so; | |
144 | ||
a130a8be KS |
145 | /* |
146 | * If the X.25 connection is torn down due to link | |
147 | * level failure (e.g. LLC2 FRMR) and at the same the user | |
148 | * level is still filling up the socket send buffer that | |
2418950a | 149 | * send buffer is locked. An attempt to sbflush () that send |
a130a8be KS |
150 | * buffer will lead us into - no, not temptation but - panic! |
151 | * So - we'll just check wether the send buffer is locked | |
152 | * and if that's the case we'll mark the lcp as zombie and | |
2418950a | 153 | * have the pk_timer () do the cleaning ... |
a130a8be KS |
154 | */ |
155 | ||
156 | if (so && so -> so_snd.sb_flags & SB_LOCK) | |
157 | lcp -> lcd_state = LCN_ZOMBIE; | |
158 | else | |
159 | pk_freelcd (lcp); | |
6567c660 KS |
160 | |
161 | if (so == NULL) | |
162 | return; | |
163 | ||
164 | so -> so_pcb = 0; | |
6567c660 | 165 | soisdisconnected (so); |
c4b47c42 | 166 | /* sofree (so); /* gak!!! you can't do that here */ |
6567c660 KS |
167 | } |
168 | ||
169 | /* | |
170 | * Create a template to be used to send X.25 packets on a logical | |
171 | * channel. It allocates an mbuf and fills in a skeletal packet | |
172 | * depending on its type. This packet is passed to pk_output where | |
173 | * the remainer of the packet is filled in. | |
174 | */ | |
175 | ||
c4b47c42 | 176 | struct mbuf * |
6567c660 KS |
177 | pk_template (lcn, type) |
178 | int lcn, type; | |
179 | { | |
180 | register struct mbuf *m; | |
181 | register struct x25_packet *xp; | |
182 | ||
1c41f5e9 | 183 | MGETHDR (m, M_DONTWAIT, MT_HEADER); |
6567c660 KS |
184 | if (m == 0) |
185 | panic ("pk_template"); | |
186 | m -> m_act = 0; | |
187 | ||
188 | /* | |
189 | * Efficiency hack: leave a four byte gap at the beginning | |
190 | * of the packet level header with the hope that this will | |
191 | * be enough room for the link level to insert its header. | |
192 | */ | |
1c41f5e9 | 193 | m -> m_data += max_linkhdr; |
822e810c | 194 | m -> m_pkthdr.len = m -> m_len = PKHEADERLN; |
6567c660 KS |
195 | |
196 | xp = mtod (m, struct x25_packet *); | |
197 | *(long *)xp = 0; /* ugly, but fast */ | |
198 | /* xp -> q_bit = 0;*/ | |
a130a8be | 199 | X25SBITS(xp -> bits, fmt_identifier, 1); |
6567c660 KS |
200 | /* xp -> lc_group_number = 0;*/ |
201 | ||
9a1afe6f | 202 | SET_LCN(xp, lcn); |
6567c660 KS |
203 | xp -> packet_type = type; |
204 | ||
c4b47c42 | 205 | return (m); |
6567c660 KS |
206 | } |
207 | ||
208 | /* | |
209 | * This routine restarts all the virtual circuits. Actually, | |
210 | * the virtual circuits are not "restarted" as such. Instead, | |
211 | * any active switched circuit is simply returned to READY | |
212 | * state. | |
213 | */ | |
214 | ||
215 | pk_restart (pkp, restart_cause) | |
216 | register struct pkcb *pkp; | |
217 | int restart_cause; | |
218 | { | |
c4b47c42 | 219 | register struct mbuf *m; |
6567c660 KS |
220 | register struct pklcd *lcp; |
221 | register int i; | |
222 | ||
223 | /* Restart all logical channels. */ | |
1c41f5e9 | 224 | if (pkp -> pk_chan == 0) |
039be508 | 225 | return; |
a130a8be KS |
226 | |
227 | /* | |
228 | * Don't do this if we're doing a restart issued from | |
2418950a | 229 | * inside pk_connect () --- which is only done if and |
a130a8be KS |
230 | * only if the X.25 link is down, i.e. a RESTART needs |
231 | * to be done to get it up. | |
232 | */ | |
233 | if (!(pkp -> pk_dxerole & DTE_CONNECTPENDING)) { | |
234 | for (i = 1; i <= pkp -> pk_maxlcn; ++i) | |
235 | if ((lcp = pkp -> pk_chan[i]) != NULL) { | |
236 | if (lcp -> lcd_so) { | |
237 | lcp -> lcd_so -> so_error = ENETRESET; | |
238 | pk_close (lcp); | |
239 | } else { | |
240 | pk_flush (lcp); | |
241 | lcp -> lcd_state = READY; | |
242 | if (lcp -> lcd_upper) | |
243 | lcp -> lcd_upper (lcp, 0); | |
244 | } | |
c4b47c42 | 245 | } |
a130a8be | 246 | } |
6567c660 KS |
247 | |
248 | if (restart_cause < 0) | |
249 | return; | |
250 | ||
1c41f5e9 | 251 | pkp -> pk_state = DTE_SENT_RESTART; |
a130a8be | 252 | pkp -> pk_dxerole &= ~(DTE_PLAYDCE | DTE_PLAYDTE); |
1c41f5e9 | 253 | lcp = pkp -> pk_chan[0]; |
c4b47c42 | 254 | m = lcp -> lcd_template = pk_template (lcp -> lcd_lcn, X25_RESTART); |
822e810c | 255 | m -> m_pkthdr.len = m -> m_len += 2; |
32f30cd6 KS |
256 | mtod (m, struct x25_packet *) -> packet_data = 0; /* DTE only */ |
257 | mtod (m, octet *)[4] = restart_cause; | |
6567c660 KS |
258 | pk_output (lcp); |
259 | } | |
260 | ||
261 | ||
262 | /* | |
263 | * This procedure frees up the Logical Channel Descripter. | |
264 | */ | |
265 | ||
6567c660 KS |
266 | pk_freelcd (lcp) |
267 | register struct pklcd *lcp; | |
268 | { | |
269 | if (lcp == NULL) | |
270 | return; | |
271 | ||
6567c660 KS |
272 | if (lcp -> lcd_lcn > 0) |
273 | lcp -> lcd_pkp -> pk_chan[lcp -> lcd_lcn] = NULL; | |
274 | ||
32f30cd6 KS |
275 | pk_flush (lcp); |
276 | remque (&lcp -> lcd_q); | |
277 | free ((caddr_t)lcp, M_PCB); | |
6567c660 KS |
278 | } |
279 | ||
2418950a KS |
280 | static struct x25_ifaddr * |
281 | pk_ifwithaddr (sx) | |
282 | struct sockaddr_x25 *sx; | |
283 | { | |
284 | struct ifnet *ifp; | |
285 | struct ifaddr *ifa; | |
286 | register struct x25_ifaddr *ia; | |
287 | char *addr = sx -> x25_addr; | |
288 | ||
289 | for (ifp = ifnet; ifp; ifp = ifp -> if_next) | |
290 | for (ifa = ifp -> if_addrlist; ifa; ifa = ifa -> ifa_next) | |
291 | if (ifa -> ifa_addr -> sa_family == AF_CCITT) { | |
292 | ia = (struct x25_ifaddr *)ifa; | |
293 | if (bcmp (addr, ia -> ia_xc.xc_addr.x25_addr, | |
294 | 16) == 0) | |
295 | return (ia); | |
296 | ||
297 | } | |
298 | return ((struct x25_ifaddr *)0); | |
299 | } | |
300 | ||
6567c660 KS |
301 | |
302 | /* | |
303 | * Bind a address and protocol value to a socket. The important | |
304 | * part is the protocol value - the first four characters of the | |
305 | * Call User Data field. | |
306 | */ | |
307 | ||
2418950a KS |
308 | #define XTRACTPKP(rt) ((rt) -> rt_flags & RTF_GATEWAY ? \ |
309 | ((rt) -> rt_llinfo ? \ | |
310 | (struct pkcb *) ((struct rtentry *)((rt) -> rt_llinfo)) -> rt_llinfo : \ | |
a130a8be | 311 | (struct pkcb *) NULL) : \ |
2418950a | 312 | (struct pkcb *)((rt) -> rt_llinfo)) |
a130a8be | 313 | |
6567c660 KS |
314 | pk_bind (lcp, nam) |
315 | struct pklcd *lcp; | |
316 | struct mbuf *nam; | |
317 | { | |
6567c660 | 318 | register struct pklcd *pp; |
ffababe5 | 319 | register struct sockaddr_x25 *sa; |
6567c660 KS |
320 | |
321 | if (nam == NULL) | |
322 | return (EADDRNOTAVAIL); | |
323 | if (lcp -> lcd_ceaddr) /* XXX */ | |
324 | return (EADDRINUSE); | |
c4b47c42 | 325 | if (pk_checksockaddr (nam)) |
6567c660 KS |
326 | return (EINVAL); |
327 | sa = mtod (nam, struct sockaddr_x25 *); | |
328 | ||
329 | /* | |
330 | * If the user wishes to accept calls only from a particular | |
331 | * net (net != 0), make sure the net is known | |
332 | */ | |
333 | ||
2418950a KS |
334 | if (sa -> x25_addr[0]) { |
335 | if (!pk_ifwithaddr (sa)) | |
336 | return (ENETUNREACH); | |
337 | } else if (sa -> x25_net) { | |
338 | if (!ifa_ifwithnet ((struct sockaddr *)sa)) | |
339 | return (ENETUNREACH); | |
340 | } | |
6567c660 | 341 | |
c4b47c42 KS |
342 | /* |
343 | * For ISO's sake permit default listeners, but only one such . . . | |
344 | */ | |
345 | for (pp = pk_listenhead; pp; pp = pp -> lcd_listen) { | |
346 | register struct sockaddr_x25 *sa2 = pp -> lcd_ceaddr; | |
347 | if ((sa2 -> x25_udlen == sa -> x25_udlen) && | |
348 | (sa2 -> x25_udlen == 0 || | |
349 | (bcmp (sa2 -> x25_udata, sa -> x25_udata, | |
350 | min (sa2 -> x25_udlen, sa -> x25_udlen)) == 0))) | |
351 | return (EADDRINUSE); | |
352 | } | |
ffababe5 KS |
353 | lcp -> lcd_laddr = *sa; |
354 | lcp -> lcd_ceaddr = &lcp -> lcd_laddr; | |
6567c660 KS |
355 | return (0); |
356 | } | |
357 | ||
c4b47c42 KS |
358 | /* |
359 | * Include a bound control block in the list of listeners. | |
360 | */ | |
361 | pk_listen (lcp) | |
362 | register struct pklcd *lcp; | |
363 | { | |
364 | register struct pklcd **pp; | |
365 | ||
366 | if (lcp -> lcd_ceaddr == 0) | |
367 | return (EDESTADDRREQ); | |
368 | ||
369 | lcp -> lcd_state = LISTEN; | |
370 | /* | |
371 | * Add default listener at end, any others at start. | |
372 | */ | |
373 | if (lcp -> lcd_ceaddr -> x25_udlen == 0) { | |
374 | for (pp = &pk_listenhead; *pp; ) | |
375 | pp = &((*pp) -> lcd_listen); | |
376 | *pp = lcp; | |
377 | } else { | |
378 | lcp -> lcd_listen = pk_listenhead; | |
379 | pk_listenhead = lcp; | |
380 | } | |
381 | return (0); | |
382 | } | |
383 | /* | |
384 | * Include a listening control block for the benefit of other protocols. | |
385 | */ | |
386 | pk_protolisten (spi, spilen, callee) | |
32f30cd6 | 387 | int (*callee) (); |
c4b47c42 KS |
388 | { |
389 | register struct pklcd *lcp = pk_attach ((struct socket *)0); | |
390 | register struct mbuf *nam; | |
391 | register struct sockaddr_x25 *sa; | |
392 | int error = ENOBUFS; | |
393 | ||
394 | if (lcp) { | |
32f30cd6 KS |
395 | if (nam = m_getclr (MT_SONAME, M_DONTWAIT)) { |
396 | sa = mtod (nam, struct sockaddr_x25 *); | |
c4b47c42 KS |
397 | sa -> x25_family = AF_CCITT; |
398 | sa -> x25_len = nam -> m_len = sizeof (*sa); | |
399 | sa -> x25_udlen = spilen; | |
400 | sa -> x25_udata[0] = spi; | |
401 | lcp -> lcd_upper = callee; | |
402 | lcp -> lcd_flags = X25_MBS_HOLD; | |
26696d71 KS |
403 | if ((error = pk_bind (lcp, nam)) == 0) |
404 | error = pk_listen (lcp); | |
c4b47c42 KS |
405 | (void) m_free (nam); |
406 | } | |
407 | if (error) | |
32f30cd6 | 408 | pk_freelcd (lcp); |
c4b47c42 KS |
409 | } |
410 | return error; /* Hopefully Zero !*/ | |
411 | } | |
412 | ||
6567c660 KS |
413 | /* |
414 | * Associate a logical channel descriptor with a network. | |
415 | * Fill in the default network specific parameters and then | |
416 | * set any parameters explicitly specified by the user or | |
417 | * by the remote DTE. | |
418 | */ | |
419 | ||
420 | pk_assoc (pkp, lcp, sa) | |
421 | register struct pkcb *pkp; | |
422 | register struct pklcd *lcp; | |
423 | register struct sockaddr_x25 *sa; | |
424 | { | |
425 | ||
426 | lcp -> lcd_pkp = pkp; | |
427 | lcp -> lcd_packetsize = pkp -> pk_xcp -> xc_psize; | |
428 | lcp -> lcd_windowsize = pkp -> pk_xcp -> xc_pwsize; | |
429 | lcp -> lcd_rsn = MODULUS - 1; | |
430 | pkp -> pk_chan[lcp -> lcd_lcn] = lcp; | |
431 | ||
432 | if (sa -> x25_opts.op_psize) | |
433 | lcp -> lcd_packetsize = sa -> x25_opts.op_psize; | |
434 | else | |
435 | sa -> x25_opts.op_psize = lcp -> lcd_packetsize; | |
436 | if (sa -> x25_opts.op_wsize) | |
437 | lcp -> lcd_windowsize = sa -> x25_opts.op_wsize; | |
438 | else | |
439 | sa -> x25_opts.op_wsize = lcp -> lcd_windowsize; | |
4507dea2 | 440 | sa -> x25_net = pkp -> pk_xcp -> xc_addr.x25_net; |
f60b6d8f | 441 | lcp -> lcd_flags |= sa -> x25_opts.op_flags; |
6567c660 KS |
442 | lcp -> lcd_stime = time.tv_sec; |
443 | } | |
444 | ||
c4b47c42 | 445 | pk_connect (lcp, sa) |
6567c660 | 446 | register struct pklcd *lcp; |
ffababe5 | 447 | register struct sockaddr_x25 *sa; |
6567c660 KS |
448 | { |
449 | register struct pkcb *pkp; | |
a130a8be KS |
450 | register struct rtentry *rt; |
451 | register struct rtentry *nrt; | |
452 | ||
2418950a KS |
453 | struct rtentry *npaidb_enter (); |
454 | struct pkcb *pk_newlink (); | |
6567c660 | 455 | |
6567c660 KS |
456 | if (sa -> x25_addr[0] == '\0') |
457 | return (EDESTADDRREQ); | |
a130a8be KS |
458 | |
459 | /* | |
460 | * Is the destination address known? | |
461 | */ | |
45a83555 | 462 | if (!(rt = rtalloc1 ((struct sockaddr *)sa, 1))) |
a130a8be KS |
463 | return (ENETUNREACH); |
464 | ||
465 | if (!(pkp = XTRACTPKP(rt))) | |
2418950a | 466 | pkp = pk_newlink ((struct x25_ifaddr *) (rt -> rt_ifa), |
a130a8be KS |
467 | (caddr_t) 0); |
468 | ||
469 | /* | |
470 | * Have we entered the LLC address? | |
471 | */ | |
2418950a | 472 | if (nrt = npaidb_enter (rt -> rt_gateway, rt_key (rt), rt, 0)) |
a130a8be KS |
473 | pkp -> pk_llrt = nrt; |
474 | ||
475 | /* | |
476 | * Have we allocated an LLC2 link yet? | |
477 | */ | |
2418950a | 478 | if (pkp -> pk_llnext == (caddr_t)0 && pkp -> pk_llctlinput) { |
a130a8be KS |
479 | struct dll_ctlinfo ctlinfo; |
480 | ||
481 | ctlinfo.dlcti_rt = rt; | |
482 | ctlinfo.dlcti_pcb = (caddr_t) pkp; | |
483 | ctlinfo.dlcti_conf = | |
2418950a KS |
484 | (struct dllconfig *) (&((struct x25_ifaddr *)(rt -> rt_ifa)) -> ia_xc); |
485 | pkp -> pk_llnext = | |
486 | (pkp -> pk_llctlinput) (PRC_CONNECT_REQUEST, 0, &ctlinfo); | |
6567c660 KS |
487 | } |
488 | ||
a130a8be KS |
489 | if (pkp -> pk_state != DTE_READY && pkp -> pk_state != DTE_WAITING) |
490 | return (ENETDOWN); | |
6567c660 KS |
491 | if ((lcp -> lcd_lcn = pk_getlcn (pkp)) == 0) |
492 | return (EMFILE); | |
a130a8be | 493 | |
ffababe5 | 494 | lcp -> lcd_faddr = *sa; |
1c41f5e9 | 495 | lcp -> lcd_ceaddr = & lcp -> lcd_faddr; |
6567c660 | 496 | pk_assoc (pkp, lcp, lcp -> lcd_ceaddr); |
a130a8be KS |
497 | |
498 | /* | |
499 | * If the link is not up yet, initiate an X.25 RESTART | |
500 | */ | |
501 | if (pkp -> pk_state == DTE_WAITING) { | |
502 | pkp -> pk_dxerole |= DTE_CONNECTPENDING; | |
2418950a | 503 | pk_ctlinput (PRC_LINKUP, (struct sockaddr *)0, pkp); |
a130a8be KS |
504 | if (lcp -> lcd_so) |
505 | soisconnecting (lcp -> lcd_so); | |
506 | return 0; | |
507 | } | |
508 | ||
4507dea2 | 509 | if (lcp -> lcd_so) |
039be508 | 510 | soisconnecting (lcp -> lcd_so); |
6567c660 | 511 | lcp -> lcd_template = pk_template (lcp -> lcd_lcn, X25_CALL); |
ffababe5 | 512 | pk_callrequest (lcp, lcp -> lcd_ceaddr, pkp -> pk_xcp); |
26696d71 | 513 | return (*pkp -> pk_ia -> ia_start) (lcp); |
6567c660 KS |
514 | } |
515 | ||
a130a8be KS |
516 | /* |
517 | * Complete all pending X.25 call requests --- this gets called after | |
518 | * the X.25 link has been restarted. | |
519 | */ | |
520 | #define RESHUFFLELCN(maxlcn, lcn) ((maxlcn) - (lcn) + 1) | |
521 | ||
2418950a | 522 | pk_callcomplete (pkp) |
a130a8be KS |
523 | register struct pkcb *pkp; |
524 | { | |
525 | register struct pklcd *lcp; | |
526 | register int i; | |
527 | register int ni; | |
528 | ||
529 | ||
530 | if (pkp -> pk_dxerole & DTE_CONNECTPENDING) | |
531 | pkp -> pk_dxerole &= ~DTE_CONNECTPENDING; | |
532 | else return; | |
533 | ||
534 | if (pkp -> pk_chan == 0) | |
535 | return; | |
536 | ||
537 | /* | |
538 | * We pretended to be a DTE for allocating lcns, if | |
539 | * it turns out that we are in reality performing as a | |
540 | * DCE we need to reshuffle the lcps. | |
541 | * | |
542 | * /+---------------+-------- - | |
543 | * / | a (maxlcn-1) | \ | |
544 | * / +---------------+ \ | |
545 | * +--- * | b (maxlcn-2) | \ | |
546 | * | \ +---------------+ \ | |
547 | * r | \ | c (maxlcn-3) | \ | |
548 | * e | \+---------------+ | | |
549 | * s | | . | | |
550 | * h | | . | m | |
551 | * u | | . | a | |
552 | * f | | . | x | |
553 | * f | | . | l | |
554 | * l | /+---------------+ | c | |
555 | * e | / | c' ( 3 ) | | n | |
556 | * | / +---------------+ | | |
557 | * +--> * | b' ( 2 ) | / | |
558 | * \ +---------------+ / | |
559 | * \ | a' ( 1 ) | / | |
560 | * \+---------------+ / | |
561 | * | 0 | / | |
562 | * +---------------+-------- - | |
563 | * | |
564 | */ | |
565 | if (pkp -> pk_dxerole & DTE_PLAYDCE) { | |
566 | /* Sigh, reshuffle it */ | |
567 | for (i = pkp -> pk_maxlcn; i > 0; --i) | |
568 | if (pkp -> pk_chan[i]) { | |
569 | ni = RESHUFFLELCN(pkp -> pk_maxlcn, i); | |
570 | pkp -> pk_chan[ni] = pkp -> pk_chan[i]; | |
571 | pkp -> pk_chan[i] = NULL; | |
572 | pkp -> pk_chan[ni] -> lcd_lcn = ni; | |
573 | } | |
574 | } | |
575 | ||
576 | for (i = 1; i <= pkp -> pk_maxlcn; ++i) | |
577 | if ((lcp = pkp -> pk_chan[i]) != NULL) { | |
578 | /* if (lcp -> lcd_so) | |
579 | soisconnecting (lcp -> lcd_so); */ | |
580 | lcp -> lcd_template = pk_template (lcp -> lcd_lcn, X25_CALL); | |
581 | pk_callrequest (lcp, lcp -> lcd_ceaddr, pkp -> pk_xcp); | |
2418950a | 582 | (*pkp -> pk_ia -> ia_start) (lcp); |
a130a8be KS |
583 | } |
584 | } | |
585 | ||
fe9ae892 KS |
586 | struct bcdinfo { |
587 | octet *cp; | |
588 | unsigned posn; | |
589 | }; | |
6567c660 KS |
590 | /* |
591 | * Build the rest of the CALL REQUEST packet. Fill in calling | |
592 | * address, facilities fields and the user data field. | |
593 | */ | |
594 | ||
ffababe5 | 595 | pk_callrequest (lcp, sa, xcp) |
6567c660 | 596 | struct pklcd *lcp; |
ffababe5 | 597 | register struct sockaddr_x25 *sa; |
6567c660 KS |
598 | register struct x25config *xcp; |
599 | { | |
600 | register struct x25_calladdr *a; | |
c4b47c42 | 601 | register struct mbuf *m = lcp -> lcd_template; |
32f30cd6 | 602 | register struct x25_packet *xp = mtod (m, struct x25_packet *); |
fe9ae892 | 603 | struct bcdinfo b; |
6567c660 | 604 | |
9a1afe6f | 605 | if (lcp -> lcd_flags & X25_DBIT) |
a130a8be | 606 | X25SBITS(xp -> bits, d_bit, 1); |
c4b47c42 | 607 | a = (struct x25_calladdr *) &xp -> packet_data; |
fe9ae892 KS |
608 | b.cp = (octet *) a -> address_field; |
609 | b.posn = 0; | |
a130a8be KS |
610 | X25SBITS(a -> addrlens, called_addrlen, to_bcd (&b, sa, xcp)); |
611 | X25SBITS(a -> addrlens, calling_addrlen, to_bcd (&b, &xcp -> xc_addr, xcp)); | |
fe9ae892 KS |
612 | if (b.posn & 0x01) |
613 | *b.cp++ &= 0xf0; | |
614 | m -> m_pkthdr.len = m -> m_len += b.cp - (octet *) a; | |
6567c660 | 615 | |
c4b47c42 | 616 | if (lcp -> lcd_facilities) { |
32f30cd6 | 617 | m -> m_pkthdr.len += |
fe9ae892 | 618 | (m -> m_next = lcp -> lcd_facilities) -> m_pkthdr.len; |
c4b47c42 | 619 | lcp -> lcd_facilities = 0; |
c4b47c42 | 620 | } else |
fe9ae892 | 621 | pk_build_facilities (m, sa, (int)xcp -> xc_type); |
c4b47c42 | 622 | |
32f30cd6 | 623 | m_copyback (m, m -> m_pkthdr.len, sa -> x25_udlen, sa -> x25_udata); |
6567c660 KS |
624 | } |
625 | ||
fe9ae892 | 626 | pk_build_facilities (m, sa, type) |
c4b47c42 | 627 | register struct mbuf *m; |
6567c660 KS |
628 | struct sockaddr_x25 *sa; |
629 | { | |
c4b47c42 | 630 | register octet *cp; |
6567c660 KS |
631 | register octet *fcp; |
632 | register int revcharge; | |
633 | ||
32f30cd6 | 634 | cp = mtod (m, octet *) + m -> m_len; |
c4b47c42 | 635 | fcp = cp + 1; |
6567c660 KS |
636 | revcharge = sa -> x25_opts.op_flags & X25_REVERSE_CHARGE ? 1 : 0; |
637 | /* | |
638 | * This is specific to Datapac X.25(1976) DTEs. International | |
639 | * calls must have the "hi priority" bit on. | |
640 | */ | |
641 | if (type == X25_1976 && sa -> x25_opts.op_psize == X25_PS128) | |
642 | revcharge |= 02; | |
643 | if (revcharge) { | |
644 | *fcp++ = FACILITIES_REVERSE_CHARGE; | |
645 | *fcp++ = revcharge; | |
646 | } | |
647 | switch (type) { | |
648 | case X25_1980: | |
649 | case X25_1984: | |
650 | *fcp++ = FACILITIES_PACKETSIZE; | |
651 | *fcp++ = sa -> x25_opts.op_psize; | |
652 | *fcp++ = sa -> x25_opts.op_psize; | |
653 | ||
654 | *fcp++ = FACILITIES_WINDOWSIZE; | |
655 | *fcp++ = sa -> x25_opts.op_wsize; | |
656 | *fcp++ = sa -> x25_opts.op_wsize; | |
657 | } | |
c4b47c42 KS |
658 | *cp = fcp - cp - 1; |
659 | m -> m_pkthdr.len = (m -> m_len += *cp + 1); | |
6567c660 KS |
660 | } |
661 | ||
fe9ae892 KS |
662 | to_bcd (b, sa, xcp) |
663 | register struct bcdinfo *b; | |
664 | struct sockaddr_x25 *sa; | |
665 | register struct x25config *xcp; | |
6567c660 | 666 | { |
fe9ae892 KS |
667 | register char *x = sa -> x25_addr; |
668 | unsigned start = b -> posn; | |
669 | /* | |
670 | * The nodnic and prepnd0 stuff looks tedious, | |
671 | * but it does allow full X.121 addresses to be used, | |
672 | * which is handy for routing info (& OSI type 37 addresses). | |
673 | */ | |
674 | if (xcp -> xc_addr.x25_net && (xcp -> xc_nodnic || xcp -> xc_prepnd0)) { | |
2418950a | 675 | char dnicname[sizeof (long) * NBBY/3 + 2]; |
fe9ae892 KS |
676 | register char *p = dnicname; |
677 | ||
678 | sprintf (p, "%d", xcp -> xc_addr.x25_net & 0x7fff); | |
679 | for (; *p; p++) /* *p == 0 means dnic matched */ | |
680 | if ((*p ^ *x++) & 0x0f) | |
681 | break; | |
682 | if (*p || xcp -> xc_nodnic == 0) | |
683 | x = sa -> x25_addr; | |
684 | if (*p && xcp -> xc_prepnd0) { | |
685 | if ((b -> posn)++ & 0x01) | |
686 | *(b -> cp)++; | |
687 | else | |
688 | *(b -> cp) = 0; | |
689 | } | |
690 | } | |
691 | while (*x) | |
692 | if ((b -> posn)++ & 0x01) | |
693 | *(b -> cp)++ |= *x++ & 0x0F; | |
6567c660 | 694 | else |
fe9ae892 KS |
695 | *(b -> cp) = *x++ << 4; |
696 | return ((b -> posn) - start); | |
6567c660 KS |
697 | } |
698 | ||
699 | /* | |
700 | * This routine gets the first available logical channel number. The | |
a130a8be KS |
701 | * search is |
702 | * - from the highest number to lowest number if playing DTE, and | |
703 | * - from lowest to highest number if playing DCE. | |
6567c660 KS |
704 | */ |
705 | ||
706 | pk_getlcn (pkp) | |
707 | register struct pkcb *pkp; | |
708 | { | |
709 | register int i; | |
710 | ||
1c41f5e9 | 711 | if (pkp -> pk_chan == 0) |
039be508 | 712 | return (0); |
a130a8be KS |
713 | if ( pkp -> pk_dxerole & DTE_PLAYDCE ) { |
714 | for (i = 1; i <= pkp -> pk_maxlcn; ++i) | |
715 | if (pkp -> pk_chan[i] == NULL) | |
716 | break; | |
717 | } else { | |
718 | for (i = pkp -> pk_maxlcn; i > 0; --i) | |
719 | if (pkp -> pk_chan[i] == NULL) | |
720 | break; | |
721 | } | |
722 | i = ( i > pkp -> pk_maxlcn ? 0 : i ); | |
6567c660 | 723 | return (i); |
6567c660 KS |
724 | } |
725 | ||
6567c660 KS |
726 | /* |
727 | * This procedure sends a CLEAR request packet. The lc state is | |
728 | * set to "SENT_CLEAR". | |
729 | */ | |
730 | ||
c4b47c42 KS |
731 | pk_clear (lcp, diagnostic, abortive) |
732 | register struct pklcd *lcp; | |
6567c660 | 733 | { |
c4b47c42 KS |
734 | register struct mbuf *m = pk_template (lcp -> lcd_lcn, X25_CLEAR); |
735 | ||
736 | m -> m_len += 2; | |
50c09880 | 737 | m -> m_pkthdr.len += 2; |
32f30cd6 KS |
738 | mtod (m, struct x25_packet *) -> packet_data = 0; |
739 | mtod (m, octet *)[4] = diagnostic; | |
c4b47c42 KS |
740 | if (lcp -> lcd_facilities) { |
741 | m -> m_next = lcp -> lcd_facilities; | |
742 | m -> m_pkthdr.len += m -> m_next -> m_len; | |
743 | lcp -> lcd_facilities = 0; | |
744 | } | |
745 | if (abortive) | |
746 | lcp -> lcd_template = m; | |
747 | else { | |
748 | struct socket *so = lcp -> lcd_so; | |
749 | struct sockbuf *sb = so ? & so -> so_snd : & lcp -> lcd_sb; | |
32f30cd6 | 750 | sbappendrecord (sb, m); |
c4b47c42 | 751 | } |
6567c660 KS |
752 | pk_output (lcp); |
753 | ||
754 | } | |
755 | ||
32f30cd6 KS |
756 | /* |
757 | * This procedure generates RNR's or RR's to inhibit or enable | |
758 | * inward data flow, if the current state changes (blocked ==> open or | |
759 | * vice versa), or if forced to generate one. One forces RNR's to ack data. | |
760 | */ | |
761 | pk_flowcontrol (lcp, inhibit, forced) | |
762 | register struct pklcd *lcp; | |
763 | { | |
764 | inhibit = (inhibit != 0); | |
765 | if (lcp == 0 || lcp -> lcd_state != DATA_TRANSFER || | |
766 | (forced == 0 && lcp -> lcd_rxrnr_condition == inhibit)) | |
767 | return; | |
768 | lcp -> lcd_rxrnr_condition = inhibit; | |
26696d71 KS |
769 | lcp -> lcd_template = |
770 | pk_template (lcp -> lcd_lcn, inhibit ? X25_RNR : X25_RR); | |
32f30cd6 KS |
771 | pk_output (lcp); |
772 | } | |
773 | ||
6567c660 | 774 | /* |
32f30cd6 | 775 | * This procedure sends a RESET request packet. It re-intializes |
6567c660 KS |
776 | * virtual circuit. |
777 | */ | |
778 | ||
779 | static | |
c4b47c42 | 780 | pk_reset (lcp, diagnostic) |
6567c660 KS |
781 | register struct pklcd *lcp; |
782 | { | |
c4b47c42 KS |
783 | register struct mbuf *m; |
784 | register struct socket *so = lcp -> lcd_so; | |
6567c660 KS |
785 | |
786 | if (lcp -> lcd_state != DATA_TRANSFER) | |
787 | return; | |
788 | ||
c4b47c42 KS |
789 | if (so) |
790 | so -> so_error = ECONNRESET; | |
6567c660 KS |
791 | lcp -> lcd_reset_condition = TRUE; |
792 | ||
793 | /* Reset all the control variables for the channel. */ | |
c4b47c42 | 794 | pk_flush (lcp); |
6567c660 KS |
795 | lcp -> lcd_window_condition = lcp -> lcd_rnr_condition = |
796 | lcp -> lcd_intrconf_pending = FALSE; | |
797 | lcp -> lcd_rsn = MODULUS - 1; | |
798 | lcp -> lcd_ssn = 0; | |
799 | lcp -> lcd_output_window = lcp -> lcd_input_window = | |
800 | lcp -> lcd_last_transmitted_pr = 0; | |
c4b47c42 | 801 | m = lcp -> lcd_template = pk_template (lcp -> lcd_lcn, X25_RESET); |
822e810c | 802 | m -> m_pkthdr.len = m -> m_len += 2; |
32f30cd6 KS |
803 | mtod (m, struct x25_packet *) -> packet_data = 0; |
804 | mtod (m, octet *)[4] = diagnostic; | |
c4b47c42 KS |
805 | pk_output (lcp); |
806 | ||
807 | } | |
808 | ||
809 | /* | |
810 | * This procedure frees all data queued for output or delivery on a | |
811 | * virtual circuit. | |
812 | */ | |
813 | ||
814 | pk_flush (lcp) | |
815 | register struct pklcd *lcp; | |
816 | { | |
817 | register struct socket *so; | |
818 | ||
819 | if (lcp -> lcd_template) | |
820 | m_freem (lcp -> lcd_template); | |
821 | ||
822 | if (lcp -> lcd_cps) { | |
32f30cd6 | 823 | m_freem (lcp -> lcd_cps); |
c4b47c42 KS |
824 | lcp -> lcd_cps = 0; |
825 | } | |
32f30cd6 KS |
826 | if (lcp -> lcd_facilities) { |
827 | m_freem (lcp -> lcd_facilities); | |
828 | lcp -> lcd_facilities = 0; | |
829 | } | |
a130a8be | 830 | if (so = lcp -> lcd_so) |
039be508 | 831 | sbflush (&so -> so_snd); |
a130a8be | 832 | else |
c4b47c42 | 833 | sbflush (&lcp -> lcd_sb); |
6567c660 KS |
834 | } |
835 | ||
6567c660 KS |
836 | /* |
837 | * This procedure handles all local protocol procedure errors. | |
838 | */ | |
839 | ||
c4b47c42 | 840 | pk_procerror (error, lcp, errstr, diagnostic) |
6567c660 KS |
841 | register struct pklcd *lcp; |
842 | char *errstr; | |
843 | { | |
844 | ||
845 | pk_message (lcp -> lcd_lcn, lcp -> lcd_pkp -> pk_xcp, errstr); | |
846 | ||
847 | switch (error) { | |
848 | case CLEAR: | |
1c41f5e9 KS |
849 | if (lcp -> lcd_so) { |
850 | lcp -> lcd_so -> so_error = ECONNABORTED; | |
851 | soisdisconnecting (lcp -> lcd_so); | |
6567c660 | 852 | } |
c4b47c42 | 853 | pk_clear (lcp, diagnostic, 1); |
6567c660 KS |
854 | break; |
855 | ||
856 | case RESET: | |
c4b47c42 | 857 | pk_reset (lcp, diagnostic); |
6567c660 KS |
858 | } |
859 | } | |
860 | ||
861 | /* | |
862 | * This procedure is called during the DATA TRANSFER state to check | |
863 | * and process the P(R) values received in the DATA, RR OR RNR | |
864 | * packets. | |
865 | */ | |
866 | ||
867 | pk_ack (lcp, pr) | |
868 | struct pklcd *lcp; | |
869 | unsigned pr; | |
870 | { | |
871 | register struct socket *so = lcp -> lcd_so; | |
872 | ||
873 | if (lcp -> lcd_output_window == pr) | |
874 | return (PACKET_OK); | |
875 | if (lcp -> lcd_output_window < lcp -> lcd_ssn) { | |
876 | if (pr < lcp -> lcd_output_window || pr > lcp -> lcd_ssn) { | |
c4b47c42 KS |
877 | pk_procerror (RESET, lcp, |
878 | "p(r) flow control error", 2); | |
6567c660 KS |
879 | return (ERROR_PACKET); |
880 | } | |
881 | } | |
882 | else { | |
883 | if (pr < lcp -> lcd_output_window && pr > lcp -> lcd_ssn) { | |
c4b47c42 | 884 | pk_procerror (RESET, lcp, |
32f30cd6 | 885 | "p(r) flow control error #2", 2); |
6567c660 KS |
886 | return (ERROR_PACKET); |
887 | } | |
888 | } | |
889 | ||
890 | lcp -> lcd_output_window = pr; /* Rotate window. */ | |
891 | if (lcp -> lcd_window_condition == TRUE) | |
892 | lcp -> lcd_window_condition = FALSE; | |
893 | ||
a130a8be KS |
894 | if (so && ((so -> so_snd.sb_flags & SB_WAIT) || |
895 | (so -> so_snd.sb_flags & SB_NOTIFY))) | |
6567c660 KS |
896 | sowwakeup (so); |
897 | ||
898 | return (PACKET_OK); | |
899 | } | |
900 | ||
901 | /* | |
902 | * This procedure decodes the X.25 level 3 packet returning a | |
903 | * code to be used in switchs or arrays. | |
904 | */ | |
905 | ||
906 | pk_decode (xp) | |
907 | register struct x25_packet *xp; | |
908 | { | |
909 | register int type; | |
910 | ||
a130a8be | 911 | if (X25GBITS(xp -> bits, fmt_identifier) != 1) |
6567c660 | 912 | return (INVALID_PACKET); |
c4b47c42 | 913 | #ifdef ancient_history |
6567c660 KS |
914 | /* |
915 | * Make sure that the logical channel group number is 0. | |
916 | * This restriction may be removed at some later date. | |
917 | */ | |
918 | if (xp -> lc_group_number != 0) | |
919 | return (INVALID_PACKET); | |
c4b47c42 | 920 | #endif |
6567c660 KS |
921 | /* |
922 | * Test for data packet first. | |
923 | */ | |
924 | if (!(xp -> packet_type & DATA_PACKET_DESIGNATOR)) | |
925 | return (DATA); | |
926 | ||
927 | /* | |
928 | * Test if flow control packet (RR or RNR). | |
929 | */ | |
930 | if (!(xp -> packet_type & RR_OR_RNR_PACKET_DESIGNATOR)) | |
32f30cd6 KS |
931 | switch (xp -> packet_type & 0x1f) { |
932 | case X25_RR: | |
6567c660 | 933 | return (RR); |
32f30cd6 | 934 | case X25_RNR: |
6567c660 | 935 | return (RNR); |
32f30cd6 KS |
936 | case X25_REJECT: |
937 | return (REJECT); | |
938 | } | |
6567c660 KS |
939 | |
940 | /* | |
941 | * Determine the rest of the packet types. | |
942 | */ | |
943 | switch (xp -> packet_type) { | |
944 | case X25_CALL: | |
945 | type = CALL; | |
946 | break; | |
947 | ||
948 | case X25_CALL_ACCEPTED: | |
949 | type = CALL_ACCEPTED; | |
950 | break; | |
951 | ||
952 | case X25_CLEAR: | |
953 | type = CLEAR; | |
954 | break; | |
955 | ||
956 | case X25_CLEAR_CONFIRM: | |
957 | type = CLEAR_CONF; | |
958 | break; | |
959 | ||
960 | case X25_INTERRUPT: | |
961 | type = INTERRUPT; | |
962 | break; | |
963 | ||
964 | case X25_INTERRUPT_CONFIRM: | |
965 | type = INTERRUPT_CONF; | |
966 | break; | |
967 | ||
968 | case X25_RESET: | |
969 | type = RESET; | |
970 | break; | |
971 | ||
972 | case X25_RESET_CONFIRM: | |
973 | type = RESET_CONF; | |
974 | break; | |
975 | ||
976 | case X25_RESTART: | |
977 | type = RESTART; | |
978 | break; | |
979 | ||
980 | case X25_RESTART_CONFIRM: | |
981 | type = RESTART_CONF; | |
982 | break; | |
983 | ||
32f30cd6 | 984 | case X25_DIAGNOSTIC: |
5336ccc3 | 985 | type = DIAG_TYPE; |
32f30cd6 KS |
986 | break; |
987 | ||
6567c660 KS |
988 | default: |
989 | type = INVALID_PACKET; | |
990 | } | |
991 | return (type); | |
992 | } | |
993 | ||
994 | /* | |
995 | * A restart packet has been received. Print out the reason | |
996 | * for the restart. | |
997 | */ | |
998 | ||
999 | pk_restartcause (pkp, xp) | |
1000 | struct pkcb *pkp; | |
1001 | register struct x25_packet *xp; | |
1002 | { | |
1003 | register struct x25config *xcp = pkp -> pk_xcp; | |
9a1afe6f | 1004 | register int lcn = LCN(xp); |
6567c660 KS |
1005 | |
1006 | switch (xp -> packet_data) { | |
1007 | case X25_RESTART_LOCAL_PROCEDURE_ERROR: | |
1008 | pk_message (lcn, xcp, "restart: local procedure error"); | |
1009 | break; | |
1010 | ||
1011 | case X25_RESTART_NETWORK_CONGESTION: | |
1012 | pk_message (lcn, xcp, "restart: network congestion"); | |
1013 | break; | |
1014 | ||
1015 | case X25_RESTART_NETWORK_OPERATIONAL: | |
1016 | pk_message (lcn, xcp, "restart: network operational"); | |
1017 | break; | |
1018 | ||
1019 | default: | |
1020 | pk_message (lcn, xcp, "restart: unknown cause"); | |
1021 | } | |
1022 | } | |
1023 | ||
1024 | #define MAXRESETCAUSE 7 | |
1025 | ||
1026 | int Reset_cause[] = { | |
1027 | EXRESET, EXROUT, 0, EXRRPE, 0, EXRLPE, 0, EXRNCG | |
1028 | }; | |
1029 | ||
1030 | /* | |
1031 | * A reset packet has arrived. Return the cause to the user. | |
1032 | */ | |
1033 | ||
1034 | pk_resetcause (pkp, xp) | |
1035 | struct pkcb *pkp; | |
1036 | register struct x25_packet *xp; | |
1037 | { | |
1c41f5e9 | 1038 | register struct pklcd *lcp = |
9a1afe6f | 1039 | pkp -> pk_chan[LCN(xp)]; |
6567c660 KS |
1040 | register int code = xp -> packet_data; |
1041 | ||
1042 | if (code > MAXRESETCAUSE) | |
1043 | code = 7; /* EXRNCG */ | |
1044 | ||
2418950a | 1045 | pk_message (LCN(xp), lcp -> lcd_pkp, "reset code 0x%x, diagnostic 0x%x", |
32f30cd6 KS |
1046 | xp -> packet_data, 4[(u_char *)xp]); |
1047 | ||
26696d71 KS |
1048 | if (lcp -> lcd_so) |
1049 | lcp -> lcd_so -> so_error = Reset_cause[code]; | |
6567c660 KS |
1050 | } |
1051 | ||
1052 | #define MAXCLEARCAUSE 25 | |
1053 | ||
1054 | int Clear_cause[] = { | |
1055 | EXCLEAR, EXCBUSY, 0, EXCINV, 0, EXCNCG, 0, | |
1056 | 0, 0, EXCOUT, 0, EXCAB, 0, EXCNOB, 0, 0, 0, EXCRPE, | |
1057 | 0, EXCLPE, 0, 0, 0, 0, 0, EXCRRC | |
1058 | }; | |
1059 | ||
1060 | /* | |
1061 | * A clear packet has arrived. Return the cause to the user. | |
1062 | */ | |
1063 | ||
1064 | pk_clearcause (pkp, xp) | |
1065 | struct pkcb *pkp; | |
1066 | register struct x25_packet *xp; | |
1067 | { | |
1c41f5e9 | 1068 | register struct pklcd *lcp = |
9a1afe6f | 1069 | pkp -> pk_chan[LCN(xp)]; |
6567c660 KS |
1070 | register int code = xp -> packet_data; |
1071 | ||
1072 | if (code > MAXCLEARCAUSE) | |
1073 | code = 5; /* EXRNCG */ | |
822e810c KS |
1074 | if (lcp -> lcd_so) |
1075 | lcp -> lcd_so -> so_error = Clear_cause[code]; | |
6567c660 KS |
1076 | } |
1077 | ||
1078 | char * | |
1079 | format_ntn (xcp) | |
1080 | register struct x25config *xcp; | |
1081 | { | |
4507dea2 KS |
1082 | |
1083 | return (xcp -> xc_addr.x25_addr); | |
6567c660 KS |
1084 | } |
1085 | ||
1086 | /* VARARGS1 */ | |
1087 | pk_message (lcn, xcp, fmt, a1, a2, a3, a4, a5, a6) | |
1088 | struct x25config *xcp; | |
1089 | char *fmt; | |
1090 | { | |
1091 | ||
1092 | if (lcn) | |
a130a8be | 1093 | if (!PQEMPTY) |
6567c660 KS |
1094 | printf ("X.25(%s): lcn %d: ", format_ntn (xcp), lcn); |
1095 | else | |
1096 | printf ("X.25: lcn %d: ", lcn); | |
1097 | else | |
a130a8be | 1098 | if (!PQEMPTY) |
6567c660 KS |
1099 | printf ("X.25(%s): ", format_ntn (xcp)); |
1100 | else | |
1101 | printf ("X.25: "); | |
1102 | ||
1103 | printf (fmt, a1, a2, a3, a4, a5, a6); | |
1104 | printf ("\n"); | |
1105 | } | |
1c41f5e9 | 1106 | |
32f30cd6 | 1107 | pk_fragment (lcp, m0, qbit, mbit, wait) |
1c41f5e9 KS |
1108 | struct mbuf *m0; |
1109 | register struct pklcd *lcp; | |
1110 | { | |
1111 | register struct mbuf *m = m0; | |
1112 | register struct x25_packet *xp; | |
1113 | register struct sockbuf *sb; | |
32f30cd6 | 1114 | struct mbuf *head = 0, *next, **mp = &head, *m_split (); |
1c41f5e9 KS |
1115 | int totlen, psize = 1 << (lcp -> lcd_packetsize); |
1116 | ||
1117 | if (m == 0) | |
822e810c | 1118 | return 0; |
a130a8be | 1119 | if (m -> m_flags & M_PKTHDR == 0) |
32f30cd6 | 1120 | panic ("pk_fragment"); |
1c41f5e9 | 1121 | totlen = m -> m_pkthdr.len; |
9a1afe6f | 1122 | m -> m_act = 0; |
1c41f5e9 KS |
1123 | sb = lcp -> lcd_so ? &lcp -> lcd_so -> so_snd : & lcp -> lcd_sb; |
1124 | do { | |
1125 | if (totlen > psize) { | |
32f30cd6 | 1126 | if ((next = m_split (m, psize, wait)) == 0) |
1c41f5e9 | 1127 | goto abort; |
1c41f5e9 | 1128 | totlen -= psize; |
9a1afe6f KS |
1129 | } else |
1130 | next = 0; | |
1c41f5e9 KS |
1131 | M_PREPEND(m, PKHEADERLN, wait); |
1132 | if (m == 0) | |
1133 | goto abort; | |
9a1afe6f KS |
1134 | *mp = m; |
1135 | mp = & m -> m_act; | |
1136 | *mp = 0; | |
32f30cd6 | 1137 | xp = mtod (m, struct x25_packet *); |
1c41f5e9 KS |
1138 | 0[(char *)xp] = 0; |
1139 | if (qbit) | |
a130a8be | 1140 | X25SBITS(xp -> bits, q_bit, 1); |
9a1afe6f | 1141 | if (lcp -> lcd_flags & X25_DBIT) |
a130a8be KS |
1142 | X25SBITS(xp -> bits, d_bit, 1); |
1143 | X25SBITS(xp -> bits, fmt_identifier, 1); | |
1c41f5e9 | 1144 | xp -> packet_type = X25_DATA; |
9a1afe6f KS |
1145 | SET_LCN(xp, lcp -> lcd_lcn); |
1146 | if (next || (mbit && (totlen == psize || | |
1147 | (lcp -> lcd_flags & X25_DBIT)))) | |
a130a8be | 1148 | SMBIT(xp, 1); |
1c41f5e9 | 1149 | } while (m = next); |
9a1afe6f | 1150 | for (m = head; m; m = next) { |
1c41f5e9 KS |
1151 | next = m -> m_act; |
1152 | m -> m_act = 0; | |
32f30cd6 | 1153 | sbappendrecord (sb, m); |
1c41f5e9 KS |
1154 | } |
1155 | return 0; | |
1156 | abort: | |
9a1afe6f | 1157 | if (wait) |
32f30cd6 | 1158 | panic ("pk_fragment null mbuf after wait"); |
9a1afe6f | 1159 | if (next) |
32f30cd6 | 1160 | m_freem (next); |
9a1afe6f | 1161 | for (m = head; m; m = next) { |
1c41f5e9 | 1162 | next = m -> m_act; |
32f30cd6 | 1163 | m_freem (m); |
1c41f5e9 KS |
1164 | } |
1165 | return ENOBUFS; | |
1166 | } |