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