Beispiel #1
0
static u16_t
altcp_tcp_mss(struct altcp_pcb *conn)
{
  struct tcp_pcb *pcb;
  if (conn == NULL) {
    return 0;
  }
  ALTCP_TCP_ASSERT_CONN(conn);
  pcb = (struct tcp_pcb *)conn->state;
  return tcp_mss(pcb);
}
Beispiel #2
0
static void
tcp_dooptions(struct tcpcb *tp, u_char *cp, int cnt, struct tcpiphdr *ti)
{
	uint16_t mss;
	int opt, optlen;

	DEBUG_CALL("tcp_dooptions");
	DEBUG_ARGS((dfd, " tp = %lx  cnt=%i\n", (long)tp, cnt));

	for (; cnt > 0; cnt -= optlen, cp += optlen) {
		opt = cp[0];
		if (opt == TCPOPT_EOL)
			break;
		if (opt == TCPOPT_NOP)
			optlen = 1;
		else {
			optlen = cp[1];
			if (optlen <= 0)
				break;
		}
		switch (opt) {

		default:
			continue;

		case TCPOPT_MAXSEG:
			if (optlen != TCPOLEN_MAXSEG)
				continue;
			if (!(ti->ti_flags & TH_SYN))
				continue;
			memcpy((char *) &mss, (char *) cp + 2, sizeof(mss));
			NTOHS(mss);
			(void) tcp_mss(tp, mss);	/* sets t_maxseg */
			break;
		}
	}
}
Beispiel #3
0
/*
 * Do a send by putting data in output queue and updating urgent
 * marker if URG set.  Possibly send more data.  Unlike the other
 * pru_*() routines, the mbuf chains are our responsibility.  We
 * must either enqueue them or free them.  The other pru_* routines
 * generally are caller-frees.
 */
static int
tcp_usr_send(struct socket *so, int flags, struct mbuf *m,
    struct sockaddr *nam, struct mbuf *control, struct thread *td)
{
	int error = 0;
	struct inpcb *inp;
	struct tcpcb *tp = NULL;
	int headlocked = 0;
#ifdef INET6
	int isipv6;
#endif
	TCPDEBUG0;

	/*
	 * We require the pcbinfo lock in two cases:
	 *
	 * (1) An implied connect is taking place, which can result in
	 *     binding IPs and ports and hence modification of the pcb hash
	 *     chains.
	 *
	 * (2) PRUS_EOF is set, resulting in explicit close on the send.
	 */
	if ((nam != NULL) || (flags & PRUS_EOF)) {
		INP_INFO_WLOCK(&V_tcbinfo);
		headlocked = 1;
	}
	inp = sotoinpcb(so);
	KASSERT(inp != NULL, ("tcp_usr_send: inp == NULL"));
	INP_WLOCK(inp);
	if (inp->inp_flags & (INP_TIMEWAIT | INP_DROPPED)) {
		if (control)
			m_freem(control);
		if (m)
			m_freem(m);
		error = ECONNRESET;
		goto out;
	}
#ifdef INET6
	isipv6 = nam && nam->sa_family == AF_INET6;
#endif /* INET6 */
	tp = intotcpcb(inp);
	TCPDEBUG1();
	if (control) {
		/* TCP doesn't do control messages (rights, creds, etc) */
		if (control->m_len) {
			m_freem(control);
			if (m)
				m_freem(m);
			error = EINVAL;
			goto out;
		}
		m_freem(control);	/* empty control, just free it */
	}
	if (!(flags & PRUS_OOB)) {
		sbappendstream(&so->so_snd, m);
		if (nam && tp->t_state < TCPS_SYN_SENT) {
			/*
			 * Do implied connect if not yet connected,
			 * initialize window to default value, and
			 * initialize maxseg/maxopd using peer's cached
			 * MSS.
			 */
			INP_INFO_WLOCK_ASSERT(&V_tcbinfo);
#ifdef INET6
			if (isipv6)
				error = tcp6_connect(tp, nam, td);
			else
#endif /* INET6 */
			error = tcp_connect(tp, nam, td);
			if (error)
				goto out;
			tp->snd_wnd = TTCP_CLIENT_SND_WND;
			tcp_mss(tp, -1);
		}
		if (flags & PRUS_EOF) {
			/*
			 * Close the send side of the connection after
			 * the data is sent.
			 */
			INP_INFO_WLOCK_ASSERT(&V_tcbinfo);
			socantsendmore(so);
			tcp_usrclosed(tp);
		}
		if (headlocked) {
			INP_INFO_WUNLOCK(&V_tcbinfo);
			headlocked = 0;
		}
		if (!(inp->inp_flags & INP_DROPPED)) {
			if (flags & PRUS_MORETOCOME)
				tp->t_flags |= TF_MORETOCOME;
			error = tcp_output_send(tp);
			if (flags & PRUS_MORETOCOME)
				tp->t_flags &= ~TF_MORETOCOME;
		}
	} else {
		/*
		 * XXXRW: PRUS_EOF not implemented with PRUS_OOB?
		 */
		SOCKBUF_LOCK(&so->so_snd);
		if (sbspace(&so->so_snd) < -512) {
			SOCKBUF_UNLOCK(&so->so_snd);
			m_freem(m);
			error = ENOBUFS;
			goto out;
		}
		/*
		 * According to RFC961 (Assigned Protocols),
		 * the urgent pointer points to the last octet
		 * of urgent data.  We continue, however,
		 * to consider it to indicate the first octet
		 * of data past the urgent section.
		 * Otherwise, snd_up should be one lower.
		 */
		sbappendstream_locked(&so->so_snd, m);
		SOCKBUF_UNLOCK(&so->so_snd);
		if (nam && tp->t_state < TCPS_SYN_SENT) {
			/*
			 * Do implied connect if not yet connected,
			 * initialize window to default value, and
			 * initialize maxseg/maxopd using peer's cached
			 * MSS.
			 */
			INP_INFO_WLOCK_ASSERT(&V_tcbinfo);
#ifdef INET6
			if (isipv6)
				error = tcp6_connect(tp, nam, td);
			else
#endif /* INET6 */
			error = tcp_connect(tp, nam, td);
			if (error)
				goto out;
			tp->snd_wnd = TTCP_CLIENT_SND_WND;
			tcp_mss(tp, -1);
			INP_INFO_WUNLOCK(&V_tcbinfo);
			headlocked = 0;
		} else if (nam) {
			INP_INFO_WUNLOCK(&V_tcbinfo);
			headlocked = 0;
		}
		tp->snd_up = tp->snd_una + so->so_snd.sb_cc;
		tp->t_flags |= TF_FORCEDATA;
		error = tcp_output_send(tp);
		tp->t_flags &= ~TF_FORCEDATA;
	}
out:
	TCPDEBUG2((flags & PRUS_OOB) ? PRU_SENDOOB :
		  ((flags & PRUS_EOF) ? PRU_SEND_EOF : PRU_SEND));
	INP_WUNLOCK(inp);
	if (headlocked)
		INP_INFO_WUNLOCK(&V_tcbinfo);
	return (error);
}
Beispiel #4
0
/*
 * Do a send by putting data in output queue and updating urgent
 * marker if URG set.  Possibly send more data.  Unlike the other
 * pru_*() routines, the mbuf chains are our responsibility.  We
 * must either enqueue them or free them.  The other pru_* routines
 * generally are caller-frees.
 */
