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