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