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