]> git.saurik.com Git - apple/xnu.git/blob - bsd/netiso/if_cons.c
xnu-124.8.tar.gz
[apple/xnu.git] / bsd / netiso / if_cons.c
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 */