static int
tcp_usr_send(struct socket *so, int flags, struct mbuf *m, 
	     struct sockaddr *nam, struct mbuf *control, struct proc *p)
{
	int s = splnet();
	int error = 0;
	struct inpcb *inp = sotoinpcb(so);
	struct tcpcb *tp;
#ifdef INET6
	int isipv6;
#endif
	TCPDEBUG0;

	if (inp == NULL) {
		/*
		 * OOPS! we lost a race, the TCP session got reset after
		 * we checked SS_CANTSENDMORE, eg: while doing uiomove or a
		 * network interrupt in the non-splnet() section of sosend().
		 */
		if (m)
			m_freem(m);
		if (control)
			m_freem(control);
		error = ECONNRESET;	/* XXX EPIPE? */
		tp = NULL;
		TCPDEBUG1();
		goto out;
	}
#ifdef INET6
	isipv6 = nam && nam->sa_family == AF_INET6;
#endif /* INET6 */
	tp = intotcpcb(inp);
	TCPDEBUG1();
	if (control) {
		/* TCP doesn't do control messages (rights, creds, etc) */
		if (control->m_len) {
			m_freem(control);
			if (m)
				m_freem(m);
			error = EINVAL;
			goto out;
		}
		m_freem(control);	/* empty control, just free it */
	}
	if(!(flags & PRUS_OOB)) {
		sbappend(&so->so_snd, m);
		if (nam && tp->t_state < TCPS_SYN_SENT) {
			/*
			 * Do implied connect if not yet connected,
			 * initialize window to default value, and
			 * initialize maxseg/maxopd using peer's cached
			 * MSS.
			 */
#ifdef INET6
			if (isipv6)
				error = tcp6_connect(tp, nam, p);
			else
#endif /* INET6 */
			error = tcp_connect(tp, nam, p);
			if (error)
				goto out;
			tp->snd_wnd = TTCP_CLIENT_SND_WND;
			tcp_mss(tp, -1);
		}

		if (flags & PRUS_EOF) {
			/*
			 * Close the send side of the connection after
			 * the data is sent.
			 */
			socantsendmore(so);
			tp = tcp_usrclosed(tp);
		}
		if (tp != NULL) {
			if (flags & PRUS_MORETOCOME)
				tp->t_flags |= TF_MORETOCOME;
			error = tcp_output(tp);
			if (flags & PRUS_MORETOCOME)
				tp->t_flags &= ~TF_MORETOCOME;
		}
	} else {
		if (sbspace(&so->so_snd) < -512) {
			m_freem(m);
			error = ENOBUFS;
			goto out;
		}
		/*
		 * According to RFC961 (Assigned Protocols),
		 * the urgent pointer points to the last octet
		 * of urgent data.  We continue, however,
		 * to consider it to indicate the first octet
		 * of data past the urgent section.
		 * Otherwise, snd_up should be one lower.
		 */
		sbappend(&so->so_snd, m);
		if (nam && tp->t_state < TCPS_SYN_SENT) {
			/*
			 * Do implied connect if not yet connected,
			 * initialize window to default value, and
			 * initialize maxseg/maxopd using peer's cached
			 * MSS.
			 */
#ifdef INET6
			if (isipv6)
				error = tcp6_connect(tp, nam, p);
			else
#endif /* INET6 */
			error = tcp_connect(tp, nam, p);
			if (error)
				goto out;
			tp->snd_wnd = TTCP_CLIENT_SND_WND;
			tcp_mss(tp, -1);
		}
		tp->snd_up = tp->snd_una + so->so_snd.sb_cc;
		tp->t_force = 1;
		error = tcp_output(tp);
		tp->t_force = 0;
	}
	COMMON_END((flags & PRUS_OOB) ? PRU_SENDOOB : 
		   ((flags & PRUS_EOF) ? PRU_SEND_EOF : PRU_SEND));
}
static uint16_t psock_send_interrupt(FAR struct net_driver_s *dev,
                                     FAR void *pvconn, FAR void *pvpriv,
                                     uint16_t flags)
{
    FAR struct tcp_conn_s *conn = (FAR struct tcp_conn_s *)pvconn;
    FAR struct socket *psock = (FAR struct socket *)pvpriv;

    nllvdbg("flags: %04x\n", flags);

    /* If this packet contains an acknowledgement, then update the count of
     * acknowledged bytes.
     */

    if ((flags & TCP_ACKDATA) != 0)
    {
        FAR struct tcp_wrbuffer_s *wrb;
        FAR sq_entry_t *entry;
        FAR sq_entry_t *next;
        uint32_t ackno;

        ackno = tcp_getsequence(TCPBUF->ackno);
        nllvdbg("ACK: ackno=%u flags=%04x\n", ackno, flags);

        /* Look at every write buffer in the unacked_q.  The unacked_q
         * holds write buffers that have been entirely sent, but which
         * have not yet been ACKed.
         */

        for (entry = sq_peek(&conn->unacked_q); entry; entry = next)
        {
            uint32_t lastseq;

            /* Check of some or all of this write buffer has been ACKed. */

            next = sq_next(entry);
            wrb = (FAR struct tcp_wrbuffer_s*)entry;

            /* If the ACKed sequence number is greater than the start
             * sequence number of the write buffer, then some or all of
             * the write buffer has been ACKed.
             */

            if (ackno > WRB_SEQNO(wrb))
            {
                /* Get the sequence number at the end of the data */

                lastseq = WRB_SEQNO(wrb) + WRB_PKTLEN(wrb);
                nllvdbg("ACK: wrb=%p seqno=%u lastseq=%u pktlen=%u ackno=%u\n",
                        wrb, WRB_SEQNO(wrb), lastseq, WRB_PKTLEN(wrb), ackno);

                /* Has the entire buffer been ACKed? */

                if (ackno >= lastseq)
                {
                    nllvdbg("ACK: wrb=%p Freeing write buffer\n", wrb);

                    /* Yes... Remove the write buffer from ACK waiting queue */

                    sq_rem(entry, &conn->unacked_q);

                    /* And return the write buffer to the pool of free buffers */

                    tcp_wrbuffer_release(wrb);
                }
                else
                {
                    unsigned int trimlen;

                    /* No, then just trim the ACKed bytes from the beginning
                     * of the write buffer.  This will free up some I/O buffers
                     * that can be reused while are still sending the last
                     * buffers in the chain.
                     */

                    trimlen = ackno - WRB_SEQNO(wrb);
                    if (trimlen > WRB_SENT(wrb))
                    {
                        /* More data has been ACKed then we have sent? */

                        trimlen = WRB_SENT(wrb);
                    }

                    nllvdbg("ACK: wrb=%p trim %u bytes\n", wrb, trimlen);

                    WRB_TRIM(wrb, trimlen);
                    WRB_SEQNO(wrb) = ackno;
                    WRB_SENT(wrb) -= trimlen;

                    /* Set the new sequence number for what remains */

                    nllvdbg("ACK: wrb=%p seqno=%u pktlen=%u\n",
                            wrb, WRB_SEQNO(wrb), WRB_PKTLEN(wrb));
                }
            }
        }

        /* A special case is the head of the write_q which may be partially
         * sent and so can still have un-ACKed bytes that could get ACKed
         * before the entire write buffer has even been sent.
         */

        wrb = (FAR struct tcp_wrbuffer_s*)sq_peek(&conn->write_q);
        if (wrb && WRB_SENT(wrb) > 0 && ackno > WRB_SEQNO(wrb))
        {
            uint32_t nacked;

            /* Number of bytes that were ACKed */

            nacked = ackno - WRB_SEQNO(wrb);
            if (nacked > WRB_SENT(wrb))
            {
                /* More data has been ACKed then we have sent? ASSERT? */

                nacked = WRB_SENT(wrb);
            }

            nllvdbg("ACK: wrb=%p seqno=%u nacked=%u sent=%u ackno=%u\n",
                    wrb, WRB_SEQNO(wrb), nacked, WRB_SENT(wrb), ackno);

            /* Trim the ACKed bytes from the beginning of the write buffer. */

            WRB_TRIM(wrb, nacked);
            WRB_SEQNO(wrb) = ackno;
            WRB_SENT(wrb) -= nacked;

            nllvdbg("ACK: wrb=%p seqno=%u pktlen=%u sent=%u\n",
                    wrb, WRB_SEQNO(wrb), WRB_PKTLEN(wrb), WRB_SENT(wrb));
        }
    }

    /* Check for a loss of connection */

    else if ((flags & (TCP_CLOSE | TCP_ABORT | TCP_TIMEDOUT)) != 0)
    {
        nllvdbg("Lost connection: %04x\n", flags);

        /* Report not connected */

        net_lostconnection(psock, flags);

        /* Free write buffers and terminate polling */

        psock_lost_connection(psock, conn);
        return flags;
    }

    /* Check if we are being asked to retransmit data */

    else if ((flags & TCP_REXMIT) != 0)
    {
        FAR struct tcp_wrbuffer_s *wrb;
        FAR sq_entry_t *entry;

        nllvdbg("REXMIT: %04x\n", flags);

        /* If there is a partially sent write buffer at the head of the
         * write_q?  Has anything been sent from that write buffer?
         */

        wrb = (FAR struct tcp_wrbuffer_s *)sq_peek(&conn->write_q);
        nllvdbg("REXMIT: wrb=%p sent=%u\n", wrb, wrb ? WRB_SENT(wrb) : 0);

        if (wrb != NULL && WRB_SENT(wrb) > 0)
        {
            FAR struct tcp_wrbuffer_s *tmp;
            uint16_t sent;

            /* Yes.. Reset the number of bytes sent sent from the write buffer */

            sent = WRB_SENT(wrb);
            if (conn->unacked > sent)
            {
                conn->unacked -= sent;
            }
            else
            {
                conn->unacked = 0;
            }

            if (conn->sent > sent)
            {
                conn->sent -= sent;
            }
            else
            {
                conn->sent = 0;
            }

            WRB_SENT(wrb) = 0;
            nllvdbg("REXMIT: wrb=%p sent=%u, conn unacked=%d sent=%d\n",
                    wrb, WRB_SENT(wrb), conn->unacked, conn->sent);

            /* Increment the retransmit count on this write buffer. */

            if (++WRB_NRTX(wrb) >= TCP_MAXRTX)
            {
                nlldbg("Expiring wrb=%p nrtx=%u\n", wrb, WRB_NRTX(wrb));

                /* The maximum retry count as been exhausted. Remove the write
                 * buffer at the head of the queue.
                 */

                tmp = (FAR struct tcp_wrbuffer_s *)sq_remfirst(&conn->write_q);
                DEBUGASSERT(tmp == wrb);
                UNUSED(tmp);

                /* And return the write buffer to the free list */

                tcp_wrbuffer_release(wrb);

                /* NOTE expired is different from un-ACKed, it is designed to
                 * represent the number of segments that have been sent,
                 * retransmitted, and un-ACKed, if expired is not zero, the
                 * connection will be closed.
                 *
                 * field expired can only be updated at TCP_ESTABLISHED state
                 */

                conn->expired++;
            }
        }

        /* Move all segments that have been sent but not ACKed to the write
         * queue again note, the un-ACKed segments are put at the head of the
         * write_q so they can be resent as soon as possible.
         */

        while ((entry = sq_remlast(&conn->unacked_q)) != NULL)
        {
            wrb = (FAR struct tcp_wrbuffer_s*)entry;
            uint16_t sent;

            /* Reset the number of bytes sent sent from the write buffer */

            sent = WRB_SENT(wrb);
            if (conn->unacked > sent)
            {
                conn->unacked -= sent;
            }
            else
            {
                conn->unacked = 0;
            }

            if (conn->sent > sent)
            {
                conn->sent -= sent;
            }
            else
            {
                conn->sent = 0;
            }

            WRB_SENT(wrb) = 0;
            nllvdbg("REXMIT: wrb=%p sent=%u, conn unacked=%d sent=%d\n",
                    wrb, WRB_SENT(wrb), conn->unacked, conn->sent);

            /* Free any write buffers that have exceed the retry count */

            if (++WRB_NRTX(wrb) >= TCP_MAXRTX)
            {
                nlldbg("Expiring wrb=%p nrtx=%u\n", wrb, WRB_NRTX(wrb));

                /* Return the write buffer to the free list */

                tcp_wrbuffer_release(wrb);

                /* NOTE expired is different from un-ACKed, it is designed to
                 * represent the number of segments that have been sent,
                 * retransmitted, and un-ACKed, if expired is not zero, the
                 * connection will be closed.
                 *
                 * field expired can only be updated at TCP_ESTABLISHED state
                 */

                conn->expired++;
                continue;
            }
            else
            {
                /* Insert the write buffer into the write_q (in sequence
                 * number order).  The retransmission will occur below
                 * when the write buffer with the lowest sequenc number
                 * is pulled from the write_q again.
                 */

                nllvdbg("REXMIT: Moving wrb=%p nrtx=%u\n", wrb, WRB_NRTX(wrb));

                psock_insert_segment(wrb, &conn->write_q);
            }
        }
    }

    /* Check if the outgoing packet is available (it may have been claimed
     * by a sendto interrupt serving a different thread).
     */

    if (dev->d_sndlen > 0)
    {
        /* Another thread has beat us sending data, wait for the next poll */

        return flags;
    }

    /* We get here if (1) not all of the data has been ACKed, (2) we have been
     * asked to retransmit data, (3) the connection is still healthy, and (4)
     * the outgoing packet is available for our use.  In this case, we are
     * now free to send more data to receiver -- UNLESS the buffer contains
     * unprocessed incoming data.  In that event, we will have to wait for the
     * next polling cycle.
     */

    if ((conn->tcpstateflags & TCP_ESTABLISHED) &&
            (flags & (TCP_POLL | TCP_REXMIT)) &&
            !(sq_empty(&conn->write_q)))
    {
        /* Check if the destination IP address is in the ARP table.  If not,
         * then the send won't actually make it out... it will be replaced with
         * an ARP request.
         *
         * NOTE 1: This could be an expensive check if there are a lot of
         * entries in the ARP table.
         *
         * NOTE 2: If we are actually harvesting IP addresses on incoming IP
         * packets, then this check should not be necessary; the MAC mapping
         * should already be in the ARP table in many cases.
         *
         * NOTE 3: If CONFIG_NET_ARP_SEND then we can be assured that the IP
         * address mapping is already in the ARP table.
         */

#if defined(CONFIG_NET_ETHERNET) && !defined(CONFIG_NET_ARP_IPIN) && \
    !defined(CONFIG_NET_ARP_SEND)
        if (arp_find(conn->ripaddr) != NULL)
#endif
        {
            FAR struct tcp_wrbuffer_s *wrb;
            size_t sndlen;

            /* Peek at the head of the write queue (but don't remove anything
             * from the write queue yet).  We know from the above test that
             * the write_q is not empty.
             */

            wrb = (FAR struct tcp_wrbuffer_s *)sq_peek(&conn->write_q);
            DEBUGASSERT(wrb);

            /* Get the amount of data that we can send in the next packet.
             * We will send either the remaining data in the buffer I/O
             * buffer chain, or as much as will fit given the MSS and current
             * window size.
             */

            sndlen = WRB_PKTLEN(wrb) - WRB_SENT(wrb);
            if (sndlen > tcp_mss(conn))
            {
                sndlen = tcp_mss(conn);
            }

            if (sndlen > conn->winsize)
            {
                sndlen = conn->winsize;
            }

            nllvdbg("SEND: wrb=%p pktlen=%u sent=%u sndlen=%u\n",
                    wrb, WRB_PKTLEN(wrb), WRB_SENT(wrb), sndlen);

            /* Set the sequence number for this segment.  If we are
             * retransmitting, then the sequence number will already
             * be set for this write buffer.
             */

            if (WRB_SEQNO(wrb) == (unsigned)-1)
            {
                WRB_SEQNO(wrb) = conn->isn + conn->sent;
            }

            /* The TCP stack updates sndseq on receipt of ACK *before*
             * this function is called. In that case sndseq will point
             * to the next unacknowledged byte (which might have already
             * been sent). We will overwrite the value of sndseq here
             * before the packet is sent.
             */

            tcp_setsequence(conn->sndseq, WRB_SEQNO(wrb) + WRB_SENT(wrb));

            /* Then set-up to send that amount of data with the offset
             * corresponding to the amount of data already sent. (this
             * won't actually happen until the polling cycle completes).
             */

            devif_iob_send(dev, WRB_IOB(wrb), sndlen, WRB_SENT(wrb));

            /* Remember how much data we send out now so that we know
             * when everything has been acknowledged.  Just increment
             * the amount of data sent. This will be needed in sequence
             * number calculations.
             */

            conn->unacked += sndlen;
            conn->sent    += sndlen;

            nllvdbg("SEND: wrb=%p nrtx=%u unacked=%u sent=%u\n",
                    wrb, WRB_NRTX(wrb), conn->unacked, conn->sent);

            /* Increment the count of bytes sent from this write buffer */

            WRB_SENT(wrb) += sndlen;

            nllvdbg("SEND: wrb=%p sent=%u pktlen=%u\n",
                    wrb, WRB_SENT(wrb), WRB_PKTLEN(wrb));

            /* Remove the write buffer from the write queue if the
             * last of the data has been sent from the buffer.
             */

            DEBUGASSERT(WRB_SENT(wrb) <= WRB_PKTLEN(wrb));
            if (WRB_SENT(wrb) >= WRB_PKTLEN(wrb))
            {
                FAR struct tcp_wrbuffer_s *tmp;

                nllvdbg("SEND: wrb=%p Move to unacked_q\n", wrb);

                tmp = (FAR struct tcp_wrbuffer_s *)sq_remfirst(&conn->write_q);
                DEBUGASSERT(tmp == wrb);
                UNUSED(tmp);

                /* Put the I/O buffer chain in the un-acked queue; the
                 * segment is waiting for ACK again
                 */

                psock_insert_segment(wrb, &conn->unacked_q);
            }

            /* Only one data can be sent by low level driver at once,
             * tell the caller stop polling the other connection.
             */

            flags &= ~TCP_POLL;
        }
    }

    /* Continue waiting */

    return flags;
}
/*	int *ts_present;
 *	u_int32_t *ts_val, *ts_ecr;
 */
