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.8 (Berkeley) 05/06/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, m0) 297 struct pklcd *lcp; 298 struct mbuf *m0; 299 { 300 register struct mbuf *m = m0->m_next; /* m0 has calling sockaddr_x25 */ 301 register struct isopcb *isop; 302 extern struct isopcb tp_isopcb; 303 int cons_tpinput(); 304 305 if (iso_pcballoc((struct socket *)0, &tp_incoming_pending)) { 306 m_freem(m); 307 pk_clear(lcp); 308 return; 309 } 310 isop = tp_incoming_pending.isop_next; 311 pk_output(lcp); /* Confirms call */ 312 lcp->lcd_upper = cons_tpinput; 313 lcp->lcd_upnext = (caddr_t)isop; 314 isop->isop_chan = (caddr_t)lcp; 315 isop->isop_laddr = &isop->isop_sladdr; 316 isop->isop_faddr = &isop->isop_sfaddr; 317 DTEtoNSAP(isop->isop_laddr, &lcp->lcd_laddr); 318 DTEtoNSAP(isop->isop_faddr, &lcp->lcd_faddr); 319 parse_facil(isop, lcp, &(mtod(m, struct x25_packet *)->packet_data), 320 m->m_pkthdr.len - PKHEADERLN); 321 m_freem(m); 322 } 323 324 cons_tpinput(lcp, m0) 325 struct mbuf *m0; 326 struct pklcd *lcp; 327 { 328 register struct isopcb *isop = (struct isopcb *)lcp->lcd_upnext; 329 register struct x25_packet *xp; 330 int cmd; 331 332 if (isop == 0) 333 return; 334 if (m0 == 0) { 335 isop->isop_chan = 0; 336 isop->isop_refcnt = 0; 337 lcp->lcd_upnext = 0; 338 lcp->lcd_upper = 0; 339 goto dead; 340 } 341 switch(m0->m_type) { 342 case MT_DATA: 343 case MT_OOBDATA: 344 tpcons_input(m0, isop->isop_faddr, isop->isop_laddr, 345 (struct socket *)0, (caddr_t)lcp); 346 347 case MT_CONTROL: 348 switch (pk_decode(mtod(m0, struct x25_packet *))) { 349 default: 350 return; 351 352 case RR: 353 cmd = PRC_CONS_SEND_DONE; 354 break; 355 356 case CALL_ACCEPTED: 357 if (lcp->lcd_sb.sb_mb) 358 lcp->lcd_send(lcp); /* XXX - fix this */ 359 break; 360 361 dead: 362 case RESET: 363 case CLEAR: 364 case CLEAR_CONF: 365 cmd = PRC_ROUTEDEAD; 366 } 367 tpcons_ctlinput(cmd, isop->isop_faddr, isop); 368 } 369 } 370 371 /* 372 * NAME: cons_connect() 373 * CALLED FROM: 374 * tpcons_pcbconnect() when opening a new connection. 375 * FUNCTION anD ARGUMENTS: 376 * Figures out which device to use, finding a route if one doesn't 377 * already exist. 378 * RETURN VALUE: 379 * returns E* 380 */ 381 cons_connect(isop) 382 register struct isopcb *isop; 383 { 384 register struct pklcd *lcp = (struct pklcd *)isop->isop_chan; 385 register struct mbuf *m; 386 struct ifaddr *ifa; 387 388 IFDEBUG(D_CCONN) 389 printf("cons_connect(0x%x): ", isop); 390 dump_isoaddr(isop->isop_faddr); 391 printf("myaddr: "); 392 dump_isoaddr(isop->isop_laddr); 393 printf("\n" ); 394 ENDDEBUG 395 NSAPtoDTE(isop->isop_faddr, &lcp->lcd_faddr); 396 lcp->lcd_upper = cons_tpinput; 397 lcp->lcd_upnext = (caddr_t)isop; 398 IFDEBUG(D_CCONN) 399 printf( 400 "calling make_partial_x25_packet( 0x%x, 0x%x, 0x%x)\n", 401 &lcp->lcd_faddr, &lcp->lcd_laddr, 402 isop->isop_socket->so_proto->pr_protocol); 403 ENDDEBUG 404 return (make_partial_x25_packet(isop, lcp, m) || 405 pk_connect(lcp, &lcp->lcd_faddr)); 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 MGET(m, MT_DATA, M_WAITOK); 555 if (m == 0) 556 return ENOBUFS; 557 buf = mtod(m, caddr_t); 558 ptr = buf; 559 IFDEBUG(D_CCONN) 560 printf("make_partial_x25_packet(0x%x, 0x%x, 0x%x, 0x%x, 0x%x)\n", 561 isop->isop_laddr, isop->isop_faddr, proto, m, flag); 562 ENDDEBUG 563 564 /* ptr now points to facil length (len of whole facil field in OCTETS */ 565 facil_len = ptr ++; 566 567 IFDEBUG(D_CADDR) 568 printf("make_partial calling: ptr 0x%x, len 0x%x\n", ptr, 569 isop->isop_laddr->siso_addr.isoa_len); 570 ENDDEBUG 571 if (cons_use_facils) { 572 *ptr = 0xcb; /* calling facility code */ 573 ptr ++; 574 ptr ++; /* leave room for facil param len (in OCTETS + 1) */ 575 ptr ++; /* leave room for the facil param len (in nibbles), 576 * high two bits of which indicate full/partial NSAP 577 */ 578 len = isop->isop_laddr->siso_addr.isoa_len; 579 bcopy( isop->isop_laddr->siso_data, ptr, len); 580 *(ptr-2) = len+2; /* facil param len in octets */ 581 *(ptr-1) = len<<1; /* facil param len in nibbles */ 582 ptr += len; 583 584 IFDEBUG(D_CADDR) 585 printf("make_partial called: ptr 0x%x, len 0x%x\n", ptr, 586 isop->isop_faddr->siso_addr.isoa_len); 587 ENDDEBUG 588 *ptr = 0xc9; /* called facility code */ 589 ptr ++; 590 ptr ++; /* leave room for facil param len (in OCTETS + 1) */ 591 ptr ++; /* leave room for the facil param len (in nibbles), 592 * high two bits of which indicate full/partial NSAP 593 */ 594 len = isop->isop_faddr->siso_nlen; 595 bcopy(isop->isop_faddr->siso_data, ptr, len); 596 *(ptr-2) = len+2; /* facil param len = addr len + 1 for each of these 597 * two length fields, in octets */ 598 *(ptr-1) = len<<1; /* facil param len in nibbles */ 599 ptr += len; 600 601 } 602 *facil_len = ptr - facil_len - 1; 603 if (*facil_len > MAX_FACILITIES) 604 return E_CO_PNA_LONG; 605 606 if (cons_use_udata) { 607 if (isop->isop_x25crud_len > 0) { 608 /* 609 * The user specified something. Stick it in 610 */ 611 bcopy(isop->isop_x25crud, lcp->lcd_faddr.x25_udata, 612 isop->isop_x25crud_len); 613 lcp->lcd_faddr.x25_udlen = isop->isop_x25crud_len; 614 } 615 } 616 617 buflen = (int)(ptr - buf); 618 619 IFDEBUG(D_CDUMP_REQ) 620 register int i; 621 622 printf("ECN_CONNECT DATA buf 0x%x len %d (0x%x)\n", 623 buf, buflen, buflen); 624 for( i=0; i < buflen; ) { 625 printf("+%d: %x %x %x %x %x %x %x %x\n", 626 i, 627 *(buf+i), *(buf+i+1), *(buf+i+2), *(buf+i+3), 628 *(buf+i+4), *(buf+i+5), *(buf+i+6), *(buf+i+7)); 629 i+=8; 630 } 631 ENDDEBUG 632 IFDEBUG(D_CADDR) 633 printf("make_partial returns buf 0x%x size 0x%x bytes\n", 634 mtod(m, caddr_t), buflen); 635 ENDDEBUG 636 637 if (buflen > MHLEN) 638 return E_CO_PNA_LONG; 639 640 m->m_len = buflen; 641 lcp->lcd_facilities = m; 642 return 0; 643 } 644 645 /* 646 * NAME: NSAPtoDTE() 647 * CALLED FROM: 648 * make_partial_x25_packet() 649 * FUNCTION and ARGUMENTS: 650 * get a DTE address from an NSAP-address (struct sockaddr_iso) 651 * (dst_octet) is the octet into which to begin stashing the DTE addr 652 * (dst_nibble) takes 0 or 1. 1 means begin filling in the DTE addr 653 * in the high-order nibble of dst_octet. 0 means low-order nibble. 654 * (addr) is the NSAP-address 655 * (flag) is true if the transport suffix is to become the 656 * last two digits of the DTE address 657 * A DTE address is a series of ASCII digits 658 * 659 * A DTE address may have leading zeros. The are significant. 660 * 1 digit per nibble, may be an odd number of nibbles. 661 * 662 * An NSAP-address has the DTE address in the IDI. Leading zeros are 663 * significant. Trailing hex f indicates the end of the DTE address. 664 * The IDI is a series of BCD digits, one per nibble. 665 * 666 * RETURNS 667 * # significant digits in the DTE address, -1 if error. 668 */ 669 670 Static int 671 NSAPtoDTE(siso, sx25) 672 register struct sockaddr_iso *siso; 673 register struct sockaddr_x25 *sx25; 674 { 675 int dtelen = -1; 676 677 IFDEBUG(D_CADDR) 678 printf("NSAPtoDTE: nsap: %s\n", clnp_iso_addrp(&siso->siso_addr)); 679 ENDDEBUG 680 681 if (siso->siso_data[0] == AFI_37) { 682 register char *out = sx25->x25_addr; 683 register char *in = siso->siso_data + 1; 684 register int nibble; 685 char *lim = siso->siso_data + siso->siso_nlen; 686 char *olim = out+15; 687 int lowNibble = 0; 688 689 while (in < lim) { 690 nibble = ((lowNibble ? *in++ : (*in >> 4)) & 0xf) | 0x30; 691 lowNibble ^= 1; 692 if (nibble != 0x3f && out < olim) 693 *out++ = nibble; 694 } 695 dtelen = out - sx25->x25_addr; 696 *out++ = 0; 697 } else { 698 register struct rtentry *rt = rtalloc1(siso, 1); 699 /* error = iso_8208snparesolve(addr, x121string, &x121strlen);*/ 700 701 if (rt) { 702 register struct sockaddr_x25 *sxx = 703 (struct sockaddr_x25 *)rt->rt_gateway; 704 register char *in = sxx->x25_addr; 705 706 rt->rt_use--; 707 if (sxx && sxx->x25_family == AF_CCITT) { 708 bcopy(sx25->x25_addr, sxx->x25_addr, sizeof(sx25->x25_addr)); 709 while (*in++) {} 710 dtelen = in - sxx->x25_addr; 711 } 712 } 713 } 714 return dtelen; 715 } 716 717 /* 718 * NAME: FACILtoNSAP() 719 * CALLED FROM: 720 * parse_facil() 721 * FUNCTION and ARGUMENTS: 722 * Creates and NSAP in the sockaddr_iso (addr) from the 723 * x.25 facility found at buf - 1. 724 * RETURNS: 725 * length of parameter if ok, -1 if error. 726 */ 727 728 Static int 729 FACILtoNSAP(addr, buf) 730 u_char *buf; 731 register struct sockaddr_iso *addr; 732 { 733 int len_in_nibbles, param_len = *buf++; 734 u_char buf_len; /* in bytes */ 735 736 IFDEBUG(D_CADDR) 737 printf("FACILtoNSAP( 0x%x, 0x%x, 0x%x )\n", 738 buf, buf_len, addr ); 739 ENDDEBUG 740 741 len_in_nibbles = *buf & 0x3f; 742 buf_len = (len_in_nibbles + 1) >> 1; 743 /* despite the fact that X.25 makes us put a length in nibbles 744 * here, the NSAP-addrs are always in full octets 745 */ 746 switch (*buf++ & 0xc0) { 747 case 0: 748 /* Entire OSI NSAP address */ 749 bcopy((caddr_t)buf, addr->siso_data, addr->siso_nlen = buf_len); 750 break; 751 752 case 40: 753 /* Partial OSI NSAP address, assume trailing */ 754 if (buf_len + addr->siso_nlen > sizeof(addr->siso_addr)) 755 return -1; 756 bcopy((caddr_t)buf, TSEL(addr), buf_len); 757 addr->siso_nlen += buf_len; 758 break; 759 760 default: 761 /* Rather than blow away the connection, just ignore and use 762 NSAP from DTE */; 763 } 764 return param_len; 765 } 766 767 static 768 init_siso(siso) 769 register struct sockaddr_iso *siso; 770 { 771 siso->siso_len = sizeof (*siso); 772 siso->siso_family = AF_ISO; 773 siso->siso_data[0] = AFI_37; 774 siso->siso_nlen = 8; 775 } 776 777 /* 778 * NAME: DTEtoNSAP() 779 * CALLED FROM: 780 * parse_facil() 781 * FUNCTION and ARGUMENTS: 782 * Creates a type 37 NSAP in the sockaddr_iso (addr) 783 * from a DTE address found in a sockaddr_x25. 784 * 785 * RETURNS: 786 * 0 if ok; E* otherwise. 787 */ 788 789 Static int 790 DTEtoNSAP(addr, sx) 791 struct sockaddr_iso *addr; 792 struct sockaddr_x25 *sx; 793 { 794 register char *in, *out; 795 register int first; 796 int pad_tail = 0; 797 int src_len; 798 799 800 init_siso(addr); 801 src_len = strlen(sx->x25_addr); 802 in = sx->x25_addr; 803 out = addr->siso_data + 1; 804 if (*in == '0' && (src_len & 1 == 0)) { 805 pad_tail = 0xf; 806 src_len++; 807 } 808 for (first = 0; src_len > 0; src_len --) { 809 first |= *in++; 810 if (src_len & 1) { 811 *out++ = first; 812 first = 0; 813 } 814 else first <<= 4; 815 } 816 if (pad_tail) 817 out[-1] |= 0xf; 818 return 0; /* ok */ 819 } 820 821 /* 822 * FUNCTION and ARGUMENTS: 823 * parses (buf_len) bytes beginning at (buf) and finds 824 * a called nsap, a calling nsap, and protocol identifier. 825 * RETURNS: 826 * 0 if ok, E* otherwise. 827 */ 828 829 static int 830 parse_facil(lcp, isop, buf, buf_len) 831 caddr_t buf; 832 u_char buf_len; /* in bytes */ 833 struct isopcb *isop; 834 struct pklcd *lcp; 835 { 836 register struct sockaddr_iso *called = isop->isop_laddr; 837 register struct sockaddr_iso *calling = isop->isop_faddr; 838 register int i; 839 register u_char *ptr = (u_char *)buf; 840 u_char *ptr_lim, *facil_lim; 841 int facil_param_len, facil_len; 842 843 IFDEBUG(D_CADDR) 844 printf("parse_facil(0x%x, 0x%x, 0x%x, 0x%x)\n", 845 buf, buf_len, called, calling); 846 dump_buf(buf, buf_len); 847 ENDDEBUG 848 849 /* find the beginnings of the facility fields in buf 850 * by skipping over the called & calling DTE addresses 851 * i <- # nibbles in called + # nibbles in calling 852 * i += 1 so that an odd nibble gets rounded up to even 853 * before dividing by 2, then divide by two to get # octets 854 */ 855 i = (int)(*ptr >> 4) + (int)(*ptr&0xf); 856 i++; 857 ptr += i >> 1; 858 ptr ++; /* plus one for the DTE lengths byte */ 859 860 /* ptr now is at facil_length field */ 861 facil_len = *ptr++; 862 facil_lim = ptr + facil_len; 863 IFDEBUG(D_CADDR) 864 printf("parse_facils: facil length is 0x%x\n", (int) facil_len); 865 ENDDEBUG 866 867 while (ptr <= facil_lim) { 868 /* get NSAP addresses from facilities */ 869 switch (*ptr++) { 870 case 0xcb: 871 /* calling NSAP */ 872 facil_param_len = FACILtoNSAP(isop->isop_faddr, ptr); 873 break; 874 case 0xc9: 875 /* called NSAP */ 876 facil_param_len = FACILtoNSAP(isop->isop_laddr, ptr); 877 break; 878 879 /* from here to default are legit cases that I ignore */ 880 /* variable length */ 881 case 0xca: /* end-to-end transit delay negot */ 882 case 0xc6: /* network user id */ 883 case 0xc5: /* charging info : indicating monetary unit */ 884 case 0xc2: /* charging info : indicating segment count */ 885 case 0xc1: /* charging info : indicating call duration */ 886 case 0xc4: /* RPOA extended format */ 887 case 0xc3: /* call redirection notification */ 888 facil_param_len = 0; 889 break; 890 891 /* 1 octet */ 892 case 0x0a: /* min. throughput class negot */ 893 case 0x02: /* throughput class */ 894 case 0x03: case 0x47: /* CUG shit */ 895 case 0x0b: /* expedited data negot */ 896 case 0x01: /* Fast select or reverse charging 897 (example of intelligent protocol design) */ 898 case 0x04: /* charging info : requesting service */ 899 case 0x08: /* called line addr modified notification */ 900 facil_param_len = 1; 901 break; 902 903 /* any 2 octets */ 904 case 0x42: /* pkt size */ 905 case 0x43: /* win size */ 906 case 0x44: /* RPOA basic format */ 907 case 0x41: /* bilateral CUG shit */ 908 case 0x49: /* transit delay selection and indication */ 909 facil_param_len = 2; 910 break; 911 912 /* don't have any 3 octets */ 913 /* 914 facil_param_len = 3; 915 */ 916 default: 917 printf( 918 "BOGUS FACILITY CODE facil_len 0x%x *facil_len 0x%x, ptr 0x%x *ptr 0x%x\n", 919 ptr, facil_len, ptr - 1, ptr[-1]); 920 /* facil that we don't handle */ 921 return E_CO_HLI_REJI; 922 } 923 if (facil_param_len == -1) 924 return E_CO_REG_ICDA; 925 if (facil_param_len == 0) /* variable length */ 926 facil_param_len = (int)*ptr; /* 1 + the real facil param */ 927 ptr += facil_param_len; 928 } 929 return 0; 930 } 931 932 #endif TPCONS 933