2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
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.
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
20 * @APPLE_LICENSE_HEADER_END@
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.
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.
34 * Redistribution and use in source and binary forms, with or without
35 * modification, are permitted provided that the following conditions
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.
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
62 * @(#)pk_subr.c 8.1 (Berkeley) 6/10/93
65 #include <sys/param.h>
66 #include <sys/systm.h>
68 #include <sys/socket.h>
69 #include <sys/protosw.h>
70 #include <sys/socketvar.h>
71 #include <sys/errno.h>
73 #include <sys/kernel.h>
74 #include <sys/malloc.h>
77 #include <net/route.h>
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>
85 int pk_sendspace
= 1024 * 2 + 8;
86 int pk_recvspace
= 1024 * 2 + 8;
88 struct pklcd_q pklcd_q
= {&pklcd_q
, &pklcd_q
};
90 struct x25bitslice x25_bitslice
[] = {
91 /* mask, shift value */
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.
115 register struct pklcd
*lcp
;
116 register int error
= ENOBUFS
;
119 MALLOC(lcp
, struct pklcd
*, sizeof (*lcp
), M_PCB
, M_NOWAIT
);
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
;
126 error
= soreserve (so
, pk_sendspace
, pk_recvspace
);
128 if (so
-> so_options
& SO_ACCEPTCONN
)
129 lcp
-> lcd_state
= LISTEN
;
131 sbreserve (&lcp
-> lcd_sb
, pk_sendspace
);
134 so
-> so_pcb
= (caddr_t
) lcp
;
135 so
-> so_error
= error
;
141 * Disconnect X.25 protocol from socket.
145 register struct pklcd
*lcp
;
147 register struct socket
*so
= lcp
-> lcd_so
;
148 register struct pklcd
*l
, *p
;
150 switch (lcp
-> lcd_state
) {
152 for (p
= 0, l
= pk_listenhead
; l
&& l
!= lcp
; p
= l
, l
= l
-> lcd_listen
);
155 pk_listenhead
= l
-> lcd_listen
;
159 p
-> lcd_listen
= l
-> lcd_listen
;
175 soisdisconnecting (so
);
176 sbflush (&so
-> so_rcv
);
178 pk_clear (lcp
, 241, 0); /* Normal Disconnect */
184 * Close an X.25 Logical Channel. Discard all space held by the
185 * connection and internal descriptors. Wake up any sleepers.
191 register struct socket
*so
= lcp
-> lcd_so
;
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 ...
204 if (so
&& so
-> so_snd
.sb_flags
& SB_LOCK
)
205 lcp
-> lcd_state
= LCN_ZOMBIE
;
213 soisdisconnected (so
);
214 /* sofree (so); /* gak!!! you can't do that here */
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.
225 pk_template (lcn
, type
)
228 register struct mbuf
*m
;
229 register struct x25_packet
*xp
;
231 MGETHDR (m
, M_DONTWAIT
, MT_HEADER
);
233 panic ("pk_template");
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.
241 m
-> m_data
+= max_linkhdr
;
242 m
-> m_pkthdr
.len
= m
-> m_len
= PKHEADERLN
;
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;*/
251 xp
-> packet_type
= type
;
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
263 pk_restart (pkp
, restart_cause
)
264 register struct pkcb
*pkp
;
267 register struct mbuf
*m
;
268 register struct pklcd
*lcp
;
271 /* Restart all logical channels. */
272 if (pkp
-> pk_chan
== 0)
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.
281 if (!(pkp
-> pk_dxerole
& DTE_CONNECTPENDING
)) {
282 for (i
= 1; i
<= pkp
-> pk_maxlcn
; ++i
)
283 if ((lcp
= pkp
-> pk_chan
[i
]) != NULL
) {
285 lcp
-> lcd_so
-> so_error
= ENETRESET
;
289 lcp
-> lcd_state
= READY
;
290 if (lcp
-> lcd_upper
)
291 lcp
-> lcd_upper (lcp
, 0);
296 if (restart_cause
< 0)
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
;
311 * This procedure frees up the Logical Channel Descripter.
315 register struct pklcd
*lcp
;
320 if (lcp
-> lcd_lcn
> 0)
321 lcp
-> lcd_pkp
-> pk_chan
[lcp
-> lcd_lcn
] = NULL
;
324 remque (&lcp
-> lcd_q
);
325 FREE((caddr_t
)lcp
, M_PCB
);
328 static struct x25_ifaddr
*
330 struct sockaddr_x25
*sx
;
334 register struct x25_ifaddr
*ia
;
335 char *addr
= sx
-> x25_addr
;
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
,
346 return ((struct x25_ifaddr
*)0);
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.
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))
366 register struct pklcd
*pp
;
367 register struct sockaddr_x25
*sa
;
370 return (EADDRNOTAVAIL
);
371 if (lcp
-> lcd_ceaddr
) /* XXX */
373 if (pk_checksockaddr (nam
))
375 sa
= mtod (nam
, struct sockaddr_x25
*);
378 * If the user wishes to accept calls only from a particular
379 * net (net != 0), make sure the net is known
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
);
391 * For ISO's sake permit default listeners, but only one such . . .
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)))
401 lcp
-> lcd_laddr
= *sa
;
402 lcp
-> lcd_ceaddr
= &lcp
-> lcd_laddr
;
407 * Include a bound control block in the list of listeners.
410 register struct pklcd
*lcp
;
412 register struct pklcd
**pp
;
414 if (lcp
-> lcd_ceaddr
== 0)
415 return (EDESTADDRREQ
);
417 lcp
-> lcd_state
= LISTEN
;
419 * Add default listener at end, any others at start.
421 if (lcp
-> lcd_ceaddr
-> x25_udlen
== 0) {
422 for (pp
= &pk_listenhead
; *pp
; )
423 pp
= &((*pp
) -> lcd_listen
);
426 lcp
-> lcd_listen
= pk_listenhead
;
432 * Include a listening control block for the benefit of other protocols.
434 pk_protolisten (spi
, spilen
, callee
)
437 register struct pklcd
*lcp
= pk_attach ((struct socket
*)0);
438 register struct mbuf
*nam
;
439 register struct sockaddr_x25
*sa
;
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
);
458 return error
; /* Hopefully Zero !*/
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
468 pk_assoc (pkp
, lcp
, sa
)
469 register struct pkcb
*pkp
;
470 register struct pklcd
*lcp
;
471 register struct sockaddr_x25
*sa
;
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
;
480 if (sa
-> x25_opts
.op_psize
)
481 lcp
-> lcd_packetsize
= sa
-> x25_opts
.op_psize
;
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
;
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
;
494 register struct pklcd
*lcp
;
495 register struct sockaddr_x25
*sa
;
497 register struct pkcb
*pkp
;
498 register struct rtentry
*rt
;
499 register struct rtentry
*nrt
;
501 struct rtentry
*npaidb_enter ();
502 struct pkcb
*pk_newlink ();
504 if (sa
-> x25_addr
[0] == '\0')
505 return (EDESTADDRREQ
);
508 * Is the destination address known?
510 if (!(rt
= rtalloc1 ((struct sockaddr
*)sa
, 1)))
511 return (ENETUNREACH
);
513 if (!(pkp
= XTRACTPKP(rt
)))
514 pkp
= pk_newlink ((struct x25_ifaddr
*) (rt
-> rt_ifa
),
518 * Have we entered the LLC address?
520 if (nrt
= npaidb_enter (rt
-> rt_gateway
, rt_key (rt
), rt
, 0))
521 pkp
-> pk_llrt
= nrt
;
524 * Have we allocated an LLC2 link yet?
526 if (pkp
-> pk_llnext
== (caddr_t
)0 && pkp
-> pk_llctlinput
) {
527 struct dll_ctlinfo ctlinfo
;
529 ctlinfo
.dlcti_rt
= rt
;
530 ctlinfo
.dlcti_pcb
= (caddr_t
) pkp
;
532 (struct dllconfig
*) (&((struct x25_ifaddr
*)(rt
-> rt_ifa
)) -> ia_xc
);
534 (pkp
-> pk_llctlinput
) (PRC_CONNECT_REQUEST
, 0, &ctlinfo
);
537 if (pkp
-> pk_state
!= DTE_READY
&& pkp
-> pk_state
!= DTE_WAITING
)
539 if ((lcp
-> lcd_lcn
= pk_getlcn (pkp
)) == 0)
542 lcp
-> lcd_faddr
= *sa
;
543 lcp
-> lcd_ceaddr
= & lcp
-> lcd_faddr
;
544 pk_assoc (pkp
, lcp
, lcp
-> lcd_ceaddr
);
547 * If the link is not up yet, initiate an X.25 RESTART
549 if (pkp
-> pk_state
== DTE_WAITING
) {
550 pkp
-> pk_dxerole
|= DTE_CONNECTPENDING
;
551 pk_ctlinput (PRC_LINKUP
, (struct sockaddr
*)0, pkp
);
553 soisconnecting (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
);
565 * Complete all pending X.25 call requests --- this gets called after
566 * the X.25 link has been restarted.
568 #define RESHUFFLELCN(maxlcn, lcn) ((maxlcn) - (lcn) + 1)
570 pk_callcomplete (pkp
)
571 register struct pkcb
*pkp
;
573 register struct pklcd
*lcp
;
578 if (pkp
-> pk_dxerole
& DTE_CONNECTPENDING
)
579 pkp
-> pk_dxerole
&= ~DTE_CONNECTPENDING
;
582 if (pkp
-> pk_chan
== 0)
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.
590 * /+---------------+-------- -
591 * / | a (maxlcn-1) | \
592 * / +---------------+ \
593 * +--- * | b (maxlcn-2) | \
594 * | \ +---------------+ \
595 * r | \ | c (maxlcn-3) | \
596 * e | \+---------------+ |
602 * l | /+---------------+ | c
603 * e | / | c' ( 3 ) | | n
604 * | / +---------------+ |
605 * +--> * | b' ( 2 ) | /
606 * \ +---------------+ /
608 * \+---------------+ /
610 * +---------------+-------- -
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
;
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
);
639 * Build the rest of the CALL REQUEST packet. Fill in calling
640 * address, facilities fields and the user data field.
643 pk_callrequest (lcp
, sa
, xcp
)
645 register struct sockaddr_x25
*sa
;
646 register struct x25config
*xcp
;
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
*);
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
;
658 X25SBITS(a
-> addrlens
, called_addrlen
, to_bcd (&b
, sa
, xcp
));
659 X25SBITS(a
-> addrlens
, calling_addrlen
, to_bcd (&b
, &xcp
-> xc_addr
, xcp
));
662 m
-> m_pkthdr
.len
= m
-> m_len
+= b
.cp
- (octet
*) a
;
664 if (lcp
-> lcd_facilities
) {
666 (m
-> m_next
= lcp
-> lcd_facilities
) -> m_pkthdr
.len
;
667 lcp
-> lcd_facilities
= 0;
669 pk_build_facilities (m
, sa
, (int)xcp
-> xc_type
);
671 m_copyback (m
, m
-> m_pkthdr
.len
, sa
-> x25_udlen
, sa
-> x25_udata
);
674 pk_build_facilities (m
, sa
, type
)
675 register struct mbuf
*m
;
676 struct sockaddr_x25
*sa
;
680 register int revcharge
;
682 cp
= mtod (m
, octet
*) + m
-> m_len
;
684 revcharge
= sa
-> x25_opts
.op_flags
& X25_REVERSE_CHARGE
? 1 : 0;
686 * This is specific to Datapac X.25(1976) DTEs. International
687 * calls must have the "hi priority" bit on.
689 if (type
== X25_1976
&& sa
-> x25_opts
.op_psize
== X25_PS128
)
692 *fcp
++ = FACILITIES_REVERSE_CHARGE
;
698 *fcp
++ = FACILITIES_PACKETSIZE
;
699 *fcp
++ = sa
-> x25_opts
.op_psize
;
700 *fcp
++ = sa
-> x25_opts
.op_psize
;
702 *fcp
++ = FACILITIES_WINDOWSIZE
;
703 *fcp
++ = sa
-> x25_opts
.op_wsize
;
704 *fcp
++ = sa
-> x25_opts
.op_wsize
;
707 m
-> m_pkthdr
.len
= (m
-> m_len
+= *cp
+ 1);
711 register struct bcdinfo
*b
;
712 struct sockaddr_x25
*sa
;
713 register struct x25config
*xcp
;
715 register char *x
= sa
-> x25_addr
;
716 unsigned start
= b
-> posn
;
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).
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
;
726 sprintf (p
, "%d", xcp
-> xc_addr
.x25_net
& 0x7fff);
727 for (; *p
; p
++) /* *p == 0 means dnic matched */
728 if ((*p
^ *x
++) & 0x0f)
730 if (*p
|| xcp
-> xc_nodnic
== 0)
732 if (*p
&& xcp
-> xc_prepnd0
) {
733 if ((b
-> posn
)++ & 0x01)
740 if ((b
-> posn
)++ & 0x01)
741 *(b
-> cp
)++ |= *x
++ & 0x0F;
743 *(b
-> cp
) = *x
++ << 4;
744 return ((b
-> posn
) - start
);
748 * This routine gets the first available logical channel number. The
750 * - from the highest number to lowest number if playing DTE, and
751 * - from lowest to highest number if playing DCE.
755 register struct pkcb
*pkp
;
759 if (pkp
-> pk_chan
== 0)
761 if ( pkp
-> pk_dxerole
& DTE_PLAYDCE
) {
762 for (i
= 1; i
<= pkp
-> pk_maxlcn
; ++i
)
763 if (pkp
-> pk_chan
[i
] == NULL
)
766 for (i
= pkp
-> pk_maxlcn
; i
> 0; --i
)
767 if (pkp
-> pk_chan
[i
] == NULL
)
770 i
= ( i
> pkp
-> pk_maxlcn
? 0 : i
);
775 * This procedure sends a CLEAR request packet. The lc state is
776 * set to "SENT_CLEAR".
779 pk_clear (lcp
, diagnostic
, abortive
)
780 register struct pklcd
*lcp
;
782 register struct mbuf
*m
= pk_template (lcp
-> lcd_lcn
, X25_CLEAR
);
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;
794 lcp
-> lcd_template
= m
;
796 struct socket
*so
= lcp
-> lcd_so
;
797 struct sockbuf
*sb
= so
? & so
-> so_snd
: & lcp
-> lcd_sb
;
798 sbappendrecord (sb
, m
);
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.
809 pk_flowcontrol (lcp
, inhibit
, forced
)
810 register struct pklcd
*lcp
;
812 inhibit
= (inhibit
!= 0);
813 if (lcp
== 0 || lcp
-> lcd_state
!= DATA_TRANSFER
||
814 (forced
== 0 && lcp
-> lcd_rxrnr_condition
== inhibit
))
816 lcp
-> lcd_rxrnr_condition
= inhibit
;
817 lcp
-> lcd_template
=
818 pk_template (lcp
-> lcd_lcn
, inhibit
? X25_RNR
: X25_RR
);
823 * This procedure sends a RESET request packet. It re-intializes
828 pk_reset (lcp
, diagnostic
)
829 register struct pklcd
*lcp
;
831 register struct mbuf
*m
;
832 register struct socket
*so
= lcp
-> lcd_so
;
834 if (lcp
-> lcd_state
!= DATA_TRANSFER
)
838 so
-> so_error
= ECONNRESET
;
839 lcp
-> lcd_reset_condition
= TRUE
;
841 /* Reset all the control variables for the channel. */
843 lcp
-> lcd_window_condition
= lcp
-> lcd_rnr_condition
=
844 lcp
-> lcd_intrconf_pending
= FALSE
;
845 lcp
-> lcd_rsn
= MODULUS
- 1;
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
;
858 * This procedure frees all data queued for output or delivery on a
863 register struct pklcd
*lcp
;
865 register struct socket
*so
;
867 if (lcp
-> lcd_template
)
868 m_freem (lcp
-> lcd_template
);
870 if (lcp
-> lcd_cps
) {
871 m_freem (lcp
-> lcd_cps
);
874 if (lcp
-> lcd_facilities
) {
875 m_freem (lcp
-> lcd_facilities
);
876 lcp
-> lcd_facilities
= 0;
878 if (so
= lcp
-> lcd_so
)
879 sbflush (&so
-> so_snd
);
881 sbflush (&lcp
-> lcd_sb
);
885 * This procedure handles all local protocol procedure errors.
888 pk_procerror (error
, lcp
, errstr
, diagnostic
)
889 register struct pklcd
*lcp
;
893 pk_message (lcp
-> lcd_lcn
, lcp
-> lcd_pkp
-> pk_xcp
, errstr
);
898 lcp
-> lcd_so
-> so_error
= ECONNABORTED
;
899 soisdisconnecting (lcp
-> lcd_so
);
901 pk_clear (lcp
, diagnostic
, 1);
905 pk_reset (lcp
, diagnostic
);
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
919 register struct socket
*so
= lcp
-> lcd_so
;
921 if (lcp
-> lcd_output_window
== pr
)
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
);
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
);
938 lcp
-> lcd_output_window
= pr
; /* Rotate window. */
939 if (lcp
-> lcd_window_condition
== TRUE
)
940 lcp
-> lcd_window_condition
= FALSE
;
942 if (so
&& ((so
-> so_snd
.sb_flags
& SB_WAIT
) ||
943 (so
-> so_snd
.sb_flags
& SB_NOTIFY
)))
950 * This procedure decodes the X.25 level 3 packet returning a
951 * code to be used in switchs or arrays.
955 register struct x25_packet
*xp
;
959 if (X25GBITS(xp
-> bits
, fmt_identifier
) != 1)
960 return (INVALID_PACKET
);
961 #ifdef ancient_history
963 * Make sure that the logical channel group number is 0.
964 * This restriction may be removed at some later date.
966 if (xp
-> lc_group_number
!= 0)
967 return (INVALID_PACKET
);
970 * Test for data packet first.
972 if (!(xp
-> packet_type
& DATA_PACKET_DESIGNATOR
))
976 * Test if flow control packet (RR or RNR).
978 if (!(xp
-> packet_type
& RR_OR_RNR_PACKET_DESIGNATOR
))
979 switch (xp
-> packet_type
& 0x1f) {
989 * Determine the rest of the packet types.
991 switch (xp
-> packet_type
) {
996 case X25_CALL_ACCEPTED
:
997 type
= CALL_ACCEPTED
;
1004 case X25_CLEAR_CONFIRM
:
1012 case X25_INTERRUPT_CONFIRM
:
1013 type
= INTERRUPT_CONF
;
1020 case X25_RESET_CONFIRM
:
1028 case X25_RESTART_CONFIRM
:
1029 type
= RESTART_CONF
;
1032 case X25_DIAGNOSTIC
:
1037 type
= INVALID_PACKET
;
1043 * A restart packet has been received. Print out the reason
1047 pk_restartcause (pkp
, xp
)
1049 register struct x25_packet
*xp
;
1051 register struct x25config
*xcp
= pkp
-> pk_xcp
;
1052 register int lcn
= LCN(xp
);
1054 switch (xp
-> packet_data
) {
1055 case X25_RESTART_LOCAL_PROCEDURE_ERROR
:
1056 pk_message (lcn
, xcp
, "restart: local procedure error");
1059 case X25_RESTART_NETWORK_CONGESTION
:
1060 pk_message (lcn
, xcp
, "restart: network congestion");
1063 case X25_RESTART_NETWORK_OPERATIONAL
:
1064 pk_message (lcn
, xcp
, "restart: network operational");
1068 pk_message (lcn
, xcp
, "restart: unknown cause");
1072 #define MAXRESETCAUSE 7
1074 int Reset_cause
[] = {
1075 EXRESET
, EXROUT
, 0, EXRRPE
, 0, EXRLPE
, 0, EXRNCG
1079 * A reset packet has arrived. Return the cause to the user.
1082 pk_resetcause (pkp
, xp
)
1084 register struct x25_packet
*xp
;
1086 register struct pklcd
*lcp
=
1087 pkp
-> pk_chan
[LCN(xp
)];
1088 register int code
= xp
-> packet_data
;
1090 if (code
> MAXRESETCAUSE
)
1091 code
= 7; /* EXRNCG */
1093 pk_message (LCN(xp
), lcp
-> lcd_pkp
, "reset code 0x%x, diagnostic 0x%x",
1094 xp
-> packet_data
, 4[(u_char
*)xp
]);
1097 lcp
-> lcd_so
-> so_error
= Reset_cause
[code
];
1100 #define MAXCLEARCAUSE 25
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
1109 * A clear packet has arrived. Return the cause to the user.
1112 pk_clearcause (pkp
, xp
)
1114 register struct x25_packet
*xp
;
1116 register struct pklcd
*lcp
=
1117 pkp
-> pk_chan
[LCN(xp
)];
1118 register int code
= xp
-> packet_data
;
1120 if (code
> MAXCLEARCAUSE
)
1121 code
= 5; /* EXRNCG */
1123 lcp
-> lcd_so
-> so_error
= Clear_cause
[code
];
1128 register struct x25config
*xcp
;
1131 return (xcp
-> xc_addr
.x25_addr
);
1135 pk_message (lcn
, xcp
, fmt
, a1
, a2
, a3
, a4
, a5
, a6
)
1136 struct x25config
*xcp
;
1142 printf ("X.25(%s): lcn %d: ", format_ntn (xcp
), lcn
);
1144 printf ("X.25: lcn %d: ", lcn
);
1147 printf ("X.25(%s): ", format_ntn (xcp
));
1151 printf (fmt
, a1
, a2
, a3
, a4
, a5
, a6
);
1155 pk_fragment (lcp
, m0
, qbit
, mbit
, wait
)
1157 register struct pklcd
*lcp
;
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
);
1167 if (m
-> m_flags
& M_PKTHDR
== 0)
1168 panic ("pk_fragment");
1169 totlen
= m
-> m_pkthdr
.len
;
1171 sb
= lcp
-> lcd_so
? &lcp
-> lcd_so
-> so_snd
: & lcp
-> lcd_sb
;
1173 if (totlen
> psize
) {
1174 if ((next
= m_split (m
, psize
, wait
)) == 0)
1179 M_PREPEND(m
, PKHEADERLN
, wait
);
1185 xp
= mtod (m
, struct x25_packet
*);
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
))))
1198 for (m
= head
; m
; m
= next
) {
1201 sbappendrecord (sb
, m
);
1206 panic ("pk_fragment null mbuf after wait");
1209 for (m
= head
; m
; m
= next
) {