* 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.8 (Berkeley) %G%
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
, (struct sockaddr_25
*)0);
* 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
);
* 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
;
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
;
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_pkcb
.pk_next
= pkcbhead
;
ia
->ia_pkcb
.pk_state
= DTE_WAITING
;
old_maxlcn
= ia
->ia_maxlcn
;
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
);
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
;
if (cmd
== PRCO_SETOPT
) switch (optname
) {
error
= pk_accton(mtod(m
, char *));
error
= pk_accton((char *)0);
* 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
);
* 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)