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