Commit | Line | Data |
---|---|---|
3b1d357b KS |
1 | /*********************************************************** |
2 | Copyright IBM Corporation 1987 | |
3 | ||
4 | All Rights Reserved | |
5 | ||
6 | Permission to use, copy, modify, and distribute this software and its | |
7 | documentation for any purpose and without fee is hereby granted, | |
8 | provided that the above copyright notice appear in all copies and that | |
9 | both that copyright notice and this permission notice appear in | |
10 | supporting documentation, and that the name of IBM not be | |
11 | used in advertising or publicity pertaining to distribution of the | |
12 | software without specific, written prior permission. | |
13 | ||
14 | IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING | |
15 | ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL | |
16 | IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR | |
17 | ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, | |
18 | WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, | |
19 | ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS | |
20 | SOFTWARE. | |
21 | ||
22 | ******************************************************************/ | |
23 | ||
24 | /* | |
25 | * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison | |
26 | */ | |
27 | /* | |
28 | * $Header: if_cons.c,v 4.7 88/08/11 15:52:55 nhall Exp $ | |
29 | * $Source: /usr/argo/sys/netiso/RCS/if_cons.c,v $ | |
30 | * | |
31 | * cons.c - Connection Oriented Network Service: | |
32 | * including support for a) user transport-level service, | |
33 | * b) COSNS below CLNP, and c) CONS below TP. | |
3b1d357b KS |
34 | |
35 | #ifndef lint | |
36 | static char *rcsid = "$Header: if_cons.c,v 4.7 88/08/11 15:52:55 nhall Exp $"; | |
37 | #endif lint | |
194a383a | 38 | */ |
3b1d357b | 39 | |
194a383a KS |
40 | #ifdef TPCONS |
41 | #ifdef KERNEL | |
3b1d357b KS |
42 | #ifdef ARGO_DEBUG |
43 | #define Static | |
44 | unsigned LAST_CALL_PCB; | |
45 | #else ARGO_DEBUG | |
46 | #define Static static | |
47 | #endif ARGO_DEBUG | |
48 | ||
3b1d357b | 49 | |
3b1d357b | 50 | |
194a383a | 51 | #ifndef SOCK_STREAM |
3b1d357b KS |
52 | #include "param.h" |
53 | #include "systm.h" | |
54 | #include "mbuf.h" | |
55 | #include "protosw.h" | |
56 | #include "socket.h" | |
57 | #include "socketvar.h" | |
58 | #include "errno.h" | |
59 | #include "ioctl.h" | |
c3e97825 | 60 | #include "tsleep.h" |
3b1d357b KS |
61 | |
62 | #include "../net/if.h" | |
63 | #include "../net/netisr.h" | |
64 | #include "../net/route.h" | |
65 | ||
194a383a KS |
66 | #include "iso_errno.h" |
67 | #include "argo_debug.h" | |
68 | #include "tp_trace.h" | |
69 | #include "iso.h" | |
70 | #include "cons.h" | |
71 | #include "iso_pcb.h" | |
72 | ||
73 | #include "../netccitt/x25.h" | |
74 | #include "../netccitt/pk.h" | |
75 | #include "../netccitt/pk_var.h" | |
76 | #endif | |
3b1d357b KS |
77 | |
78 | #ifdef ARGO_DEBUG | |
79 | #define MT_XCONN 0x50 | |
80 | #define MT_XCLOSE 0x51 | |
81 | #define MT_XCONFIRM 0x52 | |
82 | #define MT_XDATA 0x53 | |
83 | #define MT_XHEADER 0x54 | |
84 | #else | |
85 | #define MT_XCONN MT_DATA | |
86 | #define MT_XCLOSE MT_DATA | |
87 | #define MT_XCONFIRM MT_DATA | |
88 | #define MT_XDATA MT_DATA | |
89 | #define MT_XHEADER MT_HEADER | |
90 | #endif ARGO_DEBUG | |
91 | ||
92 | #define DONTCLEAR -1 | |
93 | ||
94 | /********************************************************************* | |
194a383a | 95 | * cons.c - CONS interface to the x.25 layer |
3b1d357b KS |
96 | * |
97 | * TODO: figure out what resources we might run out of besides mbufs. | |
98 | * If we run out of any of them (including mbufs) close and recycle | |
99 | * lru x% of the connections, for some parameter x. | |
100 | * | |
194a383a | 101 | * There are 2 interfaces from above: |
3b1d357b KS |
102 | * 1) from TP0: |
103 | * cons CO network service | |
104 | * TP associates a transport connection with a network connection. | |
105 | * cons_output( isop, m, len, isdgm==0 ) | |
106 | * co_flags == 0 | |
194a383a | 107 | * 2) from TP4: |
3b1d357b KS |
108 | * It's a datagram service, like clnp is. - even though it calls |
109 | * cons_output( isop, m, len, isdgm==1 ) | |
110 | * it eventually goes through | |
111 | * cosns_output(ifp, m, dst). | |
112 | * TP4 permits multiplexing (reuse, possibly simultaneously) of the | |
113 | * network connections. | |
114 | * This means that many sockets (many tpcbs) may be associated with | |
194a383a | 115 | * this pklcd, hence cannot have a back ptr from pklcd to a tpcb. |
3b1d357b | 116 | * co_flags & CONSF_DGM |
194a383a | 117 | * co_socket is null since there may be many sockets that use this pklcd. |
3b1d357b KS |
118 | * |
119 | NOTE: | |
120 | streams would really be nice. sigh. | |
3b1d357b KS |
121 | NOTE: |
122 | PVCs could be handled by config-ing a cons with an address and with the | |
123 | IFF_POINTTOPOINT flag on. This code would then have to skip the | |
124 | connection setup stuff for pt-to-pt links. | |
3b1d357b KS |
125 | |
126 | ||
127 | *********************************************************************/ | |
128 | ||
3b1d357b KS |
129 | |
130 | #define CONS_IFQMAXLEN 5 | |
131 | ||
3b1d357b KS |
132 | |
133 | /* protosw pointers for getting to higher layer */ | |
134 | Static struct protosw *CLNP_proto; | |
135 | Static struct protosw *TP_proto; | |
136 | Static struct protosw *X25_proto; | |
137 | Static int issue_clear_req(); | |
138 | ||
139 | #ifndef PHASEONE | |
140 | extern struct ifaddr *ifa_ifwithnet(); | |
141 | #endif PHASEONE | |
142 | ||
143 | extern struct ifaddr *ifa_ifwithaddr(); | |
144 | ||
145 | Static struct socket dummysocket; /* for use by cosns */ | |
146 | ||
147 | extern struct isopcb tp_isopcb; /* chain of all TP pcbs */ | |
3b1d357b KS |
148 | struct isopcb tp_incoming_pending; /* incoming connections |
149 | for TP, pending */ | |
150 | ||
151 | struct isopcb *Xpcblist[] = { | |
3b1d357b KS |
152 | &tp_incoming_pending, |
153 | &tp_isopcb, | |
154 | (struct isopcb *)0 | |
155 | }; | |
156 | ||
157 | Static int parse_facil(), NSAPtoDTE(), make_partial_x25_packet(); | |
158 | Static int FACILtoNSAP(), DTEtoNSAP(); | |
194a383a | 159 | Static struct pklcd *cons_chan_to_pcb(); |
3b1d357b KS |
160 | |
161 | #define HIGH_NIBBLE 1 | |
162 | #define LOW_NIBBLE 0 | |
163 | ||
164 | /* | |
165 | * NAME: nibble_copy() | |
166 | * FUNCTION and ARGUMENTS: | |
167 | * copies (len) nibbles from (src_octet), high or low nibble | |
168 | * to (dst_octet), high or low nibble, | |
169 | * src_nibble & dst_nibble should be: | |
170 | * HIGH_NIBBLE (1) if leftmost 4 bits/ most significant nibble | |
171 | * LOW_NIBBLE (0) if rightmost 4 bits/ least significant nibble | |
172 | * RETURNS: VOID | |
173 | */ | |
174 | void | |
194a383a | 175 | nibble_copy(src_octet, src_nibble, dst_octet, dst_nibble, len) |
3b1d357b KS |
176 | register char *src_octet; |
177 | register char *dst_octet; | |
178 | register unsigned src_nibble; | |
179 | register unsigned dst_nibble; | |
180 | int len; | |
181 | { | |
182 | ||
183 | register i; | |
184 | register unsigned dshift, sshift; | |
185 | ||
186 | IFDEBUG(D_CADDR) | |
187 | printf("nibble_copy ( 0x%x, 0x%x, 0x%x, 0x%x 0x%x)\n", | |
188 | src_octet, src_nibble, dst_octet, dst_nibble, len); | |
189 | ENDDEBUG | |
190 | #define SHIFT 0x4 | |
191 | ||
192 | dshift = dst_nibble << 2; | |
193 | sshift = src_nibble << 2; | |
194 | ||
195 | for (i=0; i<len; i++) { | |
196 | /* clear dst_nibble */ | |
197 | *dst_octet &= ~(0xf<< dshift); | |
198 | ||
199 | /* set dst nibble */ | |
200 | *dst_octet |= ( 0xf & (*src_octet >> sshift))<< dshift; | |
201 | ||
202 | dshift ^= SHIFT; | |
203 | sshift ^= SHIFT; | |
204 | src_nibble = 1-src_nibble; | |
205 | dst_nibble = 1-dst_nibble; | |
206 | src_octet += src_nibble; | |
207 | dst_octet += dst_nibble; | |
208 | } | |
209 | IFDEBUG(D_CADDR) | |
210 | printf("nibble_copy DONE\n"); | |
211 | ENDDEBUG | |
212 | } | |
213 | ||
214 | /* | |
215 | * NAME: nibble_match() | |
216 | * FUNCTION and ARGUMENTS: | |
217 | * compares src_octet/src_nibble and dst_octet/dst_nibble for len nibbles. | |
218 | * RETURNS: 0 if they differ, 1 if they are the same. | |
219 | */ | |
220 | int | |
221 | nibble_match( src_octet, src_nibble, dst_octet, dst_nibble, len) | |
222 | register char *src_octet; | |
223 | register char *dst_octet; | |
224 | register unsigned src_nibble; | |
225 | register unsigned dst_nibble; | |
226 | int len; | |
227 | { | |
228 | ||
229 | register i; | |
230 | register unsigned dshift, sshift; | |
231 | u_char nibble_a, nibble_b; | |
232 | ||
233 | IFDEBUG(D_CADDR) | |
234 | printf("nibble_match ( 0x%x, 0x%x, 0x%x, 0x%x 0x%x)\n", | |
235 | src_octet, src_nibble, dst_octet, dst_nibble, len); | |
236 | ENDDEBUG | |
237 | #define SHIFT 0x4 | |
238 | ||
239 | dshift = dst_nibble << 2; | |
240 | sshift = src_nibble << 2; | |
241 | ||
242 | for (i=0; i<len; i++) { | |
243 | nibble_b = ((*dst_octet)>>dshift) & 0xf; | |
244 | nibble_a = ( 0xf & (*src_octet >> sshift)); | |
194a383a | 245 | if (nibble_b != nibble_a) |
3b1d357b KS |
246 | return 0; |
247 | ||
248 | dshift ^= SHIFT; | |
249 | sshift ^= SHIFT; | |
250 | src_nibble = 1-src_nibble; | |
251 | dst_nibble = 1-dst_nibble; | |
252 | src_octet += src_nibble; | |
253 | dst_octet += dst_nibble; | |
254 | } | |
255 | IFDEBUG(D_CADDR) | |
256 | printf("nibble_match DONE\n"); | |
257 | ENDDEBUG | |
258 | return 1; | |
259 | } | |
260 | ||
3b1d357b KS |
261 | /* |
262 | **************************** NET PROTOCOL cons *************************** | |
263 | */ | |
3b1d357b KS |
264 | /* |
265 | * NAME: cons_init() | |
266 | * CALLED FROM: | |
267 | * autoconf | |
268 | * FUNCTION: | |
269 | * initialize the protocol | |
270 | */ | |
271 | cons_init() | |
272 | { | |
194a383a | 273 | int tp_incoming(), clnp_incoming(); |
3b1d357b | 274 | |
194a383a KS |
275 | |
276 | CLNP_proto = pffindproto(AF_ISO, ISOPROTO_CLNP, SOCK_DGRAM); | |
277 | X25_proto = pffindproto(AF_ISO, ISOPROTO_X25, SOCK_STREAM); | |
278 | TP_proto = pffindproto(AF_ISO, ISOPROTO_TP0, SOCK_SEQPACKET); | |
3b1d357b | 279 | IFDEBUG(D_CCONS) |
194a383a KS |
280 | printf("cons_init end : cnlp_proto 0x%x cons proto 0x%x tp proto 0x%x\n", |
281 | CLNP_proto, X25_proto, TP_proto); | |
3b1d357b | 282 | ENDDEBUG |
3b1d357b | 283 | #ifdef notdef |
194a383a KS |
284 | pk_protolisten(0x81, 0, clnp_incoming); |
285 | pk_protolisten(0x82, 0, esis_incoming); | |
286 | pk_protolisten(0x84, 0, tp8878_A_incoming); | |
287 | #endif | |
288 | pk_protolisten(0, 0, tp_incoming); | |
3b1d357b KS |
289 | } |
290 | ||
194a383a KS |
291 | tp_incoming(lcp, m0) |
292 | struct pklcd *lcp; | |
293 | struct mbuf *m0; | |
294 | { | |
295 | register struct mbuf *m = m0->m_next; /* m0 has calling sockaddr_x25 */ | |
296 | register struct isopcb *isop; | |
297 | extern struct isopcb tp_isopcb; | |
298 | int cons_tpinput(); | |
3b1d357b | 299 | |
194a383a KS |
300 | if (iso_pcballoc((struct socket *)0, &tp_incoming_pending)) { |
301 | m_freem(m); | |
302 | pk_clear(lcp); | |
303 | return; | |
304 | } | |
305 | isop = tp_incoming_pending.isop_next; | |
306 | pk_output(lcp); /* Confirms call */ | |
307 | lcp->lcd_upper = cons_tpinput; | |
308 | lcp->lcd_upnext = (caddr_t)isop; | |
309 | isop->isop_chan = (caddr_t)lcp; | |
310 | isop->isop_laddr = &isop->isop_sladdr; | |
311 | isop->isop_faddr = &isop->isop_sfaddr; | |
312 | DTEtoNSAP(isop->isop_laddr, &lcp->lcd_laddr); | |
313 | DTEtoNSAP(isop->isop_faddr, &lcp->lcd_faddr); | |
314 | parse_facil(isop, lcp, &(mtod(m, struct x25_packet *)->packet_data), | |
315 | m->m_pkthdr.len - PKHEADERLN); | |
316 | m_freem(m); | |
317 | } | |
318 | ||
319 | cons_tpinput(lcp, m0) | |
320 | struct mbuf *m0; | |
321 | struct pklcd *lcp; | |
322 | { | |
323 | register struct isopcb *isop = (struct isopcb *)lcp->lcd_upnext; | |
324 | register struct x25_packet *xp; | |
325 | int cmd; | |
3b1d357b | 326 | |
194a383a KS |
327 | switch(m0->m_type) { |
328 | case MT_DATA: | |
329 | case MT_OOBDATA: | |
330 | tpcons_input(m0, isop->isop_faddr, isop->isop_laddr, | |
331 | (struct socket *)0, (caddr_t)lcp); | |
332 | ||
333 | case MT_CONTROL: | |
334 | switch (pk_decode(mtod(m0, struct x25_packet *))) { | |
3b1d357b | 335 | default: |
194a383a KS |
336 | return; |
337 | ||
338 | case RR: | |
339 | cmd = PRC_CONS_SEND_DONE; | |
3b1d357b | 340 | break; |
194a383a KS |
341 | |
342 | case RESET: | |
343 | cmd = PRC_ROUTEDEAD; | |
3b1d357b | 344 | } |
194a383a | 345 | tpcons_ctlinput(cmd, isop->isop_faddr, isop); |
3b1d357b | 346 | } |
3b1d357b KS |
347 | } |
348 | ||
349 | /* | |
194a383a | 350 | * NAME: cons_connect() |
3b1d357b | 351 | * CALLED FROM: |
194a383a KS |
352 | * tpcons_pcbconnect() when opening a new connection. |
353 | * FUNCTION anD ARGUMENTS: | |
354 | * Figures out which device to use, finding a route if one doesn't | |
355 | * already exist. | |
356 | * RETURN VALUE: | |
357 | * returns E* | |
3b1d357b | 358 | */ |
194a383a KS |
359 | cons_connect(isop) |
360 | register struct isopcb *isop; | |
3b1d357b | 361 | { |
194a383a KS |
362 | register struct pklcd *lcp = (struct pklcd *)isop->isop_chan; |
363 | register struct mbuf *m; | |
364 | struct ifaddr *ifa; | |
3b1d357b | 365 | |
194a383a KS |
366 | IFDEBUG(D_CCONN) |
367 | printf("cons_connect(0x%x): ", isop); | |
368 | dump_isoaddr(isop->isop_faddr); | |
369 | printf("myaddr: "); | |
370 | dump_isoaddr(isop->isop_laddr); | |
371 | printf("\n" ); | |
372 | ENDDEBUG | |
373 | NSAPtoDTE(isop->isop_faddr, &lcp->lcd_faddr); | |
374 | IFDEBUG(D_CCONN) | |
375 | printf( | |
376 | "calling make_partial_x25_packet( 0x%x, 0x%x, 0x%x)\n", | |
377 | &lcp->lcd_faddr, &lcp->lcd_laddr, | |
378 | isop->isop_socket->so_proto->pr_protocol); | |
379 | ENDDEBUG | |
380 | return (make_partial_x25_packet(isop, lcp, m) || | |
381 | pk_connect(lcp, &lcp->lcd_faddr)); | |
3b1d357b KS |
382 | } |
383 | ||
384 | /* | |
194a383a | 385 | **************************** DEVICE cons *************************** |
3b1d357b | 386 | */ |
3b1d357b | 387 | |
3b1d357b KS |
388 | |
389 | /* | |
194a383a | 390 | * NAME: cons_ctlinput() |
3b1d357b | 391 | * CALLED FROM: |
194a383a KS |
392 | * lower layer when ECN_CLEAR occurs : this routine is here |
393 | * for consistency - cons subnet service calls its higher layer | |
394 | * through the protosw entry. | |
395 | * FUNCTION & ARGUMENTS: | |
396 | * cmd is a PRC_* command, list found in ../sys/protosw.h | |
397 | * copcb is the obvious. | |
398 | * This serves the higher-layer cons service. | |
399 | * NOTE: this takes 3rd arg. because cons uses it to inform itself | |
400 | * of things (timeouts, etc) but has a pcb instead of an address. | |
3b1d357b | 401 | */ |
194a383a KS |
402 | cons_ctlinput(cmd, sa, copcb) |
403 | int cmd; | |
404 | struct sockaddr *sa; | |
405 | register struct pklcd *copcb; | |
3b1d357b | 406 | { |
3b1d357b | 407 | } |
3b1d357b | 408 | |
3b1d357b | 409 | |
194a383a KS |
410 | find_error_reason( xp ) |
411 | register struct x25_packet *xp; | |
412 | { | |
413 | extern u_char x25_error_stats[]; | |
414 | int error, cause; | |
3b1d357b | 415 | |
194a383a KS |
416 | if (xp) { |
417 | cause = 4[(char *)xp]; | |
418 | switch (cause) { | |
419 | case 0x00: | |
420 | case 0x80: | |
421 | /* DTE originated; look at the diagnostic */ | |
422 | error = (CONL_ERROR_MASK | cause); | |
423 | goto done; | |
3b1d357b | 424 | |
194a383a KS |
425 | case 0x01: /* number busy */ |
426 | case 0x81: | |
427 | case 0x09: /* Out of order */ | |
428 | case 0x89: | |
429 | case 0x11: /* Remot Procedure Error */ | |
430 | case 0x91: | |
431 | case 0x19: /* reverse charging accept not subscribed */ | |
432 | case 0x99: | |
433 | case 0x21: /* Incampat destination */ | |
434 | case 0xa1: | |
435 | case 0x29: /* fast select accept not subscribed */ | |
436 | case 0xa9: | |
437 | case 0x39: /* ship absent */ | |
438 | case 0xb9: | |
439 | case 0x03: /* invalid facil request */ | |
440 | case 0x83: | |
441 | case 0x0b: /* access barred */ | |
442 | case 0x8b: | |
443 | case 0x13: /* local procedure error */ | |
444 | case 0x93: | |
445 | case 0x05: /* network congestion */ | |
446 | case 0x85: | |
447 | case 0x8d: /* not obtainable */ | |
448 | case 0x0d: | |
449 | case 0x95: /* RPOA out of order */ | |
450 | case 0x15: | |
451 | /* take out bit 8 | |
452 | * so we don't have to have so many perror entries | |
453 | */ | |
454 | error = (CONL_ERROR_MASK | 0x100 | (cause & ~0x80)); | |
455 | goto done; | |
3b1d357b | 456 | |
194a383a KS |
457 | case 0xc1: /* gateway-detected proc error */ |
458 | case 0xc3: /* gateway congestion */ | |
3b1d357b | 459 | |
194a383a KS |
460 | error = (CONL_ERROR_MASK | 0x100 | cause); |
461 | goto done; | |
462 | } | |
463 | } | |
464 | /* otherwise, a *hopefully* valid perror exists in the e_reason field */ | |
465 | error = xp->packet_data; | |
466 | if (error = 0) { | |
467 | printf("Incoming PKT TYPE 0x%x with reason 0x%x\n", | |
468 | pk_decode(xp), | |
469 | cause); | |
470 | error = E_CO_HLI_DISCA; | |
471 | } | |
3b1d357b | 472 | |
194a383a KS |
473 | done: |
474 | return error; | |
475 | } | |
3b1d357b | 476 | |
3b1d357b | 477 | |
3b1d357b | 478 | |
194a383a | 479 | #endif KERNEL |
3b1d357b KS |
480 | |
481 | /* | |
482 | * NAME: make_partial_x25_packet() | |
483 | * | |
484 | * FUNCTION and ARGUMENTS: | |
194a383a | 485 | * Makes part of an X.25 call packet, for use by x25. |
3b1d357b | 486 | * (src) and (dst) are the NSAP-addresses of source and destination. |
3b1d357b KS |
487 | * (buf) is a ptr to a buffer into which to write this partial header. |
488 | * | |
194a383a KS |
489 | * 0 Facility length (in octets) |
490 | * 1 Facility field, which is a set of: | |
3b1d357b KS |
491 | * m facil code |
492 | * m+1 facil param len (for >2-byte facilities) in octets | |
493 | * m+2..p facil param field | |
494 | * q user data (protocol identification octet) | |
495 | * | |
496 | * | |
497 | * RETURNS: | |
498 | * 0 if OK | |
499 | * E* if failed. | |
194a383a KS |
500 | * |
501 | * SIDE EFFECTS: | |
502 | * Stores facilites mbuf in X.25 control block, where the connect | |
503 | * routine knows where to look for it. | |
3b1d357b KS |
504 | */ |
505 | ||
506 | #ifdef X25_1984 | |
507 | int cons_use_facils = 1; | |
508 | #else X25_1984 | |
509 | int cons_use_facils = 0; | |
510 | #endif X25_1984 | |
511 | ||
512 | int cons_use_udata = 1; /* KLUDGE FOR DEBUGGING */ | |
513 | ||
514 | Static int | |
194a383a KS |
515 | make_partial_x25_packet(isop, lcp) |
516 | struct isopcb *isop; | |
517 | struct pklcd *lcp; | |
3b1d357b | 518 | { |
3b1d357b KS |
519 | u_int proto; |
520 | int flag; | |
194a383a KS |
521 | caddr_t buf; |
522 | register caddr_t ptr = buf; | |
3b1d357b KS |
523 | register int len = 0; |
524 | int buflen =0; | |
525 | caddr_t facil_len; | |
526 | int oddness = 0; | |
194a383a | 527 | struct mbuf *m; |
3b1d357b KS |
528 | |
529 | ||
194a383a KS |
530 | MGET(m, MT_DATA, M_WAITOK); |
531 | if (m == 0) | |
532 | return ENOBUFS; | |
533 | buf = mtod(m, caddr_t); | |
3b1d357b KS |
534 | IFDEBUG(D_CCONN) |
535 | printf("make_partial_x25_packet(0x%x, 0x%x, 0x%x, 0x%x, 0x%x)\n", | |
194a383a | 536 | isop->isop_laddr, isop->isop_faddr, proto, m, flag); |
3b1d357b KS |
537 | ENDDEBUG |
538 | ||
3b1d357b KS |
539 | /* ptr now points to facil length (len of whole facil field in OCTETS */ |
540 | facil_len = ptr ++; | |
541 | ||
542 | IFDEBUG(D_CADDR) | |
543 | printf("make_partial calling: ptr 0x%x, len 0x%x\n", ptr, | |
194a383a | 544 | isop->isop_laddr->siso_addr.isoa_len); |
3b1d357b | 545 | ENDDEBUG |
194a383a | 546 | if (cons_use_facils) { |
3b1d357b KS |
547 | *ptr = 0xcb; /* calling facility code */ |
548 | ptr ++; | |
549 | ptr ++; /* leave room for facil param len (in OCTETS + 1) */ | |
550 | ptr ++; /* leave room for the facil param len (in nibbles), | |
551 | * high two bits of which indicate full/partial NSAP | |
552 | */ | |
194a383a KS |
553 | len = isop->isop_laddr->siso_addr.isoa_len; |
554 | bcopy( isop->isop_laddr->siso_data, ptr, len); | |
3b1d357b KS |
555 | *(ptr-2) = len+2; /* facil param len in octets */ |
556 | *(ptr-1) = len<<1; /* facil param len in nibbles */ | |
557 | ptr += len; | |
558 | ||
559 | IFDEBUG(D_CADDR) | |
560 | printf("make_partial called: ptr 0x%x, len 0x%x\n", ptr, | |
194a383a | 561 | isop->isop_faddr->siso_addr.isoa_len); |
3b1d357b KS |
562 | ENDDEBUG |
563 | *ptr = 0xc9; /* called facility code */ | |
564 | ptr ++; | |
565 | ptr ++; /* leave room for facil param len (in OCTETS + 1) */ | |
566 | ptr ++; /* leave room for the facil param len (in nibbles), | |
567 | * high two bits of which indicate full/partial NSAP | |
568 | */ | |
194a383a KS |
569 | len = isop->isop_faddr->siso_nlen; |
570 | bcopy(isop->isop_faddr->siso_data, ptr, len); | |
3b1d357b KS |
571 | *(ptr-2) = len+2; /* facil param len = addr len + 1 for each of these |
572 | * two length fields, in octets */ | |
573 | *(ptr-1) = len<<1; /* facil param len in nibbles */ | |
574 | ptr += len; | |
575 | ||
576 | } | |
577 | *facil_len = ptr - facil_len - 1; | |
194a383a | 578 | if (*facil_len > MAX_FACILITIES) |
3b1d357b KS |
579 | return E_CO_PNA_LONG; |
580 | ||
194a383a KS |
581 | if (cons_use_udata) { |
582 | if (isop->isop_x25crud_len > 0) { | |
3b1d357b KS |
583 | /* |
584 | * The user specified something. Stick it in | |
585 | */ | |
194a383a KS |
586 | bcopy(isop->isop_x25crud, lcp->lcd_faddr.x25_udata, |
587 | isop->isop_x25crud_len); | |
588 | lcp->lcd_faddr.x25_udlen = isop->isop_x25crud_len; | |
3b1d357b KS |
589 | } |
590 | } | |
591 | ||
592 | buflen = (int)(ptr - buf); | |
593 | ||
594 | IFDEBUG(D_CDUMP_REQ) | |
595 | register int i; | |
596 | ||
597 | printf("ECN_CONNECT DATA buf 0x%x len %d (0x%x)\n", | |
598 | buf, buflen, buflen); | |
599 | for( i=0; i < buflen; ) { | |
600 | printf("+%d: %x %x %x %x %x %x %x %x\n", | |
601 | i, | |
602 | *(buf+i), *(buf+i+1), *(buf+i+2), *(buf+i+3), | |
603 | *(buf+i+4), *(buf+i+5), *(buf+i+6), *(buf+i+7)); | |
604 | i+=8; | |
605 | } | |
606 | ENDDEBUG | |
607 | IFDEBUG(D_CADDR) | |
608 | printf("make_partial returns buf 0x%x size 0x%x bytes\n", | |
609 | mtod(m, caddr_t), buflen); | |
610 | ENDDEBUG | |
611 | ||
194a383a | 612 | if (buflen > MHLEN) |
3b1d357b KS |
613 | return E_CO_PNA_LONG; |
614 | ||
615 | m->m_len = buflen; | |
194a383a | 616 | lcp->lcd_facilities = m; |
3b1d357b KS |
617 | return 0; |
618 | } | |
619 | ||
620 | /* | |
621 | * NAME: NSAPtoDTE() | |
622 | * CALLED FROM: | |
623 | * make_partial_x25_packet() | |
624 | * FUNCTION and ARGUMENTS: | |
625 | * get a DTE address from an NSAP-address (struct sockaddr_iso) | |
626 | * (dst_octet) is the octet into which to begin stashing the DTE addr | |
627 | * (dst_nibble) takes 0 or 1. 1 means begin filling in the DTE addr | |
628 | * in the high-order nibble of dst_octet. 0 means low-order nibble. | |
629 | * (addr) is the NSAP-address | |
630 | * (flag) is true if the transport suffix is to become the | |
631 | * last two digits of the DTE address | |
194a383a | 632 | * A DTE address is a series of ASCII digits |
3b1d357b KS |
633 | * |
634 | * A DTE address may have leading zeros. The are significant. | |
635 | * 1 digit per nibble, may be an odd number of nibbles. | |
636 | * | |
637 | * An NSAP-address has the DTE address in the IDI. Leading zeros are | |
638 | * significant. Trailing hex f indicates the end of the DTE address. | |
194a383a | 639 | * The IDI is a series of BCD digits, one per nibble. |
3b1d357b KS |
640 | * |
641 | * RETURNS | |
642 | * # significant digits in the DTE address, -1 if error. | |
643 | */ | |
644 | ||
645 | Static int | |
194a383a KS |
646 | NSAPtoDTE(siso, sx25) |
647 | register struct sockaddr_iso *siso; | |
648 | register struct sockaddr_x25 *sx25; | |
3b1d357b | 649 | { |
194a383a | 650 | int dtelen = -1; |
3b1d357b KS |
651 | |
652 | IFDEBUG(D_CADDR) | |
194a383a | 653 | printf("NSAPtoDTE: nsap: %s\n", clnp_iso_addrp(&siso->siso_addr)); |
3b1d357b KS |
654 | ENDDEBUG |
655 | ||
194a383a KS |
656 | if (siso->siso_data[0] == AFI_37) { |
657 | register char *out = sx25->x25_addr; | |
658 | register char *in = siso->siso_data + 1; | |
659 | register int nibble; | |
660 | char *lim = in + 15; | |
661 | int lowNibble = 0; | |
3b1d357b | 662 | |
194a383a KS |
663 | while (in < lim) { |
664 | nibble = ((lowNibble ? *in++ : (*in >> 4)) & 0xf) | 0x30; | |
665 | lowNibble ^= 1; | |
666 | if (nibble != 0x3f) | |
667 | *out++ = nibble; | |
668 | } | |
669 | dtelen = out - sx25->x25_addr; | |
670 | *out++ = 0; | |
671 | } else { | |
672 | register struct rtentry *rt = rtalloc1(siso, 1); | |
673 | /* error = iso_8208snparesolve(addr, x121string, &x121strlen);*/ | |
674 | ||
675 | if (rt) { | |
676 | register struct sockaddr_x25 *sxx = | |
677 | (struct sockaddr_x25 *)rt->rt_gateway; | |
678 | register char *in = sxx->x25_addr; | |
679 | ||
680 | rt->rt_use--; | |
681 | if (sxx && sxx->x25_family == AF_CCITT) { | |
682 | bcopy(sx25->x25_addr, sxx->x25_addr, sizeof(sx25->x25_addr)); | |
683 | while (*in++) {} | |
684 | dtelen = in - sxx->x25_addr; | |
685 | } | |
686 | } | |
687 | } | |
688 | return dtelen; | |
3b1d357b KS |
689 | } |
690 | ||
691 | /* | |
692 | * NAME: FACILtoNSAP() | |
693 | * CALLED FROM: | |
694 | * parse_facil() | |
695 | * FUNCTION and ARGUMENTS: | |
696 | * Creates and NSAP in the sockaddr_iso (addr) from the | |
194a383a | 697 | * x.25 facility found at buf - 1. |
3b1d357b | 698 | * RETURNS: |
194a383a | 699 | * length of parameter if ok, -1 if error. |
3b1d357b KS |
700 | */ |
701 | ||
702 | Static int | |
194a383a KS |
703 | FACILtoNSAP(addr, buf) |
704 | u_char *buf; | |
3b1d357b KS |
705 | register struct sockaddr_iso *addr; |
706 | { | |
194a383a KS |
707 | int len_in_nibbles, param_len = *buf++; |
708 | u_char buf_len; /* in bytes */ | |
3b1d357b KS |
709 | |
710 | IFDEBUG(D_CADDR) | |
711 | printf("FACILtoNSAP( 0x%x, 0x%x, 0x%x )\n", | |
712 | buf, buf_len, addr ); | |
713 | ENDDEBUG | |
714 | ||
194a383a KS |
715 | len_in_nibbles = *buf & 0x3f; |
716 | buf_len = (len_in_nibbles + 1) >> 1; | |
3b1d357b KS |
717 | /* despite the fact that X.25 makes us put a length in nibbles |
718 | * here, the NSAP-addrs are always in full octets | |
719 | */ | |
194a383a KS |
720 | switch (*buf++ & 0xc0) { |
721 | case 0: | |
722 | /* Entire OSI NSAP address */ | |
723 | bcopy((caddr_t)buf, addr->siso_data, addr->siso_nlen = buf_len); | |
724 | break; | |
3b1d357b | 725 | |
194a383a KS |
726 | case 40: |
727 | /* Partial OSI NSAP address, assume trailing */ | |
728 | if (buf_len + addr->siso_nlen > sizeof(addr->siso_addr)) | |
729 | return -1; | |
730 | bcopy((caddr_t)buf, TSEL(addr), buf_len); | |
731 | addr->siso_nlen += buf_len; | |
732 | break; | |
3b1d357b | 733 | |
194a383a KS |
734 | default: |
735 | /* Rather than blow away the connection, just ignore and use | |
736 | NSAP from DTE */; | |
3b1d357b | 737 | } |
194a383a KS |
738 | return param_len; |
739 | } | |
3b1d357b | 740 | |
194a383a KS |
741 | static |
742 | init_siso(siso) | |
743 | register struct sockaddr_iso *siso; | |
744 | { | |
745 | siso->siso_len = sizeof (*siso); | |
746 | siso->siso_family = AF_ISO; | |
747 | siso->siso_data[0] = AFI_37; | |
748 | siso->siso_nlen = 8; | |
3b1d357b KS |
749 | } |
750 | ||
751 | /* | |
752 | * NAME: DTEtoNSAP() | |
753 | * CALLED FROM: | |
754 | * parse_facil() | |
755 | * FUNCTION and ARGUMENTS: | |
756 | * Creates a type 37 NSAP in the sockaddr_iso (addr) | |
194a383a | 757 | * from a DTE address found in a sockaddr_x25. |
3b1d357b KS |
758 | * |
759 | * RETURNS: | |
760 | * 0 if ok; E* otherwise. | |
761 | */ | |
762 | ||
763 | Static int | |
194a383a | 764 | DTEtoNSAP(addr, sx) |
3b1d357b | 765 | struct sockaddr_iso *addr; |
194a383a | 766 | struct sockaddr_x25 *sx; |
3b1d357b | 767 | { |
194a383a KS |
768 | register char *in, *out; |
769 | register int first; | |
770 | int pad_tail = 0; | |
771 | int src_len; | |
3b1d357b | 772 | |
3b1d357b | 773 | |
194a383a KS |
774 | init_siso(addr); |
775 | src_len = strlen(sx->x25_addr); | |
776 | in = sx->x25_addr; | |
777 | out = addr->siso_data + 1; | |
778 | if (*in == '0' && (src_len & 1 == 0)) { | |
779 | pad_tail = 0xf; | |
780 | src_len++; | |
781 | } | |
782 | for (first = 0; src_len > 0; src_len --) { | |
783 | first |= *in++; | |
784 | if (src_len & 1) { | |
785 | *out++ = first; | |
786 | first = 0; | |
787 | } | |
788 | else first <<= 4; | |
789 | } | |
790 | if (pad_tail) | |
791 | out[-1] |= 0xf; | |
3b1d357b KS |
792 | return 0; /* ok */ |
793 | } | |
794 | ||
795 | /* | |
796 | * FUNCTION and ARGUMENTS: | |
797 | * parses (buf_len) bytes beginning at (buf) and finds | |
798 | * a called nsap, a calling nsap, and protocol identifier. | |
799 | * RETURNS: | |
800 | * 0 if ok, E* otherwise. | |
801 | */ | |
802 | ||
194a383a KS |
803 | static int |
804 | parse_facil(lcp, isop, buf, buf_len) | |
3b1d357b KS |
805 | caddr_t buf; |
806 | u_char buf_len; /* in bytes */ | |
194a383a KS |
807 | struct isopcb *isop; |
808 | struct pklcd *lcp; | |
3b1d357b | 809 | { |
194a383a KS |
810 | register struct sockaddr_iso *called = isop->isop_laddr; |
811 | register struct sockaddr_iso *calling = isop->isop_faddr; | |
3b1d357b | 812 | register int i; |
194a383a KS |
813 | register u_char *ptr = (u_char *)buf; |
814 | u_char *ptr_lim, *facil_lim; | |
815 | int facil_param_len, facil_len; | |
3b1d357b KS |
816 | |
817 | IFDEBUG(D_CADDR) | |
194a383a KS |
818 | printf("parse_facil(0x%x, 0x%x, 0x%x, 0x%x)\n", |
819 | buf, buf_len, called, calling); | |
3b1d357b KS |
820 | dump_buf(buf, buf_len); |
821 | ENDDEBUG | |
822 | ||
823 | /* find the beginnings of the facility fields in buf | |
824 | * by skipping over the called & calling DTE addresses | |
825 | * i <- # nibbles in called + # nibbles in calling | |
826 | * i += 1 so that an odd nibble gets rounded up to even | |
827 | * before dividing by 2, then divide by two to get # octets | |
828 | */ | |
194a383a | 829 | i = (int)(*ptr >> 4) + (int)(*ptr&0xf); |
3b1d357b | 830 | i++; |
194a383a | 831 | ptr += i >> 1; |
3b1d357b KS |
832 | ptr ++; /* plus one for the DTE lengths byte */ |
833 | ||
834 | /* ptr now is at facil_length field */ | |
194a383a KS |
835 | facil_len = *ptr++; |
836 | facil_lim = ptr + facil_len; | |
3b1d357b | 837 | IFDEBUG(D_CADDR) |
194a383a | 838 | printf("parse_facils: facil length is 0x%x\n", (int) facil_len); |
3b1d357b KS |
839 | ENDDEBUG |
840 | ||
194a383a | 841 | while (ptr <= facil_lim) { |
3b1d357b | 842 | /* get NSAP addresses from facilities */ |
194a383a | 843 | switch (*ptr++) { |
3b1d357b | 844 | case 0xcb: |
194a383a KS |
845 | /* calling NSAP */ |
846 | facil_param_len = FACILtoNSAP(isop->isop_faddr, ptr); | |
3b1d357b KS |
847 | break; |
848 | case 0xc9: | |
194a383a KS |
849 | /* called NSAP */ |
850 | facil_param_len = FACILtoNSAP(isop->isop_laddr, ptr); | |
3b1d357b KS |
851 | break; |
852 | ||
853 | /* from here to default are legit cases that I ignore */ | |
3b1d357b KS |
854 | /* variable length */ |
855 | case 0xca: /* end-to-end transit delay negot */ | |
856 | case 0xc6: /* network user id */ | |
857 | case 0xc5: /* charging info : indicating monetary unit */ | |
858 | case 0xc2: /* charging info : indicating segment count */ | |
859 | case 0xc1: /* charging info : indicating call duration */ | |
860 | case 0xc4: /* RPOA extended format */ | |
861 | case 0xc3: /* call redirection notification */ | |
862 | facil_param_len = 0; | |
3b1d357b KS |
863 | break; |
864 | ||
865 | /* 1 octet */ | |
866 | case 0x0a: /* min. throughput class negot */ | |
867 | case 0x02: /* throughput class */ | |
868 | case 0x03: case 0x47: /* CUG shit */ | |
869 | case 0x0b: /* expedited data negot */ | |
870 | case 0x01: /* Fast select or reverse charging | |
871 | (example of intelligent protocol design) */ | |
872 | case 0x04: /* charging info : requesting service */ | |
873 | case 0x08: /* called line addr modified notification */ | |
874 | facil_param_len = 1; | |
3b1d357b KS |
875 | break; |
876 | ||
877 | /* any 2 octets */ | |
878 | case 0x42: /* pkt size */ | |
879 | case 0x43: /* win size */ | |
880 | case 0x44: /* RPOA basic format */ | |
881 | case 0x41: /* bilateral CUG shit */ | |
882 | case 0x49: /* transit delay selection and indication */ | |
883 | facil_param_len = 2; | |
3b1d357b KS |
884 | break; |
885 | ||
886 | /* don't have any 3 octets */ | |
887 | /* | |
888 | facil_param_len = 3; | |
889 | */ | |
890 | default: | |
3b1d357b KS |
891 | printf( |
892 | "BOGUS FACILITY CODE facil_len 0x%x *facil_len 0x%x, ptr 0x%x *ptr 0x%x\n", | |
194a383a | 893 | ptr, facil_len, ptr - 1, ptr[-1]); |
3b1d357b KS |
894 | /* facil that we don't handle */ |
895 | return E_CO_HLI_REJI; | |
896 | } | |
194a383a KS |
897 | if (facil_param_len == -1) |
898 | return E_CO_REG_ICDA; | |
899 | if (facil_param_len == 0) /* variable length */ | |
3b1d357b | 900 | facil_param_len = (int)*ptr; /* 1 + the real facil param */ |
3b1d357b KS |
901 | ptr += facil_param_len; |
902 | } | |
3b1d357b KS |
903 | return 0; |
904 | } | |
905 | ||
194a383a | 906 | #endif TPCONS |