static void
tcp_dooptions(struct tcpcb *tp, u_char *cp, int cnt, struct tcpiphdr *ti)
{
	u_int16_t mss;
	int opt, optlen;

	DEBUG_CALL("tcp_dooptions");
	DEBUG_ARGS((dfd," tp = %lx  cnt=%i \n", (long )tp, cnt));

	for (; cnt > 0; cnt -= optlen, cp += optlen) {
		opt = cp[0];
		if (opt == TCPOPT_EOL)
			break;
		if (opt == TCPOPT_NOP)
			optlen = 1;
		else {
			optlen = cp[1];
			if (optlen <= 0)
				break;
		}
		switch (opt) {

		default:
			continue;

		case TCPOPT_MAXSEG:
			if (optlen != TCPOLEN_MAXSEG)
				continue;
			if (!(ti->ti_flags & TH_SYN))
				continue;
			memcpy((char *) &mss, (char *) cp + 2, sizeof(mss));
			NTOHS(mss);
			(void) tcp_mss(tp, mss);	/* sets t_maxseg */
			break;

/*		case TCPOPT_WINDOW:
 *			if (optlen != TCPOLEN_WINDOW)
 *				continue;
 *			if (!(ti->ti_flags & TH_SYN))
 *				continue;
 *			tp->t_flags |= TF_RCVD_SCALE;
 *			tp->requested_s_scale = min(cp[2], TCP_MAX_WINSHIFT);
 *			break;
 */
/*		case TCPOPT_TIMESTAMP:
 *			if (optlen != TCPOLEN_TIMESTAMP)
 *				continue;
 *			*ts_present = 1;
 *			memcpy((char *) ts_val, (char *)cp + 2, sizeof(*ts_val));
 *			NTOHL(*ts_val);
 *			memcpy((char *) ts_ecr, (char *)cp + 6, sizeof(*ts_ecr));
 *			NTOHL(*ts_ecr);
 *
 */			/*
 *			 * A timestamp received in a SYN makes
 *			 * it ok to send timestamp requests and replies.
 *			 */
/*			if (ti->ti_flags & TH_SYN) {
 *				tp->t_flags |= TF_RCVD_TSTMP;
 *				tp->ts_recent = *ts_val;
 *				tp->ts_recent_age = tcp_now;
 *			}
 */			break;
		}
	}
}
Beispiel #7
0
void
tcp_dooptions( struct tcpcb *tp, u_char *cp, int cnt,
	struct tcpiphdr *ti, int *ts_present,
	u_long *ts_val, u_long *ts_ecr)
{
	u_short mss;
	int opt, optlen;

	for (; cnt > 0; cnt -= optlen, cp += optlen) {
		opt = cp[0];
		if (opt == TCPOPT_EOL)
			break;
		if (opt == TCPOPT_NOP)
			optlen = 1;
		else {
			optlen = cp[1];
			if (optlen <= 0)
				break;
		}
		switch (opt) {

		default:
			continue;

		case TCPOPT_MAXSEG:
			if (optlen != TCPOLEN_MAXSEG)
				continue;
			if (!(ti->ti_flags & TH_SYN))
				continue;
			bcopy((char *) cp + 2, (char *) &mss, sizeof(mss));
			NTOHS(mss);
			tcp_mss(tp, mss);	// sets t_maxseg
			break;

		case TCPOPT_WINDOW:
			if (optlen != TCPOLEN_WINDOW)
				continue;
			if (!(ti->ti_flags & TH_SYN))
				continue;
			tp->t_flags |= TF_RCVD_SCALE;
			tp->requested_s_scale = min(cp[2], TCP_MAX_WINSHIFT);
			break;

		case TCPOPT_TIMESTAMP:
			if (optlen != TCPOLEN_TIMESTAMP)
				continue;
			*ts_present = 1;
			bcopy((char *)cp + 2, (char *) ts_val, sizeof(*ts_val));
			NTOHL(*ts_val);
			bcopy((char *)cp + 6, (char *) ts_ecr, sizeof(*ts_ecr));
			NTOHL(*ts_ecr);

			// A timestamp received in a SYN makes
			// it ok to send timestamp requests and replies.
			if (ti->ti_flags & TH_SYN) {
				tp->t_flags |= TF_RCVD_TSTMP;
				tp->ts_recent = *ts_val;
				tp->ts_recent_age = g_tcp_now;
			}
			break;
		}
	}
}
Beispiel #8
0
static uint16_t sendfile_interrupt(FAR struct net_driver_s *dev, FAR void *pvconn,
                                   FAR void *pvpriv, uint16_t flags)
{
  FAR struct tcp_conn_s *conn = (FAR struct tcp_conn_s*)pvconn;
  FAR struct sendfile_s *pstate = (FAR struct sendfile_s *)pvpriv;
  int ret;

  nllvdbg("flags: %04x acked: %d sent: %d\n",
          flags, pstate->snd_acked, pstate->snd_sent);

  /* Check for a loss of connection */

  if ((flags & (TCP_CLOSE | TCP_ABORT | TCP_TIMEDOUT)) != 0)
    {
      /* Report not connected */

      nlldbg("Lost connection\n");

      net_lostconnection(pstate->snd_sock, flags);
      pstate->snd_sent = -ENOTCONN;
      goto end_wait;
    }

  /* We get here if (1) not all of the data has been ACKed, (2) we have been
   * asked to retransmit data, (3) the connection is still healthy, and (4)
   * the outgoing packet is available for our use.  In this case, we are
   * now free to send more data to receiver -- UNLESS the buffer contains
   * unprocessing incoming data.  In that event, we will have to wait for the
   * next polling cycle.
   */

  if ((flags & TCP_NEWDATA) == 0 && pstate->snd_sent < pstate->snd_flen)
    {
      /* Get the amount of data that we can send in the next packet */

      uint32_t sndlen = pstate->snd_flen - pstate->snd_sent;

      if (sndlen > tcp_mss(conn))
        {
          sndlen = tcp_mss(conn);
        }

      /* Check if we have "space" in the window */

      if ((pstate->snd_sent - pstate->snd_acked + sndlen) < conn->winsize)
        {
          uint32_t seqno;

          /* Then set-up to send that amount of data. (this won't actually
           * happen until the polling cycle completes).
           */

          ret = file_seek(pstate->snd_file,
                          pstate->snd_foffset + pstate->snd_sent, SEEK_SET);
          if (ret < 0)
            {
              int errcode = errno;
              nlldbg("failed to lseek: %d\n", errcode);
              pstate->snd_sent = -errcode;
              goto end_wait;
            }

          ret = file_read(pstate->snd_file, dev->d_snddata, sndlen);
          if (ret < 0)
            {
              int errcode = errno;
              nlldbg("failed to read from input file: %d\n", errcode);
              pstate->snd_sent = -errcode;
              goto end_wait;
            }

          dev->d_sndlen = sndlen;

          /* Set the sequence number for this packet.  NOTE:  uIP updates
           * sndseq on recept of ACK *before* this function is called.  In that
           * case sndseq will point to the next unacknowledge byte (which might
           * have already been sent).  We will overwrite the value of sndseq
           * here before the packet is sent.
           */

          seqno = pstate->snd_sent + pstate->snd_isn;
          nllvdbg("SEND: sndseq %08x->%08x len: %d\n", conn->sndseq, seqno, ret);

          tcp_setsequence(conn->sndseq, seqno);

          /* Check if the destination IP address is in the ARP table.  If not,
           * then the send won't actually make it out... it will be replaced with
           * an ARP request.
           *
           * NOTE 1: This could be an expensive check if there are a lot of entries
           * in the ARP table.  Hence, we only check on the first packet -- when
           * snd_sent is zero.
           *
           * NOTE 2: If we are actually harvesting IP addresses on incoming IP
           * packets, then this check should not be necessary; the MAC mapping
           * should already be in the ARP table in many cases.
           *
           * NOTE 3: If CONFIG_NET_ARP_SEND then we can be assured that the IP
           * address mapping is already in the ARP table.
           */

#if defined(CONFIG_NET_ETHERNET) && !defined(CONFIG_NET_ARP_IPIN) && \
    !defined(CONFIG_NET_ARP_SEND)
          if (pstate->snd_sent != 0 || arp_find(conn->ripaddr) != NULL)
#endif
            {
              /* Update the amount of data sent (but not necessarily ACKed) */

              pstate->snd_sent += sndlen;
              nllvdbg("pid: %d SEND: acked=%d sent=%d flen=%d\n", getpid(),
                     pstate->snd_acked, pstate->snd_sent, pstate->snd_flen);
            }
        }
      else
        {
          nlldbg("Window full, wait for ack\n");
          goto wait;
        }
    }

#ifdef CONFIG_NET_SOCKOPTS
  /* All data has been send and we are just waiting for ACK or re-transmit
   * indications to complete the send.  Check for a timeout.
   */

  if (sendfile_timeout(pstate))
    {
      /* Yes.. report the timeout */

      nlldbg("SEND timeout\n");
      pstate->snd_sent = -ETIMEDOUT;
      goto end_wait;
    }
#endif /* CONFIG_NET_SOCKOPTS */

  if (pstate->snd_sent >= pstate->snd_flen
      && pstate->snd_acked < pstate->snd_flen)
    {
      /* All data has been sent, but there are outstanding ACK's */

      goto wait;
    }

end_wait:

  /* Do not allow any further callbacks */

  pstate->snd_datacb->flags   = 0;
  pstate->snd_datacb->priv    = NULL;
  pstate->snd_datacb->event   = NULL;

  /* Wake up the waiting thread */

  sem_post(&pstate->snd_sem);

wait:
  return flags;
}
Beispiel #9
0
/*
 * Tcp output routine: figure out what should be sent and send it.
 */
