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