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