xref: /original-bsd/sys/netccitt/if_x25subr.c (revision 8ed7e0f3)
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.11 (Berkeley) 05/16/91
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 struct llinfo_x25 llinfo_x25 = {&llinfo_x25, &llinfo_x25};
51 int x25_autoconnect = 0;
52 
53 #define senderr(x) {error = x; goto bad;}
54 /*
55  * Ancillary routines
56  */
57 static struct llinfo_x25 *
58 x25_lxalloc(rt)
59 register struct rtentry *rt;
60 {
61 	register struct llinfo_x25 *lx;
62 	register struct sockaddr *dst = rt_key(rt);
63 	register struct ifaddr *ifa;
64 
65 	MALLOC(lx, struct llinfo_x25 *, sizeof (*lx), M_PCB, M_NOWAIT);
66 	if (lx == 0)
67 		return lx;
68 	Bzero(lx, sizeof(*lx));
69 	lx->lx_rt = rt;
70 	lx->lx_family = dst->sa_family;
71 	rt->rt_refcnt++;
72 	if (rt->rt_llinfo)
73 		insque(lx, (struct llinfo_x25 *)rt->rt_llinfo);
74 	else {
75 		rt->rt_llinfo = (caddr_t)lx;
76 		insque(lx, &llinfo_x25);
77 	}
78 	for (ifa = rt->rt_ifp->if_addrlist; ifa; ifa = ifa->ifa_next) {
79 		if (ifa->ifa_addr->sa_family == AF_CCITT)
80 			lx->lx_ia = (struct x25_ifaddr *)ifa;
81 	}
82 	return lx;
83 }
84 x25_lxfree(lx)
85 register struct llinfo_x25 *lx;
86 {
87 	register struct rtentry *rt = lx->lx_rt;
88 	register struct pklcd *lcp = lx->lx_lcd;
89 
90 	if (lcp) {
91 		lcp->lcd_upper = 0;
92 		pk_disconnect(lcp);
93 	}
94 	if ((rt->rt_llinfo == (caddr_t)lx) && (lx->lx_next->lx_rt == rt))
95 		rt->rt_llinfo = (caddr_t)lx->lx_next;
96 	else
97 		rt->rt_llinfo = 0;
98 	RTFREE(rt);
99 	remque(lx);
100 	FREE(lx, M_PCB);
101 }
102 /*
103  * Process a x25 packet as datagram;
104  */
105 x25_ifinput(lcp, m)
106 struct pklcd *lcp;
107 register struct mbuf *m;
108 {
109 	struct llinfo_x25 *lx = (struct llinfo_x25 *)lcp->lcd_upnext;
110 	register struct ifnet *ifp;
111 	struct ifqueue *inq;
112 	extern struct timeval time;
113 	int s, len, isr;
114 
115 	if (m == 0 || lcp->lcd_state != DATA_TRANSFER) {
116 		x25_connect_callback(lcp, 0);
117 		return;
118 	}
119 	ifp = m->m_pkthdr.rcvif;
120 	ifp->if_lastchange = time;
121 	switch (m->m_type) {
122 	case MT_OOBDATA:
123 		if (m)
124 			m_freem(m);
125 	default:
126 		return;
127 
128 	case MT_DATA:
129 		/* FALLTHROUGH */;
130 	}
131 	switch (lx->lx_family) {
132 #ifdef INET
133 	case AF_INET:
134 		isr = NETISR_IP;
135 		inq = &ipintrq;
136 		break;
137 
138 #endif
139 #ifdef NS
140 	case AF_NS:
141 		isr = NETISR_NS;
142 		inq = &nsintrq;
143 		break;
144 
145 #endif
146 #ifdef	ISO
147 	case AF_ISO:
148 		isr = NETISR_ISO;
149 		inq = &clnlintrq;
150 		break;
151 #endif
152 	default:
153 		m_freem(m);
154 		ifp->if_noproto++;
155 		return;
156 	}
157 	s = splimp();
158 	schednetisr(isr);
159 	if (IF_QFULL(inq)) {
160 		IF_DROP(inq);
161 		m_freem(m);
162 	} else {
163 		IF_ENQUEUE(inq, m);
164 		ifp->if_ibytes += m->m_pkthdr.len;
165 	}
166 	splx(s);
167 }
168 x25_connect_callback(lcp, m)
169 register struct pklcd *lcp;
170 register struct mbuf *m;
171 {
172 	register struct llinfo_x25 *lx = (struct llinfo_x25 *)lcp->lcd_upnext;
173 	if (m == 0)
174 		goto refused;
175 	if (m->m_type != MT_CONTROL) {
176 		printf("x25_connect_callback: should panic\n");
177 		goto refused;
178 	}
179 	switch (pk_decode(mtod(m, struct x25_packet *))) {
180 	case CALL_ACCEPTED:
181 		lcp->lcd_upper = x25_ifinput;
182 		if (lcp->lcd_sb.sb_mb)
183 			lcp->lcd_send(lcp); /* XXX start queued packets */
184 		return;
185 	default:
186 	refused:
187 		lcp->lcd_upper = 0;
188 		lx->lx_lcd = 0;
189 		pk_disconnect(lcp);
190 		return;
191 	}
192 }
193 /*
194  * X.25 output routine.
195  */
196 x25_ifoutput(ifp, m0, dst, rt)
197 struct	ifnet *ifp;
198 struct	mbuf *m0;
199 struct	sockaddr *dst;
200 register struct	rtentry *rt;
201 {
202 	register struct	mbuf *m;
203 	register struct	llinfo_x25 *lx;
204 	struct pklcd *lcp;
205 	int             s, error = 0;
206 
207 	if ((ifp->if_flags & IFF_UP) == 0)
208 		senderr(ENETDOWN);
209 	while (rt == 0 || (rt->rt_flags & RTF_GATEWAY)) {
210 		if (rt) {
211 			if (rt->rt_llinfo) {
212 				rt = (struct rtentry *)rt->rt_llinfo;
213 				continue;
214 			}
215 			dst = rt->rt_gateway;
216 		}
217 		if ((rt = rtalloc1(dst, 1)) == 0)
218 			senderr(EHOSTUNREACH);
219 		rt->rt_refcnt--;
220 	}
221 	/*
222 	 * Sanity checks.
223 	 */
224 	if ((rt->rt_ifp != ifp) ||
225 	    (rt->rt_flags & (RTF_CLONING | RTF_GATEWAY)) ||
226 	    ((lx = (struct llinfo_x25 *)rt->rt_llinfo) == 0)) {
227 		senderr(ENETUNREACH);
228 	}
229 next_circuit:
230 	lcp = lx->lx_lcd;
231 	if (lcp == 0) {
232 		lx->lx_lcd = lcp = pk_attach((struct socket *)0);
233 		if (lcp == 0)
234 			senderr(ENOBUFS);
235 		lcp->lcd_upper = x25_connect_callback;
236 		lcp->lcd_upnext = (caddr_t)lx;
237 		lcp->lcd_packetsize = lx->lx_ia->ia_xc.xc_psize;
238 	}
239 	switch (lcp->lcd_state) {
240 	case READY:
241 		if (dst->sa_family == AF_INET &&
242 		    ifp->if_type == IFT_X25DDN &&
243 		    rt->rt_gateway->sa_family != AF_CCITT)
244 			x25_ddnip_to_ccitt(dst, rt);
245 		if (rt->rt_gateway->sa_family != AF_CCITT) {
246 			if ((rt->rt_flags & RTF_XRESOLVE) == 0)
247 				senderr(EHOSTUNREACH);
248 		} else if (x25_autoconnect)
249 			error = pk_connect(lcp,
250 					(struct sockaddr_x25 *)rt->rt_gateway);
251 		if (error)
252 			senderr(error);
253 		/* FALLTHROUGH */
254 	case SENT_CALL:
255 	case DATA_TRANSFER:
256 		if (sbspace(&lcp->lcd_sb) < 0) {
257 			lx = lx->lx_next;
258 			if (lx->lx_rt != rt)
259 				senderr(ENOSPC);
260 			goto next_circuit;
261 		}
262 		if (lx->lx_ia)
263 			lcp->lcd_dg_timer =
264 				       lx->lx_ia->ia_xc.xc_dg_idletimo;
265 		pk_send(lcp, m);
266 		break;
267 	default:
268 		/*
269 		 * We count on the timer routine to close idle
270 		 * connections, if there are not enough circuits to go
271 		 * around.
272 		 *
273 		 * So throw away data for now.
274 		 * After we get it all working, we'll rewrite to handle
275 		 * actively closing connections (other than by timers),
276 		 * when circuits get tight.
277 		 *
278 		 * In the DDN case, the imp itself closes connections
279 		 * under heavy load.
280 		 */
281 		error = ENOBUFS;
282 	bad:
283 		if (m)
284 			m_freem(m);
285 	}
286 	return (error);
287 }
288 
289 /*
290  * Simpleminded timer routine.
291  */
292 x25_iftimeout(ifp)
293 struct ifnet *ifp;
294 {
295 	register struct pkcb *pkcb = 0;
296 	register struct ifaddr *ifa;
297 	register struct pklcd **lcpp, *lcp;
298 	int s = splimp();
299 
300 	for (ifa = ifp->if_addrlist; ifa && !pkcb; ifa = ifa->ifa_next) {
301 		if (ifa->ifa_addr->sa_family == AF_CCITT)
302 			pkcb = &((struct x25_ifaddr *)ifa)->ia_pkcb;
303 	}
304 	if (pkcb)
305 		for (lcpp = pkcb->pk_chan + pkcb->pk_maxlcn;
306 		     --lcpp > pkcb->pk_chan;)
307 			if ((lcp = *lcpp) &&
308 			    lcp->lcd_state == DATA_TRANSFER &&
309 			    (lcp->lcd_flags & X25_DG_CIRCUIT) &&
310 			    (lcp->lcd_dg_timer && --lcp->lcd_dg_timer == 0)) {
311 				lcp->lcd_upper(lcp, 0);
312 			}
313 	splx(s);
314 }
315 /*
316  * This routine gets called when validating additions of new routes
317  * or deletions of old ones.
318  */
319 x25_ifrtchange(cmd, rt, dst)
320 register struct rtentry *rt;
321 struct sockaddr *dst;
322 {
323 	register struct llinfo_x25 *lx = (struct llinfo_x25 *)rt->rt_llinfo;
324 	register struct sockaddr_x25 *sa =(struct sockaddr_x25 *)rt->rt_gateway;
325 	register struct pklcd *lcp;
326 #define SA(p) ((struct sockaddr *)(p))
327 
328 	if (rt->rt_flags & RTF_GATEWAY) {
329 		if (rt->rt_llinfo)
330 			RTFREE((struct rtentry *)rt->rt_llinfo);
331 		rt->rt_llinfo = (cmd == RTM_ADD) ?
332 			(caddr_t)rtalloc1(rt->rt_gateway, 1) : 0;
333 		return;
334 	}
335 	if ((rt->rt_flags & RTF_HOST) == 0)
336 		return;
337 	if (cmd == RTM_DELETE) {
338 		while (rt->rt_llinfo)
339 			x25_lxfree((struct llinfo *)rt->rt_llinfo);
340 		x25_rtinvert(RTM_DELETE, rt->rt_gateway, rt);
341 		return;
342 	}
343 	if (lx == 0 && (lx = x25_lxalloc(rt)) == 0)
344 		return;
345 	if ((lcp = lx->lx_lcd) && lcp->lcd_state != READY) {
346 		/*
347 		 * This can only happen on a RTM_CHANGE operation
348 		 * though cmd will be RTM_ADD.
349 		 */
350 		if (lcp->lcd_ceaddr &&
351 		    Bcmp(rt->rt_gateway, lcp->lcd_ceaddr,
352 					 lcp->lcd_ceaddr->x25_len) != 0) {
353 			x25_rtinvert(RTM_DELETE, lcp->lcd_ceaddr, rt);
354 			lcp->lcd_upper = 0;
355 			pk_disconnect(lcp);
356 		}
357 		lcp = 0;
358 	}
359 	x25_rtinvert(RTM_ADD, rt->rt_gateway, rt);
360 }
361 
362 int x25_dont_rtinvert = 1;
363 
364 x25_rtinvert(cmd, sa, rt)
365 register struct sockaddr *sa;
366 register struct rtentry *rt;
367 {
368 	struct rtentry *rt2 = 0;
369 	/*
370 	 * rt_gateway contains PID indicating which proto
371 	 * family on the other end, so will be different
372 	 * from general host route via X.25.
373 	 */
374 	if (x25_dont_rtinvert)
375 		return;
376 	if (rt->rt_ifp->if_type == IFT_X25DDN)
377 		return;
378 	if (sa->sa_family != AF_CCITT)
379 		return;
380 	if (cmd == RTM_ADD) {
381 		rtrequest(RTM_ADD, sa, rt_key(rt), SA(0),
382 				RTF_HOST|RTF_PROTO1, &rt2);
383 		if (rt2) {
384 			rt2->rt_llinfo = (caddr_t) rt;
385 			rt->rt_refcnt++;
386 		}
387 		return;
388 	}
389 	rt2 = rt;
390 	if ((rt = rtalloc1(sa, 0)) == 0 ||
391 	    (rt->rt_flags & RTF_PROTO1) == 0 ||
392 	    rt->rt_llinfo != (caddr_t)rt) {
393 		printf("x25_rtchange: inverse route screwup\n");
394 		return;
395 	} else
396 		rt2->rt_refcnt--;
397 	rtrequest(RTM_DELETE, rt->rt_gateway, rt_key(rt),
398 		SA(0), 0, (struct rtentry **) 0);
399 }
400 
401 static struct sockaddr_x25 blank_x25 = {sizeof blank_x25, AF_CCITT};
402 /*
403  * IP to X25 address routine copyright ACC, used by permission.
404  */
405 union imp_addr {
406 	struct in_addr  ip;
407 	struct imp {
408 		u_char		s_net;
409 		u_char		s_host;
410 		u_char		s_lh;
411 		u_char		s_impno;
412 	}		    imp;
413 };
414 
415 /*
416  * The following is totally bogus and here only to preserve
417  * the IP to X.25 translation.
418  */
419 x25_ddnip_to_ccitt(src, rt)
420 struct sockaddr_in *src;
421 register struct rtentry *rt;
422 {
423 	register struct sockaddr_x25 *dst = (struct sockaddr_x25 *)rt->rt_gateway;
424 	union imp_addr imp_addr;
425 	int             imp_no, imp_port, temp;
426 	char *x25addr = dst->x25_addr;
427 
428 
429 	imp_addr.ip = src->sin_addr;
430 	*dst = blank_x25;
431 	if ((imp_addr.imp.s_net & 0x80) == 0x00) {	/* class A */
432 	    imp_no = imp_addr.imp.s_impno;
433 	    imp_port = imp_addr.imp.s_host;
434 	} else if ((imp_addr.imp.s_net & 0xc0) == 0x80) {	/* class B */
435 	    imp_no = imp_addr.imp.s_impno;
436 	    imp_port = imp_addr.imp.s_lh;
437 	} else {		/* class C */
438 	    imp_no = imp_addr.imp.s_impno / 32;
439 	    imp_port = imp_addr.imp.s_impno % 32;
440 	}
441 
442 	x25addr[0] = 12; /* length */
443 	/* DNIC is cleared by struct copy above */
444 
445 	if (imp_port < 64) {	/* Physical:  0000 0 IIIHH00 [SS] *//* s_impno
446 				 *  -> III, s_host -> HH */
447 	    x25addr[5] = 0;	/* set flag bit */
448 	    x25addr[6] = imp_no / 100;
449 	    x25addr[7] = (imp_no % 100) / 10;
450 	    x25addr[8] = imp_no % 10;
451 	    x25addr[9] = imp_port / 10;
452 	    x25addr[10] = imp_port % 10;
453 	} else {		/* Logical:   0000 1 RRRRR00 [SS]	 *//* s
454 				 * _host * 256 + s_impno -> RRRRR */
455 	    temp = (imp_port << 8) + imp_no;
456 	    x25addr[5] = 1;
457 	    x25addr[6] = temp / 10000;
458 	    x25addr[7] = (temp % 10000) / 1000;
459 	    x25addr[8] = (temp % 1000) / 100;
460 	    x25addr[9] = (temp % 100) / 10;
461 	    x25addr[10] = temp % 10;
462 	}
463 }
464 
465 /*
466  * This routine is a sketch and is not to be believed!!!!!
467  *
468  * This is a utility routine to be called by x25 devices when a
469  * call request is honored with the intent of starting datagram forwarding.
470  */
471 x25_dg_rtinit(dst, ia, af)
472 struct sockaddr_x25 *dst;
473 register struct x25_ifaddr *ia;
474 {
475 	struct sockaddr *sa = 0;
476 	struct rtentry *rt;
477 	struct in_addr my_addr;
478 	static struct sockaddr_in sin = {sizeof(sin), AF_INET};
479 
480 	if (ia->ia_ifp->if_type == IFT_X25DDN && af == AF_INET) {
481 	/*
482 	 * Inverse X25 to IP mapping copyright and courtesy ACC.
483 	 */
484 		int             imp_no, imp_port, temp;
485 		union imp_addr imp_addr;
486 	    {
487 		/*
488 		 * First determine our IP addr for network
489 		 */
490 		register struct in_ifaddr *ina;
491 		extern struct in_ifaddr *in_ifaddr;
492 
493 		for (ina = in_ifaddr; ina; ina = ina->ia_next)
494 			if (ina->ia_ifp == ia->ia_ifp) {
495 				my_addr = ina->ia_addr.sin_addr;
496 				break;
497 			}
498 	    }
499 	    {
500 
501 		register char *x25addr = dst->x25_addr;
502 
503 		switch (x25addr[5] & 0x0f) {
504 		  case 0:	/* Physical:  0000 0 IIIHH00 [SS]	 */
505 		    imp_no =
506 			((int) (x25addr[6] & 0x0f) * 100) +
507 			((int) (x25addr[7] & 0x0f) * 10) +
508 			((int) (x25addr[8] & 0x0f));
509 
510 
511 		    imp_port =
512 			((int) (x25addr[9] & 0x0f) * 10) +
513 			((int) (x25addr[10] & 0x0f));
514 		    break;
515 		  case 1:	/* Logical:   0000 1 RRRRR00 [SS]	 */
516 		    temp = ((int) (x25addr[6] & 0x0f) * 10000)
517 			+ ((int) (x25addr[7] & 0x0f) * 1000)
518 			+ ((int) (x25addr[8] & 0x0f) * 100)
519 			+ ((int) (x25addr[9] & 0x0f) * 10)
520 			+ ((int) (x25addr[10] & 0x0f));
521 
522 		    imp_port = temp >> 8;
523 		    imp_no = temp & 0xff;
524 		    break;
525 		  default:
526 		    return (0L);
527 		}
528 		imp_addr.ip = my_addr;
529 		if ((imp_addr.imp.s_net & 0x80) == 0x00) {
530 		/* class A */
531 		    imp_addr.imp.s_host = imp_port;
532 		    imp_addr.imp.s_impno = imp_no;
533 		    imp_addr.imp.s_lh = 0;
534 		} else if ((imp_addr.imp.s_net & 0xc0) == 0x80) {
535 		/* class B */
536 		    imp_addr.imp.s_lh = imp_port;
537 		    imp_addr.imp.s_impno = imp_no;
538 		} else {
539 		/* class C */
540 		    imp_addr.imp.s_impno = (imp_no << 5) + imp_port;
541 		}
542 	    }
543 		sin.sin_addr = imp_addr.ip;
544 		sa = (struct sockaddr *)&sin;
545 	} else {
546 		/*
547 		 * This uses the X25 routing table to do inverse
548 		 * lookup of x25 address to sockaddr.
549 		 */
550 		if (rt = rtalloc1(dst, 0)) {
551 			sa = rt->rt_gateway;
552 			rt->rt_refcnt--;
553 		}
554 	}
555 	/*
556 	 * Call to rtalloc1 will create rtentry for reverse path
557 	 * to callee by virtue of cloning magic and will allocate
558 	 * space for local control block.
559 	 */
560 	if (sa && (rt = rtalloc1(sa, 1)))
561 		rt->rt_refcnt--;
562 }
563 
564 struct radix_tree_head *x25_rnhead;
565 
566 pk_init()
567 {
568 	/*
569 	 * warning, sizeof (struct sockaddr_x25) > 32,
570 	 * but contains no data of interest beyond 32
571 	 */
572 	rn_inithead(&x25_rnhead, 32, AF_CCITT);
573 }
574 /*
575  * This routine steals a virtual circuit from a socket,
576  * and glues it to a routing entry.  It wouldn't be hard
577  * to extend this to a routine that stole back the vc from
578  * rtentry.
579  */
580 pk_rtattach(so, m0)
581 register struct socket *so;
582 struct mbuf *m0;
583 {
584 	register struct pklcd *lcp = (struct pklcd *)so->so_pcb;
585 	register struct mbuf *m = m0;
586 	struct sockaddr *dst = mtod(m, struct sockaddr *);
587 	register struct rtentry *rt = rtalloc1(dst, 0);
588 	register struct llinfo_x25 *lx;
589 	caddr_t cp;
590 #define ROUNDUP(a) \
591 	((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
592 #define transfer_sockbuf(s, f, l) \
593 	while (m = (s)->sb_mb) {(s)->sb_mb = m->m_act; sbfree((s), m); f(l, m);}
594 
595 	if (rt)
596 		rt->rt_refcnt--;
597 	cp = (dst->sa_len < m->m_len) ? ROUNDUP(dst->sa_len) + (caddr_t)dst : 0;
598 	while (rt &&
599 	       ((cp == 0 && rt_mask(rt) != 0) ||
600 		(cp != 0 && (rt_mask(rt) == 0 ||
601 			     Bcmp(cp, rt_mask(rt), rt_mask(rt)->sa_len)) != 0)))
602 			rt = (struct rtentry *)rt->rt_nodes->rn_dupedkey;
603 	if (rt == 0 || (rt->rt_flags & RTF_GATEWAY) ||
604 	    (lx = (struct llinfo_x25 *)rt->rt_llinfo) == 0)
605 		return ESRCH;
606 	if (lcp == 0 || lcp->lcd_state != DATA_TRANSFER)
607 		return ENOTCONN;
608 	if (lcp = lx->lx_lcd) { /* adding an additional VC */
609 		if (lcp->lcd_state == READY) {
610 			transfer_sockbuf(&lcp->lcd_sb, pk_output,
611 					 (struct pklcd *)so->so_pcb);
612 			lcp->lcd_upper = 0;
613 			pk_close(lcp);
614 		} else {
615 			lx = x25_lxalloc(rt);
616 			if (lx == 0)
617 				return ENOBUFS;
618 		}
619 	}
620 	lx->lx_lcd = lcp = (struct pklcd *)so->so_pcb;
621 	lcp->lcd_so = 0;
622 	lcp->lcd_sb = so->so_snd; /* structure copy */
623 	lcp->lcd_upper = x25_ifinput;
624 	lcp->lcd_upnext = (caddr_t)lx;
625 	transfer_sockbuf(&so->so_rcv, x25_ifinput, lcp);
626 	so->so_pcb = 0;
627 	bzero((caddr_t)&so->so_snd, sizeof(so->so_snd)); /* XXXXXX */
628 	soisdisconnected(so);
629 	return (0);
630 }
631