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