1 /*
2 * Copyright (c) 1990, 1993
3 * The Regents of the University of California. All rights reserved.
4 *
5 * %sccs.include.redist.c%
6 *
7 * @(#)if_x25subr.c 8.1 (Berkeley) 06/10/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 *
x25_lxalloc(rt)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 }
x25_lxfree(lx)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 }
x25_connect_callback(lcp,m)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
x25_dgram_incoming(lcp,m0)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 */
x25_rtrequest(cmd,rt,dst)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
x25_rtinvert(cmd,sa,rt)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
pk_init()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
pk_user_protolisten(info)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 */
pk_rtattach(so,m0)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 }
x25_rtattach(lcp0,rt)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