* Copyright (c) 1990 The Regents of the University of California.
* 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: @(#)if_x25subr.c 7.14 (Berkeley) 6/26/91
* $Id: if_x25subr.c,v 1.4 1993/12/19 00:52:16 wollman Exp $
#include "../net/if_types.h"
#include "../net/netisr.h"
#include "../net/route.h"
#include "machine/mtpr.h"
#include "../netinet/in.h"
#include "../netinet/in_var.h"
#include "../netns/ns_if.h"
#include "../netiso/argo_debug.h"
#include "../netiso/iso.h"
#include "../netiso/iso_var.h"
extern struct ifnet loif
;
struct llinfo_x25 llinfo_x25
= {&llinfo_x25
, &llinfo_x25
};
struct sockaddr
*x25_dgram_sockmask
;
#define senderr(x) {error = x; goto bad;}
static struct llinfo_x25
*
register struct rtentry
*rt
;
register struct llinfo_x25
*lx
;
register struct sockaddr
*dst
= rt_key(rt
);
register struct ifaddr
*ifa
;
MALLOC(lx
, struct llinfo_x25
*, sizeof (*lx
), M_PCB
, M_NOWAIT
);
lx
->lx_family
= dst
->sa_family
;
insque(lx
, (struct llinfo_x25
*)rt
->rt_llinfo
);
rt
->rt_llinfo
= (caddr_t
)lx
;
for (ifa
= rt
->rt_ifp
->if_addrlist
; ifa
; ifa
= ifa
->ifa_next
) {
if (ifa
->ifa_addr
->sa_family
== AF_CCITT
)
lx
->lx_ia
= (struct x25_ifaddr
*)ifa
;
register struct llinfo_x25
*lx
;
register struct rtentry
*rt
= lx
->lx_rt
;
register struct pklcd
*lcp
= lx
->lx_lcd
;
if ((rt
->rt_llinfo
== (caddr_t
)lx
) && (lx
->lx_next
->lx_rt
== rt
))
rt
->rt_llinfo
= (caddr_t
)lx
->lx_next
;
* Process a x25 packet as datagram;
struct llinfo_x25
*lx
= (struct llinfo_x25
*)lcp
->lcd_upnext
;
register struct ifnet
*ifp
;
extern struct timeval time
;
if (m
== 0 || lcp
->lcd_state
!= DATA_TRANSFER
) {
x25_connect_callback(lcp
, 0);
pk_flowcontrol(lcp
, 0, 1); /* Generate RR */
ifp
->if_lastchange
= time
;
ifp
->if_ibytes
+= m
->m_pkthdr
.len
;
x25_connect_callback(lcp
, m
)
register struct pklcd
*lcp
;
register struct llinfo_x25
*lx
= (struct llinfo_x25
*)lcp
->lcd_upnext
;
if (m
->m_type
!= MT_CONTROL
) {
printf("x25_connect_callback: should panic\n");
switch (pk_decode(mtod(m
, struct x25_packet
*))) {
lcp
->lcd_upper
= x25_ifinput
;
lcp
->lcd_send(lcp
); /* XXX start queued packets */
#define SA(p) ((struct sockaddr *)(p))
#define RT(p) ((struct rtentry *)(p))
x25_dgram_incoming(lcp
, m0
)
register struct pklcd
*lcp
;
register struct rtentry
*rt
, *nrt
;
register struct mbuf
*m
= m0
->m_next
; /* m0 has calling sockaddr_x25 */
rt
= rtalloc1(SA(&lcp
->lcd_faddr
), 0);
refuse
: lcp
->lcd_upper
= 0;
if ((nrt
= RT(rt
->rt_llinfo
)) == 0 || rt_mask(rt
) != x25_dgram_sockmask
)
if ((nrt
->rt_flags
& RTF_UP
) == 0) {
rt
->rt_llinfo
= (caddr_t
)rtalloc1(rt
->rt_gateway
, 0);
if ((nrt
= RT(rt
->rt_llinfo
)) == 0)
if (nrt
->rt_ifa
== 0 || nrt
->rt_ifa
->ifa_rtrequest
!= x25_rtrequest
)
lcp
->lcd_send(lcp
); /* confirm call */
x25_ifoutput(ifp
, m0
, dst
, rt
)
register struct rtentry
*rt
;
register struct mbuf
*m
= m0
;
register struct llinfo_x25
*lx
;
for (plen
= 0; m
; m
= m
->m_next
)
if ((ifp
->if_flags
& IFF_UP
) == 0)
while (rt
== 0 || (rt
->rt_flags
& RTF_GATEWAY
)) {
rt
= (struct rtentry
*)rt
->rt_llinfo
;
if ((rt
= rtalloc1(dst
, 1)) == 0)
if ((rt
->rt_ifp
!= ifp
) ||
(rt
->rt_flags
& (RTF_CLONING
| RTF_GATEWAY
)) ||
((lx
= (struct llinfo_x25
*)rt
->rt_llinfo
) == 0)) {
if ((m
->m_flags
& M_PKTHDR
) == 0) {
if_x25stats
.ifx_nophdr
++;
m
= m_gethdr(M_NOWAIT
, MT_HEADER
);
if (plen
!= m
->m_pkthdr
.len
) {
if_x25stats
.ifx_wrongplen
++;
lx
->lx_lcd
= lcp
= pk_attach((struct socket
*)0);
lcp
->lcd_upper
= x25_connect_callback
;
lcp
->lcd_upnext
= (caddr_t
)lx
;
lcp
->lcd_packetsize
= lx
->lx_ia
->ia_xc
.xc_psize
;
lcp
->lcd_flags
= X25_MBS_HOLD
;
switch (lcp
->lcd_state
) {
if (dst
->sa_family
== AF_INET
&&
ifp
->if_type
== IFT_X25DDN
&&
rt
->rt_gateway
->sa_family
!= AF_CCITT
)
x25_ddnip_to_ccitt((struct sockaddr_in
*)dst
, rt
);
if (rt
->rt_gateway
->sa_family
!= AF_CCITT
) {
if ((rt
->rt_flags
& RTF_XRESOLVE
) == 0)
} else if (x25_autoconnect
)
(struct sockaddr_x25
*)rt
->rt_gateway
);
if (sbspace(&lcp
->lcd_sb
) < 0) {
lx
->lx_ia
->ia_xc
.xc_dg_idletimo
;
* We count on the timer routine to close idle
* connections, if there are not enough circuits to go
* So throw away data for now.
* After we get it all working, we'll rewrite to handle
* actively closing connections (other than by timers),
* when circuits get tight.
* In the DDN case, the imp itself closes connections
* Simpleminded timer routine.
register struct pkcb
*pkcb
= 0;
register struct pklcd
**lcpp
, *lcp
;
for (pkcb
= pkcbhead
; pkcb
; pkcb
= pkcb
->pk_next
)
if (pkcb
->pk_ia
->ia_ifp
== ifp
)
for (lcpp
= pkcb
->pk_chan
+ pkcb
->pk_maxlcn
;
lcp
->lcd_state
== DATA_TRANSFER
&&
(lcp
->lcd_flags
& X25_DG_CIRCUIT
) &&
(lcp
->lcd_dg_timer
&& --lcp
->lcd_dg_timer
== 0)) {
* This routine gets called when validating additions of new routes
* or deletions of old ones.
x25_rtrequest(cmd
, rt
, dst
)
register struct rtentry
*rt
;
register struct llinfo_x25
*lx
= (struct llinfo_x25
*)rt
->rt_llinfo
;
register struct sockaddr_x25
*sa
=(struct sockaddr_x25
*)rt
->rt_gateway
;
register struct pklcd
*lcp
;
if (rt
->rt_flags
& RTF_GATEWAY
) {
RTFREE((struct rtentry
*)rt
->rt_llinfo
);
rt
->rt_llinfo
= (cmd
== RTM_ADD
) ?
(caddr_t
)rtalloc1(rt
->rt_gateway
, 1) : 0;
if ((rt
->rt_flags
& RTF_HOST
) == 0)
x25_lxfree((struct llinfo
*)rt
->rt_llinfo
);
x25_rtinvert(RTM_DELETE
, rt
->rt_gateway
, rt
);
if (lx
== 0 && (lx
= x25_lxalloc(rt
)) == 0)
if ((lcp
= lx
->lx_lcd
) && lcp
->lcd_state
!= READY
) {
* This can only happen on a RTM_CHANGE operation
* though cmd will be RTM_ADD.
Bcmp(rt
->rt_gateway
, lcp
->lcd_ceaddr
,
lcp
->lcd_ceaddr
->x25_len
) != 0) {
(struct sockaddr
*)lcp
->lcd_ceaddr
, rt
);
x25_rtinvert(RTM_ADD
, rt
->rt_gateway
, rt
);
int x25_dont_rtinvert
= 0;
x25_rtinvert(cmd
, sa
, rt
)
register struct sockaddr
*sa
;
register struct rtentry
*rt
;
* rt_gateway contains PID indicating which proto
* family on the other end, so will be different
* from general host route via X.25.
if (rt
->rt_ifp
->if_type
== IFT_X25DDN
|| x25_dont_rtinvert
)
if (sa
->sa_family
!= AF_CCITT
)
rtrequest(RTM_ADD
, sa
, rt_key(rt
), x25_dgram_sockmask
,
rt2
->rt_llinfo
= (caddr_t
) rt
;
if ((rt
= rtalloc1(sa
, 0)) == 0 ||
(rt
->rt_flags
& RTF_PROTO2
) == 0 ||
rt
->rt_llinfo
!= (caddr_t
)rt2
) {
printf("x25_rtchange: inverse route screwup\n");
rtrequest(RTM_DELETE
, sa
, rt_key(rt2
), x25_dgram_sockmask
,
0, (struct rtentry
**) 0);
static struct sockaddr_x25 blank_x25
= {sizeof blank_x25
, AF_CCITT
};
* IP to X25 address routine copyright ACC, used by permission.
* The following is totally bogus and here only to preserve
* the IP to X.25 translation.
x25_ddnip_to_ccitt(src
, rt
)
register struct rtentry
*rt
;
register struct sockaddr_x25
*dst
= (struct sockaddr_x25
*)rt
->rt_gateway
;
int imp_no
, imp_port
, temp
;
char *x25addr
= dst
->x25_addr
;
imp_addr
.ip
= src
->sin_addr
;
if ((imp_addr
.imp
.s_net
& 0x80) == 0x00) { /* class A */
imp_no
= imp_addr
.imp
.s_impno
;
imp_port
= imp_addr
.imp
.s_host
;
} else if ((imp_addr
.imp
.s_net
& 0xc0) == 0x80) { /* class B */
imp_no
= imp_addr
.imp
.s_impno
;
imp_port
= imp_addr
.imp
.s_lh
;
imp_no
= imp_addr
.imp
.s_impno
/ 32;
imp_port
= imp_addr
.imp
.s_impno
% 32;
x25addr
[0] = 12; /* length */
/* DNIC is cleared by struct copy above */
if (imp_port
< 64) { /* Physical: 0000 0 IIIHH00 [SS] *//* s_impno
* -> III, s_host -> HH */
x25addr
[5] = 0; /* set flag bit */
x25addr
[6] = imp_no
/ 100;
x25addr
[7] = (imp_no
% 100) / 10;
x25addr
[8] = imp_no
% 10;
x25addr
[9] = imp_port
/ 10;
x25addr
[10] = imp_port
% 10;
} else { /* Logical: 0000 1 RRRRR00 [SS] *//* s
* _host * 256 + s_impno -> RRRRR */
temp
= (imp_port
<< 8) + imp_no
;
x25addr
[6] = temp
/ 10000;
x25addr
[7] = (temp
% 10000) / 1000;
x25addr
[8] = (temp
% 1000) / 100;
x25addr
[9] = (temp
% 100) / 10;
* This routine is a sketch and is not to be believed!!!!!
* This is a utility routine to be called by x25 devices when a
* call request is honored with the intent of starting datagram forwarding.
x25_dg_rtinit(dst
, ia
, af
)
struct sockaddr_x25
*dst
;
register struct x25_ifaddr
*ia
;
static struct sockaddr_in sin
= {sizeof(sin
), AF_INET
};
if (ia
->ia_ifp
->if_type
== IFT_X25DDN
&& af
== AF_INET
) {
* Inverse X25 to IP mapping copyright and courtesy ACC.
int imp_no
, imp_port
, temp
;
* First determine our IP addr for network
register struct in_ifaddr
*ina
;
extern struct in_ifaddr
*in_ifaddr
;
for (ina
= in_ifaddr
; ina
; ina
= ina
->ia_next
)
if (ina
->ia_ifp
== ia
->ia_ifp
) {
my_addr
= ina
->ia_addr
.sin_addr
;
register char *x25addr
= dst
->x25_addr
;
switch (x25addr
[5] & 0x0f) {
case 0: /* Physical: 0000 0 IIIHH00 [SS] */
((int) (x25addr
[6] & 0x0f) * 100) +
((int) (x25addr
[7] & 0x0f) * 10) +
((int) (x25addr
[8] & 0x0f));
((int) (x25addr
[9] & 0x0f) * 10) +
((int) (x25addr
[10] & 0x0f));
case 1: /* Logical: 0000 1 RRRRR00 [SS] */
temp
= ((int) (x25addr
[6] & 0x0f) * 10000)
+ ((int) (x25addr
[7] & 0x0f) * 1000)
+ ((int) (x25addr
[8] & 0x0f) * 100)
+ ((int) (x25addr
[9] & 0x0f) * 10)
+ ((int) (x25addr
[10] & 0x0f));
if ((imp_addr
.imp
.s_net
& 0x80) == 0x00) {
imp_addr
.imp
.s_host
= imp_port
;
imp_addr
.imp
.s_impno
= imp_no
;
} else if ((imp_addr
.imp
.s_net
& 0xc0) == 0x80) {
imp_addr
.imp
.s_lh
= imp_port
;
imp_addr
.imp
.s_impno
= imp_no
;
imp_addr
.imp
.s_impno
= (imp_no
<< 5) + imp_port
;
sin
.sin_addr
= imp_addr
.ip
;
sa
= (struct sockaddr
*)&sin
;
* This uses the X25 routing table to do inverse
* lookup of x25 address to sockaddr.
if (rt
= rtalloc1((struct sockaddr
*)dst
, 0)) {
* Call to rtalloc1 will create rtentry for reverse path
* to callee by virtue of cloning magic and will allocate
* space for local control block.
if (sa
&& (rt
= rtalloc1(sa
, 1)))
#define _offsetof(t, m) ((int)((caddr_t)&((t *)0)->m))
struct sockaddr_x25 x25_dgmask
= {
_offsetof(struct sockaddr_x25
, x25_udata
[1]), /* _len */
{ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, /* _addr */
struct radix_tree_head
*x25_rnhead
;
* warning, sizeof (struct sockaddr_x25) > 32,
* but contains no data of interest beyond 32
struct radix_node
*rn_addmask();
rn_inithead(&x25_rnhead
, 32, AF_CCITT
);
SA(rn_addmask((caddr_t
)&x25_dgmask
, 0, 4)->rn_key
);
pk_protolisten(0xcc, 1, x25_dgram_incoming
);
pk_protolisten(0x81, 1, x25_dgram_incoming
);
void (*f
)(struct pklcd
*, struct mbuf
*);
#if defined(ISO) && defined(TPCONS)
{ 0x0, 0, (void (*)(struct pklcd
*, struct mbuf
*))tp_incoming
},
{ 0xcc, 1, x25_dgram_incoming
},
{ 0xcd, 1, x25_dgram_incoming
},
{ 0x81, 1, x25_dgram_incoming
},
pk_user_protolisten(info
)
register struct x25_dgproto
*dp
= x25_dgprototab
+ ((sizeof x25_dgprototab
) / (sizeof *dp
));
register struct pklcd
*lcp
;
while (dp
> x25_dgprototab
)
if ((--dp
)->spi
== info
[0])
return pk_protolisten(dp
->spi
, dp
->spilen
, dp
->f
);
for (lcp
= pk_listenhead
; lcp
; lcp
= lcp
->lcd_listen
)
if (lcp
->lcd_laddr
.x25_udlen
== dp
->spilen
&&
Bcmp(&dp
->spi
, lcp
->lcd_laddr
.x25_udata
, dp
->spilen
) == 0) {
* This routine transfers an X.25 circuit to or from a routing entry.
* If the supplied circuit is * in DATA_TRANSFER state, it is added to the
* routing entry. If freshly allocated, it glues back the vc from
* the rtentry to the socket.
register struct socket
*so
;
register struct pklcd
*lcp
= (struct pklcd
*)so
->so_pcb
;
register struct mbuf
*m
= m0
;
struct sockaddr
*dst
= mtod(m
, struct sockaddr
*);
register struct rtentry
*rt
= rtalloc1(dst
, 0);
register struct llinfo_x25
*lx
;
((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
#define transfer_sockbuf(s, f, l) \
{(s)->sb_mb = m->m_act; m->m_act = 0; sbfree((s), m); f(l, m);}
cp
= (dst
->sa_len
< m
->m_len
) ? ROUNDUP(dst
->sa_len
) + (caddr_t
)dst
: 0;
((cp
== 0 && rt_mask(rt
) != 0) ||
(cp
!= 0 && (rt_mask(rt
) == 0 ||
Bcmp(cp
, rt_mask(rt
), rt_mask(rt
)->sa_len
)) != 0)))
rt
= (struct rtentry
*)rt
->rt_nodes
->rn_dupedkey
;
if (rt
== 0 || (rt
->rt_flags
& RTF_GATEWAY
) ||
(lx
= (struct llinfo_x25
*)rt
->rt_llinfo
) == 0)
switch (lcp
->lcd_state
) {
/* Detach VC from rtentry */
if (lx
->lx_next
->lx_rt
== rt
)
transfer_sockbuf(&lcp
->lcd_sb
, sbappendrecord
, &so
->so_snd
);
lcp
->lcd_sb
= so
->so_snd
; /* structure copy */
bzero((caddr_t
)&so
->so_snd
, sizeof(so
->so_snd
)); /* XXXXXX */
transfer_sockbuf(&so
->so_rcv
, x25_ifinput
, lcp
);
register struct pklcd
*lcp0
;
register struct llinfo_x25
*lx
= (struct llinfo_x25
*)rt
->rt_llinfo
;
register struct pklcd
*lcp
;
if (lcp
= lx
->lx_lcd
) { /* adding an additional VC */
if (lcp
->lcd_state
== READY
) {
transfer_sockbuf(&lcp
->lcd_sb
, pk_output
, lcp0
);
lcp
->lcd_upper
= x25_ifinput
;
lcp
->lcd_upnext
= (caddr_t
)lx
;