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