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