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