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