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