Commit | Line | Data |
---|---|---|
16e7cbfd | 1 | /* |
94b7ce3b | 2 | * Copyright (c) 1990 The Regents of the University of California. |
16e7cbfd KS |
3 | * All rights reserved. |
4 | * | |
af359dea C |
5 | * Redistribution and use in source and binary forms, with or without |
6 | * modification, are permitted provided that the following conditions | |
7 | * are met: | |
8 | * 1. Redistributions of source code must retain the above copyright | |
9 | * notice, this list of conditions and the following disclaimer. | |
10 | * 2. Redistributions in binary form must reproduce the above copyright | |
11 | * notice, this list of conditions and the following disclaimer in the | |
12 | * documentation and/or other materials provided with the distribution. | |
13 | * 3. All advertising materials mentioning features or use of this software | |
14 | * must display the following acknowledgement: | |
15 | * This product includes software developed by the University of | |
16 | * California, Berkeley and its contributors. | |
17 | * 4. Neither the name of the University nor the names of its contributors | |
18 | * may be used to endorse or promote products derived from this software | |
19 | * without specific prior written permission. | |
16e7cbfd | 20 | * |
af359dea C |
21 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND |
22 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
23 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |
24 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE | |
25 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |
26 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | |
27 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |
28 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |
29 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | |
30 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
31 | * SUCH DAMAGE. | |
32 | * | |
33 | * @(#)if_x25subr.c 7.14 (Berkeley) 6/26/91 | |
16e7cbfd KS |
34 | */ |
35 | ||
36 | #include "param.h" | |
37 | #include "systm.h" | |
38 | #include "malloc.h" | |
39 | #include "mbuf.h" | |
40 | #include "protosw.h" | |
41 | #include "socket.h" | |
4507dea2 | 42 | #include "socketvar.h" |
16e7cbfd KS |
43 | #include "ioctl.h" |
44 | #include "errno.h" | |
45 | #include "syslog.h" | |
46 | ||
039be508 | 47 | #include "../net/if.h" |
4507dea2 | 48 | #include "../net/if_types.h" |
039be508 KS |
49 | #include "../net/netisr.h" |
50 | #include "../net/route.h" | |
51 | ||
52 | #include "x25.h" | |
4507dea2 KS |
53 | #include "x25err.h" |
54 | #include "pk.h" | |
039be508 | 55 | #include "pk_var.h" |
16e7cbfd | 56 | |
16e7cbfd KS |
57 | #include "machine/mtpr.h" |
58 | ||
59 | #ifdef INET | |
60 | #include "../netinet/in.h" | |
61 | #include "../netinet/in_var.h" | |
62 | #endif | |
63 | ||
64 | #ifdef NS | |
65 | #include "../netns/ns.h" | |
66 | #include "../netns/ns_if.h" | |
67 | #endif | |
68 | ||
69 | #ifdef ISO | |
af359dea | 70 | int tp_incoming(); |
16e7cbfd KS |
71 | #include "../netiso/argo_debug.h" |
72 | #include "../netiso/iso.h" | |
73 | #include "../netiso/iso_var.h" | |
74 | #endif | |
75 | ||
76 | extern struct ifnet loif; | |
af359dea C |
77 | struct llinfo_x25 llinfo_x25 = {&llinfo_x25, &llinfo_x25}; |
78 | struct sockaddr *x25_dgram_sockmask; | |
79 | ||
80 | struct if_x25stats { | |
81 | int ifx_wrongplen; | |
82 | int ifx_nophdr; | |
83 | } if_x25stats; | |
84 | int x25_autoconnect = 0; | |
16e7cbfd KS |
85 | |
86 | #define senderr(x) {error = x; goto bad;} | |
af359dea C |
87 | /* |
88 | * Ancillary routines | |
89 | */ | |
90 | static struct llinfo_x25 * | |
91 | x25_lxalloc(rt) | |
92 | register struct rtentry *rt; | |
93 | { | |
94 | register struct llinfo_x25 *lx; | |
95 | register struct sockaddr *dst = rt_key(rt); | |
96 | register struct ifaddr *ifa; | |
97 | ||
98 | MALLOC(lx, struct llinfo_x25 *, sizeof (*lx), M_PCB, M_NOWAIT); | |
99 | if (lx == 0) | |
100 | return lx; | |
101 | Bzero(lx, sizeof(*lx)); | |
102 | lx->lx_rt = rt; | |
103 | lx->lx_family = dst->sa_family; | |
104 | rt->rt_refcnt++; | |
105 | if (rt->rt_llinfo) | |
106 | insque(lx, (struct llinfo_x25 *)rt->rt_llinfo); | |
107 | else { | |
108 | rt->rt_llinfo = (caddr_t)lx; | |
109 | insque(lx, &llinfo_x25); | |
110 | } | |
111 | for (ifa = rt->rt_ifp->if_addrlist; ifa; ifa = ifa->ifa_next) { | |
112 | if (ifa->ifa_addr->sa_family == AF_CCITT) | |
113 | lx->lx_ia = (struct x25_ifaddr *)ifa; | |
114 | } | |
115 | return lx; | |
116 | } | |
117 | x25_lxfree(lx) | |
118 | register struct llinfo_x25 *lx; | |
119 | { | |
120 | register struct rtentry *rt = lx->lx_rt; | |
121 | register struct pklcd *lcp = lx->lx_lcd; | |
122 | ||
123 | if (lcp) { | |
124 | lcp->lcd_upper = 0; | |
125 | pk_disconnect(lcp); | |
126 | } | |
127 | if ((rt->rt_llinfo == (caddr_t)lx) && (lx->lx_next->lx_rt == rt)) | |
128 | rt->rt_llinfo = (caddr_t)lx->lx_next; | |
129 | else | |
130 | rt->rt_llinfo = 0; | |
131 | RTFREE(rt); | |
132 | remque(lx); | |
133 | FREE(lx, M_PCB); | |
134 | } | |
135 | /* | |
136 | * Process a x25 packet as datagram; | |
137 | */ | |
138 | x25_ifinput(lcp, m) | |
139 | struct pklcd *lcp; | |
140 | register struct mbuf *m; | |
141 | { | |
142 | struct llinfo_x25 *lx = (struct llinfo_x25 *)lcp->lcd_upnext; | |
143 | register struct ifnet *ifp; | |
144 | struct ifqueue *inq; | |
145 | extern struct timeval time; | |
146 | int s, len, isr; | |
147 | ||
148 | if (m == 0 || lcp->lcd_state != DATA_TRANSFER) { | |
149 | x25_connect_callback(lcp, 0); | |
150 | return; | |
151 | } | |
152 | pk_flowcontrol(lcp, 0, 1); /* Generate RR */ | |
153 | ifp = m->m_pkthdr.rcvif; | |
154 | ifp->if_lastchange = time; | |
155 | switch (m->m_type) { | |
156 | case MT_OOBDATA: | |
157 | if (m) | |
158 | m_freem(m); | |
159 | default: | |
160 | return; | |
161 | ||
162 | case MT_DATA: | |
163 | /* FALLTHROUGH */; | |
164 | } | |
165 | switch (lx->lx_family) { | |
166 | #ifdef INET | |
167 | case AF_INET: | |
168 | isr = NETISR_IP; | |
169 | inq = &ipintrq; | |
170 | break; | |
171 | ||
172 | #endif | |
173 | #ifdef NS | |
174 | case AF_NS: | |
175 | isr = NETISR_NS; | |
176 | inq = &nsintrq; | |
177 | break; | |
178 | ||
179 | #endif | |
180 | #ifdef ISO | |
181 | case AF_ISO: | |
182 | isr = NETISR_ISO; | |
183 | inq = &clnlintrq; | |
184 | break; | |
185 | #endif | |
186 | default: | |
187 | m_freem(m); | |
188 | ifp->if_noproto++; | |
189 | return; | |
190 | } | |
191 | s = splimp(); | |
192 | schednetisr(isr); | |
193 | if (IF_QFULL(inq)) { | |
194 | IF_DROP(inq); | |
195 | m_freem(m); | |
196 | } else { | |
197 | IF_ENQUEUE(inq, m); | |
198 | ifp->if_ibytes += m->m_pkthdr.len; | |
199 | } | |
200 | splx(s); | |
201 | } | |
202 | x25_connect_callback(lcp, m) | |
203 | register struct pklcd *lcp; | |
204 | register struct mbuf *m; | |
205 | { | |
206 | register struct llinfo_x25 *lx = (struct llinfo_x25 *)lcp->lcd_upnext; | |
207 | if (m == 0) | |
208 | goto refused; | |
209 | if (m->m_type != MT_CONTROL) { | |
210 | printf("x25_connect_callback: should panic\n"); | |
211 | goto refused; | |
212 | } | |
213 | switch (pk_decode(mtod(m, struct x25_packet *))) { | |
214 | case CALL_ACCEPTED: | |
215 | lcp->lcd_upper = x25_ifinput; | |
216 | if (lcp->lcd_sb.sb_mb) | |
217 | lcp->lcd_send(lcp); /* XXX start queued packets */ | |
218 | return; | |
219 | default: | |
220 | refused: | |
221 | lcp->lcd_upper = 0; | |
222 | lx->lx_lcd = 0; | |
223 | pk_disconnect(lcp); | |
224 | return; | |
225 | } | |
226 | } | |
227 | #define SA(p) ((struct sockaddr *)(p)) | |
228 | #define RT(p) ((struct rtentry *)(p)) | |
229 | ||
230 | x25_dgram_incoming(lcp, m0) | |
231 | register struct pklcd *lcp; | |
232 | struct mbuf *m0; | |
233 | { | |
234 | register struct rtentry *rt, *nrt; | |
235 | register struct mbuf *m = m0->m_next; /* m0 has calling sockaddr_x25 */ | |
236 | int x25_rtrequest(); | |
237 | ||
238 | rt = rtalloc1(SA(&lcp->lcd_faddr), 0); | |
239 | if (rt == 0) { | |
240 | refuse: lcp->lcd_upper = 0; | |
241 | pk_close(lcp); | |
242 | return; | |
243 | } | |
244 | rt->rt_refcnt--; | |
245 | if ((nrt = RT(rt->rt_llinfo)) == 0 || rt_mask(rt) != x25_dgram_sockmask) | |
246 | goto refuse; | |
247 | if ((nrt->rt_flags & RTF_UP) == 0) { | |
248 | rt->rt_llinfo = (caddr_t)rtalloc1(rt->rt_gateway, 0); | |
249 | rtfree(nrt); | |
250 | if ((nrt = RT(rt->rt_llinfo)) == 0) | |
251 | goto refuse; | |
252 | nrt->rt_refcnt--; | |
253 | } | |
254 | if (nrt->rt_ifa == 0 || nrt->rt_ifa->ifa_rtrequest != x25_rtrequest) | |
255 | goto refuse; | |
256 | lcp->lcd_send(lcp); /* confirm call */ | |
257 | x25_rtattach(lcp, nrt); | |
258 | m_freem(m); | |
259 | } | |
260 | ||
16e7cbfd KS |
261 | /* |
262 | * X.25 output routine. | |
263 | */ | |
039be508 KS |
264 | x25_ifoutput(ifp, m0, dst, rt) |
265 | struct ifnet *ifp; | |
16e7cbfd KS |
266 | struct mbuf *m0; |
267 | struct sockaddr *dst; | |
268 | register struct rtentry *rt; | |
269 | { | |
af359dea C |
270 | register struct mbuf *m = m0; |
271 | register struct llinfo_x25 *lx; | |
039be508 | 272 | struct pklcd *lcp; |
af359dea C |
273 | int s, error = 0; |
274 | ||
275 | int plen; | |
276 | for (plen = 0; m; m = m->m_next) | |
277 | plen += m->m_len; | |
278 | m = m0; | |
16e7cbfd | 279 | |
039be508 | 280 | if ((ifp->if_flags & IFF_UP) == 0) |
af359dea C |
281 | senderr(ENETDOWN); |
282 | while (rt == 0 || (rt->rt_flags & RTF_GATEWAY)) { | |
283 | if (rt) { | |
284 | if (rt->rt_llinfo) { | |
285 | rt = (struct rtentry *)rt->rt_llinfo; | |
286 | continue; | |
287 | } | |
288 | dst = rt->rt_gateway; | |
289 | } | |
16e7cbfd | 290 | if ((rt = rtalloc1(dst, 1)) == 0) |
af359dea C |
291 | senderr(EHOSTUNREACH); |
292 | rt->rt_refcnt--; | |
16e7cbfd KS |
293 | } |
294 | /* | |
295 | * Sanity checks. | |
296 | */ | |
039be508 | 297 | if ((rt->rt_ifp != ifp) || |
16e7cbfd | 298 | (rt->rt_flags & (RTF_CLONING | RTF_GATEWAY)) || |
4507dea2 | 299 | ((lx = (struct llinfo_x25 *)rt->rt_llinfo) == 0)) { |
16e7cbfd KS |
300 | senderr(ENETUNREACH); |
301 | } | |
af359dea C |
302 | if ((m->m_flags & M_PKTHDR) == 0) { |
303 | if_x25stats.ifx_nophdr++; | |
304 | m = m_gethdr(M_NOWAIT, MT_HEADER); | |
305 | if (m == 0) | |
306 | senderr(ENOBUFS); | |
307 | m->m_pkthdr.len = plen; | |
308 | m->m_next = m0; | |
309 | } | |
310 | if (plen != m->m_pkthdr.len) { | |
311 | if_x25stats.ifx_wrongplen++; | |
312 | m->m_pkthdr.len = plen; | |
313 | } | |
314 | next_circuit: | |
315 | lcp = lx->lx_lcd; | |
316 | if (lcp == 0) { | |
317 | lx->lx_lcd = lcp = pk_attach((struct socket *)0); | |
318 | if (lcp == 0) | |
16e7cbfd | 319 | senderr(ENOBUFS); |
af359dea C |
320 | lcp->lcd_upper = x25_connect_callback; |
321 | lcp->lcd_upnext = (caddr_t)lx; | |
322 | lcp->lcd_packetsize = lx->lx_ia->ia_xc.xc_psize; | |
323 | lcp->lcd_flags = X25_MBS_HOLD; | |
324 | } | |
325 | switch (lcp->lcd_state) { | |
326 | case READY: | |
16e7cbfd | 327 | if (dst->sa_family == AF_INET && |
af359dea | 328 | ifp->if_type == IFT_X25DDN && |
16e7cbfd | 329 | rt->rt_gateway->sa_family != AF_CCITT) |
af359dea | 330 | x25_ddnip_to_ccitt(dst, rt); |
16e7cbfd | 331 | if (rt->rt_gateway->sa_family != AF_CCITT) { |
16e7cbfd | 332 | if ((rt->rt_flags & RTF_XRESOLVE) == 0) |
af359dea C |
333 | senderr(EHOSTUNREACH); |
334 | } else if (x25_autoconnect) | |
335 | error = pk_connect(lcp, | |
336 | (struct sockaddr_x25 *)rt->rt_gateway); | |
337 | if (error) | |
338 | senderr(error); | |
16e7cbfd | 339 | /* FALLTHROUGH */ |
af359dea C |
340 | case SENT_CALL: |
341 | case DATA_TRANSFER: | |
342 | if (sbspace(&lcp->lcd_sb) < 0) { | |
343 | lx = lx->lx_next; | |
344 | if (lx->lx_rt != rt) | |
345 | senderr(ENOSPC); | |
346 | goto next_circuit; | |
347 | } | |
348 | if (lx->lx_ia) | |
349 | lcp->lcd_dg_timer = | |
350 | lx->lx_ia->ia_xc.xc_dg_idletimo; | |
351 | pk_send(lcp, m); | |
039be508 | 352 | break; |
16e7cbfd KS |
353 | default: |
354 | /* | |
355 | * We count on the timer routine to close idle | |
356 | * connections, if there are not enough circuits to go | |
357 | * around. | |
358 | * | |
359 | * So throw away data for now. | |
360 | * After we get it all working, we'll rewrite to handle | |
361 | * actively closing connections (other than by timers), | |
362 | * when circuits get tight. | |
363 | * | |
364 | * In the DDN case, the imp itself closes connections | |
365 | * under heavy load. | |
366 | */ | |
367 | error = ENOBUFS; | |
368 | bad: | |
369 | if (m) | |
370 | m_freem(m); | |
371 | } | |
16e7cbfd KS |
372 | return (error); |
373 | } | |
374 | ||
375 | /* | |
039be508 | 376 | * Simpleminded timer routine. |
16e7cbfd | 377 | */ |
039be508 KS |
378 | x25_iftimeout(ifp) |
379 | struct ifnet *ifp; | |
16e7cbfd | 380 | { |
039be508 | 381 | register struct pkcb *pkcb = 0; |
039be508 | 382 | register struct pklcd **lcpp, *lcp; |
16e7cbfd KS |
383 | int s = splimp(); |
384 | ||
af359dea C |
385 | for (pkcb = pkcbhead; pkcb; pkcb = pkcb->pk_next) |
386 | if (pkcb->pk_ia->ia_ifp == ifp) | |
039be508 | 387 | for (lcpp = pkcb->pk_chan + pkcb->pk_maxlcn; |
c4b47c42 | 388 | --lcpp > pkcb->pk_chan;) |
039be508 KS |
389 | if ((lcp = *lcpp) && |
390 | lcp->lcd_state == DATA_TRANSFER && | |
4507dea2 | 391 | (lcp->lcd_flags & X25_DG_CIRCUIT) && |
c4b47c42 | 392 | (lcp->lcd_dg_timer && --lcp->lcd_dg_timer == 0)) { |
af359dea | 393 | lcp->lcd_upper(lcp, 0); |
c4b47c42 | 394 | } |
16e7cbfd KS |
395 | splx(s); |
396 | } | |
16e7cbfd | 397 | /* |
af359dea C |
398 | * This routine gets called when validating additions of new routes |
399 | * or deletions of old ones. | |
16e7cbfd | 400 | */ |
af359dea | 401 | x25_rtrequest(cmd, rt, dst) |
c4b47c42 KS |
402 | register struct rtentry *rt; |
403 | struct sockaddr *dst; | |
404 | { | |
405 | register struct llinfo_x25 *lx = (struct llinfo_x25 *)rt->rt_llinfo; | |
406 | register struct sockaddr_x25 *sa =(struct sockaddr_x25 *)rt->rt_gateway; | |
407 | register struct pklcd *lcp; | |
c4b47c42 | 408 | |
af359dea C |
409 | if (rt->rt_flags & RTF_GATEWAY) { |
410 | if (rt->rt_llinfo) | |
411 | RTFREE((struct rtentry *)rt->rt_llinfo); | |
412 | rt->rt_llinfo = (cmd == RTM_ADD) ? | |
413 | (caddr_t)rtalloc1(rt->rt_gateway, 1) : 0; | |
414 | return; | |
c4b47c42 | 415 | } |
af359dea C |
416 | if ((rt->rt_flags & RTF_HOST) == 0) |
417 | return; | |
c4b47c42 | 418 | if (cmd == RTM_DELETE) { |
af359dea C |
419 | while (rt->rt_llinfo) |
420 | x25_lxfree((struct llinfo *)rt->rt_llinfo); | |
421 | x25_rtinvert(RTM_DELETE, rt->rt_gateway, rt); | |
c4b47c42 KS |
422 | return; |
423 | } | |
af359dea C |
424 | if (lx == 0 && (lx = x25_lxalloc(rt)) == 0) |
425 | return; | |
426 | if ((lcp = lx->lx_lcd) && lcp->lcd_state != READY) { | |
427 | /* | |
428 | * This can only happen on a RTM_CHANGE operation | |
429 | * though cmd will be RTM_ADD. | |
430 | */ | |
431 | if (lcp->lcd_ceaddr && | |
432 | Bcmp(rt->rt_gateway, lcp->lcd_ceaddr, | |
433 | lcp->lcd_ceaddr->x25_len) != 0) { | |
434 | x25_rtinvert(RTM_DELETE, lcp->lcd_ceaddr, rt); | |
435 | lcp->lcd_upper = 0; | |
436 | pk_disconnect(lcp); | |
437 | } | |
c4b47c42 KS |
438 | lcp = 0; |
439 | } | |
af359dea C |
440 | x25_rtinvert(RTM_ADD, rt->rt_gateway, rt); |
441 | } | |
442 | ||
443 | int x25_dont_rtinvert = 0; | |
444 | ||
445 | x25_rtinvert(cmd, sa, rt) | |
446 | register struct sockaddr *sa; | |
447 | register struct rtentry *rt; | |
448 | { | |
449 | struct rtentry *rt2 = 0; | |
450 | /* | |
451 | * rt_gateway contains PID indicating which proto | |
452 | * family on the other end, so will be different | |
453 | * from general host route via X.25. | |
454 | */ | |
455 | if (rt->rt_ifp->if_type == IFT_X25DDN || x25_dont_rtinvert) | |
456 | return; | |
457 | if (sa->sa_family != AF_CCITT) | |
c4b47c42 | 458 | return; |
af359dea C |
459 | if (cmd != RTM_DELETE) { |
460 | rtrequest(RTM_ADD, sa, rt_key(rt), x25_dgram_sockmask, | |
461 | RTF_PROTO2, &rt2); | |
462 | if (rt2) { | |
463 | rt2->rt_llinfo = (caddr_t) rt; | |
464 | rt->rt_refcnt++; | |
c4b47c42 | 465 | } |
af359dea | 466 | return; |
c4b47c42 | 467 | } |
af359dea C |
468 | rt2 = rt; |
469 | if ((rt = rtalloc1(sa, 0)) == 0 || | |
470 | (rt->rt_flags & RTF_PROTO2) == 0 || | |
471 | rt->rt_llinfo != (caddr_t)rt2) { | |
472 | printf("x25_rtchange: inverse route screwup\n"); | |
473 | return; | |
474 | } else | |
475 | rt2->rt_refcnt--; | |
476 | rtrequest(RTM_DELETE, sa, rt_key(rt2), x25_dgram_sockmask, | |
477 | 0, (struct rtentry **) 0); | |
c4b47c42 KS |
478 | } |
479 | ||
16e7cbfd KS |
480 | static struct sockaddr_x25 blank_x25 = {sizeof blank_x25, AF_CCITT}; |
481 | /* | |
482 | * IP to X25 address routine copyright ACC, used by permission. | |
483 | */ | |
c4b47c42 KS |
484 | union imp_addr { |
485 | struct in_addr ip; | |
486 | struct imp { | |
487 | u_char s_net; | |
488 | u_char s_host; | |
489 | u_char s_lh; | |
490 | u_char s_impno; | |
491 | } imp; | |
492 | }; | |
493 | ||
af359dea C |
494 | /* |
495 | * The following is totally bogus and here only to preserve | |
496 | * the IP to X.25 translation. | |
497 | */ | |
498 | x25_ddnip_to_ccitt(src, rt) | |
16e7cbfd | 499 | struct sockaddr_in *src; |
af359dea | 500 | register struct rtentry *rt; |
16e7cbfd | 501 | { |
af359dea | 502 | register struct sockaddr_x25 *dst = (struct sockaddr_x25 *)rt->rt_gateway; |
16e7cbfd | 503 | union imp_addr imp_addr; |
4507dea2 KS |
504 | int imp_no, imp_port, temp; |
505 | char *x25addr = dst->x25_addr; | |
16e7cbfd KS |
506 | |
507 | ||
4507dea2 | 508 | imp_addr.ip = src->sin_addr; |
16e7cbfd KS |
509 | *dst = blank_x25; |
510 | if ((imp_addr.imp.s_net & 0x80) == 0x00) { /* class A */ | |
511 | imp_no = imp_addr.imp.s_impno; | |
512 | imp_port = imp_addr.imp.s_host; | |
513 | } else if ((imp_addr.imp.s_net & 0xc0) == 0x80) { /* class B */ | |
514 | imp_no = imp_addr.imp.s_impno; | |
515 | imp_port = imp_addr.imp.s_lh; | |
516 | } else { /* class C */ | |
517 | imp_no = imp_addr.imp.s_impno / 32; | |
518 | imp_port = imp_addr.imp.s_impno % 32; | |
519 | } | |
520 | ||
521 | x25addr[0] = 12; /* length */ | |
522 | /* DNIC is cleared by struct copy above */ | |
523 | ||
524 | if (imp_port < 64) { /* Physical: 0000 0 IIIHH00 [SS] *//* s_impno | |
525 | * -> III, s_host -> HH */ | |
526 | x25addr[5] = 0; /* set flag bit */ | |
527 | x25addr[6] = imp_no / 100; | |
528 | x25addr[7] = (imp_no % 100) / 10; | |
529 | x25addr[8] = imp_no % 10; | |
530 | x25addr[9] = imp_port / 10; | |
531 | x25addr[10] = imp_port % 10; | |
532 | } else { /* Logical: 0000 1 RRRRR00 [SS] *//* s | |
533 | * _host * 256 + s_impno -> RRRRR */ | |
534 | temp = (imp_port << 8) + imp_no; | |
535 | x25addr[5] = 1; | |
536 | x25addr[6] = temp / 10000; | |
537 | x25addr[7] = (temp % 10000) / 1000; | |
538 | x25addr[8] = (temp % 1000) / 100; | |
539 | x25addr[9] = (temp % 100) / 10; | |
540 | x25addr[10] = temp % 10; | |
541 | } | |
542 | } | |
543 | ||
16e7cbfd | 544 | /* |
c4b47c42 KS |
545 | * This routine is a sketch and is not to be believed!!!!! |
546 | * | |
16e7cbfd KS |
547 | * This is a utility routine to be called by x25 devices when a |
548 | * call request is honored with the intent of starting datagram forwarding. | |
549 | */ | |
039be508 | 550 | x25_dg_rtinit(dst, ia, af) |
16e7cbfd | 551 | struct sockaddr_x25 *dst; |
4507dea2 | 552 | register struct x25_ifaddr *ia; |
16e7cbfd KS |
553 | { |
554 | struct sockaddr *sa = 0; | |
4507dea2 KS |
555 | struct rtentry *rt; |
556 | struct in_addr my_addr; | |
af359dea | 557 | static struct sockaddr_in sin = {sizeof(sin), AF_INET}; |
4507dea2 KS |
558 | |
559 | if (ia->ia_ifp->if_type == IFT_X25DDN && af == AF_INET) { | |
16e7cbfd | 560 | /* |
4507dea2 | 561 | * Inverse X25 to IP mapping copyright and courtesy ACC. |
16e7cbfd KS |
562 | */ |
563 | int imp_no, imp_port, temp; | |
564 | union imp_addr imp_addr; | |
565 | { | |
566 | /* | |
567 | * First determine our IP addr for network | |
568 | */ | |
4507dea2 | 569 | register struct in_ifaddr *ina; |
16e7cbfd | 570 | extern struct in_ifaddr *in_ifaddr; |
4507dea2 KS |
571 | |
572 | for (ina = in_ifaddr; ina; ina = ina->ia_next) | |
573 | if (ina->ia_ifp == ia->ia_ifp) { | |
574 | my_addr = ina->ia_addr.sin_addr; | |
16e7cbfd KS |
575 | break; |
576 | } | |
577 | } | |
578 | { | |
579 | ||
580 | register char *x25addr = dst->x25_addr; | |
581 | ||
582 | switch (x25addr[5] & 0x0f) { | |
583 | case 0: /* Physical: 0000 0 IIIHH00 [SS] */ | |
584 | imp_no = | |
585 | ((int) (x25addr[6] & 0x0f) * 100) + | |
586 | ((int) (x25addr[7] & 0x0f) * 10) + | |
587 | ((int) (x25addr[8] & 0x0f)); | |
588 | ||
589 | ||
590 | imp_port = | |
591 | ((int) (x25addr[9] & 0x0f) * 10) + | |
592 | ((int) (x25addr[10] & 0x0f)); | |
593 | break; | |
594 | case 1: /* Logical: 0000 1 RRRRR00 [SS] */ | |
595 | temp = ((int) (x25addr[6] & 0x0f) * 10000) | |
596 | + ((int) (x25addr[7] & 0x0f) * 1000) | |
597 | + ((int) (x25addr[8] & 0x0f) * 100) | |
598 | + ((int) (x25addr[9] & 0x0f) * 10) | |
599 | + ((int) (x25addr[10] & 0x0f)); | |
600 | ||
601 | imp_port = temp >> 8; | |
602 | imp_no = temp & 0xff; | |
603 | break; | |
604 | default: | |
605 | return (0L); | |
606 | } | |
4507dea2 | 607 | imp_addr.ip = my_addr; |
16e7cbfd KS |
608 | if ((imp_addr.imp.s_net & 0x80) == 0x00) { |
609 | /* class A */ | |
610 | imp_addr.imp.s_host = imp_port; | |
611 | imp_addr.imp.s_impno = imp_no; | |
612 | imp_addr.imp.s_lh = 0; | |
613 | } else if ((imp_addr.imp.s_net & 0xc0) == 0x80) { | |
614 | /* class B */ | |
615 | imp_addr.imp.s_lh = imp_port; | |
616 | imp_addr.imp.s_impno = imp_no; | |
617 | } else { | |
618 | /* class C */ | |
619 | imp_addr.imp.s_impno = (imp_no << 5) + imp_port; | |
620 | } | |
621 | } | |
622 | sin.sin_addr = imp_addr.ip; | |
623 | sa = (struct sockaddr *)&sin; | |
624 | } else { | |
625 | /* | |
626 | * This uses the X25 routing table to do inverse | |
627 | * lookup of x25 address to sockaddr. | |
628 | */ | |
16e7cbfd KS |
629 | if (rt = rtalloc1(dst, 0)) { |
630 | sa = rt->rt_gateway; | |
631 | rt->rt_refcnt--; | |
632 | } | |
16e7cbfd KS |
633 | } |
634 | /* | |
635 | * Call to rtalloc1 will create rtentry for reverse path | |
636 | * to callee by virtue of cloning magic and will allocate | |
637 | * space for local control block. | |
638 | */ | |
4507dea2 | 639 | if (sa && (rt = rtalloc1(sa, 1))) |
16e7cbfd KS |
640 | rt->rt_refcnt--; |
641 | } | |
af359dea C |
642 | #ifndef _offsetof |
643 | #define _offsetof(t, m) ((int)((caddr_t)&((t *)0)->m)) | |
644 | #endif | |
645 | struct sockaddr_x25 x25_dgmask = { | |
646 | _offsetof(struct sockaddr_x25, x25_udata[1]), /* _len */ | |
647 | 0, /* _family */ | |
648 | 0, /* _net */ | |
649 | { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, /* _addr */ | |
650 | {0}, /* opts */ | |
651 | -1, /* _udlen */ | |
652 | {-1} /* _udata */ | |
653 | }; | |
654 | int x25_startproto = 1; | |
b84e7ca8 KS |
655 | struct radix_tree_head *x25_rnhead; |
656 | ||
657 | pk_init() | |
658 | { | |
659 | /* | |
660 | * warning, sizeof (struct sockaddr_x25) > 32, | |
661 | * but contains no data of interest beyond 32 | |
662 | */ | |
af359dea C |
663 | struct radix_node *rn_addmask(); |
664 | rn_inithead(&x25_rnhead, 32, AF_CCITT); | |
665 | x25_dgram_sockmask = | |
666 | SA(rn_addmask((caddr_t)&x25_dgmask, 0, 4)->rn_key); | |
667 | if (x25_startproto) { | |
668 | pk_protolisten(0xcc, 1, x25_dgram_incoming); | |
669 | pk_protolisten(0x81, 1, x25_dgram_incoming); | |
670 | } | |
671 | } | |
672 | ||
673 | struct x25_dgproto { | |
674 | u_char spi; | |
675 | u_char spilen; | |
676 | int (*f)(); | |
677 | } x25_dgprototab[] = { | |
678 | #if defined(ISO) && defined(TPCONS) | |
679 | { 0x0, 0, tp_incoming}, | |
680 | #endif | |
681 | { 0xcc, 1, x25_dgram_incoming}, | |
682 | { 0xcd, 1, x25_dgram_incoming}, | |
683 | { 0x81, 1, x25_dgram_incoming}, | |
684 | }; | |
685 | ||
686 | pk_user_protolisten(info) | |
687 | register u_char *info; | |
688 | { | |
689 | register struct x25_dgproto *dp = x25_dgprototab | |
690 | + ((sizeof x25_dgprototab) / (sizeof *dp)); | |
691 | register struct pklcd *lcp; | |
692 | ||
693 | while (dp > x25_dgprototab) | |
694 | if ((--dp)->spi == info[0]) | |
695 | goto gotspi; | |
696 | return ESRCH; | |
697 | ||
698 | gotspi: if (info[1]) | |
699 | return pk_protolisten(dp->spi, dp->spilen, dp->f); | |
700 | for (lcp = pk_listenhead; lcp; lcp = lcp->lcd_listen) | |
701 | if (lcp->lcd_laddr.x25_udlen == dp->spilen && | |
702 | Bcmp(&dp->spi, lcp->lcd_laddr.x25_udata, dp->spilen) == 0) { | |
703 | pk_disconnect(lcp); | |
704 | return 0; | |
705 | } | |
706 | return ESRCH; | |
707 | } | |
708 | ||
709 | /* | |
710 | * This routine transfers an X.25 circuit to or from a routing entry. | |
711 | * If the supplied circuit is * in DATA_TRANSFER state, it is added to the | |
712 | * routing entry. If freshly allocated, it glues back the vc from | |
713 | * the rtentry to the socket. | |
714 | */ | |
715 | pk_rtattach(so, m0) | |
716 | register struct socket *so; | |
717 | struct mbuf *m0; | |
718 | { | |
719 | register struct pklcd *lcp = (struct pklcd *)so->so_pcb; | |
720 | register struct mbuf *m = m0; | |
721 | struct sockaddr *dst = mtod(m, struct sockaddr *); | |
722 | register struct rtentry *rt = rtalloc1(dst, 0); | |
723 | register struct llinfo_x25 *lx; | |
724 | caddr_t cp; | |
725 | #define ROUNDUP(a) \ | |
726 | ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long)) | |
727 | #define transfer_sockbuf(s, f, l) \ | |
728 | while (m = (s)->sb_mb)\ | |
729 | {(s)->sb_mb = m->m_act; m->m_act = 0; sbfree((s), m); f(l, m);} | |
730 | ||
731 | if (rt) | |
732 | rt->rt_refcnt--; | |
733 | cp = (dst->sa_len < m->m_len) ? ROUNDUP(dst->sa_len) + (caddr_t)dst : 0; | |
734 | while (rt && | |
735 | ((cp == 0 && rt_mask(rt) != 0) || | |
736 | (cp != 0 && (rt_mask(rt) == 0 || | |
737 | Bcmp(cp, rt_mask(rt), rt_mask(rt)->sa_len)) != 0))) | |
738 | rt = (struct rtentry *)rt->rt_nodes->rn_dupedkey; | |
739 | if (rt == 0 || (rt->rt_flags & RTF_GATEWAY) || | |
740 | (lx = (struct llinfo_x25 *)rt->rt_llinfo) == 0) | |
741 | return ESRCH; | |
742 | if (lcp == 0) | |
743 | return ENOTCONN; | |
744 | switch (lcp->lcd_state) { | |
745 | default: | |
746 | return ENOTCONN; | |
747 | ||
748 | case READY: | |
749 | /* Detach VC from rtentry */ | |
750 | if (lx->lx_lcd == 0) | |
751 | return ENOTCONN; | |
752 | lcp->lcd_so = 0; | |
753 | pk_close(lcp); | |
754 | lcp = lx->lx_lcd; | |
755 | if (lx->lx_next->lx_rt == rt) | |
756 | x25_lxfree(lx); | |
757 | lcp->lcd_so = so; | |
758 | lcp->lcd_upper = 0; | |
759 | lcp->lcd_upnext = 0; | |
760 | transfer_sockbuf(&lcp->lcd_sb, sbappendrecord, &so->so_snd); | |
761 | soisconnected(so); | |
762 | return 0; | |
763 | ||
764 | case DATA_TRANSFER: | |
765 | /* Add VC to rtentry */ | |
766 | lcp->lcd_so = 0; | |
767 | lcp->lcd_sb = so->so_snd; /* structure copy */ | |
768 | bzero((caddr_t)&so->so_snd, sizeof(so->so_snd)); /* XXXXXX */ | |
769 | so->so_pcb = 0; | |
770 | x25_rtattach(lcp, rt); | |
771 | transfer_sockbuf(&so->so_rcv, x25_ifinput, lcp); | |
772 | soisdisconnected(so); | |
773 | } | |
774 | return 0; | |
775 | } | |
776 | x25_rtattach(lcp0, rt) | |
777 | register struct pklcd *lcp0; | |
778 | struct rtentry *rt; | |
779 | { | |
780 | register struct llinfo_x25 *lx = (struct llinfo_x25 *)rt->rt_llinfo; | |
781 | register struct pklcd *lcp; | |
782 | register struct mbuf *m; | |
783 | if (lcp = lx->lx_lcd) { /* adding an additional VC */ | |
784 | if (lcp->lcd_state == READY) { | |
785 | transfer_sockbuf(&lcp->lcd_sb, pk_output, lcp0); | |
786 | lcp->lcd_upper = 0; | |
787 | pk_close(lcp); | |
788 | } else { | |
789 | lx = x25_lxalloc(rt); | |
790 | if (lx == 0) | |
791 | return ENOBUFS; | |
792 | } | |
793 | } | |
794 | lx->lx_lcd = lcp = lcp0; | |
795 | lcp->lcd_upper = x25_ifinput; | |
796 | lcp->lcd_upnext = (caddr_t)lx; | |
b84e7ca8 | 797 | } |