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