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