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