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