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