int
tcp_output(PNATState pData, register struct tcpcb *tp)
{
    register struct socket *so = tp->t_socket;
    register long len, win;
    int off, flags, error;
    register struct mbuf *m = NULL;
    register struct tcpiphdr *ti;
    u_char opt[MAX_TCPOPTLEN];
    unsigned optlen, hdrlen;
    int idle, sendalot;
    int size = 0;

    LogFlowFunc(("ENTER: tcp_output: tp = %R[tcpcb793]\n", tp));

    /*
     * Determine length of data that should be transmitted,
     * and flags that will be used.
     * If there is some data or critical controls (SYN, RST)
     * to send, then transmit; otherwise, investigate further.
     */
    idle = (tp->snd_max == tp->snd_una);
    if (idle && tp->t_idle >= tp->t_rxtcur)
        /*
         * We have been idle for "a while" and no acks are
         * expected to clock out any data we send --
         * slow start to get ack "clock" running again.
         */
        tp->snd_cwnd = tp->t_maxseg;

again:
    sendalot = 0;
    off = tp->snd_nxt - tp->snd_una;
    win = min(tp->snd_wnd, tp->snd_cwnd);

    flags = tcp_outflags[tp->t_state];

    Log2((" --- tcp_output flags = 0x%x\n", flags));

    /*
     * If in persist timeout with window of 0, send 1 byte.
     * Otherwise, if window is small but nonzero
     * and timer expired, we will send what we can
     * and go to transmit state.
     */
    if (tp->t_force)
    {
        if (win == 0)
        {
            /*
             * If we still have some data to send, then
             * clear the FIN bit.  Usually this would
             * happen below when it realizes that we
             * aren't sending all the data.  However,
             * if we have exactly 1 byte of unset data,
             * then it won't clear the FIN bit below,
             * and if we are in persist state, we wind
             * up sending the packet without recording
             * that we sent the FIN bit.
             *
             * We can't just blindly clear the FIN bit,
             * because if we don't have any more data
             * to send then the probe will be the FIN
             * itself.
             */
            if (off < SBUF_LEN(&so->so_snd))
                flags &= ~TH_FIN;
            win = 1;
        }
        else
        {
            tp->t_timer[TCPT_PERSIST] = 0;
            tp->t_rxtshift = 0;
        }
    }

    len = min(SBUF_LEN(&so->so_snd), win) - off;
    if (len < 0)
    {
        /*
         * If FIN has been sent but not acked,
         * but we haven't been called to retransmit,
         * len will be -1.  Otherwise, window shrank
         * after we sent into it.  If window shrank to 0,
         * cancel pending retransmit and pull snd_nxt
         * back to (closed) window.  We will enter persist
         * state below.  If the window didn't close completely,
         * just wait for an ACK.
         */
        len = 0;
        if (win == 0)
        {
            tp->t_timer[TCPT_REXMT] = 0;
            tp->snd_nxt = tp->snd_una;
        }
    }
    if (len > tp->t_maxseg)
    {
        len = tp->t_maxseg;
        sendalot = 1;
    }
    if (SEQ_LT(tp->snd_nxt + len, tp->snd_una + SBUF_LEN(&so->so_snd)))
        flags &= ~TH_FIN;

    win = sbspace(&so->so_rcv);

    /*
     * Sender silly window avoidance.  If connection is idle
     * and can send all data, a maximum segment,
     * at least a maximum default-size segment do it,
     * or are forced, do it; otherwise don't bother.
     * If peer's buffer is tiny, then send
     * when window is at least half open.
     * If retransmitting (possibly after persist timer forced us
     * to send into a small window), then must resend.
     */
    if (len)
    {
        if (len == tp->t_maxseg)
            goto send;
        if ((1 || idle || tp->t_flags & TF_NODELAY) &&
                len + off >= SBUF_LEN(&so->so_snd))
            goto send;
        if (tp->t_force)
            goto send;
        if (len >= tp->max_sndwnd / 2 && tp->max_sndwnd > 0)
            goto send;
        if (SEQ_LT(tp->snd_nxt, tp->snd_max))
            goto send;
    }

    /*
     * Compare available window to amount of window
     * known to peer (as advertised window less
     * next expected input).  If the difference is at least two
     * max size segments, or at least 50% of the maximum possible
     * window, then want to send a window update to peer.
     */
    if (win > 0)
    {
        /*
         * "adv" is the amount we can increase the window,
         * taking into account that we are limited by
         * TCP_MAXWIN << tp->rcv_scale.
         */
        long adv = min(win, (long)TCP_MAXWIN << tp->rcv_scale);
        if (SEQ_GT(tp->rcv_adv, tp->rcv_nxt))
            adv -= tp->rcv_adv - tp->rcv_nxt;

        if (adv >= (long) (2 * tp->t_maxseg))
            goto send;
        if (2 * adv >= (long) SBUF_SIZE(&so->so_rcv))
            goto send;
    }

    /*
     * Send if we owe peer an ACK.
     */
    if (tp->t_flags & TF_ACKNOW)
        goto send;
    if (flags & (TH_SYN|TH_RST))
        goto send;
    if (SEQ_GT(tp->snd_up, tp->snd_una))
        goto send;
    /*
     * If our state indicates that FIN should be sent
     * and we have not yet done so, or we're retransmitting the FIN,
     * then we need to send.
     */
    if (   flags & TH_FIN
        && ((tp->t_flags & TF_SENTFIN) == 0 || tp->snd_nxt == tp->snd_una))
        goto send;

    /*
     * TCP window updates are not reliable, rather a polling protocol
     * using ``persist'' packets is used to insure receipt of window
     * updates.  The three ``states'' for the output side are:
     *      idle                    not doing retransmits or persists
     *      persisting              to move a small or zero window
     *      (re)transmitting        and thereby not persisting
     *
     * tp->t_timer[TCPT_PERSIST]
     *      is set when we are in persist state.
     * tp->t_force
     *      is set when we are called to send a persist packet.
     * tp->t_timer[TCPT_REXMT]
     *      is set when we are retransmitting
     * The output side is idle when both timers are zero.
     *
     * If send window is too small, there is data to transmit, and no
     * retransmit or persist is pending, then go to persist state.
     * If nothing happens soon, send when timer expires:
     * if window is nonzero, transmit what we can,
     * otherwise force out a byte.
     */
    if (   SBUF_LEN(&so->so_snd)
        && tp->t_timer[TCPT_REXMT] == 0
        && tp->t_timer[TCPT_PERSIST] == 0)
    {
        tp->t_rxtshift = 0;
        tcp_setpersist(tp);
    }

    /*
     * No reason to send a segment, just return.
     */
    tcpstat.tcps_didnuttin++;

    LogFlowFuncLeave();
    return (0);

send:
    LogFlowFunc(("send\n"));
    /*
     * Before ESTABLISHED, force sending of initial options
     * unless TCP set not to do any options.
     * NOTE: we assume that the IP/TCP header plus TCP options
     * always fit in a single mbuf, leaving room for a maximum
     * link header, i.e.
     *      max_linkhdr + sizeof (struct tcpiphdr) + optlen <= MHLEN
     */
    optlen = 0;
    hdrlen = sizeof (struct tcpiphdr);
    if (flags & TH_SYN)
    {
        tp->snd_nxt = tp->iss;
        if ((tp->t_flags & TF_NOOPT) == 0)
        {
            u_int16_t mss;

            opt[0] = TCPOPT_MAXSEG;
            opt[1] = 4;
            mss = RT_H2N_U16((u_int16_t) tcp_mss(pData, tp, 0));
            memcpy((caddr_t)(opt + 2), (caddr_t)&mss, sizeof(mss));
            optlen = 4;

#if 0
            if (   (tp->t_flags & TF_REQ_SCALE)
                && (   (flags & TH_ACK) == 0
                    || (tp->t_flags & TF_RCVD_SCALE)))
            {
                *((u_int32_t *) (opt + optlen)) = RT_H2N_U32(  TCPOPT_NOP << 24
                                                             | TCPOPT_WINDOW << 16
                                                             | TCPOLEN_WINDOW << 8
                                                             | tp->request_r_scale);
                optlen += 4;
            }
#endif
        }
    }

    /*
     * Send a timestamp and echo-reply if this is a SYN and our side
     * wants to use timestamps (TF_REQ_TSTMP is set) or both our side
     * and our peer have sent timestamps in our SYN's.
     */
#if 0
    if (   (tp->t_flags & (TF_REQ_TSTMP|TF_NOOPT)) == TF_REQ_TSTMP
        && (flags & TH_RST) == 0
        && (   (flags & (TH_SYN|TH_ACK)) == TH_SYN
            || (tp->t_flags & TF_RCVD_TSTMP)))
    {
        u_int32_t *lp = (u_int32_t *)(opt + optlen);

        /* Form timestamp option as shown in appendix A of RFC 1323. */
        *lp++ = RT_H2N_U32_C(TCPOPT_TSTAMP_HDR);
        *lp++ = RT_H2N_U32(tcp_now);
        *lp   = RT_H2N_U32(tp->ts_recent);
        optlen += TCPOLEN_TSTAMP_APPA;
    }
#endif
    hdrlen += optlen;

    /*
     * Adjust data length if insertion of options will
     * bump the packet length beyond the t_maxseg length.
     */
    if (len > tp->t_maxseg - optlen)
    {
        len = tp->t_maxseg - optlen;
        sendalot = 1;
    }

    /*
     * Grab a header mbuf, attaching a copy of data to
     * be transmitted, and initialize the header from
     * the template for sends on this connection.
     */
    if (len)
    {
        if (tp->t_force && len == 1)
            tcpstat.tcps_sndprobe++;
        else if (SEQ_LT(tp->snd_nxt, tp->snd_max))
        {
            tcpstat.tcps_sndrexmitpack++;
            tcpstat.tcps_sndrexmitbyte += len;
        }
        else
        {
            tcpstat.tcps_sndpack++;
            tcpstat.tcps_sndbyte += len;
        }

        size = MCLBYTES;
        if ((len + hdrlen + ETH_HLEN) < MSIZE)
            size = MCLBYTES;
        else if ((len + hdrlen + ETH_HLEN) < MCLBYTES)
            size = MCLBYTES;
        else if((len + hdrlen + ETH_HLEN) < MJUM9BYTES)
            size = MJUM9BYTES;
        else if ((len + hdrlen + ETH_HLEN) < MJUM16BYTES)
            size = MJUM16BYTES;
        else
            AssertMsgFailed(("Unsupported size"));
        m = m_getjcl(pData, M_NOWAIT, MT_HEADER, M_PKTHDR, size);
        if (m == NULL)
        {
/*          error = ENOBUFS; */
            error = 1;
            goto out;
        }
        m->m_data += if_maxlinkhdr;
        m->m_pkthdr.header = mtod(m, void *);
        m->m_len = hdrlen;

        /*
         * This will always succeed, since we make sure our mbufs
         * are big enough to hold one MSS packet + header + ... etc.
         */
#if 0
        if (len <= MHLEN - hdrlen - max_linkhdr)
        {
#endif
            sbcopy(&so->so_snd, off, (int) len, mtod(m, caddr_t) + hdrlen);
            m->m_len += len;
#if 0
        }
        else
        {
            m->m_next = m_copy(so->so_snd.sb_mb, off, (int) len);
            if (m->m_next == 0)
                len = 0;
        }
#endif
        /*
         * If we're sending everything we've got, set PUSH.
         * (This will keep happy those implementations which only
         * give data to the user when a buffer fills or
         * a PUSH comes in.)
         */
        if (off + len == SBUF_LEN(&so->so_snd))
            flags |= TH_PUSH;
    }
    else
    {
Beispiel #10
0
uint16_t AsyncClient::getMss(){
    if(_pcb)
        return tcp_mss(_pcb);
    return 0;
}