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