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