Commit | Line | Data |
---|---|---|
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 | ||
44 | extern struct ifnet loif; | |
45 | ||
46 | #define senderr(x) {error = x; goto bad;} | |
47 | /* | |
48 | * X.25 output routine. | |
49 | */ | |
50 | x25_ifoutput(xc, m0, dst, rt) | |
51 | struct x25com *xc; | |
52 | struct mbuf *m0; | |
53 | struct sockaddr *dst; | |
54 | register 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 | } | |
172 | out: | |
173 | if (flags & XL_RTHELD) | |
174 | RTFREE(rt); | |
175 | return (error); | |
176 | } | |
177 | ||
178 | /* | |
179 | * Simpleminded timer for very smart devices. | |
180 | */ | |
181 | x25_iftimeout(xc) | |
182 | register 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 | */ | |
199 | x25_ifinput(xq, m) | |
200 | struct xq *xq; | |
201 | struct 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 | ||
250 | union 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 | }; | |
259 | static struct sockaddr_x25 blank_x25 = {sizeof blank_x25, AF_CCITT}; | |
260 | /* | |
261 | * IP to X25 address routine copyright ACC, used by permission. | |
262 | */ | |
263 | x25_ddnip_to_ccitt(src, dst) | |
264 | struct sockaddr_in *src; | |
265 | register 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 | */ | |
318 | x25_ifrtchange(cmd, rt, dst) | |
319 | register struct rtentry *rt; | |
320 | struct 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 | } | |
376 | static 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 | */ | |
381 | x25_dg_rtinit(dst, xc, af) | |
382 | struct sockaddr_x25 *dst; | |
383 | register 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 | } |