install combined copyright headers using sccs include for terms
[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 *
94b7ce3b 7 * @(#)if_x25subr.c 7.2 (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
20#include "if.h"
21#include "netisr.h"
22#include "route.h"
23
24#include "x25_var.h"
25#include "x25_pk.h"
26#include "machine/mtpr.h"
27
28#ifdef INET
29#include "../netinet/in.h"
30#include "../netinet/in_var.h"
31#endif
32
33#ifdef NS
34#include "../netns/ns.h"
35#include "../netns/ns_if.h"
36#endif
37
38#ifdef ISO
39#include "../netiso/argo_debug.h"
40#include "../netiso/iso.h"
41#include "../netiso/iso_var.h"
42#endif
43
44extern struct ifnet loif;
45
46#define senderr(x) {error = x; goto bad;}
47/*
48 * X.25 output routine.
49 */
50x25_ifoutput(xc, m0, dst, rt)
51struct x25com *xc;
52struct mbuf *m0;
53struct sockaddr *dst;
54register struct rtentry *rt;
55{
56 register struct mbuf *m = m0;
57 register struct x25lcb *xl;
58 register struct xq *oq;
59 register struct x25lcb **xlp;
60 struct mbuf *prev;
61 int s, error = 0, flags = 0;
62 union imp_addr imp_addr;
63 int flags = 0;
64
65 if ((xc->xc_if.if_flags & IFF_UP) == 0)
66 return (ENETDOWN);
67 if (rt == 0 ||
68 ((rt->rt_flags & RTF_GATEWAY) && (dst = rt->rt_gateway))) {
69 if ((rt = rtalloc1(dst, 1)) == 0)
70 return (EHOSTUNREACH);
71 rt->rt_refcnt++;
72 flags = XL_RTHELD;
73 }
74 /*
75 * Sanity checks.
76 */
77 if ((rt->rt_ifp != (struct ifnet *)xc) ||
78 (rt->rt_flags & (RTF_CLONING | RTF_GATEWAY)) ||
79 ((xl = (struct x25lcb *)rt->rt_llinfo) == 0)) {
80 printf("Inconsistent call to x25_output, should panic\n");
81 senderr(ENETUNREACH);
82 }
83 xq = &xl->xl_downq;
84 switch (xl->xl_state) {
85
86 case XLS_CONNECTED:
87 xl->xl_timer = xc->xc_dg_idletimo;
88 /* FALLTHROUGH */
89 case XLS_CONNECTING:
90 if (xq->xq_space < 0)
91 senderr(ENOBUFS);
92 xq->xq_put(xq, m);
93 break;
94
95 case XLS_NEWBORN:
96 xq = &xl->xl_upq;
97 xq->xq_next = (caddr_t)rt;
98 xq->xq_put = x25_ifinput;
99 if (dst->sa_family == AF_INET &&
100 xc->xc_if.if_type == IFT_DDN &&
101 rt->rt_gateway->sa_family != AF_CCITT)
102 x25_ddnip_to_ccitt(dst, rt->rt_gateway);
103 xl->xl_xc = xc;
104 xq = &xl->xl_downq;
105 xq->xq_space = 2048; /* XXX: bogus xq before if_start called */
106 xl->xl_flags |= XL_DGRAM;
107 xl->xl_state = XLS_FREE;
108 if (rt->rt_gateway->sa_family != AF_CCITT) {
109 /*
110 * Need external resolution of dst
111 */
112 if ((rt->rt_flags & RTF_XRESOLVE) == 0)
113 senderr(ENETUNREACH);
114 xl->xl_flags |= flags;
115 xl->xl_timer = xc->xc_rslvtimo;
116 flags = 0;
117 rt_missmsg(RTM_RESOLVE, dst,
118 (struct sockaddr *)0, (struct sockaddr *)0,
119 (struct sockaddr *)0, 0, 0);
120 xl->xl_state = XLS_RESOLVING;
121 /* FALLTHROUGH */
122 case XLS_RESOLVING:
123 if (xq->xq_space < 0)
124 senderr(ENOBUFS);
125 xq->xq_space -= m->m_pkthdr.len;
126 if (xq->xq_data == 0)
127 xq->xq_data = m;
128 else {
129 for (m = xq->xq_data; m->m_nextpkt; )
130 m = m->m_nextpkt;
131 m->m_nextpkt = m0;
132 }
133 break;
134 }
135 /* FALLTHROUGH */
136 case XLS_FREE:
137 xlp = xc->xc_lcbvec + xc->xc_nchan;
138 s = splimp(); /* need to block out incoming requests */
139 if (xc->xc_nactive < xc->xc_nchan) {
140 while (--xlp > xc->xc_lcbvec && *xlp)
141 ;
142 if (xlp > xc->xc_lcbvec) {
143 xc->xc_nactive++;
144 *xlp = xl;
145 xl->xl_index = xlp - xc->xc_lcbvec;
146 x25_ifstart(xl, m, rt->rt_gateway, dst);
147 splx(s);
148 break;
149 }
150 }
151 splx(s);
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:
173 if (flags & XL_RTHELD)
174 RTFREE(rt);
175 return (error);
176}
177
178/*
179 * Simpleminded timer for very smart devices.
180 */
181x25_iftimeout(xc)
182register struct x25com *xc;
183{
184 register struct x25lcb **xlp = xc->xc_lcbvec + xc->xc_nchan;
185 register struct x25lcb *xl;
186 int s = splimp();
187
188 if (xc->xc_disconnect)
189 while (--xlp > xc->xc_lcbvec)
190 if ((xl = *xlp) && xl->xl_state == XLS_CONECTED &&
191 (xl->xl_flags & XL_DGRAM) && --(xl->xl_timer) <= 0)
192 xc->xc_disconnect(xl);
193 splx(s);
194}
195
196/*
197 * Process a x25 packet as datagram;
198 */
199x25_ifinput(xq, m)
200struct xq *xq;
201struct mbuf *m;
202{
203 struct rtentry *rt = (struct rtentry *)xq->xq_next;
204 struct x25lcb *xl = (struct x25lcb *)rt->rt_llinfo;
205 register struct ifnet *ifp = &xl->xl_xc.xc_if;
206 register struct llc *l;
207 int s;
208
209 ifp->if_lastchange = time;
210
211 switch (rt_dst(rt)->sa_family) {
212#ifdef INET
213 case AF_INET:
214 schednetisr(NETISR_IP);
215 inq = &ipintrq;
216 break;
217
218#endif
219#ifdef NS
220 case AF_NS:
221 schednetisr(NETISR_NS);
222 inq = &nsintrq;
223 break;
224
225#endif
226#ifdef ISO
227 case AF_ISO:
228 /* XXXX need to find out about tearing off COSNS
229 headers if any */
230 schednetisr(NETISR_ISO);
231 inq = &clnlintrq;
232 break;
233#endif
234 default:
235 m_freem(m);
236 ifp->if_noproto++;
237 return;
238 }
239 s = splimp();
240 if (IF_QFULL(inq)) {
241 IF_DROP(inq);
242 m_freem(m);
243 } else {
244 IF_ENQUEUE(inq, m);
245 ifp->if_ibytes += m->m_pkthdr.len;
246 }
247 splx(s);
248}
249
250union imp_addr {
251 struct in_addr ip;
252 struct imp {
253 u_char s_net;
254 u_char s_host;
255 u_char s_lh;
256 u_char s_impno;
257 } imp;
258};
259static struct sockaddr_x25 blank_x25 = {sizeof blank_x25, AF_CCITT};
260/*
261 * IP to X25 address routine copyright ACC, used by permission.
262 */
263x25_ddnip_to_ccitt(src, dst)
264struct sockaddr_in *src;
265register struct sockaddr_x25 *dst;
266{
267 union imp_addr imp_addr;
268 int imp_no, imp_port;
269 char *x25addr = dst->x25_x25addr;
270
271
272 imp_addr.ip = src->sin_addr.s_addr;
273 *dst = blank_x25;
274 if ((imp_addr.imp.s_net & 0x80) == 0x00) { /* class A */
275 imp_no = imp_addr.imp.s_impno;
276 imp_port = imp_addr.imp.s_host;
277 } else if ((imp_addr.imp.s_net & 0xc0) == 0x80) { /* class B */
278 imp_no = imp_addr.imp.s_impno;
279 imp_port = imp_addr.imp.s_lh;
280 } else { /* class C */
281 imp_no = imp_addr.imp.s_impno / 32;
282 imp_port = imp_addr.imp.s_impno % 32;
283 }
284
285 x25addr[0] = 12; /* length */
286 /* DNIC is cleared by struct copy above */
287
288 if (imp_port < 64) { /* Physical: 0000 0 IIIHH00 [SS] *//* s_impno
289 * -> III, s_host -> HH */
290 x25addr[5] = 0; /* set flag bit */
291 x25addr[6] = imp_no / 100;
292 x25addr[7] = (imp_no % 100) / 10;
293 x25addr[8] = imp_no % 10;
294 x25addr[9] = imp_port / 10;
295 x25addr[10] = imp_port % 10;
296 } else { /* Logical: 0000 1 RRRRR00 [SS] *//* s
297 * _host * 256 + s_impno -> RRRRR */
298 temp = (imp_port << 8) + imp_no;
299 x25addr[5] = 1;
300 x25addr[6] = temp / 10000;
301 x25addr[7] = (temp % 10000) / 1000;
302 x25addr[8] = (temp % 1000) / 100;
303 x25addr[9] = (temp % 100) / 10;
304 x25addr[10] = temp % 10;
305 }
306}
307
308#ifdef caseof
309#undef caseof
310#endif
311#define caseof(a, b) (b + 8 * a)
312#define SA(p) ((struct sockaddr *)(p))
313
314/*
315 * This routine gets called when validing new routes or deletions of old
316 * ones.
317 */
318x25_ifrtchange(cmd, rt, dst)
319register struct rtentry *rt;
320struct sockaddr *dst;
321{
322 register struct x25lcb *xl = (struct x25lcb *)rt->rt_llinfo;
323 register struct x25com *xc;
324 register struct sockaddr_x25 *sa =(struct sockaddr_x25 *)rt->rt_gateway;
325 register struct sockaddr *sa2;
326 struct mbuf *m, *mold;
327
328 if (xl == 0)
329 return;
330 xc = xl->xl_xc;
331 switch (caseof(xl->xl_state, cmd)) {
332 case caseof(XLS_CONNECTED, RTM_DELETE):
333 case caseof(XLS_CONNECTED, RTM_CHANGE):
334 case caseof(XLS_CONNECTING, RTM_DELETE):
335 case caseof(XLS_CONNECTING, RTM_CHANGE):
336 xc->xc_disconnect(xl);
337 break;
338
339 case caseof(XLS_CONNECTED, RTM_ADD):
340 case caseof(XLS_CONNECTING, RTM_ADD):
341 case caseof(XLS_RESOLVING, RTM_ADD):
342 printf("ifrtchange: impossible transition, should panic\n");
343 break;
344
345 case caseof(XLS_RESOLVING, RTM_DELETE):
346 for (m = xl->xl_downq.xq_data; m;) {
347 mold = m;
348 m = m->m_nextpkt;
349 m_freem(mold);
350 }
351 break;
352
353 case caseof(XLS_RESOLVING, RTM_CHANGE):
354 xc->xc_if.if_start(xl, 0, dst);
355 break;
356 }
357 if (xc->xc_if.if_type == IFT_DDN)
358 return; /* reverse name table not necessary */
359 sa2 = SA(rt->rt_key);
360 if (cmd == RTM_CHANGE) {
361 if (sa->sa_family == AF_CCITT) {
362 sa->sa_rfamily = sa2->sa_family;
363 (void) rtrequest(RTM_DELETE, SA(sa), sa2,
364 SA(0), RTF_HOST, (struct rtentry **)0);
365 }
366 sa = (struct sockaddr_x25 *)dst;
367 cmd = RTM_ADD;
368 }
369 if (sa->sa_family == AF_CCITT) {
370 sa->sa_rfamily = sa2->sa_family;
371 (void) rtrequest(cmd, SA(sa), sa2, SA(0), RTF_HOST,
372 (struct rtentry **)0);
373 sa->sa_rfamily = 0;
374 }
375}
376static struct sockaddr sin = {sizeof(sin), AF_INET};
377/*
378 * This is a utility routine to be called by x25 devices when a
379 * call request is honored with the intent of starting datagram forwarding.
380 */
381x25_dg_rtinit(dst, xc, af)
382struct sockaddr_x25 *dst;
383register struct x25com *xc;
384{
385 struct sockaddr *sa = 0;
386 if (xc->xc_if.if_type == IFT_DDN && af == AF_INET) {
387 /*
388 * Inverse X25 to IPP mapping copyright and courtesy ACC.
389 */
390 int imp_no, imp_port, temp;
391 union imp_addr imp_addr;
392 {
393 /*
394 * First determine our IP addr for network
395 */
396 register struct in_ifaddr *ia;
397 extern struct in_ifaddr *in_ifaddr;
398 for (ia = in_ifaddr; ia; ia = ia->ia_next)
399 if (ia->ia_ifp == &xc->xc_if) {
400 imp_addr.ip = ia->ia_addr.sin_addr;
401 break;
402 }
403 }
404 {
405
406 register char *x25addr = dst->x25_addr;
407
408 switch (x25addr[5] & 0x0f) {
409 case 0: /* Physical: 0000 0 IIIHH00 [SS] */
410 imp_no =
411 ((int) (x25addr[6] & 0x0f) * 100) +
412 ((int) (x25addr[7] & 0x0f) * 10) +
413 ((int) (x25addr[8] & 0x0f));
414
415
416 imp_port =
417 ((int) (x25addr[9] & 0x0f) * 10) +
418 ((int) (x25addr[10] & 0x0f));
419 break;
420 case 1: /* Logical: 0000 1 RRRRR00 [SS] */
421 temp = ((int) (x25addr[6] & 0x0f) * 10000)
422 + ((int) (x25addr[7] & 0x0f) * 1000)
423 + ((int) (x25addr[8] & 0x0f) * 100)
424 + ((int) (x25addr[9] & 0x0f) * 10)
425 + ((int) (x25addr[10] & 0x0f));
426
427 imp_port = temp >> 8;
428 imp_no = temp & 0xff;
429 break;
430 default:
431 return (0L);
432 }
433 imp_addr.ip.s_addr = my_addr;
434 if ((imp_addr.imp.s_net & 0x80) == 0x00) {
435 /* class A */
436 imp_addr.imp.s_host = imp_port;
437 imp_addr.imp.s_impno = imp_no;
438 imp_addr.imp.s_lh = 0;
439 } else if ((imp_addr.imp.s_net & 0xc0) == 0x80) {
440 /* class B */
441 imp_addr.imp.s_lh = imp_port;
442 imp_addr.imp.s_impno = imp_no;
443 } else {
444 /* class C */
445 imp_addr.imp.s_impno = (imp_no << 5) + imp_port;
446 }
447 }
448 sin.sin_addr = imp_addr.ip;
449 sa = (struct sockaddr *)&sin;
450 } else {
451 /*
452 * This uses the X25 routing table to do inverse
453 * lookup of x25 address to sockaddr.
454 */
455 dst->sa_rfamily = af;
456 if (rt = rtalloc1(dst, 0)) {
457 sa = rt->rt_gateway;
458 rt->rt_refcnt--;
459 }
460 dst->sa_rfamily = 0;
461 }
462 /*
463 * Call to rtalloc1 will create rtentry for reverse path
464 * to callee by virtue of cloning magic and will allocate
465 * space for local control block.
466 */
467 if (sa && rt = rtalloc1(sa, 1))
468 rt->rt_refcnt--;
469}