xref: /csrg-svn/sys/netccitt/if_x25subr.c (revision 42277)
1 /*
2  * Copyright (c) 1990 The Regents of the University of California.
3  * All rights reserved.
4  *
5  * %sccs.include.redist.c%
6  *
7  *	@(#)if_x25subr.c	7.4 (Berkeley) 05/22/90
8  */
9 
10 #include "param.h"
11 #include "systm.h"
12 #include "malloc.h"
13 #include "mbuf.h"
14 #include "protosw.h"
15 #include "socket.h"
16 #include "ioctl.h"
17 #include "errno.h"
18 #include "syslog.h"
19 
20 #include "../net/if.h"
21 #include "../net/netisr.h"
22 #include "../net/route.h"
23 
24 #include "x25.h"
25 #include "x25error.h"
26 #include "pk_var.h"
27 
28 #include "machine/mtpr.h"
29 
30 #ifdef INET
31 #include "../netinet/in.h"
32 #include "../netinet/in_var.h"
33 #endif
34 
35 #ifdef NS
36 #include "../netns/ns.h"
37 #include "../netns/ns_if.h"
38 #endif
39 
40 #ifdef ISO
41 #include "../netiso/argo_debug.h"
42 #include "../netiso/iso.h"
43 #include "../netiso/iso_var.h"
44 #endif
45 
46 extern	struct ifnet loif;
47 
48 #define senderr(x) {error = x; goto bad;}
49 /*
50  * X.25 output routine.
51  */
52 x25_ifoutput(ifp, m0, dst, rt)
53 struct	ifnet *ifp;
54 struct	mbuf *m0;
55 struct	sockaddr *dst;
56 register struct	rtentry *rt;
57 {
58 	register struct mbuf *m;
59 	register struct rtextension_x25 *rtx;
60 	register struct pq *pq;
61 	struct pklcd *lcp;
62 	struct x25_ifaddr *ia;
63 	struct mbuf    *prev;
64 	int             s, error = 0, flags = 0;
65 	union imp_addr  imp_addr;
66 	int flags = 0;
67 
68 	if ((ifp->if_flags & IFF_UP) == 0)
69 		return (ENETDOWN);
70 	if (rt == 0 ||
71 	    ((rt->rt_flags & RTF_GATEWAY) && (dst = rt->rt_gateway))) {
72 		if ((rt = rtalloc1(dst, 1)) == 0)
73 			return (EHOSTUNREACH);
74 		rt->rt_refcnt++;
75 		flags = XRF_RTHELD;
76 	}
77 	/*
78 	 * Sanity checks.
79 	 */
80 	if ((rt->rt_ifp != ifp) ||
81 	    (rt->rt_flags & (RTF_CLONING | RTF_GATEWAY)) ||
82 	    ((rtx = (struct rtextension_x25 *)rt->rt_llinfo) == 0)) {
83 		printf("Inconsistent call to x25_output, should panic\n");
84 		senderr(ENETUNREACH);
85 	}
86     {
87 	register struct ifaddr *ifa;
88 	for (ifa = ifp->if_addrlist; ; ifa = ifa->ifa_next) {
89 		if (ifa == 0)
90 			senderr(ENETDOWN);
91 		if (ifa->ifa_addr->sa_family == AF_CCITT)
92 			break;
93 	}
94 	ia = (struct x25_ifaddr *)ifa;
95     }
96 	if (rtx->rtx_lcd == 0) {
97 		int x25_ifinput();
98 
99 		lcp = pk_attach((struct socket *)0);
100 		if (lcp == 0)
101 			senderr(ENOBUFS);
102 		rtx->rtx_lcd = lcp;
103 		rtx->rtx_rt = rt;
104 		rtx->rtx_ia = ia;
105 		lcp->lcd_upq.pq_next = (caddr_t)rtx;
106 		lcp->lcd_upq.pq_put = x25_ifinput;
107 	}
108 	pq = &lcp->lcd_downq;
109 	switch (rtx->rtx_state) {
110 
111 	case XRS_CONNECTED:
112 		lcd->lcd_dg_timer = ia->ia_xc.xc_dg_idletimo;
113 		/* FALLTHROUGH */
114 	case XRS_CONNECTING:
115 		if (pq->pq_space < 0)
116 			senderr(ENOBUFS);
117 		pq->pq_put(pq, m);
118 		break;
119 
120 	case XRS_NEWBORN:
121 		if (dst->sa_family == AF_INET &&
122 		    ia->xc_if.if_type == IFT_DDN &&
123 		    rt->rt_gateway->sa_family != AF_CCITT)
124 			x25_ddnip_to_ccitt(dst, rt->rt_gateway);
125 		pq->pq_space = 2048;  /* XXX: bogus pq before if_start called */
126 		lcp->lcd_flags |= X25_DG_CIRCUIT;
127 		rtx->rtx_state = XRS_FREE;
128 		if (rt->rt_gateway->sa_family != AF_CCITT) {
129 			/*
130 			 * Need external resolution of dst
131 			 */
132 			if ((rt->rt_flags & RTF_XRESOLVE) == 0)
133 				senderr(ENETUNREACH);
134 			rtx->rtx_flags |= flags;
135 			flags = 0;
136 			rt_missmsg(RTM_RESOLVE, dst,
137 			    (struct sockaddr *)0, (struct sockaddr *)0,
138 			    (struct sockaddr *)0, 0, 0);
139 			rtx->rtx_state = XRS_RESOLVING;
140 			/* FALLTHROUGH */
141 	case XRS_RESOLVING:
142 			if (pq->pq_space < 0)
143 				senderr(ENOBUFS);
144 			pq->pq_space -= m->m_pkthdr.len;
145 			if (pq->pq_data == 0)
146 				pq->pq_data = m;
147 			else {
148 				for (m = pq->pq_data; m->m_nextpkt; )
149 					m = m->m_nextpkt;
150 				m->m_nextpkt = m0;
151 			}
152 			break;
153 		}
154 		/* FALLTHROUGH */
155 	case XRS_FREE:
156 		lcp->lcd_downq.pq_data = m;
157 		lcp->lcd_pkcb = &(rtx->rtx_ia->ia_pkcb);
158 		pk_connect(lcp, (struct mbuf *)0,
159 				(struct sockaddr_x25 *)rt->rt_gateway);
160 		break;
161 		/* FALLTHROUGH */
162 	default:
163 		/*
164 		 * We count on the timer routine to close idle
165 		 * connections, if there are not enough circuits to go
166 		 * around.
167 		 *
168 		 * So throw away data for now.
169 		 * After we get it all working, we'll rewrite to handle
170 		 * actively closing connections (other than by timers),
171 		 * when circuits get tight.
172 		 *
173 		 * In the DDN case, the imp itself closes connections
174 		 * under heavy load.
175 		 */
176 		error = ENOBUFS;
177 	bad:
178 		if (m)
179 			m_freem(m);
180 	}
181 out:
182 	if (flags & XRF_RTHELD)
183 		RTFREE(rt);
184 	return (error);
185 }
186 
187 /*
188  * Simpleminded timer routine.
189  */
190 x25_iftimeout(ifp)
191 struct ifnet *ifp;
192 {
193 	register struct pkcb *pkcb = 0;
194 	register struct ifaddr *ifa;
195 	register struct pklcd **lcpp, *lcp;
196 	int s = splimp();
197 
198 	for (ifa = ifp->if_addrlist; ; ifa = ifa->ifa_next) {
199 		if (ifa->ifa_addr->sa_family == AF_CCITT)
200 			break;
201 	}
202 	if (ifa)
203 		pkcb = &((struct x25_ifaddr *)ifa)->ia_pkcb;
204 	if (pkcb)
205 		for (lcpp = pkcb->pk_chan + pkcb->pk_maxlcn;
206 		     --lcpp >= pkcb->pk_chan;)
207 			if ((lcp = *lcpp) &&
208 			    lcp->lcd_state == DATA_TRANSFER &&
209 			    (lcp->lcd_flags & X25_DG_CICRUIT) &&
210 			    (--(lcp->lcd_dg_timer) <= 0)) {
211 				register struct rtextension_x25 *rtx;
212 				pk_disconnect(lcp);
213 				rtx = (struct rtextension_x25 *)
214 						lcp->lcp_upq.pq_next;
215 				if (rtx)
216 					rtx->rtx_state = XRS_DISCONNECTING;
217 			    }
218 	splx(s);
219 }
220 
221 /*
222  * Process a x25 packet as datagram;
223  */
224 x25_ifinput(pq, m)
225 struct pq *pq;
226 struct mbuf *m;
227 {
228 	struct rtentry *rt = (struct rtentry *)pq->pq_next;
229 	struct pklcd *xl = (struct pklcd *)rt->rt_llinfo;
230 	register struct ifnet *ifp = &xl->xl_xc.xc_if;
231 	register struct llc *l;
232 	int s;
233 
234 	ifp->if_lastchange = time;
235 
236 	switch (rt_dst(rt)->sa_family) {
237 #ifdef INET
238 	case AF_INET:
239 		schednetisr(NETISR_IP);
240 		inq = &ipintrq;
241 		break;
242 
243 #endif
244 #ifdef NS
245 	case AF_NS:
246 		schednetisr(NETISR_NS);
247 		inq = &nsintrq;
248 		break;
249 
250 #endif
251 #ifdef	ISO
252 	case AF_ISO:
253 		/* XXXX need to find out about tearing off COSNS
254 		   headers if any */
255 		schednetisr(NETISR_ISO);
256 		inq = &clnlintrq;
257 		break;
258 #endif
259 	default:
260 		m_freem(m);
261 		ifp->if_noproto++;
262 		return;
263 	}
264 	s = splimp();
265 	if (IF_QFULL(inq)) {
266 		IF_DROP(inq);
267 		m_freem(m);
268 	} else {
269 		IF_ENQUEUE(inq, m);
270 		ifp->if_ibytes += m->m_pkthdr.len;
271 	}
272 	splx(s);
273 }
274 
275 union imp_addr {
276 	struct in_addr  ip;
277 	struct imp {
278 		u_char		s_net;
279 		u_char		s_host;
280 		u_char		s_lh;
281 		u_char		s_impno;
282 	}		    imp;
283 };
284 static struct sockaddr_x25 blank_x25 = {sizeof blank_x25, AF_CCITT};
285 /*
286  * IP to X25 address routine copyright ACC, used by permission.
287  */
288 x25_ddnip_to_ccitt(src, dst)
289 struct sockaddr_in *src;
290 register struct sockaddr_x25 *dst;
291 {
292 	union imp_addr imp_addr;
293 	int             imp_no, imp_port;
294 	char *x25addr = dst->x25_x25addr;
295 
296 
297 	imp_addr.ip = src->sin_addr.s_addr;
298 	*dst = blank_x25;
299 	if ((imp_addr.imp.s_net & 0x80) == 0x00) {	/* class A */
300 	    imp_no = imp_addr.imp.s_impno;
301 	    imp_port = imp_addr.imp.s_host;
302 	} else if ((imp_addr.imp.s_net & 0xc0) == 0x80) {	/* class B */
303 	    imp_no = imp_addr.imp.s_impno;
304 	    imp_port = imp_addr.imp.s_lh;
305 	} else {		/* class C */
306 	    imp_no = imp_addr.imp.s_impno / 32;
307 	    imp_port = imp_addr.imp.s_impno % 32;
308 	}
309 
310 	x25addr[0] = 12; /* length */
311 	/* DNIC is cleared by struct copy above */
312 
313 	if (imp_port < 64) {	/* Physical:  0000 0 IIIHH00 [SS] *//* s_impno
314 				 *  -> III, s_host -> HH */
315 	    x25addr[5] = 0;	/* set flag bit */
316 	    x25addr[6] = imp_no / 100;
317 	    x25addr[7] = (imp_no % 100) / 10;
318 	    x25addr[8] = imp_no % 10;
319 	    x25addr[9] = imp_port / 10;
320 	    x25addr[10] = imp_port % 10;
321 	} else {		/* Logical:   0000 1 RRRRR00 [SS]	 *//* s
322 				 * _host * 256 + s_impno -> RRRRR */
323 	    temp = (imp_port << 8) + imp_no;
324 	    x25addr[5] = 1;
325 	    x25addr[6] = temp / 10000;
326 	    x25addr[7] = (temp % 10000) / 1000;
327 	    x25addr[8] = (temp % 1000) / 100;
328 	    x25addr[9] = (temp % 100) / 10;
329 	    x25addr[10] = temp % 10;
330 	}
331 }
332 
333 #ifdef caseof
334 #undef caseof
335 #endif
336 #define caseof(a, b) (b + 8 * a)
337 #define SA(p) ((struct sockaddr *)(p))
338 
339 /*
340  * This routine gets called when validing new routes or deletions of old
341  * ones.
342  */
343 x25_ifrtchange(cmd, rt, dst)
344 register struct rtentry *rt;
345 struct sockaddr *dst;
346 {
347 	register struct rtextension_x25 *rtx = (struct pklcd *)rt->rt_llinfo;
348 	register struct sockaddr_x25 *sa =(struct sockaddr_x25 *)rt->rt_gateway;
349 	register struct pklcd *lcp;
350 	register struct x25_ifaddr *ia;
351 	register struct sockaddr *sa2;
352 	struct mbuf *m, *mold;
353 	int x25_ifrtree();
354 
355 	if (rtx == 0)
356 		return;
357 	ia = rtx->rtx_ia;
358 	lcp = rtx->rtx_lcd;
359 
360 	switch (caseof(xl->xl_state, cmd)) {
361 
362 	case caseof(XRS_CONNECTED, RTM_DELETE):
363 	case caseof(XRS_CONNECTED, RTM_CHANGE):
364 	case caseof(XRS_CONNECTING, RTM_DELETE):
365 	case caseof(XRS_CONNECTING, RTM_CHANGE):
366 		pk_disconnect(lcp);
367 		lcp->lcd_upq.pq_unblock = x25_ifrtfree;
368 		rt->rt_refcnt++;
369 		break;
370 
371 	case caseof(XRS_CONNECTED, RTM_ADD):
372 	case caseof(XRS_CONNECTING, RTM_ADD):
373 	case caseof(XRS_RESOLVING, RTM_ADD):
374 		printf("ifrtchange: impossible transition, should panic\n");
375 		break;
376 
377 	case caseof(XRS_RESOLVING, RTM_DELETE):
378 		for (m = lcp->lcd_downq.pq_data; m;) {
379 			mold = m;
380 			m = m->m_nextpkt;
381 			m_freem(mold);
382 		}
383 		m_free(dtom(rtx->rtx_lcd));
384 		rtx->rtx_lcd = 0;
385 		break;
386 
387 	case caseof(XRS_RESOLVING, RTM_CHANGE):
388 		lcp->lcd_pkcb = &(ia->ia_pkcb);
389 		pk_connect(lcp, (struct mbuf *)0, sa);
390 		break;
391 	}
392 	if (rt->rt_ifp->if_type == IFT_DDN)
393 		return;
394 	sa2 = SA(rt->rt_key);
395 	if (cmd == RTM_CHANGE) {
396 		if (sa->sa_family == AF_CCITT) {
397 			sa->sa_rfamily = sa2->sa_family;
398 			(void) rtrequest(RTM_DELETE, SA(sa), sa2,
399 			       SA(0), RTF_HOST, (struct rtentry **)0);
400 		}
401 		sa = (struct sockaddr_x25 *)dst;
402 		cmd = RTM_ADD;
403 	}
404 	if (sa->sa_family == AF_CCITT) {
405 		sa->sa_rfamily = sa2->sa_family;
406 		(void) rtrequest(cmd, SA(sa), sa2, SA(0), RTF_HOST,
407 							(struct rtentry **)0);
408 		sa->sa_rfamily = 0;
409 	}
410 }
411 static struct sockaddr sin = {sizeof(sin), AF_INET};
412 /*
413  * This is a utility routine to be called by x25 devices when a
414  * call request is honored with the intent of starting datagram forwarding.
415  */
416 x25_dg_rtinit(dst, ia, af)
417 struct sockaddr_x25 *dst;
418 register struct x25com *ia;
419 {
420 	struct sockaddr *sa = 0;
421 	if (ia->xc_if.if_type == IFT_DDN && af == AF_INET) {
422 	/*
423 	 * Inverse X25 to IPP mapping copyright and courtesy ACC.
424 	 */
425 		int             imp_no, imp_port, temp;
426 		union imp_addr imp_addr;
427 	    {
428 		/*
429 		 * First determine our IP addr for network
430 		 */
431 		register struct in_ifaddr *ia;
432 		extern struct in_ifaddr *in_ifaddr;
433 		for (ia = in_ifaddr; ia; ia = ia->ia_next)
434 			if (ia->ia_ifp == &ia->xc_if) {
435 				imp_addr.ip = ia->ia_addr.sin_addr;
436 				break;
437 			}
438 	    }
439 	    {
440 
441 		register char *x25addr = dst->x25_addr;
442 
443 		switch (x25addr[5] & 0x0f) {
444 		  case 0:	/* Physical:  0000 0 IIIHH00 [SS]	 */
445 		    imp_no =
446 			((int) (x25addr[6] & 0x0f) * 100) +
447 			((int) (x25addr[7] & 0x0f) * 10) +
448 			((int) (x25addr[8] & 0x0f));
449 
450 
451 		    imp_port =
452 			((int) (x25addr[9] & 0x0f) * 10) +
453 			((int) (x25addr[10] & 0x0f));
454 		    break;
455 		  case 1:	/* Logical:   0000 1 RRRRR00 [SS]	 */
456 		    temp = ((int) (x25addr[6] & 0x0f) * 10000)
457 			+ ((int) (x25addr[7] & 0x0f) * 1000)
458 			+ ((int) (x25addr[8] & 0x0f) * 100)
459 			+ ((int) (x25addr[9] & 0x0f) * 10)
460 			+ ((int) (x25addr[10] & 0x0f));
461 
462 		    imp_port = temp >> 8;
463 		    imp_no = temp & 0xff;
464 		    break;
465 		  default:
466 		    return (0L);
467 		}
468 		imp_addr.ip.s_addr = my_addr;
469 		if ((imp_addr.imp.s_net & 0x80) == 0x00) {
470 		/* class A */
471 		    imp_addr.imp.s_host = imp_port;
472 		    imp_addr.imp.s_impno = imp_no;
473 		    imp_addr.imp.s_lh = 0;
474 		} else if ((imp_addr.imp.s_net & 0xc0) == 0x80) {
475 		/* class B */
476 		    imp_addr.imp.s_lh = imp_port;
477 		    imp_addr.imp.s_impno = imp_no;
478 		} else {
479 		/* class C */
480 		    imp_addr.imp.s_impno = (imp_no << 5) + imp_port;
481 		}
482 	    }
483 		sin.sin_addr = imp_addr.ip;
484 		sa = (struct sockaddr *)&sin;
485 	} else {
486 		/*
487 		 * This uses the X25 routing table to do inverse
488 		 * lookup of x25 address to sockaddr.
489 		 */
490 		dst->sa_rfamily = af;
491 		if (rt = rtalloc1(dst, 0)) {
492 			sa = rt->rt_gateway;
493 			rt->rt_refcnt--;
494 		}
495 		dst->sa_rfamily = 0;
496 	}
497 	/*
498 	 * Call to rtalloc1 will create rtentry for reverse path
499 	 * to callee by virtue of cloning magic and will allocate
500 	 * space for local control block.
501 	 */
502 	if (sa && rt = rtalloc1(sa, 1))
503 		rt->rt_refcnt--;
504 }
505