split out descend and inherit attributes; add signal tracing
[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 *
b84e7ca8 7 * @(#)if_x25subr.c 7.5 (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"
16#include "ioctl.h"
17#include "errno.h"
18#include "syslog.h"
19
039be508
KS
20#include "../net/if.h"
21#include "../net/netisr.h"
22#include "../net/route.h"
23
24#include "x25.h"
25#include "x25error.h"
26#include "pk_var.h"
16e7cbfd 27
16e7cbfd
KS
28#include "machine/mtpr.h"
29
30#ifdef INET
31#include "../netinet/in.h"
32#include "../netinet/in_var.h"
33#endif
34
35#ifdef NS
36#include "../netns/ns.h"
37#include "../netns/ns_if.h"
38#endif
39
40#ifdef ISO
41#include "../netiso/argo_debug.h"
42#include "../netiso/iso.h"
43#include "../netiso/iso_var.h"
44#endif
45
46extern struct ifnet loif;
47
48#define senderr(x) {error = x; goto bad;}
49/*
50 * X.25 output routine.
51 */
039be508
KS
52x25_ifoutput(ifp, m0, dst, rt)
53struct ifnet *ifp;
16e7cbfd
KS
54struct mbuf *m0;
55struct sockaddr *dst;
56register struct rtentry *rt;
57{
039be508 58 register struct mbuf *m;
ffababe5
KS
59 register struct rtextension_x25 *rtx;
60 register struct pq *pq;
039be508
KS
61 struct pklcd *lcp;
62 struct x25_ifaddr *ia;
16e7cbfd
KS
63 struct mbuf *prev;
64 int s, error = 0, flags = 0;
65 union imp_addr imp_addr;
66 int flags = 0;
67
039be508 68 if ((ifp->if_flags & IFF_UP) == 0)
16e7cbfd
KS
69 return (ENETDOWN);
70 if (rt == 0 ||
71 ((rt->rt_flags & RTF_GATEWAY) && (dst = rt->rt_gateway))) {
72 if ((rt = rtalloc1(dst, 1)) == 0)
73 return (EHOSTUNREACH);
74 rt->rt_refcnt++;
039be508 75 flags = XRF_RTHELD;
16e7cbfd
KS
76 }
77 /*
78 * Sanity checks.
79 */
039be508 80 if ((rt->rt_ifp != ifp) ||
16e7cbfd 81 (rt->rt_flags & (RTF_CLONING | RTF_GATEWAY)) ||
039be508 82 ((rtx = (struct rtextension_x25 *)rt->rt_llinfo) == 0)) {
16e7cbfd
KS
83 printf("Inconsistent call to x25_output, should panic\n");
84 senderr(ENETUNREACH);
85 }
039be508
KS
86 {
87 register struct ifaddr *ifa;
88 for (ifa = ifp->if_addrlist; ; ifa = ifa->ifa_next) {
89 if (ifa == 0)
90 senderr(ENETDOWN);
91 if (ifa->ifa_addr->sa_family == AF_CCITT)
92 break;
93 }
94 ia = (struct x25_ifaddr *)ifa;
95 }
96 if (rtx->rtx_lcd == 0) {
97 int x25_ifinput();
98
ffababe5
KS
99 lcp = pk_attach((struct socket *)0);
100 if (lcp == 0)
039be508 101 senderr(ENOBUFS);
ffababe5 102 rtx->rtx_lcd = lcp;
039be508
KS
103 rtx->rtx_rt = rt;
104 rtx->rtx_ia = ia;
b84e7ca8
KS
105 lcp->lcd_upnext = (caddr_t)rtx;
106 lcp->lcd_upper = x25_ifinput;
039be508 107 }
039be508 108 switch (rtx->rtx_state) {
16e7cbfd 109
039be508
KS
110 case XRS_CONNECTED:
111 lcd->lcd_dg_timer = ia->ia_xc.xc_dg_idletimo;
16e7cbfd 112 /* FALLTHROUGH */
039be508 113 case XRS_CONNECTING:
b84e7ca8 114 if (sbspace(&lcp->lcd_sb) < 0)
16e7cbfd 115 senderr(ENOBUFS);
b84e7ca8 116 lcp->lcd_send(lcp, m);
16e7cbfd
KS
117 break;
118
039be508 119 case XRS_NEWBORN:
16e7cbfd 120 if (dst->sa_family == AF_INET &&
039be508 121 ia->xc_if.if_type == IFT_DDN &&
16e7cbfd
KS
122 rt->rt_gateway->sa_family != AF_CCITT)
123 x25_ddnip_to_ccitt(dst, rt->rt_gateway);
039be508
KS
124 lcp->lcd_flags |= X25_DG_CIRCUIT;
125 rtx->rtx_state = XRS_FREE;
16e7cbfd
KS
126 if (rt->rt_gateway->sa_family != AF_CCITT) {
127 /*
128 * Need external resolution of dst
129 */
130 if ((rt->rt_flags & RTF_XRESOLVE) == 0)
131 senderr(ENETUNREACH);
039be508 132 rtx->rtx_flags |= flags;
16e7cbfd
KS
133 flags = 0;
134 rt_missmsg(RTM_RESOLVE, dst,
135 (struct sockaddr *)0, (struct sockaddr *)0,
136 (struct sockaddr *)0, 0, 0);
039be508 137 rtx->rtx_state = XRS_RESOLVING;
16e7cbfd 138 /* FALLTHROUGH */
039be508 139 case XRS_RESOLVING:
b84e7ca8 140 if (sbspace(&lcp->lcd_sb) < 0)
16e7cbfd 141 senderr(ENOBUFS);
b84e7ca8 142 sbappendrecord(&lcp->lcd_sb, m);
16e7cbfd
KS
143 break;
144 }
145 /* FALLTHROUGH */
039be508 146 case XRS_FREE:
b84e7ca8 147 sbappendrecord(&lcp->lcd_sb, m);
039be508 148 lcp->lcd_pkcb = &(rtx->rtx_ia->ia_pkcb);
ffababe5
KS
149 pk_connect(lcp, (struct mbuf *)0,
150 (struct sockaddr_x25 *)rt->rt_gateway);
039be508 151 break;
16e7cbfd
KS
152 /* FALLTHROUGH */
153 default:
154 /*
155 * We count on the timer routine to close idle
156 * connections, if there are not enough circuits to go
157 * around.
158 *
159 * So throw away data for now.
160 * After we get it all working, we'll rewrite to handle
161 * actively closing connections (other than by timers),
162 * when circuits get tight.
163 *
164 * In the DDN case, the imp itself closes connections
165 * under heavy load.
166 */
167 error = ENOBUFS;
168 bad:
169 if (m)
170 m_freem(m);
171 }
172out:
039be508 173 if (flags & XRF_RTHELD)
16e7cbfd
KS
174 RTFREE(rt);
175 return (error);
176}
177
178/*
039be508 179 * Simpleminded timer routine.
16e7cbfd 180 */
039be508
KS
181x25_iftimeout(ifp)
182struct ifnet *ifp;
16e7cbfd 183{
039be508
KS
184 register struct pkcb *pkcb = 0;
185 register struct ifaddr *ifa;
186 register struct pklcd **lcpp, *lcp;
16e7cbfd
KS
187 int s = splimp();
188
039be508
KS
189 for (ifa = ifp->if_addrlist; ; ifa = ifa->ifa_next) {
190 if (ifa->ifa_addr->sa_family == AF_CCITT)
191 break;
192 }
193 if (ifa)
194 pkcb = &((struct x25_ifaddr *)ifa)->ia_pkcb;
195 if (pkcb)
196 for (lcpp = pkcb->pk_chan + pkcb->pk_maxlcn;
197 --lcpp >= pkcb->pk_chan;)
198 if ((lcp = *lcpp) &&
199 lcp->lcd_state == DATA_TRANSFER &&
200 (lcp->lcd_flags & X25_DG_CICRUIT) &&
201 (--(lcp->lcd_dg_timer) <= 0)) {
202 register struct rtextension_x25 *rtx;
203 pk_disconnect(lcp);
204 rtx = (struct rtextension_x25 *)
b84e7ca8 205 lcp->lcp_upnext;
039be508
KS
206 if (rtx)
207 rtx->rtx_state = XRS_DISCONNECTING;
208 }
16e7cbfd
KS
209 splx(s);
210}
211
212/*
213 * Process a x25 packet as datagram;
214 */
b84e7ca8
KS
215x25_ifinput(lcp, m)
216struct pklcd *lcp;
16e7cbfd
KS
217struct mbuf *m;
218{
b84e7ca8
KS
219 struct rtextension *rtx = (struct rtentry *)lcp->lcd_upnext;
220 register struct ifnet *ifp = &rtx->rtx_rt->rt_ifp;
16e7cbfd
KS
221 int s;
222
223 ifp->if_lastchange = time;
224
225 switch (rt_dst(rt)->sa_family) {
226#ifdef INET
227 case AF_INET:
228 schednetisr(NETISR_IP);
229 inq = &ipintrq;
230 break;
231
232#endif
233#ifdef NS
234 case AF_NS:
235 schednetisr(NETISR_NS);
236 inq = &nsintrq;
237 break;
238
239#endif
240#ifdef ISO
241 case AF_ISO:
242 /* XXXX need to find out about tearing off COSNS
243 headers if any */
244 schednetisr(NETISR_ISO);
245 inq = &clnlintrq;
246 break;
247#endif
248 default:
249 m_freem(m);
250 ifp->if_noproto++;
251 return;
252 }
253 s = splimp();
254 if (IF_QFULL(inq)) {
255 IF_DROP(inq);
256 m_freem(m);
257 } else {
258 IF_ENQUEUE(inq, m);
259 ifp->if_ibytes += m->m_pkthdr.len;
260 }
261 splx(s);
262}
263
264union imp_addr {
265 struct in_addr ip;
266 struct imp {
267 u_char s_net;
268 u_char s_host;
269 u_char s_lh;
270 u_char s_impno;
271 } imp;
272};
273static struct sockaddr_x25 blank_x25 = {sizeof blank_x25, AF_CCITT};
274/*
275 * IP to X25 address routine copyright ACC, used by permission.
276 */
277x25_ddnip_to_ccitt(src, dst)
278struct sockaddr_in *src;
279register struct sockaddr_x25 *dst;
280{
281 union imp_addr imp_addr;
282 int imp_no, imp_port;
283 char *x25addr = dst->x25_x25addr;
284
285
286 imp_addr.ip = src->sin_addr.s_addr;
287 *dst = blank_x25;
288 if ((imp_addr.imp.s_net & 0x80) == 0x00) { /* class A */
289 imp_no = imp_addr.imp.s_impno;
290 imp_port = imp_addr.imp.s_host;
291 } else if ((imp_addr.imp.s_net & 0xc0) == 0x80) { /* class B */
292 imp_no = imp_addr.imp.s_impno;
293 imp_port = imp_addr.imp.s_lh;
294 } else { /* class C */
295 imp_no = imp_addr.imp.s_impno / 32;
296 imp_port = imp_addr.imp.s_impno % 32;
297 }
298
299 x25addr[0] = 12; /* length */
300 /* DNIC is cleared by struct copy above */
301
302 if (imp_port < 64) { /* Physical: 0000 0 IIIHH00 [SS] *//* s_impno
303 * -> III, s_host -> HH */
304 x25addr[5] = 0; /* set flag bit */
305 x25addr[6] = imp_no / 100;
306 x25addr[7] = (imp_no % 100) / 10;
307 x25addr[8] = imp_no % 10;
308 x25addr[9] = imp_port / 10;
309 x25addr[10] = imp_port % 10;
310 } else { /* Logical: 0000 1 RRRRR00 [SS] *//* s
311 * _host * 256 + s_impno -> RRRRR */
312 temp = (imp_port << 8) + imp_no;
313 x25addr[5] = 1;
314 x25addr[6] = temp / 10000;
315 x25addr[7] = (temp % 10000) / 1000;
316 x25addr[8] = (temp % 1000) / 100;
317 x25addr[9] = (temp % 100) / 10;
318 x25addr[10] = temp % 10;
319 }
320}
321
322#ifdef caseof
323#undef caseof
324#endif
325#define caseof(a, b) (b + 8 * a)
326#define SA(p) ((struct sockaddr *)(p))
327
328/*
329 * This routine gets called when validing new routes or deletions of old
330 * ones.
331 */
332x25_ifrtchange(cmd, rt, dst)
333register struct rtentry *rt;
334struct sockaddr *dst;
335{
039be508 336 register struct rtextension_x25 *rtx = (struct pklcd *)rt->rt_llinfo;
16e7cbfd 337 register struct sockaddr_x25 *sa =(struct sockaddr_x25 *)rt->rt_gateway;
039be508
KS
338 register struct pklcd *lcp;
339 register struct x25_ifaddr *ia;
16e7cbfd
KS
340 register struct sockaddr *sa2;
341 struct mbuf *m, *mold;
b84e7ca8 342 int x25_ifrtfree();
16e7cbfd 343
039be508 344 if (rtx == 0)
16e7cbfd 345 return;
039be508
KS
346 ia = rtx->rtx_ia;
347 lcp = rtx->rtx_lcd;
348
16e7cbfd 349 switch (caseof(xl->xl_state, cmd)) {
039be508
KS
350
351 case caseof(XRS_CONNECTED, RTM_DELETE):
352 case caseof(XRS_CONNECTED, RTM_CHANGE):
353 case caseof(XRS_CONNECTING, RTM_DELETE):
354 case caseof(XRS_CONNECTING, RTM_CHANGE):
355 pk_disconnect(lcp);
b84e7ca8 356 lcp->lcd_upper = x25_ifrtfree;
039be508 357 rt->rt_refcnt++;
16e7cbfd
KS
358 break;
359
039be508
KS
360 case caseof(XRS_CONNECTED, RTM_ADD):
361 case caseof(XRS_CONNECTING, RTM_ADD):
362 case caseof(XRS_RESOLVING, RTM_ADD):
16e7cbfd
KS
363 printf("ifrtchange: impossible transition, should panic\n");
364 break;
365
039be508 366 case caseof(XRS_RESOLVING, RTM_DELETE):
b84e7ca8
KS
367 sbflush(&(rtx->rtx_lcd->lcd_sb));
368 free((caddr_t)rtx->rtx_lcd, M_PCB);
039be508 369 rtx->rtx_lcd = 0;
16e7cbfd
KS
370 break;
371
039be508
KS
372 case caseof(XRS_RESOLVING, RTM_CHANGE):
373 lcp->lcd_pkcb = &(ia->ia_pkcb);
ffababe5 374 pk_connect(lcp, (struct mbuf *)0, sa);
16e7cbfd
KS
375 break;
376 }
039be508
KS
377 if (rt->rt_ifp->if_type == IFT_DDN)
378 return;
16e7cbfd
KS
379 sa2 = SA(rt->rt_key);
380 if (cmd == RTM_CHANGE) {
381 if (sa->sa_family == AF_CCITT) {
b84e7ca8 382 sa->x25_opts.op_speed = sa2->sa_family;
16e7cbfd
KS
383 (void) rtrequest(RTM_DELETE, SA(sa), sa2,
384 SA(0), RTF_HOST, (struct rtentry **)0);
385 }
386 sa = (struct sockaddr_x25 *)dst;
387 cmd = RTM_ADD;
388 }
389 if (sa->sa_family == AF_CCITT) {
b84e7ca8 390 sa->x25_opts.op_speed = sa2->sa_family;
16e7cbfd
KS
391 (void) rtrequest(cmd, SA(sa), sa2, SA(0), RTF_HOST,
392 (struct rtentry **)0);
b84e7ca8 393 sa->x25_opts.op_speed = 0;
16e7cbfd
KS
394 }
395}
b84e7ca8 396
16e7cbfd
KS
397static struct sockaddr sin = {sizeof(sin), AF_INET};
398/*
399 * This is a utility routine to be called by x25 devices when a
400 * call request is honored with the intent of starting datagram forwarding.
401 */
039be508 402x25_dg_rtinit(dst, ia, af)
16e7cbfd 403struct sockaddr_x25 *dst;
039be508 404register struct x25com *ia;
16e7cbfd
KS
405{
406 struct sockaddr *sa = 0;
039be508 407 if (ia->xc_if.if_type == IFT_DDN && af == AF_INET) {
16e7cbfd
KS
408 /*
409 * Inverse X25 to IPP mapping copyright and courtesy ACC.
410 */
411 int imp_no, imp_port, temp;
412 union imp_addr imp_addr;
413 {
414 /*
415 * First determine our IP addr for network
416 */
417 register struct in_ifaddr *ia;
418 extern struct in_ifaddr *in_ifaddr;
419 for (ia = in_ifaddr; ia; ia = ia->ia_next)
039be508 420 if (ia->ia_ifp == &ia->xc_if) {
16e7cbfd
KS
421 imp_addr.ip = ia->ia_addr.sin_addr;
422 break;
423 }
424 }
425 {
426
427 register char *x25addr = dst->x25_addr;
428
429 switch (x25addr[5] & 0x0f) {
430 case 0: /* Physical: 0000 0 IIIHH00 [SS] */
431 imp_no =
432 ((int) (x25addr[6] & 0x0f) * 100) +
433 ((int) (x25addr[7] & 0x0f) * 10) +
434 ((int) (x25addr[8] & 0x0f));
435
436
437 imp_port =
438 ((int) (x25addr[9] & 0x0f) * 10) +
439 ((int) (x25addr[10] & 0x0f));
440 break;
441 case 1: /* Logical: 0000 1 RRRRR00 [SS] */
442 temp = ((int) (x25addr[6] & 0x0f) * 10000)
443 + ((int) (x25addr[7] & 0x0f) * 1000)
444 + ((int) (x25addr[8] & 0x0f) * 100)
445 + ((int) (x25addr[9] & 0x0f) * 10)
446 + ((int) (x25addr[10] & 0x0f));
447
448 imp_port = temp >> 8;
449 imp_no = temp & 0xff;
450 break;
451 default:
452 return (0L);
453 }
454 imp_addr.ip.s_addr = my_addr;
455 if ((imp_addr.imp.s_net & 0x80) == 0x00) {
456 /* class A */
457 imp_addr.imp.s_host = imp_port;
458 imp_addr.imp.s_impno = imp_no;
459 imp_addr.imp.s_lh = 0;
460 } else if ((imp_addr.imp.s_net & 0xc0) == 0x80) {
461 /* class B */
462 imp_addr.imp.s_lh = imp_port;
463 imp_addr.imp.s_impno = imp_no;
464 } else {
465 /* class C */
466 imp_addr.imp.s_impno = (imp_no << 5) + imp_port;
467 }
468 }
469 sin.sin_addr = imp_addr.ip;
470 sa = (struct sockaddr *)&sin;
471 } else {
472 /*
473 * This uses the X25 routing table to do inverse
474 * lookup of x25 address to sockaddr.
475 */
b84e7ca8 476 dst->x25_opts.op_speed = af;
16e7cbfd
KS
477 if (rt = rtalloc1(dst, 0)) {
478 sa = rt->rt_gateway;
479 rt->rt_refcnt--;
480 }
b84e7ca8 481 dst->x25_opts.op_speed = 0;
16e7cbfd
KS
482 }
483 /*
484 * Call to rtalloc1 will create rtentry for reverse path
485 * to callee by virtue of cloning magic and will allocate
486 * space for local control block.
487 */
488 if (sa && rt = rtalloc1(sa, 1))
489 rt->rt_refcnt--;
490}
b84e7ca8
KS
491
492struct radix_tree_head *x25_rnhead;
493
494pk_init()
495{
496 /*
497 * warning, sizeof (struct sockaddr_x25) > 32,
498 * but contains no data of interest beyond 32
499 */
500 rn_inithead(&x25_rnhead, 16, AF_CCITT);
501}