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.6 (Berkeley) 05/03/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 (m0 == 0) 329 goto dead; 330 switch(m0->m_type) { 331 case MT_DATA: 332 case MT_OOBDATA: 333 tpcons_input(m0, isop->isop_faddr, isop->isop_laddr, 334 (struct socket *)0, (caddr_t)lcp); 335 336 case MT_CONTROL: 337 switch (pk_decode(mtod(m0, struct x25_packet *))) { 338 default: 339 return; 340 341 case RR: 342 cmd = PRC_CONS_SEND_DONE; 343 break; 344 345 dead: 346 case RESET: 347 case CLEAR: 348 case CLEAR_CONF: 349 cmd = PRC_ROUTEDEAD; 350 } 351 tpcons_ctlinput(cmd, isop->isop_faddr, isop); 352 } 353 } 354 355 /* 356 * NAME: cons_connect() 357 * CALLED FROM: 358 * tpcons_pcbconnect() when opening a new connection. 359 * FUNCTION anD ARGUMENTS: 360 * Figures out which device to use, finding a route if one doesn't 361 * already exist. 362 * RETURN VALUE: 363 * returns E* 364 */ 365 cons_connect(isop) 366 register struct isopcb *isop; 367 { 368 register struct pklcd *lcp = (struct pklcd *)isop->isop_chan; 369 register struct mbuf *m; 370 struct ifaddr *ifa; 371 372 IFDEBUG(D_CCONN) 373 printf("cons_connect(0x%x): ", isop); 374 dump_isoaddr(isop->isop_faddr); 375 printf("myaddr: "); 376 dump_isoaddr(isop->isop_laddr); 377 printf("\n" ); 378 ENDDEBUG 379 NSAPtoDTE(isop->isop_faddr, &lcp->lcd_faddr); 380 IFDEBUG(D_CCONN) 381 printf( 382 "calling make_partial_x25_packet( 0x%x, 0x%x, 0x%x)\n", 383 &lcp->lcd_faddr, &lcp->lcd_laddr, 384 isop->isop_socket->so_proto->pr_protocol); 385 ENDDEBUG 386 return (make_partial_x25_packet(isop, lcp, m) || 387 pk_connect(lcp, &lcp->lcd_faddr)); 388 } 389 390 /* 391 **************************** DEVICE cons *************************** 392 */ 393 394 395 /* 396 * NAME: cons_ctlinput() 397 * CALLED FROM: 398 * lower layer when ECN_CLEAR occurs : this routine is here 399 * for consistency - cons subnet service calls its higher layer 400 * through the protosw entry. 401 * FUNCTION & ARGUMENTS: 402 * cmd is a PRC_* command, list found in ../sys/protosw.h 403 * copcb is the obvious. 404 * This serves the higher-layer cons service. 405 * NOTE: this takes 3rd arg. because cons uses it to inform itself 406 * of things (timeouts, etc) but has a pcb instead of an address. 407 */ 408 cons_ctlinput(cmd, sa, copcb) 409 int cmd; 410 struct sockaddr *sa; 411 register struct pklcd *copcb; 412 { 413 } 414 415 416 find_error_reason( xp ) 417 register struct x25_packet *xp; 418 { 419 extern u_char x25_error_stats[]; 420 int error, cause; 421 422 if (xp) { 423 cause = 4[(char *)xp]; 424 switch (cause) { 425 case 0x00: 426 case 0x80: 427 /* DTE originated; look at the diagnostic */ 428 error = (CONL_ERROR_MASK | cause); 429 goto done; 430 431 case 0x01: /* number busy */ 432 case 0x81: 433 case 0x09: /* Out of order */ 434 case 0x89: 435 case 0x11: /* Remot Procedure Error */ 436 case 0x91: 437 case 0x19: /* reverse charging accept not subscribed */ 438 case 0x99: 439 case 0x21: /* Incampat destination */ 440 case 0xa1: 441 case 0x29: /* fast select accept not subscribed */ 442 case 0xa9: 443 case 0x39: /* ship absent */ 444 case 0xb9: 445 case 0x03: /* invalid facil request */ 446 case 0x83: 447 case 0x0b: /* access barred */ 448 case 0x8b: 449 case 0x13: /* local procedure error */ 450 case 0x93: 451 case 0x05: /* network congestion */ 452 case 0x85: 453 case 0x8d: /* not obtainable */ 454 case 0x0d: 455 case 0x95: /* RPOA out of order */ 456 case 0x15: 457 /* take out bit 8 458 * so we don't have to have so many perror entries 459 */ 460 error = (CONL_ERROR_MASK | 0x100 | (cause & ~0x80)); 461 goto done; 462 463 case 0xc1: /* gateway-detected proc error */ 464 case 0xc3: /* gateway congestion */ 465 466 error = (CONL_ERROR_MASK | 0x100 | cause); 467 goto done; 468 } 469 } 470 /* otherwise, a *hopefully* valid perror exists in the e_reason field */ 471 error = xp->packet_data; 472 if (error = 0) { 473 printf("Incoming PKT TYPE 0x%x with reason 0x%x\n", 474 pk_decode(xp), 475 cause); 476 error = E_CO_HLI_DISCA; 477 } 478 479 done: 480 return error; 481 } 482 483 484 485 #endif KERNEL 486 487 /* 488 * NAME: make_partial_x25_packet() 489 * 490 * FUNCTION and ARGUMENTS: 491 * Makes part of an X.25 call packet, for use by x25. 492 * (src) and (dst) are the NSAP-addresses of source and destination. 493 * (buf) is a ptr to a buffer into which to write this partial header. 494 * 495 * 0 Facility length (in octets) 496 * 1 Facility field, which is a set of: 497 * m facil code 498 * m+1 facil param len (for >2-byte facilities) in octets 499 * m+2..p facil param field 500 * q user data (protocol identification octet) 501 * 502 * 503 * RETURNS: 504 * 0 if OK 505 * E* if failed. 506 * 507 * SIDE EFFECTS: 508 * Stores facilites mbuf in X.25 control block, where the connect 509 * routine knows where to look for it. 510 */ 511 512 #ifdef X25_1984 513 int cons_use_facils = 1; 514 #else X25_1984 515 int cons_use_facils = 0; 516 #endif X25_1984 517 518 int cons_use_udata = 1; /* KLUDGE FOR DEBUGGING */ 519 520 Static int 521 make_partial_x25_packet(isop, lcp) 522 struct isopcb *isop; 523 struct pklcd *lcp; 524 { 525 u_int proto; 526 int flag; 527 caddr_t buf; 528 register caddr_t ptr; 529 register int len = 0; 530 int buflen =0; 531 caddr_t facil_len; 532 int oddness = 0; 533 struct mbuf *m; 534 535 536 MGET(m, MT_DATA, M_WAITOK); 537 if (m == 0) 538 return ENOBUFS; 539 buf = mtod(m, caddr_t); 540 ptr = buf; 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 546 /* ptr now points to facil length (len of whole facil field in OCTETS */ 547 facil_len = ptr ++; 548 549 IFDEBUG(D_CADDR) 550 printf("make_partial calling: ptr 0x%x, len 0x%x\n", ptr, 551 isop->isop_laddr->siso_addr.isoa_len); 552 ENDDEBUG 553 if (cons_use_facils) { 554 *ptr = 0xcb; /* calling facility code */ 555 ptr ++; 556 ptr ++; /* leave room for facil param len (in OCTETS + 1) */ 557 ptr ++; /* leave room for the facil param len (in nibbles), 558 * high two bits of which indicate full/partial NSAP 559 */ 560 len = isop->isop_laddr->siso_addr.isoa_len; 561 bcopy( isop->isop_laddr->siso_data, ptr, len); 562 *(ptr-2) = len+2; /* facil param len in octets */ 563 *(ptr-1) = len<<1; /* facil param len in nibbles */ 564 ptr += len; 565 566 IFDEBUG(D_CADDR) 567 printf("make_partial called: ptr 0x%x, len 0x%x\n", ptr, 568 isop->isop_faddr->siso_addr.isoa_len); 569 ENDDEBUG 570 *ptr = 0xc9; /* called facility code */ 571 ptr ++; 572 ptr ++; /* leave room for facil param len (in OCTETS + 1) */ 573 ptr ++; /* leave room for the facil param len (in nibbles), 574 * high two bits of which indicate full/partial NSAP 575 */ 576 len = isop->isop_faddr->siso_nlen; 577 bcopy(isop->isop_faddr->siso_data, ptr, len); 578 *(ptr-2) = len+2; /* facil param len = addr len + 1 for each of these 579 * two length fields, in octets */ 580 *(ptr-1) = len<<1; /* facil param len in nibbles */ 581 ptr += len; 582 583 } 584 *facil_len = ptr - facil_len - 1; 585 if (*facil_len > MAX_FACILITIES) 586 return E_CO_PNA_LONG; 587 588 if (cons_use_udata) { 589 if (isop->isop_x25crud_len > 0) { 590 /* 591 * The user specified something. Stick it in 592 */ 593 bcopy(isop->isop_x25crud, lcp->lcd_faddr.x25_udata, 594 isop->isop_x25crud_len); 595 lcp->lcd_faddr.x25_udlen = isop->isop_x25crud_len; 596 } 597 } 598 599 buflen = (int)(ptr - buf); 600 601 IFDEBUG(D_CDUMP_REQ) 602 register int i; 603 604 printf("ECN_CONNECT DATA buf 0x%x len %d (0x%x)\n", 605 buf, buflen, buflen); 606 for( i=0; i < buflen; ) { 607 printf("+%d: %x %x %x %x %x %x %x %x\n", 608 i, 609 *(buf+i), *(buf+i+1), *(buf+i+2), *(buf+i+3), 610 *(buf+i+4), *(buf+i+5), *(buf+i+6), *(buf+i+7)); 611 i+=8; 612 } 613 ENDDEBUG 614 IFDEBUG(D_CADDR) 615 printf("make_partial returns buf 0x%x size 0x%x bytes\n", 616 mtod(m, caddr_t), buflen); 617 ENDDEBUG 618 619 if (buflen > MHLEN) 620 return E_CO_PNA_LONG; 621 622 m->m_len = buflen; 623 lcp->lcd_facilities = m; 624 return 0; 625 } 626 627 /* 628 * NAME: NSAPtoDTE() 629 * CALLED FROM: 630 * make_partial_x25_packet() 631 * FUNCTION and ARGUMENTS: 632 * get a DTE address from an NSAP-address (struct sockaddr_iso) 633 * (dst_octet) is the octet into which to begin stashing the DTE addr 634 * (dst_nibble) takes 0 or 1. 1 means begin filling in the DTE addr 635 * in the high-order nibble of dst_octet. 0 means low-order nibble. 636 * (addr) is the NSAP-address 637 * (flag) is true if the transport suffix is to become the 638 * last two digits of the DTE address 639 * A DTE address is a series of ASCII digits 640 * 641 * A DTE address may have leading zeros. The are significant. 642 * 1 digit per nibble, may be an odd number of nibbles. 643 * 644 * An NSAP-address has the DTE address in the IDI. Leading zeros are 645 * significant. Trailing hex f indicates the end of the DTE address. 646 * The IDI is a series of BCD digits, one per nibble. 647 * 648 * RETURNS 649 * # significant digits in the DTE address, -1 if error. 650 */ 651 652 Static int 653 NSAPtoDTE(siso, sx25) 654 register struct sockaddr_iso *siso; 655 register struct sockaddr_x25 *sx25; 656 { 657 int dtelen = -1; 658 659 IFDEBUG(D_CADDR) 660 printf("NSAPtoDTE: nsap: %s\n", clnp_iso_addrp(&siso->siso_addr)); 661 ENDDEBUG 662 663 if (siso->siso_data[0] == AFI_37) { 664 register char *out = sx25->x25_addr; 665 register char *in = siso->siso_data + 1; 666 register int nibble; 667 char *lim = siso->siso_data + siso->siso_nlen; 668 char *olim = out+15; 669 int lowNibble = 0; 670 671 while (in < lim) { 672 nibble = ((lowNibble ? *in++ : (*in >> 4)) & 0xf) | 0x30; 673 lowNibble ^= 1; 674 if (nibble != 0x3f && out < olim) 675 *out++ = nibble; 676 } 677 dtelen = out - sx25->x25_addr; 678 *out++ = 0; 679 } else { 680 register struct rtentry *rt = rtalloc1(siso, 1); 681 /* error = iso_8208snparesolve(addr, x121string, &x121strlen);*/ 682 683 if (rt) { 684 register struct sockaddr_x25 *sxx = 685 (struct sockaddr_x25 *)rt->rt_gateway; 686 register char *in = sxx->x25_addr; 687 688 rt->rt_use--; 689 if (sxx && sxx->x25_family == AF_CCITT) { 690 bcopy(sx25->x25_addr, sxx->x25_addr, sizeof(sx25->x25_addr)); 691 while (*in++) {} 692 dtelen = in - sxx->x25_addr; 693 } 694 } 695 } 696 return dtelen; 697 } 698 699 /* 700 * NAME: FACILtoNSAP() 701 * CALLED FROM: 702 * parse_facil() 703 * FUNCTION and ARGUMENTS: 704 * Creates and NSAP in the sockaddr_iso (addr) from the 705 * x.25 facility found at buf - 1. 706 * RETURNS: 707 * length of parameter if ok, -1 if error. 708 */ 709 710 Static int 711 FACILtoNSAP(addr, buf) 712 u_char *buf; 713 register struct sockaddr_iso *addr; 714 { 715 int len_in_nibbles, param_len = *buf++; 716 u_char buf_len; /* in bytes */ 717 718 IFDEBUG(D_CADDR) 719 printf("FACILtoNSAP( 0x%x, 0x%x, 0x%x )\n", 720 buf, buf_len, addr ); 721 ENDDEBUG 722 723 len_in_nibbles = *buf & 0x3f; 724 buf_len = (len_in_nibbles + 1) >> 1; 725 /* despite the fact that X.25 makes us put a length in nibbles 726 * here, the NSAP-addrs are always in full octets 727 */ 728 switch (*buf++ & 0xc0) { 729 case 0: 730 /* Entire OSI NSAP address */ 731 bcopy((caddr_t)buf, addr->siso_data, addr->siso_nlen = buf_len); 732 break; 733 734 case 40: 735 /* Partial OSI NSAP address, assume trailing */ 736 if (buf_len + addr->siso_nlen > sizeof(addr->siso_addr)) 737 return -1; 738 bcopy((caddr_t)buf, TSEL(addr), buf_len); 739 addr->siso_nlen += buf_len; 740 break; 741 742 default: 743 /* Rather than blow away the connection, just ignore and use 744 NSAP from DTE */; 745 } 746 return param_len; 747 } 748 749 static 750 init_siso(siso) 751 register struct sockaddr_iso *siso; 752 { 753 siso->siso_len = sizeof (*siso); 754 siso->siso_family = AF_ISO; 755 siso->siso_data[0] = AFI_37; 756 siso->siso_nlen = 8; 757 } 758 759 /* 760 * NAME: DTEtoNSAP() 761 * CALLED FROM: 762 * parse_facil() 763 * FUNCTION and ARGUMENTS: 764 * Creates a type 37 NSAP in the sockaddr_iso (addr) 765 * from a DTE address found in a sockaddr_x25. 766 * 767 * RETURNS: 768 * 0 if ok; E* otherwise. 769 */ 770 771 Static int 772 DTEtoNSAP(addr, sx) 773 struct sockaddr_iso *addr; 774 struct sockaddr_x25 *sx; 775 { 776 register char *in, *out; 777 register int first; 778 int pad_tail = 0; 779 int src_len; 780 781 782 init_siso(addr); 783 src_len = strlen(sx->x25_addr); 784 in = sx->x25_addr; 785 out = addr->siso_data + 1; 786 if (*in == '0' && (src_len & 1 == 0)) { 787 pad_tail = 0xf; 788 src_len++; 789 } 790 for (first = 0; src_len > 0; src_len --) { 791 first |= *in++; 792 if (src_len & 1) { 793 *out++ = first; 794 first = 0; 795 } 796 else first <<= 4; 797 } 798 if (pad_tail) 799 out[-1] |= 0xf; 800 return 0; /* ok */ 801 } 802 803 /* 804 * FUNCTION and ARGUMENTS: 805 * parses (buf_len) bytes beginning at (buf) and finds 806 * a called nsap, a calling nsap, and protocol identifier. 807 * RETURNS: 808 * 0 if ok, E* otherwise. 809 */ 810 811 static int 812 parse_facil(lcp, isop, buf, buf_len) 813 caddr_t buf; 814 u_char buf_len; /* in bytes */ 815 struct isopcb *isop; 816 struct pklcd *lcp; 817 { 818 register struct sockaddr_iso *called = isop->isop_laddr; 819 register struct sockaddr_iso *calling = isop->isop_faddr; 820 register int i; 821 register u_char *ptr = (u_char *)buf; 822 u_char *ptr_lim, *facil_lim; 823 int facil_param_len, facil_len; 824 825 IFDEBUG(D_CADDR) 826 printf("parse_facil(0x%x, 0x%x, 0x%x, 0x%x)\n", 827 buf, buf_len, called, calling); 828 dump_buf(buf, buf_len); 829 ENDDEBUG 830 831 /* find the beginnings of the facility fields in buf 832 * by skipping over the called & calling DTE addresses 833 * i <- # nibbles in called + # nibbles in calling 834 * i += 1 so that an odd nibble gets rounded up to even 835 * before dividing by 2, then divide by two to get # octets 836 */ 837 i = (int)(*ptr >> 4) + (int)(*ptr&0xf); 838 i++; 839 ptr += i >> 1; 840 ptr ++; /* plus one for the DTE lengths byte */ 841 842 /* ptr now is at facil_length field */ 843 facil_len = *ptr++; 844 facil_lim = ptr + facil_len; 845 IFDEBUG(D_CADDR) 846 printf("parse_facils: facil length is 0x%x\n", (int) facil_len); 847 ENDDEBUG 848 849 while (ptr <= facil_lim) { 850 /* get NSAP addresses from facilities */ 851 switch (*ptr++) { 852 case 0xcb: 853 /* calling NSAP */ 854 facil_param_len = FACILtoNSAP(isop->isop_faddr, ptr); 855 break; 856 case 0xc9: 857 /* called NSAP */ 858 facil_param_len = FACILtoNSAP(isop->isop_laddr, ptr); 859 break; 860 861 /* from here to default are legit cases that I ignore */ 862 /* variable length */ 863 case 0xca: /* end-to-end transit delay negot */ 864 case 0xc6: /* network user id */ 865 case 0xc5: /* charging info : indicating monetary unit */ 866 case 0xc2: /* charging info : indicating segment count */ 867 case 0xc1: /* charging info : indicating call duration */ 868 case 0xc4: /* RPOA extended format */ 869 case 0xc3: /* call redirection notification */ 870 facil_param_len = 0; 871 break; 872 873 /* 1 octet */ 874 case 0x0a: /* min. throughput class negot */ 875 case 0x02: /* throughput class */ 876 case 0x03: case 0x47: /* CUG shit */ 877 case 0x0b: /* expedited data negot */ 878 case 0x01: /* Fast select or reverse charging 879 (example of intelligent protocol design) */ 880 case 0x04: /* charging info : requesting service */ 881 case 0x08: /* called line addr modified notification */ 882 facil_param_len = 1; 883 break; 884 885 /* any 2 octets */ 886 case 0x42: /* pkt size */ 887 case 0x43: /* win size */ 888 case 0x44: /* RPOA basic format */ 889 case 0x41: /* bilateral CUG shit */ 890 case 0x49: /* transit delay selection and indication */ 891 facil_param_len = 2; 892 break; 893 894 /* don't have any 3 octets */ 895 /* 896 facil_param_len = 3; 897 */ 898 default: 899 printf( 900 "BOGUS FACILITY CODE facil_len 0x%x *facil_len 0x%x, ptr 0x%x *ptr 0x%x\n", 901 ptr, facil_len, ptr - 1, ptr[-1]); 902 /* facil that we don't handle */ 903 return E_CO_HLI_REJI; 904 } 905 if (facil_param_len == -1) 906 return E_CO_REG_ICDA; 907 if (facil_param_len == 0) /* variable length */ 908 facil_param_len = (int)*ptr; /* 1 + the real facil param */ 909 ptr += facil_param_len; 910 } 911 return 0; 912 } 913 914 #endif TPCONS 915