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