* 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.
* 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
* from: @(#)pk_usrreq.c 7.16 (Berkeley) 6/27/91
* $Id: pk_usrreq.c,v 1.4 1993/11/25 01:34:33 wollman Exp $
#include "../net/route.h"
old_to_new (struct mbuf
*m
);
new_to_old (struct mbuf
*m
);
* 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.
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
);
error
= 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 ia -> ia_start when called with SIOCSIFCONF_X25.
register struct pklcd
*lcp
;
#define _offsetof(t, m) ((int)((caddr_t)&((t *)0)->m))
struct sockaddr_x25 pk_sockmask
= {
_offsetof(struct sockaddr_x25
, x25_addr
[0]),
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
= 0, 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 ((so
->so_state
& SS_PRIV
) == 0)
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
*)&pk_sockmask
;
ifa
-> ifa_addr
= (struct sockaddr
*)&ia
-> ia_xc
.xc_addr
;
ifa
-> ifa_dstaddr
= (struct sockaddr
*)&ia
-> ia_dstaddr
; /* XXX */
ia
-> ia_dstaddr
.x25_family
= AF_CCITT
;
ia
-> ia_dstaddr
.x25_len
= pk_sockmask
.x25_len
;
rtinit (ifa
, (int)RTM_DELETE
, 0);
old_maxlcn
= ia
-> ia_maxlcn
;
ia
-> ia_xc
= ifr
-> ifr_xc
;
ia
-> ia_dstaddr
.x25_net
= ia
-> ia_xc
.xc_addr
.x25_net
;
if (ia
-> ia_maxlcn
!= old_maxlcn
&& old_maxlcn
!= 0) {
register struct pkcb
*pkp
;
for (pkp
= pkcbhead
; pkp
; pkp
= pkp
-> pk_next
)
* Give the interface a chance to initialize if this
* is its first address, and to validate the address.
ia
-> ia_start
= pk_start
;
error
= (*ifp
-> if_ioctl
)(ifp
, SIOCSIFCONF_X25
,
ifp
-> if_flags
&= ~IFF_UP
;
error
= rtinit (ifa
, (int)RTM_ADD
, RTF_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
) {
lcp
-> lcd_facilities
= m
;
if ((so
->so_state
& SS_PRIV
) == 0)
error
= pk_accton (mtod (m
, char *));
error
= pk_accton ((char *)0);
error
= pk_rtattach (so
, m
);
error
= pk_user_protolisten (mtod (m
, u_char
*));
* 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_len
= sizeof(*newp
);
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));
if (bcmp ((caddr_t
)oldp
-> xaddr_proto
, newp
-> x25_udata
, 4) != 0) {
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) {
if (newp
-> x25_udlen
== 0)
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);
if (newp
-> x25_udlen
> 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
;
register struct socket
*so
;
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
);
sbinsertoob ( (so
= lcp
-> lcd_so
) ?
&so
-> so_snd
: &lcp
-> lcd_sb
, m
);
* 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
*));
error
= pk_fragment (lcp
, m
, mqbit
& 0x80, mqbit
& 0x40, 1);
if (error
== 0 && lcp
-> lcd_state
== DATA_TRANSFER
)
lcp
-> lcd_send (lcp
); /* XXXXXXXXX fix pk_output!!! */