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