- if ( iso_8208snparesolve(dst, &dest_dte, &dummy)) {
- ASSERT(0);
- return (struct cons_pcb *)0; /* error */
- }
- ASSERT(dummy == sizeof(struct dte_addr));
-
- for( copcb = *copcblist; copcb; copcb = *(++copcblist) ) {
- copcb = (struct cons_pcb *)copcb->co_next;
- while (copcb != *copcblist) {
- IFDEBUG(D_CFIND)
- printf(
- "cons_find: chan 0x%x flags 0x%x proto 0x%x state 0x%x \n",
- copcb->co_channel, copcb->co_flags, copcb->co_proto,
- copcb->co_state);
- ENDDEBUG
- /*
- * if flags is a subset of the bits in co_flags, it will suffice
- */
- if( ((copcb->co_flags & flags) == flags ) &&
- /* PHASE2: where do we get the mask if we use nsaps ????
- * If dte addresses are used, then use
- * nibble compare otherwise...???
- */
-#ifdef notdef
- iso_addrmatch1(&(copcb->co_faddr.siso_addr), &(dst->siso_addr))
-#else
- dest_dte.dtea_niblen == copcb->co_peer_dte.dtea_niblen &&
- nibble_match( (char *)&(copcb->co_peer_dte.dtea_addr),
- HIGH_NIBBLE, (char *)dest_dte.dtea_addr,
- HIGH_NIBBLE, dest_dte.dtea_niblen)
-#endif notdef
- &&
- (copcb->co_proto == proto) &&
- (copcb->co_state >= MIN_USABLE_STATE)) {
- IFDEBUG(D_CFIND)
- printf(
- "cons_find: add'l criteria...\n" );
- ENDDEBUG
- if((copcb->co_state != OPEN) &&
- (next_best.xd_qlen > copcb->co_pending.ifq_len)) {
- next_best.xd_pcb = copcb;
- next_best.xd_qlen = copcb->co_pending.ifq_len;
- }
- if( !addl_criteria || (*addl_criteria)(copcb, mask) ) {
- goto found; /* have to break out of 2 loops */
- }
- }
- copcb = (struct cons_pcb *)copcb->co_next ;
- }
- }
-#ifdef notdef
- /* TODO:
- * have a limit of the number of calls per desitination.
- * If we didn't find one already open AND our limit for this
- * destination hasn't been reached, return 0 'cause
- * then the caller will open a new one.
- * Otherwise return next_best.
- * To do this we need some sort of per-destination info.
- * Could go into the directory service. Oh, grotesque.
- */
-#endif notdef
- if( copcb == (struct cons_pcb *)0 ) {
- copcb = next_best.xd_pcb; /* may be zero too */
- IFDEBUG(D_CFIND)
- printf("NEXT_BEST! \n");
- dump_copcb(copcb, "find: next_best");
- ENDDEBUG
- }
-found:
-
- splx(s);
-
- IFDEBUG(D_CFIND)
- printf("returns 0x%x \n", copcb);
- ENDDEBUG
- return copcb;
-}
-
-
-/*
- * NAME: issue_clear_req()
- * CALLED FROM:
- * cons_clear() and wherever we get an error from x.25 that makes us
- * want to close the vc on which it came, but don't have
- * a copcb assoc. with that vc.
- * FUNCTION and ARGUMENTS:
- * Creates an eicon_request for a clear request, returns it in an mbuf.
- * (chan) is the channel on which to do the clear, (reason) is the
- * clear reason(diagnostic).
- * RETURN VALUE:
- * returns E*
- */
-Static int
-issue_clear_req(chan, reason, ifp, loop)
- u_char chan, reason;
- struct ifnet *ifp;
- int loop;
-{
- register struct mbuf *m;
- register struct mbuf *cdm;
- register struct eicon_request *ecnrq;
- struct e_clear_data *ecd;
-
- IFDEBUG(D_CCONN)
- printf("issue_clear_req(0x%x, 0x%x, 0x%x, 0x%x)\n",
- chan, reason, ifp, loop);
- ENDDEBUG
- m = m_getclr(M_DONTWAIT, MT_XCLOSE);
- if( !m ) {
- return ENOBUFS;
- }
- m->m_len = sizeof(struct eicon_request);
- ecnrq = mtod(m, struct eicon_request *);
- ecnrq->e_cmd = ECN_CLEAR;
- ecnrq->e_vc = chan & 0xff;
- /*
- * see p. 149 of 8208 for reasons (diagnostic codes)
- */
- MGET(cdm, M_DONTWAIT, MT_XCLOSE);
- if( !cdm ) {
- m_freem(m);
- return ENOBUFS;
- }
- cdm->m_len = sizeof(struct e_clear_data); /* cause, diagnostic */
- e_data(ecnrq) = cdm;
-
- ecd = mtod(cdm, struct e_clear_data *);
- ecd->ecd_cause = 0x0; /* DTE initiated, diagnostic tells more */
- ecd->ecd_diagnostic = (u_char)reason;
-
- IncStat(co_clear_out);
- return choose_output(ifp, m, loop);
-}
-
-
-/*
- * NAME: cons_clear()
- * CALLED FROM:
- * cons_usrreq(), PRU_DISCONNECT,
- * cons_slowtimo(), cons_free_lru()
- * FUNCTION and ARGUMENTS:
- * Builds a clear request for the connection represented by copcb,
- * gives it to the device.
- * ECN_CLEAR(request) takes e_vc only, returns adr_status.
- * RETURN VALUE:
- */
-
-Static int
-cons_clear( copcb, reason)
- register struct cons_pcb *copcb;
- u_char reason;
-{
- register struct mbuf *m;
- int error;
-
- IFDEBUG(D_CCONN)
- printf("cons_clear(0x%x, 0x%x)\n", copcb, reason);
- ENDDEBUG
- if( !copcb) {
- printf("cons PANIC: clear: No copcb\n");
- return 0;
- }
- while( copcb->co_pending.ifq_len > 0 ) {
- register int s = splimp();
-
- IF_DEQUEUE( &copcb->co_pending, m );
- splx(s);
- m_freem(m);
- }
- if( (copcb->co_state == CLOSED) || (copcb->co_state == CLOSING) )
- return 0;
-
-#ifdef ARGO_DEBUG
- if( copcb->co_state == CONNECTING) {
- IFDEBUG(D_CCONN)
- dump_copcb(copcb, "clear");
- ENDDEBUG
- } else if( (copcb->co_channel == 0) || (copcb->co_channel == X_NOCHANNEL) ) {
- IFDEBUG(D_CCONN)
- dump_copcb(copcb, "clear");
- ENDDEBUG
- }
-#endif ARGO_DEBUG
-
- copcb->co_state = CLOSING;
-
- IFDEBUG(D_CCONN)
- printf("cons_clear: channel 0x%x copcb 0x%x dst: ",
- copcb->co_channel, copcb);
- dump_isoaddr(&copcb->co_faddr);
- dump_copcb(copcb, "clear");
- ENDDEBUG
-
- error = issue_clear_req(copcb->co_channel, reason, copcb->co_ifp,
- copcb->co_flags & CONSF_LOOPBACK);
- copcb->co_channel = X_NOCHANNEL;
- copcb->co_state = CLOSED;
- return error;
-}
-
-
-/*
- * NAME: cons_senddata()
- * CALLED FROM:
- * cons_output(), consoutput(), consintr()
- * FUNCTION and ARGUMENTS:
- * issued a data (write) command - if the device isn't ready,
- * it enqueues the command on a per-connection queue.
- * RETURN VALUE:
- * ENOBUFS
- * Is responsible for freeing m0!
- *
- * ECN_SEND (write)
- */
-
-Static int
-cons_senddata(copcb, m0)
- register struct cons_pcb *copcb;
- struct mbuf *m0;
-{
- register struct mbuf *m;
- register struct eicon_request *ecnrq;
- int s;
-
- IFDEBUG(D_CDATA)
- printf("cons_senddata( 0x%x, m 0x%x ) chan 0x%x",
- copcb, m0, copcb->co_channel );
- printf(" co_lport 0x%x\n", copcb->co_lport);
- ENDDEBUG
- if( m0 == MNULL )
- return;
- ASSERT( m0->m_len > 0);
- if( m0->m_len <= 0) {
- printf("cons_senddata : BAD MLEN? 0x%x", m0->m_len);
- }
-
- touch(copcb);
-
- if( (copcb->co_state == CONNECTING) || (copcb->co_state == ACKWAIT) ) {
- IFDEBUG(D_CDATA)
- printf("senddata PUTTING ON PENDING Q copcb 0x%x state 0x%x\n",
- copcb, copcb->co_state);
- ENDDEBUG
- s = splimp();
- if (IF_QFULL(&copcb->co_pending)) {
- IFDEBUG(D_CDATA)
- printf("senddata DROPPING m0 0x%x\n", m0);
- ENDDEBUG
- IF_DROP(&copcb->co_pending);
- if(copcb->co_ifp) {
- copcb->co_ifp->if_snd.ifq_drops ++;
- }
- IncStat(co_Xdrops);
- copcb->co_ifp->if_oerrors ++;
- splx(s);
- m_freem (m0);
-
- if( copcb->co_proto && copcb->co_proto->pr_ctlinput ) {
- (*copcb->co_proto->pr_ctlinput)(PRC_QUENCH,
- (struct sockaddr_iso *)&copcb->co_faddr,
- (caddr_t)copcb);
-
- return 0;
- } else
- return E_CO_QFULL;
- }
- IFDEBUG(D_CDATA)
- printf("Putting 0x%x on 0x%x->pending Q\n", m0, copcb);
- ENDDEBUG
- IF_ENQUEUE( &copcb->co_pending, m0 );
- splx(s);
- return 0;
- }
- if(copcb->co_channel == 0 ) {
- return E_CO_CHAN;
- }
- ASSERT( copcb->co_state == OPEN);
-
- m = m_getclr(M_DONTWAIT, MT_XDATA);
- if( !m ) {
- copcb->co_ifp->if_oerrors ++;
- m_freem (m0);
- return ENOBUFS;
- }
- m->m_len = sizeof(struct eicon_request);
- ecnrq = mtod(m, struct eicon_request *);
- ecnrq->e_pcb = (caddr_t)copcb;
- if( copcb->co_myself != copcb ) {
- struct mbuf *mm;
- /* TODO: REMOVE THIS DEBUGGING HACK */
- ASSERT(0);
- printf("BAD e_pcb from HL (0x%x,0x%x)\n", copcb, copcb->co_myself);
- mm = dtom( copcb );
- if(mm->m_type == MT_FREE)
- printf("FREED MBUF!\n");
- return ENETDOWN;
- }
- ASSERT( copcb->co_channel != 0);
- ASSERT( copcb->co_channel != X_NOCHANNEL);
- ecnrq->e_vc = (copcb->co_channel & 0xff);
- ecnrq->e_cmd = ECN_SEND;
- e_data(ecnrq) = m0;
- {
- /* TODO: REMOVE THIS DEBUGGING HACK */
- struct mbuf *thedata = e_data(ecnrq);
- u_int *firstint = mtod( thedata, u_int *);
-
- if( (*firstint & 0xff000000) != 0x81000000 ) {
- /* not clnp */
- switch( ((*firstint) & 0x00ff0000) >> 20 ) {
- case 0x1:
- case 0x2:
- case 0x3:
- case 0x6:
- case 0x7:
- case 0x8:
- case 0xc:
- case 0xd:
- case 0xe:
- case 0xf:
- break;
- default:
- printf(" ECN_SEND! BAD DATA\n" );
- dump_buf( thedata, 20 + 12 );
- m_freem( m0 );
- return ENETDOWN;
- }
- }
- }
-
- ecnrq->e_info = 0;
-
- IFDEBUG(D_CDUMP_REQ)
- printf("senddata ecnrq\n");
- ENDDEBUG
- IncStat(co_send);
-
- ASSERT( copcb->co_state == OPEN );
- copcb->co_state = ACKWAIT;
-
- if( copcb->co_myself != copcb ) {
- struct mbuf *mm;
- /* TODO: REMOVE this and all mention of co_myself */
- ASSERT(0);
- printf("BAD e_pcb TO THE BOARD ecn (0x%x) cmd 0x%x\n",
- ecnrq->e_pcb, ecnrq->e_cmd);
- mm = dtom( copcb );
- if(mm->m_type == MT_FREE)
- printf("FREED MBUF!\n");
- dump_buf (ecnrq, sizeof (*ecnrq));
- return ENETDOWN;
- }
-
- return
- choose_output(copcb->co_ifp, dtom(ecnrq), copcb->co_flags&CONSF_LOOPBACK);
-}
-
-/*
- * NAME: cons_send_on_vc()
- * CALLED FROM:
- * tp_error_emit()
- * FUNCTION and ARGUMENTS:
- * Take a packet(m0), of length (datalen) from tp and
- * send it on the channel (chan).
- *
- * RETURN VALUE:
- * whatever (E*) is returned form the net layer output routine.
- */
-int
-cons_send_on_vc(chan, m, datalen)
- int chan;
- struct mbuf *m;
- int datalen;
-{
- struct cons_pcb *copcb = (struct cons_pcb *)0;
-
- if(m == MNULL)
- return;
-
- if((copcb =
-#ifdef ARGO_DEBUG
- cons_chan_to_pcb( chan, __LINE__ )
-#else ARGO_DEBUG
- cons_chan_to_pcb( chan )
-#endif ARGO_DEBUG
- ) == (struct cons_pcb *)0 )
- return E_CO_CHAN;
- IFDEBUG(D_CCONS)
- printf("cons_send_on_vc m 0x%x m_len 0x%x\n", m, m->m_len);
- ENDDEBUG
- return cons_senddata( copcb, m);
-}
-
-/*
- * NAME: cons_output()
- * CALLED FROM:
- * tpiso_output(), can have whatever interface we want it to...
- * tpiso_output() decides whether to give a packet to CLNP or to
- * cons; if the latter, it calls this routine.
- * FUNCTION and ARGUMENTS:
- * tp has alloc-ed a pcb - but it may not be open.
- * some classes of tp may allow multiplexing, in which
- * case, you may choose to send the data on ANOTHER cons connection.
- * This decides which net connection to use, opens one if necessary.
- * Then it sends the data.
- */
-
-cons_output(isop, m, len, isdgm)
- struct isopcb *isop;
- struct mbuf *m;
- int len;
- int isdgm;
-{
- struct cons_pcb *copcb = (struct cons_pcb *)0;
- int error;
- int s = splnet();
-
- IFDEBUG(D_CCONS)
- printf("cons_output( isop 0x%x, m 0x%x, len 0x%x, dgm 0x%x )\n",
- isop,m,len, isdgm);
- ENDDEBUG
-
- if( m == MNULL )
- return 0;
- ASSERT(m->m_len > 0);
- if( isdgm ) {
- error = cosns_output1(0, m, &isop->isop_faddr, TP_proto, isop);
- IFDEBUG(D_CDATA)
- if(error)
- printf("cosns_output1 RETURNS ERROR 0x%x\n", error);
- ENDDEBUG
- return error;
- }
-
- if( isop->isop_chanmask || isop->isop_negchanmask) {
- register int mask = isop->isop_chanmask;
- register int chan = 1;
-
- if( mask == 0)
- mask = isop->isop_negchanmask;
-
- for ( chan=1; (mask & 1)==0; chan++,mask>>=1 ) ;
-
- if( isop->isop_chanmask == 0 )
- chan = -chan;
-
- IFDEBUG(D_CCONS)
- printf(
- "cons_output: isop 0x%x cmask 0x%x negmask 0x%x, chan 0x%x\n",
- isop, isop->isop_chanmask, isop->isop_negchanmask, chan);
- ENDDEBUG
- ASSERT( chan != 0);
-#ifdef ARGO_DEBUG
- copcb = cons_chan_to_pcb( chan, __LINE__ );
-#else ARGO_DEBUG
- copcb = cons_chan_to_pcb( chan );
-#endif ARGO_DEBUG
- }
- if( copcb == (struct cons_pcb *)0 ) {
- /* get a new one */
-
- if(( error = cons_pcballoc(&dummysocket, &cons_isopcb, CONSF_OCRE,
- TP_proto, &copcb)) != EOK ) {
- IFDEBUG(D_CCONS)
- printf("cosns_output: no copcb; returns 0x%x\n", error);
- ENDDEBUG
- (void) m_freem (m);
- splx(s);
- return error ;
- }
-
- /* abbreviated form of iso_pcbconnect(): */
- bcopy((caddr_t)&isop->isop_faddr, (caddr_t)&copcb->co_faddr,
- sizeof(struct sockaddr_iso));
-
- if ( error = cons_connect( copcb ) ) { /* if it doesn't work */
- /* oh, dear, throw packet away */
- remque((struct isopcb *)copcb);
- (void) m_free(dtom(copcb));
- (void) m_freem( m );
- splx(s);
- return error;
- }
-
- if( copcb->co_socket ) {
- while( (copcb->co_state != OPEN) &&
- !(error = copcb->co_socket->so_error) ) {
- IFDEBUG(D_CCONS)
- printf(
- "SLEEP1 copcb 0x%x isop 0x%x state 0x%x chan 0x%x mask 0x%x neg 0x%x\n",
- copcb, isop, copcb->co_state, copcb->co_channel,
- ((struct isopcb *)isop)->isop_chanmask,
- ((struct isopcb *)isop)->isop_negchanmask
- );
- ENDDEBUG
- tsleep( (caddr_t)&copcb->co_state, PZERO+1,
- SLP_ISO_CONSOUT, 0);
- IFDEBUG(D_CCONS)
- printf("AFTER SLEEP 1 chan 0x%x chanmask 0x%x negchanmask 0x%x\n",
- copcb->co_channel, isop->isop_chanmask,
- isop->isop_negchanmask);
- ENDDEBUG
- }
- if( !error )
- SET_CHANMASK( isop, copcb->co_channel);
- }
-
- }
-
- IFDEBUG(D_CDATA)
- printf("cons_output calling senddata(0x%x 0x%x)\n", copcb, m);
- ASSERT(m != MNULL);
- ASSERT(m->m_len != 0);
- ENDDEBUG
-
- if( !error )
- error = cons_senddata( copcb, m);
- splx(s);
- return error;
-}
-
-/*
- * NAME: cons_openvc()
- * CALLED FROM:
- * TP when it decides to open a VC for TP 0
- * FUNCTION:
- * opens a connection and stashes the pcb info in the socket
- * substitute for iso_pcbconnect/ in_pcbconnect for the class 0 case
- * only.
- */
-int
-cons_openvc(copcb, faddr, so)
- struct cons_pcb *copcb;
- struct sockaddr_iso *faddr;
- struct socket *so;
-{
- int error = 0;
- int s = splnet();
- struct cons_pcb *cons_chan_to_pcb();
-
-
- ASSERT( copcb->co_socket == so );
- IFTRACE(D_CCONN)
- tptrace(TPPTmisc, "cons_openvc( copcb so )\n", copcb, so, 0, 0);
- ENDTRACE
- IFDEBUG(D_CCONN)
- printf("cons_openvc( copcb 0x%x, so 0x%x )\n", copcb,so);
- ENDDEBUG
- /*
- * initialize the copcb part of the isopcb
- */
- copcb->co_ttl = copcb->co_init_ttl = X25_TTL;
- copcb->co_flags = CONSF_OCRE;
- copcb->co_proto = TP_proto;
- copcb->co_pending.ifq_maxlen = CONS_IFQMAXLEN;
-
- /* abbreviated form of iso_pcbconnect(): */
- bcopy((caddr_t)faddr, (caddr_t)&copcb->co_faddr,
- sizeof(struct sockaddr_iso));
-
- ASSERT( copcb->co_socket == so );
- if( error = cons_connect( copcb ) )
- goto done;
- while( (copcb->co_state != OPEN) && !(error = so->so_error) ) {
- IFDEBUG(D_CCONS)
- printf(
- "SLEEP2 copcb 0x%x state 0x%x chan 0x%x mask 0x%x neg 0x%x\n",
- copcb, copcb->co_state, copcb->co_channel,
- copcb->co_chanmask,
- copcb->co_negchanmask
- );
- ENDDEBUG
- tsleep((caddr_t)&copcb->co_state, PZERO+2, SLP_ISO_CONSCONN, 0);
- IFDEBUG(D_CCONS)
- printf("AFTER SLEEP2 chan 0x%x chanmask 0x%x negchanmask 0x%x\n",
- copcb->co_channel, copcb->co_chanmask,
- copcb->co_negchanmask);
- ENDDEBUG
- }
- if( !error )
- SET_CHANMASK( (struct isopcb *)copcb, copcb->co_channel);
-done:
- ASSERT( copcb->co_socket == so );
- splx(s);
-
- IFDEBUG(D_CCONN)
- printf("cons_openvc: copcb 0x%x error 0x%x\n", copcb, error );
- ENDDEBUG
- return error;
-}
-
-/*
- * NAME: cons_netcmd()
- * CALLED FROM:
- * tp_route_to() when it decides to accept or reject an incoming
- * connection it calls this.
- * FUNCTION:
- * either closes the cons connection named by (channel)
- * or associates the copcb with the channel #.
- * and removes the old copcb from the tp_incoming_pending list.
- */
-int
-cons_netcmd(cmd, isop, channel, isdgm)
- int cmd;
- struct isopcb *isop;
- int channel;
-{
- int s = splnet();
- int error = 0;
- struct cons_pcb *copcb = (struct cons_pcb *)0;
- struct cons_pcb *cons_chan_to_pcb();
-
- IFTRACE(D_CCONN)
- tptrace(TPPTmisc, "cons_netcmd( cmd isopcb channel isdgm)\n",
- cmd,isop,channel, isdgm);
- ENDTRACE
- IFDEBUG(D_CCONN)
- printf("cons_netcmd( cmd 0x%x, isop 0x%x, channel 0x%x, isdgm 0x%x)\n",
- cmd,isop,channel, isdgm);
- if( isop )
- printf("cons_netcmd: isop->socket 0x%x\n",
- isop->isop_socket);
- ENDDEBUG
- ASSERT(cmd != CONN_OPEN);
-
- /* Can we find a cons-level pcb based on channel? */
- if(channel) {
- if((copcb =
-#ifdef ARGO_DEBUG
- cons_chan_to_pcb( channel, __LINE__ )
-#else ARGO_DEBUG
- cons_chan_to_pcb( channel)
-#endif ARGO_DEBUG
- ) == (struct cons_pcb *)0) {
- error = ECONNABORTED;
- splx(s);
- return error;
- }
- if( copcb == (struct cons_pcb *) isop ) {
- copcb = (struct cons_pcb *)0;
- /* avoid operating on a pcb twice */
- } else {
- /* if isop is null (close/refuse):
- * this would remove from the TP list, which is NOT what we want
- * so only remove if there is an isop (gag)
- */
- if( isop ) {
- remque((struct cons_pcb *)copcb); /* take it off pending list */
- } else {
- ASSERT( (cmd == CONN_CLOSE) || (cmd == CONN_REFUSE) );
- }
- }
- }
- /* now we have one of these cases:
- * 1) isop is non-null and copcb is null
- * 2) isop is non-null and copcb is non-null and they are different
- * 3) isop is null and copcb is non-null
- */
- ASSERT( (isop != (struct isopcb *)0) || (copcb != (struct cons_pcb *)0));
-
- switch(cmd) {
-
- case CONN_CONFIRM:
- if( isdgm ) {
- /* we want two separate pcbs */
- /* if we don't have a copcb, get one */
-
- if( copcb == (struct cons_pcb *)0 ) {
- if(( error = cons_pcballoc(&dummysocket, &cons_isopcb,
- ((struct cons_pcb *)isop)->co_flags,
- TP_proto, &copcb)) != EOK )
- return error;
- /* copy missing info from isop */
- copcb->co_laddr = isop->isop_laddr;
- copcb->co_faddr = isop->isop_faddr;
- /* don't care about tsuffices */
- ((struct cons_pcb *)isop)->co_channel = 0;
- /* no longer used */
-
- copcb->co_ifp = ((struct cons_pcb *)isop)->co_ifp ;
- ASSERT( copcb->co_pending.ifq_len == 0 );
-
- } else {
- insque((struct isopcb *)copcb,
- (struct isopcb *)&cons_isopcb);
- }
- copcb->co_state = OPEN;
- copcb->co_flags |= CONSF_DGM;
- copcb->co_channel = channel;
- ASSERT(copcb->co_channel != 0);
-
- IFDEBUG(D_CCONN)
- printf("cons_netcmd: put 0x%x on regular list \n", copcb);
- ENDDEBUG
- } else {
- /* must be TP 0, since this is never called from XTS code */
- /* we want ONE pcb, namely isop.
- * If this TPE were the active side,
- * there ought not to be a copcb, since TP should
- * know that you can't send a CR with dgm and negot down
- * to non-dgm.
- * If this TPE were the passive side, we want to copy from
- * the copcb that was on the pending list, and delete the
- * pending copcb.
- */
- if( copcb ) {
- IFDEBUG(D_CCONN)
- printf("cons_netcmd: copied info from 0x%x to 0x%x\n",
- copcb, isop);
- ENDDEBUG
- isop->isop_laddr = copcb->co_laddr;
- isop->isop_faddr = copcb->co_faddr;
- /* tsuffices, socket should be there already */
- ((struct cons_pcb *)isop)->co_flags =
- copcb->co_flags & ~CONSF_DGM;
- ((struct cons_pcb *)isop)->co_init_ttl = copcb->co_init_ttl;
- touch(((struct cons_pcb *)isop));
- ((struct cons_pcb *)isop)->co_channel = channel;
- ((struct cons_pcb *)isop)->co_ifp = copcb->co_ifp;
- ((struct cons_pcb *)isop)->co_proto = copcb->co_proto;
- ((struct cons_pcb *)isop)->co_myself =
- (struct cons_pcb *)isop;
- SET_CHANMASK( isop, ((struct cons_pcb *)isop)->co_channel );
- ASSERT( copcb->co_pending.ifq_len == 0 );
-
- /* get rid of the copcb that was on the pending list */
- (void) m_free(dtom(copcb));
- }
- ((struct cons_pcb *)isop)->co_state = OPEN;
- }
- break;
-
- case CONN_CLOSE:
- case CONN_REFUSE:
- /* if dgm then ignore; the connections will
- * be re-used or will time out
- */
- if( isdgm )
- break;
-
- /* we should never come in here with both isop and copcb
- * unless is dgm, hence the following assertion:
- */
- ASSERT( (copcb == (struct cons_pcb *)0) ||
- (isop == (struct isopcb *)0) );
-
- /* close whichever pcb we have */
- if( copcb )
- error = cons_clear(copcb, (cmd == CONN_CLOSE)?
- E_CO_HLI_DISCN:E_CO_HLI_REJT);
- if( isop )
- error = cons_clear((struct cons_pcb *)isop, (cmd == CONN_CLOSE)?
- E_CO_HLI_DISCN:E_CO_HLI_REJT);
-
- if(copcb && (copcb->co_socket == (struct socket *)0) ) {
- ASSERT( copcb->co_flags & (CONSF_DGM | CONSF_ICRE) );
- (void) m_free(dtom(copcb)); /* detached */
- }
- /* isop will always be detached by the higher layer */
- break;
- default:
- error = EOPNOTSUPP;
- break;
- }
- splx(s);
-
- IFDEBUG(D_CCONN)
- printf("cons_netcmd returns 0x%x: isop 0x%x\n", isop, error );
- ENDDEBUG
- return error;
-}
-
-
-/*
- * NAME: addr_proto_consistency_check()
- * CALLED FROM: cons_incoming()
- * FUNCTION and ARGUMENTS:
- * Enforces a set of rules regarding what addresses will serve
- * what protocol stack. This is a kludge forced upon us by the
- * fact that there's no way to tell which NET layer you want to
- * run when opening a socket. Besides, no doubt, OSI directory
- * services won't advertise any kind of a protocol stack with the
- * NSAPs. sigh.
- * RETURNS
- * EAFNOSUPPORT or EOK.
- */
-Static int
-addr_proto_consistency_check(proto, addr)
- int proto;
- struct sockaddr_iso *addr;
-{
- switch( proto ) {
- case ISOPROTO_CLNP:
- break;
-
- case ISOPROTO_INACT_NL:
- case ISOPROTO_CLTP:
- return E_CO_HLI_PROTOID;
-
- case ISOPROTO_TP:
- case ISOPROTO_X25:
- /* hl is TP or X.25 */
- if (addr->siso_addr.isoa_afi != AFI_37)
- return E_CO_AIWP;
- /* kludge - necessary because this is the only type of
- * NSAP we build for an incoming NC
- */
- break;
- default: /* unsupported */
- return E_CO_HLI_PROTOID;
- }
- return EOK;
-}
-/*
- * NAME: cons_incoming()
- * CALLED FROM:
- * consintr() for incoming OPEN
- * FUNCTION and ARGUMENTS:
- * Determines which higher layer gets this call, and
- * thus whether to immediately accept, reject, or to let the
- * higher layer determine this question.
- */
-Static
-cons_incoming(ifp, ecnrq)
- struct ifnet *ifp;
- register struct eicon_request *ecnrq;
-{
- struct sockaddr_iso me;
- struct sockaddr_iso peer;
- struct cons_pcb *copcb;
- int loop = 0;
- int proto =0;
- int error = 0;
- struct dte_addr peer_dte;
-
- IFDEBUG(D_INCOMING)
- printf("consincoming enter: ifp 0x%x ecnrq 0x%x\n", ifp, ecnrq);
- ENDDEBUG
- bzero( &me, sizeof(me));
- error = parse_facil( mtod(e_data(ecnrq), caddr_t),
- (e_data(ecnrq))->m_len, &me, &peer, &proto,
- &peer_dte);
- loop = is_me( &peer ); /* <-- THIS may be a problem :
- * peer may be nonsense.
- * We can only expect that WE will do it right
- * and never will we get an error return from
- * parse_facil on a facil that WE generated,
- * so if garbage comes in, peer will be garbage,
- * and loop will be false.
- */
- if( error != EOK ) {
- (void) issue_clear_req(ecnrq->e_vc, error, ifp, loop);
- IncStat(co_parse_facil_err);
- IncStat(co_Rdrops);
- return;
- }
-
- if( (error = addr_proto_consistency_check(proto, &me)) != EOK ) {
- /* problem with consistency */
- (void) issue_clear_req(ecnrq->e_vc, error, ifp, loop);
- IncStat(co_addr_proto_consist_err);
- IncStat(co_Rdrops);
- return;
- } else {
- switch( proto ) {
- case ISOPROTO_X25:
- copcb = (struct cons_pcb *)
- ((struct cons_pcb *)(&cons_isopcb))->co_next;
-
- while (copcb != (struct cons_pcb *)&cons_isopcb) {
- if( copcb->co_lport == me.siso_tsuffix ) {
- /* for cons "transport service",
- * multiplexing is not allowed
- */
- if( !copcb->co_socket ) {
- printf(
- "PANIC cons_incoming NOT TP but no sock\n");
- copcb = (struct cons_pcb *)0;
- break;
- }
- if( copcb->co_socket->so_options & SO_ACCEPTCONN ) {
- struct cons_pcb *newx;
-
- newx = (struct cons_pcb *)
- sonewconn(copcb->co_socket)->so_pcb;
- newx->co_laddr = copcb->co_laddr;
- newx->co_peer_dte = peer_dte;
- newx->co_proto = copcb->co_proto;
- newx->co_myself = newx;
- touch(copcb);
- copcb = newx;
- soisconnected(copcb->co_socket);
- break;
- } /* else keep looking */
- }
- copcb = (struct cons_pcb *)copcb->co_next;
- }
- if (copcb == (struct cons_pcb *)&cons_isopcb)
- copcb = (struct cons_pcb *) 0;
- break;
-
- case ISOPROTO_TP:
- ASSERT( me.siso_tsuffix == 0 );
- /*
- * We treat this rather like we do for CLNP.
- * TP can't tell which socket
- * wants this until the TP header comes in, so there's no way
- * to associate this channel with a tpcb/isopcb.
- * We assume data will arrive (a CR TPDU) and be given to TP along with
- * the channel number. We can then expect TP to call us with
- * the channel number and pcb ptr, telling us to keep this connection
- * or clear it.
- * Now, tp will have created an isopcb in the tp_isopcb list.
- * We will have to keep another copcb though, because there is no
- * 1-1 correspondence between socket and copcb when multiplexing
- * is allowed.
- * But we want to save the peer address, ifp, and state, proto.
- * If the channel should clear before TP responds, we need
- * to know that also, so we create a tp-pending list...
- */
- if( cons_pcballoc(&dummysocket, &tp_incoming_pending,
- CONSF_ICRE, TP_proto, &copcb) != EOK ) {
- copcb = (struct cons_pcb *)0;
- } else {
- copcb->co_peer_dte = peer_dte;
- }
- break;
-
-
- case ISOPROTO_CLNP:
- if( cons_pcballoc(&dummysocket, &cons_isopcb,
- CONSF_ICRE | CONSF_DGM, CLNP_proto, &copcb ) != EOK ) {
- /* choke */
- copcb = (struct cons_pcb *)0;
- } else {
- copcb->co_peer_dte = peer_dte;
- }
- break;
-
- default:
- panic("cons_incoming");
- } /* end switch */
-
- if(copcb) {
- touch(copcb);
- copcb->co_channel = (int)ecnrq->e_vc;
- ASSERT( copcb->co_channel != 0);
- copcb->co_state = OPEN;
- copcb->co_ifp = ifp;
- copcb->co_laddr = me;
- copcb->co_faddr = peer;
- if(loop)
- copcb->co_flags |= CONSF_LOOPBACK;
- IFDEBUG(D_CADDR)
- printf("cons_incoming found XPCB 0x%x, loop 0x%x\n",
- copcb, loop);
- printf("\nco_laddr: ");
- dump_buf(&copcb->co_laddr, sizeof(copcb->co_laddr));
- printf("\nco_faddr: ");
- dump_buf(&copcb->co_faddr, sizeof(copcb->co_faddr));
- printf("\n");
- ENDDEBUG
- } else {
- ifp->if_ierrors ++;
- (void) issue_clear_req(ecnrq->e_vc, E_CO_OSI_UNSAP, ifp, loop);
- IncStat(co_no_copcb);
- IncStat(co_Rdrops);
- }
- }
- /* caller frees the mbuf so we don't have to do any such thing */
-}
-
-/*
- **************************** DEVICE cons ***************************
- */
-
-/*
- * NAME: cosns_output()
- * CALLED FROM:
- * clnp - this routine is given as the device-output routine
- * for the adcom driver.
- * FUNCTION and ARGUMENTS:
- * (ifp) is the cons/adcom, found by routing function.
- * (m0) is the clnp datagram.
- * (dst) is the destination address
- * This routine finds an x.25 connection for datagram use and
- * sends the packet.
- */
-int
-cosns_output(ifp, m0, dst)
-{
- return cosns_output1(ifp, m0, dst, CLNP_proto, NULL);
-}
-
-/* DEBUGGING ONLY? */
-int total_cosns_len = 0;
-int total_cosns_cnt = 0;
-int total_pkts_to_clnp = 0;
-
-/*
- * The isop is passed here so that if we have set x25crud in the
- * pcb, it can be passed down to cons_connect. It could be null
- * however, in the case of tp4/x25/clnp
- */
-Static int
-cosns_output1(ifp, m0, dst, proto, isop)
- struct ifnet *ifp;
- register struct mbuf *m0;
- struct sockaddr_iso *dst;
- struct protosw *proto;
- struct isopcb *isop; /* NULL if coming from clnp */
-{
- register struct cons_pcb *copcb;
- int s = splnet();
- int error = 0;
-
- { register struct mbuf *n=m0;
- register int len = 0;
-
- for(;;) {
- len += n->m_len;
- if (n->m_next == MNULL ) {
- break;
- }
- n = n->m_next;
- }
- total_cosns_len += len;
- total_cosns_cnt ++;
-
- }
-
- IFDEBUG(D_CCONS)
- printf("cosns_output1( ifp 0x%x, m 0x%x, dst 0x%x )\n", ifp, m0, dst );
- ENDDEBUG
- if ( ! (copcb = cons_find( CONSF_DGM, dst, proto, 0, 0) )) {
- struct cons_pcb *newcopcb; /* so we can pass addr of this to pcballoc */
-
- if( (error = cons_pcballoc(&dummysocket, &cons_isopcb,
- CONSF_DGM | CONSF_OCRE, proto, &newcopcb) ) != EOK ) {
- IFDEBUG(D_CCONS)
- printf("cosns_output: no copcb; returns \n");
- ENDDEBUG
- (void) m_freem(m0);
- goto done;
- }
- copcb = newcopcb;
-
- /* abbreviated form of iso_pcbconnect(): */
- bcopy((caddr_t)dst, (caddr_t)&copcb->co_faddr,
- sizeof(struct sockaddr_iso));
-
- /* copy x25crud into copcb if necessary */
- if ((isop != NULL) && (isop->isop_x25crud_len > 0)) {
- bcopy(isop->isop_x25crud, copcb->co_x25crud,
- isop->isop_x25crud_len);
- copcb->co_x25crud_len = isop->isop_x25crud_len;
- }
-
- copcb->co_ifp = ifp; /* NULL IF COMING FROM TP4! */
-
- if ( error = cons_connect( copcb ) ) { /* if it doesn't work */
- /* oh, dear, throw packet away */
- remque((struct isopcb *)copcb);
- (void) m_free(dtom(copcb));
- (void) m_freem(m0);
- goto done;
- }
- }
- IFDEBUG(D_CDATA)
- printf("cosns_output1 @ senddata: state 0x%x flags 0x%x channel 0x%x\n",
- copcb->co_state, copcb->co_flags, copcb->co_channel);
- ENDDEBUG
- ASSERT(copcb->co_channel != X_NOCHANNEL);
- error = cons_senddata(copcb, m0);
-done:
- splx(s);
- return error;
-}
-
-
-/*
- **************************** TRANSPORT cons ***************************
- */
-
-
-/*
- * NAME: cons_detach()
- * CALLED FROM:
- * cons_usrreq() on PRU_DETACH
- * cons_netcmd() when TP releases a net connection
- * cons_slowtimo() when timeout releases a net connection
- * FUNCTION and ARGUMENT:
- * removes the copcb from the list of copcbs in use, and frees the mbufs.
- * detaches the pcb from the socket, where a socket exists.
- * RETURN VALUE:
- * ENOTCONN if it couldn't find the copcb in the list of connections.
- */
-
-Static int
-cons_detach( copcb )
- register struct cons_pcb *copcb;
-{
- struct socket *so = copcb->co_socket;
-
- IFDEBUG(D_CCONN)
- printf("cons_detach( copcb 0x%x )\n", copcb);
- ENDDEBUG
- if(so) {
- if (so->so_head) {
- if (!soqremque(so, 0) && !soqremque(so, 1))
- panic("sofree dq");
- so->so_head = 0;
- }
- ((struct isopcb *)copcb)->isop_options = 0; /* kludge */
- iso_pcbdetach(copcb); /* detaches from so */
- } else {
- remque((struct isopcb *)copcb);
- (void) m_free(dtom(copcb));
- }
-}
-
-Static int
-cons_clear_and_detach(copcb, clearreason, ctlcmd)
- register struct cons_pcb *copcb;
- int clearreason;
- int ctlcmd;
-{
- IFDEBUG(D_CCONN)
- printf("Clear and Detach (0x%x, 0x%x, 0x%x)\n",
- copcb, clearreason, ctlcmd);
- ENDDEBUG
- if( clearreason != DONTCLEAR ) {
- (void) cons_clear( copcb , clearreason );
- }
- if( copcb->co_proto && copcb->co_proto->pr_ctlinput )
- (*copcb->co_proto->pr_ctlinput)(ctlcmd,
- (struct sockaddr_iso *)&copcb->co_faddr, (caddr_t)copcb);
-
- if( copcb->co_socket == (struct socket *)0 ) {
- /* tp4, clnp users only */
- (void) cons_detach( copcb );
- } /* else detach will be called by the socket's closing */
- else {
- ASSERT( copcb->co_socket != &dummysocket );
- ASSERT( (copcb->co_flags & CONSF_DGM) == 0 );
- }
- IFDEBUG(D_CCONN)
- printf("END OF Clear and Detach (0x%x, 0x%x, 0x%x)\n",
- copcb, clearreason, ctlcmd);
- ENDDEBUG
-}
-
-Static int
-cons_pcbbind( copcb, nam )
- register struct cons_pcb *copcb;
- struct mbuf *nam;
-{
- int error;
-
- if( error = iso_pcbbind( copcb, nam) )
- return error;
-
- /* iso_pcbbind already ensured that if port < 1024 it's superuser */
- /* Now we check: must be in range 0 .. 23 or in range 1024 .. 99 */
-
- if( (copcb->co_lport < X25_PORT_RESERVED) ||
- ((copcb->co_lport >= ISO_PORT_RESERVED) &&
- (copcb->co_lport <= X25_PORT_USERMAX))) {
- munge( copcb->co_lport, (&copcb->co_laddr)->siso_addr.t37_idi +
- ADDR37_IDI_LEN, 1 /* nibble */);
- munge( copcb->co_fport, (&copcb->co_faddr)->siso_addr.t37_idi +
- ADDR37_IDI_LEN, 1 /* nibble */);
- return 0;
- } else
- return EADDRNOTAVAIL;
-}
-/*
- * NAME: cons_usrreq()
- * CALLED FROM:
- * user level via proto switch
- * FUNCTION and ARGUMENTS:
- * so : socket
- * req: which PRU* request
- * m : data or mbuf ptr into which to stash data
- * nam: mbuf ptr which is really a sockaddr_iso
- * ifq: in PRU_CONTROL case, an ifnet structure
- * RETURN VALUE:
- * ENOTCONN if trying to do something which requires a connection
- * and it's not yet connected
- * EISCONN if trying to do something which cannot be done to a connection
- * but it's connected
- * ENOBUFS if ran out of mbufs
- * EWOULDBLOCK if in nonblocking mode & can't send right away
- * EOPNOSUPP if req isn't supported
- * E* other passed up from lower layers or from other routines
- */
-
-cons_usrreq(so, req, m, nam, ifp)
- struct socket *so;
- u_int req;
- struct mbuf *m, *nam;
- int *ifp;
-{
- struct cons_pcb *copcb = (struct cons_pcb *)so->so_pcb;
- int s = splnet();
- int error = 0;
-
- IFDEBUG(D_CCONS)
- printf("cons_usrreq 0x%x so 0x%x copcb 0x%x\n", req, so, copcb);
- ENDDEBUG
- if (req == PRU_CONTROL) {
- error = iso_control(so, (int)m, (caddr_t)nam, (struct ifnet *)ifp);
- splx(s);
- return error;
- }
- if (copcb == (struct cons_pcb *)0 && req != PRU_ATTACH) {
- splx(s);
- return ENOTCONN;
- }
-
- switch (req) {
-
- case PRU_ATTACH:
- if (copcb) {
- error = EISCONN;
- break;
- }
- soreserve(so, X25_SBSIZE, X25_SBSIZE); /* CONS size */
- error = cons_pcballoc(so, &cons_isopcb, CONSF_XTS, X25_proto, &copcb );
- break;
-
- case PRU_ABORT: /* called from close() */
- /* called for each incoming connect queued on the parent (accepting)
- * socket (SO_ACCEPTCONN);
- */
- error = cons_detach ( copcb );
- break;
-
- case PRU_DETACH: /* called from close() */
- /* called after disconnect was called iff was connected at the time
- * of the close, or directly if socket never got connected */
- error = cons_detach ( copcb );
- break;
-
- case PRU_SHUTDOWN:
- /* recv end may have been released; local credit might be zero */
- case PRU_DISCONNECT:
- soisdisconnected(so);
- error = cons_clear(copcb, E_CO_HLI_DISCN);
- break;
-
- case PRU_BIND:
- error = cons_pcbbind( copcb, nam);
- break;
-
- case PRU_LISTEN:
- if (copcb->co_lport == 0)
- error = cons_pcbbind( copcb, 0 );
- break;
-
-
- case PRU_SOCKADDR: {
- struct sockaddr_iso *siso = mtod(nam, struct sockaddr_iso *);
-
- nam->m_len = sizeof (struct sockaddr_iso);
- if(copcb->co_ifp)
- bcopy( (caddr_t)&copcb->co_laddr,
- (caddr_t)siso, sizeof(struct sockaddr_iso) );
-
- ((struct sockaddr_iso *)siso)->siso_tsuffix = copcb->co_lport;
- }
- break;
-
- case PRU_PEERADDR:
- if( (so->so_state & SS_ISCONNECTED) &&
- (so->so_state & SS_ISDISCONNECTING) == 0) {
- struct sockaddr_iso *siso = mtod(nam, struct sockaddr_iso *);
-
- nam->m_len = sizeof (struct sockaddr_iso);
- bcopy( (caddr_t)&copcb->co_faddr, (caddr_t)siso,
- sizeof(struct sockaddr_iso) );
- } else
- error = ENOTCONN;
- break;
-
- case PRU_CONNECT:
- /* TODO: We need to bind to the RIGHT interface.
- * The only way to have the right interface is to have
- * the right route.
- */
- IFDEBUG(D_CCONN)
- printf("PRU_CONNECT 1: local tsuffix 0x%x so->so_head 0x%x nam:\n",
- copcb->co_lport, so->so_head);
- dump_isoaddr( mtod(nam, struct sockaddr_iso *) );
- ENDDEBUG
- if (copcb->co_lport == 0) {
- if( error = cons_pcbbind( copcb, 0 ))
- break;
- }
- IFDEBUG(D_CCONN)
- printf("PRU_CONNECT 2: local tsuffix 0x%x so->so_head 0x%x nam:\n",
- copcb->co_lport, so->so_head);
- dump_isoaddr( mtod(nam, struct sockaddr_iso *) );
- ENDDEBUG
-
- { /* change the destination address so the last 2 digits
- * are the port/suffix/selector (whatever you want to call it)
- */
- register struct sockaddr_iso *siso =
- mtod(nam, struct sockaddr_iso *);
- if( (siso->siso_tsuffix < X25_PORT_RESERVED) ||
- ((siso->siso_tsuffix >= ISO_PORT_RESERVED) &&
- (siso->siso_tsuffix <= X25_PORT_USERMAX)))
- munge( siso->siso_tsuffix,
- siso->siso_addr.t37_idi + ADDR37_IDI_LEN,
- 1 /* nibble */);
- }
-
- soisconnecting(so);
- if (error = iso_pcbconnect(copcb, nam))
- break;
- error = cons_connect( copcb );
- if ( error ) {
- /*
- remque((struct isopcb *)copcb);
- (void) m_free(dtom(copcb));
- */
- break;
- }
- while( (copcb->co_state != OPEN)&&(copcb->co_socket->so_error == 0) ) {
- IFDEBUG(D_CCONN)
- printf("PRU_CONNECT: error 0x%x sleeping on 0x%x\n",
- copcb->co_socket->so_error,
- (caddr_t)&copcb->co_state );
- ENDDEBUG
- sleep((caddr_t)&copcb->co_state, PZERO+3, SLP_ISO_CONS, 0 );
- }
-
- ASSERT( copcb->co_channel != 0);
-
- SET_CHANMASK ( (struct isopcb *)copcb, copcb->co_channel);
- break;
-
- case PRU_ACCEPT:
- /* so here is the NEW socket */
- so->so_error = 0;
- if ((so->so_state & SS_NBIO) && (so->so_state & SS_ISCONNECTED)== 0) {
- error = EWOULDBLOCK;
- break;
- }
- {
- struct sockaddr_iso *siso = mtod(nam, struct sockaddr_iso *);
-
- /* copy the peer's address into the return argument */
- nam->m_len = sizeof (struct sockaddr_iso);
- bcopy( (caddr_t)&copcb->co_faddr, (caddr_t)siso,
- sizeof(struct sockaddr_iso));
- }
- break;
-
- case PRU_SEND:
- case PRU_SENDEOT:
- /*
- * sosend calls this until sbspace goes negative.
- * Sbspace may be made negative by appending this mbuf chain,
- * possibly by a whole cluster.
- */
- {
- /* no need to actually queue this stuff and dequeue it,
- * just bump the pointers in so_snd so that higher
- * layer of socket code will cause it to sleep when
- * we've run out of socket space
- * TODO:
- * Unfortunately that makes sbflush vomit so we have
- * to allocate a single real mbuf (say size 240)
- * and sballoc it and sbfree it upon CONS_SEND_DONE.
- * Oh, my, is this sickening or what?
- */
- {
- struct mbuf *mx;
-
- MGET(mx, M_DONTWAIT, MT_DATA);
- mx->m_len = MLEN;
- sbappend((caddr_t)&copcb->co_socket->so_snd, mx);
- }
- if( m ) {
- IFDEBUG(D_CDATA)
- printf("X.25 Usrreq calling cons_senddata(0x%x, 0x%x)\n",
- copcb, m);
- ENDDEBUG
- error = cons_senddata(copcb, m);
- }
- IFDEBUG(D_CCONS)
- printf("PRU_SEND sent tsuffix 0x%x, m 0x%x error 0x%x\n",
- copcb->co_lport, m, error);
- ENDDEBUG
-
- if( req == PRU_SENDEOT ) {
- while(copcb->co_socket->so_snd.sb_cc > 0)
- sbwait(&copcb->co_socket->so_snd);
- }
- }
- break;
-
- case PRU_CONTROL:
- error = cons_ioctl(so, m, (caddr_t)nam);
- break;
-
-
- case PRU_RCVD:
- case PRU_RCVOOB:
- case PRU_SENDOOB:
- /* COULD support INTERRUPT packets as oob */
- case PRU_PROTOSEND:
- case PRU_PROTORCV:
- case PRU_SENSE:
- case PRU_SLOWTIMO:
- case PRU_CONNECT2:
- case PRU_FASTTIMO:
- default:
- error = EOPNOTSUPP;
- }
-
- IFDEBUG(D_CCONS)
- printf("cons_usrreq cmd 0x%x copcb 0x%x returned error 0x%x\n",
- req, copcb, error);
- ENDDEBUG
- splx(s);
- return error;
-}
-
-/*
- * NAME: cons_input()
- * CALLED FROM:
- * consintr() through the isosw protosw for "transport" version of X25
- * FUNCTION & ARGUMENTS:
- * process incoming data
- */
-cons_input(m, faddr, laddr, so)
- register struct mbuf *m;
- struct sockaddr_iso *faddr, *laddr; /* not used */
- register struct socket *so;
-{
- IFDEBUG(D_CCONS)
- printf("cons_input( m 0x%x, so 0x%x)\n", m,so);
- ENDDEBUG
- sbappend(&so->so_rcv, m);
- sbwakeup(&so->so_rcv);
-}
-
-#ifdef notdef
-/*
- * NAME: cons_ctloutput()
- * CALLED FROM:
- * set/get sockopts()
- * Presently the protosw has 0 in the ctloutput spot
- * because we haven't inplemented anything yet.
- * If there's reason to put some options in here,
- * be sure to stick this routine name in the protosw in iso_proto.c
- */
-cons_ctloutput(cmd, so, level, optname, mp)
- int cmd, level, optname;
- struct socket *so;
- struct mbuf **mp;
-{
- int s = splnet();
-
- splx(s);
- return EOPNOTSUPP;
-}
-#endif notdef
-
-
-/*
- * NAME: cons_ctlinput()
- * CALLED FROM:
- * lower layer when ECN_CLEAR occurs : this routine is here
- * for consistency - cons subnet service calls its higher layer
- * through the protosw entry.
- * FUNCTION & ARGUMENTS:
- * cmd is a PRC_* command, list found in ../sys/protosw.h
- * copcb is the obvious.
- * This serves the higher-layer cons service.
- * NOTE: this takes 3rd arg. because cons uses it to inform itself
- * of things (timeouts, etc) but has a pcb instead of an address.
- */
-cons_ctlinput(cmd, sa, copcb)
- int cmd;
- struct sockaddr *sa;
- register struct cons_pcb *copcb;
-{
- int error = 0;
- int s = splnet();
- extern u_char inetctlerrmap[];
- extern int iso_rtchange();
-
- IFDEBUG(D_CCONS)
- printf("cons_ctlinput( cmd 0x%x, copcb 0x%x)\n", cmd, copcb);
- ENDDEBUG
- /* co_socket had better exist */
- switch (cmd) {
- case PRC_CONS_SEND_DONE:
- ASSERT( copcb->co_socket );
- ASSERT( copcb->co_flags & CONSF_XTS );
- sbdrop((caddr_t)&copcb->co_socket->so_snd, MLEN);
- sbwakeup((caddr_t)&copcb->co_socket->so_snd);
- break;
-
- case PRC_ROUTEDEAD:
- error = ENETUNREACH;
- break;
-
- case PRC_TIMXCEED_REASS:
- error = ETIMEDOUT;
- break;
-
- /*
- case PRC_QUENCH:
- iso_pcbnotify(&cons_pcb, sa,
- (int)inetctlerrmap[cmd], iso_rtchange);
- iso_pcbnotify(&tp_incoming_pending, sa,
- (int)inetctlerrmap[cmd], tpiso_quench);
- iso_pcbnotify(&tp_isopcb, sa,
- (int)inetctlerrmap[cmd], tpiso_quench);
- */
-
- case PRC_IFDOWN:
- iso_pcbnotify(&cons_isopcb, sa,
- (int)inetctlerrmap[cmd], iso_rtchange);
- iso_pcbnotify(&tp_incoming_pending, sa,
- (int)inetctlerrmap[cmd], iso_rtchange);
- iso_pcbnotify(&tp_isopcb, sa,
- (int)inetctlerrmap[cmd], iso_rtchange);
- break;
-
-
- default:
- printf("cons_ctlinput: unknown cmd 0x%x\n", cmd);
- }
- if(error) {
- soisdisconnected(copcb->co_socket);
- sohasoutofband(copcb->co_socket);
- }
- splx(s);
-}
-
-/*
- *********************** SERVES ALL cons embodiments *******************
- */
-
-/*
- * NAME: cons_chan_to_pcb()
- * CALLED FROM:
- * cons_chan_to_tpcb() in tp_cons.c
- * and in this file: incoming requests that give only a channel number, i.e.,
- * ECN_ACCEPT, ECN_RECEIVE, ECN_CLEAR
- * FUNCTION:
- * identify the pcb assoc with that channel
- * RETURN:
- * ptr to the pcb
- */
-struct cons_pcb *
-#ifdef ARGO_DEBUG
-cons_chan_to_pcb( channel, linenumber )
- int linenumber;
-#else ARGO_DEBUG
-cons_chan_to_pcb( channel)
-#endif ARGO_DEBUG
- register int channel;
-{
- register struct cons_pcb **copcblist = (struct cons_pcb **)Xpcblist;
- register struct cons_pcb *copcb;
-
- /* just to be sure */
- channel = channel & 0xff;
-
- for( copcb = *copcblist; copcb; copcb = *(++copcblist) ) {
- copcb = (struct cons_pcb *)copcb->co_next;
- while (copcb != *copcblist) {
- if ( copcb->co_channel == channel )
- goto found; /* want to break out of both loops */
-
- copcb = (struct cons_pcb *)copcb->co_next;
- }
- }
-found: /* or maybe not... */
- IFDEBUG(D_CCONS)
- printf("cons_chan_to_pcb( 0x%x, %d ) %s 0x%x\n", channel, linenumber,
- copcb?"FOUND":"FAILED", copcb);
- ENDDEBUG
-
- return copcb;
-}
-
-
-/*
- * NAME: is_me()
- * CALLED FROM:
- * cons_incoming(). Perhaps could just expand in line.
- * FUNCTION and ARGUMENTS:
- * for the given remote address (remadr) if it exactly matches
- * one of the addresses of ME, and I am up as loopback,
- * return TRUE, else return FALSE.
- * RETURNS:
- * Boolean
- */
-Static int
-is_me(remaddr)
- struct sockaddr_iso *remaddr;
-{
- struct ifnet *ifp = consif;
- /* PHASE2: this is ok */
- struct ifaddr *ifa = ifa_ifwithaddr(remaddr);
-
- IFDEBUG(D_CADDR)
- printf("is_me: withaddr returns %s\n",
- ifa?ifa->ifa_ifp->if_name:"NONE");
- ENDDEBUG
- if( ifa ) {
- /* remaddr matches one of my interfaces exactly */
- if( ifa->ifa_ifp->if_flags & IFF_LOOPBACK ) {
- ASSERT( ifp == ifa->ifa_ifp );
- return 1;
- }
- }
- return 0;
-}
-
-find_error_reason( ecnrq )
- register struct eicon_request *ecnrq;
-{
- extern u_char x25_error_stats[];
- int error;
- struct mbuf *cdm;
- struct e_clear_data *ecd;
-
- cdm = e_data(ecnrq);
- if( cdm && cdm->m_len > 0 ) {
- ecd = mtod(cdm, struct e_clear_data *);
- switch( ecd->ecd_cause ) {
- case 0x00:
- case 0x80:
- /* DTE originated; look at the diagnostic */
- error = (CONL_ERROR_MASK | ecd->ecd_diagnostic);
- goto done;
-
- case 0x01: /* number busy */
- case 0x81:
- case 0x09: /* Out of order */
- case 0x89:
- case 0x11: /* Remot Procedure Error */
- case 0x91:
- case 0x19: /* reverse charging accept not subscribed */
- case 0x99:
- case 0x21: /* Incampat destination */
- case 0xa1:
- case 0x29: /* fast select accept not subscribed */
- case 0xa9:
- case 0x39: /* ship absent */
- case 0xb9:
- case 0x03: /* invalid facil request */
- case 0x83:
- case 0x0b: /* access barred */
- case 0x8b:
- case 0x13: /* local procedure error */
- case 0x93:
- case 0x05: /* network congestion */
- case 0x85:
- case 0x8d: /* not obtainable */
- case 0x0d:
- case 0x95: /* RPOA out of order */
- case 0x15:
- /* take out bit 8
- * so we don't have to have so many perror entries
- */
- error = (CONL_ERROR_MASK | 0x100 | (ecd->ecd_cause & ~0x80));
- goto done;
-
- case 0xc1: /* gateway-detected proc error */
- case 0xc3: /* gateway congestion */
-
- error = (CONL_ERROR_MASK | 0x100 | ecd->ecd_cause);
- goto done;
- }
- }
- /* otherwise, a *hopefully* valid perror exists in the e_reason field */
- error = ecnrq->e_reason;
- if (error = 0) {
- printf("Incoming PKT TYPE 0x%x with reason 0x%x\n",
- ecnrq->e_cmd,
- ecnrq->e_reason);
- error = E_CO_HLI_DISCA;
- }
-
-done:
- if(error & 0x1ff == 0) {
- error = 0;
- } else if( error & 0x1ff > sizeof(x25_error_stats)) {
- ASSERT(0);
- } else {
- x25_error_stats[error& 0x1ff] ++;
- }
- return error;
-}
-
-/*
- * NAME: consintr()
- * CALLED FROM:
- * the eicon driver via software interrupt
- * FUNCTION and ARGUMENTS:
- * processes incoming indications, passing them
- * along to clnp, tp, or x.25-transport as appropriate.
- */
-consintr()
-{
- struct ifnet *ifp = consif;
- register struct eicon_request *ecnrq;
- register struct cons_pcb *copcb = (struct cons_pcb *)0;
- register struct mbuf *m;
- int s, s0 = splnet();
-
- IncStat(co_intr);
- ifp->if_ipackets ++;
-
- for(;;) {
- /*
- * Get next request off input queue
- */
- s = splimp();
- IF_DEQUEUE(&consintrq, m);
- splx(s);
- IFDEBUG(D_INCOMING)
- printf("cons intr() 0x%x m_off 0x%x m_len 0x%x dequeued\n",
- m, m?m->m_off:0, m?m->m_len:0);
- ENDDEBUG
-
- if (m == 0) {
- splx(s0);
- return;
- }
-
- if((m->m_off != MMINOFF)||(m->m_len != sizeof (struct eicon_request))){
- ifp->if_ierrors ++;
- IncStat(co_Rdrops);
- printf("Cons R DROP! BAD MBUF FROM LL 0x%x sizeof(...) 0x%x\n",
- m, sizeof(struct eicon_request));
- continue;
- }
-
- ecnrq = mtod(m, struct eicon_request *);
-
-
- IFDEBUG(D_INCOMING)
- printf("INTR: e_cmd 0x%x, e_data 0x%x\n", ecnrq->e_cmd,
- e_data(ecnrq));
- if( e_data(ecnrq) != 0 ) {
- /* let's just look at the first few bytes */
- /*
- dump_buf( e_data(ecnrq), (e_data(ecnrq))->m_len + 12);
- */
- dump_buf( e_data(ecnrq), 20 + 12);
- }
- ENDDEBUG
- IFTRACE(D_CDATA)
- tptrace( TPPTmisc, "INTR: req_type m lun\n",
- ecnrq->e_cmd, m, ecnrq->e_vc, 0);
- ENDTRACE
-
- switch( ecnrq->e_cmd ) {
-
- case ECN_ACK: /* data put on the board */
- IncStat(co_ack);
- ASSERT( ecnrq->e_vc != 0);
- /* from ACKWAIT to OPEN */
- if ( (copcb =
-#ifdef ARGO_DEBUG
- cons_chan_to_pcb( (int)ecnrq->e_vc, __LINE__ )
-#else ARGO_DEBUG
- cons_chan_to_pcb( (int)ecnrq->e_vc )
-#endif ARGO_DEBUG
- ) == (struct cons_pcb *)0 )
- break;
- copcb->co_state = OPEN;
- /*
- * Anything on the pending queue for this connection?
- */
- if( copcb->co_pending.ifq_len == 0 ) {
- if( copcb->co_proto->pr_ctlinput )
- /* for the sake of higher layer protocol (tp) */
- (*copcb->co_proto->pr_ctlinput)
- (PRC_CONS_SEND_DONE,
- (struct sockaddr_iso *)&copcb->co_faddr,
- (caddr_t)copcb);
- } else {
- register struct mbuf *m0;
-
- s = splimp();
- IF_DEQUEUE( &copcb->co_pending, m0 );
- splx(s);
- /* CAN ONLY DO 1 item here
- * if you change this if to while, HA HA
- * it'll go right back onto
- * the pending queue (which means things will
- * be reordered on the queue!)
- */
- if( m0 ) {
- IFDEBUG(D_CDATA)
- printf("ACK sending pending queue 0x%x len 0x%x\n",
- m0, m0->m_len);
- ENDDEBUG
- ASSERT( m0->m_len != 0);
- (void) cons_senddata(copcb, m0);
- }
- }
-
- /* send more? */
- break;
-
- case ECN_ACCEPT: /* call accepted at other end */
- /* adr_src, adr_dst are as given in the ECN_CALL
- * pcb field is copied from our ECN_CALL
- * request, confirm gives me a channel number
- */
- ASSERT( ecnrq->e_vc != 0);
-
- IncStat(co_accept);
- if(copcb =
-#ifdef ARGO_DEBUG
- cons_chan_to_pcb((int)ecnrq->e_vc, __LINE__ )
-#else ARGO_DEBUG
- cons_chan_to_pcb((int)ecnrq->e_vc)
-#endif ARGO_DEBUG
- ) {
- /* error: already exists */
- printf("cons PANIC: dbl confirm for channel 0x%x\n",
- ecnrq->e_vc);
- break;
- }
- copcb = (struct cons_pcb *)ecnrq->e_pcb;
- if( copcb->co_myself != copcb ) {
- struct mbuf *mm;
- /* TODO: REMOVE */
- ASSERT(0);
- printf("BAD e_pcb from ecn (0x%x) cmd 0x%x\n",
- ecnrq->e_pcb, ecnrq->e_cmd);
- mm = dtom( copcb );
- if(mm->m_type == MT_FREE)
- printf("FREED MBUF!\n");
- dump_buf (ecnrq, sizeof (*ecnrq));
- panic("BAD ecnrq");
- break;
- }
- touch(copcb);
- copcb->co_state = OPEN;
- copcb->co_channel = (int)ecnrq->e_vc;
- if(copcb->co_socket) {
- /* tp0 will take care of itself */
- if( copcb->co_flags & CONSF_XTS)
- soisconnected(copcb->co_socket); /* wake 'em up */
- }
- wakeup( (caddr_t)&copcb->co_state );
-
- /*
- * Anything on the pending queue for this connection?
- */
- if( copcb->co_pending.ifq_len > 0 ) {
- register struct mbuf *m0;
-
- s = splimp();
- IF_DEQUEUE( &copcb->co_pending, m0 );
- splx(s);
- /* CAN ONLY DO 1 item here
- * if you change this if to while, HA HA
- * it'll go right back onto
- * the pending queue (which means things will
- * be reordered on the queue!)
- */
- if( m0 ) {
- IFDEBUG(D_CDATA)
- printf("ACPT sending pending queue 0x%x len 0x%x\n",
- m0, m0->m_len);
- ENDDEBUG
- ASSERT( m0->m_len != 0);
- (void) cons_senddata(copcb, m0);
- }
- }
- break;
-
- case ECN_REFUSE:
- /* other end refused our connect request */
- /* src, dst are as given in the ECN_CALL */
-
- IncStat(co_refuse);
- copcb = (struct cons_pcb *)ecnrq->e_pcb;
- if( copcb->co_myself != copcb ) {
- struct mbuf *mm;
- /* TODO: REMOVE */
- ASSERT(0);
- printf("BAD e_pcb from ecn (0x%x) cmd 0x%x\n",
- ecnrq->e_pcb, ecnrq->e_cmd);
- mm = dtom( copcb );
- if(mm->m_type == MT_FREE)
- printf("FREED MBUF!\n");
- dump_buf (ecnrq, sizeof (*ecnrq));
- dump_buf (copcb, sizeof (*copcb));
- panic("BAD ecnrq");
- break;
- }
- touch(copcb);
- copcb->co_state = CLOSED; /* do we have to do a clear?? */
- copcb->co_channel = X_NOCHANNEL;
- if(copcb->co_socket) {
- copcb->co_socket->so_error = ECONNREFUSED;
- /* TODO: if there's diagnostic info in the
- * packet, and it's more useful than this E*,
- * get it
- */
- soisdisconnected(copcb->co_socket); /* wake 'em up */
- IFDEBUG(D_INCOMING)
- printf("ECN_REFUSE: waking up 0x%x\n",
- (caddr_t)&copcb->co_state );
- ENDDEBUG
- wakeup( (caddr_t)&copcb->co_state );
- }
- /*
- * Anything on the pending queue for this connection?
- */
- while( copcb->co_pending.ifq_len > 0 ) {
- register struct mbuf *m0;
-
- s = splimp();
- IF_DEQUEUE( &copcb->co_pending, m0 );
- splx(s);
- m_freem(m0);
- }
- if ( ecnrq->e_reason == E_CO_NORESOURCES ) {
- IncStat(co_noresources);
- cons_clear_and_detach( copcb, DONTCLEAR, PRC_QUENCH );
- } else if(copcb->co_socket ) {
- copcb->co_socket->so_error = find_error_reason( ecnrq );
- }
- break;
-
- case ECN_CONNECT: /* incoming call */
- /*
- * ECN_CONNECT indication gives adc_src, adc_dst and channel
- */
- ASSERT( ecnrq->e_vc != 0);
-
- IncStat(co_connect);
- cons_incoming(ifp, ecnrq);
- break;
-
- case ECN_RESET:
- case ECN_CLEAR:
- /*
- * ECN_CLEAR(indication) (if we can construct such a beast)
- * gives e_vc,
- * Throw away anything queued pending on this connection
- * give a reset indication to the upper layer if TP
- * free the mbufs
- */
- ASSERT( ecnrq->e_vc != 0);
- if( ecnrq->e_cmd == ECN_CLEAR )
- IncStat(co_clear_in);
- else
- IncStat(co_reset_in);
-#ifdef ARGO_DEBUG
- if( ! (copcb=cons_chan_to_pcb((int)ecnrq->e_vc, __LINE__)) )
-#else ARGO_DEBUG
- if( ! (copcb=cons_chan_to_pcb((int)ecnrq->e_vc)) )
-#endif ARGO_DEBUG
-
- break;
- while( copcb->co_pending.ifq_len ) {
- register struct mbuf *m0;
-
- s = splimp();
- IF_DEQUEUE( &copcb->co_pending, m0 );
- splx(s);
- m_freem(m0);
- }
- copcb->co_state = CLOSED; /* do we have to do a clear? */
- copcb->co_channel = X_NOCHANNEL;
-
- cons_clear_and_detach( copcb, DONTCLEAR, PRC_ROUTEDEAD );
- if (copcb->co_socket ) {
- copcb->co_socket->so_error = find_error_reason( ecnrq );
- }
- break;
-
- case ECN_RECEIVE:
- /*
- * ECN_RECEIVE (read)
- */
- ASSERT( ecnrq->e_vc != 0);
- IncStat(co_receive);
- {
- /* TODO: REMOVE */
- struct mbuf *thedata = e_data(ecnrq);
- u_int *firstint = mtod( thedata, u_int *);
-
- if( (*firstint & 0xff000000) != 0x81000000 ) {
- /* not clnp */
- switch( ((*firstint) & 0x00ff0000) >> 20 ) {
- case 0x1:
- case 0x2:
- case 0x3:
- case 0x6:
- case 0x7:
- case 0x8:
- case 0xc:
- case 0xd:
- case 0xe:
- case 0xf:
- break;
- default:
- printf(" ECN_RECEIVE! BAD DATA\n" );
- dump_buf( thedata, 20 + 12 );
- m_freem( m );
- splx(s0);
- }
- }
- }
- if ( (copcb =
-#ifdef ARGO_DEBUG
- cons_chan_to_pcb( (int)ecnrq->e_vc, __LINE__ )
-#else ARGO_DEBUG
- cons_chan_to_pcb( (int)ecnrq->e_vc )
-#endif ARGO_DEBUG
- ) == (struct cons_pcb *)0 ) {
- ifp->if_ierrors ++;
- IFTRACE(D_CDATA)
- tptrace(TPPTmisc, "ECN_RECEIVE DROPPED chan \n",
- ecnrq->e_vc, 0, 0, 0);
- ENDTRACE
- break;
- }
-
- touch(copcb);
- if( ecnrq->e_info & ECN_INFO_RCVD_INT ) {
- /* interrupt packet */
- printf("consintr: interrupt pkttype : DROPPED\n");
- IncStat(co_intrpt_pkts_in);
- IncStat(co_Rdrops);
- break;
- }
- /* new way */
- if( copcb->co_proto == CLNP_proto )
- {
- /* IP: put it on the queue and set soft interrupt */
- struct ifqueue *ifq;
- extern struct ifqueue clnlintrq;
- register struct mbuf *ifpp; /* for ptr to ifp */
- register struct mbuf *data = e_data(ecnrq);
-
- total_pkts_to_clnp ++;
-
- /* when acting as a subnet service, have to prepend a
- * pointer to the ifnet before handing this to clnp
- * GAG
- */
- if( ( data->m_off > MMINOFF + sizeof(struct snpa_hdr)) &&
- ( data->m_off <= MMAXOFF )) {
- data->m_off -= sizeof(struct snpa_hdr);
- data->m_len += sizeof(struct snpa_hdr);
- } else {
- MGET(ifpp, M_DONTWAIT, MT_XHEADER);
- if( !ifpp ) {
- ifp->if_ierrors ++;
- splx(s0);
- m_freem(m); /* frees everything */
- return;
- }
- ifpp->m_len = sizeof(struct snpa_hdr);
- ifpp->m_act = 0;
- ifpp->m_next = data;
- data = ifpp;
- }
- IFTRACE(D_CDATA)
- tptrace(TPPTmisc, "-->CLNP copcb\n", copcb, 0, 0, 0);
- ENDTRACE
- {
- /*
- * TODO: if we ever use esis/cons we have to
- * think of something reasonable to stick in the
- * snh_shost,snh_dhost fields. I guess
- * the x.121 address is what we want.
- *
- * That would also require length fields in the
- * snpa_hdr structure.
- */
- struct snpa_hdr *snh =
- mtod(data, struct snpa_hdr *);
- bzero((caddr_t)&snh, sizeof(struct snpa_hdr));
- bcopy((caddr_t)&ifp, (caddr_t)&snh->snh_ifp,
- sizeof(struct ifnet *));
- }
- *( mtod(data, struct ifnet **) ) = ifp; /* KLUDGE */
-
- ifq = &clnlintrq;
- splimp();
- if (IF_QFULL(ifq)) {
- IF_DROP(ifq);
- m_freem(m);
- IFDEBUG(D_INCOMING)
- printf("DROPPED! ecnrq 0x%x, data 0x%x\n", m,data);
- ENDDEBUG
- splx(s0);
- ifp->if_ierrors ++;
- return;
- }
- IF_ENQUEUE(ifq, data);
- IFDEBUG(D_INCOMING)
- printf(
- "0x%x enqueued on ip Q: m_len 0x%x m_type 0x%x m_off 0x%x\n",
- data, data->m_len, data->m_type, data->m_off);
- dump_buf(mtod(data, caddr_t), data->m_len);
- ENDDEBUG
- e_data(ecnrq) = (struct mbuf *)0;
- schednetisr(NETISR_CLNP);
- } else {
- /* HL is NOT clnp */
- IFTRACE(D_CDATA)
- tptrace(TPPTmisc,
- "-->HL pr_input so copcb channel\n",
- copcb->co_proto->pr_input,
- copcb->co_socket, copcb,
- copcb->co_channel);
- ENDTRACE
- IFDEBUG(D_INCOMING)
- printf( "0x%x --> HL proto 0x%x chan 0x%x\n",
- e_data(ecnrq), copcb->co_proto, copcb->co_channel );
- ENDDEBUG
-
- (*copcb->co_proto->pr_input)(e_data(ecnrq),
- &copcb->co_faddr,
- &copcb->co_laddr,
- copcb->co_socket, /* used by cons-transport interface */
- (copcb->co_flags & CONSF_DGM)?0:
- copcb->co_channel);/* used by tp-cons interface */
-
- /*
- * the pr_input will free the data chain, so we must
- * zero the ptr to is so that m_free doesn't panic
- */
- e_data(ecnrq) = (struct mbuf *)0;
- }
- break;
-
- default:
- /* error */
- ifp->if_ierrors ++;
- printf("consintr: unknown request\n");
- }
- IFDEBUG(D_INCOMING)
- printf("consintr: m_freem( 0x%x )\n", m);
- ENDDEBUG
- m_freem( m );
- }
- splx(s0);
-}
-
-/*
- * Process an ioctl request.
- * also set-time-limit, extend-time-limit
- * for ALL channels, the time-limit ioctls will be done by open-a-dummy-socket,
- * do ioctl with the channel number, close the socket (dumb!).
- */
-/* ARGSUSED */
-cons_ioctl(so, cmd, data)
- struct socket *so;
- int cmd;
- caddr_t data;
-{
- int s = splnet();
- int error = 0;
-
- IFDEBUG(D_CCONS)
- printf("cons_ioctl( cmd 0x%x )\n", cmd);
- ENDDEBUG
-
-#ifdef notdef
- switch (cmd) {
-
- default:
-#endif notdef
- error = EOPNOTSUPP;
-#ifdef notdef
- }
-#endif notdef
-
- splx(s);
- return (error);
-}
-
-
-/*
- *************************************************************
- * *
- * *
- * Interface to CO Subnetwork service from CLNP *
- * Must be a device interface. *****
- * ***
- * *
- * Poof!
- */
-
-/*
- * NAME: consioctl()
- * CALLED FROM:
- * called through the ifnet structure.
- * FUNCTION and ARGUMENTS:
- * the usual ioctl stuff
- * RETURNS:
- * E*
- * SIDE EFFECTS:
- * NOTES:
- */
-consioctl(ifp, cmd, data)
- register struct ifnet *ifp;
- register int cmd;
- register caddr_t data;
-{
- register struct ifaddr *ifa = (struct ifaddr *)data;
- register int s = splimp();
- register struct ifreq *ifr = (struct ifreq *)data;
- register int error = 0;
- void consshutdown();
-
- switch (cmd) {
- case SIOCSIFADDR:
- switch (ifa->ifa_addr.sa_family) {
- case AF_ISO:
- if( (ifp->if_flags & IFF_UP ) == 0)
- consinit(ifp->if_unit);
- break;
- default:
- printf("CANNOT config cons with address family %d\n",
- ifa->ifa_addr.sa_family);
- break;
- }
- break;
- case SIOCSIFFLAGS:
- IFDEBUG(D_CCONS)
- printf("consioctl: set flags to x%x\n", ifr->ifr_flags);
- printf("consioctl: ifp flags are x%x\n", ifp->if_flags);
- ENDDEBUG
- if( ifr->ifr_flags & IFF_LOOPBACK )
- ifp->if_flags |= IFF_LOOPBACK;
- else
- ifp->if_flags &= ~IFF_LOOPBACK;
-
- /* if board is down but request takes it up, init the board */
- if (ifr->ifr_flags & IFF_UP && (ifp->if_flags & IFF_UP) == 0)
- consinit(ifp->if_unit);
-
- /* if board is up but request takes it down, shut the board down */
- if (((ifr->ifr_flags & IFF_UP) == 0) && (ifp->if_flags & IFF_UP)) {
- consshutdown(ifp->if_unit);
- }
- IFDEBUG(D_CCONS)
- printf("consioctl: flags are x%x\n", ifp->if_flags);
- ENDDEBUG
- break;
- case SIOCGSTATUS:
- /* warning: must coerse ifp to (struct ifstatus *) in order to use */
- IFDEBUG(D_CCONS)
- printf("consioctl: EICON status request\n");
- ENDDEBUG
-#if NECN>0
- ecnioctl(ifp, cmd, data);
-#else
- error = ENODEV;
-#endif NECN>0
- break;
- default:
- error = EINVAL;
- }
- splx(s);
- return error;
-}
-
-/*
- * NAME: consattach()
- * CALLED FROM:
- * cons_init() (which comes from autoconf)
- * FUNCTION and ARGUMENTS:
- * creates an ifp and fills it in; calls ifattach() on it.
- * RETURNS:
- * no return value
- * SIDE EFFECTS:
- * NOTES:
- */
-consattach()
-{
- register struct ifnet *ifp;
- register struct mbuf *m;
-
- if(sizeof(struct ifnet) > MLEN) {
- printf("Can't attach cons! sizeof(struct ifnet) > MLEN\n");
- return;
- }
- MGET(m, M_DONTWAIT, MT_IFADDR);
- if( !m ) {
- printf("Can't attach cons! NO MBUFS!\n");
- return;
- }
- m->m_len = sizeof(struct ifnet);
- ifp = consif = mtod(m, struct ifnet *);
- ifp->if_unit = 0;
- ifp->if_name = "cons";
- ifp->if_mtu = ECN_MTU;
- ifp->if_init = consinit;
- ifp->if_ioctl = consioctl;
- ifp->if_output = cosns_output; /* called by clnp */
- ifp->if_flags = IFF_LOOPBACK; /* default */
- if_attach(ifp);
- printf("cons%d: pseudo device attached \n", ifp->if_unit);
-}
-
-/*
- * NAME: consinit()
- * CALLED FROM:
- * consioctl()
- * FUNCTION and ARGUMENTS:
- * Initializes apropos data structures, etc.
- * Marks the device as up.
- * Zaps the address list.
- * Calls device layer restart on the device if necessary.
- */
-Static
-consinit(_unit)
-register int _unit; /* unit to initialize */
-{
- struct ifnet *ecnifp();
- struct ifnet *ifp;
- int s;
-
- if ((ifp = ecnifp(_unit)) != (struct ifnet *)0 ) {
- ecnrestart(ifp);
- IncStat(co_restart);
- }
- if (consif->if_addrlist == (struct ifaddr *)0)
- return;
- if ((consif->if_flags & IFF_UP) == 0) {
- s = splimp();
- consif->if_flags |= IFF_UP;
- splx(s);
- }
-
-}
-
-/*
- * NAME: consshutdown()
- * CALLED FROM:
- * cons_ioctl() when user takes down an interface w/ SIOCSIFFLAGS
- * FUNCTION and ARGUMENTS:
- * calls lower layer shutdown routine on the device.
- * and marks the if as down if the if is the sw loopback pseudodevice.
- * RETURNS:
- * no return value
- */
-void
-consshutdown(_unit)
-register int _unit; /* unit to shutdown */
-{
- extern struct ifnet *ecnifp();
- struct ifnet *ifp;
- int s;
-
- if ((ifp = ecnifp(_unit)) != (struct ifnet *)0 ) {
- ecnshutdown(ifp);
- }
- if ((consif->if_flags & IFF_UP) ) {
- s = splimp();
- consif->if_flags &= ~IFF_UP;
- splx(s);
- }
-}
-#endif KERNEL
-
-/*
- * NAME: munge()
- * CALLED FROM:
- * cons_pcbbind(), cons_usrreq()
- * FUNCTION and ARGUMENTS:
- * Takes the argument (value) and stashes it into the last two
- * nibbles of an X.121 address. Does this in the two nibbles beginning
- * at the location defined by the character pointer (dst_octet) and the
- * integer (dst_nibble). Nibble 0 is the lower nibble (high
- * order 4 bits); nibble 1 is the low order 4 bits of *(dst_octet).
- *
- * RETURNS:
- * no return value
- */
-Static
-munge( value, dst_octet, dst_nibble)
- int value;
- caddr_t dst_octet;
- int dst_nibble;
-{
- IFDEBUG(D_CCONN)
- printf("MUNGE: value 0x%x dst_octet 0x%x, nibble 0x%x)\n",
- value, dst_octet, dst_nibble);
- ENDDEBUG
- if (value >= ISO_PORT_RESERVED)
- value -= 1000;
-
- {
- /* convert so it looks like a decimal number */
- register int tens, ones;
-
- tens = value/10;
- ASSERT( tens <= 9 );
- ones = value - (tens * 10);
-
- value = tens * 16 + ones;
- }
-
- dst_octet --;
- /* leave nibble same 'cause it's one after the last set nibble */
-
- *dst_octet &= ~(0xff<<(dst_nibble << 2)); /* zero it */
- *dst_octet |= ((value>>4) << (dst_nibble<<2));
- dst_nibble = 1-dst_nibble;
- dst_octet += dst_nibble;
-
- *dst_octet &= ~(0xff<<(dst_nibble << 2)); /* zero it */
- *dst_octet |= ((value&0xff) << (dst_nibble<<2));
-}
-
-/*
- * NAME: unmunge()
- * CALLED FROM:
- * DTEtoNSAP(), FACILtoNSAP()
- * FUNCTION and ARGUMENTS:
- * return the port/tsuffix represented by the two digits found in a
- * bcd string beginning at the (dst_nibble)th nibble of the
- * octet BEFORE (dst_octet).
- *
- * dst_octet,dst_nibble is the nibble after the one we'll look at
- * RETURNS:
- * an integer, the port/tsuffix
- * Note- converts to a port > 1000 if necessary.
- */
-Static int
-unmunge( dst_octet, dst_nibble )
- caddr_t dst_octet;
- int dst_nibble;
-{
- register u_short last = 0;
-
- dst_octet --;
- /* leave nibble same 'cause it's one after the last set nibble */
- IFDEBUG(D_CADDR)
- printf("unmunge: *octet 0x%x, nibble 0x%x\n", *dst_octet,
- dst_nibble);
- ENDDEBUG
-
- last = ((*dst_octet) & (0xff<<(dst_nibble<<2)));
- dst_nibble = 1-dst_nibble;
- dst_octet += dst_nibble;
-
- last |= ((*dst_octet) & (0xff<<(dst_nibble << 2)));
- {
- /* convert to a decimal number */
- register int tens, ones;
-
- tens = (last&0xf0)>>4;
- ones = last&0xf;
-
- last = tens * 10 + ones;
- }
-
- IFDEBUG(D_CADDR)
- printf("unmunge computes 0x%x\n", last);
- ENDDEBUG
- if((int)last+1000 >= ISO_PORT_RESERVED)
- last += 1000;
- IFDEBUG(D_CADDR)
- printf("unmunge returns 0x%x\n", last);
- ENDDEBUG
- return last;
-}
-
-/*
- * NAME: make_partial_x25_packet()
- *
- * FUNCTION and ARGUMENTS:
- * Makes part of an X.25 call packet, for use by the eicon board.
- * (src) and (dst) are the NSAP-addresses of source and destination.
- * (proto) is the higher-layer protocol number (in iso.h)
- * (buf) is a ptr to a buffer into which to write this partial header.
- *
- * The partial header looks like (choke):
- * octet meaning
- * 1 calling DTE len | called DTE len (lengths in nibbles)
- * 2..n-1 called DTE addr | (<-- boundary may be middle of an octet)
- * calling DTE addr | zero nibble to round to octet boundary.
- * n Facility length (in octets)
- * n+1 Facility field, which is a set of:
- * m facil code
- * m+1 facil param len (for >2-byte facilities) in octets
- * m+2..p facil param field
- * q user data (protocol identification octet)
- *
- *
- * RETURNS:
- * 0 if OK
- * E* if failed.
- */
-
-#ifdef X25_1984
-int cons_use_facils = 1;
-#else X25_1984
-int cons_use_facils = 0;
-#endif X25_1984
-
-int cons_use_udata = 1; /* KLUDGE FOR DEBUGGING */