* Copyright (c) 1990 The Regents of the University of California.
* %sccs.include.redist.c%
* @(#)if_x25subr.c 7.8 (Berkeley) %G%
#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
;
#define senderr(x) {error = x; goto bad;}
x25_ifoutput(ifp
, m0
, dst
, rt
)
register struct rtentry
*rt
;
register struct llinfo_x25
*lx
;
int s
, error
= 0, flags
= 0, af
;
if ((ifp
->if_flags
& IFF_UP
) == 0)
((rt
->rt_flags
& RTF_GATEWAY
) && (dst
= rt
->rt_gateway
))) {
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)) {
printf("Inconsistent call to x25_output, should panic\n");
register struct ifaddr
*ifa
;
for (ifa
= ifp
->if_addrlist
; ; ifa
= ifa
->ifa_next
) {
if (ifa
->ifa_addr
->sa_family
== AF_CCITT
)
ia
= (struct x25_ifaddr
*)ifa
;
lcp
->lcd_dg_timer
= ia
->ia_xc
.xc_dg_idletimo
;
if (sbspace(&lcp
->lcd_sb
) < 0)
if (dst
->sa_family
== AF_INET
&&
ia
->ia_ifp
->if_type
== IFT_X25DDN
&&
rt
->rt_gateway
->sa_family
!= AF_CCITT
)
x25_ddnip_to_ccitt(dst
, rt
->rt_gateway
);
lcp
->lcd_flags
|= X25_DG_CIRCUIT
;
if (rt
->rt_gateway
->sa_family
!= AF_CCITT
) {
* Need external resolution of dst
if ((rt
->rt_flags
& RTF_XRESOLVE
) == 0)
rt_missmsg(RTM_RESOLVE
, dst
,
(struct sockaddr
*)0, (struct sockaddr
*)0,
(struct sockaddr
*)0, 0, 0);
lx
->lx_state
= LXS_RESOLVING
;
if (sbspace(&lcp
->lcd_sb
) < 0)
pk_fragment(lcp
, m
, 0, 0, 0);
lcp
->lcd_pkp
= &(lx
->lx_ia
->ia_pkcb
);
pk_fragment(lcp
, m
, 0, 0, 0);
pk_connect(lcp
, (struct sockaddr_x25
*)rt
->rt_gateway
);
* 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 ifaddr
*ifa
;
register struct pklcd
**lcpp
, *lcp
;
for (ifa
= ifp
->if_addrlist
; ; ifa
= ifa
->ifa_next
) {
if (ifa
->ifa_addr
->sa_family
== AF_CCITT
)
pkcb
= &((struct x25_ifaddr
*)ifa
)->ia_pkcb
;
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)) {
* Process a x25 packet as datagram;
struct llinfo_x25
*lx
= (struct llinfo_x25
*)lcp
->lcd_upnext
;
register struct ifnet
*ifp
= m
->m_pkthdr
.rcvif
;
extern struct timeval time
;
ifp
->if_lastchange
= time
;
if (lcp
->lcd_state
!= DATA_TRANSFER
) {
ifp
->if_ibytes
+= m
->m_pkthdr
.len
;
* This routine gets called when validing new routes or deletions of old
x25_ifrtchange(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
;
register struct x25_ifaddr
*ia
;
register struct sockaddr
*sa2
;
#define SA(p) ((struct sockaddr *)(p))
MALLOC(lx
, struct llinfo_x25
*, sizeof (*lx
), M_PCB
, M_NOWAIT
);
rt
->rt_llinfo
= (caddr_t
)lx
;
lx
->lx_ia
= (struct x25_ifaddr
*)rt
->rt_ifa
;
if (lcp
&& lcp
->lcd_state
!= READY
) {
if (rt
->rt_flags
& RTF_XRESOLVE
|| sa
->x25_family
!= AF_CCITT
)
lx
->lx_lcd
= lcp
= pk_attach((struct socket
*)0);
lcp
->lcd_upnext
= (caddr_t
)lx
;
lcp
->lcd_upper
= x25_ifinput
;
lcp
->lcd_packetsize
= ia
->ia_xc
.xc_psize
; /* XXX pk_fragment */
lcp
->lcd_pkp
= &(ia
->ia_pkcb
);
if (rt
->rt_ifp
->if_type
== IFT_X25DDN
)
if (sa
->x25_family
== AF_CCITT
) {
sa
->x25_opts
.op_speed
= sa2
->sa_family
;
(void) rtrequest(RTM_DELETE
, SA(sa
), sa2
,
SA(0), RTF_HOST
, (struct rtentry
**)0);
sa
= (struct sockaddr_x25
*)dst
;
if (sa
->x25_family
== AF_CCITT
) {
sa
->x25_opts
.op_speed
= sa2
->sa_family
;
(void) rtrequest(cmd
, SA(sa
), sa2
, SA(0), RTF_HOST
,
sa
->x25_opts
.op_speed
= 0;
static struct sockaddr_x25 blank_x25
= {sizeof blank_x25
, AF_CCITT
};
* IP to X25 address routine copyright ACC, used by permission.
x25_ddnip_to_ccitt(src
, dst
)
register struct sockaddr_x25
*dst
;
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;
static struct sockaddr_in sin
= {sizeof(sin
), AF_INET
};
* 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
;
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.
dst
->x25_opts
.op_speed
= af
;
if (rt
= rtalloc1(dst
, 0)) {
dst
->x25_opts
.op_speed
= 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)))
struct radix_tree_head
*x25_rnhead
;
* warning, sizeof (struct sockaddr_x25) > 32,
* but contains no data of interest beyond 32
rn_inithead(&x25_rnhead
, 16, AF_CCITT
);