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