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