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