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