xref: /csrg-svn/sys/netccitt/if_x25subr.c (revision 63216)
141598Ssklower /*
2*63216Sbostic  * Copyright (c) 1990, 1993
3*63216Sbostic  *	The Regents of the University of California.  All rights reserved.
441598Ssklower  *
541707Ssklower  * %sccs.include.redist.c%
641598Ssklower  *
7*63216Sbostic  *	@(#)if_x25subr.c	8.1 (Berkeley) 06/10/93
841598Ssklower  */
941598Ssklower 
1057016Sbostic #include <sys/param.h>
1157016Sbostic #include <sys/systm.h>
1257016Sbostic #include <sys/malloc.h>
1357016Sbostic #include <sys/mbuf.h>
1457016Sbostic #include <sys/protosw.h>
1557016Sbostic #include <sys/socket.h>
1657016Sbostic #include <sys/socketvar.h>
1757016Sbostic #include <sys/ioctl.h>
1857016Sbostic #include <sys/errno.h>
1957016Sbostic #include <sys/syslog.h>
2041598Ssklower 
2157030Ssklower #include <machine/mtpr.h>
2257030Ssklower 
2357016Sbostic #include <net/if.h>
2457016Sbostic #include <net/if_types.h>
2557016Sbostic #include <net/netisr.h>
2657016Sbostic #include <net/route.h>
2741598Ssklower 
2857016Sbostic #include <netccitt/x25.h>
2957016Sbostic #include <netccitt/x25err.h>
3057016Sbostic #include <netccitt/pk.h>
3157016Sbostic #include <netccitt/pk_var.h>
3242140Ssklower 
3341598Ssklower #ifdef INET
3457016Sbostic #include <netinet/in.h>
3557016Sbostic #include <netinet/in_var.h>
3641598Ssklower #endif
3741598Ssklower 
3841598Ssklower #ifdef NS
3957016Sbostic #include <netns/ns.h>
4057016Sbostic #include <netns/ns_if.h>
4141598Ssklower #endif
4241598Ssklower 
4341598Ssklower #ifdef ISO
4449928Ssklower int tp_incoming();
4557016Sbostic #include <netiso/argo_debug.h>
4657016Sbostic #include <netiso/iso.h>
4757016Sbostic #include <netiso/iso_var.h>
4841598Ssklower #endif
4941598Ssklower 
5041598Ssklower extern	struct ifnet loif;
5149727Ssklower struct llinfo_x25 llinfo_x25 = {&llinfo_x25, &llinfo_x25};
5257015Ssklower #ifndef _offsetof
5357015Ssklower #define _offsetof(t, m) ((int)((caddr_t)&((t *)0)->m))
5457015Ssklower #endif
5549928Ssklower struct sockaddr *x25_dgram_sockmask;
5657015Ssklower struct sockaddr_x25 x25_dgmask = {
5757015Ssklower  _offsetof(struct sockaddr_x25, x25_udata[1]),			/* _len */
5857015Ssklower  0,								/* _family */
5957015Ssklower  0,								/* _net */
6057015Ssklower  { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, /* _addr */
6157015Ssklower  {0},								/* opts */
6257015Ssklower  -1,								/* _udlen */
6357015Ssklower  {-1}								/* _udata */
6457015Ssklower };
6549928Ssklower 
6650020Ssklower struct if_x25stats {
6750020Ssklower 	int	ifx_wrongplen;
6850020Ssklower 	int	ifx_nophdr;
6950020Ssklower } if_x25stats;
7049727Ssklower int x25_autoconnect = 0;
7141598Ssklower 
7241598Ssklower #define senderr(x) {error = x; goto bad;}
7341598Ssklower /*
7449727Ssklower  * Ancillary routines
7549727Ssklower  */
7649727Ssklower static struct llinfo_x25 *
x25_lxalloc(rt)7749727Ssklower x25_lxalloc(rt)
7849727Ssklower register struct rtentry *rt;
7949727Ssklower {
8049727Ssklower 	register struct llinfo_x25 *lx;
8149727Ssklower 	register struct sockaddr *dst = rt_key(rt);
8249727Ssklower 	register struct ifaddr *ifa;
8349727Ssklower 
8449727Ssklower 	MALLOC(lx, struct llinfo_x25 *, sizeof (*lx), M_PCB, M_NOWAIT);
8549727Ssklower 	if (lx == 0)
8649727Ssklower 		return lx;
8749727Ssklower 	Bzero(lx, sizeof(*lx));
8849727Ssklower 	lx->lx_rt = rt;
8949727Ssklower 	lx->lx_family = dst->sa_family;
9049727Ssklower 	rt->rt_refcnt++;
9149727Ssklower 	if (rt->rt_llinfo)
9249727Ssklower 		insque(lx, (struct llinfo_x25 *)rt->rt_llinfo);
9349727Ssklower 	else {
9449727Ssklower 		rt->rt_llinfo = (caddr_t)lx;
9549727Ssklower 		insque(lx, &llinfo_x25);
9649727Ssklower 	}
9749727Ssklower 	for (ifa = rt->rt_ifp->if_addrlist; ifa; ifa = ifa->ifa_next) {
9849727Ssklower 		if (ifa->ifa_addr->sa_family == AF_CCITT)
9949727Ssklower 			lx->lx_ia = (struct x25_ifaddr *)ifa;
10049727Ssklower 	}
10149727Ssklower 	return lx;
10249727Ssklower }
x25_lxfree(lx)10349727Ssklower x25_lxfree(lx)
10449727Ssklower register struct llinfo_x25 *lx;
10549727Ssklower {
10649727Ssklower 	register struct rtentry *rt = lx->lx_rt;
10749727Ssklower 	register struct pklcd *lcp = lx->lx_lcd;
10849727Ssklower 
10949727Ssklower 	if (lcp) {
11049727Ssklower 		lcp->lcd_upper = 0;
11149727Ssklower 		pk_disconnect(lcp);
11249727Ssklower 	}
11349727Ssklower 	if ((rt->rt_llinfo == (caddr_t)lx) && (lx->lx_next->lx_rt == rt))
11449727Ssklower 		rt->rt_llinfo = (caddr_t)lx->lx_next;
11549727Ssklower 	else
11649727Ssklower 		rt->rt_llinfo = 0;
11749727Ssklower 	RTFREE(rt);
11849727Ssklower 	remque(lx);
11949727Ssklower 	FREE(lx, M_PCB);
12049727Ssklower }
12149727Ssklower /*
12249727Ssklower  * Process a x25 packet as datagram;
12349727Ssklower  */
12449727Ssklower x25_ifinput(lcp, m)
12549727Ssklower struct pklcd *lcp;
12649727Ssklower register struct mbuf *m;
12749727Ssklower {
12849727Ssklower 	struct llinfo_x25 *lx = (struct llinfo_x25 *)lcp->lcd_upnext;
12949727Ssklower 	register struct ifnet *ifp;
13049727Ssklower 	struct ifqueue *inq;
13149727Ssklower 	extern struct timeval time;
13249727Ssklower 	int s, len, isr;
13349727Ssklower 
13449727Ssklower 	if (m == 0 || lcp->lcd_state != DATA_TRANSFER) {
13549727Ssklower 		x25_connect_callback(lcp, 0);
13649727Ssklower 		return;
13749727Ssklower 	}
13849928Ssklower 	pk_flowcontrol(lcp, 0, 1); /* Generate RR */
13949727Ssklower 	ifp = m->m_pkthdr.rcvif;
14049727Ssklower 	ifp->if_lastchange = time;
14149727Ssklower 	switch (m->m_type) {
14257953Ssklower 	default:
14349727Ssklower 		if (m)
14449727Ssklower 			m_freem(m);
14549727Ssklower 		return;
14649727Ssklower 
14749727Ssklower 	case MT_DATA:
14849727Ssklower 		/* FALLTHROUGH */;
14949727Ssklower 	}
15049727Ssklower 	switch (lx->lx_family) {
15149727Ssklower #ifdef INET
15249727Ssklower 	case AF_INET:
15349727Ssklower 		isr = NETISR_IP;
15449727Ssklower 		inq = &ipintrq;
15549727Ssklower 		break;
15649727Ssklower 
15749727Ssklower #endif
15849727Ssklower #ifdef NS
15949727Ssklower 	case AF_NS:
16049727Ssklower 		isr = NETISR_NS;
16149727Ssklower 		inq = &nsintrq;
16249727Ssklower 		break;
16349727Ssklower 
16449727Ssklower #endif
16549727Ssklower #ifdef	ISO
16649727Ssklower 	case AF_ISO:
16749727Ssklower 		isr = NETISR_ISO;
16849727Ssklower 		inq = &clnlintrq;
16949727Ssklower 		break;
17049727Ssklower #endif
17149727Ssklower 	default:
17249727Ssklower 		m_freem(m);
17349727Ssklower 		ifp->if_noproto++;
17449727Ssklower 		return;
17549727Ssklower 	}
17649727Ssklower 	s = splimp();
17749727Ssklower 	schednetisr(isr);
17849727Ssklower 	if (IF_QFULL(inq)) {
17949727Ssklower 		IF_DROP(inq);
18049727Ssklower 		m_freem(m);
18149727Ssklower 	} else {
18249727Ssklower 		IF_ENQUEUE(inq, m);
18349727Ssklower 		ifp->if_ibytes += m->m_pkthdr.len;
18449727Ssklower 	}
18549727Ssklower 	splx(s);
18649727Ssklower }
x25_connect_callback(lcp,m)18749727Ssklower x25_connect_callback(lcp, m)
18849727Ssklower register struct pklcd *lcp;
18949727Ssklower register struct mbuf *m;
19049727Ssklower {
19149727Ssklower 	register struct llinfo_x25 *lx = (struct llinfo_x25 *)lcp->lcd_upnext;
19257953Ssklower 	int do_clear = 1;
19349727Ssklower 	if (m == 0)
19449727Ssklower 		goto refused;
19549727Ssklower 	if (m->m_type != MT_CONTROL) {
19649727Ssklower 		printf("x25_connect_callback: should panic\n");
19749727Ssklower 		goto refused;
19849727Ssklower 	}
19949727Ssklower 	switch (pk_decode(mtod(m, struct x25_packet *))) {
20049727Ssklower 	case CALL_ACCEPTED:
20149727Ssklower 		lcp->lcd_upper = x25_ifinput;
20249727Ssklower 		if (lcp->lcd_sb.sb_mb)
20349727Ssklower 			lcp->lcd_send(lcp); /* XXX start queued packets */
20449727Ssklower 		return;
20549727Ssklower 	default:
20657953Ssklower 		do_clear = 0;
20749727Ssklower 	refused:
20849727Ssklower 		lcp->lcd_upper = 0;
20949727Ssklower 		lx->lx_lcd = 0;
21057953Ssklower 		if (do_clear)
21157953Ssklower 			pk_disconnect(lcp);
21249727Ssklower 		return;
21349727Ssklower 	}
21449727Ssklower }
21549928Ssklower #define SA(p) ((struct sockaddr *)(p))
21649928Ssklower #define RT(p) ((struct rtentry *)(p))
21749928Ssklower 
x25_dgram_incoming(lcp,m0)21849928Ssklower x25_dgram_incoming(lcp, m0)
21949928Ssklower register struct pklcd *lcp;
22049928Ssklower struct mbuf *m0;
22149928Ssklower {
22249928Ssklower 	register struct rtentry *rt, *nrt;
22349928Ssklower 	register struct mbuf *m = m0->m_next; /* m0 has calling sockaddr_x25 */
22454827Ssklower 	void x25_rtrequest();
22549928Ssklower 
22649928Ssklower 	rt = rtalloc1(SA(&lcp->lcd_faddr), 0);
22749928Ssklower 	if (rt == 0) {
22849928Ssklower refuse: 	lcp->lcd_upper = 0;
22949928Ssklower 		pk_close(lcp);
23049928Ssklower 		return;
23149928Ssklower 	}
23249928Ssklower 	rt->rt_refcnt--;
23349928Ssklower 	if ((nrt = RT(rt->rt_llinfo)) == 0 || rt_mask(rt) != x25_dgram_sockmask)
23449928Ssklower 		goto refuse;
23549928Ssklower 	if ((nrt->rt_flags & RTF_UP) == 0) {
23649928Ssklower 		rt->rt_llinfo = (caddr_t)rtalloc1(rt->rt_gateway, 0);
23749928Ssklower 		rtfree(nrt);
23849928Ssklower 		if ((nrt = RT(rt->rt_llinfo)) == 0)
23949928Ssklower 			goto refuse;
24049928Ssklower 		nrt->rt_refcnt--;
24149928Ssklower 	}
24249928Ssklower 	if (nrt->rt_ifa == 0 || nrt->rt_ifa->ifa_rtrequest != x25_rtrequest)
24349928Ssklower 		goto refuse;
24449928Ssklower 	lcp->lcd_send(lcp); /* confirm call */
24549928Ssklower 	x25_rtattach(lcp, nrt);
24649928Ssklower 	m_freem(m);
24749928Ssklower }
24849928Ssklower 
24949727Ssklower /*
25041598Ssklower  * X.25 output routine.
25141598Ssklower  */
25242140Ssklower x25_ifoutput(ifp, m0, dst, rt)
25342140Ssklower struct	ifnet *ifp;
25441598Ssklower struct	mbuf *m0;
25541598Ssklower struct	sockaddr *dst;
25641598Ssklower register struct	rtentry *rt;
25741598Ssklower {
25849928Ssklower 	register struct	mbuf *m = m0;
25949727Ssklower 	register struct	llinfo_x25 *lx;
26042140Ssklower 	struct pklcd *lcp;
26149727Ssklower 	int             s, error = 0;
26241598Ssklower 
26350020Ssklower int plen;
26450020Ssklower for (plen = 0; m; m = m->m_next)
26550020Ssklower 	plen += m->m_len;
26650020Ssklower m = m0;
26750020Ssklower 
26842140Ssklower 	if ((ifp->if_flags & IFF_UP) == 0)
26949727Ssklower 		senderr(ENETDOWN);
27049748Ssklower 	while (rt == 0 || (rt->rt_flags & RTF_GATEWAY)) {
27149748Ssklower 		if (rt) {
27249748Ssklower 			if (rt->rt_llinfo) {
27349748Ssklower 				rt = (struct rtentry *)rt->rt_llinfo;
27449748Ssklower 				continue;
27549748Ssklower 			}
27649748Ssklower 			dst = rt->rt_gateway;
27749748Ssklower 		}
27841598Ssklower 		if ((rt = rtalloc1(dst, 1)) == 0)
27949727Ssklower 			senderr(EHOSTUNREACH);
28049727Ssklower 		rt->rt_refcnt--;
28141598Ssklower 	}
28241598Ssklower 	/*
28341598Ssklower 	 * Sanity checks.
28441598Ssklower 	 */
28542140Ssklower 	if ((rt->rt_ifp != ifp) ||
28641598Ssklower 	    (rt->rt_flags & (RTF_CLONING | RTF_GATEWAY)) ||
28745165Ssklower 	    ((lx = (struct llinfo_x25 *)rt->rt_llinfo) == 0)) {
28841598Ssklower 		senderr(ENETUNREACH);
28941598Ssklower 	}
29050020Ssklower if ((m->m_flags & M_PKTHDR) == 0) {
29150020Ssklower 	if_x25stats.ifx_nophdr++;
29250020Ssklower 	m = m_gethdr(M_NOWAIT, MT_HEADER);
29350020Ssklower 	if (m == 0)
29450020Ssklower 		senderr(ENOBUFS);
29550020Ssklower 	m->m_pkthdr.len = plen;
29650020Ssklower 	m->m_next = m0;
29750020Ssklower }
29850020Ssklower if (plen != m->m_pkthdr.len) {
29950020Ssklower 	if_x25stats.ifx_wrongplen++;
30050020Ssklower 	m->m_pkthdr.len = plen;
30150020Ssklower }
30249727Ssklower next_circuit:
30349727Ssklower 	lcp = lx->lx_lcd;
30449727Ssklower 	if (lcp == 0) {
30549727Ssklower 		lx->lx_lcd = lcp = pk_attach((struct socket *)0);
30649727Ssklower 		if (lcp == 0)
30749727Ssklower 			senderr(ENOBUFS);
30849727Ssklower 		lcp->lcd_upper = x25_connect_callback;
30949727Ssklower 		lcp->lcd_upnext = (caddr_t)lx;
31049727Ssklower 		lcp->lcd_packetsize = lx->lx_ia->ia_xc.xc_psize;
31150020Ssklower 		lcp->lcd_flags = X25_MBS_HOLD;
31242140Ssklower 	}
31349727Ssklower 	switch (lcp->lcd_state) {
31449727Ssklower 	case READY:
31549748Ssklower 		if (dst->sa_family == AF_INET &&
31649748Ssklower 		    ifp->if_type == IFT_X25DDN &&
31749748Ssklower 		    rt->rt_gateway->sa_family != AF_CCITT)
31849748Ssklower 			x25_ddnip_to_ccitt(dst, rt);
31941598Ssklower 		if (rt->rt_gateway->sa_family != AF_CCITT) {
32041598Ssklower 			if ((rt->rt_flags & RTF_XRESOLVE) == 0)
32149727Ssklower 				senderr(EHOSTUNREACH);
32249727Ssklower 		} else if (x25_autoconnect)
32349727Ssklower 			error = pk_connect(lcp,
32449727Ssklower 					(struct sockaddr_x25 *)rt->rt_gateway);
32549727Ssklower 		if (error)
32649727Ssklower 			senderr(error);
32749727Ssklower 		/* FALLTHROUGH */
32849727Ssklower 	case SENT_CALL:
32949727Ssklower 	case DATA_TRANSFER:
33049727Ssklower 		if (sbspace(&lcp->lcd_sb) < 0) {
33149727Ssklower 			lx = lx->lx_next;
33249727Ssklower 			if (lx->lx_rt != rt)
33349727Ssklower 				senderr(ENOSPC);
33449727Ssklower 			goto next_circuit;
33541598Ssklower 		}
33649727Ssklower 		if (lx->lx_ia)
33749727Ssklower 			lcp->lcd_dg_timer =
33849727Ssklower 				       lx->lx_ia->ia_xc.xc_dg_idletimo;
33949032Ssklower 		pk_send(lcp, m);
34042140Ssklower 		break;
34141598Ssklower 	default:
34241598Ssklower 		/*
34341598Ssklower 		 * We count on the timer routine to close idle
34441598Ssklower 		 * connections, if there are not enough circuits to go
34541598Ssklower 		 * around.
34641598Ssklower 		 *
34741598Ssklower 		 * So throw away data for now.
34841598Ssklower 		 * After we get it all working, we'll rewrite to handle
34941598Ssklower 		 * actively closing connections (other than by timers),
35041598Ssklower 		 * when circuits get tight.
35141598Ssklower 		 *
35241598Ssklower 		 * In the DDN case, the imp itself closes connections
35341598Ssklower 		 * under heavy load.
35441598Ssklower 		 */
35541598Ssklower 		error = ENOBUFS;
35641598Ssklower 	bad:
35741598Ssklower 		if (m)
35841598Ssklower 			m_freem(m);
35941598Ssklower 	}
36041598Ssklower 	return (error);
36141598Ssklower }
36241598Ssklower 
36341598Ssklower /*
36442140Ssklower  * Simpleminded timer routine.
36541598Ssklower  */
36642140Ssklower x25_iftimeout(ifp)
36742140Ssklower struct ifnet *ifp;
36841598Ssklower {
36942140Ssklower 	register struct pkcb *pkcb = 0;
37042140Ssklower 	register struct pklcd **lcpp, *lcp;
37141598Ssklower 	int s = splimp();
37241598Ssklower 
37357030Ssklower 	FOR_ALL_PKCBS(pkcb)
37449928Ssklower 	    if (pkcb->pk_ia->ia_ifp == ifp)
37542140Ssklower 		for (lcpp = pkcb->pk_chan + pkcb->pk_maxlcn;
37645895Ssklower 		     --lcpp > pkcb->pk_chan;)
37742140Ssklower 			if ((lcp = *lcpp) &&
37842140Ssklower 			    lcp->lcd_state == DATA_TRANSFER &&
37945165Ssklower 			    (lcp->lcd_flags & X25_DG_CIRCUIT) &&
38045895Ssklower 			    (lcp->lcd_dg_timer && --lcp->lcd_dg_timer == 0)) {
38149727Ssklower 				lcp->lcd_upper(lcp, 0);
38245895Ssklower 			}
38341598Ssklower 	splx(s);
38441598Ssklower }
38541598Ssklower /*
38649727Ssklower  * This routine gets called when validating additions of new routes
38749748Ssklower  * or deletions of old ones.
38841598Ssklower  */
x25_rtrequest(cmd,rt,dst)38949928Ssklower x25_rtrequest(cmd, rt, dst)
39045895Ssklower register struct rtentry *rt;
39145895Ssklower struct sockaddr *dst;
39245895Ssklower {
39345895Ssklower 	register struct llinfo_x25 *lx = (struct llinfo_x25 *)rt->rt_llinfo;
39445895Ssklower 	register struct sockaddr_x25 *sa =(struct sockaddr_x25 *)rt->rt_gateway;
39545895Ssklower 	register struct pklcd *lcp;
39645895Ssklower 
39757015Ssklower 	/* would put this pk_init, except routing table doesn't
39857015Ssklower 	   exist yet. */
39957015Ssklower 	if (x25_dgram_sockmask == 0) {
40057015Ssklower 		struct radix_node *rn_addmask();
40157015Ssklower 		x25_dgram_sockmask =
40257015Ssklower 			SA(rn_addmask((caddr_t)&x25_dgmask, 0, 4)->rn_key);
40357015Ssklower 	}
40449727Ssklower 	if (rt->rt_flags & RTF_GATEWAY) {
40549727Ssklower 		if (rt->rt_llinfo)
40649727Ssklower 			RTFREE((struct rtentry *)rt->rt_llinfo);
40749727Ssklower 		rt->rt_llinfo = (cmd == RTM_ADD) ?
40849727Ssklower 			(caddr_t)rtalloc1(rt->rt_gateway, 1) : 0;
40949727Ssklower 		return;
41049727Ssklower 	}
41149748Ssklower 	if ((rt->rt_flags & RTF_HOST) == 0)
41249748Ssklower 		return;
41349032Ssklower 	if (cmd == RTM_DELETE) {
41449727Ssklower 		while (rt->rt_llinfo)
41549727Ssklower 			x25_lxfree((struct llinfo *)rt->rt_llinfo);
41649727Ssklower 		x25_rtinvert(RTM_DELETE, rt->rt_gateway, rt);
41749032Ssklower 		return;
41849032Ssklower 	}
41949748Ssklower 	if (lx == 0 && (lx = x25_lxalloc(rt)) == 0)
42049748Ssklower 		return;
42149727Ssklower 	if ((lcp = lx->lx_lcd) && lcp->lcd_state != READY) {
42249727Ssklower 		/*
42349727Ssklower 		 * This can only happen on a RTM_CHANGE operation
42449727Ssklower 		 * though cmd will be RTM_ADD.
42549727Ssklower 		 */
42649727Ssklower 		if (lcp->lcd_ceaddr &&
42749727Ssklower 		    Bcmp(rt->rt_gateway, lcp->lcd_ceaddr,
42849727Ssklower 					 lcp->lcd_ceaddr->x25_len) != 0) {
42949727Ssklower 			x25_rtinvert(RTM_DELETE, lcp->lcd_ceaddr, rt);
43049727Ssklower 			lcp->lcd_upper = 0;
43149727Ssklower 			pk_disconnect(lcp);
43249727Ssklower 		}
43349727Ssklower 		lcp = 0;
43445895Ssklower 	}
43549727Ssklower 	x25_rtinvert(RTM_ADD, rt->rt_gateway, rt);
43649727Ssklower }
43749727Ssklower 
43849928Ssklower int x25_dont_rtinvert = 0;
43949748Ssklower 
x25_rtinvert(cmd,sa,rt)44049727Ssklower x25_rtinvert(cmd, sa, rt)
44149727Ssklower register struct sockaddr *sa;
44249727Ssklower register struct rtentry *rt;
44349727Ssklower {
44449727Ssklower 	struct rtentry *rt2 = 0;
44549727Ssklower 	/*
44649727Ssklower 	 * rt_gateway contains PID indicating which proto
44749727Ssklower 	 * family on the other end, so will be different
44849727Ssklower 	 * from general host route via X.25.
44949727Ssklower 	 */
45049928Ssklower 	if (rt->rt_ifp->if_type == IFT_X25DDN || x25_dont_rtinvert)
45149748Ssklower 		return;
45249727Ssklower 	if (sa->sa_family != AF_CCITT)
45349727Ssklower 		return;
45449928Ssklower 	if (cmd != RTM_DELETE) {
45549928Ssklower 		rtrequest(RTM_ADD, sa, rt_key(rt), x25_dgram_sockmask,
45649928Ssklower 				RTF_PROTO2, &rt2);
45749032Ssklower 		if (rt2) {
45849727Ssklower 			rt2->rt_llinfo = (caddr_t) rt;
45949032Ssklower 			rt->rt_refcnt++;
46049032Ssklower 		}
46145895Ssklower 		return;
46245895Ssklower 	}
46349727Ssklower 	rt2 = rt;
46449727Ssklower 	if ((rt = rtalloc1(sa, 0)) == 0 ||
46549928Ssklower 	    (rt->rt_flags & RTF_PROTO2) == 0 ||
46649928Ssklower 	    rt->rt_llinfo != (caddr_t)rt2) {
46749727Ssklower 		printf("x25_rtchange: inverse route screwup\n");
46845895Ssklower 		return;
46949727Ssklower 	} else
47049727Ssklower 		rt2->rt_refcnt--;
47149928Ssklower 	rtrequest(RTM_DELETE, sa, rt_key(rt2), x25_dgram_sockmask,
47249928Ssklower 				0, (struct rtentry **) 0);
47345895Ssklower }
47445895Ssklower 
47541598Ssklower static struct sockaddr_x25 blank_x25 = {sizeof blank_x25, AF_CCITT};
47641598Ssklower /*
47741598Ssklower  * IP to X25 address routine copyright ACC, used by permission.
47841598Ssklower  */
47945895Ssklower union imp_addr {
48045895Ssklower 	struct in_addr  ip;
48145895Ssklower 	struct imp {
48245895Ssklower 		u_char		s_net;
48345895Ssklower 		u_char		s_host;
48445895Ssklower 		u_char		s_lh;
48545895Ssklower 		u_char		s_impno;
48645895Ssklower 	}		    imp;
48745895Ssklower };
48845895Ssklower 
48949727Ssklower /*
49049727Ssklower  * The following is totally bogus and here only to preserve
49149727Ssklower  * the IP to X.25 translation.
49249727Ssklower  */
49349727Ssklower x25_ddnip_to_ccitt(src, rt)
49441598Ssklower struct sockaddr_in *src;
49549727Ssklower register struct rtentry *rt;
49641598Ssklower {
49749727Ssklower 	register struct sockaddr_x25 *dst = (struct sockaddr_x25 *)rt->rt_gateway;
49841598Ssklower 	union imp_addr imp_addr;
49945165Ssklower 	int             imp_no, imp_port, temp;
50045165Ssklower 	char *x25addr = dst->x25_addr;
50141598Ssklower 
50241598Ssklower 
50345165Ssklower 	imp_addr.ip = src->sin_addr;
50441598Ssklower 	*dst = blank_x25;
50541598Ssklower 	if ((imp_addr.imp.s_net & 0x80) == 0x00) {	/* class A */
50641598Ssklower 	    imp_no = imp_addr.imp.s_impno;
50741598Ssklower 	    imp_port = imp_addr.imp.s_host;
50841598Ssklower 	} else if ((imp_addr.imp.s_net & 0xc0) == 0x80) {	/* class B */
50941598Ssklower 	    imp_no = imp_addr.imp.s_impno;
51041598Ssklower 	    imp_port = imp_addr.imp.s_lh;
51141598Ssklower 	} else {		/* class C */
51241598Ssklower 	    imp_no = imp_addr.imp.s_impno / 32;
51341598Ssklower 	    imp_port = imp_addr.imp.s_impno % 32;
51441598Ssklower 	}
51541598Ssklower 
51641598Ssklower 	x25addr[0] = 12; /* length */
51741598Ssklower 	/* DNIC is cleared by struct copy above */
51841598Ssklower 
51941598Ssklower 	if (imp_port < 64) {	/* Physical:  0000 0 IIIHH00 [SS] *//* s_impno
52041598Ssklower 				 *  -> III, s_host -> HH */
52141598Ssklower 	    x25addr[5] = 0;	/* set flag bit */
52241598Ssklower 	    x25addr[6] = imp_no / 100;
52341598Ssklower 	    x25addr[7] = (imp_no % 100) / 10;
52441598Ssklower 	    x25addr[8] = imp_no % 10;
52541598Ssklower 	    x25addr[9] = imp_port / 10;
52641598Ssklower 	    x25addr[10] = imp_port % 10;
52741598Ssklower 	} else {		/* Logical:   0000 1 RRRRR00 [SS]	 *//* s
52841598Ssklower 				 * _host * 256 + s_impno -> RRRRR */
52941598Ssklower 	    temp = (imp_port << 8) + imp_no;
53041598Ssklower 	    x25addr[5] = 1;
53141598Ssklower 	    x25addr[6] = temp / 10000;
53241598Ssklower 	    x25addr[7] = (temp % 10000) / 1000;
53341598Ssklower 	    x25addr[8] = (temp % 1000) / 100;
53441598Ssklower 	    x25addr[9] = (temp % 100) / 10;
53541598Ssklower 	    x25addr[10] = temp % 10;
53641598Ssklower 	}
53741598Ssklower }
53841598Ssklower 
53941598Ssklower /*
54045895Ssklower  * This routine is a sketch and is not to be believed!!!!!
54145895Ssklower  *
54241598Ssklower  * This is a utility routine to be called by x25 devices when a
54341598Ssklower  * call request is honored with the intent of starting datagram forwarding.
54441598Ssklower  */
54542140Ssklower x25_dg_rtinit(dst, ia, af)
54641598Ssklower struct sockaddr_x25 *dst;
54745165Ssklower register struct x25_ifaddr *ia;
54841598Ssklower {
54941598Ssklower 	struct sockaddr *sa = 0;
55045165Ssklower 	struct rtentry *rt;
55145165Ssklower 	struct in_addr my_addr;
55249727Ssklower 	static struct sockaddr_in sin = {sizeof(sin), AF_INET};
55345165Ssklower 
55445165Ssklower 	if (ia->ia_ifp->if_type == IFT_X25DDN && af == AF_INET) {
55541598Ssklower 	/*
55645165Ssklower 	 * Inverse X25 to IP mapping copyright and courtesy ACC.
55741598Ssklower 	 */
55841598Ssklower 		int             imp_no, imp_port, temp;
55941598Ssklower 		union imp_addr imp_addr;
56041598Ssklower 	    {
56141598Ssklower 		/*
56241598Ssklower 		 * First determine our IP addr for network
56341598Ssklower 		 */
56445165Ssklower 		register struct in_ifaddr *ina;
56541598Ssklower 		extern struct in_ifaddr *in_ifaddr;
56645165Ssklower 
56745165Ssklower 		for (ina = in_ifaddr; ina; ina = ina->ia_next)
56845165Ssklower 			if (ina->ia_ifp == ia->ia_ifp) {
56945165Ssklower 				my_addr = ina->ia_addr.sin_addr;
57041598Ssklower 				break;
57141598Ssklower 			}
57241598Ssklower 	    }
57341598Ssklower 	    {
57441598Ssklower 
57541598Ssklower 		register char *x25addr = dst->x25_addr;
57641598Ssklower 
57741598Ssklower 		switch (x25addr[5] & 0x0f) {
57841598Ssklower 		  case 0:	/* Physical:  0000 0 IIIHH00 [SS]	 */
57941598Ssklower 		    imp_no =
58041598Ssklower 			((int) (x25addr[6] & 0x0f) * 100) +
58141598Ssklower 			((int) (x25addr[7] & 0x0f) * 10) +
58241598Ssklower 			((int) (x25addr[8] & 0x0f));
58341598Ssklower 
58441598Ssklower 
58541598Ssklower 		    imp_port =
58641598Ssklower 			((int) (x25addr[9] & 0x0f) * 10) +
58741598Ssklower 			((int) (x25addr[10] & 0x0f));
58841598Ssklower 		    break;
58941598Ssklower 		  case 1:	/* Logical:   0000 1 RRRRR00 [SS]	 */
59041598Ssklower 		    temp = ((int) (x25addr[6] & 0x0f) * 10000)
59141598Ssklower 			+ ((int) (x25addr[7] & 0x0f) * 1000)
59241598Ssklower 			+ ((int) (x25addr[8] & 0x0f) * 100)
59341598Ssklower 			+ ((int) (x25addr[9] & 0x0f) * 10)
59441598Ssklower 			+ ((int) (x25addr[10] & 0x0f));
59541598Ssklower 
59641598Ssklower 		    imp_port = temp >> 8;
59741598Ssklower 		    imp_no = temp & 0xff;
59841598Ssklower 		    break;
59941598Ssklower 		  default:
60041598Ssklower 		    return (0L);
60141598Ssklower 		}
60245165Ssklower 		imp_addr.ip = my_addr;
60341598Ssklower 		if ((imp_addr.imp.s_net & 0x80) == 0x00) {
60441598Ssklower 		/* class A */
60541598Ssklower 		    imp_addr.imp.s_host = imp_port;
60641598Ssklower 		    imp_addr.imp.s_impno = imp_no;
60741598Ssklower 		    imp_addr.imp.s_lh = 0;
60841598Ssklower 		} else if ((imp_addr.imp.s_net & 0xc0) == 0x80) {
60941598Ssklower 		/* class B */
61041598Ssklower 		    imp_addr.imp.s_lh = imp_port;
61141598Ssklower 		    imp_addr.imp.s_impno = imp_no;
61241598Ssklower 		} else {
61341598Ssklower 		/* class C */
61441598Ssklower 		    imp_addr.imp.s_impno = (imp_no << 5) + imp_port;
61541598Ssklower 		}
61641598Ssklower 	    }
61741598Ssklower 		sin.sin_addr = imp_addr.ip;
61841598Ssklower 		sa = (struct sockaddr *)&sin;
61941598Ssklower 	} else {
62041598Ssklower 		/*
62141598Ssklower 		 * This uses the X25 routing table to do inverse
62241598Ssklower 		 * lookup of x25 address to sockaddr.
62341598Ssklower 		 */
62461656Ssklower 		if (rt = rtalloc1(SA(dst), 0)) {
62541598Ssklower 			sa = rt->rt_gateway;
62641598Ssklower 			rt->rt_refcnt--;
62741598Ssklower 		}
62841598Ssklower 	}
62941598Ssklower 	/*
63041598Ssklower 	 * Call to rtalloc1 will create rtentry for reverse path
63141598Ssklower 	 * to callee by virtue of cloning magic and will allocate
63241598Ssklower 	 * space for local control block.
63341598Ssklower 	 */
63445165Ssklower 	if (sa && (rt = rtalloc1(sa, 1)))
63541598Ssklower 		rt->rt_refcnt--;
63641598Ssklower }
63749928Ssklower int x25_startproto = 1;
63843362Ssklower 
pk_init()63943362Ssklower pk_init()
64043362Ssklower {
64143362Ssklower 	/*
64243362Ssklower 	 * warning, sizeof (struct sockaddr_x25) > 32,
64343362Ssklower 	 * but contains no data of interest beyond 32
64443362Ssklower 	 */
64549928Ssklower 	if (x25_startproto) {
64649928Ssklower 		pk_protolisten(0xcc, 1, x25_dgram_incoming);
64749928Ssklower 		pk_protolisten(0x81, 1, x25_dgram_incoming);
64849928Ssklower 	}
64943362Ssklower }
65049928Ssklower 
65149928Ssklower struct x25_dgproto {
65249928Ssklower 	u_char spi;
65349928Ssklower 	u_char spilen;
65449928Ssklower 	int (*f)();
65549928Ssklower } x25_dgprototab[] = {
65649928Ssklower #if defined(ISO) && defined(TPCONS)
65749928Ssklower { 0x0, 0, tp_incoming},
65849928Ssklower #endif
65949928Ssklower { 0xcc, 1, x25_dgram_incoming},
66049928Ssklower { 0xcd, 1, x25_dgram_incoming},
66149928Ssklower { 0x81, 1, x25_dgram_incoming},
66249928Ssklower };
66349928Ssklower 
pk_user_protolisten(info)66449928Ssklower pk_user_protolisten(info)
66549928Ssklower register u_char *info;
66649928Ssklower {
66749928Ssklower 	register struct x25_dgproto *dp = x25_dgprototab
66849928Ssklower 		    + ((sizeof x25_dgprototab) / (sizeof *dp));
66949928Ssklower 	register struct pklcd *lcp;
67049928Ssklower 
67149928Ssklower 	while (dp > x25_dgprototab)
67249928Ssklower 		if ((--dp)->spi == info[0])
67349928Ssklower 			goto gotspi;
67449928Ssklower 	return ESRCH;
67549928Ssklower 
67649928Ssklower gotspi:	if (info[1])
67749928Ssklower 		return pk_protolisten(dp->spi, dp->spilen, dp->f);
67849928Ssklower 	for (lcp = pk_listenhead; lcp; lcp = lcp->lcd_listen)
67949928Ssklower 		if (lcp->lcd_laddr.x25_udlen == dp->spilen &&
68049928Ssklower 		    Bcmp(&dp->spi, lcp->lcd_laddr.x25_udata, dp->spilen) == 0) {
68150155Ssklower 			pk_disconnect(lcp);
68249928Ssklower 			return 0;
68349928Ssklower 		}
68449928Ssklower 	return ESRCH;
68549928Ssklower }
68649928Ssklower 
68749727Ssklower /*
68849928Ssklower  * This routine transfers an X.25 circuit to or from a routing entry.
68949928Ssklower  * If the supplied circuit is * in DATA_TRANSFER state, it is added to the
69049928Ssklower  * routing entry.  If freshly allocated, it glues back the vc from
69149928Ssklower  * the rtentry to the socket.
69249727Ssklower  */
pk_rtattach(so,m0)69349727Ssklower pk_rtattach(so, m0)
69449727Ssklower register struct socket *so;
69549727Ssklower struct mbuf *m0;
69649727Ssklower {
69749727Ssklower 	register struct pklcd *lcp = (struct pklcd *)so->so_pcb;
69849727Ssklower 	register struct mbuf *m = m0;
69949727Ssklower 	struct sockaddr *dst = mtod(m, struct sockaddr *);
70049727Ssklower 	register struct rtentry *rt = rtalloc1(dst, 0);
70149727Ssklower 	register struct llinfo_x25 *lx;
70249727Ssklower 	caddr_t cp;
70349727Ssklower #define ROUNDUP(a) \
70449727Ssklower 	((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
70549727Ssklower #define transfer_sockbuf(s, f, l) \
70649928Ssklower 	while (m = (s)->sb_mb)\
70749928Ssklower 		{(s)->sb_mb = m->m_act; m->m_act = 0; sbfree((s), m); f(l, m);}
70849727Ssklower 
70949727Ssklower 	if (rt)
71049727Ssklower 		rt->rt_refcnt--;
71149727Ssklower 	cp = (dst->sa_len < m->m_len) ? ROUNDUP(dst->sa_len) + (caddr_t)dst : 0;
71249727Ssklower 	while (rt &&
71349727Ssklower 	       ((cp == 0 && rt_mask(rt) != 0) ||
71449727Ssklower 		(cp != 0 && (rt_mask(rt) == 0 ||
71549727Ssklower 			     Bcmp(cp, rt_mask(rt), rt_mask(rt)->sa_len)) != 0)))
71649727Ssklower 			rt = (struct rtentry *)rt->rt_nodes->rn_dupedkey;
71749727Ssklower 	if (rt == 0 || (rt->rt_flags & RTF_GATEWAY) ||
71849727Ssklower 	    (lx = (struct llinfo_x25 *)rt->rt_llinfo) == 0)
71949727Ssklower 		return ESRCH;
72049928Ssklower 	if (lcp == 0)
72149727Ssklower 		return ENOTCONN;
72249928Ssklower 	switch (lcp->lcd_state) {
72349928Ssklower 	default:
72449928Ssklower 		return ENOTCONN;
72549928Ssklower 
72649928Ssklower 	case READY:
72749928Ssklower 		/* Detach VC from rtentry */
72849928Ssklower 		if (lx->lx_lcd == 0)
72949928Ssklower 			return ENOTCONN;
73049928Ssklower 		lcp->lcd_so = 0;
73149928Ssklower 		pk_close(lcp);
73249928Ssklower 		lcp = lx->lx_lcd;
73349928Ssklower 		if (lx->lx_next->lx_rt == rt)
73449928Ssklower 			x25_lxfree(lx);
73549928Ssklower 		lcp->lcd_so = so;
73649928Ssklower 		lcp->lcd_upper = 0;
73749928Ssklower 		lcp->lcd_upnext = 0;
73849928Ssklower 		transfer_sockbuf(&lcp->lcd_sb, sbappendrecord, &so->so_snd);
73949928Ssklower 		soisconnected(so);
74049928Ssklower 		return 0;
74149928Ssklower 
74249928Ssklower 	case DATA_TRANSFER:
74349928Ssklower 		/* Add VC to rtentry */
74449928Ssklower 		lcp->lcd_so = 0;
74549928Ssklower 		lcp->lcd_sb = so->so_snd; /* structure copy */
74649928Ssklower 		bzero((caddr_t)&so->so_snd, sizeof(so->so_snd)); /* XXXXXX */
74749928Ssklower 		so->so_pcb = 0;
74849928Ssklower 		x25_rtattach(lcp, rt);
74949928Ssklower 		transfer_sockbuf(&so->so_rcv, x25_ifinput, lcp);
75049928Ssklower 		soisdisconnected(so);
75149928Ssklower 	}
75249928Ssklower 	return 0;
75349928Ssklower }
x25_rtattach(lcp0,rt)75449928Ssklower x25_rtattach(lcp0, rt)
75549928Ssklower register struct pklcd *lcp0;
75649928Ssklower struct rtentry *rt;
75749928Ssklower {
75849928Ssklower 	register struct llinfo_x25 *lx = (struct llinfo_x25 *)rt->rt_llinfo;
75949928Ssklower 	register struct pklcd *lcp;
76049928Ssklower 	register struct mbuf *m;
76149727Ssklower 	if (lcp = lx->lx_lcd) { /* adding an additional VC */
76249727Ssklower 		if (lcp->lcd_state == READY) {
76349928Ssklower 			transfer_sockbuf(&lcp->lcd_sb, pk_output, lcp0);
76449727Ssklower 			lcp->lcd_upper = 0;
76549727Ssklower 			pk_close(lcp);
76649727Ssklower 		} else {
76749727Ssklower 			lx = x25_lxalloc(rt);
76849727Ssklower 			if (lx == 0)
76949727Ssklower 				return ENOBUFS;
77049727Ssklower 		}
77149727Ssklower 	}
77249928Ssklower 	lx->lx_lcd = lcp = lcp0;
77349727Ssklower 	lcp->lcd_upper = x25_ifinput;
77449727Ssklower 	lcp->lcd_upnext = (caddr_t)lx;
77549727Ssklower }
776