* Copyright (c) University of British Columbia, 1984
* Copyright (C) Computer Science Department IV,
* University of Erlangen-Nuremberg, Germany, 1992
* Copyright (c) 1991, 1992 The Regents of the University of California.
* 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.
* %sccs.include.redist.c%
* @(#)pk_input.c 7.19 (Berkeley) %G%
#include <sys/socketvar.h>
#include <netccitt/dll.h>
#include <netccitt/x25.h>
#include <netccitt/pk_var.h>
#include <netccitt/llc_var.h>
struct pkcb_q pkcb_q
= {&pkcb_q
, &pkcb_q
};
* ccittintr() is the generic interrupt handler for HDLC, LLC2, and X.25. This
* allows to have kernel running X.25 but no HDLC or LLC2 or both (in case we
* employ boards that do all the stuff themselves, e.g. ADAX X.25 or TPS ISDN.)
extern struct ifqueue pkintrq
;
extern struct ifqueue hdintrq
;
extern struct ifqueue llcintrq
;
register struct x25config
*xcp
= &ia
->ia_xc
;
register struct pkcb
*pkp
;
register struct pklcd
*lcp
;
register struct protosw
*pp
;
pp
= pffindproto (AF_CCITT
, (int)xcp
-> xc_lproto
, 0);
if (pp
== 0 || pp
-> pr_output
== 0) {
pk_message (0, xcp
, "link level protosw error");
return ((struct pkcb
*)0);
* Allocate a network control block structure
size
= sizeof (struct pkcb
);
pkp
= (struct pkcb
*)malloc(size
, M_PCB
, M_WAITOK
);
return ((struct pkcb
*)0);
bzero ((caddr_t
)pkp
, size
);
pkp
-> pk_lloutput
= pp
-> pr_output
;
pkp
-> pk_llctlinput
= (caddr_t (*)())pp
-> pr_ctlinput
;
pkp
-> pk_state
= DTE_WAITING
;
pkp
-> pk_llnext
= llnext
;
if (xcp
-> xc_pwsize
== 0)
xcp
-> xc_pwsize
= DEFAULT_WINDOW_SIZE
;
if (xcp
-> xc_psize
== 0)
xcp
-> xc_psize
= X25_PS128
;
* Allocate logical channel descriptor vector
register struct pkcb
*pkp
;
register struct protosw
*pp
;
* Essentially we have the choice to
* (a) go ahead and let the route be deleted and
* leave the pkcb associated with that route
* as it is, i.e. the connections stay open
* (b) do a pk_disconnect() on all channels associated
* with the route via the pkcb and then proceed.
* For the time being we stick with (b)
for(i
= 1; i
< pkp
->pk_maxlcn
; ++i
)
pk_disconnect(pkp
->pk_chan
[i
]);
* First find the protoswitch to get hold of the link level
* protocol to be notified that the packet level entity is
pp
= pffindproto (AF_CCITT
, (int)pkp
->pk_xcp
-> xc_lproto
, 0);
if (pp
== 0 || pp
-> pr_output
== 0) {
pk_message (0, pkp
-> pk_xcp
, "link level protosw error");
if (!pkp
-> pk_refcount
) {
struct dll_ctlinfo ctlinfo
;
if (pkp
-> pk_rt
-> rt_llinfo
== (caddr_t
) pkp
)
pkp
-> pk_rt
-> rt_llinfo
= (caddr_t
) NULL
;
* Tell the link level that the pkcb is dissolving
if (pp
-> pr_ctlinput
&& pkp
-> pk_llnext
) {
ctlinfo
.dlcti_pcb
= pkp
-> pk_llnext
;
ctlinfo
.dlcti_rt
= pkp
-> pk_rt
;
(pp
-> pr_ctlinput
)(PRC_DISCONNECT_REQUEST
,
pkp
-> pk_xcp
, &ctlinfo
);
free((caddr_t
) pkp
-> pk_chan
, M_IFADDR
);
free((caddr_t
) pkp
, M_PCB
);
register struct pkcb
*pkp
;
struct pklcd
*dev_lcp
= 0;
struct x25config
*xcp
= pkp
-> pk_xcp
;
(pkp
-> pk_maxlcn
!= xcp
-> xc_maxlcn
)) {
pk_restart (pkp
, X25_RESTART_NETWORK_CONGESTION
);
dev_lcp
= pkp
-> pk_chan
[0];
free ((caddr_t
)pkp
-> pk_chan
, M_IFADDR
);
if (pkp
-> pk_chan
== 0) {
pkp
-> pk_maxlcn
= xcp
-> xc_maxlcn
;
size
= (pkp
-> pk_maxlcn
+ 1) * sizeof (struct pklcd
*);
(struct pklcd
**) malloc (size
, M_IFADDR
, M_WAITOK
);
bzero ((caddr_t
)pkp
-> pk_chan
, size
);
* Allocate a logical channel descriptor for lcn 0
(dev_lcp
= pk_attach ((struct socket
*)0)) == 0)
dev_lcp
-> lcd_state
= READY
;
dev_lcp
-> lcd_pkp
= pkp
;
pkp
-> pk_chan
[0] = dev_lcp
;
* This procedure is called by the link level whenever the link
* becomes operational, is reset, or when the link goes down.
pk_ctlinput (code
, src
, addr
)
register struct pkcb
*pkp
= (struct pkcb
*)addr
;
if (pkp
-> pk_state
== DTE_WAITING
)
pk_restart (pkp
, X25_RESTART_NETWORK_CONGESTION
);
pk_restart (pkp
, -1); /* Clear all active circuits */
pkp
-> pk_state
= DTE_WAITING
;
pk_restart (pkp
, X25_RESTART_NETWORK_CONGESTION
);
case PRC_CONNECT_INDICATION
: {
if ((llrt
= rtalloc1(src
, 0)) == 0)
pkp
= (((struct npaidbentry
*)llrt
->rt_llinfo
)->np_rt
) ?
(struct pkcb
*)(((struct npaidbentry
*)llrt
->rt_llinfo
)->np_rt
->rt_llinfo
) : (struct pkcb
*) 0;
if (pkp
== (struct pkcb
*) 0)
case PRC_DISCONNECT_INDICATION
:
pk_restart (pkp
, -1) ; /* Clear all active circuits */
pkp
->pk_state
= DTE_WAITING
;
pkp
->pk_llnext
= (caddr_t
) 0;
* This routine is called if there are semi-smart devices that do HDLC
* in hardware and want to queue the packet and call level 3 directly
register struct ifaddr
*ifa
;
register struct ifnet
*ifp
;
IF_DEQUEUE (&pkintrq
, m
);
if (m
->m_len
< PKHEADERLN
) {
printf ("pkintr: packet too short (len=%d)\n",
struct mbuf
*pk_bad_packet
;
struct mbuf_cache pk_input_cache
= {0 };
* This procedure is called by a link level procedure whenever
* an information frame is received. It decodes the packet and
* demultiplexes based on the logical channel number.
* We change the original conventions of the UBC code here --
* since there may be multiple pkcb's for a given interface
* of type 802.2 class 2, we retrieve which one it is from
* m_pkthdr.rcvif (which has been overwritten by lower layers);
* That field is then restored for the benefit of upper layers which
* may make use of it, such as CLNP.
#define RESTART_DTE_ORIGINATED(xp) (((xp) -> packet_cause == X25_RESTART_DTE_ORIGINATED) || \
((xp) -> packet_cause >= X25_RESTART_DTE_ORIGINATED2))
register struct x25_packet
*xp
;
register struct pklcd
*lcp
;
register struct socket
*so
= 0;
register struct pkcb
*pkp
;
int ptype
, lcn
, lcdstate
= LISTEN
;
if (pk_input_cache
.mbc_size
|| pk_input_cache
.mbc_oldsize
)
mbuf_cache(&pk_input_cache
, m
);
if ((m
->m_flags
& M_PKTHDR
) == 0)
if ((pkp
= (struct pkcb
*)m
->m_pkthdr
.rcvif
) == 0)
xp
= mtod (m
, struct x25_packet
*);
lcp
= pkp
-> pk_chan
[lcn
];
* If the DTE is in Restart state, then it will ignore data,
* interrupt, call setup and clearing, flow control and reset
if (lcn
< 0 || lcn
> pkp
-> pk_maxlcn
) {
pk_message (lcn
, pkp
-> pk_xcp
, "illegal lcn");
pk_trace (pkp
-> pk_xcp
, m
, "P-In");
if (pkp
-> pk_state
!= DTE_READY
&& ptype
!= RESTART
&& ptype
!= RESTART_CONF
) {
lcdstate
= lcp
-> lcd_state
;
if (ptype
== CLEAR
) { /* idle line probe (Datapac specific) */
/* send response on lcd 0's output queue */
lcp
-> lcd_template
= pk_template (lcn
, X25_CLEAR_CONFIRM
);
if (lcn
== 0 && ptype
!= RESTART
&& ptype
!= RESTART_CONF
) {
pk_message (0, pkp
-> pk_xcp
, "illegal ptype (%d, %s) on lcn 0",
ptype
, pk_name
[ptype
/ MAXSTATES
]);
m
-> m_pkthdr
.rcvif
= pkp
-> pk_ia
-> ia_ifp
;
switch (ptype
+ lcdstate
) {
* Incoming Call packet received.
pk_incoming_call (pkp
, m
);
* Call collision: Just throw this "incoming call" away since
* the DCE will ignore it anyway.
pk_message ((int)lcn
, pkp
-> pk_xcp
,
"incoming call collision");
* Call confirmation packet received. This usually means our
* previous connect request is now complete.
case CALL_ACCEPTED
+ SENT_CALL
:
pk_call_accepted (lcp
, m
);
* This condition can only happen if the previous state was
* SENT_CALL. Just ignore the packet, eventually a clear
* confirmation should arrive.
case CALL_ACCEPTED
+ SENT_CLEAR
:
* Clear packet received. This requires a complete tear down
* of the virtual circuit. Free buffers and control blocks.
* and send a clear confirmation.
case CLEAR
+ RECEIVED_CALL
:
case CLEAR
+ DATA_TRANSFER
:
lcp
-> lcd_state
= RECEIVED_CLEAR
;
lcp
-> lcd_template
= pk_template (lcp
-> lcd_lcn
, X25_CLEAR_CONFIRM
);
lcp
-> lcd_upper (lcp
, m
);
* Clear collision: Treat this clear packet as a confirmation.
* Clear confirmation received. This usually means the virtual
* circuit is now completely removed.
case CLEAR_CONF
+ SENT_CLEAR
:
* A clear confirmation on an unassigned logical channel - just
* ignore it. Note: All other packets on an unassigned channel
case CLEAR_CONF
+ LISTEN
:
* Data packet received. Pass on to next level. Move the Q and M
* bits into the data portion for the next level.
case DATA
+ DATA_TRANSFER
:
if (lcp
-> lcd_reset_condition
) {
* Process the P(S) flow control information in this Data packet.
* Check that the packets arrive in the correct sequence and that
* they are within the "lcd_input_window". Input window rotation is
* initiated by the receive interface.
if (PS(xp
) != ((lcp
-> lcd_rsn
+ 1) % MODULUS
) ||
PS(xp
) == ((lcp
-> lcd_input_window
+ lcp
->lcd_windowsize
) % MODULUS
)) {
pk_procerror (RESET
, lcp
, "p(s) flow control error", 1);
if (pk_ack (lcp
, PR(xp
)) != PACKET_OK
) {
m
-> m_data
+= PKHEADERLN
;
m
-> m_len
-= PKHEADERLN
;
m
-> m_pkthdr
.len
-= PKHEADERLN
;
if (lcp
-> lcd_flags
& X25_MBS_HOLD
) {
register struct mbuf
*n
= lcp
-> lcd_cps
;
n
-> m_pkthdr
.len
+= m
-> m_pkthdr
.len
;
n
-> m_pkthdr
.len
> lcp
-> lcd_cpsmax
) {
pk_procerror (RESET
, lcp
,
q_and_d_bits
= 0xc0 & *(octet
*)xp
;
xp
= (struct x25_packet
*)
(mtod(m
, octet
*) - PKHEADERLN
);
*(octet
*)xp
|= q_and_d_bits
;
pk_flowcontrol(lcp
, 0, 1);
if (lcp
-> lcd_flags
& X25_MQBIT
) {
octet t
= (X25GBITS(xp
-> bits
, q_bit
)) ? t
= 0x80 : 0;
* Discard Q-BIT packets if the application
* doesn't want to be informed of M and Q bit status
if (X25GBITS(xp
-> bits
, q_bit
)
&& (lcp
-> lcd_flags
& X25_MQBIT
) == 0) {
* NB. This is dangerous: sending a RR here can
* cause sequence number errors if a previous data
* packet has not yet been passed up to the application
* (RR's are normally generated via PRU_RCVD).
pk_flowcontrol(lcp
, 0, 1);
sbappendrecord (&so
-> so_rcv
, m
);
* Interrupt packet received.
case INTERRUPT
+ DATA_TRANSFER
:
if (lcp
-> lcd_reset_condition
)
lcp
-> lcd_intrdata
= xp
-> packet_data
;
lcp
-> lcd_template
= pk_template (lcp
-> lcd_lcn
, X25_INTERRUPT_CONFIRM
);
m
-> m_data
+= PKHEADERLN
;
m
-> m_len
-= PKHEADERLN
;
m
-> m_pkthdr
.len
-= PKHEADERLN
;
if (so
-> so_options
& SO_OOBINLINE
)
sbinsertoob (&so
-> so_rcv
, m
);
* Interrupt confirmation packet received.
case INTERRUPT_CONF
+ DATA_TRANSFER
:
if (lcp
-> lcd_reset_condition
)
if (lcp
-> lcd_intrconf_pending
== TRUE
)
lcp
-> lcd_intrconf_pending
= FALSE
;
pk_procerror (RESET
, lcp
, "unexpected packet", 43);
* Receiver ready received. Rotate the output window and output
* any data packets waiting transmission.
if (lcp
-> lcd_reset_condition
||
pk_ack (lcp
, PR(xp
)) != PACKET_OK
) {
if (lcp
-> lcd_rnr_condition
== TRUE
)
lcp
-> lcd_rnr_condition
= FALSE
;
* Receiver Not Ready received. Packets up to the P(R) can be
* be sent. Condition is cleared with a RR.
case RNR
+ DATA_TRANSFER
:
if (lcp
-> lcd_reset_condition
||
pk_ack (lcp
, PR(xp
)) != PACKET_OK
) {
lcp
-> lcd_rnr_condition
= TRUE
;
* Reset packet received. Set state to FLOW_OPEN. The Input and
* Output window edges ar set to zero. Both the send and receive
* numbers are reset. A confirmation is returned.
case RESET
+ DATA_TRANSFER
:
if (lcp
-> lcd_reset_condition
)
/* Reset collision. Just ignore packet. */
lcp
-> lcd_window_condition
= lcp
-> lcd_rnr_condition
=
lcp
-> lcd_intrconf_pending
= FALSE
;
lcp
-> lcd_output_window
= lcp
-> lcd_input_window
=
lcp
-> lcd_last_transmitted_pr
= 0;
lcp
-> lcd_rsn
= MODULUS
- 1;
lcp
-> lcd_template
= pk_template (lcp
-> lcd_lcn
, X25_RESET_CONFIRM
);
wakeup ((caddr_t
) & so
-> so_timeo
);
* Reset confirmation received.
case RESET_CONF
+ DATA_TRANSFER
:
if (lcp
-> lcd_reset_condition
) {
lcp
-> lcd_reset_condition
= FALSE
;
pk_procerror (RESET
, lcp
, "unexpected packet", 32);
case INTERRUPT
+ SENT_CLEAR
:
case INTERRUPT_CONF
+ SENT_CLEAR
:
case RESET_CONF
+ SENT_CLEAR
:
/* Just ignore p if we have sent a CLEAR already.
* Restart sets all the permanent virtual circuits to the "Data
* Transfer" stae and all the switched virtual circuits to the
switch (pkp
-> pk_state
) {
* If case the restart cause is "DTE originated" we
* have a DTE-DTE situation and are trying to resolve
* who is going to play DTE/DCE [ISO 8208:4.2-4.5]
if (RESTART_DTE_ORIGINATED(xp
)) {
pk_restart (pkp
, X25_RESTART_DTE_ORIGINATED
);
pk_message (0, pkp
-> pk_xcp
,
if ((pkp
-> pk_restartcolls
++) > MAXRESTARTCOLLISIONS
) {
pk_message (0, pkp
-> pk_xcp
,
"excessive RESTART collisions");
pkp
-> pk_restartcolls
= 0;
pkp
-> pk_state
= DTE_READY
;
pkp
-> pk_dxerole
|= DTE_PLAYDTE
;
pkp
-> pk_dxerole
&= ~DTE_PLAYDCE
;
pk_message (0, pkp
-> pk_xcp
,
"Packet level operational");
pk_message (0, pkp
-> pk_xcp
,
if (pkp
-> pk_dxerole
& DTE_CONNECTPENDING
)
pk_restartcause (pkp
, xp
);
pkp
-> pk_chan
[0] -> lcd_template
= pk_template (0,
pk_output (pkp
-> pk_chan
[0]);
pkp
-> pk_state
= DTE_READY
;
pkp
-> pk_dxerole
|= RESTART_DTE_ORIGINATED(xp
) ? DTE_PLAYDCE
:
if (pkp
-> pk_dxerole
& DTE_PLAYDTE
) {
pkp
-> pk_dxerole
&= ~DTE_PLAYDCE
;
pk_message (0, pkp
-> pk_xcp
,
pkp
-> pk_dxerole
&= ~DTE_PLAYDTE
;
pk_message (0, pkp
-> pk_xcp
,
if (pkp
-> pk_dxerole
& DTE_CONNECTPENDING
)
* Restart confirmation received. All logical channels are set
case RESTART_CONF
+ READY
:
switch (pkp
-> pk_state
) {
pkp
-> pk_state
= DTE_READY
;
pkp
-> pk_dxerole
|= DTE_PLAYDTE
;
pkp
-> pk_dxerole
&= ~DTE_PLAYDCE
;
pk_message (0, pkp
-> pk_xcp
,
"Packet level operational");
pk_message (0, pkp
-> pk_xcp
,
if (pkp
-> pk_dxerole
& DTE_CONNECTPENDING
)
/* Restart local procedure error. */
pk_restart (pkp
, X25_RESTART_LOCAL_PROCEDURE_ERROR
);
pkp
-> pk_state
= DTE_SENT_RESTART
;
pkp
-> pk_dxerole
&= ~(DTE_PLAYDTE
| DTE_PLAYDCE
);
pk_procerror (CLEAR
, lcp
, "unknown packet error", 33);
pk_message (lcn
, pkp
-> pk_xcp
,
"\"%s\" unexpected in \"%s\" state",
pk_name
[ptype
/MAXSTATES
], pk_state
[lcdstate
]);
pk_message (lcn
, pkp
-> pk_xcp
,
"packet arrived on unassigned lcn");
if (so
== 0 && lcp
&& lcp
-> lcd_upper
&& lcdstate
== DATA_TRANSFER
) {
if (ptype
!= DATA
&& ptype
!= INTERRUPT
)
lcp
-> lcd_upper (lcp
, m
);
} else if (ptype
!= DATA
&& ptype
!= INTERRUPT
)
prune_dnic(from
, to
, dnicname
, xcp
)
char *from
, *to
, *dnicname
;
register struct x25config
*xcp
;
register char *cp1
= from
, *cp2
= from
;
if (xcp
->xc_prepnd0
&& *cp1
== '0') {
for (cp1
= dnicname
; *cp2
= *cp1
++;)
for (cp1
= dnicname
; *cp2
= *cp1
++;)
pk_simple_bsd (from
, to
, lower
, len
)
register octet
*from
, *to
;
c
&= 0x0f; c
|= 0x30; *to
++ = c
; lower
++;
pk_from_bcd (a
, iscalling
, sa
, xcp
)
register struct x25_calladdr
*a
;
register struct sockaddr_x25
*sa
;
register struct x25config
*xcp
;
bzero ((caddr_t
)sa
, sizeof (*sa
));
sa
-> x25_len
= sizeof (*sa
);
sa
-> x25_family
= AF_CCITT
;
cp
= a
-> address_field
+ (X25GBITS(a
-> addrlens
, called_addrlen
) / 2);
count
= X25GBITS(a
-> addrlens
, calling_addrlen
);
pk_simple_bsd (cp
, buf
, X25GBITS(a
-> addrlens
, called_addrlen
), count
);
count
= X25GBITS(a
-> addrlens
, called_addrlen
);
pk_simple_bsd (a
-> address_field
, buf
, 0, count
);
if (xcp
-> xc_addr
.x25_net
&& (xcp
-> xc_nodnic
|| xcp
->xc_prepnd0
)) {
octet dnicname
[sizeof(long) * NBBY
/3 + 2];
sprintf ((char *) dnicname
, "%d", xcp
-> xc_addr
.x25_net
);
prune_dnic ((char *)buf
, sa
-> x25_addr
, dnicname
, xcp
);
bcopy ((caddr_t
)buf
, (caddr_t
)sa
-> x25_addr
, count
+ 1);
if (m
= m_copy (m
, 0, (int)M_COPYALL
)) {
int off
= fp
- mtod (m0
, octet
*);
int len
= m
->m_pkthdr
.len
- off
+ sizeof (cmsghdr
);
cmsghdr
.cmsg_level
= AF_CCITT
;
cmsghdr
.cmsg_type
= PK_FACILITIES
;
M_PREPEND (m
, sizeof(cmsghdr
), M_DONTWAIT
);
bcopy ((caddr_t
)&cmsghdr
, mtod (m
, caddr_t
), sizeof (cmsghdr
));
sbappendrecord(&so
-> so_rcv
, m
);
* This routine handles incoming call packets. It matches the protocol
* field on the Call User Data field (usually the first four bytes) with
* sockets awaiting connections.
pk_incoming_call (pkp
, m0
)
register struct pklcd
*lcp
= 0, *l
;
register struct sockaddr_x25
*sa
;
register struct x25_calladdr
*a
;
register struct socket
*so
= 0;
struct x25_packet
*xp
= mtod(m0
, struct x25_packet
*);
struct x25config
*xcp
= pkp
-> pk_xcp
;
int len
= m0
->m_pkthdr
.len
;
char *errstr
= "server unavailable";
/* First, copy the data from the incoming call packet to a X25 address
descriptor. It is to be regretted that you have
to parse the facilities into a sockaddr to determine
if reverse charging is being requested */
if ((m
= m_get (M_DONTWAIT
, MT_SONAME
)) == 0)
sa
= mtod (m
, struct sockaddr_x25
*);
a
= (struct x25_calladdr
*) &xp
-> packet_data
;
facp
= u
= (octet
*) (a
-> address_field
+
((X25GBITS(a
-> addrlens
, called_addrlen
) + X25GBITS(a
-> addrlens
, calling_addrlen
) + 1) / 2));
udlen
= min (16, ((octet
*)xp
) + len
- u
);
pk_from_bcd (a
, 1, sa
, pkp
-> pk_xcp
); /* get calling address */
pk_parse_facilities (facp
, sa
);
bcopy ((caddr_t
)u
, sa
-> x25_udata
, udlen
);
* Now, loop through the listen sockets looking for a match on the
* PID. That is the first few octets of the user data field.
* This is the closest thing to a port number for X.25 packets.
* It does provide a way of multiplexing services at the user level.
for (l
= pk_listenhead
; l
; l
= l
-> lcd_listen
) {
struct sockaddr_x25
*sxp
= l
-> lcd_ceaddr
;
if (bcmp (sxp
-> x25_udata
, u
, sxp
->x25_udlen
))
sxp
-> x25_net
!= xcp
-> xc_addr
.x25_net
)
* don't accept incoming calls with the D-Bit on
* unless the server agrees
if (X25GBITS(xp
-> bits
, d_bit
) && !(sxp
-> x25_opts
.op_flags
& X25_DBIT
)) {
errstr
= "incoming D-Bit mismatch";
* don't accept incoming collect calls unless
* the server sets the reverse charging option.
if ((sxp
-> x25_opts
.op_flags
& (X25_OLDSOCKADDR
|X25_REVERSE_CHARGE
)) == 0 &&
sa
-> x25_opts
.op_flags
& X25_REVERSE_CHARGE
) {
errstr
= "incoming collect call refused";
if (so
= sonewconn (l
-> lcd_so
, SS_ISCONNECTED
))
lcp
= (struct pklcd
*) so
-> so_pcb
;
lcp
= pk_attach((struct socket
*) 0);
* Insufficient space or too many unaccepted
* connections. Just throw the call away.
errstr
= "server malfunction";
lcp
-> lcd_upper
= l
-> lcd_upper
;
lcp
-> lcd_upnext
= l
-> lcd_upnext
;
lcp
-> lcd_state
= RECEIVED_CALL
;
sa
-> x25_opts
.op_flags
|= (sxp
-> x25_opts
.op_flags
&
~X25_REVERSE_CHARGE
) | l
-> lcd_flags
;
lcp
-> lcd_laddr
.x25_udlen
= sxp
-> x25_udlen
;
lcp
-> lcd_craddr
= &lcp
->lcd_faddr
;
lcp
-> lcd_template
= pk_template (lcp
-> lcd_lcn
, X25_CALL_ACCEPTED
);
if (lcp
-> lcd_flags
& X25_DBIT
) {
if (X25GBITS(xp
-> bits
, d_bit
))
X25SBITS(mtod(lcp
-> lcd_template
,
struct x25_packet
*) -> bits
, d_bit
, 1);
lcp
-> lcd_flags
&= ~X25_DBIT
;
if (so
-> so_options
& SO_OOBINLINE
)
save_extra(m0
, facp
, so
);
} else if (lcp
-> lcd_upper
) {
(*lcp
-> lcd_upper
) (lcp
, m0
);
* If the call fails for whatever reason, we still need to build a
* skeleton LCD in order to be able to properly receive the CLEAR
#ifdef WATERLOO /* be explicit */
if (l
== 0 && bcmp(sa
->x25_udata
, "ean", 3) == 0)
pk_message (lcn
, pkp
-> pk_xcp
, "host=%s ean%c: %s",
sa
->x25_addr
, sa
->x25_udata
[3] & 0xff, errstr
);
else if (l
== 0 && bcmp(sa
->x25_udata
, "\1\0\0\0", 4) == 0)
pk_message (lcn
, pkp
-> pk_xcp
, "host=%s x29d: %s",
pk_message (lcn
, pkp
-> pk_xcp
, "host=%s pid=%x %x %x %x: %s",
sa
-> x25_addr
, sa
-> x25_udata
[0] & 0xff,
sa
-> x25_udata
[1] & 0xff, sa
-> x25_udata
[2] & 0xff,
sa
-> x25_udata
[3] & 0xff, errstr
);
if ((lcp
= pk_attach((struct socket
*)0)) == 0) {
lcp
-> lcd_state
= RECEIVED_CALL
;
pk_call_accepted (lcp
, m
)
register struct x25_calladdr
*ap
;
struct x25_packet
*xp
= mtod (m
, struct x25_packet
*);
lcp
-> lcd_state
= DATA_TRANSFER
;
soisconnected (lcp
-> lcd_so
);
if ((lcp
-> lcd_flags
& X25_DBIT
) && (X25GBITS(xp
-> bits
, d_bit
) == 0))
lcp
-> lcd_flags
&= ~X25_DBIT
;
ap
= (struct x25_calladdr
*) &xp
-> packet_data
;
fcp
= (octet
*) ap
-> address_field
+ (X25GBITS(ap
-> addrlens
, calling_addrlen
) +
X25GBITS(ap
-> addrlens
, called_addrlen
) + 1) / 2;
if (fcp
+ *fcp
<= ((octet
*)xp
) + len
)
pk_parse_facilities (fcp
, lcp
-> lcd_ceaddr
);
pk_assoc (lcp
-> lcd_pkp
, lcp
, lcp
-> lcd_ceaddr
);
if (lcp
-> lcd_so
== 0 && lcp
-> lcd_upper
)
lcp
-> lcd_upper(lcp
, m
);
pk_parse_facilities (fcp
, sa
)
register struct sockaddr_x25
*sa
;
* Ignore national DCE or DTE facilities
if (*fcp
== 0 || *fcp
== 0xff)
case FACILITIES_WINDOWSIZE
:
sa
-> x25_opts
.op_wsize
= fcp
[1];
case FACILITIES_PACKETSIZE
:
sa
-> x25_opts
.op_psize
= fcp
[1];
case FACILITIES_THROUGHPUT
:
sa
-> x25_opts
.op_speed
= fcp
[1];
case FACILITIES_REVERSE_CHARGE
:
sa
-> x25_opts
.op_flags
|= X25_REVERSE_CHARGE
;
* Datapac specific: for a X.25(1976) DTE, bit 2
* indicates a "hi priority" (eg. international) call.
if (fcp
[1] & 02 && sa
-> x25_opts
.op_psize
== 0)
sa
-> x25_opts
.op_psize
= X25_PS128
;
/*printf("unknown facility %x, class=%d\n", *fcp, (*fcp & 0xc0) >> 6);*/
switch ((*fcp
& 0xc0) >> 6) {