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