1 /*-
2 * Copyright (c) 1991, 1993
3 * The Regents of the University of California. All rights reserved.
4 *
5 * %sccs.include.redist.c%
6 *
7 * @(#)if_cons.c 8.1 (Berkeley) 06/10/93
8 */
9
10 /***********************************************************
11 Copyright IBM Corporation 1987
12
13 All Rights Reserved
14
15 Permission to use, copy, modify, and distribute this software and its
16 documentation for any purpose and without fee is hereby granted,
17 provided that the above copyright notice appear in all copies and that
18 both that copyright notice and this permission notice appear in
19 supporting documentation, and that the name of IBM not be
20 used in advertising or publicity pertaining to distribution of the
21 software without specific, written prior permission.
22
23 IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
24 ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
25 IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
26 ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
27 WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
28 ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
29 SOFTWARE.
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.
43 */
44
45 #ifdef TPCONS
46 #ifdef KERNEL
47 #ifdef ARGO_DEBUG
48 #define Static
49 unsigned LAST_CALL_PCB;
50 #else /* ARGO_DEBUG */
51 #define Static static
52 #endif /* ARGO_DEBUG */
53
54 #ifndef SOCK_STREAM
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>
79 #endif
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
93 #endif /* ARGO_DEBUG */
94
95 #define DONTCLEAR -1
96
97 /*********************************************************************
98 * cons.c - CONS interface to the x.25 layer
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 *
104 * There are 2 interfaces from above:
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
110 * 2) from TP4:
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
118 * this pklcd, hence cannot have a back ptr from pklcd to a tpcb.
119 * co_flags & CONSF_DGM
120 * co_socket is null since there may be many sockets that use this pklcd.
121 *
122 NOTE:
123 streams would really be nice. sigh.
124 NOTE:
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.
128
129
130 *********************************************************************/
131
132
133 #define CONS_IFQMAXLEN 5
134
135
136 /* protosw pointers for getting to higher layer */
137 Static struct protosw *CLNP_proto;
138 Static struct protosw *TP_proto;
139 Static struct protosw *X25_proto;
140 Static int issue_clear_req();
141
142 #ifndef PHASEONE
143 extern struct ifaddr *ifa_ifwithnet();
144 #endif /* PHASEONE */
145
146 extern struct ifaddr *ifa_ifwithaddr();
147
148 extern struct isopcb tp_isopcb; /* chain of all TP pcbs */
149
150
151 Static int parse_facil(), NSAPtoDTE(), make_partial_x25_packet();
152 Static int FACILtoNSAP(), DTEtoNSAP();
153 Static struct pklcd *cons_chan_to_pcb();
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 */
168 void
nibble_copy(src_octet,src_nibble,dst_octet,dst_nibble,len)169 nibble_copy(src_octet, src_nibble, dst_octet, dst_nibble, len)
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 */
214 int
nibble_match(src_octet,src_nibble,dst_octet,dst_nibble,len)215 nibble_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));
239 if (nibble_b != nibble_a)
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
255 /*
256 **************************** NET PROTOCOL cons ***************************
257 */
258 /*
259 * NAME: cons_init()
260 * CALLED FROM:
261 * autoconf
262 * FUNCTION:
263 * initialize the protocol
264 */
cons_init()265 cons_init()
266 {
267 int tp_incoming(), clnp_incoming();
268
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);
273 IFDEBUG(D_CCONS)
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);
276 ENDDEBUG
277 #ifdef notdef
278 pk_protolisten(0x81, 0, clnp_incoming);
279 pk_protolisten(0x82, 0, esis_incoming);
280 pk_protolisten(0x84, 0, tp8878_A_incoming);
281 pk_protolisten(0, 0, tp_incoming);
282 #endif
283 }
284
285 tp_incoming(lcp, m)
286 struct pklcd *lcp;
287 register struct mbuf *m;
288 {
289 register struct isopcb *isop;
290 int cons_tpinput();
291
292 if (iso_pcballoc((struct socket *)0, &tp_isopcb)) {
293 pk_close(lcp);
294 return;
295 }
296 isop = tp_isopcb.isop_next;
297 lcp->lcd_upper = cons_tpinput;
298 lcp->lcd_upnext = (caddr_t)isop;
299 lcp->lcd_send(lcp); /* Confirms call */
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);
305 parse_facil(lcp, isop, &(mtod(m, struct x25_packet *)->packet_data),
306 m->m_pkthdr.len - PKHEADERLN);
307 }
308
309 cons_tpinput(lcp, m0)
310 struct mbuf *m0;
311 struct pklcd *lcp;
312 {
313 register struct isopcb *isop = (struct isopcb *)lcp->lcd_upnext;
314 register struct x25_packet *xp;
315 int cmd, ptype = CLEAR;
316
317 if (isop == 0)
318 return;
319 if (m0 == 0)
320 goto dead;
321 switch(m0->m_type) {
322 case MT_DATA:
323 case MT_OOBDATA:
324 tpcons_input(m0, isop->isop_faddr, isop->isop_laddr, (caddr_t)lcp);
325 return;
326
327 case MT_CONTROL:
328 switch (ptype = pk_decode(mtod(m0, struct x25_packet *))) {
329
330 case RR:
331 cmd = PRC_CONS_SEND_DONE;
332 break;
333
334 case CALL_ACCEPTED:
335 if (lcp->lcd_sb.sb_mb)
336 lcp->lcd_send(lcp); /* XXX - fix this */
337 /*FALLTHROUGH*/
338 default:
339 return;
340
341 dead:
342 case CLEAR:
343 case CLEAR_CONF:
344 lcp->lcd_upper = 0;
345 lcp->lcd_upnext = 0;
346 isop->isop_chan = 0;
347 case RESET:
348 cmd = PRC_ROUTEDEAD;
349 }
350 tpcons_ctlinput(cmd, isop->isop_faddr, isop);
351 if (cmd = PRC_ROUTEDEAD && isop->isop_refcnt == 0)
352 iso_pcbdetach(isop);
353 }
354 }
355
356 /*
357 * NAME: cons_connect()
358 * CALLED FROM:
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*
365 */
cons_connect(isop)366 cons_connect(isop)
367 register struct isopcb *isop;
368 {
369 register struct pklcd *lcp = (struct pklcd *)isop->isop_chan;
370 register struct mbuf *m;
371 struct ifaddr *ifa;
372 int error;
373
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);
382 lcp->lcd_upper = cons_tpinput;
383 lcp->lcd_upnext = (caddr_t)isop;
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
390 if ((error = make_partial_x25_packet(isop, lcp, m)) == 0)
391 error = pk_connect(lcp, &lcp->lcd_faddr);
392 return error;
393 }
394
395 /*
396 **************************** DEVICE cons ***************************
397 */
398
399
400 /*
401 * NAME: cons_ctlinput()
402 * CALLED FROM:
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.
412 */
cons_ctlinput(cmd,sa,copcb)413 cons_ctlinput(cmd, sa, copcb)
414 int cmd;
415 struct sockaddr *sa;
416 register struct pklcd *copcb;
417 {
418 }
419
420
find_error_reason(xp)421 find_error_reason( xp )
422 register struct x25_packet *xp;
423 {
424 extern u_char x25_error_stats[];
425 int error, cause;
426
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;
435
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;
467
468 case 0xc1: /* gateway-detected proc error */
469 case 0xc3: /* gateway congestion */
470
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 }
483
484 done:
485 return error;
486 }
487
488
489
490 #endif /* KERNEL */
491
492 /*
493 * NAME: make_partial_x25_packet()
494 *
495 * FUNCTION and ARGUMENTS:
496 * Makes part of an X.25 call packet, for use by x25.
497 * (src) and (dst) are the NSAP-addresses of source and destination.
498 * (buf) is a ptr to a buffer into which to write this partial header.
499 *
500 * 0 Facility length (in octets)
501 * 1 Facility field, which is a set of:
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.
511 *
512 * SIDE EFFECTS:
513 * Stores facilites mbuf in X.25 control block, where the connect
514 * routine knows where to look for it.
515 */
516
517 #ifdef X25_1984
518 int cons_use_facils = 1;
519 #else /* X25_1984 */
520 int cons_use_facils = 0;
521 #endif /* X25_1984 */
522
523 int cons_use_udata = 1; /* KLUDGE FOR DEBUGGING */
524
525 Static int
make_partial_x25_packet(isop,lcp)526 make_partial_x25_packet(isop, lcp)
527 struct isopcb *isop;
528 struct pklcd *lcp;
529 {
530 u_int proto;
531 int flag;
532 caddr_t buf;
533 register caddr_t ptr;
534 register int len = 0;
535 int buflen =0;
536 caddr_t facil_len;
537 int oddness = 0;
538 struct mbuf *m;
539
540
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 }
560 MGETHDR(m, MT_DATA, M_WAITOK);
561 if (m == 0)
562 return ENOBUFS;
563 buf = mtod(m, caddr_t);
564 ptr = buf;
565
566 /* ptr now points to facil length (len of whole facil field in OCTETS */
567 facil_len = ptr ++;
568 m->m_len = 0;
569 pk_build_facilities(m, &lcp->lcd_faddr, 0);
570
571 IFDEBUG(D_CADDR)
572 printf("make_partial calling: ptr 0x%x, len 0x%x\n", ptr,
573 isop->isop_laddr->siso_addr.isoa_len);
574 ENDDEBUG
575 if (cons_use_facils) {
576 *ptr++ = 0; /* Marker to separate X.25 facitilies from CCITT ones */
577 *ptr++ = 0x0f;
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),
582 * high two bits of which indicate full/partial NSAP
583 */
584 len = isop->isop_laddr->siso_addr.isoa_len;
585 bcopy( isop->isop_laddr->siso_data, ptr, len);
586 *(ptr-2) = len+1; /* facil param len in octets */
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,
592 isop->isop_faddr->siso_addr.isoa_len);
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),
598 * high two bits of which indicate full/partial NSAP
599 */
600 len = isop->isop_faddr->siso_nlen;
601 bcopy(isop->isop_faddr->siso_data, ptr, len);
602 *(ptr-2) = len+1; /* facil param len = addr len + 1 for each of these
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;
609 if (*facil_len > MAX_FACILITIES)
610 return E_CO_PNA_LONG;
611
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
632 if (buflen > MHLEN)
633 return E_CO_PNA_LONG;
634
635 m->m_pkthdr.len = m->m_len = buflen;
636 lcp->lcd_facilities = m;
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
652 * A DTE address is a series of ASCII digits
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.
659 * The IDI is a series of BCD digits, one per nibble.
660 *
661 * RETURNS
662 * # significant digits in the DTE address, -1 if error.
663 */
664
665 Static int
NSAPtoDTE(siso,sx25)666 NSAPtoDTE(siso, sx25)
667 register struct sockaddr_iso *siso;
668 register struct sockaddr_x25 *sx25;
669 {
670 int dtelen = -1;
671
672 IFDEBUG(D_CADDR)
673 printf("NSAPtoDTE: nsap: %s\n", clnp_iso_addrp(&siso->siso_addr));
674 ENDDEBUG
675
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;
680 char *lim = siso->siso_data + siso->siso_nlen;
681 char *olim = out+15;
682 int lowNibble = 0;
683
684 while (in < lim) {
685 nibble = ((lowNibble ? *in++ : (*in >> 4)) & 0xf) | 0x30;
686 lowNibble ^= 1;
687 if (nibble != 0x3f && out < olim)
688 *out++ = nibble;
689 }
690 dtelen = out - sx25->x25_addr;
691 *out++ = 0;
692 } else {
693 /* error = iso_8208snparesolve(addr, x121string, &x121strlen);*/
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)) {
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;
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
723 * x.25 facility found at buf - 1.
724 * RETURNS:
725 * 0 if ok, -1 if error.
726 */
727
728 Static int
FACILtoNSAP(addr,buf)729 FACILtoNSAP(addr, buf)
730 register u_char *buf;
731 register struct sockaddr_iso *addr;
732 {
733 int len_in_nibbles = *++buf & 0x3f;
734 u_char buf_len = (len_in_nibbles + 1) >> 1;; /* in bytes */
735
736 IFDEBUG(D_CADDR)
737 printf("FACILtoNSAP( 0x%x, 0x%x, 0x%x )\n",
738 buf, buf_len, addr );
739 ENDDEBUG
740
741 len_in_nibbles = *buf & 0x3f;
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 */
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;
750
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;
758
759 default:
760 /* Rather than blow away the connection, just ignore and use
761 NSAP from DTE */;
762 }
763 return 0;
764 }
765
766 Static
init_siso(siso)767 init_siso(siso)
768 register 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;
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)
782 * from a DTE address found in a sockaddr_x25.
783 *
784 * RETURNS:
785 * 0 if ok; E* otherwise.
786 */
787
788 Static int
DTEtoNSAP(addr,sx)789 DTEtoNSAP(addr, sx)
790 struct sockaddr_iso *addr;
791 struct sockaddr_x25 *sx;
792 {
793 register char *in, *out;
794 register int first;
795 int pad_tail = 0;
796 int src_len;
797
798
799 init_siso(addr);
800 in = sx->x25_addr;
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) {
806 pad_tail = 0xf;
807 src_len++;
808 }
809 for (first = 0; src_len > 0; src_len--) {
810 first |= 0xf & *in++;
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;
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
830 Static int
parse_facil(lcp,isop,buf,buf_len)831 parse_facil(lcp, isop, buf, buf_len)
832 caddr_t buf;
833 u_char buf_len; /* in bytes */
834 struct isopcb *isop;
835 struct pklcd *lcp;
836 {
837 register int i;
838 register u_char *ptr = (u_char *)buf;
839 u_char *ptr_lim, *facil_lim;
840 int facil_param_len, facil_len;
841
842 IFDEBUG(D_CADDR)
843 printf("parse_facil(0x%x, 0x%x, 0x%x, 0x%x)\n",
844 lcp, isop, buf, buf_len);
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 */
854 i = (int)(*ptr >> 4) + (int)(*ptr&0xf);
855 i++;
856 ptr += i >> 1;
857 ptr ++; /* plus one for the DTE lengths byte */
858
859 /* ptr now is at facil_length field */
860 facil_len = *ptr++;
861 facil_lim = ptr + facil_len;
862 IFDEBUG(D_CADDR)
863 printf("parse_facils: facil length is 0x%x\n", (int) facil_len);
864 ENDDEBUG
865
866 while (ptr < facil_lim) {
867 /* get NSAP addresses from facilities */
868 switch (*ptr++) {
869 case 0xcb:
870 /* calling NSAP */
871 facil_param_len = FACILtoNSAP(isop->isop_faddr, ptr);
872 break;
873 case 0xc9:
874 /* called NSAP */
875 facil_param_len = FACILtoNSAP(isop->isop_laddr, ptr);
876 break;
877
878 /* from here to default are legit cases that I ignore */
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;
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 */
899 case 0x00: /* marker to indicate beginning of CCITT facils */
900 facil_param_len = 1;
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;
910 break;
911
912 default:
913 printf(
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 }
924 }
925 if (facil_param_len == -1)
926 return E_CO_REG_ICDA;
927 if (facil_param_len == 0) /* variable length */
928 facil_param_len = (int)*ptr++; /* 1 + the real facil param */
929 ptr += facil_param_len;
930 }
931 return 0;
932 }
933
934 #endif /* TPCONS */
935