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