1 /*********************************************************** 2 Copyright IBM Corporation 1987 3 4 All Rights Reserved 5 6 Permission to use, copy, modify, and distribute this software and its 7 documentation for any purpose and without fee is hereby granted, 8 provided that the above copyright notice appear in all copies and that 9 both that copyright notice and this permission notice appear in 10 supporting documentation, and that the name of IBM not be 11 used in advertising or publicity pertaining to distribution of the 12 software without specific, written prior permission. 13 14 IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING 15 ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL 16 IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR 17 ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, 18 WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, 19 ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS 20 SOFTWARE. 21 22 ******************************************************************/ 23 24 /* 25 * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison 26 */ 27 /* 28 * $Header: if_cons.c,v 4.7 88/08/11 15:52:55 nhall Exp $ 29 * $Source: /usr/argo/sys/netiso/RCS/if_cons.c,v $ 30 * 31 * cons.c - Connection Oriented Network Service: 32 * including support for a) user transport-level service, 33 * b) COSNS below CLNP, and c) CONS below TP. 34 */ 35 36 #ifndef lint 37 static char *rcsid = "$Header: if_cons.c,v 4.7 88/08/11 15:52:55 nhall Exp $"; 38 #endif lint 39 40 #ifdef ARGO_DEBUG 41 #define Static 42 unsigned LAST_CALL_PCB; 43 #else ARGO_DEBUG 44 #define Static static 45 #endif ARGO_DEBUG 46 47 #include "ecn.h" 48 #include "argoxtwentyfive.h" 49 50 #if NARGOXTWENTYFIVE > 0 51 52 #ifdef KERNEL 53 54 #include "param.h" 55 #include "systm.h" 56 #include "mbuf.h" 57 #include "protosw.h" 58 #include "socket.h" 59 #include "socketvar.h" 60 #include "errno.h" 61 #include "ioctl.h" 62 #include "tsleep.h" 63 64 #include "../net/if.h" 65 #include "../net/netisr.h" 66 #include "../net/route.h" 67 68 #include "../netiso/iso_errno.h" 69 #include "../netiso/argo_debug.h" 70 #include "../netiso/tp_trace.h" 71 #include "../netiso/iso.h" 72 #include "../netiso/cons.h" 73 #include "../netiso/iso_pcb.h" 74 #include "../netiso/cons_pcb.h" 75 #include "../caif/eicon.h" 76 77 #ifdef ARGO_DEBUG 78 #define MT_XCONN 0x50 79 #define MT_XCLOSE 0x51 80 #define MT_XCONFIRM 0x52 81 #define MT_XDATA 0x53 82 #define MT_XHEADER 0x54 83 #else 84 #define MT_XCONN MT_DATA 85 #define MT_XCLOSE MT_DATA 86 #define MT_XCONFIRM MT_DATA 87 #define MT_XDATA MT_DATA 88 #define MT_XHEADER MT_HEADER 89 #endif ARGO_DEBUG 90 91 #define DONTCLEAR -1 92 93 /********************************************************************* 94 * cons.c - CONS interface to the eicon adapter 95 * Includes connection manager - for (TP, CLNP)/x.25 96 * 97 * TODO: figure out what resources we might run out of besides mbufs. 98 * If we run out of any of them (including mbufs) close and recycle 99 * lru x% of the connections, for some parameter x. 100 * 101 * There are 4 interfaces from above: 102 * 0) from CLNP: 103 * cons is an interface driver - CLNP calls 104 * cosns_output(ifp, m, dst), a device-type interface output routine 105 * that does some connection management stuff and queues a 106 * request on the eicon driver queue by calling ifp->if_output. 107 * The eicon's ifp structure contains cosns_output as its output routine 108 * rather than ifp_>if_output! Kludge, but we don't have much choice... 109 * X25 connections created in this manner may always be multiplexed 110 * but only with their own kind (not with connections servicing TP 111 * directly.) 112 * co_flags & CONSF_DGM 113 * 1) from TP0: 114 * cons CO network service 115 * TP associates a transport connection with a network connection. 116 * cons_output( isop, m, len, isdgm==0 ) 117 * co_flags == 0 118 * 2) from TP 4: 119 * It's a datagram service, like clnp is. - even though it calls 120 * cons_output( isop, m, len, isdgm==1 ) 121 * it eventually goes through 122 * cosns_output(ifp, m, dst). 123 * TP4 permits multiplexing (reuse, possibly simultaneously) of the 124 * network connections. 125 * This means that many sockets (many tpcbs) may be associated with 126 * this cons_pcb, hence cannot have a back ptr from cons_pcb to a tpcb. 127 * co_flags & CONSF_DGM 128 * co_socket is null since there may be many sockets that use this copcb. 129 * 3) from user: cons_usrreq(), cons_ctloutput() 130 * cons is a standard transport service interface. 131 * There is a 1-1 correspondence between net connections and sockets. 132 * co_socket points to a socket. 133 * 134 NOTE: 135 streams would really be nice. sigh. 136 NOTE: 137 eicon <--> cons interface: the first mbuf (the ecn_request structure) 138 had better NOT be a cluster. 139 NOTE: 140 PVCs could be handled by config-ing a cons with an address and with the 141 IFF_POINTTOPOINT flag on. This code would then have to skip the 142 connection setup stuff for pt-to-pt links. 143 NOTE: 144 We keep track of the ifp for each connection. Right now this is 145 unnecessary, but just in case someone comes up with some kind 146 of a kludge to allow > 1 eicon to be attached at a time, 147 (i.e., some meaningful netof( a type 37 address ) ), 148 we do keep track of this. 149 150 151 *********************************************************************/ 152 153 #define touch(copcb) copcb->co_ttl = copcb->co_init_ttl 154 155 #define CONS_IFQMAXLEN 5 156 157 #define SET_CHANMASK( isop, chan )\ 158 if( (u_int)(chan) < 32 ) \ 159 (isop)->isop_chanmask = (1<<((chan)-1));\ 160 else \ 161 (isop)->isop_negchanmask = (1<<((256-(chan))-1)) 162 163 #define ADD_CHANMASK( isop, chan )\ 164 if( (u_int)(chan) < 32 ) \ 165 (isop)->isop_chanmask |= (1<<((chan)-1));\ 166 else \ 167 (isop)->isop_negchanmask |= (1<<((256-(chan))-1)) 168 169 struct ifnet *consif; /* TO BE REMOVED */ 170 Static int consinit(), consioctl(), consattach(); 171 172 /* protosw pointers for getting to higher layer */ 173 Static struct protosw *CLNP_proto; 174 Static struct protosw *TP_proto; 175 Static struct protosw *X25_proto; 176 Static int issue_clear_req(); 177 178 #ifndef PHASEONE 179 extern struct ifaddr *ifa_ifwithnet(); 180 #endif PHASEONE 181 182 extern struct ifaddr *ifa_ifwithaddr(); 183 184 Static struct socket dummysocket; /* for use by cosns */ 185 186 extern struct isopcb tp_isopcb; /* chain of all TP pcbs */ 187 struct isopcb cons_isopcb; /* chain of all cons pcbs */ 188 struct isopcb tp_incoming_pending; /* incoming connections 189 for TP, pending */ 190 191 struct isopcb *Xpcblist[] = { 192 &cons_isopcb, 193 &tp_incoming_pending, 194 &tp_isopcb, 195 (struct isopcb *)0 196 }; 197 198 Static int parse_facil(), NSAPtoDTE(), make_partial_x25_packet(); 199 Static int FACILtoNSAP(), DTEtoNSAP(); 200 Static struct cons_pcb *cons_chan_to_pcb(); 201 202 #define HIGH_NIBBLE 1 203 #define LOW_NIBBLE 0 204 205 /* 206 * NAME: nibble_copy() 207 * FUNCTION and ARGUMENTS: 208 * copies (len) nibbles from (src_octet), high or low nibble 209 * to (dst_octet), high or low nibble, 210 * src_nibble & dst_nibble should be: 211 * HIGH_NIBBLE (1) if leftmost 4 bits/ most significant nibble 212 * LOW_NIBBLE (0) if rightmost 4 bits/ least significant nibble 213 * RETURNS: VOID 214 */ 215 void 216 nibble_copy( src_octet, src_nibble, dst_octet, dst_nibble, len) 217 register char *src_octet; 218 register char *dst_octet; 219 register unsigned src_nibble; 220 register unsigned dst_nibble; 221 int len; 222 { 223 224 register i; 225 register unsigned dshift, sshift; 226 227 IFDEBUG(D_CADDR) 228 printf("nibble_copy ( 0x%x, 0x%x, 0x%x, 0x%x 0x%x)\n", 229 src_octet, src_nibble, dst_octet, dst_nibble, len); 230 ENDDEBUG 231 #define SHIFT 0x4 232 233 dshift = dst_nibble << 2; 234 sshift = src_nibble << 2; 235 236 for (i=0; i<len; i++) { 237 /* clear dst_nibble */ 238 *dst_octet &= ~(0xf<< dshift); 239 240 /* set dst nibble */ 241 *dst_octet |= ( 0xf & (*src_octet >> sshift))<< dshift; 242 243 dshift ^= SHIFT; 244 sshift ^= SHIFT; 245 src_nibble = 1-src_nibble; 246 dst_nibble = 1-dst_nibble; 247 src_octet += src_nibble; 248 dst_octet += dst_nibble; 249 } 250 IFDEBUG(D_CADDR) 251 printf("nibble_copy DONE\n"); 252 ENDDEBUG 253 } 254 255 /* 256 * NAME: nibble_match() 257 * FUNCTION and ARGUMENTS: 258 * compares src_octet/src_nibble and dst_octet/dst_nibble for len nibbles. 259 * RETURNS: 0 if they differ, 1 if they are the same. 260 */ 261 int 262 nibble_match( src_octet, src_nibble, dst_octet, dst_nibble, len) 263 register char *src_octet; 264 register char *dst_octet; 265 register unsigned src_nibble; 266 register unsigned dst_nibble; 267 int len; 268 { 269 270 register i; 271 register unsigned dshift, sshift; 272 u_char nibble_a, nibble_b; 273 274 IFDEBUG(D_CADDR) 275 printf("nibble_match ( 0x%x, 0x%x, 0x%x, 0x%x 0x%x)\n", 276 src_octet, src_nibble, dst_octet, dst_nibble, len); 277 ENDDEBUG 278 #define SHIFT 0x4 279 280 dshift = dst_nibble << 2; 281 sshift = src_nibble << 2; 282 283 for (i=0; i<len; i++) { 284 nibble_b = ((*dst_octet)>>dshift) & 0xf; 285 nibble_a = ( 0xf & (*src_octet >> sshift)); 286 if( nibble_b != nibble_a ) 287 return 0; 288 289 dshift ^= SHIFT; 290 sshift ^= SHIFT; 291 src_nibble = 1-src_nibble; 292 dst_nibble = 1-dst_nibble; 293 src_octet += src_nibble; 294 dst_octet += dst_nibble; 295 } 296 IFDEBUG(D_CADDR) 297 printf("nibble_match DONE\n"); 298 ENDDEBUG 299 return 1; 300 } 301 302 #ifdef ARGO_DEBUG 303 304 Static 305 dump_copcb(copcb, str) 306 char * str; 307 register struct cons_pcb *copcb; 308 { 309 printf("XPCB DUMP %s\n", str); 310 if (copcb) { 311 printf("\t copcb 0x%x next 0x%x head 0x%x socket 0x%x ifp 0x%x\n", 312 copcb, copcb->co_next, copcb->co_head, copcb->co_socket, copcb->co_ifp); 313 printf("\t channel 0x%x state 0x%x flags 0x%x proto 0x%x\n", 314 copcb->co_channel, copcb->co_state, copcb->co_flags, copcb->co_proto); 315 printf("\t laddr :\n"); 316 dump_isoaddr(&copcb->co_laddr); 317 printf("\t faddr :\n"); 318 dump_isoaddr(&copcb->co_faddr); 319 printf("\tttl 0x%x init_ttl 0x%x pending: %d\n", 320 copcb->co_ttl, copcb->co_init_ttl, copcb->co_pending.ifq_len); 321 } 322 printf("END DUMP\n"); 323 } 324 #endif ARGO_DEBUG 325 326 /* 327 * FUNCTION : choose_output - chooses between the eicon and loopback. 328 * This MUST be here because the ifp->if_output routine is cosns_output 329 * -- due to our need to look like a device driver for CLNP. sigh. 330 * ARGUMENTS & PURPOSE: (copcb) ptr to a protocol control block for 331 * x.25, (m) is an mbuf ptr. *m is a request destined either 332 * for the eicon driver or for the loopback driver. 333 * RETURNS : whatever error value the 2I or loopback returns. 334 */ 335 Static int 336 choose_output( ifp, m, loop) 337 struct ifnet *ifp; 338 struct mbuf *m; 339 int loop; 340 { 341 int error; 342 343 if( !m ) 344 return 0; 345 ASSERT(m->m_len != 0); 346 if( loop != 0) 347 error = lpboutput( ifp, m ); 348 else 349 error = ecnoutput( ifp, m ); 350 351 if (error == 0) 352 ifp->if_opackets ++; 353 else { 354 ifp->if_oerrors ++; 355 IFTRACE(D_CDATA) 356 tptrace( TPPTmisc, 357 "choose_output: ifp m error loop\n", 358 ifp, m, error, loop); 359 ENDTRACE 360 } 361 IFDEBUG(D_CCONS) 362 printf("choose_output returns 0x%x\n", error ); 363 ENDDEBUG 364 return error; 365 } 366 367 /* 368 **************************** NET PROTOCOL cons *************************** 369 */ 370 371 /* 372 * NAME: cons_init() 373 * CALLED FROM: 374 * autoconf 375 * FUNCTION: 376 * initialize the protocol 377 */ 378 cons_init() 379 { 380 init_lpb(); 381 consattach(); 382 383 /* protocol init stuff */ 384 385 consintrq.ifq_maxlen = IFQ_MAXLEN; 386 consintrq.ifq_head = consintrq.ifq_tail = (struct mbuf *)0; 387 388 CLNP_proto = pffindproto(AF_ISO, ISOPROTO_CLNP, SOCK_DGRAM); 389 X25_proto = pffindproto(AF_ISO, ISOPROTO_X25, SOCK_STREAM); 390 TP_proto = pffindproto(AF_ISO, ISOPROTO_TP0, SOCK_SEQPACKET); 391 IFDEBUG(D_CCONS) 392 printf("cons_init end : cnlp_proto 0x%x cons proto 0x%x tp proto 0x%x\n", 393 CLNP_proto, X25_proto, TP_proto); 394 ENDDEBUG 395 396 cons_isopcb.isop_next = cons_isopcb.isop_prev = &cons_isopcb; 397 tp_incoming_pending.isop_next = tp_incoming_pending.isop_prev = 398 &tp_incoming_pending; 399 } 400 401 #ifdef notdef 402 403 /* 404 * NAME: cons_free_lru() 405 * some day CALLED FROM: 406 * wherever we run out of mbufs (not used right yet) 407 * FUNCTION: 408 * get rid of the num least recently used connections and 409 * recycle their mbufs. 410 * NOTE: GROTESQUELY INEFFICIENT needs to be written nicely 411 */ 412 413 Static 414 cons_free_lru(qty) 415 int qty; 416 { 417 register struct cons_pcb **copcblist = (struct cons_pcb **)Xpcblist; 418 register struct cons_pcb *copcb; 419 struct cons_pcb Lru; 420 struct cons_pcb *lru; 421 422 IFDEBUG(D_CCONS) 423 printf("cons_free_lru( 0x%x )\n", qty); 424 ENDDEBUG 425 426 Lru.co_ttl = X25_TTL; 427 lru = &Lru; 428 429 while (qty > 1) { /* GROT */ 430 cons_free_lru( 1 ); 431 qty -- ; 432 } 433 434 for( copcb = *copcblist; copcb; copcb = *(++copcblist) ) { 435 copcb = (struct cons_pcb *)copcb->co_next; 436 while (copcb != *copcblist) { 437 if( copcb->co_ttl < lru->co_ttl ) 438 lru = copcb; 439 copcb = (struct cons_pcb *)copcb->co_next; 440 } 441 } 442 443 if(lru->co_socket) { 444 soisdisconnected(lru->co_socket); 445 sohasoutofband(lru->co_socket); /* signal */ 446 } 447 448 cons_clear_and_detach( lru, E_CO_HLI_RESYNC, PRC_TIMXCEED_REASS); 449 } 450 #endif notdef 451 452 /* 453 * NAME: cons_slowtimo() 454 * CALLED FROM: 455 * the clock 456 * FUNCTION: 457 * get rid of any timed-out cons connections 458 * cons connections get "touched" with every use, meaning the 459 * time-to-live gets reset to its max value w/ every use. 460 * The slowtimo() rtn decrements the time-to-live for each 461 * cons connection. If one of them hits zero ---> zap the connection. 462 * This really only applies to those used for CLNP and TP4. 463 * TP4 keeps the connections open with keepalive. 464 * TODO: 465 * Have this happen ONLY for international connections since 466 * there's no connect time charge for domestic calls. 467 * Make default 5 min; make a user option to change it. 468 * TODO: 469 * Maybe if the ttl gets lower than a certain threshold, move this 470 * copcb to the END of its queue so it doesn't slow down the others. 471 */ 472 473 cons_slowtimo() 474 { 475 register struct cons_pcb **copcblist = (struct cons_pcb **)Xpcblist; 476 register struct cons_pcb *copcb; 477 int s = splnet(); 478 int qlen = 0; 479 int qdrops = 0; 480 int nvisited = 0; 481 482 #ifdef ARGO_DEBUG 483 Static int count; 484 485 count = 0; 486 #endif ARGO_DEBUG 487 488 IncStat(co_slowtimo); 489 for( copcb = *copcblist; copcb; copcb = *(++copcblist) ) { 490 #ifdef ARGO_DEBUG 491 if( copcb == (struct cons_pcb *)0 ) { 492 ASSERT( 0 ); 493 panic("TURNING OFF cons_slowtimo()!!! \n"); 494 } 495 #endif ARGO_DEBUG 496 copcb = (struct cons_pcb *)copcb->co_next; 497 while (copcb != *copcblist) { 498 #ifdef ARGO_DEBUG 499 if(++count >50 ) { 500 printf("cons PANIC: slowtimo LOOP\n"); 501 splx(s); 502 return; 503 } 504 #endif ARGO_DEBUG 505 #ifdef notdef 506 if( copcb->co_init_ttl == 0 ) { 507 ASSERT( (struct isopcb *)(*copcblist)==(struct isopcb *)&tp_isopcb ); 508 copcb = (struct cons_pcb *)copcb->co_next; 509 continue; 510 } 511 #endif notdef 512 nvisited ++; 513 ASSERT( copcb != (struct cons_pcb *)0 ); 514 qlen += copcb->co_pending.ifq_len; 515 qdrops += copcb->co_pending.ifq_drops; 516 517 if( copcb->co_socket) { 518 /* don't want XTS, TP0 connections to be subject to time out */ 519 copcb = (struct cons_pcb *)copcb->co_next; 520 continue; 521 } 522 523 if( -- (copcb->co_ttl) > 0 ) { 524 copcb = (struct cons_pcb *)copcb->co_next; 525 continue; 526 } 527 528 IncStat(co_timedout); 529 530 IFDEBUG(D_CCONN) 531 printf("TIMING OUT chan 0x%x copcb 0x%x flags 0x%x\n", 532 copcb->co_channel, copcb, copcb->co_flags ); 533 ENDDEBUG 534 535 { 536 register struct cons_pcb * next = 537 (struct cons_pcb *)copcb->co_next; 538 cons_clear_and_detach(copcb, 539 E_CO_HLI_RESYNC, PRC_TIMXCEED_REASS); 540 copcb = next; 541 } 542 } 543 } 544 if(nvisited) { 545 cons_stat.co_avg_qlen = qlen / nvisited; 546 cons_stat.co_avg_qdrop = qdrops / nvisited; 547 cons_stat.co_active = nvisited; 548 } 549 done: 550 splx(s); 551 } 552 553 DUMP_PCBLIST() 554 { 555 register int i=0; 556 register struct cons_pcb *copcb; 557 register struct cons_pcb **copcblist = (struct cons_pcb **)Xpcblist; 558 559 for( copcb = *copcblist; copcb; copcb = *(++copcblist) ) { 560 printf("FOR %d: 0x%x ", ++i, copcb); 561 copcb = (struct cons_pcb *)copcb->co_next; 562 printf(" next 0x%x, *copcblist 0x%x\n", copcb, *copcblist); 563 while (copcb != *copcblist) { 564 ASSERT( copcb != (struct cons_pcb *)0 ); 565 printf("\tCOPCB 0x%x\n", copcb); 566 if( copcb ) 567 dump_buf(copcb, sizeof( *copcb)); 568 else 569 break; 570 copcb = (struct cons_pcb *)copcb->co_next; 571 } 572 } 573 } 574 575 /* 576 * NAME: cons_pcballoc() 577 * CALLED FROM: 578 * cons_usrreq() when doing PRU_ATTACH, 579 * cons_incoming() when opening a new connection. 580 * FUNCTION and ARGUMENTS: 581 * Allocates a new pcb. 582 * The flags and proto arguments are stashed into the new pcb. 583 * RETURN VALUE: 584 * E* if error, 0 if ok 585 */ 586 Static int 587 cons_pcballoc(so, head, flags, proto, dest) 588 struct socket *so; 589 struct isopcb *head; 590 u_short flags; 591 struct protosw *proto; 592 struct cons_pcb **dest; 593 { 594 int error; 595 register struct cons_pcb *copcb; 596 597 IFDEBUG(D_CCONN) 598 printf("cons_pcballoc (0x%x, 0x%x, 0x%x, 0x%x, 0x%x\n", 599 so, head, flags, proto, dest); 600 ENDDEBUG 601 if(proto == (struct protosw *)0) 602 return EPROTONOSUPPORT; 603 604 if( ( error = iso_pcballoc(so, head) ) == EOK ) { 605 /* Have allocated a cleared mbuf */ 606 607 copcb = (struct cons_pcb *)so->so_pcb; 608 copcb->co_ttl = copcb->co_init_ttl = X25_TTL; 609 copcb->co_flags = flags; 610 copcb->co_proto = proto; 611 copcb->co_pending.ifq_maxlen = CONS_IFQMAXLEN; 612 copcb->co_myself = copcb; 613 614 if (so == &dummysocket) 615 copcb->co_socket = (struct socket *)0; 616 617 *dest = copcb; 618 } 619 done: 620 IFDEBUG(D_CCONN) 621 printf("cons_pcballoc returns 0x%x: DUMP\n", copcb); 622 dump_buf( copcb, sizeof(*copcb)); 623 ENDDEBUG 624 if( (flags & CONSF_ICRE) == 0) { 625 struct dte_addr *dtea = &(*dest)->co_peer_dte; 626 int len; 627 628 error = iso_8208snparesolve(&(*dest)->co_faddr, dtea, &len); 629 ASSERT(error == 0); 630 ASSERT(len == sizeof(struct dte_addr)); 631 } 632 633 return error; 634 } 635 636 /* 637 * NAME: cons_connect() 638 * CALLED FROM: 639 * cons_usrreq() when opening a new connection. 640 * FUNCTION anD ARGUMENTS: 641 * Figures out which device to use, finding a route if one doesn't 642 * already exist. 643 * Builds an eicon connection request and gives it to the device. 644 * RETURN VALUE: 645 * returns E* 646 */ 647 Static int 648 cons_connect( copcb ) 649 register struct cons_pcb *copcb; 650 { 651 register struct eicon_request *ecnrq; 652 register struct mbuf *m; 653 int error = 0; 654 struct ifaddr *ifa; 655 656 IFDEBUG(D_CCONN) 657 printf("cons_connect( 0x%x ) : ifp 0x%x\npeer: ", copcb, copcb->co_ifp); 658 dump_isoaddr(&copcb->co_faddr); 659 printf("\nmyaddr: "); 660 dump_isoaddr(&copcb->co_laddr); 661 printf("\n" ); 662 ENDDEBUG 663 664 /* PHASE 2: this call is OK */ 665 if( ifa = ifa_ifwithaddr(&copcb->co_faddr ) ) { 666 /* foreign address is me */ 667 copcb->co_ifp = ifa->ifa_ifp; 668 IFDEBUG(D_CCONN) 669 printf("cons_connect: after if_withaddr copcb->co_ifp 0x%x\n", 670 copcb->co_ifp); 671 ENDDEBUG 672 673 if( (ifa->ifa_ifp->if_flags&(IFF_LOOPBACK|IFF_UP)) == 674 (IFF_LOOPBACK|IFF_UP)) { 675 copcb->co_flags |= CONSF_LOOPBACK; 676 } 677 bcopy((caddr_t)&ifa->ifa_addr, (caddr_t)&copcb->co_laddr, 678 sizeof(struct sockaddr)); 679 } 680 IFDEBUG(D_CCONN) 681 printf("cons_connect: co_flags 0x%x\n", copcb->co_flags); 682 if( ifa ) { 683 printf(" cons_connect withaddr returns %s\n", 684 copcb->co_ifp->if_name); 685 } 686 ENDDEBUG 687 else if ( copcb->co_ifp == (struct ifnet *)0 ) { 688 #ifdef PHASEONE 689 /* 690 * We need to get the local nsap address. 691 * First, route to the destination. This will provide us with 692 * an ifp. Second, determine which local address linked on 693 * that ifp is appropriate 694 */ 695 struct sockaddr_iso *first_hop; /* filled by clnp_route */ 696 struct iso_addr *localaddr, *clnp_srcaddr(); 697 698 if (error = clnp_route(&copcb->co_faddr, 699 &((struct isopcb *)copcb)->isop_route, /* flags */0, 700 &first_hop, &copcb->co_ifp)) 701 goto bad; 702 703 /* determine local address based upon ifp */ 704 if ((localaddr = clnp_srcaddr(copcb->co_ifp, 705 &first_hop->siso_addr)) == NULL) { 706 error = ENETUNREACH; 707 goto bad; 708 } 709 copcb->co_laddr.siso_family = AF_ISO; 710 copcb->co_laddr.siso_addr = *localaddr; 711 #else 712 /* Foreign addr isn't me (lpb). If still don't have an ifp or have 713 * an ifp but don't know its address, look for a route 714 */ 715 if( ifa = ifa_ifwithnet(&copcb->co_faddr) ) { 716 copcb->co_ifp = ifa->ifa_ifp; 717 IFDEBUG(D_CCONN) 718 printf(" cons_connect withnet returns %s\n", 719 copcb->co_ifp->if_name); 720 ENDDEBUG 721 } else { 722 printf("cons PANIC: connect: can't find SNPA \n"); 723 error = ENETUNREACH; 724 goto bad; 725 } 726 #endif PHASEONE 727 } 728 #ifndef PHASEONE 729 if( ifa == (struct ifaddr *)0 ) { 730 struct ifaddr * iso_ifwithidi(); 731 732 if( ifa = iso_ifwithidi(&copcb->co_faddr) ) { 733 copcb->co_ifp = ifa->ifa_ifp; 734 IFDEBUG(D_CCONN) 735 printf(" cons_connect withnet returns %s\n", 736 copcb->co_ifp->if_name); 737 ENDDEBUG 738 } else { 739 printf("cons PANIC: connect: can't find SNPA \n"); 740 error = ENETUNREACH; 741 goto bad; 742 } 743 } 744 bcopy((caddr_t)&ifa->ifa_addr, (caddr_t)&copcb->co_laddr, 745 sizeof(struct sockaddr)); 746 #endif PHASEONE 747 748 copcb->co_state = CONNECTING; 749 750 ASSERT( copcb->co_ifp != (struct ifnet *) 0); 751 if ( copcb->co_ifp == (struct ifnet *)0 ) { 752 error = ENETUNREACH; 753 goto bad; 754 } 755 756 m = m_getclr(M_DONTWAIT, MT_XCONN); 757 if( !m ) { 758 copcb->co_ifp->if_oerrors ++; 759 error = ENOBUFS; 760 goto bad; 761 } 762 m->m_len = sizeof(struct eicon_request); 763 764 ecnrq = mtod(m, struct eicon_request *); 765 766 copcb->co_myself = copcb; 767 ecnrq->e_pcb = (caddr_t)copcb; 768 #ifdef ARGO_DEBUG 769 LAST_CALL_PCB = (unsigned) ecnrq->e_pcb; 770 #endif ARGO_DEBUG 771 ecnrq->e_cmd = ECN_CALL; 772 ecnrq->e_vc = 0; /* mbz ? */ 773 ecnrq->e_info = 0; /* mbz */ 774 775 /* get data buffer */ 776 { struct mbuf *n; 777 778 MGET(n, M_DONTWAIT, MT_XCONN); 779 if( n==MNULL ) { 780 copcb->co_ifp->if_oerrors ++; 781 error = ENOBUFS; 782 goto bad; 783 } 784 e_data(ecnrq) = n; /* e_data is really dtom(ecnrq)->m_next */ 785 } 786 787 IFDEBUG(D_CCONN) 788 printf( 789 "calling make_partial_x25_packet( 0x%x, 0x%x, 0x%x, 0x%x, 0x%x)\n", 790 &copcb->co_laddr, &copcb->co_faddr, 791 copcb->co_proto->pr_protocol, 792 e_data(ecnrq), 793 copcb->co_flags & CONSF_XTS); 794 ENDDEBUG 795 if( error = make_partial_x25_packet( copcb, e_data(ecnrq)) ) { 796 copcb->co_ifp->if_oerrors ++; 797 m_freem(m); 798 goto bad; 799 } 800 801 IncStat(co_call); 802 803 IFDEBUG(D_CDUMP_REQ) 804 printf("cons_connect ecnrq:\n"); 805 dump_buf(ecnrq, sizeof(*ecnrq)); 806 ENDDEBUG 807 808 ASSERT( copcb->co_channel == 0); 809 if( copcb->co_channel != 0) { 810 printf("cons_connect PANIC: channel is 0x%x\n", copcb->co_channel); 811 } 812 813 error = choose_output(copcb->co_ifp, m, copcb->co_flags & CONSF_LOOPBACK); 814 815 switch( error ) { 816 case 0: /* ok */ 817 break; 818 default: /* problem */ 819 printf("cons: PANIC: if_output returns 0x%x\n", error); 820 cons_clear_and_detach( copcb, DONTCLEAR, PRC_ROUTEDEAD); 821 } 822 823 bad: 824 IFTRACE(D_CDATA) 825 tptrace( TPPTmisc, 826 "cons_connect: choose (copcb m) returned error\n", 827 copcb, m, error, 0); 828 ENDTRACE 829 return error; 830 } 831 832 /* 833 * NAME: cons_find() 834 * CALLED FROM: 835 * cosns_output1() thus: 836 * cons_find( CONSF_DGM, dst, proto, 0, 0) where 837 * proto is one of { TP_proto, CLNP_proto } 838 * FUNCTION and ARGUMENTS: 839 * Looks through list of connections for the destination, 840 * for one marked for the use indicated by flags. 841 * If none found, opens up a new connection. 842 * These connections will be eliminated by : 843 * a) slowtimo timer, or 844 * b) the need for a new connection, when we've run out of resources. 845 * The argument flags describes the type of pcb we want - may 846 * specify multiplexing-ok, datagram use, etc. 847 * The argument proto points the the higher layer protocol that 848 * will be using this connection. 849 * RETURN VALUE: 850 * returns a ptr to a pcb whose characteristics match those 851 * described by (flags, proto) 852 */ 853 854 Static struct cons_pcb * 855 cons_find(flags, dst, proto, addl_criteria, mask) 856 u_int flags, mask; 857 struct sockaddr_iso *dst; 858 struct protosw *proto; 859 int (*addl_criteria)(); 860 { 861 register struct cons_pcb *copcb; 862 register struct cons_pcb **copcblist = (struct cons_pcb **)Xpcblist; 863 int s = splnet(); /* or whatever, for the device! */ 864 struct dte_addr dest_dte; 865 int dummy; 866 867 struct copcb_descriptor { 868 int xd_qlen; 869 struct cons_pcb *xd_pcb; 870 } next_best = { 871 0, (struct cons_pcb *)0 872 }; 873 874 IFDEBUG(D_CFIND) 875 printf("cons_find( flags 0x%x proto 0x%x) ", flags, proto); 876 ENDDEBUG 877 878 if ( iso_8208snparesolve(dst, &dest_dte, &dummy)) { 879 ASSERT(0); 880 return (struct cons_pcb *)0; /* error */ 881 } 882 ASSERT(dummy == sizeof(struct dte_addr)); 883 884 for( copcb = *copcblist; copcb; copcb = *(++copcblist) ) { 885 copcb = (struct cons_pcb *)copcb->co_next; 886 while (copcb != *copcblist) { 887 IFDEBUG(D_CFIND) 888 printf( 889 "cons_find: chan 0x%x flags 0x%x proto 0x%x state 0x%x \n", 890 copcb->co_channel, copcb->co_flags, copcb->co_proto, 891 copcb->co_state); 892 ENDDEBUG 893 /* 894 * if flags is a subset of the bits in co_flags, it will suffice 895 */ 896 if( ((copcb->co_flags & flags) == flags ) && 897 /* PHASE2: where do we get the mask if we use nsaps ???? 898 * If dte addresses are used, then use 899 * nibble compare otherwise...??? 900 */ 901 #ifdef notdef 902 iso_addrmatch1(&(copcb->co_faddr.siso_addr), &(dst->siso_addr)) 903 #else 904 dest_dte.dtea_niblen == copcb->co_peer_dte.dtea_niblen && 905 nibble_match( (char *)&(copcb->co_peer_dte.dtea_addr), 906 HIGH_NIBBLE, (char *)dest_dte.dtea_addr, 907 HIGH_NIBBLE, dest_dte.dtea_niblen) 908 #endif notdef 909 && 910 (copcb->co_proto == proto) && 911 (copcb->co_state >= MIN_USABLE_STATE)) { 912 IFDEBUG(D_CFIND) 913 printf( 914 "cons_find: add'l criteria...\n" ); 915 ENDDEBUG 916 if((copcb->co_state != OPEN) && 917 (next_best.xd_qlen > copcb->co_pending.ifq_len)) { 918 next_best.xd_pcb = copcb; 919 next_best.xd_qlen = copcb->co_pending.ifq_len; 920 } 921 if( !addl_criteria || (*addl_criteria)(copcb, mask) ) { 922 goto found; /* have to break out of 2 loops */ 923 } 924 } 925 copcb = (struct cons_pcb *)copcb->co_next ; 926 } 927 } 928 #ifdef notdef 929 /* TODO: 930 * have a limit of the number of calls per desitination. 931 * If we didn't find one already open AND our limit for this 932 * destination hasn't been reached, return 0 'cause 933 * then the caller will open a new one. 934 * Otherwise return next_best. 935 * To do this we need some sort of per-destination info. 936 * Could go into the directory service. Oh, grotesque. 937 */ 938 #endif notdef 939 if( copcb == (struct cons_pcb *)0 ) { 940 copcb = next_best.xd_pcb; /* may be zero too */ 941 IFDEBUG(D_CFIND) 942 printf("NEXT_BEST! \n"); 943 dump_copcb(copcb, "find: next_best"); 944 ENDDEBUG 945 } 946 found: 947 948 splx(s); 949 950 IFDEBUG(D_CFIND) 951 printf("returns 0x%x \n", copcb); 952 ENDDEBUG 953 return copcb; 954 } 955 956 957 /* 958 * NAME: issue_clear_req() 959 * CALLED FROM: 960 * cons_clear() and wherever we get an error from x.25 that makes us 961 * want to close the vc on which it came, but don't have 962 * a copcb assoc. with that vc. 963 * FUNCTION and ARGUMENTS: 964 * Creates an eicon_request for a clear request, returns it in an mbuf. 965 * (chan) is the channel on which to do the clear, (reason) is the 966 * clear reason(diagnostic). 967 * RETURN VALUE: 968 * returns E* 969 */ 970 Static int 971 issue_clear_req(chan, reason, ifp, loop) 972 u_char chan, reason; 973 struct ifnet *ifp; 974 int loop; 975 { 976 register struct mbuf *m; 977 register struct mbuf *cdm; 978 register struct eicon_request *ecnrq; 979 struct e_clear_data *ecd; 980 981 IFDEBUG(D_CCONN) 982 printf("issue_clear_req(0x%x, 0x%x, 0x%x, 0x%x)\n", 983 chan, reason, ifp, loop); 984 ENDDEBUG 985 m = m_getclr(M_DONTWAIT, MT_XCLOSE); 986 if( !m ) { 987 return ENOBUFS; 988 } 989 m->m_len = sizeof(struct eicon_request); 990 ecnrq = mtod(m, struct eicon_request *); 991 ecnrq->e_cmd = ECN_CLEAR; 992 ecnrq->e_vc = chan & 0xff; 993 /* 994 * see p. 149 of 8208 for reasons (diagnostic codes) 995 */ 996 MGET(cdm, M_DONTWAIT, MT_XCLOSE); 997 if( !cdm ) { 998 m_freem(m); 999 return ENOBUFS; 1000 } 1001 cdm->m_len = sizeof(struct e_clear_data); /* cause, diagnostic */ 1002 e_data(ecnrq) = cdm; 1003 1004 ecd = mtod(cdm, struct e_clear_data *); 1005 ecd->ecd_cause = 0x0; /* DTE initiated, diagnostic tells more */ 1006 ecd->ecd_diagnostic = (u_char)reason; 1007 1008 IncStat(co_clear_out); 1009 return choose_output(ifp, m, loop); 1010 } 1011 1012 1013 /* 1014 * NAME: cons_clear() 1015 * CALLED FROM: 1016 * cons_usrreq(), PRU_DISCONNECT, 1017 * cons_slowtimo(), cons_free_lru() 1018 * FUNCTION and ARGUMENTS: 1019 * Builds a clear request for the connection represented by copcb, 1020 * gives it to the device. 1021 * ECN_CLEAR(request) takes e_vc only, returns adr_status. 1022 * RETURN VALUE: 1023 */ 1024 1025 Static int 1026 cons_clear( copcb, reason) 1027 register struct cons_pcb *copcb; 1028 u_char reason; 1029 { 1030 register struct mbuf *m; 1031 int error; 1032 1033 IFDEBUG(D_CCONN) 1034 printf("cons_clear(0x%x, 0x%x)\n", copcb, reason); 1035 ENDDEBUG 1036 if( !copcb) { 1037 printf("cons PANIC: clear: No copcb\n"); 1038 return 0; 1039 } 1040 while( copcb->co_pending.ifq_len > 0 ) { 1041 register int s = splimp(); 1042 1043 IF_DEQUEUE( &copcb->co_pending, m ); 1044 splx(s); 1045 m_freem(m); 1046 } 1047 if( (copcb->co_state == CLOSED) || (copcb->co_state == CLOSING) ) 1048 return 0; 1049 1050 #ifdef ARGO_DEBUG 1051 if( copcb->co_state == CONNECTING) { 1052 IFDEBUG(D_CCONN) 1053 dump_copcb(copcb, "clear"); 1054 ENDDEBUG 1055 } else if( (copcb->co_channel == 0) || (copcb->co_channel == X_NOCHANNEL) ) { 1056 IFDEBUG(D_CCONN) 1057 dump_copcb(copcb, "clear"); 1058 ENDDEBUG 1059 } 1060 #endif ARGO_DEBUG 1061 1062 copcb->co_state = CLOSING; 1063 1064 IFDEBUG(D_CCONN) 1065 printf("cons_clear: channel 0x%x copcb 0x%x dst: ", 1066 copcb->co_channel, copcb); 1067 dump_isoaddr(&copcb->co_faddr); 1068 dump_copcb(copcb, "clear"); 1069 ENDDEBUG 1070 1071 error = issue_clear_req(copcb->co_channel, reason, copcb->co_ifp, 1072 copcb->co_flags & CONSF_LOOPBACK); 1073 copcb->co_channel = X_NOCHANNEL; 1074 copcb->co_state = CLOSED; 1075 return error; 1076 } 1077 1078 1079 /* 1080 * NAME: cons_senddata() 1081 * CALLED FROM: 1082 * cons_output(), consoutput(), consintr() 1083 * FUNCTION and ARGUMENTS: 1084 * issued a data (write) command - if the device isn't ready, 1085 * it enqueues the command on a per-connection queue. 1086 * RETURN VALUE: 1087 * ENOBUFS 1088 * Is responsible for freeing m0! 1089 * 1090 * ECN_SEND (write) 1091 */ 1092 1093 Static int 1094 cons_senddata(copcb, m0) 1095 register struct cons_pcb *copcb; 1096 struct mbuf *m0; 1097 { 1098 register struct mbuf *m; 1099 register struct eicon_request *ecnrq; 1100 int s; 1101 1102 IFDEBUG(D_CDATA) 1103 printf("cons_senddata( 0x%x, m 0x%x ) chan 0x%x", 1104 copcb, m0, copcb->co_channel ); 1105 printf(" co_lport 0x%x\n", copcb->co_lport); 1106 ENDDEBUG 1107 if( m0 == MNULL ) 1108 return; 1109 ASSERT( m0->m_len > 0); 1110 if( m0->m_len <= 0) { 1111 printf("cons_senddata : BAD MLEN? 0x%x", m0->m_len); 1112 } 1113 1114 touch(copcb); 1115 1116 if( (copcb->co_state == CONNECTING) || (copcb->co_state == ACKWAIT) ) { 1117 IFDEBUG(D_CDATA) 1118 printf("senddata PUTTING ON PENDING Q copcb 0x%x state 0x%x\n", 1119 copcb, copcb->co_state); 1120 ENDDEBUG 1121 s = splimp(); 1122 if (IF_QFULL(&copcb->co_pending)) { 1123 IFDEBUG(D_CDATA) 1124 printf("senddata DROPPING m0 0x%x\n", m0); 1125 ENDDEBUG 1126 IF_DROP(&copcb->co_pending); 1127 if(copcb->co_ifp) { 1128 copcb->co_ifp->if_snd.ifq_drops ++; 1129 } 1130 IncStat(co_Xdrops); 1131 copcb->co_ifp->if_oerrors ++; 1132 splx(s); 1133 m_freem (m0); 1134 1135 if( copcb->co_proto && copcb->co_proto->pr_ctlinput ) { 1136 (*copcb->co_proto->pr_ctlinput)(PRC_QUENCH, 1137 (struct sockaddr_iso *)&copcb->co_faddr, 1138 (caddr_t)copcb); 1139 1140 return 0; 1141 } else 1142 return E_CO_QFULL; 1143 } 1144 IFDEBUG(D_CDATA) 1145 printf("Putting 0x%x on 0x%x->pending Q\n", m0, copcb); 1146 ENDDEBUG 1147 IF_ENQUEUE( &copcb->co_pending, m0 ); 1148 splx(s); 1149 return 0; 1150 } 1151 if(copcb->co_channel == 0 ) { 1152 return E_CO_CHAN; 1153 } 1154 ASSERT( copcb->co_state == OPEN); 1155 1156 m = m_getclr(M_DONTWAIT, MT_XDATA); 1157 if( !m ) { 1158 copcb->co_ifp->if_oerrors ++; 1159 m_freem (m0); 1160 return ENOBUFS; 1161 } 1162 m->m_len = sizeof(struct eicon_request); 1163 ecnrq = mtod(m, struct eicon_request *); 1164 ecnrq->e_pcb = (caddr_t)copcb; 1165 if( copcb->co_myself != copcb ) { 1166 struct mbuf *mm; 1167 /* TODO: REMOVE THIS DEBUGGING HACK */ 1168 ASSERT(0); 1169 printf("BAD e_pcb from HL (0x%x,0x%x)\n", copcb, copcb->co_myself); 1170 mm = dtom( copcb ); 1171 if(mm->m_type == MT_FREE) 1172 printf("FREED MBUF!\n"); 1173 return ENETDOWN; 1174 } 1175 ASSERT( copcb->co_channel != 0); 1176 ASSERT( copcb->co_channel != X_NOCHANNEL); 1177 ecnrq->e_vc = (copcb->co_channel & 0xff); 1178 ecnrq->e_cmd = ECN_SEND; 1179 e_data(ecnrq) = m0; 1180 { 1181 /* TODO: REMOVE THIS DEBUGGING HACK */ 1182 struct mbuf *thedata = e_data(ecnrq); 1183 u_int *firstint = mtod( thedata, u_int *); 1184 1185 if( (*firstint & 0xff000000) != 0x81000000 ) { 1186 /* not clnp */ 1187 switch( ((*firstint) & 0x00ff0000) >> 20 ) { 1188 case 0x1: 1189 case 0x2: 1190 case 0x3: 1191 case 0x6: 1192 case 0x7: 1193 case 0x8: 1194 case 0xc: 1195 case 0xd: 1196 case 0xe: 1197 case 0xf: 1198 break; 1199 default: 1200 printf(" ECN_SEND! BAD DATA\n" ); 1201 dump_buf( thedata, 20 + 12 ); 1202 m_freem( m0 ); 1203 return ENETDOWN; 1204 } 1205 } 1206 } 1207 1208 ecnrq->e_info = 0; 1209 1210 IFDEBUG(D_CDUMP_REQ) 1211 printf("senddata ecnrq\n"); 1212 ENDDEBUG 1213 IncStat(co_send); 1214 1215 ASSERT( copcb->co_state == OPEN ); 1216 copcb->co_state = ACKWAIT; 1217 1218 if( copcb->co_myself != copcb ) { 1219 struct mbuf *mm; 1220 /* TODO: REMOVE this and all mention of co_myself */ 1221 ASSERT(0); 1222 printf("BAD e_pcb TO THE BOARD ecn (0x%x) cmd 0x%x\n", 1223 ecnrq->e_pcb, ecnrq->e_cmd); 1224 mm = dtom( copcb ); 1225 if(mm->m_type == MT_FREE) 1226 printf("FREED MBUF!\n"); 1227 dump_buf (ecnrq, sizeof (*ecnrq)); 1228 return ENETDOWN; 1229 } 1230 1231 return 1232 choose_output(copcb->co_ifp, dtom(ecnrq), copcb->co_flags&CONSF_LOOPBACK); 1233 } 1234 1235 /* 1236 * NAME: cons_send_on_vc() 1237 * CALLED FROM: 1238 * tp_error_emit() 1239 * FUNCTION and ARGUMENTS: 1240 * Take a packet(m0), of length (datalen) from tp and 1241 * send it on the channel (chan). 1242 * 1243 * RETURN VALUE: 1244 * whatever (E*) is returned form the net layer output routine. 1245 */ 1246 int 1247 cons_send_on_vc(chan, m, datalen) 1248 int chan; 1249 struct mbuf *m; 1250 int datalen; 1251 { 1252 struct cons_pcb *copcb = (struct cons_pcb *)0; 1253 1254 if(m == MNULL) 1255 return; 1256 1257 if((copcb = 1258 #ifdef ARGO_DEBUG 1259 cons_chan_to_pcb( chan, __LINE__ ) 1260 #else ARGO_DEBUG 1261 cons_chan_to_pcb( chan ) 1262 #endif ARGO_DEBUG 1263 ) == (struct cons_pcb *)0 ) 1264 return E_CO_CHAN; 1265 IFDEBUG(D_CCONS) 1266 printf("cons_send_on_vc m 0x%x m_len 0x%x\n", m, m->m_len); 1267 ENDDEBUG 1268 return cons_senddata( copcb, m); 1269 } 1270 1271 /* 1272 * NAME: cons_output() 1273 * CALLED FROM: 1274 * tpiso_output(), can have whatever interface we want it to... 1275 * tpiso_output() decides whether to give a packet to CLNP or to 1276 * cons; if the latter, it calls this routine. 1277 * FUNCTION and ARGUMENTS: 1278 * tp has alloc-ed a pcb - but it may not be open. 1279 * some classes of tp may allow multiplexing, in which 1280 * case, you may choose to send the data on ANOTHER cons connection. 1281 * This decides which net connection to use, opens one if necessary. 1282 * Then it sends the data. 1283 */ 1284 1285 cons_output(isop, m, len, isdgm) 1286 struct isopcb *isop; 1287 struct mbuf *m; 1288 int len; 1289 int isdgm; 1290 { 1291 struct cons_pcb *copcb = (struct cons_pcb *)0; 1292 int error; 1293 int s = splnet(); 1294 1295 IFDEBUG(D_CCONS) 1296 printf("cons_output( isop 0x%x, m 0x%x, len 0x%x, dgm 0x%x )\n", 1297 isop,m,len, isdgm); 1298 ENDDEBUG 1299 1300 if( m == MNULL ) 1301 return 0; 1302 ASSERT(m->m_len > 0); 1303 if( isdgm ) { 1304 error = cosns_output1(0, m, &isop->isop_faddr, TP_proto, isop); 1305 IFDEBUG(D_CDATA) 1306 if(error) 1307 printf("cosns_output1 RETURNS ERROR 0x%x\n", error); 1308 ENDDEBUG 1309 return error; 1310 } 1311 1312 if( isop->isop_chanmask || isop->isop_negchanmask) { 1313 register int mask = isop->isop_chanmask; 1314 register int chan = 1; 1315 1316 if( mask == 0) 1317 mask = isop->isop_negchanmask; 1318 1319 for ( chan=1; (mask & 1)==0; chan++,mask>>=1 ) ; 1320 1321 if( isop->isop_chanmask == 0 ) 1322 chan = -chan; 1323 1324 IFDEBUG(D_CCONS) 1325 printf( 1326 "cons_output: isop 0x%x cmask 0x%x negmask 0x%x, chan 0x%x\n", 1327 isop, isop->isop_chanmask, isop->isop_negchanmask, chan); 1328 ENDDEBUG 1329 ASSERT( chan != 0); 1330 #ifdef ARGO_DEBUG 1331 copcb = cons_chan_to_pcb( chan, __LINE__ ); 1332 #else ARGO_DEBUG 1333 copcb = cons_chan_to_pcb( chan ); 1334 #endif ARGO_DEBUG 1335 } 1336 if( copcb == (struct cons_pcb *)0 ) { 1337 /* get a new one */ 1338 1339 if(( error = cons_pcballoc(&dummysocket, &cons_isopcb, CONSF_OCRE, 1340 TP_proto, &copcb)) != EOK ) { 1341 IFDEBUG(D_CCONS) 1342 printf("cosns_output: no copcb; returns 0x%x\n", error); 1343 ENDDEBUG 1344 (void) m_freem (m); 1345 splx(s); 1346 return error ; 1347 } 1348 1349 /* abbreviated form of iso_pcbconnect(): */ 1350 bcopy((caddr_t)&isop->isop_faddr, (caddr_t)&copcb->co_faddr, 1351 sizeof(struct sockaddr_iso)); 1352 1353 if ( error = cons_connect( copcb ) ) { /* if it doesn't work */ 1354 /* oh, dear, throw packet away */ 1355 remque((struct isopcb *)copcb); 1356 (void) m_free(dtom(copcb)); 1357 (void) m_freem( m ); 1358 splx(s); 1359 return error; 1360 } 1361 1362 if( copcb->co_socket ) { 1363 while( (copcb->co_state != OPEN) && 1364 !(error = copcb->co_socket->so_error) ) { 1365 IFDEBUG(D_CCONS) 1366 printf( 1367 "SLEEP1 copcb 0x%x isop 0x%x state 0x%x chan 0x%x mask 0x%x neg 0x%x\n", 1368 copcb, isop, copcb->co_state, copcb->co_channel, 1369 ((struct isopcb *)isop)->isop_chanmask, 1370 ((struct isopcb *)isop)->isop_negchanmask 1371 ); 1372 ENDDEBUG 1373 tsleep( (caddr_t)&copcb->co_state, PZERO+1, 1374 SLP_ISO_CONSOUT, 0); 1375 IFDEBUG(D_CCONS) 1376 printf("AFTER SLEEP 1 chan 0x%x chanmask 0x%x negchanmask 0x%x\n", 1377 copcb->co_channel, isop->isop_chanmask, 1378 isop->isop_negchanmask); 1379 ENDDEBUG 1380 } 1381 if( !error ) 1382 SET_CHANMASK( isop, copcb->co_channel); 1383 } 1384 1385 } 1386 1387 IFDEBUG(D_CDATA) 1388 printf("cons_output calling senddata(0x%x 0x%x)\n", copcb, m); 1389 ASSERT(m != MNULL); 1390 ASSERT(m->m_len != 0); 1391 ENDDEBUG 1392 1393 if( !error ) 1394 error = cons_senddata( copcb, m); 1395 splx(s); 1396 return error; 1397 } 1398 1399 /* 1400 * NAME: cons_openvc() 1401 * CALLED FROM: 1402 * TP when it decides to open a VC for TP 0 1403 * FUNCTION: 1404 * opens a connection and stashes the pcb info in the socket 1405 * substitute for iso_pcbconnect/ in_pcbconnect for the class 0 case 1406 * only. 1407 */ 1408 int 1409 cons_openvc(copcb, faddr, so) 1410 struct cons_pcb *copcb; 1411 struct sockaddr_iso *faddr; 1412 struct socket *so; 1413 { 1414 int error = 0; 1415 int s = splnet(); 1416 struct cons_pcb *cons_chan_to_pcb(); 1417 1418 1419 ASSERT( copcb->co_socket == so ); 1420 IFTRACE(D_CCONN) 1421 tptrace(TPPTmisc, "cons_openvc( copcb so )\n", copcb, so, 0, 0); 1422 ENDTRACE 1423 IFDEBUG(D_CCONN) 1424 printf("cons_openvc( copcb 0x%x, so 0x%x )\n", copcb,so); 1425 ENDDEBUG 1426 /* 1427 * initialize the copcb part of the isopcb 1428 */ 1429 copcb->co_ttl = copcb->co_init_ttl = X25_TTL; 1430 copcb->co_flags = CONSF_OCRE; 1431 copcb->co_proto = TP_proto; 1432 copcb->co_pending.ifq_maxlen = CONS_IFQMAXLEN; 1433 1434 /* abbreviated form of iso_pcbconnect(): */ 1435 bcopy((caddr_t)faddr, (caddr_t)&copcb->co_faddr, 1436 sizeof(struct sockaddr_iso)); 1437 1438 ASSERT( copcb->co_socket == so ); 1439 if( error = cons_connect( copcb ) ) 1440 goto done; 1441 while( (copcb->co_state != OPEN) && !(error = so->so_error) ) { 1442 IFDEBUG(D_CCONS) 1443 printf( 1444 "SLEEP2 copcb 0x%x state 0x%x chan 0x%x mask 0x%x neg 0x%x\n", 1445 copcb, copcb->co_state, copcb->co_channel, 1446 copcb->co_chanmask, 1447 copcb->co_negchanmask 1448 ); 1449 ENDDEBUG 1450 tsleep((caddr_t)&copcb->co_state, PZERO+2, SLP_ISO_CONSCONN, 0); 1451 IFDEBUG(D_CCONS) 1452 printf("AFTER SLEEP2 chan 0x%x chanmask 0x%x negchanmask 0x%x\n", 1453 copcb->co_channel, copcb->co_chanmask, 1454 copcb->co_negchanmask); 1455 ENDDEBUG 1456 } 1457 if( !error ) 1458 SET_CHANMASK( (struct isopcb *)copcb, copcb->co_channel); 1459 done: 1460 ASSERT( copcb->co_socket == so ); 1461 splx(s); 1462 1463 IFDEBUG(D_CCONN) 1464 printf("cons_openvc: copcb 0x%x error 0x%x\n", copcb, error ); 1465 ENDDEBUG 1466 return error; 1467 } 1468 1469 /* 1470 * NAME: cons_netcmd() 1471 * CALLED FROM: 1472 * tp_route_to() when it decides to accept or reject an incoming 1473 * connection it calls this. 1474 * FUNCTION: 1475 * either closes the cons connection named by (channel) 1476 * or associates the copcb with the channel #. 1477 * and removes the old copcb from the tp_incoming_pending list. 1478 */ 1479 int 1480 cons_netcmd(cmd, isop, channel, isdgm) 1481 int cmd; 1482 struct isopcb *isop; 1483 int channel; 1484 { 1485 int s = splnet(); 1486 int error = 0; 1487 struct cons_pcb *copcb = (struct cons_pcb *)0; 1488 struct cons_pcb *cons_chan_to_pcb(); 1489 1490 IFTRACE(D_CCONN) 1491 tptrace(TPPTmisc, "cons_netcmd( cmd isopcb channel isdgm)\n", 1492 cmd,isop,channel, isdgm); 1493 ENDTRACE 1494 IFDEBUG(D_CCONN) 1495 printf("cons_netcmd( cmd 0x%x, isop 0x%x, channel 0x%x, isdgm 0x%x)\n", 1496 cmd,isop,channel, isdgm); 1497 if( isop ) 1498 printf("cons_netcmd: isop->socket 0x%x\n", 1499 isop->isop_socket); 1500 ENDDEBUG 1501 ASSERT(cmd != CONN_OPEN); 1502 1503 /* Can we find a cons-level pcb based on channel? */ 1504 if(channel) { 1505 if((copcb = 1506 #ifdef ARGO_DEBUG 1507 cons_chan_to_pcb( channel, __LINE__ ) 1508 #else ARGO_DEBUG 1509 cons_chan_to_pcb( channel) 1510 #endif ARGO_DEBUG 1511 ) == (struct cons_pcb *)0) { 1512 error = ECONNABORTED; 1513 splx(s); 1514 return error; 1515 } 1516 if( copcb == (struct cons_pcb *) isop ) { 1517 copcb = (struct cons_pcb *)0; 1518 /* avoid operating on a pcb twice */ 1519 } else { 1520 /* if isop is null (close/refuse): 1521 * this would remove from the TP list, which is NOT what we want 1522 * so only remove if there is an isop (gag) 1523 */ 1524 if( isop ) { 1525 remque((struct cons_pcb *)copcb); /* take it off pending list */ 1526 } else { 1527 ASSERT( (cmd == CONN_CLOSE) || (cmd == CONN_REFUSE) ); 1528 } 1529 } 1530 } 1531 /* now we have one of these cases: 1532 * 1) isop is non-null and copcb is null 1533 * 2) isop is non-null and copcb is non-null and they are different 1534 * 3) isop is null and copcb is non-null 1535 */ 1536 ASSERT( (isop != (struct isopcb *)0) || (copcb != (struct cons_pcb *)0)); 1537 1538 switch(cmd) { 1539 1540 case CONN_CONFIRM: 1541 if( isdgm ) { 1542 /* we want two separate pcbs */ 1543 /* if we don't have a copcb, get one */ 1544 1545 if( copcb == (struct cons_pcb *)0 ) { 1546 if(( error = cons_pcballoc(&dummysocket, &cons_isopcb, 1547 ((struct cons_pcb *)isop)->co_flags, 1548 TP_proto, &copcb)) != EOK ) 1549 return error; 1550 /* copy missing info from isop */ 1551 copcb->co_laddr = isop->isop_laddr; 1552 copcb->co_faddr = isop->isop_faddr; 1553 /* don't care about tsuffices */ 1554 ((struct cons_pcb *)isop)->co_channel = 0; 1555 /* no longer used */ 1556 1557 copcb->co_ifp = ((struct cons_pcb *)isop)->co_ifp ; 1558 ASSERT( copcb->co_pending.ifq_len == 0 ); 1559 1560 } else { 1561 insque((struct isopcb *)copcb, 1562 (struct isopcb *)&cons_isopcb); 1563 } 1564 copcb->co_state = OPEN; 1565 copcb->co_flags |= CONSF_DGM; 1566 copcb->co_channel = channel; 1567 ASSERT(copcb->co_channel != 0); 1568 1569 IFDEBUG(D_CCONN) 1570 printf("cons_netcmd: put 0x%x on regular list \n", copcb); 1571 ENDDEBUG 1572 } else { 1573 /* must be TP 0, since this is never called from XTS code */ 1574 /* we want ONE pcb, namely isop. 1575 * If this TPE were the active side, 1576 * there ought not to be a copcb, since TP should 1577 * know that you can't send a CR with dgm and negot down 1578 * to non-dgm. 1579 * If this TPE were the passive side, we want to copy from 1580 * the copcb that was on the pending list, and delete the 1581 * pending copcb. 1582 */ 1583 if( copcb ) { 1584 IFDEBUG(D_CCONN) 1585 printf("cons_netcmd: copied info from 0x%x to 0x%x\n", 1586 copcb, isop); 1587 ENDDEBUG 1588 isop->isop_laddr = copcb->co_laddr; 1589 isop->isop_faddr = copcb->co_faddr; 1590 /* tsuffices, socket should be there already */ 1591 ((struct cons_pcb *)isop)->co_flags = 1592 copcb->co_flags & ~CONSF_DGM; 1593 ((struct cons_pcb *)isop)->co_init_ttl = copcb->co_init_ttl; 1594 touch(((struct cons_pcb *)isop)); 1595 ((struct cons_pcb *)isop)->co_channel = channel; 1596 ((struct cons_pcb *)isop)->co_ifp = copcb->co_ifp; 1597 ((struct cons_pcb *)isop)->co_proto = copcb->co_proto; 1598 ((struct cons_pcb *)isop)->co_myself = 1599 (struct cons_pcb *)isop; 1600 SET_CHANMASK( isop, ((struct cons_pcb *)isop)->co_channel ); 1601 ASSERT( copcb->co_pending.ifq_len == 0 ); 1602 1603 /* get rid of the copcb that was on the pending list */ 1604 (void) m_free(dtom(copcb)); 1605 } 1606 ((struct cons_pcb *)isop)->co_state = OPEN; 1607 } 1608 break; 1609 1610 case CONN_CLOSE: 1611 case CONN_REFUSE: 1612 /* if dgm then ignore; the connections will 1613 * be re-used or will time out 1614 */ 1615 if( isdgm ) 1616 break; 1617 1618 /* we should never come in here with both isop and copcb 1619 * unless is dgm, hence the following assertion: 1620 */ 1621 ASSERT( (copcb == (struct cons_pcb *)0) || 1622 (isop == (struct isopcb *)0) ); 1623 1624 /* close whichever pcb we have */ 1625 if( copcb ) 1626 error = cons_clear(copcb, (cmd == CONN_CLOSE)? 1627 E_CO_HLI_DISCN:E_CO_HLI_REJT); 1628 if( isop ) 1629 error = cons_clear((struct cons_pcb *)isop, (cmd == CONN_CLOSE)? 1630 E_CO_HLI_DISCN:E_CO_HLI_REJT); 1631 1632 if(copcb && (copcb->co_socket == (struct socket *)0) ) { 1633 ASSERT( copcb->co_flags & (CONSF_DGM | CONSF_ICRE) ); 1634 (void) m_free(dtom(copcb)); /* detached */ 1635 } 1636 /* isop will always be detached by the higher layer */ 1637 break; 1638 default: 1639 error = EOPNOTSUPP; 1640 break; 1641 } 1642 splx(s); 1643 1644 IFDEBUG(D_CCONN) 1645 printf("cons_netcmd returns 0x%x: isop 0x%x\n", isop, error ); 1646 ENDDEBUG 1647 return error; 1648 } 1649 1650 1651 /* 1652 * NAME: addr_proto_consistency_check() 1653 * CALLED FROM: cons_incoming() 1654 * FUNCTION and ARGUMENTS: 1655 * Enforces a set of rules regarding what addresses will serve 1656 * what protocol stack. This is a kludge forced upon us by the 1657 * fact that there's no way to tell which NET layer you want to 1658 * run when opening a socket. Besides, no doubt, OSI directory 1659 * services won't advertise any kind of a protocol stack with the 1660 * NSAPs. sigh. 1661 * RETURNS 1662 * EAFNOSUPPORT or EOK. 1663 */ 1664 Static int 1665 addr_proto_consistency_check(proto, addr) 1666 int proto; 1667 struct sockaddr_iso *addr; 1668 { 1669 switch( proto ) { 1670 case ISOPROTO_CLNP: 1671 break; 1672 1673 case ISOPROTO_INACT_NL: 1674 case ISOPROTO_CLTP: 1675 return E_CO_HLI_PROTOID; 1676 1677 case ISOPROTO_TP: 1678 case ISOPROTO_X25: 1679 /* hl is TP or X.25 */ 1680 if (addr->siso_addr.isoa_afi != AFI_37) 1681 return E_CO_AIWP; 1682 /* kludge - necessary because this is the only type of 1683 * NSAP we build for an incoming NC 1684 */ 1685 break; 1686 default: /* unsupported */ 1687 return E_CO_HLI_PROTOID; 1688 } 1689 return EOK; 1690 } 1691 /* 1692 * NAME: cons_incoming() 1693 * CALLED FROM: 1694 * consintr() for incoming OPEN 1695 * FUNCTION and ARGUMENTS: 1696 * Determines which higher layer gets this call, and 1697 * thus whether to immediately accept, reject, or to let the 1698 * higher layer determine this question. 1699 */ 1700 Static 1701 cons_incoming(ifp, ecnrq) 1702 struct ifnet *ifp; 1703 register struct eicon_request *ecnrq; 1704 { 1705 struct sockaddr_iso me; 1706 struct sockaddr_iso peer; 1707 struct cons_pcb *copcb; 1708 int loop = 0; 1709 int proto =0; 1710 int error = 0; 1711 struct dte_addr peer_dte; 1712 1713 IFDEBUG(D_INCOMING) 1714 printf("consincoming enter: ifp 0x%x ecnrq 0x%x\n", ifp, ecnrq); 1715 ENDDEBUG 1716 bzero( &me, sizeof(me)); 1717 error = parse_facil( mtod(e_data(ecnrq), caddr_t), 1718 (e_data(ecnrq))->m_len, &me, &peer, &proto, 1719 &peer_dte); 1720 loop = is_me( &peer ); /* <-- THIS may be a problem : 1721 * peer may be nonsense. 1722 * We can only expect that WE will do it right 1723 * and never will we get an error return from 1724 * parse_facil on a facil that WE generated, 1725 * so if garbage comes in, peer will be garbage, 1726 * and loop will be false. 1727 */ 1728 if( error != EOK ) { 1729 (void) issue_clear_req(ecnrq->e_vc, error, ifp, loop); 1730 IncStat(co_parse_facil_err); 1731 IncStat(co_Rdrops); 1732 return; 1733 } 1734 1735 if( (error = addr_proto_consistency_check(proto, &me)) != EOK ) { 1736 /* problem with consistency */ 1737 (void) issue_clear_req(ecnrq->e_vc, error, ifp, loop); 1738 IncStat(co_addr_proto_consist_err); 1739 IncStat(co_Rdrops); 1740 return; 1741 } else { 1742 switch( proto ) { 1743 case ISOPROTO_X25: 1744 copcb = (struct cons_pcb *) 1745 ((struct cons_pcb *)(&cons_isopcb))->co_next; 1746 1747 while (copcb != (struct cons_pcb *)&cons_isopcb) { 1748 if( copcb->co_lport == me.siso_tsuffix ) { 1749 /* for cons "transport service", 1750 * multiplexing is not allowed 1751 */ 1752 if( !copcb->co_socket ) { 1753 printf( 1754 "PANIC cons_incoming NOT TP but no sock\n"); 1755 copcb = (struct cons_pcb *)0; 1756 break; 1757 } 1758 if( copcb->co_socket->so_options & SO_ACCEPTCONN ) { 1759 struct cons_pcb *newx; 1760 1761 newx = (struct cons_pcb *) 1762 sonewconn(copcb->co_socket)->so_pcb; 1763 newx->co_laddr = copcb->co_laddr; 1764 newx->co_peer_dte = peer_dte; 1765 newx->co_proto = copcb->co_proto; 1766 newx->co_myself = newx; 1767 touch(copcb); 1768 copcb = newx; 1769 soisconnected(copcb->co_socket); 1770 break; 1771 } /* else keep looking */ 1772 } 1773 copcb = (struct cons_pcb *)copcb->co_next; 1774 } 1775 if (copcb == (struct cons_pcb *)&cons_isopcb) 1776 copcb = (struct cons_pcb *) 0; 1777 break; 1778 1779 case ISOPROTO_TP: 1780 ASSERT( me.siso_tsuffix == 0 ); 1781 /* 1782 * We treat this rather like we do for CLNP. 1783 * TP can't tell which socket 1784 * wants this until the TP header comes in, so there's no way 1785 * to associate this channel with a tpcb/isopcb. 1786 * We assume data will arrive (a CR TPDU) and be given to TP along with 1787 * the channel number. We can then expect TP to call us with 1788 * the channel number and pcb ptr, telling us to keep this connection 1789 * or clear it. 1790 * Now, tp will have created an isopcb in the tp_isopcb list. 1791 * We will have to keep another copcb though, because there is no 1792 * 1-1 correspondence between socket and copcb when multiplexing 1793 * is allowed. 1794 * But we want to save the peer address, ifp, and state, proto. 1795 * If the channel should clear before TP responds, we need 1796 * to know that also, so we create a tp-pending list... 1797 */ 1798 if( cons_pcballoc(&dummysocket, &tp_incoming_pending, 1799 CONSF_ICRE, TP_proto, &copcb) != EOK ) { 1800 copcb = (struct cons_pcb *)0; 1801 } else { 1802 copcb->co_peer_dte = peer_dte; 1803 } 1804 break; 1805 1806 1807 case ISOPROTO_CLNP: 1808 if( cons_pcballoc(&dummysocket, &cons_isopcb, 1809 CONSF_ICRE | CONSF_DGM, CLNP_proto, &copcb ) != EOK ) { 1810 /* choke */ 1811 copcb = (struct cons_pcb *)0; 1812 } else { 1813 copcb->co_peer_dte = peer_dte; 1814 } 1815 break; 1816 1817 default: 1818 panic("cons_incoming"); 1819 } /* end switch */ 1820 1821 if(copcb) { 1822 touch(copcb); 1823 copcb->co_channel = (int)ecnrq->e_vc; 1824 ASSERT( copcb->co_channel != 0); 1825 copcb->co_state = OPEN; 1826 copcb->co_ifp = ifp; 1827 copcb->co_laddr = me; 1828 copcb->co_faddr = peer; 1829 if(loop) 1830 copcb->co_flags |= CONSF_LOOPBACK; 1831 IFDEBUG(D_CADDR) 1832 printf("cons_incoming found XPCB 0x%x, loop 0x%x\n", 1833 copcb, loop); 1834 printf("\nco_laddr: "); 1835 dump_buf(&copcb->co_laddr, sizeof(copcb->co_laddr)); 1836 printf("\nco_faddr: "); 1837 dump_buf(&copcb->co_faddr, sizeof(copcb->co_faddr)); 1838 printf("\n"); 1839 ENDDEBUG 1840 } else { 1841 ifp->if_ierrors ++; 1842 (void) issue_clear_req(ecnrq->e_vc, E_CO_OSI_UNSAP, ifp, loop); 1843 IncStat(co_no_copcb); 1844 IncStat(co_Rdrops); 1845 } 1846 } 1847 /* caller frees the mbuf so we don't have to do any such thing */ 1848 } 1849 1850 /* 1851 **************************** DEVICE cons *************************** 1852 */ 1853 1854 /* 1855 * NAME: cosns_output() 1856 * CALLED FROM: 1857 * clnp - this routine is given as the device-output routine 1858 * for the adcom driver. 1859 * FUNCTION and ARGUMENTS: 1860 * (ifp) is the cons/adcom, found by routing function. 1861 * (m0) is the clnp datagram. 1862 * (dst) is the destination address 1863 * This routine finds an x.25 connection for datagram use and 1864 * sends the packet. 1865 */ 1866 int 1867 cosns_output(ifp, m0, dst) 1868 { 1869 return cosns_output1(ifp, m0, dst, CLNP_proto, NULL); 1870 } 1871 1872 /* DEBUGGING ONLY? */ 1873 int total_cosns_len = 0; 1874 int total_cosns_cnt = 0; 1875 int total_pkts_to_clnp = 0; 1876 1877 /* 1878 * The isop is passed here so that if we have set x25crud in the 1879 * pcb, it can be passed down to cons_connect. It could be null 1880 * however, in the case of tp4/x25/clnp 1881 */ 1882 Static int 1883 cosns_output1(ifp, m0, dst, proto, isop) 1884 struct ifnet *ifp; 1885 register struct mbuf *m0; 1886 struct sockaddr_iso *dst; 1887 struct protosw *proto; 1888 struct isopcb *isop; /* NULL if coming from clnp */ 1889 { 1890 register struct cons_pcb *copcb; 1891 int s = splnet(); 1892 int error = 0; 1893 1894 { register struct mbuf *n=m0; 1895 register int len = 0; 1896 1897 for(;;) { 1898 len += n->m_len; 1899 if (n->m_next == MNULL ) { 1900 break; 1901 } 1902 n = n->m_next; 1903 } 1904 total_cosns_len += len; 1905 total_cosns_cnt ++; 1906 1907 } 1908 1909 IFDEBUG(D_CCONS) 1910 printf("cosns_output1( ifp 0x%x, m 0x%x, dst 0x%x )\n", ifp, m0, dst ); 1911 ENDDEBUG 1912 if ( ! (copcb = cons_find( CONSF_DGM, dst, proto, 0, 0) )) { 1913 struct cons_pcb *newcopcb; /* so we can pass addr of this to pcballoc */ 1914 1915 if( (error = cons_pcballoc(&dummysocket, &cons_isopcb, 1916 CONSF_DGM | CONSF_OCRE, proto, &newcopcb) ) != EOK ) { 1917 IFDEBUG(D_CCONS) 1918 printf("cosns_output: no copcb; returns \n"); 1919 ENDDEBUG 1920 (void) m_freem(m0); 1921 goto done; 1922 } 1923 copcb = newcopcb; 1924 1925 /* abbreviated form of iso_pcbconnect(): */ 1926 bcopy((caddr_t)dst, (caddr_t)&copcb->co_faddr, 1927 sizeof(struct sockaddr_iso)); 1928 1929 /* copy x25crud into copcb if necessary */ 1930 if ((isop != NULL) && (isop->isop_x25crud_len > 0)) { 1931 bcopy(isop->isop_x25crud, copcb->co_x25crud, 1932 isop->isop_x25crud_len); 1933 copcb->co_x25crud_len = isop->isop_x25crud_len; 1934 } 1935 1936 copcb->co_ifp = ifp; /* NULL IF COMING FROM TP4! */ 1937 1938 if ( error = cons_connect( copcb ) ) { /* if it doesn't work */ 1939 /* oh, dear, throw packet away */ 1940 remque((struct isopcb *)copcb); 1941 (void) m_free(dtom(copcb)); 1942 (void) m_freem(m0); 1943 goto done; 1944 } 1945 } 1946 IFDEBUG(D_CDATA) 1947 printf("cosns_output1 @ senddata: state 0x%x flags 0x%x channel 0x%x\n", 1948 copcb->co_state, copcb->co_flags, copcb->co_channel); 1949 ENDDEBUG 1950 ASSERT(copcb->co_channel != X_NOCHANNEL); 1951 error = cons_senddata(copcb, m0); 1952 done: 1953 splx(s); 1954 return error; 1955 } 1956 1957 1958 /* 1959 **************************** TRANSPORT cons *************************** 1960 */ 1961 1962 1963 /* 1964 * NAME: cons_detach() 1965 * CALLED FROM: 1966 * cons_usrreq() on PRU_DETACH 1967 * cons_netcmd() when TP releases a net connection 1968 * cons_slowtimo() when timeout releases a net connection 1969 * FUNCTION and ARGUMENT: 1970 * removes the copcb from the list of copcbs in use, and frees the mbufs. 1971 * detaches the pcb from the socket, where a socket exists. 1972 * RETURN VALUE: 1973 * ENOTCONN if it couldn't find the copcb in the list of connections. 1974 */ 1975 1976 Static int 1977 cons_detach( copcb ) 1978 register struct cons_pcb *copcb; 1979 { 1980 struct socket *so = copcb->co_socket; 1981 1982 IFDEBUG(D_CCONN) 1983 printf("cons_detach( copcb 0x%x )\n", copcb); 1984 ENDDEBUG 1985 if(so) { 1986 if (so->so_head) { 1987 if (!soqremque(so, 0) && !soqremque(so, 1)) 1988 panic("sofree dq"); 1989 so->so_head = 0; 1990 } 1991 ((struct isopcb *)copcb)->isop_options = 0; /* kludge */ 1992 iso_pcbdetach(copcb); /* detaches from so */ 1993 } else { 1994 remque((struct isopcb *)copcb); 1995 (void) m_free(dtom(copcb)); 1996 } 1997 } 1998 1999 Static int 2000 cons_clear_and_detach(copcb, clearreason, ctlcmd) 2001 register struct cons_pcb *copcb; 2002 int clearreason; 2003 int ctlcmd; 2004 { 2005 IFDEBUG(D_CCONN) 2006 printf("Clear and Detach (0x%x, 0x%x, 0x%x)\n", 2007 copcb, clearreason, ctlcmd); 2008 ENDDEBUG 2009 if( clearreason != DONTCLEAR ) { 2010 (void) cons_clear( copcb , clearreason ); 2011 } 2012 if( copcb->co_proto && copcb->co_proto->pr_ctlinput ) 2013 (*copcb->co_proto->pr_ctlinput)(ctlcmd, 2014 (struct sockaddr_iso *)&copcb->co_faddr, (caddr_t)copcb); 2015 2016 if( copcb->co_socket == (struct socket *)0 ) { 2017 /* tp4, clnp users only */ 2018 (void) cons_detach( copcb ); 2019 } /* else detach will be called by the socket's closing */ 2020 else { 2021 ASSERT( copcb->co_socket != &dummysocket ); 2022 ASSERT( (copcb->co_flags & CONSF_DGM) == 0 ); 2023 } 2024 IFDEBUG(D_CCONN) 2025 printf("END OF Clear and Detach (0x%x, 0x%x, 0x%x)\n", 2026 copcb, clearreason, ctlcmd); 2027 ENDDEBUG 2028 } 2029 2030 Static int 2031 cons_pcbbind( copcb, nam ) 2032 register struct cons_pcb *copcb; 2033 struct mbuf *nam; 2034 { 2035 int error; 2036 2037 if( error = iso_pcbbind( copcb, nam) ) 2038 return error; 2039 2040 /* iso_pcbbind already ensured that if port < 1024 it's superuser */ 2041 /* Now we check: must be in range 0 .. 23 or in range 1024 .. 99 */ 2042 2043 if( (copcb->co_lport < X25_PORT_RESERVED) || 2044 ((copcb->co_lport >= ISO_PORT_RESERVED) && 2045 (copcb->co_lport <= X25_PORT_USERMAX))) { 2046 munge( copcb->co_lport, (&copcb->co_laddr)->siso_addr.t37_idi + 2047 ADDR37_IDI_LEN, 1 /* nibble */); 2048 munge( copcb->co_fport, (&copcb->co_faddr)->siso_addr.t37_idi + 2049 ADDR37_IDI_LEN, 1 /* nibble */); 2050 return 0; 2051 } else 2052 return EADDRNOTAVAIL; 2053 } 2054 /* 2055 * NAME: cons_usrreq() 2056 * CALLED FROM: 2057 * user level via proto switch 2058 * FUNCTION and ARGUMENTS: 2059 * so : socket 2060 * req: which PRU* request 2061 * m : data or mbuf ptr into which to stash data 2062 * nam: mbuf ptr which is really a sockaddr_iso 2063 * ifq: in PRU_CONTROL case, an ifnet structure 2064 * RETURN VALUE: 2065 * ENOTCONN if trying to do something which requires a connection 2066 * and it's not yet connected 2067 * EISCONN if trying to do something which cannot be done to a connection 2068 * but it's connected 2069 * ENOBUFS if ran out of mbufs 2070 * EWOULDBLOCK if in nonblocking mode & can't send right away 2071 * EOPNOSUPP if req isn't supported 2072 * E* other passed up from lower layers or from other routines 2073 */ 2074 2075 cons_usrreq(so, req, m, nam, ifp) 2076 struct socket *so; 2077 u_int req; 2078 struct mbuf *m, *nam; 2079 int *ifp; 2080 { 2081 struct cons_pcb *copcb = (struct cons_pcb *)so->so_pcb; 2082 int s = splnet(); 2083 int error = 0; 2084 2085 IFDEBUG(D_CCONS) 2086 printf("cons_usrreq 0x%x so 0x%x copcb 0x%x\n", req, so, copcb); 2087 ENDDEBUG 2088 if (req == PRU_CONTROL) { 2089 error = iso_control(so, (int)m, (caddr_t)nam, (struct ifnet *)ifp); 2090 splx(s); 2091 return error; 2092 } 2093 if (copcb == (struct cons_pcb *)0 && req != PRU_ATTACH) { 2094 splx(s); 2095 return ENOTCONN; 2096 } 2097 2098 switch (req) { 2099 2100 case PRU_ATTACH: 2101 if (copcb) { 2102 error = EISCONN; 2103 break; 2104 } 2105 soreserve(so, X25_SBSIZE, X25_SBSIZE); /* CONS size */ 2106 error = cons_pcballoc(so, &cons_isopcb, CONSF_XTS, X25_proto, &copcb ); 2107 break; 2108 2109 case PRU_ABORT: /* called from close() */ 2110 /* called for each incoming connect queued on the parent (accepting) 2111 * socket (SO_ACCEPTCONN); 2112 */ 2113 error = cons_detach ( copcb ); 2114 break; 2115 2116 case PRU_DETACH: /* called from close() */ 2117 /* called after disconnect was called iff was connected at the time 2118 * of the close, or directly if socket never got connected */ 2119 error = cons_detach ( copcb ); 2120 break; 2121 2122 case PRU_SHUTDOWN: 2123 /* recv end may have been released; local credit might be zero */ 2124 case PRU_DISCONNECT: 2125 soisdisconnected(so); 2126 error = cons_clear(copcb, E_CO_HLI_DISCN); 2127 break; 2128 2129 case PRU_BIND: 2130 error = cons_pcbbind( copcb, nam); 2131 break; 2132 2133 case PRU_LISTEN: 2134 if (copcb->co_lport == 0) 2135 error = cons_pcbbind( copcb, 0 ); 2136 break; 2137 2138 2139 case PRU_SOCKADDR: { 2140 struct sockaddr_iso *siso = mtod(nam, struct sockaddr_iso *); 2141 2142 nam->m_len = sizeof (struct sockaddr_iso); 2143 if(copcb->co_ifp) 2144 bcopy( (caddr_t)&copcb->co_laddr, 2145 (caddr_t)siso, sizeof(struct sockaddr_iso) ); 2146 2147 ((struct sockaddr_iso *)siso)->siso_tsuffix = copcb->co_lport; 2148 } 2149 break; 2150 2151 case PRU_PEERADDR: 2152 if( (so->so_state & SS_ISCONNECTED) && 2153 (so->so_state & SS_ISDISCONNECTING) == 0) { 2154 struct sockaddr_iso *siso = mtod(nam, struct sockaddr_iso *); 2155 2156 nam->m_len = sizeof (struct sockaddr_iso); 2157 bcopy( (caddr_t)&copcb->co_faddr, (caddr_t)siso, 2158 sizeof(struct sockaddr_iso) ); 2159 } else 2160 error = ENOTCONN; 2161 break; 2162 2163 case PRU_CONNECT: 2164 /* TODO: We need to bind to the RIGHT interface. 2165 * The only way to have the right interface is to have 2166 * the right route. 2167 */ 2168 IFDEBUG(D_CCONN) 2169 printf("PRU_CONNECT 1: local tsuffix 0x%x so->so_head 0x%x nam:\n", 2170 copcb->co_lport, so->so_head); 2171 dump_isoaddr( mtod(nam, struct sockaddr_iso *) ); 2172 ENDDEBUG 2173 if (copcb->co_lport == 0) { 2174 if( error = cons_pcbbind( copcb, 0 )) 2175 break; 2176 } 2177 IFDEBUG(D_CCONN) 2178 printf("PRU_CONNECT 2: local tsuffix 0x%x so->so_head 0x%x nam:\n", 2179 copcb->co_lport, so->so_head); 2180 dump_isoaddr( mtod(nam, struct sockaddr_iso *) ); 2181 ENDDEBUG 2182 2183 { /* change the destination address so the last 2 digits 2184 * are the port/suffix/selector (whatever you want to call it) 2185 */ 2186 register struct sockaddr_iso *siso = 2187 mtod(nam, struct sockaddr_iso *); 2188 if( (siso->siso_tsuffix < X25_PORT_RESERVED) || 2189 ((siso->siso_tsuffix >= ISO_PORT_RESERVED) && 2190 (siso->siso_tsuffix <= X25_PORT_USERMAX))) 2191 munge( siso->siso_tsuffix, 2192 siso->siso_addr.t37_idi + ADDR37_IDI_LEN, 2193 1 /* nibble */); 2194 } 2195 2196 soisconnecting(so); 2197 if (error = iso_pcbconnect(copcb, nam)) 2198 break; 2199 error = cons_connect( copcb ); 2200 if ( error ) { 2201 /* 2202 remque((struct isopcb *)copcb); 2203 (void) m_free(dtom(copcb)); 2204 */ 2205 break; 2206 } 2207 while( (copcb->co_state != OPEN)&&(copcb->co_socket->so_error == 0) ) { 2208 IFDEBUG(D_CCONN) 2209 printf("PRU_CONNECT: error 0x%x sleeping on 0x%x\n", 2210 copcb->co_socket->so_error, 2211 (caddr_t)&copcb->co_state ); 2212 ENDDEBUG 2213 sleep((caddr_t)&copcb->co_state, PZERO+3, SLP_ISO_CONS, 0 ); 2214 } 2215 2216 ASSERT( copcb->co_channel != 0); 2217 2218 SET_CHANMASK ( (struct isopcb *)copcb, copcb->co_channel); 2219 break; 2220 2221 case PRU_ACCEPT: 2222 /* so here is the NEW socket */ 2223 so->so_error = 0; 2224 if ((so->so_state & SS_NBIO) && (so->so_state & SS_ISCONNECTED)== 0) { 2225 error = EWOULDBLOCK; 2226 break; 2227 } 2228 { 2229 struct sockaddr_iso *siso = mtod(nam, struct sockaddr_iso *); 2230 2231 /* copy the peer's address into the return argument */ 2232 nam->m_len = sizeof (struct sockaddr_iso); 2233 bcopy( (caddr_t)&copcb->co_faddr, (caddr_t)siso, 2234 sizeof(struct sockaddr_iso)); 2235 } 2236 break; 2237 2238 case PRU_SEND: 2239 case PRU_SENDEOT: 2240 /* 2241 * sosend calls this until sbspace goes negative. 2242 * Sbspace may be made negative by appending this mbuf chain, 2243 * possibly by a whole cluster. 2244 */ 2245 { 2246 /* no need to actually queue this stuff and dequeue it, 2247 * just bump the pointers in so_snd so that higher 2248 * layer of socket code will cause it to sleep when 2249 * we've run out of socket space 2250 * TODO: 2251 * Unfortunately that makes sbflush vomit so we have 2252 * to allocate a single real mbuf (say size 240) 2253 * and sballoc it and sbfree it upon CONS_SEND_DONE. 2254 * Oh, my, is this sickening or what? 2255 */ 2256 { 2257 struct mbuf *mx; 2258 2259 MGET(mx, M_DONTWAIT, MT_DATA); 2260 mx->m_len = MLEN; 2261 sbappend((caddr_t)&copcb->co_socket->so_snd, mx); 2262 } 2263 if( m ) { 2264 IFDEBUG(D_CDATA) 2265 printf("X.25 Usrreq calling cons_senddata(0x%x, 0x%x)\n", 2266 copcb, m); 2267 ENDDEBUG 2268 error = cons_senddata(copcb, m); 2269 } 2270 IFDEBUG(D_CCONS) 2271 printf("PRU_SEND sent tsuffix 0x%x, m 0x%x error 0x%x\n", 2272 copcb->co_lport, m, error); 2273 ENDDEBUG 2274 2275 if( req == PRU_SENDEOT ) { 2276 while(copcb->co_socket->so_snd.sb_cc > 0) 2277 sbwait(&copcb->co_socket->so_snd); 2278 } 2279 } 2280 break; 2281 2282 case PRU_CONTROL: 2283 error = cons_ioctl(so, m, (caddr_t)nam); 2284 break; 2285 2286 2287 case PRU_RCVD: 2288 case PRU_RCVOOB: 2289 case PRU_SENDOOB: 2290 /* COULD support INTERRUPT packets as oob */ 2291 case PRU_PROTOSEND: 2292 case PRU_PROTORCV: 2293 case PRU_SENSE: 2294 case PRU_SLOWTIMO: 2295 case PRU_CONNECT2: 2296 case PRU_FASTTIMO: 2297 default: 2298 error = EOPNOTSUPP; 2299 } 2300 2301 IFDEBUG(D_CCONS) 2302 printf("cons_usrreq cmd 0x%x copcb 0x%x returned error 0x%x\n", 2303 req, copcb, error); 2304 ENDDEBUG 2305 splx(s); 2306 return error; 2307 } 2308 2309 /* 2310 * NAME: cons_input() 2311 * CALLED FROM: 2312 * consintr() through the isosw protosw for "transport" version of X25 2313 * FUNCTION & ARGUMENTS: 2314 * process incoming data 2315 */ 2316 cons_input(m, faddr, laddr, so) 2317 register struct mbuf *m; 2318 struct sockaddr_iso *faddr, *laddr; /* not used */ 2319 register struct socket *so; 2320 { 2321 IFDEBUG(D_CCONS) 2322 printf("cons_input( m 0x%x, so 0x%x)\n", m,so); 2323 ENDDEBUG 2324 sbappend(&so->so_rcv, m); 2325 sbwakeup(&so->so_rcv); 2326 } 2327 2328 #ifdef notdef 2329 /* 2330 * NAME: cons_ctloutput() 2331 * CALLED FROM: 2332 * set/get sockopts() 2333 * Presently the protosw has 0 in the ctloutput spot 2334 * because we haven't inplemented anything yet. 2335 * If there's reason to put some options in here, 2336 * be sure to stick this routine name in the protosw in iso_proto.c 2337 */ 2338 cons_ctloutput(cmd, so, level, optname, mp) 2339 int cmd, level, optname; 2340 struct socket *so; 2341 struct mbuf **mp; 2342 { 2343 int s = splnet(); 2344 2345 splx(s); 2346 return EOPNOTSUPP; 2347 } 2348 #endif notdef 2349 2350 2351 /* 2352 * NAME: cons_ctlinput() 2353 * CALLED FROM: 2354 * lower layer when ECN_CLEAR occurs : this routine is here 2355 * for consistency - cons subnet service calls its higher layer 2356 * through the protosw entry. 2357 * FUNCTION & ARGUMENTS: 2358 * cmd is a PRC_* command, list found in ../sys/protosw.h 2359 * copcb is the obvious. 2360 * This serves the higher-layer cons service. 2361 * NOTE: this takes 3rd arg. because cons uses it to inform itself 2362 * of things (timeouts, etc) but has a pcb instead of an address. 2363 */ 2364 cons_ctlinput(cmd, sa, copcb) 2365 int cmd; 2366 struct sockaddr *sa; 2367 register struct cons_pcb *copcb; 2368 { 2369 int error = 0; 2370 int s = splnet(); 2371 extern u_char inetctlerrmap[]; 2372 extern int iso_rtchange(); 2373 2374 IFDEBUG(D_CCONS) 2375 printf("cons_ctlinput( cmd 0x%x, copcb 0x%x)\n", cmd, copcb); 2376 ENDDEBUG 2377 /* co_socket had better exist */ 2378 switch (cmd) { 2379 case PRC_CONS_SEND_DONE: 2380 ASSERT( copcb->co_socket ); 2381 ASSERT( copcb->co_flags & CONSF_XTS ); 2382 sbdrop((caddr_t)&copcb->co_socket->so_snd, MLEN); 2383 sbwakeup((caddr_t)&copcb->co_socket->so_snd); 2384 break; 2385 2386 case PRC_ROUTEDEAD: 2387 error = ENETUNREACH; 2388 break; 2389 2390 case PRC_TIMXCEED_REASS: 2391 error = ETIMEDOUT; 2392 break; 2393 2394 /* 2395 case PRC_QUENCH: 2396 iso_pcbnotify(&cons_pcb, sa, 2397 (int)inetctlerrmap[cmd], iso_rtchange); 2398 iso_pcbnotify(&tp_incoming_pending, sa, 2399 (int)inetctlerrmap[cmd], tpiso_quench); 2400 iso_pcbnotify(&tp_isopcb, sa, 2401 (int)inetctlerrmap[cmd], tpiso_quench); 2402 */ 2403 2404 case PRC_IFDOWN: 2405 iso_pcbnotify(&cons_isopcb, sa, 2406 (int)inetctlerrmap[cmd], iso_rtchange); 2407 iso_pcbnotify(&tp_incoming_pending, sa, 2408 (int)inetctlerrmap[cmd], iso_rtchange); 2409 iso_pcbnotify(&tp_isopcb, sa, 2410 (int)inetctlerrmap[cmd], iso_rtchange); 2411 break; 2412 2413 2414 default: 2415 printf("cons_ctlinput: unknown cmd 0x%x\n", cmd); 2416 } 2417 if(error) { 2418 soisdisconnected(copcb->co_socket); 2419 sohasoutofband(copcb->co_socket); 2420 } 2421 splx(s); 2422 } 2423 2424 /* 2425 *********************** SERVES ALL cons embodiments ******************* 2426 */ 2427 2428 /* 2429 * NAME: cons_chan_to_pcb() 2430 * CALLED FROM: 2431 * cons_chan_to_tpcb() in tp_cons.c 2432 * and in this file: incoming requests that give only a channel number, i.e., 2433 * ECN_ACCEPT, ECN_RECEIVE, ECN_CLEAR 2434 * FUNCTION: 2435 * identify the pcb assoc with that channel 2436 * RETURN: 2437 * ptr to the pcb 2438 */ 2439 struct cons_pcb * 2440 #ifdef ARGO_DEBUG 2441 cons_chan_to_pcb( channel, linenumber ) 2442 int linenumber; 2443 #else ARGO_DEBUG 2444 cons_chan_to_pcb( channel) 2445 #endif ARGO_DEBUG 2446 register int channel; 2447 { 2448 register struct cons_pcb **copcblist = (struct cons_pcb **)Xpcblist; 2449 register struct cons_pcb *copcb; 2450 2451 /* just to be sure */ 2452 channel = channel & 0xff; 2453 2454 for( copcb = *copcblist; copcb; copcb = *(++copcblist) ) { 2455 copcb = (struct cons_pcb *)copcb->co_next; 2456 while (copcb != *copcblist) { 2457 if ( copcb->co_channel == channel ) 2458 goto found; /* want to break out of both loops */ 2459 2460 copcb = (struct cons_pcb *)copcb->co_next; 2461 } 2462 } 2463 found: /* or maybe not... */ 2464 IFDEBUG(D_CCONS) 2465 printf("cons_chan_to_pcb( 0x%x, %d ) %s 0x%x\n", channel, linenumber, 2466 copcb?"FOUND":"FAILED", copcb); 2467 ENDDEBUG 2468 2469 return copcb; 2470 } 2471 2472 2473 /* 2474 * NAME: is_me() 2475 * CALLED FROM: 2476 * cons_incoming(). Perhaps could just expand in line. 2477 * FUNCTION and ARGUMENTS: 2478 * for the given remote address (remadr) if it exactly matches 2479 * one of the addresses of ME, and I am up as loopback, 2480 * return TRUE, else return FALSE. 2481 * RETURNS: 2482 * Boolean 2483 */ 2484 Static int 2485 is_me(remaddr) 2486 struct sockaddr_iso *remaddr; 2487 { 2488 struct ifnet *ifp = consif; 2489 /* PHASE2: this is ok */ 2490 struct ifaddr *ifa = ifa_ifwithaddr(remaddr); 2491 2492 IFDEBUG(D_CADDR) 2493 printf("is_me: withaddr returns %s\n", 2494 ifa?ifa->ifa_ifp->if_name:"NONE"); 2495 ENDDEBUG 2496 if( ifa ) { 2497 /* remaddr matches one of my interfaces exactly */ 2498 if( ifa->ifa_ifp->if_flags & IFF_LOOPBACK ) { 2499 ASSERT( ifp == ifa->ifa_ifp ); 2500 return 1; 2501 } 2502 } 2503 return 0; 2504 } 2505 2506 find_error_reason( ecnrq ) 2507 register struct eicon_request *ecnrq; 2508 { 2509 extern u_char x25_error_stats[]; 2510 int error; 2511 struct mbuf *cdm; 2512 struct e_clear_data *ecd; 2513 2514 cdm = e_data(ecnrq); 2515 if( cdm && cdm->m_len > 0 ) { 2516 ecd = mtod(cdm, struct e_clear_data *); 2517 switch( ecd->ecd_cause ) { 2518 case 0x00: 2519 case 0x80: 2520 /* DTE originated; look at the diagnostic */ 2521 error = (CONL_ERROR_MASK | ecd->ecd_diagnostic); 2522 goto done; 2523 2524 case 0x01: /* number busy */ 2525 case 0x81: 2526 case 0x09: /* Out of order */ 2527 case 0x89: 2528 case 0x11: /* Remot Procedure Error */ 2529 case 0x91: 2530 case 0x19: /* reverse charging accept not subscribed */ 2531 case 0x99: 2532 case 0x21: /* Incampat destination */ 2533 case 0xa1: 2534 case 0x29: /* fast select accept not subscribed */ 2535 case 0xa9: 2536 case 0x39: /* ship absent */ 2537 case 0xb9: 2538 case 0x03: /* invalid facil request */ 2539 case 0x83: 2540 case 0x0b: /* access barred */ 2541 case 0x8b: 2542 case 0x13: /* local procedure error */ 2543 case 0x93: 2544 case 0x05: /* network congestion */ 2545 case 0x85: 2546 case 0x8d: /* not obtainable */ 2547 case 0x0d: 2548 case 0x95: /* RPOA out of order */ 2549 case 0x15: 2550 /* take out bit 8 2551 * so we don't have to have so many perror entries 2552 */ 2553 error = (CONL_ERROR_MASK | 0x100 | (ecd->ecd_cause & ~0x80)); 2554 goto done; 2555 2556 case 0xc1: /* gateway-detected proc error */ 2557 case 0xc3: /* gateway congestion */ 2558 2559 error = (CONL_ERROR_MASK | 0x100 | ecd->ecd_cause); 2560 goto done; 2561 } 2562 } 2563 /* otherwise, a *hopefully* valid perror exists in the e_reason field */ 2564 error = ecnrq->e_reason; 2565 if (error = 0) { 2566 printf("Incoming PKT TYPE 0x%x with reason 0x%x\n", 2567 ecnrq->e_cmd, 2568 ecnrq->e_reason); 2569 error = E_CO_HLI_DISCA; 2570 } 2571 2572 done: 2573 if(error & 0x1ff == 0) { 2574 error = 0; 2575 } else if( error & 0x1ff > sizeof(x25_error_stats)) { 2576 ASSERT(0); 2577 } else { 2578 x25_error_stats[error& 0x1ff] ++; 2579 } 2580 return error; 2581 } 2582 2583 /* 2584 * NAME: consintr() 2585 * CALLED FROM: 2586 * the eicon driver via software interrupt 2587 * FUNCTION and ARGUMENTS: 2588 * processes incoming indications, passing them 2589 * along to clnp, tp, or x.25-transport as appropriate. 2590 */ 2591 consintr() 2592 { 2593 struct ifnet *ifp = consif; 2594 register struct eicon_request *ecnrq; 2595 register struct cons_pcb *copcb = (struct cons_pcb *)0; 2596 register struct mbuf *m; 2597 int s, s0 = splnet(); 2598 2599 IncStat(co_intr); 2600 ifp->if_ipackets ++; 2601 2602 for(;;) { 2603 /* 2604 * Get next request off input queue 2605 */ 2606 s = splimp(); 2607 IF_DEQUEUE(&consintrq, m); 2608 splx(s); 2609 IFDEBUG(D_INCOMING) 2610 printf("cons intr() 0x%x m_off 0x%x m_len 0x%x dequeued\n", 2611 m, m?m->m_off:0, m?m->m_len:0); 2612 ENDDEBUG 2613 2614 if (m == 0) { 2615 splx(s0); 2616 return; 2617 } 2618 2619 if((m->m_off != MMINOFF)||(m->m_len != sizeof (struct eicon_request))){ 2620 ifp->if_ierrors ++; 2621 IncStat(co_Rdrops); 2622 printf("Cons R DROP! BAD MBUF FROM LL 0x%x sizeof(...) 0x%x\n", 2623 m, sizeof(struct eicon_request)); 2624 continue; 2625 } 2626 2627 ecnrq = mtod(m, struct eicon_request *); 2628 2629 2630 IFDEBUG(D_INCOMING) 2631 printf("INTR: e_cmd 0x%x, e_data 0x%x\n", ecnrq->e_cmd, 2632 e_data(ecnrq)); 2633 if( e_data(ecnrq) != 0 ) { 2634 /* let's just look at the first few bytes */ 2635 /* 2636 dump_buf( e_data(ecnrq), (e_data(ecnrq))->m_len + 12); 2637 */ 2638 dump_buf( e_data(ecnrq), 20 + 12); 2639 } 2640 ENDDEBUG 2641 IFTRACE(D_CDATA) 2642 tptrace( TPPTmisc, "INTR: req_type m lun\n", 2643 ecnrq->e_cmd, m, ecnrq->e_vc, 0); 2644 ENDTRACE 2645 2646 switch( ecnrq->e_cmd ) { 2647 2648 case ECN_ACK: /* data put on the board */ 2649 IncStat(co_ack); 2650 ASSERT( ecnrq->e_vc != 0); 2651 /* from ACKWAIT to OPEN */ 2652 if ( (copcb = 2653 #ifdef ARGO_DEBUG 2654 cons_chan_to_pcb( (int)ecnrq->e_vc, __LINE__ ) 2655 #else ARGO_DEBUG 2656 cons_chan_to_pcb( (int)ecnrq->e_vc ) 2657 #endif ARGO_DEBUG 2658 ) == (struct cons_pcb *)0 ) 2659 break; 2660 copcb->co_state = OPEN; 2661 /* 2662 * Anything on the pending queue for this connection? 2663 */ 2664 if( copcb->co_pending.ifq_len == 0 ) { 2665 if( copcb->co_proto->pr_ctlinput ) 2666 /* for the sake of higher layer protocol (tp) */ 2667 (*copcb->co_proto->pr_ctlinput) 2668 (PRC_CONS_SEND_DONE, 2669 (struct sockaddr_iso *)&copcb->co_faddr, 2670 (caddr_t)copcb); 2671 } else { 2672 register struct mbuf *m0; 2673 2674 s = splimp(); 2675 IF_DEQUEUE( &copcb->co_pending, m0 ); 2676 splx(s); 2677 /* CAN ONLY DO 1 item here 2678 * if you change this if to while, HA HA 2679 * it'll go right back onto 2680 * the pending queue (which means things will 2681 * be reordered on the queue!) 2682 */ 2683 if( m0 ) { 2684 IFDEBUG(D_CDATA) 2685 printf("ACK sending pending queue 0x%x len 0x%x\n", 2686 m0, m0->m_len); 2687 ENDDEBUG 2688 ASSERT( m0->m_len != 0); 2689 (void) cons_senddata(copcb, m0); 2690 } 2691 } 2692 2693 /* send more? */ 2694 break; 2695 2696 case ECN_ACCEPT: /* call accepted at other end */ 2697 /* adr_src, adr_dst are as given in the ECN_CALL 2698 * pcb field is copied from our ECN_CALL 2699 * request, confirm gives me a channel number 2700 */ 2701 ASSERT( ecnrq->e_vc != 0); 2702 2703 IncStat(co_accept); 2704 if(copcb = 2705 #ifdef ARGO_DEBUG 2706 cons_chan_to_pcb((int)ecnrq->e_vc, __LINE__ ) 2707 #else ARGO_DEBUG 2708 cons_chan_to_pcb((int)ecnrq->e_vc) 2709 #endif ARGO_DEBUG 2710 ) { 2711 /* error: already exists */ 2712 printf("cons PANIC: dbl confirm for channel 0x%x\n", 2713 ecnrq->e_vc); 2714 break; 2715 } 2716 copcb = (struct cons_pcb *)ecnrq->e_pcb; 2717 if( copcb->co_myself != copcb ) { 2718 struct mbuf *mm; 2719 /* TODO: REMOVE */ 2720 ASSERT(0); 2721 printf("BAD e_pcb from ecn (0x%x) cmd 0x%x\n", 2722 ecnrq->e_pcb, ecnrq->e_cmd); 2723 mm = dtom( copcb ); 2724 if(mm->m_type == MT_FREE) 2725 printf("FREED MBUF!\n"); 2726 dump_buf (ecnrq, sizeof (*ecnrq)); 2727 panic("BAD ecnrq"); 2728 break; 2729 } 2730 touch(copcb); 2731 copcb->co_state = OPEN; 2732 copcb->co_channel = (int)ecnrq->e_vc; 2733 if(copcb->co_socket) { 2734 /* tp0 will take care of itself */ 2735 if( copcb->co_flags & CONSF_XTS) 2736 soisconnected(copcb->co_socket); /* wake 'em up */ 2737 } 2738 wakeup( (caddr_t)&copcb->co_state ); 2739 2740 /* 2741 * Anything on the pending queue for this connection? 2742 */ 2743 if( copcb->co_pending.ifq_len > 0 ) { 2744 register struct mbuf *m0; 2745 2746 s = splimp(); 2747 IF_DEQUEUE( &copcb->co_pending, m0 ); 2748 splx(s); 2749 /* CAN ONLY DO 1 item here 2750 * if you change this if to while, HA HA 2751 * it'll go right back onto 2752 * the pending queue (which means things will 2753 * be reordered on the queue!) 2754 */ 2755 if( m0 ) { 2756 IFDEBUG(D_CDATA) 2757 printf("ACPT sending pending queue 0x%x len 0x%x\n", 2758 m0, m0->m_len); 2759 ENDDEBUG 2760 ASSERT( m0->m_len != 0); 2761 (void) cons_senddata(copcb, m0); 2762 } 2763 } 2764 break; 2765 2766 case ECN_REFUSE: 2767 /* other end refused our connect request */ 2768 /* src, dst are as given in the ECN_CALL */ 2769 2770 IncStat(co_refuse); 2771 copcb = (struct cons_pcb *)ecnrq->e_pcb; 2772 if( copcb->co_myself != copcb ) { 2773 struct mbuf *mm; 2774 /* TODO: REMOVE */ 2775 ASSERT(0); 2776 printf("BAD e_pcb from ecn (0x%x) cmd 0x%x\n", 2777 ecnrq->e_pcb, ecnrq->e_cmd); 2778 mm = dtom( copcb ); 2779 if(mm->m_type == MT_FREE) 2780 printf("FREED MBUF!\n"); 2781 dump_buf (ecnrq, sizeof (*ecnrq)); 2782 dump_buf (copcb, sizeof (*copcb)); 2783 panic("BAD ecnrq"); 2784 break; 2785 } 2786 touch(copcb); 2787 copcb->co_state = CLOSED; /* do we have to do a clear?? */ 2788 copcb->co_channel = X_NOCHANNEL; 2789 if(copcb->co_socket) { 2790 copcb->co_socket->so_error = ECONNREFUSED; 2791 /* TODO: if there's diagnostic info in the 2792 * packet, and it's more useful than this E*, 2793 * get it 2794 */ 2795 soisdisconnected(copcb->co_socket); /* wake 'em up */ 2796 IFDEBUG(D_INCOMING) 2797 printf("ECN_REFUSE: waking up 0x%x\n", 2798 (caddr_t)&copcb->co_state ); 2799 ENDDEBUG 2800 wakeup( (caddr_t)&copcb->co_state ); 2801 } 2802 /* 2803 * Anything on the pending queue for this connection? 2804 */ 2805 while( copcb->co_pending.ifq_len > 0 ) { 2806 register struct mbuf *m0; 2807 2808 s = splimp(); 2809 IF_DEQUEUE( &copcb->co_pending, m0 ); 2810 splx(s); 2811 m_freem(m0); 2812 } 2813 if ( ecnrq->e_reason == E_CO_NORESOURCES ) { 2814 IncStat(co_noresources); 2815 cons_clear_and_detach( copcb, DONTCLEAR, PRC_QUENCH ); 2816 } else if(copcb->co_socket ) { 2817 copcb->co_socket->so_error = find_error_reason( ecnrq ); 2818 } 2819 break; 2820 2821 case ECN_CONNECT: /* incoming call */ 2822 /* 2823 * ECN_CONNECT indication gives adc_src, adc_dst and channel 2824 */ 2825 ASSERT( ecnrq->e_vc != 0); 2826 2827 IncStat(co_connect); 2828 cons_incoming(ifp, ecnrq); 2829 break; 2830 2831 case ECN_RESET: 2832 case ECN_CLEAR: 2833 /* 2834 * ECN_CLEAR(indication) (if we can construct such a beast) 2835 * gives e_vc, 2836 * Throw away anything queued pending on this connection 2837 * give a reset indication to the upper layer if TP 2838 * free the mbufs 2839 */ 2840 ASSERT( ecnrq->e_vc != 0); 2841 if( ecnrq->e_cmd == ECN_CLEAR ) 2842 IncStat(co_clear_in); 2843 else 2844 IncStat(co_reset_in); 2845 #ifdef ARGO_DEBUG 2846 if( ! (copcb=cons_chan_to_pcb((int)ecnrq->e_vc, __LINE__)) ) 2847 #else ARGO_DEBUG 2848 if( ! (copcb=cons_chan_to_pcb((int)ecnrq->e_vc)) ) 2849 #endif ARGO_DEBUG 2850 2851 break; 2852 while( copcb->co_pending.ifq_len ) { 2853 register struct mbuf *m0; 2854 2855 s = splimp(); 2856 IF_DEQUEUE( &copcb->co_pending, m0 ); 2857 splx(s); 2858 m_freem(m0); 2859 } 2860 copcb->co_state = CLOSED; /* do we have to do a clear? */ 2861 copcb->co_channel = X_NOCHANNEL; 2862 2863 cons_clear_and_detach( copcb, DONTCLEAR, PRC_ROUTEDEAD ); 2864 if (copcb->co_socket ) { 2865 copcb->co_socket->so_error = find_error_reason( ecnrq ); 2866 } 2867 break; 2868 2869 case ECN_RECEIVE: 2870 /* 2871 * ECN_RECEIVE (read) 2872 */ 2873 ASSERT( ecnrq->e_vc != 0); 2874 IncStat(co_receive); 2875 { 2876 /* TODO: REMOVE */ 2877 struct mbuf *thedata = e_data(ecnrq); 2878 u_int *firstint = mtod( thedata, u_int *); 2879 2880 if( (*firstint & 0xff000000) != 0x81000000 ) { 2881 /* not clnp */ 2882 switch( ((*firstint) & 0x00ff0000) >> 20 ) { 2883 case 0x1: 2884 case 0x2: 2885 case 0x3: 2886 case 0x6: 2887 case 0x7: 2888 case 0x8: 2889 case 0xc: 2890 case 0xd: 2891 case 0xe: 2892 case 0xf: 2893 break; 2894 default: 2895 printf(" ECN_RECEIVE! BAD DATA\n" ); 2896 dump_buf( thedata, 20 + 12 ); 2897 m_freem( m ); 2898 splx(s0); 2899 } 2900 } 2901 } 2902 if ( (copcb = 2903 #ifdef ARGO_DEBUG 2904 cons_chan_to_pcb( (int)ecnrq->e_vc, __LINE__ ) 2905 #else ARGO_DEBUG 2906 cons_chan_to_pcb( (int)ecnrq->e_vc ) 2907 #endif ARGO_DEBUG 2908 ) == (struct cons_pcb *)0 ) { 2909 ifp->if_ierrors ++; 2910 IFTRACE(D_CDATA) 2911 tptrace(TPPTmisc, "ECN_RECEIVE DROPPED chan \n", 2912 ecnrq->e_vc, 0, 0, 0); 2913 ENDTRACE 2914 break; 2915 } 2916 2917 touch(copcb); 2918 if( ecnrq->e_info & ECN_INFO_RCVD_INT ) { 2919 /* interrupt packet */ 2920 printf("consintr: interrupt pkttype : DROPPED\n"); 2921 IncStat(co_intrpt_pkts_in); 2922 IncStat(co_Rdrops); 2923 break; 2924 } 2925 /* new way */ 2926 if( copcb->co_proto == CLNP_proto ) 2927 { 2928 /* IP: put it on the queue and set soft interrupt */ 2929 struct ifqueue *ifq; 2930 extern struct ifqueue clnlintrq; 2931 register struct mbuf *ifpp; /* for ptr to ifp */ 2932 register struct mbuf *data = e_data(ecnrq); 2933 2934 total_pkts_to_clnp ++; 2935 2936 /* when acting as a subnet service, have to prepend a 2937 * pointer to the ifnet before handing this to clnp 2938 * GAG 2939 */ 2940 if( ( data->m_off > MMINOFF + sizeof(struct snpa_hdr)) && 2941 ( data->m_off <= MMAXOFF )) { 2942 data->m_off -= sizeof(struct snpa_hdr); 2943 data->m_len += sizeof(struct snpa_hdr); 2944 } else { 2945 MGET(ifpp, M_DONTWAIT, MT_XHEADER); 2946 if( !ifpp ) { 2947 ifp->if_ierrors ++; 2948 splx(s0); 2949 m_freem(m); /* frees everything */ 2950 return; 2951 } 2952 ifpp->m_len = sizeof(struct snpa_hdr); 2953 ifpp->m_act = 0; 2954 ifpp->m_next = data; 2955 data = ifpp; 2956 } 2957 IFTRACE(D_CDATA) 2958 tptrace(TPPTmisc, "-->CLNP copcb\n", copcb, 0, 0, 0); 2959 ENDTRACE 2960 { 2961 /* 2962 * TODO: if we ever use esis/cons we have to 2963 * think of something reasonable to stick in the 2964 * snh_shost,snh_dhost fields. I guess 2965 * the x.121 address is what we want. 2966 * 2967 * That would also require length fields in the 2968 * snpa_hdr structure. 2969 */ 2970 struct snpa_hdr *snh = 2971 mtod(data, struct snpa_hdr *); 2972 bzero((caddr_t)&snh, sizeof(struct snpa_hdr)); 2973 bcopy((caddr_t)&ifp, (caddr_t)&snh->snh_ifp, 2974 sizeof(struct ifnet *)); 2975 } 2976 *( mtod(data, struct ifnet **) ) = ifp; /* KLUDGE */ 2977 2978 ifq = &clnlintrq; 2979 splimp(); 2980 if (IF_QFULL(ifq)) { 2981 IF_DROP(ifq); 2982 m_freem(m); 2983 IFDEBUG(D_INCOMING) 2984 printf("DROPPED! ecnrq 0x%x, data 0x%x\n", m,data); 2985 ENDDEBUG 2986 splx(s0); 2987 ifp->if_ierrors ++; 2988 return; 2989 } 2990 IF_ENQUEUE(ifq, data); 2991 IFDEBUG(D_INCOMING) 2992 printf( 2993 "0x%x enqueued on ip Q: m_len 0x%x m_type 0x%x m_off 0x%x\n", 2994 data, data->m_len, data->m_type, data->m_off); 2995 dump_buf(mtod(data, caddr_t), data->m_len); 2996 ENDDEBUG 2997 e_data(ecnrq) = (struct mbuf *)0; 2998 schednetisr(NETISR_CLNP); 2999 } else { 3000 /* HL is NOT clnp */ 3001 IFTRACE(D_CDATA) 3002 tptrace(TPPTmisc, 3003 "-->HL pr_input so copcb channel\n", 3004 copcb->co_proto->pr_input, 3005 copcb->co_socket, copcb, 3006 copcb->co_channel); 3007 ENDTRACE 3008 IFDEBUG(D_INCOMING) 3009 printf( "0x%x --> HL proto 0x%x chan 0x%x\n", 3010 e_data(ecnrq), copcb->co_proto, copcb->co_channel ); 3011 ENDDEBUG 3012 3013 (*copcb->co_proto->pr_input)(e_data(ecnrq), 3014 &copcb->co_faddr, 3015 &copcb->co_laddr, 3016 copcb->co_socket, /* used by cons-transport interface */ 3017 (copcb->co_flags & CONSF_DGM)?0: 3018 copcb->co_channel);/* used by tp-cons interface */ 3019 3020 /* 3021 * the pr_input will free the data chain, so we must 3022 * zero the ptr to is so that m_free doesn't panic 3023 */ 3024 e_data(ecnrq) = (struct mbuf *)0; 3025 } 3026 break; 3027 3028 default: 3029 /* error */ 3030 ifp->if_ierrors ++; 3031 printf("consintr: unknown request\n"); 3032 } 3033 IFDEBUG(D_INCOMING) 3034 printf("consintr: m_freem( 0x%x )\n", m); 3035 ENDDEBUG 3036 m_freem( m ); 3037 } 3038 splx(s0); 3039 } 3040 3041 /* 3042 * Process an ioctl request. 3043 * also set-time-limit, extend-time-limit 3044 * for ALL channels, the time-limit ioctls will be done by open-a-dummy-socket, 3045 * do ioctl with the channel number, close the socket (dumb!). 3046 */ 3047 /* ARGSUSED */ 3048 cons_ioctl(so, cmd, data) 3049 struct socket *so; 3050 int cmd; 3051 caddr_t data; 3052 { 3053 int s = splnet(); 3054 int error = 0; 3055 3056 IFDEBUG(D_CCONS) 3057 printf("cons_ioctl( cmd 0x%x )\n", cmd); 3058 ENDDEBUG 3059 3060 #ifdef notdef 3061 switch (cmd) { 3062 3063 default: 3064 #endif notdef 3065 error = EOPNOTSUPP; 3066 #ifdef notdef 3067 } 3068 #endif notdef 3069 3070 splx(s); 3071 return (error); 3072 } 3073 3074 3075 /* 3076 ************************************************************* 3077 * * 3078 * * 3079 * Interface to CO Subnetwork service from CLNP * 3080 * Must be a device interface. ***** 3081 * *** 3082 * * 3083 * Poof! 3084 */ 3085 3086 /* 3087 * NAME: consioctl() 3088 * CALLED FROM: 3089 * called through the ifnet structure. 3090 * FUNCTION and ARGUMENTS: 3091 * the usual ioctl stuff 3092 * RETURNS: 3093 * E* 3094 * SIDE EFFECTS: 3095 * NOTES: 3096 */ 3097 consioctl(ifp, cmd, data) 3098 register struct ifnet *ifp; 3099 register int cmd; 3100 register caddr_t data; 3101 { 3102 register struct ifaddr *ifa = (struct ifaddr *)data; 3103 register int s = splimp(); 3104 register struct ifreq *ifr = (struct ifreq *)data; 3105 register int error = 0; 3106 void consshutdown(); 3107 3108 switch (cmd) { 3109 case SIOCSIFADDR: 3110 switch (ifa->ifa_addr.sa_family) { 3111 case AF_ISO: 3112 if( (ifp->if_flags & IFF_UP ) == 0) 3113 consinit(ifp->if_unit); 3114 break; 3115 default: 3116 printf("CANNOT config cons with address family %d\n", 3117 ifa->ifa_addr.sa_family); 3118 break; 3119 } 3120 break; 3121 case SIOCSIFFLAGS: 3122 IFDEBUG(D_CCONS) 3123 printf("consioctl: set flags to x%x\n", ifr->ifr_flags); 3124 printf("consioctl: ifp flags are x%x\n", ifp->if_flags); 3125 ENDDEBUG 3126 if( ifr->ifr_flags & IFF_LOOPBACK ) 3127 ifp->if_flags |= IFF_LOOPBACK; 3128 else 3129 ifp->if_flags &= ~IFF_LOOPBACK; 3130 3131 /* if board is down but request takes it up, init the board */ 3132 if (ifr->ifr_flags & IFF_UP && (ifp->if_flags & IFF_UP) == 0) 3133 consinit(ifp->if_unit); 3134 3135 /* if board is up but request takes it down, shut the board down */ 3136 if (((ifr->ifr_flags & IFF_UP) == 0) && (ifp->if_flags & IFF_UP)) { 3137 consshutdown(ifp->if_unit); 3138 } 3139 IFDEBUG(D_CCONS) 3140 printf("consioctl: flags are x%x\n", ifp->if_flags); 3141 ENDDEBUG 3142 break; 3143 case SIOCGSTATUS: 3144 /* warning: must coerse ifp to (struct ifstatus *) in order to use */ 3145 IFDEBUG(D_CCONS) 3146 printf("consioctl: EICON status request\n"); 3147 ENDDEBUG 3148 #if NECN>0 3149 ecnioctl(ifp, cmd, data); 3150 #else 3151 error = ENODEV; 3152 #endif NECN>0 3153 break; 3154 default: 3155 error = EINVAL; 3156 } 3157 splx(s); 3158 return error; 3159 } 3160 3161 /* 3162 * NAME: consattach() 3163 * CALLED FROM: 3164 * cons_init() (which comes from autoconf) 3165 * FUNCTION and ARGUMENTS: 3166 * creates an ifp and fills it in; calls ifattach() on it. 3167 * RETURNS: 3168 * no return value 3169 * SIDE EFFECTS: 3170 * NOTES: 3171 */ 3172 consattach() 3173 { 3174 register struct ifnet *ifp; 3175 register struct mbuf *m; 3176 3177 if(sizeof(struct ifnet) > MLEN) { 3178 printf("Can't attach cons! sizeof(struct ifnet) > MLEN\n"); 3179 return; 3180 } 3181 MGET(m, M_DONTWAIT, MT_IFADDR); 3182 if( !m ) { 3183 printf("Can't attach cons! NO MBUFS!\n"); 3184 return; 3185 } 3186 m->m_len = sizeof(struct ifnet); 3187 ifp = consif = mtod(m, struct ifnet *); 3188 ifp->if_unit = 0; 3189 ifp->if_name = "cons"; 3190 ifp->if_mtu = ECN_MTU; 3191 ifp->if_init = consinit; 3192 ifp->if_ioctl = consioctl; 3193 ifp->if_output = cosns_output; /* called by clnp */ 3194 ifp->if_flags = IFF_LOOPBACK; /* default */ 3195 if_attach(ifp); 3196 printf("cons%d: pseudo device attached \n", ifp->if_unit); 3197 } 3198 3199 /* 3200 * NAME: consinit() 3201 * CALLED FROM: 3202 * consioctl() 3203 * FUNCTION and ARGUMENTS: 3204 * Initializes apropos data structures, etc. 3205 * Marks the device as up. 3206 * Zaps the address list. 3207 * Calls device layer restart on the device if necessary. 3208 */ 3209 Static 3210 consinit(_unit) 3211 register int _unit; /* unit to initialize */ 3212 { 3213 struct ifnet *ecnifp(); 3214 struct ifnet *ifp; 3215 int s; 3216 3217 if ((ifp = ecnifp(_unit)) != (struct ifnet *)0 ) { 3218 ecnrestart(ifp); 3219 IncStat(co_restart); 3220 } 3221 if (consif->if_addrlist == (struct ifaddr *)0) 3222 return; 3223 if ((consif->if_flags & IFF_UP) == 0) { 3224 s = splimp(); 3225 consif->if_flags |= IFF_UP; 3226 splx(s); 3227 } 3228 3229 } 3230 3231 /* 3232 * NAME: consshutdown() 3233 * CALLED FROM: 3234 * cons_ioctl() when user takes down an interface w/ SIOCSIFFLAGS 3235 * FUNCTION and ARGUMENTS: 3236 * calls lower layer shutdown routine on the device. 3237 * and marks the if as down if the if is the sw loopback pseudodevice. 3238 * RETURNS: 3239 * no return value 3240 */ 3241 void 3242 consshutdown(_unit) 3243 register int _unit; /* unit to shutdown */ 3244 { 3245 extern struct ifnet *ecnifp(); 3246 struct ifnet *ifp; 3247 int s; 3248 3249 if ((ifp = ecnifp(_unit)) != (struct ifnet *)0 ) { 3250 ecnshutdown(ifp); 3251 } 3252 if ((consif->if_flags & IFF_UP) ) { 3253 s = splimp(); 3254 consif->if_flags &= ~IFF_UP; 3255 splx(s); 3256 } 3257 } 3258 #endif KERNEL 3259 3260 /* 3261 * NAME: munge() 3262 * CALLED FROM: 3263 * cons_pcbbind(), cons_usrreq() 3264 * FUNCTION and ARGUMENTS: 3265 * Takes the argument (value) and stashes it into the last two 3266 * nibbles of an X.121 address. Does this in the two nibbles beginning 3267 * at the location defined by the character pointer (dst_octet) and the 3268 * integer (dst_nibble). Nibble 0 is the lower nibble (high 3269 * order 4 bits); nibble 1 is the low order 4 bits of *(dst_octet). 3270 * 3271 * RETURNS: 3272 * no return value 3273 */ 3274 Static 3275 munge( value, dst_octet, dst_nibble) 3276 int value; 3277 caddr_t dst_octet; 3278 int dst_nibble; 3279 { 3280 IFDEBUG(D_CCONN) 3281 printf("MUNGE: value 0x%x dst_octet 0x%x, nibble 0x%x)\n", 3282 value, dst_octet, dst_nibble); 3283 ENDDEBUG 3284 if (value >= ISO_PORT_RESERVED) 3285 value -= 1000; 3286 3287 { 3288 /* convert so it looks like a decimal number */ 3289 register int tens, ones; 3290 3291 tens = value/10; 3292 ASSERT( tens <= 9 ); 3293 ones = value - (tens * 10); 3294 3295 value = tens * 16 + ones; 3296 } 3297 3298 dst_octet --; 3299 /* leave nibble same 'cause it's one after the last set nibble */ 3300 3301 *dst_octet &= ~(0xff<<(dst_nibble << 2)); /* zero it */ 3302 *dst_octet |= ((value>>4) << (dst_nibble<<2)); 3303 dst_nibble = 1-dst_nibble; 3304 dst_octet += dst_nibble; 3305 3306 *dst_octet &= ~(0xff<<(dst_nibble << 2)); /* zero it */ 3307 *dst_octet |= ((value&0xff) << (dst_nibble<<2)); 3308 } 3309 3310 /* 3311 * NAME: unmunge() 3312 * CALLED FROM: 3313 * DTEtoNSAP(), FACILtoNSAP() 3314 * FUNCTION and ARGUMENTS: 3315 * return the port/tsuffix represented by the two digits found in a 3316 * bcd string beginning at the (dst_nibble)th nibble of the 3317 * octet BEFORE (dst_octet). 3318 * 3319 * dst_octet,dst_nibble is the nibble after the one we'll look at 3320 * RETURNS: 3321 * an integer, the port/tsuffix 3322 * Note- converts to a port > 1000 if necessary. 3323 */ 3324 Static int 3325 unmunge( dst_octet, dst_nibble ) 3326 caddr_t dst_octet; 3327 int dst_nibble; 3328 { 3329 register u_short last = 0; 3330 3331 dst_octet --; 3332 /* leave nibble same 'cause it's one after the last set nibble */ 3333 IFDEBUG(D_CADDR) 3334 printf("unmunge: *octet 0x%x, nibble 0x%x\n", *dst_octet, 3335 dst_nibble); 3336 ENDDEBUG 3337 3338 last = ((*dst_octet) & (0xff<<(dst_nibble<<2))); 3339 dst_nibble = 1-dst_nibble; 3340 dst_octet += dst_nibble; 3341 3342 last |= ((*dst_octet) & (0xff<<(dst_nibble << 2))); 3343 { 3344 /* convert to a decimal number */ 3345 register int tens, ones; 3346 3347 tens = (last&0xf0)>>4; 3348 ones = last&0xf; 3349 3350 last = tens * 10 + ones; 3351 } 3352 3353 IFDEBUG(D_CADDR) 3354 printf("unmunge computes 0x%x\n", last); 3355 ENDDEBUG 3356 if((int)last+1000 >= ISO_PORT_RESERVED) 3357 last += 1000; 3358 IFDEBUG(D_CADDR) 3359 printf("unmunge returns 0x%x\n", last); 3360 ENDDEBUG 3361 return last; 3362 } 3363 3364 /* 3365 * NAME: make_partial_x25_packet() 3366 * 3367 * FUNCTION and ARGUMENTS: 3368 * Makes part of an X.25 call packet, for use by the eicon board. 3369 * (src) and (dst) are the NSAP-addresses of source and destination. 3370 * (proto) is the higher-layer protocol number (in iso.h) 3371 * (buf) is a ptr to a buffer into which to write this partial header. 3372 * 3373 * The partial header looks like (choke): 3374 * octet meaning 3375 * 1 calling DTE len | called DTE len (lengths in nibbles) 3376 * 2..n-1 called DTE addr | (<-- boundary may be middle of an octet) 3377 * calling DTE addr | zero nibble to round to octet boundary. 3378 * n Facility length (in octets) 3379 * n+1 Facility field, which is a set of: 3380 * m facil code 3381 * m+1 facil param len (for >2-byte facilities) in octets 3382 * m+2..p facil param field 3383 * q user data (protocol identification octet) 3384 * 3385 * 3386 * RETURNS: 3387 * 0 if OK 3388 * E* if failed. 3389 */ 3390 3391 #ifdef X25_1984 3392 int cons_use_facils = 1; 3393 #else X25_1984 3394 int cons_use_facils = 0; 3395 #endif X25_1984 3396 3397 int cons_use_udata = 1; /* KLUDGE FOR DEBUGGING */ 3398 3399 Static int 3400 make_partial_x25_packet(copcb, m) 3401 struct cons_pcb *copcb; 3402 struct mbuf *m; 3403 { 3404 struct sockaddr_iso *src, *dst; 3405 u_int proto; 3406 int flag; 3407 caddr_t buf = mtod(m, caddr_t); 3408 register caddr_t ptr = buf + 1; /* make room for 2 length nibbles */ 3409 register int len = 0; 3410 int buflen =0; 3411 caddr_t facil_len; 3412 int oddness = 0; 3413 3414 src = &copcb->co_laddr; 3415 dst = &copcb->co_faddr; 3416 proto = copcb->co_proto->pr_protocol, 3417 flag = copcb->co_flags & CONSF_XTS; 3418 3419 3420 IFDEBUG(D_CCONN) 3421 printf("make_partial_x25_packet(0x%x, 0x%x, 0x%x, 0x%x, 0x%x)\n", 3422 src, dst, proto, m, flag); 3423 ENDDEBUG 3424 3425 /* 3426 * Note - order of addrs in x25 pkt hdr is wierd: 3427 * calling len/called len/called addr/calling addr (p.40 ISO 8202) 3428 */ 3429 if( (len = copcb->co_peer_dte.dtea_niblen) > 0 ) { 3430 nibble_copy( (char *)(copcb->co_peer_dte.dtea_addr), HIGH_NIBBLE, 3431 ptr, HIGH_NIBBLE, len); 3432 } else { 3433 if ((len = NSAPtoDTE( ptr, HIGH_NIBBLE, dst)) <=0 ) { 3434 return E_CO_OSI_UNSAP; 3435 } 3436 } 3437 *buf = len; /* fill in called dte addr length */ 3438 ptr += len>>1; /* len is in nibbles */ 3439 oddness += len&0x1; 3440 3441 if ((len = NSAPtoDTE( ptr, 1-(len&0x1), src)) <=0 ) { 3442 return E_CO_OSI_UNSAP; 3443 } 3444 ptr += len>>1; /* len is in nibbles */ 3445 *buf |= len << 4; /* fill in calling dte addr length */ 3446 oddness += len&0x1; 3447 3448 IFDEBUG(D_CADDR) 3449 printf("make_partial 2: ptr 0x%x, len 0x%x oddness 0x%x\n", 3450 ptr, len, oddness ); 3451 ENDDEBUG 3452 /* if either of the addresses were an odd length, the count is off by 1 */ 3453 if( oddness ) { 3454 ptr ++; 3455 } 3456 3457 /* ptr now points to facil length (len of whole facil field in OCTETS */ 3458 facil_len = ptr ++; 3459 3460 IFDEBUG(D_CADDR) 3461 printf("make_partial calling: ptr 0x%x, len 0x%x\n", ptr, 3462 src->siso_addr.isoa_len); 3463 ENDDEBUG 3464 if( cons_use_facils ) { 3465 *ptr = 0xcb; /* calling facility code */ 3466 ptr ++; 3467 ptr ++; /* leave room for facil param len (in OCTETS + 1) */ 3468 ptr ++; /* leave room for the facil param len (in nibbles), 3469 * high two bits of which indicate full/partial NSAP 3470 */ 3471 len = src->siso_addr.isoa_len; 3472 bcopy( &src->siso_addr.isoa_afi, ptr, len); 3473 *(ptr-2) = len+2; /* facil param len in octets */ 3474 *(ptr-1) = len<<1; /* facil param len in nibbles */ 3475 ptr += len; 3476 3477 IFDEBUG(D_CADDR) 3478 printf("make_partial called: ptr 0x%x, len 0x%x\n", ptr, 3479 dst->siso_addr.isoa_len); 3480 ENDDEBUG 3481 *ptr = 0xc9; /* called facility code */ 3482 ptr ++; 3483 ptr ++; /* leave room for facil param len (in OCTETS + 1) */ 3484 ptr ++; /* leave room for the facil param len (in nibbles), 3485 * high two bits of which indicate full/partial NSAP 3486 */ 3487 len = dst->siso_addr.isoa_len; 3488 bcopy( &dst->siso_addr.isoa_afi, ptr, len); 3489 *(ptr-2) = len+2; /* facil param len = addr len + 1 for each of these 3490 * two length fields, in octets */ 3491 *(ptr-1) = len<<1; /* facil param len in nibbles */ 3492 ptr += len; 3493 3494 } 3495 *facil_len = ptr - facil_len - 1; 3496 if(*facil_len > X25_FACIL_LEN_MAX ) 3497 return E_CO_PNA_LONG; 3498 3499 if( cons_use_udata ) { 3500 if (copcb->co_x25crud_len > 0) { 3501 /* 3502 * The user specified something. Stick it in 3503 */ 3504 bcopy(copcb->co_x25crud, ptr, copcb->co_x25crud_len); 3505 ptr += copcb->co_x25crud_len; 3506 } else { 3507 /* protocol identifier */ 3508 switch (proto) { 3509 /* unfortunately all are considered 1 protocol */ 3510 case ISOPROTO_TP0: 3511 case ISOPROTO_TP1: 3512 case ISOPROTO_TP2: 3513 case ISOPROTO_TP3: 3514 case ISOPROTO_TP4: 3515 case ISOPROTO_CLTP: 3516 /* no user data for TP */ 3517 break; 3518 3519 case ISOPROTO_CLNP: 3520 *ptr = 0x81; 3521 ptr++; /* count the proto id byte! */ 3522 break; 3523 case ISOPROTO_INACT_NL: 3524 *ptr = 0x0; 3525 ptr++; /* count the proto id byte! */ 3526 break; 3527 case ISOPROTO_X25: 3528 *ptr = 0xff; /* reserved for future extensions */ 3529 /* we're stealing this value for local use */ 3530 ptr++; /* count the proto id byte! */ 3531 break; 3532 default: 3533 return EPROTONOSUPPORT; 3534 } 3535 } 3536 } 3537 3538 buflen = (int)(ptr - buf); 3539 3540 IFDEBUG(D_CDUMP_REQ) 3541 register int i; 3542 3543 printf("ECN_CONNECT DATA buf 0x%x len %d (0x%x)\n", 3544 buf, buflen, buflen); 3545 for( i=0; i < buflen; ) { 3546 printf("+%d: %x %x %x %x %x %x %x %x\n", 3547 i, 3548 *(buf+i), *(buf+i+1), *(buf+i+2), *(buf+i+3), 3549 *(buf+i+4), *(buf+i+5), *(buf+i+6), *(buf+i+7)); 3550 i+=8; 3551 } 3552 ENDDEBUG 3553 IFDEBUG(D_CADDR) 3554 printf("make_partial returns buf 0x%x size 0x%x bytes\n", 3555 mtod(m, caddr_t), buflen); 3556 ENDDEBUG 3557 3558 ASSERT( X25_PARTIAL_PKT_LEN_MAX < MLEN ); 3559 3560 if(buflen > X25_PARTIAL_PKT_LEN_MAX) 3561 return E_CO_PNA_LONG; 3562 3563 m->m_len = buflen; 3564 return 0; 3565 } 3566 3567 /* 3568 * NAME: NSAPtoDTE() 3569 * CALLED FROM: 3570 * make_partial_x25_packet() 3571 * FUNCTION and ARGUMENTS: 3572 * get a DTE address from an NSAP-address (struct sockaddr_iso) 3573 * (dst_octet) is the octet into which to begin stashing the DTE addr 3574 * (dst_nibble) takes 0 or 1. 1 means begin filling in the DTE addr 3575 * in the high-order nibble of dst_octet. 0 means low-order nibble. 3576 * (addr) is the NSAP-address 3577 * (flag) is true if the transport suffix is to become the 3578 * last two digits of the DTE address 3579 * A DTE address is a series of BCD digits 3580 * 3581 * A DTE address may have leading zeros. The are significant. 3582 * 1 digit per nibble, may be an odd number of nibbles. 3583 * 3584 * An NSAP-address has the DTE address in the IDI. Leading zeros are 3585 * significant. Trailing hex f indicates the end of the DTE address. 3586 * Also is a series of BCD digits, one per nibble. 3587 * 3588 * RETURNS 3589 * # significant digits in the DTE address, -1 if error. 3590 */ 3591 3592 Static int 3593 NSAPtoDTE( dst_octet, dst_nibble, addr) 3594 caddr_t dst_octet; 3595 int dst_nibble; 3596 register struct sockaddr_iso *addr; 3597 { 3598 int error; 3599 u_char x121string[7]; /* maximum is 14 digits */ 3600 int x121strlen; 3601 struct dte_addr *dtea; 3602 3603 IFDEBUG(D_CADDR) 3604 printf("NSAPtoDTE: nsap: %s\n", clnp_iso_addrp(&addr->siso_addr)); 3605 ENDDEBUG 3606 3607 error = iso_8208snparesolve(addr, x121string, &x121strlen); 3608 ASSERT(error == 0); 3609 if( error != 0 ) { 3610 /* no snpa - cannot send */ 3611 IFDEBUG(D_CADDR) 3612 printf("NSAPtoDTE: 8208resolve: %d\n", error ); 3613 ENDDEBUG 3614 return 0; 3615 } 3616 ASSERT(x121strlen == sizeof(struct dte_addr)); 3617 dtea = (struct dte_addr *)x121string; 3618 x121strlen = dtea->dtea_niblen; 3619 3620 nibble_copy((char *)x121string, HIGH_NIBBLE, 3621 dst_octet, dst_nibble, x121strlen); 3622 return x121strlen; 3623 } 3624 3625 /* 3626 * NAME: FACILtoNSAP() 3627 * CALLED FROM: 3628 * parse_facil() 3629 * FUNCTION and ARGUMENTS: 3630 * Creates and NSAP in the sockaddr_iso (addr) from the 3631 * x.25 facility found at (buf), of length (buf_len). 3632 * RETURNS: 3633 * 0 if ok, non-zero if error; 3634 */ 3635 3636 Static int 3637 FACILtoNSAP( buf, buf_len, addr) 3638 caddr_t buf; 3639 u_char buf_len; /* in bytes */ 3640 register struct sockaddr_iso *addr; 3641 { 3642 int len_in_nibbles; 3643 3644 IFDEBUG(D_CADDR) 3645 printf("FACILtoNSAP( 0x%x, 0x%x, 0x%x )\n", 3646 buf, buf_len, addr ); 3647 ENDDEBUG 3648 3649 len_in_nibbles = *buf; 3650 /* despite the fact that X.25 makes us put a length in nibbles 3651 * here, the NSAP-addrs are always in full octets 3652 */ 3653 buf ++; 3654 3655 bzero( addr, sizeof (struct sockaddr_iso) ); 3656 3657 ASSERT(buf_len <= 1+sizeof (struct iso_addr)); 3658 if(buf_len > 1+sizeof (struct iso_addr)) { 3659 return -1; /* error */ 3660 } 3661 ASSERT(len_in_nibbles == (buf_len - 1)<<1); 3662 if(len_in_nibbles != (buf_len - 1)<<1) { 3663 return -2; /* error */ 3664 } 3665 bcopy(buf, &addr->siso_addr.isoa_afi, buf_len-1); 3666 addr->siso_addr.isoa_len = buf_len-1; 3667 IFDEBUG(D_CADDR) 3668 printf("FACILtoNSAP: isoa_len 0x%x\n", 3669 addr->siso_addr.isoa_len); 3670 ENDDEBUG 3671 addr->siso_family = AF_ISO; 3672 3673 addr->siso_tsuffix = 3674 unmunge( ((caddr_t)&addr->siso_addr.t37_idi) + ADDR37_IDI_LEN , 1 ); 3675 return 0; 3676 } 3677 3678 /* 3679 * NAME: DTEtoNSAP() 3680 * CALLED FROM: 3681 * parse_facil() 3682 * FUNCTION and ARGUMENTS: 3683 * Creates a type 37 NSAP in the sockaddr_iso (addr) 3684 * from a DTE address found at the (src_nibble)th nibble of 3685 * the octet (src_octet), of length (src_nib_len). 3686 * 3687 * RETURNS: 3688 * 0 if ok; E* otherwise. 3689 */ 3690 3691 Static int 3692 DTEtoNSAP(addr, src_octet, src_nibble, src_nib_len) 3693 struct sockaddr_iso *addr; 3694 caddr_t src_octet; 3695 int src_nibble, src_nib_len; 3696 { 3697 caddr_t dst_octet; 3698 int pad_len; 3699 int dst_nibble; 3700 char first_nib; 3701 static char *z_pad = "\0\0\0\0\0\0\0"; 3702 static char *f_pad = "\021\021\021\021\021\021\021"; 3703 3704 IFDEBUG(D_CADDR) 3705 printf("DTEtoNSAP( 0x%x, 0x%x, 0x%x, 0x%x )\n", 3706 src_octet, src_nibble, src_nib_len, addr ); 3707 ENDDEBUG 3708 3709 bzero( addr, sizeof(*addr)); 3710 addr->siso_family = AF_ISO; 3711 /* 3712 * Coming from a DTE addr it's always type 37. 3713 * src_octet <-- starting place in the NSAP-address of 3714 * the embedded SNPA-address (x.121 addr or DTE addr). 3715 */ 3716 addr->siso_addr.isoa_afi = 0x37; 3717 3718 /* first, figure out what pad to use and pad */ 3719 3720 first_nib = (*src_octet) >> (SHIFT*(1-src_nibble)); 3721 pad_len = (ADDR37_IDI_LEN<<1 - src_nib_len); 3722 nibble_copy(first_nib? z_pad : f_pad, HIGH_NIBBLE, 3723 (caddr_t) addr->siso_addr.t37_idi, HIGH_NIBBLE, pad_len); 3724 3725 dst_octet += (pad_len>>1); 3726 dst_nibble = 1-(pad_len & 0x1); 3727 IFDEBUG(D_CADDR) 3728 printf("DTEtoNSAP 2( 0x%x, 0x%x, 0x%x, 0x%x )\n", 3729 dst_octet, dst_nibble, pad_len, src_nib_len ); 3730 ENDDEBUG 3731 3732 /* now copy the dte address */ 3733 nibble_copy( src_octet, src_nibble, dst_octet, dst_nibble, src_nib_len); 3734 3735 addr->siso_addr.isoa_len = ADDR37_IDI_LEN + ADDR37_DSP_LEN +1 /* for afi */; 3736 /* kludge */ 3737 3738 addr->siso_tsuffix = unmunge( 3739 (caddr_t) &(addr->siso_addr.t37_idi[ADDR37_IDI_LEN]), HIGH_NIBBLE); 3740 3741 IFDEBUG(D_CADDR) 3742 printf("DTEtoNSAP 3 returning 0 tsuffix 0x%x\n", addr->siso_tsuffix); 3743 ENDDEBUG 3744 3745 return 0; /* ok */ 3746 } 3747 3748 /* 3749 * FUNCTION and ARGUMENTS: 3750 * parses (buf_len) bytes beginning at (buf) and finds 3751 * a called nsap, a calling nsap, and protocol identifier. 3752 * RETURNS: 3753 * 0 if ok, E* otherwise. 3754 */ 3755 3756 Static int 3757 parse_facil( buf, buf_len, called, calling, proto, peer_dte) 3758 caddr_t buf; 3759 u_char buf_len; /* in bytes */ 3760 register struct sockaddr_iso *called, *calling; 3761 int *proto; 3762 struct dte_addr *peer_dte; 3763 { 3764 register int i; 3765 caddr_t ptr; 3766 caddr_t facil_len; 3767 int facil_param_len; 3768 struct sockaddr_iso *addr; 3769 int addrs_not_parsed = (int)0xcb + (int)0xc9; 3770 3771 IFDEBUG(D_CADDR) 3772 printf("parse_facil( 0x%x, 0x%x, 0x%x, 0x%x, 0x%x )\n", 3773 buf, buf_len, called, calling, *proto); 3774 dump_buf(buf, buf_len); 3775 ENDDEBUG 3776 3777 /* find the beginnings of the facility fields in buf 3778 * by skipping over the called & calling DTE addresses 3779 * i <- # nibbles in called + # nibbles in calling 3780 * i += 1 so that an odd nibble gets rounded up to even 3781 * before dividing by 2, then divide by two to get # octets 3782 */ 3783 i = (int)(*buf >> 4) + (int)(*buf&0xf); 3784 i++; 3785 ptr = (caddr_t) (buf + (i>>1)); 3786 /* now i is number of octets */ 3787 3788 ptr ++; /* plus one for the DTE lengths byte */ 3789 3790 /* ptr now is at facil_length field */ 3791 facil_len = ptr++; 3792 IFDEBUG(D_CADDR) 3793 printf("parse_facils: facil length is 0x%x\n", (int) *facil_len); 3794 ENDDEBUG 3795 3796 while( ptr <= (caddr_t)(facil_len + (int)*facil_len) ) { 3797 /* get NSAP addresses from facilities */ 3798 switch (*ptr) { 3799 case 0xcb: 3800 facil_param_len = 0; 3801 addr = calling; 3802 addrs_not_parsed -= 0xcb; 3803 break; 3804 case 0xc9: 3805 facil_param_len = 0; 3806 addr = called; 3807 addrs_not_parsed -= 0xc9; 3808 break; 3809 3810 /* from here to default are legit cases that I ignore */ 3811 3812 /* variable length */ 3813 case 0xca: /* end-to-end transit delay negot */ 3814 case 0xc6: /* network user id */ 3815 case 0xc5: /* charging info : indicating monetary unit */ 3816 case 0xc2: /* charging info : indicating segment count */ 3817 case 0xc1: /* charging info : indicating call duration */ 3818 case 0xc4: /* RPOA extended format */ 3819 case 0xc3: /* call redirection notification */ 3820 facil_param_len = 0; 3821 addr = (struct sockaddr_iso *)0; 3822 break; 3823 3824 /* 1 octet */ 3825 case 0x0a: /* min. throughput class negot */ 3826 case 0x02: /* throughput class */ 3827 case 0x03: case 0x47: /* CUG shit */ 3828 case 0x0b: /* expedited data negot */ 3829 case 0x01: /* Fast select or reverse charging 3830 (example of intelligent protocol design) */ 3831 case 0x04: /* charging info : requesting service */ 3832 case 0x08: /* called line addr modified notification */ 3833 facil_param_len = 1; 3834 addr = (struct sockaddr_iso *)0; 3835 break; 3836 3837 /* any 2 octets */ 3838 case 0x42: /* pkt size */ 3839 case 0x43: /* win size */ 3840 case 0x44: /* RPOA basic format */ 3841 case 0x41: /* bilateral CUG shit */ 3842 case 0x49: /* transit delay selection and indication */ 3843 facil_param_len = 2; 3844 addr = (struct sockaddr_iso *)0; 3845 break; 3846 3847 /* don't have any 3 octets */ 3848 /* 3849 facil_param_len = 3; 3850 */ 3851 default: 3852 ASSERT(0); 3853 printf( 3854 "BOGUS FACILITY CODE facil_len 0x%x *facil_len 0x%x, ptr 0x%x *ptr 0x%x\n", 3855 facil_len, *facil_len, 3856 ptr, *ptr); 3857 addr = (struct sockaddr_iso *)0; 3858 /* facil that we don't handle */ 3859 return E_CO_HLI_REJI; 3860 } 3861 ptr++; /* one for facil code */ 3862 if(facil_param_len == 0) /* variable length */ 3863 facil_param_len = (int)*ptr; /* 1 + the real facil param */ 3864 if( addr && FACILtoNSAP(ptr+1, facil_param_len-1, addr) ) { 3865 return E_CO_OSI_UNSAP; 3866 } 3867 ptr += facil_param_len; 3868 } 3869 if( addrs_not_parsed ) { 3870 /* no facilities, get NSAP addresses from DTE addresses */ 3871 register int ed, ing; 3872 3873 ed = (int)(*buf&0xf); 3874 if( ed == 0 ) { 3875 panic("Called DTE address absent"); 3876 } 3877 DTEtoNSAP(called, (buf + 1)/*octet*/, 3878 1/*nibble*/, ed); 3879 3880 ing = (int)(*buf >> 4); 3881 if( ing == 0 ) { 3882 printf("cons: panic: Calling DTE address absent"); 3883 return E_CO_HLI_REJI; 3884 } 3885 nibble_copy((buf + (ed>>1)+1)/*octet*/, 1-(ed&0x1)/*nibble*/, 3886 peer_dte->dtea_addr, HIGH_NIBBLE, ing); 3887 DTEtoNSAP(calling, (buf + (ed>>1)+1)/*octet*/, 3888 1-(ed&0x1)/*nibble*/, ing); 3889 3890 } 3891 3892 ASSERT( ptr == (caddr_t)(facil_len + 1 + (int)*facil_len) ); 3893 3894 /* 3895 * now look for user data to find protocol identifier 3896 */ 3897 if( ptr == buf + buf_len ) { 3898 /* no user data */ 3899 *proto = ISOPROTO_TP; /* to proto id --> use TP */ 3900 IFDEBUG(D_CADDR) 3901 printf("NO USER DATA: use TP\n"); 3902 ENDDEBUG 3903 } else { 3904 ASSERT ( ptr < buf + buf_len ); 3905 if ( ptr >= buf + buf_len ) { 3906 printf("ptr 0x%x buf 0x%x buf_len 0x%x buf+buf_len 0x%x\n", 3907 ptr, buf, buf_len, buf+buf_len); 3908 } 3909 IFDEBUG(D_CADDR) 3910 printf("proto byte 0x%x, value 0x%x\n", ptr, *ptr); 3911 ENDDEBUG 3912 switch(*ptr) { 3913 case 0x81: 3914 *proto = ISOPROTO_CLNP; 3915 break; 3916 case 0x0: 3917 *proto = ISOPROTO_INACT_NL; 3918 break; 3919 case 'e': /* for EAN */ 3920 *proto = ISOPROTO_TP; 3921 /* can check for "an2" or can ignore the rest of the u data */ 3922 break; 3923 case 0xff: /* reserved for future extensions */ 3924 *proto = ISOPROTO_X25; 3925 break; 3926 case 0x82: /* 9542 not implemented */ 3927 case 0x84: /* 8878/A SNDCP not implemented */ 3928 default: 3929 *proto = -1; 3930 return E_CO_HLI_PROTOID; 3931 } 3932 } 3933 return 0; 3934 } 3935 3936 #endif NARGOXTWENTYFIVE > 0 3937