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