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