* Copyright (c) University of British Columbia, 1984
* Copyright (C) Computer Science Department IV,
* University of Erlangen-Nuremberg, Germany, 1992
* Copyright (c) 1991, 1992, 1993
* The Regents of the University of California. All rights reserved.
* This code is derived from software contributed to Berkeley by the
* Laboratory for Computation Vision and the Computer Science Department
* of the the University of British Columbia and the Computer Science
* Department (IV) of the University of Erlangen-Nuremberg, Germany.
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* @(#)pk_subr.c 8.1 (Berkeley) 6/10/93
#include <sys/socketvar.h>
#include <netccitt/dll.h>
#include <netccitt/x25.h>
#include <netccitt/x25err.h>
#include <netccitt/pk_var.h>
int pk_sendspace
= 1024 * 2 + 8;
int pk_recvspace
= 1024 * 2 + 8;
struct pklcd_q pklcd_q
= {&pklcd_q
, &pklcd_q
};
struct x25bitslice x25_bitslice
[] = {
* Attach X.25 protocol to socket, allocate logical channel descripter
* and buffer space, and enter LISTEN state if we are to accept
* IN-COMMING CALL packets.
register struct pklcd
*lcp
;
register int error
= ENOBUFS
;
MALLOC(lcp
, struct pklcd
*, sizeof (*lcp
), M_PCB
, M_NOWAIT
);
bzero ((caddr_t
)lcp
, sizeof (*lcp
));
insque (&lcp
-> lcd_q
, &pklcd_q
);
lcp
-> lcd_state
= READY
;
lcp
-> lcd_send
= pk_output
;
error
= soreserve (so
, pk_sendspace
, pk_recvspace
);
if (so
-> so_options
& SO_ACCEPTCONN
)
lcp
-> lcd_state
= LISTEN
;
sbreserve (&lcp
-> lcd_sb
, pk_sendspace
);
so
-> so_pcb
= (caddr_t
) lcp
;
* Disconnect X.25 protocol from socket.
register struct pklcd
*lcp
;
register struct socket
*so
= lcp
-> lcd_so
;
register struct pklcd
*l
, *p
;
switch (lcp
-> lcd_state
) {
for (p
= 0, l
= pk_listenhead
; l
&& l
!= lcp
; p
= l
, l
= l
-> lcd_listen
);
pk_listenhead
= l
-> lcd_listen
;
p
-> lcd_listen
= l
-> lcd_listen
;
pk_clear (lcp
, 241, 0); /* Normal Disconnect */
* Close an X.25 Logical Channel. Discard all space held by the
* connection and internal descriptors. Wake up any sleepers.
register struct socket
*so
= lcp
-> lcd_so
;
* If the X.25 connection is torn down due to link
* level failure (e.g. LLC2 FRMR) and at the same the user
* level is still filling up the socket send buffer that
* send buffer is locked. An attempt to sbflush () that send
* buffer will lead us into - no, not temptation but - panic!
* So - we'll just check wether the send buffer is locked
* and if that's the case we'll mark the lcp as zombie and
* have the pk_timer () do the cleaning ...
if (so
&& so
-> so_snd
.sb_flags
& SB_LOCK
)
lcp
-> lcd_state
= LCN_ZOMBIE
;
/* sofree (so); /* gak!!! you can't do that here */
* Create a template to be used to send X.25 packets on a logical
* channel. It allocates an mbuf and fills in a skeletal packet
* depending on its type. This packet is passed to pk_output where
* the remainer of the packet is filled in.
register struct x25_packet
*xp
;
MGETHDR (m
, M_DONTWAIT
, MT_HEADER
);
* Efficiency hack: leave a four byte gap at the beginning
* of the packet level header with the hope that this will
* be enough room for the link level to insert its header.
m
-> m_data
+= max_linkhdr
;
m
-> m_pkthdr
.len
= m
-> m_len
= PKHEADERLN
;
xp
= mtod (m
, struct x25_packet
*);
*(long *)xp
= 0; /* ugly, but fast */
X25SBITS(xp
-> bits
, fmt_identifier
, 1);
/* xp -> lc_group_number = 0;*/
xp
-> packet_type
= type
;
* This routine restarts all the virtual circuits. Actually,
* the virtual circuits are not "restarted" as such. Instead,
* any active switched circuit is simply returned to READY
pk_restart (pkp
, restart_cause
)
register struct pkcb
*pkp
;
register struct pklcd
*lcp
;
/* Restart all logical channels. */
* Don't do this if we're doing a restart issued from
* inside pk_connect () --- which is only done if and
* only if the X.25 link is down, i.e. a RESTART needs
* to be done to get it up.
if (!(pkp
-> pk_dxerole
& DTE_CONNECTPENDING
)) {
for (i
= 1; i
<= pkp
-> pk_maxlcn
; ++i
)
if ((lcp
= pkp
-> pk_chan
[i
]) != NULL
) {
lcp
-> lcd_so
-> so_error
= ENETRESET
;
lcp
-> lcd_state
= READY
;
lcp
-> lcd_upper (lcp
, 0);
pkp
-> pk_state
= DTE_SENT_RESTART
;
pkp
-> pk_dxerole
&= ~(DTE_PLAYDCE
| DTE_PLAYDTE
);
m
= lcp
-> lcd_template
= pk_template (lcp
-> lcd_lcn
, X25_RESTART
);
m
-> m_pkthdr
.len
= m
-> m_len
+= 2;
mtod (m
, struct x25_packet
*) -> packet_data
= 0; /* DTE only */
mtod (m
, octet
*)[4] = restart_cause
;
* This procedure frees up the Logical Channel Descripter.
register struct pklcd
*lcp
;
lcp
-> lcd_pkp
-> pk_chan
[lcp
-> lcd_lcn
] = NULL
;
free ((caddr_t
)lcp
, M_PCB
);
static struct x25_ifaddr
*
register struct x25_ifaddr
*ia
;
char *addr
= sx
-> x25_addr
;
for (ifp
= ifnet
; ifp
; ifp
= ifp
-> if_next
)
for (ifa
= ifp
-> if_addrlist
; ifa
; ifa
= ifa
-> ifa_next
)
if (ifa
-> ifa_addr
-> sa_family
== AF_CCITT
) {
ia
= (struct x25_ifaddr
*)ifa
;
if (bcmp (addr
, ia
-> ia_xc
.xc_addr
.x25_addr
,
return ((struct x25_ifaddr
*)0);
* Bind a address and protocol value to a socket. The important
* part is the protocol value - the first four characters of the
#define XTRACTPKP(rt) ((rt) -> rt_flags & RTF_GATEWAY ? \
(struct pkcb *) ((struct rtentry *)((rt) -> rt_llinfo)) -> rt_llinfo : \
(struct pkcb *) NULL) : \
(struct pkcb *)((rt) -> rt_llinfo))
register struct pklcd
*pp
;
register struct sockaddr_x25
*sa
;
if (lcp
-> lcd_ceaddr
) /* XXX */
if (pk_checksockaddr (nam
))
sa
= mtod (nam
, struct sockaddr_x25
*);
* If the user wishes to accept calls only from a particular
* net (net != 0), make sure the net is known
} else if (sa
-> x25_net
) {
if (!ifa_ifwithnet ((struct sockaddr
*)sa
))
* For ISO's sake permit default listeners, but only one such . . .
for (pp
= pk_listenhead
; pp
; pp
= pp
-> lcd_listen
) {
register struct sockaddr_x25
*sa2
= pp
-> lcd_ceaddr
;
if ((sa2
-> x25_udlen
== sa
-> x25_udlen
) &&
(sa2
-> x25_udlen
== 0 ||
(bcmp (sa2
-> x25_udata
, sa
-> x25_udata
,
min (sa2
-> x25_udlen
, sa
-> x25_udlen
)) == 0)))
lcp
-> lcd_ceaddr
= &lcp
-> lcd_laddr
;
* Include a bound control block in the list of listeners.
register struct pklcd
*lcp
;
register struct pklcd
**pp
;
if (lcp
-> lcd_ceaddr
== 0)
lcp
-> lcd_state
= LISTEN
;
* Add default listener at end, any others at start.
if (lcp
-> lcd_ceaddr
-> x25_udlen
== 0) {
for (pp
= &pk_listenhead
; *pp
; )
pp
= &((*pp
) -> lcd_listen
);
lcp
-> lcd_listen
= pk_listenhead
;
* Include a listening control block for the benefit of other protocols.
pk_protolisten (spi
, spilen
, callee
)
register struct pklcd
*lcp
= pk_attach ((struct socket
*)0);
register struct mbuf
*nam
;
register struct sockaddr_x25
*sa
;
if (nam
= m_getclr (MT_SONAME
, M_DONTWAIT
)) {
sa
= mtod (nam
, struct sockaddr_x25
*);
sa
-> x25_family
= AF_CCITT
;
sa
-> x25_len
= nam
-> m_len
= sizeof (*sa
);
sa
-> x25_udlen
= spilen
;
sa
-> x25_udata
[0] = spi
;
lcp
-> lcd_upper
= callee
;
lcp
-> lcd_flags
= X25_MBS_HOLD
;
if ((error
= pk_bind (lcp
, nam
)) == 0)
return error
; /* Hopefully Zero !*/
* Associate a logical channel descriptor with a network.
* Fill in the default network specific parameters and then
* set any parameters explicitly specified by the user or
register struct pkcb
*pkp
;
register struct pklcd
*lcp
;
register struct sockaddr_x25
*sa
;
lcp
-> lcd_packetsize
= pkp
-> pk_xcp
-> xc_psize
;
lcp
-> lcd_windowsize
= pkp
-> pk_xcp
-> xc_pwsize
;
lcp
-> lcd_rsn
= MODULUS
- 1;
pkp
-> pk_chan
[lcp
-> lcd_lcn
] = lcp
;
if (sa
-> x25_opts
.op_psize
)
lcp
-> lcd_packetsize
= sa
-> x25_opts
.op_psize
;
sa
-> x25_opts
.op_psize
= lcp
-> lcd_packetsize
;
if (sa
-> x25_opts
.op_wsize
)
lcp
-> lcd_windowsize
= sa
-> x25_opts
.op_wsize
;
sa
-> x25_opts
.op_wsize
= lcp
-> lcd_windowsize
;
sa
-> x25_net
= pkp
-> pk_xcp
-> xc_addr
.x25_net
;
lcp
-> lcd_flags
|= sa
-> x25_opts
.op_flags
;
lcp
-> lcd_stime
= time
.tv_sec
;
register struct pklcd
*lcp
;
register struct sockaddr_x25
*sa
;
register struct pkcb
*pkp
;
register struct rtentry
*rt
;
register struct rtentry
*nrt
;
struct rtentry
*npaidb_enter ();
struct pkcb
*pk_newlink ();
if (sa
-> x25_addr
[0] == '\0')
* Is the destination address known?
if (!(rt
= rtalloc1 ((struct sockaddr
*)sa
, 1)))
if (!(pkp
= XTRACTPKP(rt
)))
pkp
= pk_newlink ((struct x25_ifaddr
*) (rt
-> rt_ifa
),
* Have we entered the LLC address?
if (nrt
= npaidb_enter (rt
-> rt_gateway
, rt_key (rt
), rt
, 0))
* Have we allocated an LLC2 link yet?
if (pkp
-> pk_llnext
== (caddr_t
)0 && pkp
-> pk_llctlinput
) {
struct dll_ctlinfo ctlinfo
;
ctlinfo
.dlcti_pcb
= (caddr_t
) pkp
;
(struct dllconfig
*) (&((struct x25_ifaddr
*)(rt
-> rt_ifa
)) -> ia_xc
);
(pkp
-> pk_llctlinput
) (PRC_CONNECT_REQUEST
, 0, &ctlinfo
);
if (pkp
-> pk_state
!= DTE_READY
&& pkp
-> pk_state
!= DTE_WAITING
)
if ((lcp
-> lcd_lcn
= pk_getlcn (pkp
)) == 0)
lcp
-> lcd_ceaddr
= & lcp
-> lcd_faddr
;
pk_assoc (pkp
, lcp
, lcp
-> lcd_ceaddr
);
* If the link is not up yet, initiate an X.25 RESTART
if (pkp
-> pk_state
== DTE_WAITING
) {
pkp
-> pk_dxerole
|= DTE_CONNECTPENDING
;
pk_ctlinput (PRC_LINKUP
, (struct sockaddr
*)0, pkp
);
soisconnecting (lcp
-> lcd_so
);
soisconnecting (lcp
-> lcd_so
);
lcp
-> lcd_template
= pk_template (lcp
-> lcd_lcn
, X25_CALL
);
pk_callrequest (lcp
, lcp
-> lcd_ceaddr
, pkp
-> pk_xcp
);
return (*pkp
-> pk_ia
-> ia_start
) (lcp
);
* Complete all pending X.25 call requests --- this gets called after
* the X.25 link has been restarted.
#define RESHUFFLELCN(maxlcn, lcn) ((maxlcn) - (lcn) + 1)
register struct pkcb
*pkp
;
register struct pklcd
*lcp
;
if (pkp
-> pk_dxerole
& DTE_CONNECTPENDING
)
pkp
-> pk_dxerole
&= ~DTE_CONNECTPENDING
;
* We pretended to be a DTE for allocating lcns, if
* it turns out that we are in reality performing as a
* DCE we need to reshuffle the lcps.
* /+---------------+-------- -
* +--- * | b (maxlcn-2) | \
* | \ +---------------+ \
* r | \ | c (maxlcn-3) | \
* e | \+---------------+ |
* l | /+---------------+ | c
* | / +---------------+ |
* +---------------+-------- -
if (pkp
-> pk_dxerole
& DTE_PLAYDCE
) {
for (i
= pkp
-> pk_maxlcn
; i
> 0; --i
)
ni
= RESHUFFLELCN(pkp
-> pk_maxlcn
, i
);
pkp
-> pk_chan
[ni
] = pkp
-> pk_chan
[i
];
pkp
-> pk_chan
[i
] = NULL
;
pkp
-> pk_chan
[ni
] -> lcd_lcn
= ni
;
for (i
= 1; i
<= pkp
-> pk_maxlcn
; ++i
)
if ((lcp
= pkp
-> pk_chan
[i
]) != NULL
) {
soisconnecting (lcp -> lcd_so); */
lcp
-> lcd_template
= pk_template (lcp
-> lcd_lcn
, X25_CALL
);
pk_callrequest (lcp
, lcp
-> lcd_ceaddr
, pkp
-> pk_xcp
);
(*pkp
-> pk_ia
-> ia_start
) (lcp
);
* Build the rest of the CALL REQUEST packet. Fill in calling
* address, facilities fields and the user data field.
pk_callrequest (lcp
, sa
, xcp
)
register struct sockaddr_x25
*sa
;
register struct x25config
*xcp
;
register struct x25_calladdr
*a
;
register struct mbuf
*m
= lcp
-> lcd_template
;
register struct x25_packet
*xp
= mtod (m
, struct x25_packet
*);
if (lcp
-> lcd_flags
& X25_DBIT
)
X25SBITS(xp
-> bits
, d_bit
, 1);
a
= (struct x25_calladdr
*) &xp
-> packet_data
;
b
.cp
= (octet
*) a
-> address_field
;
X25SBITS(a
-> addrlens
, called_addrlen
, to_bcd (&b
, sa
, xcp
));
X25SBITS(a
-> addrlens
, calling_addrlen
, to_bcd (&b
, &xcp
-> xc_addr
, xcp
));
m
-> m_pkthdr
.len
= m
-> m_len
+= b
.cp
- (octet
*) a
;
if (lcp
-> lcd_facilities
) {
(m
-> m_next
= lcp
-> lcd_facilities
) -> m_pkthdr
.len
;
lcp
-> lcd_facilities
= 0;
pk_build_facilities (m
, sa
, (int)xcp
-> xc_type
);
m_copyback (m
, m
-> m_pkthdr
.len
, sa
-> x25_udlen
, sa
-> x25_udata
);
pk_build_facilities (m
, sa
, type
)
cp
= mtod (m
, octet
*) + m
-> m_len
;
revcharge
= sa
-> x25_opts
.op_flags
& X25_REVERSE_CHARGE
? 1 : 0;
* This is specific to Datapac X.25(1976) DTEs. International
* calls must have the "hi priority" bit on.
if (type
== X25_1976
&& sa
-> x25_opts
.op_psize
== X25_PS128
)
*fcp
++ = FACILITIES_REVERSE_CHARGE
;
*fcp
++ = FACILITIES_PACKETSIZE
;
*fcp
++ = sa
-> x25_opts
.op_psize
;
*fcp
++ = sa
-> x25_opts
.op_psize
;
*fcp
++ = FACILITIES_WINDOWSIZE
;
*fcp
++ = sa
-> x25_opts
.op_wsize
;
*fcp
++ = sa
-> x25_opts
.op_wsize
;
m
-> m_pkthdr
.len
= (m
-> m_len
+= *cp
+ 1);
register struct bcdinfo
*b
;
register struct x25config
*xcp
;
register char *x
= sa
-> x25_addr
;
unsigned start
= b
-> posn
;
* The nodnic and prepnd0 stuff looks tedious,
* but it does allow full X.121 addresses to be used,
* which is handy for routing info (& OSI type 37 addresses).
if (xcp
-> xc_addr
.x25_net
&& (xcp
-> xc_nodnic
|| xcp
-> xc_prepnd0
)) {
char dnicname
[sizeof (long) * NBBY
/3 + 2];
register char *p
= dnicname
;
sprintf (p
, "%d", xcp
-> xc_addr
.x25_net
& 0x7fff);
for (; *p
; p
++) /* *p == 0 means dnic matched */
if (*p
|| xcp
-> xc_nodnic
== 0)
if (*p
&& xcp
-> xc_prepnd0
) {
if ((b
-> posn
)++ & 0x01)
if ((b
-> posn
)++ & 0x01)
*(b
-> cp
)++ |= *x
++ & 0x0F;
return ((b
-> posn
) - start
);
* This routine gets the first available logical channel number. The
* - from the highest number to lowest number if playing DTE, and
* - from lowest to highest number if playing DCE.
register struct pkcb
*pkp
;
if ( pkp
-> pk_dxerole
& DTE_PLAYDCE
) {
for (i
= 1; i
<= pkp
-> pk_maxlcn
; ++i
)
if (pkp
-> pk_chan
[i
] == NULL
)
for (i
= pkp
-> pk_maxlcn
; i
> 0; --i
)
if (pkp
-> pk_chan
[i
] == NULL
)
i
= ( i
> pkp
-> pk_maxlcn
? 0 : i
);
* This procedure sends a CLEAR request packet. The lc state is
pk_clear (lcp
, diagnostic
, abortive
)
register struct pklcd
*lcp
;
register struct mbuf
*m
= pk_template (lcp
-> lcd_lcn
, X25_CLEAR
);
mtod (m
, struct x25_packet
*) -> packet_data
= 0;
mtod (m
, octet
*)[4] = diagnostic
;
if (lcp
-> lcd_facilities
) {
m
-> m_next
= lcp
-> lcd_facilities
;
m
-> m_pkthdr
.len
+= m
-> m_next
-> m_len
;
lcp
-> lcd_facilities
= 0;
struct socket
*so
= lcp
-> lcd_so
;
struct sockbuf
*sb
= so
? & so
-> so_snd
: & lcp
-> lcd_sb
;
* This procedure generates RNR's or RR's to inhibit or enable
* inward data flow, if the current state changes (blocked ==> open or
* vice versa), or if forced to generate one. One forces RNR's to ack data.
pk_flowcontrol (lcp
, inhibit
, forced
)
register struct pklcd
*lcp
;
inhibit
= (inhibit
!= 0);
if (lcp
== 0 || lcp
-> lcd_state
!= DATA_TRANSFER
||
(forced
== 0 && lcp
-> lcd_rxrnr_condition
== inhibit
))
lcp
-> lcd_rxrnr_condition
= inhibit
;
pk_template (lcp
-> lcd_lcn
, inhibit
? X25_RNR
: X25_RR
);
* This procedure sends a RESET request packet. It re-intializes
pk_reset (lcp
, diagnostic
)
register struct pklcd
*lcp
;
register struct socket
*so
= lcp
-> lcd_so
;
if (lcp
-> lcd_state
!= DATA_TRANSFER
)
so
-> so_error
= ECONNRESET
;
lcp
-> lcd_reset_condition
= TRUE
;
/* Reset all the control variables for the channel. */
lcp
-> lcd_window_condition
= lcp
-> lcd_rnr_condition
=
lcp
-> lcd_intrconf_pending
= FALSE
;
lcp
-> lcd_rsn
= MODULUS
- 1;
lcp
-> lcd_output_window
= lcp
-> lcd_input_window
=
lcp
-> lcd_last_transmitted_pr
= 0;
m
= lcp
-> lcd_template
= pk_template (lcp
-> lcd_lcn
, X25_RESET
);
m
-> m_pkthdr
.len
= m
-> m_len
+= 2;
mtod (m
, struct x25_packet
*) -> packet_data
= 0;
mtod (m
, octet
*)[4] = diagnostic
;
* This procedure frees all data queued for output or delivery on a
register struct pklcd
*lcp
;
register struct socket
*so
;
m_freem (lcp
-> lcd_template
);
m_freem (lcp
-> lcd_cps
);
if (lcp
-> lcd_facilities
) {
m_freem (lcp
-> lcd_facilities
);
lcp
-> lcd_facilities
= 0;
sbflush (&lcp
-> lcd_sb
);
* This procedure handles all local protocol procedure errors.
pk_procerror (error
, lcp
, errstr
, diagnostic
)
register struct pklcd
*lcp
;
pk_message (lcp
-> lcd_lcn
, lcp
-> lcd_pkp
-> pk_xcp
, errstr
);
lcp
-> lcd_so
-> so_error
= ECONNABORTED
;
soisdisconnecting (lcp
-> lcd_so
);
pk_clear (lcp
, diagnostic
, 1);
pk_reset (lcp
, diagnostic
);
* This procedure is called during the DATA TRANSFER state to check
* and process the P(R) values received in the DATA, RR OR RNR
register struct socket
*so
= lcp
-> lcd_so
;
if (lcp
-> lcd_output_window
== pr
)
if (lcp
-> lcd_output_window
< lcp
-> lcd_ssn
) {
if (pr
< lcp
-> lcd_output_window
|| pr
> lcp
-> lcd_ssn
) {
pk_procerror (RESET
, lcp
,
"p(r) flow control error", 2);
if (pr
< lcp
-> lcd_output_window
&& pr
> lcp
-> lcd_ssn
) {
pk_procerror (RESET
, lcp
,
"p(r) flow control error #2", 2);
lcp
-> lcd_output_window
= pr
; /* Rotate window. */
if (lcp
-> lcd_window_condition
== TRUE
)
lcp
-> lcd_window_condition
= FALSE
;
if (so
&& ((so
-> so_snd
.sb_flags
& SB_WAIT
) ||
(so
-> so_snd
.sb_flags
& SB_NOTIFY
)))
* This procedure decodes the X.25 level 3 packet returning a
* code to be used in switchs or arrays.
register struct x25_packet
*xp
;
if (X25GBITS(xp
-> bits
, fmt_identifier
) != 1)
* Make sure that the logical channel group number is 0.
* This restriction may be removed at some later date.
if (xp
-> lc_group_number
!= 0)
* Test for data packet first.
if (!(xp
-> packet_type
& DATA_PACKET_DESIGNATOR
))
* Test if flow control packet (RR or RNR).
if (!(xp
-> packet_type
& RR_OR_RNR_PACKET_DESIGNATOR
))
switch (xp
-> packet_type
& 0x1f) {
* Determine the rest of the packet types.
switch (xp
-> packet_type
) {
case X25_INTERRUPT_CONFIRM
:
case X25_RESTART_CONFIRM
:
* A restart packet has been received. Print out the reason
pk_restartcause (pkp
, xp
)
register struct x25_packet
*xp
;
register struct x25config
*xcp
= pkp
-> pk_xcp
;
register int lcn
= LCN(xp
);
switch (xp
-> packet_data
) {
case X25_RESTART_LOCAL_PROCEDURE_ERROR
:
pk_message (lcn
, xcp
, "restart: local procedure error");
case X25_RESTART_NETWORK_CONGESTION
:
pk_message (lcn
, xcp
, "restart: network congestion");
case X25_RESTART_NETWORK_OPERATIONAL
:
pk_message (lcn
, xcp
, "restart: network operational");
pk_message (lcn
, xcp
, "restart: unknown cause");
EXRESET
, EXROUT
, 0, EXRRPE
, 0, EXRLPE
, 0, EXRNCG
* A reset packet has arrived. Return the cause to the user.
register struct x25_packet
*xp
;
register struct pklcd
*lcp
=
register int code
= xp
-> packet_data
;
if (code
> MAXRESETCAUSE
)
pk_message (LCN(xp
), lcp
-> lcd_pkp
, "reset code 0x%x, diagnostic 0x%x",
xp
-> packet_data
, 4[(u_char
*)xp
]);
lcp
-> lcd_so
-> so_error
= Reset_cause
[code
];
EXCLEAR
, EXCBUSY
, 0, EXCINV
, 0, EXCNCG
, 0,
0, 0, EXCOUT
, 0, EXCAB
, 0, EXCNOB
, 0, 0, 0, EXCRPE
,
0, EXCLPE
, 0, 0, 0, 0, 0, EXCRRC
* A clear packet has arrived. Return the cause to the user.
register struct x25_packet
*xp
;
register struct pklcd
*lcp
=
register int code
= xp
-> packet_data
;
if (code
> MAXCLEARCAUSE
)
lcp
-> lcd_so
-> so_error
= Clear_cause
[code
];
register struct x25config
*xcp
;
return (xcp
-> xc_addr
.x25_addr
);
pk_message (lcn
, xcp
, fmt
, a1
, a2
, a3
, a4
, a5
, a6
)
printf ("X.25(%s): lcn %d: ", format_ntn (xcp
), lcn
);
printf ("X.25: lcn %d: ", lcn
);
printf ("X.25(%s): ", format_ntn (xcp
));
printf (fmt
, a1
, a2
, a3
, a4
, a5
, a6
);
pk_fragment (lcp
, m0
, qbit
, mbit
, wait
)
register struct pklcd
*lcp
;
register struct mbuf
*m
= m0
;
register struct x25_packet
*xp
;
register struct sockbuf
*sb
;
struct mbuf
*head
= 0, *next
, **mp
= &head
, *m_split ();
int totlen
, psize
= 1 << (lcp
-> lcd_packetsize
);
if (m
-> m_flags
& M_PKTHDR
== 0)
totlen
= m
-> m_pkthdr
.len
;
sb
= lcp
-> lcd_so
? &lcp
-> lcd_so
-> so_snd
: & lcp
-> lcd_sb
;
if ((next
= m_split (m
, psize
, wait
)) == 0)
M_PREPEND(m
, PKHEADERLN
, wait
);
xp
= mtod (m
, struct x25_packet
*);
X25SBITS(xp
-> bits
, q_bit
, 1);
if (lcp
-> lcd_flags
& X25_DBIT
)
X25SBITS(xp
-> bits
, d_bit
, 1);
X25SBITS(xp
-> bits
, fmt_identifier
, 1);
xp
-> packet_type
= X25_DATA
;
SET_LCN(xp
, lcp
-> lcd_lcn
);
if (next
|| (mbit
&& (totlen
== psize
||
(lcp
-> lcd_flags
& X25_DBIT
))))
for (m
= head
; m
; m
= next
) {
panic ("pk_fragment null mbuf after wait");
for (m
= head
; m
; m
= next
) {