* Copyright (c) University of British Columbia, 1984
* Copyright (c) 1990 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 University of British Columbia.
* %sccs.include.redist.c%
* @(#)pk_usrreq.c 7.3 (Berkeley) %G%
#include "../h/protosw.h"
#include "../h/socketvar.h"
#include "../netccitt/x25.h"
#include "../netccitt/pk.h"
#include "../netccitt/pk_var.h"
struct x25_packet
*pk_template ();
* X.25 Packet level protocol interface to socket abstraction.
* Process an X.25 user request on a logical channel. If this is a send
* request then m is the mbuf chain of the send data. If this is a timer
* expiration (called from the software clock routine) them timertype is
pk_usrreq (so
, req
, m
, nam
, control
)
register struct mbuf
*m
, *nam
;
register struct pklcd
*lcp
= (struct pklcd
*) so
-> so_pcb
;
register struct x25_packet
*xp
;
return (pk_control(so
, (int)m
, (caddr_t
)nam
,
(struct ifnet
*)control
));
if (control
&& control
->m_len
) {
if (lcp
== NULL
&& req
!= PRU_ATTACH
) {
pk_trace (pkcbhead, TR_USER, (struct pklcd *)0,
req, (struct x25_packet *)0);
* X.25 attaches to socket via PRU_ATTACH and allocates a logical
* channel descriptor. If the socket is to receive connections,
* then the LISTEN state is entered.
/* Socket already connected. */
* Detach a logical channel from the socket. If the state of the
* channel is embryonic, simply discard it. Otherwise we have to
* initiate a PRU_DISCONNECT which will finish later.
* Give the socket an address.
if (nam
-> m_len
== sizeof (struct x25_sockaddr
))
error
= pk_bind (lcp
, nam
);
* Prepare to accept connections.
if (lcp
-> lcd_ceaddr
== 0) {
lcp
-> lcd_state
= LISTEN
;
lcp
-> lcd_listen
= pk_listenhead
;
* Initiate a CALL REQUEST to peer entity. Enter state SENT_CALL
* and mark the socket as connecting. Set timer waiting for
if (nam
-> m_len
== sizeof (struct x25_sockaddr
))
error
= pk_connect (lcp
, nam
);
* Initiate a disconnect to peer entity via a CLEAR REQUEST packet.
* The socket will be disconnected when we receive a confirmation
* Accept an INCOMING CALL. Most of the work has already been done
* by pk_input. Just return the callers address to the user.
if (lcp
-> lcd_craddr
== NULL
)
bcopy ((caddr_t
)lcp
-> lcd_craddr
, mtod (nam
, caddr_t
),
sizeof (struct sockaddr_x25
));
nam
-> m_len
= sizeof (struct sockaddr_x25
);
if (lcp
-> lcd_flags
& X25_OLDSOCKADDR
)
* After a receive, we should send a RR.
lcp
-> lcd_template
= pk_template (lcp
-> lcd_lcn
, X25_RR
);
* Do send by placing data on the socket output queue.
* SHOULD WE USE m_cat HERE.
error
= pk_send (lcp
, m
);
* Abort a virtual circuit. For example all completed calls
/* Begin unimplemented hooks. */
((struct stat
*)m
) -> st_blksize
= so
-> so_snd
.sb_hiwat
;
/* End unimplemented hooks. */
if (lcp
-> lcd_ceaddr
== 0)
nam
-> m_len
= sizeof (struct sockaddr_x25
);
bcopy ((caddr_t
)lcp
-> lcd_ceaddr
, mtod (nam
, caddr_t
),
sizeof (struct sockaddr_x25
));
if (lcp
-> lcd_flags
& X25_OLDSOCKADDR
)
if (lcp
-> lcd_state
!= DATA_TRANSFER
)
nam
-> m_len
= sizeof (struct sockaddr_x25
);
bcopy (lcp
-> lcd_craddr
? (caddr_t
)lcp
-> lcd_craddr
:
(caddr_t
)lcp
-> lcd_ceaddr
,
mtod (nam
, caddr_t
), sizeof (struct sockaddr_x25
));
if (lcp
-> lcd_flags
& X25_OLDSOCKADDR
)
* Receive INTERRUPT packet.
*mtod (m
, char *) = lcp
-> lcd_intrdata
;
if (lcp
-> lcd_intrconf_pending
) {
xp
= lcp
-> lcd_template
= pk_template (lcp
-> lcd_lcn
, X25_INTERRUPT
);
pk_control (so
, cmd
, data
, ifp
)
register struct ifnet
*ifp
;
register struct ifreq
*ifr
= (struct ifreq
*)data
;
register struct ifaddr
*ifa
= 0;
register struct x25_ifaddr
*ia
= 0;
* Find address for this interface, if it exists.
for (ifa
= ifp
->if_addrlist
; ifa
; ifa
= ifa
->ifa_next
)
if (ifa
->ifa_addr
.sa_family
== AF_CCITT
)
ia
= (struct x25_ifaddr
*)ifa
;
ifr
->ifr_addr
= *(struct sockaddr
*)ia
->ia_xc
;
if (ifa
== (struct ifaddr
*)0) {
m
= m_getclr(M_WAIT
, MT_IFADDR
);
if (m
== (struct mbuf
*)NULL
)
ia
= mtod(m
, struct x25_ifaddr
*);
if (ifa
= ifp
->if_addrlist
) {
for ( ; ifa
->ifa_next
; ifa
= ifa
->ifa_next
)
ifa
->ifa_next
= &ia
->ia_ifa
;
ifp
->if_addrlist
= &ia
->ia_ifa
;
ifa
->ifa_addr
= (struct sockaddr
*)&ia
->ia_addr
;
ifa
->ifa_netmask
= (struct sockaddr
*)&ia
->ia_sockmask
;
ia
->ia_xcp
= (struct x25config
*) &(ifr
->ifr_addr
);
if (ia
->ia_chan
&& (ia
->ia_maxlcn
!= ia
->xcp
->xc_maxlcn
)) {
free((caddr_t
)ia
->ia_chan
, M_IFADDR
);
n
= ia
->ia_maxlcn
* sizeof(struct pklcd
*);
ia
->ia_chan
= (struct pklcd
**) malloc(n
, M_IFADDR
);
bzero((caddr_t
)ia
->ia_chan
, n
);
* Give the interface a chance to initialize if this
* is its first address, and to validate the address.
error
= (*ifp
->if_ioctl
)(ifp
, SIOCSIFADDR
, ifa
)));
if (ifp
== 0 || ifp
->if_ioctl
== 0)
return ((*ifp
->if_ioctl
)(ifp
, cmd
, data
));
* Do an in-place conversion of an "old style"
* socket address to the new style
register struct x25_sockaddr
*oldp
;
register struct sockaddr_x25
*newp
;
register char *ocp
, *ncp
;
oldp
= mtod (m
, struct x25_sockaddr
*);
bzero ((caddr_t
)newp
, sizeof (*newp
));
newp
-> x25_family
= AF_CCITT
;
newp
->x25_opts
.op_flags
= (oldp
->xaddr_facilities
& X25_REVERSE_CHARGE
)
| X25_MQBIT
| X25_OLDSOCKADDR
;
if (oldp
-> xaddr_facilities
& XS_HIPRIO
) /* Datapac specific */
newp
-> x25_opts
.op_psize
= X25_PS128
;
bcopy ((caddr_t
)oldp
-> xaddr_addr
, newp
-> x25_addr
,
(unsigned)min (oldp
-> xaddr_len
, sizeof (newp
-> x25_addr
) - 1));
bcopy ((caddr_t
)oldp
-> xaddr_proto
, newp
-> x25_udata
, 4);
ocp
= (caddr_t
)oldp
-> xaddr_userdata
;
ncp
= newp
-> x25_udata
+ 4;
while (*ocp
&& ocp
< (caddr_t
)oldp
-> xaddr_userdata
+ 12) {
bcopy ((caddr_t
)newp
, mtod (m
, char *), sizeof (*newp
));
m
->m_len
= sizeof (*newp
);
* Do an in-place conversion of a new style
* socket address to the old style
register struct x25_sockaddr
*oldp
;
register struct sockaddr_x25
*newp
;
register char *ocp
, *ncp
;
newp
= mtod (m
, struct sockaddr_x25
*);
bzero ((caddr_t
)oldp
, sizeof (*oldp
));
oldp
-> xaddr_facilities
= newp
-> x25_opts
.op_flags
& X25_REVERSE_CHARGE
;
if (newp
-> x25_opts
.op_psize
== X25_PS128
)
oldp
-> xaddr_facilities
|= XS_HIPRIO
; /* Datapac specific */
ocp
= (char *)oldp
-> xaddr_addr
;
bcopy (newp
-> x25_udata
, (caddr_t
)oldp
-> xaddr_proto
, 4);
bcopy (newp
-> x25_udata
+ 4, (caddr_t
)oldp
-> xaddr_userdata
,
(unsigned)(newp
-> x25_udlen
- 4));
bcopy ((caddr_t
)oldp
, mtod (m
, char *), sizeof (*oldp
));
m
-> m_len
= sizeof (*oldp
);
register struct pklcd
*lcp
;
register struct x25_packet
*xp
;
register struct mbuf
*m0
;
m0
= dtom ((xp
= pk_template (lcp
-> lcd_lcn
, X25_DATA
)));
* Application has elected (at call setup time) to prepend
* a control byte to each packet written indicating m-bit
* and q-bit status. Examine and then discard this byte.
if (lcp
-> lcd_flags
& X25_MQBIT
) {
if (*cp
& 0x80) /* XXX */
xp
-> packet_type
|= (*cp
& 0x40) >> 2; /* XXX */
if (len
> (1 << lcp
-> lcd_packetsize
)) {
sbappendrecord (&lcp
-> lcd_so
-> so_snd
, m0
);