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 | * |
97565545 | 7 | * @(#)if_x25subr.c 7.11 (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 | ||
49 | extern struct ifnet loif; | |
461586fd KS |
50 | struct llinfo_x25 llinfo_x25 = {&llinfo_x25, &llinfo_x25}; |
51 | int x25_autoconnect = 0; | |
16e7cbfd KS |
52 | |
53 | #define senderr(x) {error = x; goto bad;} | |
461586fd KS |
54 | /* |
55 | * Ancillary routines | |
56 | */ | |
57 | static struct llinfo_x25 * | |
58 | x25_lxalloc(rt) | |
59 | register struct rtentry *rt; | |
60 | { | |
61 | register struct llinfo_x25 *lx; | |
62 | register struct sockaddr *dst = rt_key(rt); | |
63 | register struct ifaddr *ifa; | |
64 | ||
65 | MALLOC(lx, struct llinfo_x25 *, sizeof (*lx), M_PCB, M_NOWAIT); | |
66 | if (lx == 0) | |
67 | return lx; | |
68 | Bzero(lx, sizeof(*lx)); | |
69 | lx->lx_rt = rt; | |
70 | lx->lx_family = dst->sa_family; | |
71 | rt->rt_refcnt++; | |
72 | if (rt->rt_llinfo) | |
73 | insque(lx, (struct llinfo_x25 *)rt->rt_llinfo); | |
74 | else { | |
75 | rt->rt_llinfo = (caddr_t)lx; | |
76 | insque(lx, &llinfo_x25); | |
77 | } | |
78 | for (ifa = rt->rt_ifp->if_addrlist; ifa; ifa = ifa->ifa_next) { | |
79 | if (ifa->ifa_addr->sa_family == AF_CCITT) | |
80 | lx->lx_ia = (struct x25_ifaddr *)ifa; | |
81 | } | |
82 | return lx; | |
83 | } | |
84 | x25_lxfree(lx) | |
85 | register struct llinfo_x25 *lx; | |
86 | { | |
87 | register struct rtentry *rt = lx->lx_rt; | |
88 | register struct pklcd *lcp = lx->lx_lcd; | |
89 | ||
90 | if (lcp) { | |
91 | lcp->lcd_upper = 0; | |
92 | pk_disconnect(lcp); | |
93 | } | |
94 | if ((rt->rt_llinfo == (caddr_t)lx) && (lx->lx_next->lx_rt == rt)) | |
95 | rt->rt_llinfo = (caddr_t)lx->lx_next; | |
96 | else | |
97 | rt->rt_llinfo = 0; | |
98 | RTFREE(rt); | |
99 | remque(lx); | |
100 | FREE(lx, M_PCB); | |
101 | } | |
102 | /* | |
103 | * Process a x25 packet as datagram; | |
104 | */ | |
105 | x25_ifinput(lcp, m) | |
106 | struct pklcd *lcp; | |
107 | register struct mbuf *m; | |
108 | { | |
109 | struct llinfo_x25 *lx = (struct llinfo_x25 *)lcp->lcd_upnext; | |
110 | register struct ifnet *ifp; | |
111 | struct ifqueue *inq; | |
112 | extern struct timeval time; | |
113 | int s, len, isr; | |
114 | ||
115 | if (m == 0 || lcp->lcd_state != DATA_TRANSFER) { | |
116 | x25_connect_callback(lcp, 0); | |
117 | return; | |
118 | } | |
119 | ifp = m->m_pkthdr.rcvif; | |
120 | ifp->if_lastchange = time; | |
121 | switch (m->m_type) { | |
122 | case MT_OOBDATA: | |
123 | if (m) | |
124 | m_freem(m); | |
125 | default: | |
126 | return; | |
127 | ||
128 | case MT_DATA: | |
129 | /* FALLTHROUGH */; | |
130 | } | |
131 | switch (lx->lx_family) { | |
132 | #ifdef INET | |
133 | case AF_INET: | |
134 | isr = NETISR_IP; | |
135 | inq = &ipintrq; | |
136 | break; | |
137 | ||
138 | #endif | |
139 | #ifdef NS | |
140 | case AF_NS: | |
141 | isr = NETISR_NS; | |
142 | inq = &nsintrq; | |
143 | break; | |
144 | ||
145 | #endif | |
146 | #ifdef ISO | |
147 | case AF_ISO: | |
148 | isr = NETISR_ISO; | |
149 | inq = &clnlintrq; | |
150 | break; | |
151 | #endif | |
152 | default: | |
153 | m_freem(m); | |
154 | ifp->if_noproto++; | |
155 | return; | |
156 | } | |
157 | s = splimp(); | |
158 | schednetisr(isr); | |
159 | if (IF_QFULL(inq)) { | |
160 | IF_DROP(inq); | |
161 | m_freem(m); | |
162 | } else { | |
163 | IF_ENQUEUE(inq, m); | |
164 | ifp->if_ibytes += m->m_pkthdr.len; | |
165 | } | |
166 | splx(s); | |
167 | } | |
168 | x25_connect_callback(lcp, m) | |
169 | register struct pklcd *lcp; | |
170 | register struct mbuf *m; | |
171 | { | |
172 | register struct llinfo_x25 *lx = (struct llinfo_x25 *)lcp->lcd_upnext; | |
173 | if (m == 0) | |
174 | goto refused; | |
175 | if (m->m_type != MT_CONTROL) { | |
176 | printf("x25_connect_callback: should panic\n"); | |
177 | goto refused; | |
178 | } | |
179 | switch (pk_decode(mtod(m, struct x25_packet *))) { | |
180 | case CALL_ACCEPTED: | |
181 | lcp->lcd_upper = x25_ifinput; | |
182 | if (lcp->lcd_sb.sb_mb) | |
183 | lcp->lcd_send(lcp); /* XXX start queued packets */ | |
184 | return; | |
185 | default: | |
186 | refused: | |
187 | lcp->lcd_upper = 0; | |
188 | lx->lx_lcd = 0; | |
189 | pk_disconnect(lcp); | |
190 | return; | |
191 | } | |
192 | } | |
16e7cbfd KS |
193 | /* |
194 | * X.25 output routine. | |
195 | */ | |
039be508 KS |
196 | x25_ifoutput(ifp, m0, dst, rt) |
197 | struct ifnet *ifp; | |
16e7cbfd KS |
198 | struct mbuf *m0; |
199 | struct sockaddr *dst; | |
200 | register struct rtentry *rt; | |
201 | { | |
461586fd KS |
202 | register struct mbuf *m; |
203 | register struct llinfo_x25 *lx; | |
039be508 | 204 | struct pklcd *lcp; |
461586fd | 205 | int s, error = 0; |
16e7cbfd | 206 | |
039be508 | 207 | if ((ifp->if_flags & IFF_UP) == 0) |
461586fd | 208 | senderr(ENETDOWN); |
97565545 KS |
209 | while (rt == 0 || (rt->rt_flags & RTF_GATEWAY)) { |
210 | if (rt) { | |
211 | if (rt->rt_llinfo) { | |
212 | rt = (struct rtentry *)rt->rt_llinfo; | |
213 | continue; | |
214 | } | |
215 | dst = rt->rt_gateway; | |
216 | } | |
16e7cbfd | 217 | if ((rt = rtalloc1(dst, 1)) == 0) |
461586fd KS |
218 | senderr(EHOSTUNREACH); |
219 | rt->rt_refcnt--; | |
16e7cbfd KS |
220 | } |
221 | /* | |
222 | * Sanity checks. | |
223 | */ | |
039be508 | 224 | if ((rt->rt_ifp != ifp) || |
16e7cbfd | 225 | (rt->rt_flags & (RTF_CLONING | RTF_GATEWAY)) || |
4507dea2 | 226 | ((lx = (struct llinfo_x25 *)rt->rt_llinfo) == 0)) { |
16e7cbfd KS |
227 | senderr(ENETUNREACH); |
228 | } | |
461586fd KS |
229 | next_circuit: |
230 | lcp = lx->lx_lcd; | |
231 | if (lcp == 0) { | |
232 | lx->lx_lcd = lcp = pk_attach((struct socket *)0); | |
233 | if (lcp == 0) | |
234 | senderr(ENOBUFS); | |
235 | lcp->lcd_upper = x25_connect_callback; | |
236 | lcp->lcd_upnext = (caddr_t)lx; | |
237 | lcp->lcd_packetsize = lx->lx_ia->ia_xc.xc_psize; | |
039be508 | 238 | } |
461586fd KS |
239 | switch (lcp->lcd_state) { |
240 | case READY: | |
97565545 KS |
241 | if (dst->sa_family == AF_INET && |
242 | ifp->if_type == IFT_X25DDN && | |
243 | rt->rt_gateway->sa_family != AF_CCITT) | |
244 | x25_ddnip_to_ccitt(dst, rt); | |
16e7cbfd | 245 | if (rt->rt_gateway->sa_family != AF_CCITT) { |
16e7cbfd | 246 | if ((rt->rt_flags & RTF_XRESOLVE) == 0) |
461586fd KS |
247 | senderr(EHOSTUNREACH); |
248 | } else if (x25_autoconnect) | |
249 | error = pk_connect(lcp, | |
250 | (struct sockaddr_x25 *)rt->rt_gateway); | |
251 | if (error) | |
252 | senderr(error); | |
16e7cbfd | 253 | /* FALLTHROUGH */ |
461586fd KS |
254 | case SENT_CALL: |
255 | case DATA_TRANSFER: | |
256 | if (sbspace(&lcp->lcd_sb) < 0) { | |
257 | lx = lx->lx_next; | |
258 | if (lx->lx_rt != rt) | |
259 | senderr(ENOSPC); | |
260 | goto next_circuit; | |
261 | } | |
262 | if (lx->lx_ia) | |
263 | lcp->lcd_dg_timer = | |
264 | lx->lx_ia->ia_xc.xc_dg_idletimo; | |
6c58e9b2 | 265 | pk_send(lcp, m); |
039be508 | 266 | break; |
16e7cbfd KS |
267 | default: |
268 | /* | |
269 | * We count on the timer routine to close idle | |
270 | * connections, if there are not enough circuits to go | |
271 | * around. | |
272 | * | |
273 | * So throw away data for now. | |
274 | * After we get it all working, we'll rewrite to handle | |
275 | * actively closing connections (other than by timers), | |
276 | * when circuits get tight. | |
277 | * | |
278 | * In the DDN case, the imp itself closes connections | |
279 | * under heavy load. | |
280 | */ | |
281 | error = ENOBUFS; | |
282 | bad: | |
283 | if (m) | |
284 | m_freem(m); | |
285 | } | |
16e7cbfd KS |
286 | return (error); |
287 | } | |
288 | ||
289 | /* | |
039be508 | 290 | * Simpleminded timer routine. |
16e7cbfd | 291 | */ |
039be508 KS |
292 | x25_iftimeout(ifp) |
293 | struct ifnet *ifp; | |
16e7cbfd | 294 | { |
039be508 KS |
295 | register struct pkcb *pkcb = 0; |
296 | register struct ifaddr *ifa; | |
297 | register struct pklcd **lcpp, *lcp; | |
16e7cbfd KS |
298 | int s = splimp(); |
299 | ||
461586fd | 300 | for (ifa = ifp->if_addrlist; ifa && !pkcb; ifa = ifa->ifa_next) { |
039be508 | 301 | if (ifa->ifa_addr->sa_family == AF_CCITT) |
461586fd | 302 | pkcb = &((struct x25_ifaddr *)ifa)->ia_pkcb; |
039be508 | 303 | } |
039be508 KS |
304 | if (pkcb) |
305 | for (lcpp = pkcb->pk_chan + pkcb->pk_maxlcn; | |
c4b47c42 | 306 | --lcpp > pkcb->pk_chan;) |
039be508 KS |
307 | if ((lcp = *lcpp) && |
308 | lcp->lcd_state == DATA_TRANSFER && | |
4507dea2 | 309 | (lcp->lcd_flags & X25_DG_CIRCUIT) && |
c4b47c42 | 310 | (lcp->lcd_dg_timer && --lcp->lcd_dg_timer == 0)) { |
461586fd | 311 | lcp->lcd_upper(lcp, 0); |
c4b47c42 | 312 | } |
16e7cbfd KS |
313 | splx(s); |
314 | } | |
16e7cbfd | 315 | /* |
461586fd | 316 | * This routine gets called when validating additions of new routes |
97565545 | 317 | * or deletions of old ones. |
c4b47c42 KS |
318 | */ |
319 | x25_ifrtchange(cmd, rt, dst) | |
320 | register struct rtentry *rt; | |
321 | struct sockaddr *dst; | |
322 | { | |
323 | register struct llinfo_x25 *lx = (struct llinfo_x25 *)rt->rt_llinfo; | |
324 | register struct sockaddr_x25 *sa =(struct sockaddr_x25 *)rt->rt_gateway; | |
325 | register struct pklcd *lcp; | |
c4b47c42 KS |
326 | #define SA(p) ((struct sockaddr *)(p)) |
327 | ||
461586fd KS |
328 | if (rt->rt_flags & RTF_GATEWAY) { |
329 | if (rt->rt_llinfo) | |
330 | RTFREE((struct rtentry *)rt->rt_llinfo); | |
331 | rt->rt_llinfo = (cmd == RTM_ADD) ? | |
332 | (caddr_t)rtalloc1(rt->rt_gateway, 1) : 0; | |
6c58e9b2 KS |
333 | return; |
334 | } | |
97565545 KS |
335 | if ((rt->rt_flags & RTF_HOST) == 0) |
336 | return; | |
461586fd KS |
337 | if (cmd == RTM_DELETE) { |
338 | while (rt->rt_llinfo) | |
339 | x25_lxfree((struct llinfo *)rt->rt_llinfo); | |
340 | x25_rtinvert(RTM_DELETE, rt->rt_gateway, rt); | |
c4b47c42 KS |
341 | return; |
342 | } | |
97565545 KS |
343 | if (lx == 0 && (lx = x25_lxalloc(rt)) == 0) |
344 | return; | |
461586fd KS |
345 | if ((lcp = lx->lx_lcd) && lcp->lcd_state != READY) { |
346 | /* | |
347 | * This can only happen on a RTM_CHANGE operation | |
348 | * though cmd will be RTM_ADD. | |
349 | */ | |
350 | if (lcp->lcd_ceaddr && | |
351 | Bcmp(rt->rt_gateway, lcp->lcd_ceaddr, | |
352 | lcp->lcd_ceaddr->x25_len) != 0) { | |
353 | x25_rtinvert(RTM_DELETE, lcp->lcd_ceaddr, rt); | |
354 | lcp->lcd_upper = 0; | |
355 | pk_disconnect(lcp); | |
356 | } | |
c4b47c42 KS |
357 | lcp = 0; |
358 | } | |
461586fd KS |
359 | x25_rtinvert(RTM_ADD, rt->rt_gateway, rt); |
360 | } | |
361 | ||
97565545 KS |
362 | int x25_dont_rtinvert = 1; |
363 | ||
461586fd KS |
364 | x25_rtinvert(cmd, sa, rt) |
365 | register struct sockaddr *sa; | |
366 | register struct rtentry *rt; | |
367 | { | |
368 | struct rtentry *rt2 = 0; | |
369 | /* | |
370 | * rt_gateway contains PID indicating which proto | |
371 | * family on the other end, so will be different | |
372 | * from general host route via X.25. | |
373 | */ | |
97565545 KS |
374 | if (x25_dont_rtinvert) |
375 | return; | |
c4b47c42 KS |
376 | if (rt->rt_ifp->if_type == IFT_X25DDN) |
377 | return; | |
461586fd KS |
378 | if (sa->sa_family != AF_CCITT) |
379 | return; | |
380 | if (cmd == RTM_ADD) { | |
381 | rtrequest(RTM_ADD, sa, rt_key(rt), SA(0), | |
382 | RTF_HOST|RTF_PROTO1, &rt2); | |
383 | if (rt2) { | |
384 | rt2->rt_llinfo = (caddr_t) rt; | |
385 | rt->rt_refcnt++; | |
c4b47c42 | 386 | } |
461586fd | 387 | return; |
c4b47c42 | 388 | } |
461586fd KS |
389 | rt2 = rt; |
390 | if ((rt = rtalloc1(sa, 0)) == 0 || | |
391 | (rt->rt_flags & RTF_PROTO1) == 0 || | |
392 | rt->rt_llinfo != (caddr_t)rt) { | |
393 | printf("x25_rtchange: inverse route screwup\n"); | |
394 | return; | |
395 | } else | |
396 | rt2->rt_refcnt--; | |
397 | rtrequest(RTM_DELETE, rt->rt_gateway, rt_key(rt), | |
398 | SA(0), 0, (struct rtentry **) 0); | |
c4b47c42 KS |
399 | } |
400 | ||
16e7cbfd KS |
401 | static struct sockaddr_x25 blank_x25 = {sizeof blank_x25, AF_CCITT}; |
402 | /* | |
403 | * IP to X25 address routine copyright ACC, used by permission. | |
404 | */ | |
c4b47c42 KS |
405 | union imp_addr { |
406 | struct in_addr ip; | |
407 | struct imp { | |
408 | u_char s_net; | |
409 | u_char s_host; | |
410 | u_char s_lh; | |
411 | u_char s_impno; | |
412 | } imp; | |
413 | }; | |
414 | ||
461586fd KS |
415 | /* |
416 | * The following is totally bogus and here only to preserve | |
417 | * the IP to X.25 translation. | |
418 | */ | |
419 | x25_ddnip_to_ccitt(src, rt) | |
16e7cbfd | 420 | struct sockaddr_in *src; |
461586fd | 421 | register struct rtentry *rt; |
16e7cbfd | 422 | { |
461586fd | 423 | register struct sockaddr_x25 *dst = (struct sockaddr_x25 *)rt->rt_gateway; |
16e7cbfd | 424 | union imp_addr imp_addr; |
4507dea2 KS |
425 | int imp_no, imp_port, temp; |
426 | char *x25addr = dst->x25_addr; | |
16e7cbfd KS |
427 | |
428 | ||
4507dea2 | 429 | imp_addr.ip = src->sin_addr; |
16e7cbfd KS |
430 | *dst = blank_x25; |
431 | if ((imp_addr.imp.s_net & 0x80) == 0x00) { /* class A */ | |
432 | imp_no = imp_addr.imp.s_impno; | |
433 | imp_port = imp_addr.imp.s_host; | |
434 | } else if ((imp_addr.imp.s_net & 0xc0) == 0x80) { /* class B */ | |
435 | imp_no = imp_addr.imp.s_impno; | |
436 | imp_port = imp_addr.imp.s_lh; | |
437 | } else { /* class C */ | |
438 | imp_no = imp_addr.imp.s_impno / 32; | |
439 | imp_port = imp_addr.imp.s_impno % 32; | |
440 | } | |
441 | ||
442 | x25addr[0] = 12; /* length */ | |
443 | /* DNIC is cleared by struct copy above */ | |
444 | ||
445 | if (imp_port < 64) { /* Physical: 0000 0 IIIHH00 [SS] *//* s_impno | |
446 | * -> III, s_host -> HH */ | |
447 | x25addr[5] = 0; /* set flag bit */ | |
448 | x25addr[6] = imp_no / 100; | |
449 | x25addr[7] = (imp_no % 100) / 10; | |
450 | x25addr[8] = imp_no % 10; | |
451 | x25addr[9] = imp_port / 10; | |
452 | x25addr[10] = imp_port % 10; | |
453 | } else { /* Logical: 0000 1 RRRRR00 [SS] *//* s | |
454 | * _host * 256 + s_impno -> RRRRR */ | |
455 | temp = (imp_port << 8) + imp_no; | |
456 | x25addr[5] = 1; | |
457 | x25addr[6] = temp / 10000; | |
458 | x25addr[7] = (temp % 10000) / 1000; | |
459 | x25addr[8] = (temp % 1000) / 100; | |
460 | x25addr[9] = (temp % 100) / 10; | |
461 | x25addr[10] = temp % 10; | |
462 | } | |
463 | } | |
464 | ||
16e7cbfd | 465 | /* |
c4b47c42 KS |
466 | * This routine is a sketch and is not to be believed!!!!! |
467 | * | |
16e7cbfd KS |
468 | * This is a utility routine to be called by x25 devices when a |
469 | * call request is honored with the intent of starting datagram forwarding. | |
470 | */ | |
039be508 | 471 | x25_dg_rtinit(dst, ia, af) |
16e7cbfd | 472 | struct sockaddr_x25 *dst; |
4507dea2 | 473 | register struct x25_ifaddr *ia; |
16e7cbfd KS |
474 | { |
475 | struct sockaddr *sa = 0; | |
4507dea2 KS |
476 | struct rtentry *rt; |
477 | struct in_addr my_addr; | |
461586fd | 478 | static struct sockaddr_in sin = {sizeof(sin), AF_INET}; |
4507dea2 KS |
479 | |
480 | if (ia->ia_ifp->if_type == IFT_X25DDN && af == AF_INET) { | |
16e7cbfd | 481 | /* |
4507dea2 | 482 | * Inverse X25 to IP mapping copyright and courtesy ACC. |
16e7cbfd KS |
483 | */ |
484 | int imp_no, imp_port, temp; | |
485 | union imp_addr imp_addr; | |
486 | { | |
487 | /* | |
488 | * First determine our IP addr for network | |
489 | */ | |
4507dea2 | 490 | register struct in_ifaddr *ina; |
16e7cbfd | 491 | extern struct in_ifaddr *in_ifaddr; |
4507dea2 KS |
492 | |
493 | for (ina = in_ifaddr; ina; ina = ina->ia_next) | |
494 | if (ina->ia_ifp == ia->ia_ifp) { | |
495 | my_addr = ina->ia_addr.sin_addr; | |
16e7cbfd KS |
496 | break; |
497 | } | |
498 | } | |
499 | { | |
500 | ||
501 | register char *x25addr = dst->x25_addr; | |
502 | ||
503 | switch (x25addr[5] & 0x0f) { | |
504 | case 0: /* Physical: 0000 0 IIIHH00 [SS] */ | |
505 | imp_no = | |
506 | ((int) (x25addr[6] & 0x0f) * 100) + | |
507 | ((int) (x25addr[7] & 0x0f) * 10) + | |
508 | ((int) (x25addr[8] & 0x0f)); | |
509 | ||
510 | ||
511 | imp_port = | |
512 | ((int) (x25addr[9] & 0x0f) * 10) + | |
513 | ((int) (x25addr[10] & 0x0f)); | |
514 | break; | |
515 | case 1: /* Logical: 0000 1 RRRRR00 [SS] */ | |
516 | temp = ((int) (x25addr[6] & 0x0f) * 10000) | |
517 | + ((int) (x25addr[7] & 0x0f) * 1000) | |
518 | + ((int) (x25addr[8] & 0x0f) * 100) | |
519 | + ((int) (x25addr[9] & 0x0f) * 10) | |
520 | + ((int) (x25addr[10] & 0x0f)); | |
521 | ||
522 | imp_port = temp >> 8; | |
523 | imp_no = temp & 0xff; | |
524 | break; | |
525 | default: | |
526 | return (0L); | |
527 | } | |
4507dea2 | 528 | imp_addr.ip = my_addr; |
16e7cbfd KS |
529 | if ((imp_addr.imp.s_net & 0x80) == 0x00) { |
530 | /* class A */ | |
531 | imp_addr.imp.s_host = imp_port; | |
532 | imp_addr.imp.s_impno = imp_no; | |
533 | imp_addr.imp.s_lh = 0; | |
534 | } else if ((imp_addr.imp.s_net & 0xc0) == 0x80) { | |
535 | /* class B */ | |
536 | imp_addr.imp.s_lh = imp_port; | |
537 | imp_addr.imp.s_impno = imp_no; | |
538 | } else { | |
539 | /* class C */ | |
540 | imp_addr.imp.s_impno = (imp_no << 5) + imp_port; | |
541 | } | |
542 | } | |
543 | sin.sin_addr = imp_addr.ip; | |
544 | sa = (struct sockaddr *)&sin; | |
545 | } else { | |
546 | /* | |
547 | * This uses the X25 routing table to do inverse | |
548 | * lookup of x25 address to sockaddr. | |
549 | */ | |
16e7cbfd KS |
550 | if (rt = rtalloc1(dst, 0)) { |
551 | sa = rt->rt_gateway; | |
552 | rt->rt_refcnt--; | |
553 | } | |
16e7cbfd KS |
554 | } |
555 | /* | |
556 | * Call to rtalloc1 will create rtentry for reverse path | |
557 | * to callee by virtue of cloning magic and will allocate | |
558 | * space for local control block. | |
559 | */ | |
4507dea2 | 560 | if (sa && (rt = rtalloc1(sa, 1))) |
16e7cbfd KS |
561 | rt->rt_refcnt--; |
562 | } | |
b84e7ca8 KS |
563 | |
564 | struct radix_tree_head *x25_rnhead; | |
565 | ||
566 | pk_init() | |
567 | { | |
568 | /* | |
569 | * warning, sizeof (struct sockaddr_x25) > 32, | |
570 | * but contains no data of interest beyond 32 | |
571 | */ | |
6c58e9b2 | 572 | rn_inithead(&x25_rnhead, 32, AF_CCITT); |
b84e7ca8 | 573 | } |
461586fd KS |
574 | /* |
575 | * This routine steals a virtual circuit from a socket, | |
576 | * and glues it to a routing entry. It wouldn't be hard | |
577 | * to extend this to a routine that stole back the vc from | |
578 | * rtentry. | |
579 | */ | |
580 | pk_rtattach(so, m0) | |
581 | register struct socket *so; | |
582 | struct mbuf *m0; | |
583 | { | |
584 | register struct pklcd *lcp = (struct pklcd *)so->so_pcb; | |
585 | register struct mbuf *m = m0; | |
586 | struct sockaddr *dst = mtod(m, struct sockaddr *); | |
587 | register struct rtentry *rt = rtalloc1(dst, 0); | |
588 | register struct llinfo_x25 *lx; | |
589 | caddr_t cp; | |
590 | #define ROUNDUP(a) \ | |
591 | ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long)) | |
592 | #define transfer_sockbuf(s, f, l) \ | |
593 | while (m = (s)->sb_mb) {(s)->sb_mb = m->m_act; sbfree((s), m); f(l, m);} | |
594 | ||
595 | if (rt) | |
596 | rt->rt_refcnt--; | |
597 | cp = (dst->sa_len < m->m_len) ? ROUNDUP(dst->sa_len) + (caddr_t)dst : 0; | |
598 | while (rt && | |
599 | ((cp == 0 && rt_mask(rt) != 0) || | |
600 | (cp != 0 && (rt_mask(rt) == 0 || | |
601 | Bcmp(cp, rt_mask(rt), rt_mask(rt)->sa_len)) != 0))) | |
602 | rt = (struct rtentry *)rt->rt_nodes->rn_dupedkey; | |
603 | if (rt == 0 || (rt->rt_flags & RTF_GATEWAY) || | |
604 | (lx = (struct llinfo_x25 *)rt->rt_llinfo) == 0) | |
605 | return ESRCH; | |
606 | if (lcp == 0 || lcp->lcd_state != DATA_TRANSFER) | |
607 | return ENOTCONN; | |
608 | if (lcp = lx->lx_lcd) { /* adding an additional VC */ | |
609 | if (lcp->lcd_state == READY) { | |
610 | transfer_sockbuf(&lcp->lcd_sb, pk_output, | |
611 | (struct pklcd *)so->so_pcb); | |
612 | lcp->lcd_upper = 0; | |
613 | pk_close(lcp); | |
614 | } else { | |
615 | lx = x25_lxalloc(rt); | |
616 | if (lx == 0) | |
617 | return ENOBUFS; | |
618 | } | |
619 | } | |
620 | lx->lx_lcd = lcp = (struct pklcd *)so->so_pcb; | |
621 | lcp->lcd_so = 0; | |
622 | lcp->lcd_sb = so->so_snd; /* structure copy */ | |
623 | lcp->lcd_upper = x25_ifinput; | |
624 | lcp->lcd_upnext = (caddr_t)lx; | |
625 | transfer_sockbuf(&so->so_rcv, x25_ifinput, lcp); | |
626 | so->so_pcb = 0; | |
627 | bzero((caddr_t)&so->so_snd, sizeof(so->so_snd)); /* XXXXXX */ | |
628 | soisdisconnected(so); | |
629 | return (0); | |
630 | } |