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