* 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.11 (Berkeley) %G%
* 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
;
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.
* 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
))
if (pk_checksockaddr (nam
))
error
= pk_connect (lcp
, mtod (nam
, struct sockaddr_x25
*));
* 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
);
/*pk_flowcontrol (lcp, sbspace (&so -> so_rcv) <= 0, 1);*/
MGETHDR(m
, M_WAITOK
, MT_OOBDATA
);
m
-> m_pkthdr
.len
= m
-> m_len
= 1;
if (m
-> m_pkthdr
.len
> 32) {
* Do send by placing data on the socket output queue.
register struct cmsghdr
*ch
= mtod (m
, struct cmsghdr
*);
control
-> m_len
-= sizeof (*ch
);
control
-> m_data
+= sizeof (*ch
);
pk_ctloutput (PRCO_SETOPT
, so
, ch
-> cmsg_level
,
ch
-> cmsg_type
, &control
);
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.
if (so
-> so_options
& SO_OOBINLINE
) {
register struct mbuf
*n
= so
-> so_rcv
.sb_mb
;
if (n
&& n
-> m_type
== MT_OOBDATA
) {
unsigned len
= n
-> m_pkthdr
.len
;
so
-> so_rcv
.sb_mb
= n
-> m_nextpkt
;
(n
= m_pullup (n
, len
)) == 0)
bcopy (mtod (m
, caddr_t
), mtod (n
, caddr_t
), len
);
*mtod (m
, char *) = lcp
-> lcd_intrdata
;
* If you want to use UBC X.25 level 3 in conjunction with some
* other X.25 level 2 driver, have the ifp -> if_ioctl routine
* assign pk_start to pkp -> pk_start when called with SIOCSIFCONF_X25.
register struct pklcd
*lcp
;
lcp
-> lcd_send
= pk_send
;
return (pk_output (lcp
));
pk_control (so
, cmd
, data
, ifp
)
register struct ifnet
*ifp
;
register struct ifreq_x25
*ifr
= (struct ifreq_x25
*)data
;
register struct ifaddr
*ifa
= 0;
register struct x25_ifaddr
*ia
= 0;
struct pklcd
*dev_lcp
= 0;
int error
, s
, old_maxlcn
;
* 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_xc
= ia
-> ia_xc
;
if (error
= suser (u
.u_cred
, &u
.u_acflag
))
if (ifa
== (struct ifaddr
*)0) {
MALLOC(ia
, struct x25_ifaddr
*, sizeof (*ia
),
bzero ((caddr_t
)ia
, sizeof (*ia
));
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_netmask
= (struct sockaddr
*)&ia
-> ia_sockmask
;
ifa
-> ifa_addr
= (struct sockaddr
*)&ia
-> ia_xc
.xc_addr
;
ia
-> ia_xcp
= &ia
-> ia_xc
;
ia
-> ia_pkcb
.pk_ia
= ia
;
ia
-> ia_pkcb
.pk_next
= pkcbhead
;
ia
-> ia_pkcb
.pk_state
= DTE_WAITING
;
ia
-> ia_pkcb
.pk_start
= pk_start
;
pkcbhead
= &ia
-> ia_pkcb
;
old_maxlcn
= ia
-> ia_maxlcn
;
ia
-> ia_xc
= ifr
-> ifr_xc
;
if (ia
-> ia_chan
&& (ia
-> ia_maxlcn
!= old_maxlcn
)) {
pk_restart (&ia
-> ia_pkcb
, X25_RESTART_NETWORK_CONGESTION
);
dev_lcp
= ia
-> ia_chan
[0];
free ((caddr_t
)ia
-> ia_chan
, M_IFADDR
);
if (ia
-> ia_chan
== 0) {
n
= (ia
-> ia_maxlcn
+ 1) * sizeof (struct pklcd
*);
ia
-> ia_chan
= (struct pklcd
**) malloc (n
, M_IFADDR
, M_WAITOK
);
bzero ((caddr_t
)ia
-> ia_chan
, n
);
dev_lcp
= pk_attach ((struct socket
*)0);
ia
-> ia_chan
[0] = dev_lcp
;
dev_lcp
-> lcd_state
= READY
;
dev_lcp
-> lcd_pkp
= &ia
-> ia_pkcb
;
* Give the interface a chance to initialize if this
* is its first address, and to validate the address.
error
= (*ifp
-> if_ioctl
)(ifp
, SIOCSIFCONF_X25
, ifa
);
ifp
-> if_flags
&= ~IFF_UP
;
if (ifp
== 0 || ifp
-> if_ioctl
== 0)
return ((*ifp
-> if_ioctl
)(ifp
, cmd
, data
));
pk_ctloutput (cmd
, so
, level
, optname
, mp
)
register struct mbuf
*m
= *mp
;
register struct pklcd
*lcp
= (struct pklcd
*) so
-> so_pcb
;
if (cmd
== PRCO_SETOPT
) switch (optname
) {
error
= pk_accton (mtod (m
, char *));
error
= pk_accton ((char *)0);
lcp
-> lcd_facilities
= m
;
* 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 sockaddr_x25
*sa
= mtod (m
, struct sockaddr_x25
*);
if (m
-> m_len
!= sizeof (struct sockaddr_x25
))
if (sa
-> x25_family
!= AF_CCITT
||
sa
-> x25_udlen
> sizeof (sa
-> x25_udata
))
for (cp
= sa
-> x25_addr
; *cp
; cp
++) {
if (*cp
< '0' || *cp
> '9' ||
cp
>= &sa
-> x25_addr
[sizeof (sa
-> x25_addr
) - 1])
int mqbit
= 0, error
= 0;
register struct x25_packet
*xp
;
if (m
-> m_type
== MT_OOBDATA
) {
if (lcp
-> lcd_intrconf_pending
)
if (m
-> m_pkthdr
.len
> 32)
M_PREPEND(m
, PKHEADERLN
, M_WAITOK
);
*(mtod (m
, octet
*)) = 0;
xp
= mtod (m
, struct x25_packet
*);
xp
-> fmt_identifier
= 1;
xp
-> packet_type
= X25_INTERRUPT
;
SET_LCN(xp
, lcp
-> lcd_lcn
);
return (pk_output (lcp
));
* 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
) {
mqbit
= *(mtod (m
, u_char
*));
if ((error
= pk_fragment (lcp
, m
, mqbit
& 0x80, mqbit
& 0x40, 1)) == 0)