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