Commit | Line | Data |
---|---|---|
15637ed4 RG |
1 | /* |
2 | * Copyright (c) University of British Columbia, 1984 | |
3 | * Copyright (c) 1990 The Regents of the University of California. | |
4 | * All rights reserved. | |
5 | * | |
6 | * This code is derived from software contributed to Berkeley by | |
7 | * the Laboratory for Computation Vision and the Computer Science Department | |
8 | * of the University of British Columbia. | |
9 | * | |
10 | * Redistribution and use in source and binary forms, with or without | |
11 | * modification, are permitted provided that the following conditions | |
12 | * are met: | |
13 | * 1. Redistributions of source code must retain the above copyright | |
14 | * notice, this list of conditions and the following disclaimer. | |
15 | * 2. Redistributions in binary form must reproduce the above copyright | |
16 | * notice, this list of conditions and the following disclaimer in the | |
17 | * documentation and/or other materials provided with the distribution. | |
18 | * 3. All advertising materials mentioning features or use of this software | |
19 | * must display the following acknowledgement: | |
20 | * This product includes software developed by the University of | |
21 | * California, Berkeley and its contributors. | |
22 | * 4. Neither the name of the University nor the names of its contributors | |
23 | * may be used to endorse or promote products derived from this software | |
24 | * without specific prior written permission. | |
25 | * | |
26 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND | |
27 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
28 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |
29 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE | |
30 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |
31 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | |
32 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |
33 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |
34 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | |
35 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
36 | * SUCH DAMAGE. | |
37 | * | |
1cdffd64 | 38 | * from: @(#)pk_subr.c 7.16 (Berkeley) 6/6/91 |
fde1aeb2 | 39 | * $Id: pk_subr.c,v 1.4 1993/11/25 01:34:31 wollman Exp $ |
15637ed4 RG |
40 | */ |
41 | ||
42 | #include "param.h" | |
43 | #include "systm.h" | |
44 | #include "mbuf.h" | |
45 | #include "socket.h" | |
46 | #include "protosw.h" | |
47 | #include "socketvar.h" | |
48 | #include "errno.h" | |
49 | #include "time.h" | |
50 | #include "kernel.h" | |
4c45483e | 51 | #include "machine/stdarg.h" |
15637ed4 RG |
52 | |
53 | #include "../net/if.h" | |
54 | ||
55 | #include "x25.h" | |
56 | #include "pk.h" | |
57 | #include "pk_var.h" | |
58 | #include "x25err.h" | |
59 | ||
60 | int pk_sendspace = 1024 * 2 + 8; | |
61 | int pk_recvspace = 1024 * 2 + 8; | |
62 | ||
63 | struct pklcd_q pklcd_q = {&pklcd_q, &pklcd_q}; | |
64 | ||
65 | /* | |
66 | * Attach X.25 protocol to socket, allocate logical channel descripter | |
67 | * and buffer space, and enter LISTEN state if we are to accept | |
68 | * IN-COMMING CALL packets. | |
69 | * | |
70 | */ | |
71 | ||
72 | struct pklcd * | |
73 | pk_attach (so) | |
74 | struct socket *so; | |
75 | { | |
76 | register struct pklcd *lcp; | |
77 | register int error = ENOBUFS; | |
15637ed4 RG |
78 | |
79 | MALLOC(lcp, struct pklcd *, sizeof (*lcp), M_PCB, M_NOWAIT); | |
80 | if (lcp) { | |
81 | bzero ((caddr_t)lcp, sizeof (*lcp)); | |
82 | insque (&lcp -> lcd_q, &pklcd_q); | |
83 | lcp -> lcd_state = READY; | |
84 | lcp -> lcd_send = pk_output; | |
85 | if (so) { | |
86 | error = soreserve (so, pk_sendspace, pk_recvspace); | |
87 | lcp -> lcd_so = so; | |
88 | if (so -> so_options & SO_ACCEPTCONN) | |
89 | lcp -> lcd_state = LISTEN; | |
90 | } else | |
91 | sbreserve (&lcp -> lcd_sb, pk_sendspace); | |
92 | } | |
93 | if (so) { | |
94 | so -> so_pcb = (caddr_t) lcp; | |
95 | so -> so_error = error; | |
96 | } | |
97 | return (lcp); | |
98 | } | |
99 | ||
100 | /* | |
101 | * Disconnect X.25 protocol from socket. | |
102 | */ | |
103 | ||
4c45483e | 104 | void |
15637ed4 | 105 | pk_disconnect (lcp) |
4c45483e | 106 | register struct pklcd *lcp; |
15637ed4 RG |
107 | { |
108 | register struct socket *so = lcp -> lcd_so; | |
109 | register struct pklcd *l, *p; | |
110 | ||
111 | switch (lcp -> lcd_state) { | |
112 | case LISTEN: | |
113 | for (p = 0, l = pk_listenhead; l && l != lcp; p = l, l = l -> lcd_listen); | |
114 | if (p == 0) { | |
115 | if (l != 0) | |
116 | pk_listenhead = l -> lcd_listen; | |
117 | } | |
118 | else | |
119 | if (l != 0) | |
120 | p -> lcd_listen = l -> lcd_listen; | |
121 | pk_close (lcp); | |
122 | break; | |
123 | ||
124 | case READY: | |
125 | pk_acct (lcp); | |
126 | pk_close (lcp); | |
127 | break; | |
128 | ||
129 | case SENT_CLEAR: | |
130 | case RECEIVED_CLEAR: | |
131 | break; | |
132 | ||
133 | default: | |
134 | pk_acct (lcp); | |
135 | if (so) { | |
136 | soisdisconnecting (so); | |
137 | sbflush (&so -> so_rcv); | |
138 | } | |
139 | pk_clear (lcp, 241, 0); /* Normal Disconnect */ | |
140 | ||
141 | } | |
142 | } | |
143 | ||
144 | /* | |
145 | * Close an X.25 Logical Channel. Discard all space held by the | |
146 | * connection and internal descriptors. Wake up any sleepers. | |
147 | */ | |
148 | ||
4c45483e | 149 | void |
15637ed4 | 150 | pk_close (lcp) |
4c45483e | 151 | struct pklcd *lcp; |
15637ed4 RG |
152 | { |
153 | register struct socket *so = lcp -> lcd_so; | |
154 | ||
155 | pk_freelcd (lcp); | |
156 | ||
157 | if (so == NULL) | |
158 | return; | |
159 | ||
160 | so -> so_pcb = 0; | |
161 | soisdisconnected (so); | |
2f5cecf6 | 162 | /* sofree (so);*/ /* gak!!! you can't do that here */ |
15637ed4 RG |
163 | } |
164 | ||
165 | /* | |
166 | * Create a template to be used to send X.25 packets on a logical | |
167 | * channel. It allocates an mbuf and fills in a skeletal packet | |
168 | * depending on its type. This packet is passed to pk_output where | |
169 | * the remainer of the packet is filled in. | |
170 | */ | |
171 | ||
172 | struct mbuf * | |
173 | pk_template (lcn, type) | |
174 | int lcn, type; | |
175 | { | |
176 | register struct mbuf *m; | |
177 | register struct x25_packet *xp; | |
178 | ||
179 | MGETHDR (m, M_DONTWAIT, MT_HEADER); | |
180 | if (m == 0) | |
181 | panic ("pk_template"); | |
182 | m -> m_act = 0; | |
183 | ||
184 | /* | |
185 | * Efficiency hack: leave a four byte gap at the beginning | |
186 | * of the packet level header with the hope that this will | |
187 | * be enough room for the link level to insert its header. | |
188 | */ | |
189 | m -> m_data += max_linkhdr; | |
190 | m -> m_pkthdr.len = m -> m_len = PKHEADERLN; | |
191 | ||
192 | xp = mtod (m, struct x25_packet *); | |
193 | *(long *)xp = 0; /* ugly, but fast */ | |
194 | /* xp -> q_bit = 0;*/ | |
195 | xp -> fmt_identifier = 1; | |
196 | /* xp -> lc_group_number = 0;*/ | |
197 | ||
198 | SET_LCN(xp, lcn); | |
199 | xp -> packet_type = type; | |
200 | ||
201 | return (m); | |
202 | } | |
203 | ||
204 | /* | |
205 | * This routine restarts all the virtual circuits. Actually, | |
206 | * the virtual circuits are not "restarted" as such. Instead, | |
207 | * any active switched circuit is simply returned to READY | |
208 | * state. | |
209 | */ | |
210 | ||
4c45483e | 211 | void |
15637ed4 | 212 | pk_restart (pkp, restart_cause) |
4c45483e GW |
213 | register struct pkcb *pkp; |
214 | int restart_cause; | |
15637ed4 RG |
215 | { |
216 | register struct mbuf *m; | |
217 | register struct pklcd *lcp; | |
218 | register int i; | |
219 | ||
220 | /* Restart all logical channels. */ | |
221 | if (pkp -> pk_chan == 0) | |
222 | return; | |
223 | for (i = 1; i <= pkp -> pk_maxlcn; ++i) | |
224 | if ((lcp = pkp -> pk_chan[i]) != NULL) { | |
225 | if (lcp -> lcd_so) { | |
226 | lcp -> lcd_so -> so_error = ENETRESET; | |
227 | pk_close (lcp); | |
228 | } else { | |
229 | pk_flush (lcp); | |
230 | lcp -> lcd_state = READY; | |
231 | if (lcp -> lcd_upper) | |
232 | lcp -> lcd_upper (lcp, 0); | |
233 | } | |
234 | } | |
235 | ||
236 | if (restart_cause < 0) | |
237 | return; | |
238 | ||
239 | pkp -> pk_state = DTE_SENT_RESTART; | |
240 | lcp = pkp -> pk_chan[0]; | |
241 | m = lcp -> lcd_template = pk_template (lcp -> lcd_lcn, X25_RESTART); | |
242 | m -> m_pkthdr.len = m -> m_len += 2; | |
243 | mtod (m, struct x25_packet *) -> packet_data = 0; /* DTE only */ | |
244 | mtod (m, octet *)[4] = restart_cause; | |
fde1aeb2 | 245 | pk_output (lcp, 0); |
15637ed4 RG |
246 | } |
247 | ||
248 | ||
249 | /* | |
250 | * This procedure frees up the Logical Channel Descripter. | |
251 | */ | |
252 | ||
4c45483e | 253 | void |
15637ed4 | 254 | pk_freelcd (lcp) |
4c45483e | 255 | register struct pklcd *lcp; |
15637ed4 RG |
256 | { |
257 | if (lcp == NULL) | |
258 | return; | |
259 | ||
260 | if (lcp -> lcd_lcn > 0) | |
261 | lcp -> lcd_pkp -> pk_chan[lcp -> lcd_lcn] = NULL; | |
262 | ||
263 | pk_flush (lcp); | |
264 | remque (&lcp -> lcd_q); | |
265 | free ((caddr_t)lcp, M_PCB); | |
266 | } | |
267 | ||
268 | ||
269 | /* | |
270 | * Bind a address and protocol value to a socket. The important | |
271 | * part is the protocol value - the first four characters of the | |
272 | * Call User Data field. | |
273 | */ | |
274 | ||
4c45483e | 275 | int |
15637ed4 | 276 | pk_bind (lcp, nam) |
4c45483e GW |
277 | struct pklcd *lcp; |
278 | struct mbuf *nam; | |
15637ed4 RG |
279 | { |
280 | register struct pkcb *pkp; | |
281 | register struct pklcd *pp; | |
282 | register struct sockaddr_x25 *sa; | |
283 | ||
284 | if (nam == NULL) | |
285 | return (EADDRNOTAVAIL); | |
286 | if (lcp -> lcd_ceaddr) /* XXX */ | |
287 | return (EADDRINUSE); | |
288 | if (pk_checksockaddr (nam)) | |
289 | return (EINVAL); | |
290 | sa = mtod (nam, struct sockaddr_x25 *); | |
291 | ||
292 | /* | |
293 | * If the user wishes to accept calls only from a particular | |
294 | * net (net != 0), make sure the net is known | |
295 | */ | |
296 | ||
297 | if (sa -> x25_net) | |
298 | for (pkp = pkcbhead; ; pkp = pkp -> pk_next) { | |
299 | if (pkp == 0) | |
300 | return (ENETUNREACH); | |
301 | if (pkp -> pk_xcp -> xc_addr.x25_net == sa -> x25_net) | |
302 | break; | |
303 | } | |
304 | ||
305 | /* | |
306 | * For ISO's sake permit default listeners, but only one such . . . | |
307 | */ | |
308 | for (pp = pk_listenhead; pp; pp = pp -> lcd_listen) { | |
309 | register struct sockaddr_x25 *sa2 = pp -> lcd_ceaddr; | |
310 | if ((sa2 -> x25_udlen == sa -> x25_udlen) && | |
311 | (sa2 -> x25_udlen == 0 || | |
312 | (bcmp (sa2 -> x25_udata, sa -> x25_udata, | |
313 | min (sa2 -> x25_udlen, sa -> x25_udlen)) == 0))) | |
314 | return (EADDRINUSE); | |
315 | } | |
316 | lcp -> lcd_laddr = *sa; | |
317 | lcp -> lcd_ceaddr = &lcp -> lcd_laddr; | |
318 | return (0); | |
319 | } | |
320 | ||
321 | /* | |
322 | * Include a bound control block in the list of listeners. | |
323 | */ | |
4c45483e | 324 | int |
15637ed4 | 325 | pk_listen (lcp) |
4c45483e | 326 | register struct pklcd *lcp; |
15637ed4 RG |
327 | { |
328 | register struct pklcd **pp; | |
329 | ||
330 | if (lcp -> lcd_ceaddr == 0) | |
331 | return (EDESTADDRREQ); | |
332 | ||
333 | lcp -> lcd_state = LISTEN; | |
334 | /* | |
335 | * Add default listener at end, any others at start. | |
336 | */ | |
337 | if (lcp -> lcd_ceaddr -> x25_udlen == 0) { | |
338 | for (pp = &pk_listenhead; *pp; ) | |
339 | pp = &((*pp) -> lcd_listen); | |
340 | *pp = lcp; | |
341 | } else { | |
342 | lcp -> lcd_listen = pk_listenhead; | |
343 | pk_listenhead = lcp; | |
344 | } | |
345 | return (0); | |
346 | } | |
347 | /* | |
348 | * Include a listening control block for the benefit of other protocols. | |
349 | */ | |
4c45483e | 350 | int |
15637ed4 | 351 | pk_protolisten (spi, spilen, callee) |
4c45483e GW |
352 | int spi; |
353 | int spilen; | |
354 | void (*callee) (); | |
15637ed4 RG |
355 | { |
356 | register struct pklcd *lcp = pk_attach ((struct socket *)0); | |
357 | register struct mbuf *nam; | |
358 | register struct sockaddr_x25 *sa; | |
359 | int error = ENOBUFS; | |
360 | ||
361 | if (lcp) { | |
362 | if (nam = m_getclr (MT_SONAME, M_DONTWAIT)) { | |
363 | sa = mtod (nam, struct sockaddr_x25 *); | |
364 | sa -> x25_family = AF_CCITT; | |
365 | sa -> x25_len = nam -> m_len = sizeof (*sa); | |
366 | sa -> x25_udlen = spilen; | |
367 | sa -> x25_udata[0] = spi; | |
368 | lcp -> lcd_upper = callee; | |
369 | lcp -> lcd_flags = X25_MBS_HOLD; | |
370 | if ((error = pk_bind (lcp, nam)) == 0) | |
371 | error = pk_listen (lcp); | |
372 | (void) m_free (nam); | |
373 | } | |
374 | if (error) | |
375 | pk_freelcd (lcp); | |
376 | } | |
377 | return error; /* Hopefully Zero !*/ | |
378 | } | |
379 | ||
380 | /* | |
381 | * Associate a logical channel descriptor with a network. | |
382 | * Fill in the default network specific parameters and then | |
383 | * set any parameters explicitly specified by the user or | |
384 | * by the remote DTE. | |
385 | */ | |
386 | ||
4c45483e | 387 | void |
15637ed4 | 388 | pk_assoc (pkp, lcp, sa) |
4c45483e GW |
389 | register struct pkcb *pkp; |
390 | register struct pklcd *lcp; | |
391 | register struct sockaddr_x25 *sa; | |
15637ed4 RG |
392 | { |
393 | ||
394 | lcp -> lcd_pkp = pkp; | |
395 | lcp -> lcd_packetsize = pkp -> pk_xcp -> xc_psize; | |
396 | lcp -> lcd_windowsize = pkp -> pk_xcp -> xc_pwsize; | |
397 | lcp -> lcd_rsn = MODULUS - 1; | |
398 | pkp -> pk_chan[lcp -> lcd_lcn] = lcp; | |
399 | ||
400 | if (sa -> x25_opts.op_psize) | |
401 | lcp -> lcd_packetsize = sa -> x25_opts.op_psize; | |
402 | else | |
403 | sa -> x25_opts.op_psize = lcp -> lcd_packetsize; | |
404 | if (sa -> x25_opts.op_wsize) | |
405 | lcp -> lcd_windowsize = sa -> x25_opts.op_wsize; | |
406 | else | |
407 | sa -> x25_opts.op_wsize = lcp -> lcd_windowsize; | |
408 | sa -> x25_net = pkp -> pk_xcp -> xc_addr.x25_net; | |
409 | lcp -> lcd_flags |= sa -> x25_opts.op_flags; | |
410 | lcp -> lcd_stime = time.tv_sec; | |
411 | } | |
412 | ||
4c45483e | 413 | int |
15637ed4 | 414 | pk_connect (lcp, sa) |
4c45483e GW |
415 | register struct pklcd *lcp; |
416 | register struct sockaddr_x25 *sa; | |
15637ed4 | 417 | { |
4c45483e | 418 | register struct pkcb *pkp = 0; |
15637ed4 RG |
419 | |
420 | if (sa -> x25_addr[0] == '\0') | |
421 | return (EDESTADDRREQ); | |
422 | if (lcp -> lcd_pkp == 0) | |
423 | for (pkp = pkcbhead; ; pkp = pkp -> pk_next) { | |
424 | if (pkp == 0) | |
425 | return (ENETUNREACH); | |
426 | /* | |
427 | * use first net configured (last in list | |
428 | * headed by pkcbhead) if net is zero | |
429 | * | |
430 | * This is clearly bogus for many llc2's sharing | |
431 | * the same xcp; we will replace this with a | |
432 | * routing lookup. | |
433 | */ | |
434 | if (sa -> x25_net == 0 && pkp -> pk_next == 0) | |
435 | break; | |
436 | if (sa -> x25_net == pkp -> pk_xcp -> xc_addr.x25_net) | |
437 | break; | |
438 | } | |
439 | ||
440 | if (pkp -> pk_state != DTE_READY) | |
441 | return (ENETDOWN); | |
442 | if ((lcp -> lcd_lcn = pk_getlcn (pkp)) == 0) | |
443 | return (EMFILE); | |
444 | lcp -> lcd_faddr = *sa; | |
445 | lcp -> lcd_ceaddr = & lcp -> lcd_faddr; | |
446 | pk_assoc (pkp, lcp, lcp -> lcd_ceaddr); | |
447 | if (lcp -> lcd_so) | |
448 | soisconnecting (lcp -> lcd_so); | |
449 | lcp -> lcd_template = pk_template (lcp -> lcd_lcn, X25_CALL); | |
450 | pk_callrequest (lcp, lcp -> lcd_ceaddr, pkp -> pk_xcp); | |
451 | return (*pkp -> pk_ia -> ia_start) (lcp); | |
452 | } | |
453 | ||
454 | struct bcdinfo { | |
455 | octet *cp; | |
456 | unsigned posn; | |
457 | }; | |
458 | /* | |
459 | * Build the rest of the CALL REQUEST packet. Fill in calling | |
460 | * address, facilities fields and the user data field. | |
461 | */ | |
462 | ||
4c45483e | 463 | void |
15637ed4 | 464 | pk_callrequest (lcp, sa, xcp) |
4c45483e GW |
465 | struct pklcd *lcp; |
466 | register struct sockaddr_x25 *sa; | |
467 | register struct x25config *xcp; | |
15637ed4 RG |
468 | { |
469 | register struct x25_calladdr *a; | |
470 | register struct mbuf *m = lcp -> lcd_template; | |
471 | register struct x25_packet *xp = mtod (m, struct x25_packet *); | |
472 | struct bcdinfo b; | |
473 | ||
474 | if (lcp -> lcd_flags & X25_DBIT) | |
475 | xp -> d_bit = 1; | |
476 | a = (struct x25_calladdr *) &xp -> packet_data; | |
477 | b.cp = (octet *) a -> address_field; | |
478 | b.posn = 0; | |
479 | a -> called_addrlen = to_bcd (&b, sa, xcp); | |
480 | a -> calling_addrlen = to_bcd (&b, &xcp -> xc_addr, xcp); | |
481 | if (b.posn & 0x01) | |
482 | *b.cp++ &= 0xf0; | |
483 | m -> m_pkthdr.len = m -> m_len += b.cp - (octet *) a; | |
484 | ||
485 | if (lcp -> lcd_facilities) { | |
486 | m -> m_pkthdr.len += | |
487 | (m -> m_next = lcp -> lcd_facilities) -> m_pkthdr.len; | |
488 | lcp -> lcd_facilities = 0; | |
489 | } else | |
490 | pk_build_facilities (m, sa, (int)xcp -> xc_type); | |
491 | ||
492 | m_copyback (m, m -> m_pkthdr.len, sa -> x25_udlen, sa -> x25_udata); | |
493 | } | |
494 | ||
4c45483e | 495 | void |
15637ed4 | 496 | pk_build_facilities (m, sa, type) |
4c45483e GW |
497 | register struct mbuf *m; |
498 | struct sockaddr_x25 *sa; | |
499 | int type; | |
15637ed4 RG |
500 | { |
501 | register octet *cp; | |
502 | register octet *fcp; | |
503 | register int revcharge; | |
504 | ||
505 | cp = mtod (m, octet *) + m -> m_len; | |
506 | fcp = cp + 1; | |
507 | revcharge = sa -> x25_opts.op_flags & X25_REVERSE_CHARGE ? 1 : 0; | |
508 | /* | |
509 | * This is specific to Datapac X.25(1976) DTEs. International | |
510 | * calls must have the "hi priority" bit on. | |
511 | */ | |
512 | if (type == X25_1976 && sa -> x25_opts.op_psize == X25_PS128) | |
513 | revcharge |= 02; | |
514 | if (revcharge) { | |
515 | *fcp++ = FACILITIES_REVERSE_CHARGE; | |
516 | *fcp++ = revcharge; | |
517 | } | |
518 | switch (type) { | |
519 | case X25_1980: | |
520 | case X25_1984: | |
521 | *fcp++ = FACILITIES_PACKETSIZE; | |
522 | *fcp++ = sa -> x25_opts.op_psize; | |
523 | *fcp++ = sa -> x25_opts.op_psize; | |
524 | ||
525 | *fcp++ = FACILITIES_WINDOWSIZE; | |
526 | *fcp++ = sa -> x25_opts.op_wsize; | |
527 | *fcp++ = sa -> x25_opts.op_wsize; | |
528 | } | |
529 | *cp = fcp - cp - 1; | |
530 | m -> m_pkthdr.len = (m -> m_len += *cp + 1); | |
531 | } | |
532 | ||
4c45483e | 533 | int |
15637ed4 | 534 | to_bcd (b, sa, xcp) |
4c45483e GW |
535 | register struct bcdinfo *b; |
536 | struct sockaddr_x25 *sa; | |
537 | register struct x25config *xcp; | |
15637ed4 RG |
538 | { |
539 | register char *x = sa -> x25_addr; | |
540 | unsigned start = b -> posn; | |
541 | /* | |
542 | * The nodnic and prepnd0 stuff looks tedious, | |
543 | * but it does allow full X.121 addresses to be used, | |
544 | * which is handy for routing info (& OSI type 37 addresses). | |
545 | */ | |
546 | if (xcp -> xc_addr.x25_net && (xcp -> xc_nodnic || xcp -> xc_prepnd0)) { | |
547 | char dnicname[sizeof(long) * NBBY/3 + 2]; | |
548 | register char *p = dnicname; | |
549 | ||
550 | sprintf (p, "%d", xcp -> xc_addr.x25_net & 0x7fff); | |
551 | for (; *p; p++) /* *p == 0 means dnic matched */ | |
552 | if ((*p ^ *x++) & 0x0f) | |
553 | break; | |
554 | if (*p || xcp -> xc_nodnic == 0) | |
555 | x = sa -> x25_addr; | |
556 | if (*p && xcp -> xc_prepnd0) { | |
557 | if ((b -> posn)++ & 0x01) | |
558 | *(b -> cp)++; | |
559 | else | |
560 | *(b -> cp) = 0; | |
561 | } | |
562 | } | |
563 | while (*x) | |
564 | if ((b -> posn)++ & 0x01) | |
565 | *(b -> cp)++ |= *x++ & 0x0F; | |
566 | else | |
567 | *(b -> cp) = *x++ << 4; | |
568 | return ((b -> posn) - start); | |
569 | } | |
570 | ||
571 | /* | |
572 | * This routine gets the first available logical channel number. The | |
573 | * search is from the highest number to lowest number (DTE). | |
574 | */ | |
575 | ||
4c45483e | 576 | int |
15637ed4 | 577 | pk_getlcn (pkp) |
4c45483e | 578 | register struct pkcb *pkp; |
15637ed4 RG |
579 | { |
580 | register int i; | |
581 | ||
582 | if (pkp -> pk_chan == 0) | |
583 | return (0); | |
584 | for (i = pkp -> pk_maxlcn; i > 0; --i) | |
585 | if (pkp -> pk_chan[i] == NULL) | |
586 | break; | |
587 | return (i); | |
588 | ||
589 | } | |
590 | ||
591 | /* | |
592 | * This procedure sends a CLEAR request packet. The lc state is | |
593 | * set to "SENT_CLEAR". | |
594 | */ | |
4c45483e | 595 | void |
15637ed4 | 596 | pk_clear (lcp, diagnostic, abortive) |
4c45483e GW |
597 | register struct pklcd *lcp; |
598 | int diagnostic; | |
599 | int abortive; | |
15637ed4 RG |
600 | { |
601 | register struct mbuf *m = pk_template (lcp -> lcd_lcn, X25_CLEAR); | |
602 | ||
603 | m -> m_len += 2; | |
604 | mtod (m, struct x25_packet *) -> packet_data = 0; | |
605 | mtod (m, octet *)[4] = diagnostic; | |
606 | if (lcp -> lcd_facilities) { | |
607 | m -> m_next = lcp -> lcd_facilities; | |
608 | m -> m_pkthdr.len += m -> m_next -> m_len; | |
609 | lcp -> lcd_facilities = 0; | |
610 | } | |
611 | if (abortive) | |
612 | lcp -> lcd_template = m; | |
613 | else { | |
614 | struct socket *so = lcp -> lcd_so; | |
615 | struct sockbuf *sb = so ? & so -> so_snd : & lcp -> lcd_sb; | |
616 | sbappendrecord (sb, m); | |
617 | } | |
fde1aeb2 | 618 | pk_output (lcp, 0); |
15637ed4 RG |
619 | |
620 | } | |
621 | ||
622 | /* | |
623 | * This procedure generates RNR's or RR's to inhibit or enable | |
624 | * inward data flow, if the current state changes (blocked ==> open or | |
625 | * vice versa), or if forced to generate one. One forces RNR's to ack data. | |
626 | */ | |
4c45483e | 627 | void |
15637ed4 | 628 | pk_flowcontrol (lcp, inhibit, forced) |
4c45483e GW |
629 | register struct pklcd *lcp; |
630 | int inhibit; | |
631 | int forced; | |
15637ed4 RG |
632 | { |
633 | inhibit = (inhibit != 0); | |
634 | if (lcp == 0 || lcp -> lcd_state != DATA_TRANSFER || | |
635 | (forced == 0 && lcp -> lcd_rxrnr_condition == inhibit)) | |
636 | return; | |
637 | lcp -> lcd_rxrnr_condition = inhibit; | |
638 | lcp -> lcd_template = | |
639 | pk_template (lcp -> lcd_lcn, inhibit ? X25_RNR : X25_RR); | |
fde1aeb2 | 640 | pk_output (lcp, 0); |
15637ed4 RG |
641 | } |
642 | ||
643 | /* | |
644 | * This procedure sends a RESET request packet. It re-intializes | |
645 | * virtual circuit. | |
646 | */ | |
647 | ||
4c45483e | 648 | static void |
15637ed4 | 649 | pk_reset (lcp, diagnostic) |
4c45483e GW |
650 | register struct pklcd *lcp; |
651 | int diagnostic; | |
15637ed4 RG |
652 | { |
653 | register struct mbuf *m; | |
654 | register struct socket *so = lcp -> lcd_so; | |
655 | ||
656 | if (lcp -> lcd_state != DATA_TRANSFER) | |
657 | return; | |
658 | ||
659 | if (so) | |
660 | so -> so_error = ECONNRESET; | |
661 | lcp -> lcd_reset_condition = TRUE; | |
662 | ||
663 | /* Reset all the control variables for the channel. */ | |
664 | pk_flush (lcp); | |
665 | lcp -> lcd_window_condition = lcp -> lcd_rnr_condition = | |
666 | lcp -> lcd_intrconf_pending = FALSE; | |
667 | lcp -> lcd_rsn = MODULUS - 1; | |
668 | lcp -> lcd_ssn = 0; | |
669 | lcp -> lcd_output_window = lcp -> lcd_input_window = | |
670 | lcp -> lcd_last_transmitted_pr = 0; | |
671 | m = lcp -> lcd_template = pk_template (lcp -> lcd_lcn, X25_RESET); | |
672 | m -> m_pkthdr.len = m -> m_len += 2; | |
673 | mtod (m, struct x25_packet *) -> packet_data = 0; | |
674 | mtod (m, octet *)[4] = diagnostic; | |
fde1aeb2 | 675 | pk_output (lcp, 0); |
15637ed4 RG |
676 | |
677 | } | |
678 | ||
679 | /* | |
680 | * This procedure frees all data queued for output or delivery on a | |
681 | * virtual circuit. | |
682 | */ | |
683 | ||
4c45483e | 684 | void |
15637ed4 | 685 | pk_flush (lcp) |
4c45483e | 686 | register struct pklcd *lcp; |
15637ed4 RG |
687 | { |
688 | register struct socket *so; | |
689 | ||
690 | if (lcp -> lcd_template) | |
691 | m_freem (lcp -> lcd_template); | |
692 | ||
693 | if (lcp -> lcd_cps) { | |
694 | m_freem (lcp -> lcd_cps); | |
695 | lcp -> lcd_cps = 0; | |
696 | } | |
697 | if (lcp -> lcd_facilities) { | |
698 | m_freem (lcp -> lcd_facilities); | |
699 | lcp -> lcd_facilities = 0; | |
700 | } | |
701 | if (so = lcp -> lcd_so) { | |
702 | sbflush (&so -> so_rcv); | |
703 | sbflush (&so -> so_snd); | |
704 | } else | |
705 | sbflush (&lcp -> lcd_sb); | |
706 | } | |
707 | ||
708 | /* | |
709 | * This procedure handles all local protocol procedure errors. | |
710 | */ | |
4c45483e | 711 | void |
15637ed4 | 712 | pk_procerror (error, lcp, errstr, diagnostic) |
4c45483e GW |
713 | int error; |
714 | register struct pklcd *lcp; | |
fde1aeb2 | 715 | const char *errstr; |
4c45483e | 716 | int diagnostic; |
15637ed4 RG |
717 | { |
718 | ||
719 | pk_message (lcp -> lcd_lcn, lcp -> lcd_pkp -> pk_xcp, errstr); | |
720 | ||
721 | switch (error) { | |
722 | case CLEAR: | |
723 | if (lcp -> lcd_so) { | |
724 | lcp -> lcd_so -> so_error = ECONNABORTED; | |
725 | soisdisconnecting (lcp -> lcd_so); | |
726 | } | |
727 | pk_clear (lcp, diagnostic, 1); | |
728 | break; | |
729 | ||
730 | case RESET: | |
731 | pk_reset (lcp, diagnostic); | |
732 | } | |
733 | } | |
734 | ||
735 | /* | |
736 | * This procedure is called during the DATA TRANSFER state to check | |
737 | * and process the P(R) values received in the DATA, RR OR RNR | |
738 | * packets. | |
739 | */ | |
4c45483e | 740 | int |
15637ed4 | 741 | pk_ack (lcp, pr) |
4c45483e GW |
742 | struct pklcd *lcp; |
743 | unsigned pr; | |
15637ed4 RG |
744 | { |
745 | register struct socket *so = lcp -> lcd_so; | |
746 | ||
747 | if (lcp -> lcd_output_window == pr) | |
748 | return (PACKET_OK); | |
749 | if (lcp -> lcd_output_window < lcp -> lcd_ssn) { | |
750 | if (pr < lcp -> lcd_output_window || pr > lcp -> lcd_ssn) { | |
751 | pk_procerror (RESET, lcp, | |
752 | "p(r) flow control error", 2); | |
753 | return (ERROR_PACKET); | |
754 | } | |
755 | } | |
756 | else { | |
757 | if (pr < lcp -> lcd_output_window && pr > lcp -> lcd_ssn) { | |
758 | pk_procerror (RESET, lcp, | |
759 | "p(r) flow control error #2", 2); | |
760 | return (ERROR_PACKET); | |
761 | } | |
762 | } | |
763 | ||
764 | lcp -> lcd_output_window = pr; /* Rotate window. */ | |
765 | if (lcp -> lcd_window_condition == TRUE) | |
766 | lcp -> lcd_window_condition = FALSE; | |
767 | ||
768 | if (so && ((so -> so_snd.sb_flags & SB_WAIT) || so -> so_snd.sb_sel)) | |
769 | sowwakeup (so); | |
770 | ||
771 | return (PACKET_OK); | |
772 | } | |
773 | ||
774 | /* | |
775 | * This procedure decodes the X.25 level 3 packet returning a | |
776 | * code to be used in switchs or arrays. | |
777 | */ | |
4c45483e | 778 | int |
15637ed4 | 779 | pk_decode (xp) |
4c45483e | 780 | register struct x25_packet *xp; |
15637ed4 RG |
781 | { |
782 | register int type; | |
783 | ||
784 | if (xp -> fmt_identifier != 1) | |
785 | return (INVALID_PACKET); | |
786 | #ifdef ancient_history | |
787 | /* | |
788 | * Make sure that the logical channel group number is 0. | |
789 | * This restriction may be removed at some later date. | |
790 | */ | |
791 | if (xp -> lc_group_number != 0) | |
792 | return (INVALID_PACKET); | |
793 | #endif | |
794 | /* | |
795 | * Test for data packet first. | |
796 | */ | |
797 | if (!(xp -> packet_type & DATA_PACKET_DESIGNATOR)) | |
798 | return (DATA); | |
799 | ||
800 | /* | |
801 | * Test if flow control packet (RR or RNR). | |
802 | */ | |
803 | if (!(xp -> packet_type & RR_OR_RNR_PACKET_DESIGNATOR)) | |
804 | switch (xp -> packet_type & 0x1f) { | |
805 | case X25_RR: | |
806 | return (RR); | |
807 | case X25_RNR: | |
808 | return (RNR); | |
809 | case X25_REJECT: | |
810 | return (REJECT); | |
811 | } | |
812 | ||
813 | /* | |
814 | * Determine the rest of the packet types. | |
815 | */ | |
816 | switch (xp -> packet_type) { | |
817 | case X25_CALL: | |
818 | type = CALL; | |
819 | break; | |
820 | ||
821 | case X25_CALL_ACCEPTED: | |
822 | type = CALL_ACCEPTED; | |
823 | break; | |
824 | ||
825 | case X25_CLEAR: | |
826 | type = CLEAR; | |
827 | break; | |
828 | ||
829 | case X25_CLEAR_CONFIRM: | |
830 | type = CLEAR_CONF; | |
831 | break; | |
832 | ||
833 | case X25_INTERRUPT: | |
834 | type = INTERRUPT; | |
835 | break; | |
836 | ||
837 | case X25_INTERRUPT_CONFIRM: | |
838 | type = INTERRUPT_CONF; | |
839 | break; | |
840 | ||
841 | case X25_RESET: | |
842 | type = RESET; | |
843 | break; | |
844 | ||
845 | case X25_RESET_CONFIRM: | |
846 | type = RESET_CONF; | |
847 | break; | |
848 | ||
849 | case X25_RESTART: | |
850 | type = RESTART; | |
851 | break; | |
852 | ||
853 | case X25_RESTART_CONFIRM: | |
854 | type = RESTART_CONF; | |
855 | break; | |
856 | ||
857 | case X25_DIAGNOSTIC: | |
858 | type = DIAG_TYPE; | |
859 | break; | |
860 | ||
861 | default: | |
862 | type = INVALID_PACKET; | |
863 | } | |
864 | return (type); | |
865 | } | |
866 | ||
867 | /* | |
868 | * A restart packet has been received. Print out the reason | |
869 | * for the restart. | |
870 | */ | |
4c45483e | 871 | void |
15637ed4 | 872 | pk_restartcause (pkp, xp) |
4c45483e GW |
873 | struct pkcb *pkp; |
874 | register struct x25_packet *xp; | |
15637ed4 RG |
875 | { |
876 | register struct x25config *xcp = pkp -> pk_xcp; | |
877 | register int lcn = LCN(xp); | |
878 | ||
879 | switch (xp -> packet_data) { | |
880 | case X25_RESTART_LOCAL_PROCEDURE_ERROR: | |
881 | pk_message (lcn, xcp, "restart: local procedure error"); | |
882 | break; | |
883 | ||
884 | case X25_RESTART_NETWORK_CONGESTION: | |
885 | pk_message (lcn, xcp, "restart: network congestion"); | |
886 | break; | |
887 | ||
888 | case X25_RESTART_NETWORK_OPERATIONAL: | |
889 | pk_message (lcn, xcp, "restart: network operational"); | |
890 | break; | |
891 | ||
892 | default: | |
893 | pk_message (lcn, xcp, "restart: unknown cause"); | |
894 | } | |
895 | } | |
896 | ||
897 | #define MAXRESETCAUSE 7 | |
898 | ||
899 | int Reset_cause[] = { | |
900 | EXRESET, EXROUT, 0, EXRRPE, 0, EXRLPE, 0, EXRNCG | |
901 | }; | |
902 | ||
903 | /* | |
904 | * A reset packet has arrived. Return the cause to the user. | |
905 | */ | |
4c45483e | 906 | void |
15637ed4 | 907 | pk_resetcause (pkp, xp) |
4c45483e GW |
908 | struct pkcb *pkp; |
909 | register struct x25_packet *xp; | |
15637ed4 RG |
910 | { |
911 | register struct pklcd *lcp = | |
912 | pkp -> pk_chan[LCN(xp)]; | |
913 | register int code = xp -> packet_data; | |
914 | ||
915 | if (code > MAXRESETCAUSE) | |
916 | code = 7; /* EXRNCG */ | |
917 | ||
4c45483e GW |
918 | pk_message(LCN(xp), (struct x25config *)lcp -> lcd_pkp, |
919 | "reset code 0x%x, diagnostic 0x%x", | |
920 | xp -> packet_data, 4[(u_char *)xp]); | |
15637ed4 RG |
921 | |
922 | if (lcp -> lcd_so) | |
923 | lcp -> lcd_so -> so_error = Reset_cause[code]; | |
924 | } | |
925 | ||
926 | #define MAXCLEARCAUSE 25 | |
927 | ||
928 | int Clear_cause[] = { | |
929 | EXCLEAR, EXCBUSY, 0, EXCINV, 0, EXCNCG, 0, | |
930 | 0, 0, EXCOUT, 0, EXCAB, 0, EXCNOB, 0, 0, 0, EXCRPE, | |
931 | 0, EXCLPE, 0, 0, 0, 0, 0, EXCRRC | |
932 | }; | |
933 | ||
934 | /* | |
935 | * A clear packet has arrived. Return the cause to the user. | |
936 | */ | |
4c45483e | 937 | void |
15637ed4 | 938 | pk_clearcause (pkp, xp) |
4c45483e GW |
939 | struct pkcb *pkp; |
940 | register struct x25_packet *xp; | |
15637ed4 RG |
941 | { |
942 | register struct pklcd *lcp = | |
943 | pkp -> pk_chan[LCN(xp)]; | |
944 | register int code = xp -> packet_data; | |
945 | ||
946 | if (code > MAXCLEARCAUSE) | |
947 | code = 5; /* EXRNCG */ | |
948 | if (lcp -> lcd_so) | |
949 | lcp -> lcd_so -> so_error = Clear_cause[code]; | |
950 | } | |
951 | ||
952 | char * | |
953 | format_ntn (xcp) | |
954 | register struct x25config *xcp; | |
955 | { | |
956 | ||
957 | return (xcp -> xc_addr.x25_addr); | |
958 | } | |
959 | ||
960 | /* VARARGS1 */ | |
4c45483e GW |
961 | void |
962 | pk_message (int lcn, struct x25config *xcp, const char *fmt, ...) | |
15637ed4 | 963 | { |
4c45483e GW |
964 | va_list args; |
965 | va_start(args, fmt); | |
15637ed4 RG |
966 | |
967 | if (lcn) | |
968 | if (pkcbhead -> pk_next) | |
969 | printf ("X.25(%s): lcn %d: ", format_ntn (xcp), lcn); | |
970 | else | |
971 | printf ("X.25: lcn %d: ", lcn); | |
972 | else | |
973 | if (pkcbhead -> pk_next) | |
974 | printf ("X.25(%s): ", format_ntn (xcp)); | |
975 | else | |
976 | printf ("X.25: "); | |
977 | ||
4c45483e GW |
978 | printf ("%r\n", fmt, args); |
979 | va_end(args); | |
15637ed4 RG |
980 | } |
981 | ||
4c45483e | 982 | int |
15637ed4 | 983 | pk_fragment (lcp, m0, qbit, mbit, wait) |
4c45483e | 984 | register struct pklcd *lcp; |
fde1aeb2 | 985 | struct mbuf *m0; |
4c45483e GW |
986 | int qbit; |
987 | int mbit; | |
988 | int wait; | |
15637ed4 RG |
989 | { |
990 | register struct mbuf *m = m0; | |
991 | register struct x25_packet *xp; | |
992 | register struct sockbuf *sb; | |
993 | struct mbuf *head = 0, *next, **mp = &head, *m_split (); | |
994 | int totlen, psize = 1 << (lcp -> lcd_packetsize); | |
995 | ||
996 | if (m == 0) | |
997 | return 0; | |
998 | if (m -> m_flags & M_PKTHDR == 0) | |
999 | panic ("pk_fragment"); | |
1000 | totlen = m -> m_pkthdr.len; | |
1001 | m -> m_act = 0; | |
1002 | sb = lcp -> lcd_so ? &lcp -> lcd_so -> so_snd : & lcp -> lcd_sb; | |
1003 | do { | |
1004 | if (totlen > psize) { | |
1005 | if ((next = m_split (m, psize, wait)) == 0) | |
1006 | goto abort; | |
1007 | totlen -= psize; | |
1008 | } else | |
1009 | next = 0; | |
1010 | M_PREPEND(m, PKHEADERLN, wait); | |
1011 | if (m == 0) | |
1012 | goto abort; | |
1013 | *mp = m; | |
1014 | mp = & m -> m_act; | |
1015 | *mp = 0; | |
1016 | xp = mtod (m, struct x25_packet *); | |
1017 | 0[(char *)xp] = 0; | |
1018 | if (qbit) | |
1019 | xp -> q_bit = 1; | |
1020 | if (lcp -> lcd_flags & X25_DBIT) | |
1021 | xp -> d_bit = 1; | |
1022 | xp -> fmt_identifier = 1; | |
1023 | xp -> packet_type = X25_DATA; | |
1024 | SET_LCN(xp, lcp -> lcd_lcn); | |
1025 | if (next || (mbit && (totlen == psize || | |
1026 | (lcp -> lcd_flags & X25_DBIT)))) | |
1027 | MBIT(xp) = 1; | |
1028 | } while (m = next); | |
1029 | for (m = head; m; m = next) { | |
1030 | next = m -> m_act; | |
1031 | m -> m_act = 0; | |
1032 | sbappendrecord (sb, m); | |
1033 | } | |
1034 | return 0; | |
1035 | abort: | |
1036 | if (wait) | |
1037 | panic ("pk_fragment null mbuf after wait"); | |
1038 | if (next) | |
1039 | m_freem (next); | |
1040 | for (m = head; m; m = next) { | |
1041 | next = m -> m_act; | |
1042 | m_freem (m); | |
1043 | } | |
1044 | return ENOBUFS; | |
1045 | } | |
1046 |