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 | * |
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 | ||
46 | extern struct ifnet loif; | |
47 | ||
48 | #define senderr(x) {error = x; goto bad;} | |
49 | /* | |
50 | * X.25 output routine. | |
51 | */ | |
039be508 KS |
52 | x25_ifoutput(ifp, m0, dst, rt) |
53 | struct ifnet *ifp; | |
16e7cbfd KS |
54 | struct mbuf *m0; |
55 | struct sockaddr *dst; | |
56 | register 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 | } | |
172 | out: | |
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 |
181 | x25_iftimeout(ifp) |
182 | struct 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 |
215 | x25_ifinput(lcp, m) |
216 | struct pklcd *lcp; | |
16e7cbfd KS |
217 | struct 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 | ||
264 | union 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 | }; | |
273 | static struct sockaddr_x25 blank_x25 = {sizeof blank_x25, AF_CCITT}; | |
274 | /* | |
275 | * IP to X25 address routine copyright ACC, used by permission. | |
276 | */ | |
277 | x25_ddnip_to_ccitt(src, dst) | |
278 | struct sockaddr_in *src; | |
279 | register 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 | */ | |
332 | x25_ifrtchange(cmd, rt, dst) | |
333 | register struct rtentry *rt; | |
334 | struct 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 |
397 | static 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 | 402 | x25_dg_rtinit(dst, ia, af) |
16e7cbfd | 403 | struct sockaddr_x25 *dst; |
039be508 | 404 | register 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 | |
492 | struct radix_tree_head *x25_rnhead; | |
493 | ||
494 | pk_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 | } |