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 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 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 */ 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 */ 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 */ 413 cons_ctlinput(cmd, sa, copcb) 414 int cmd; 415 struct sockaddr *sa; 416 register struct pklcd *copcb; 417 { 418 } 419 420 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 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 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 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 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 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 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