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