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