Ejemplo n.º 1
0
/*
 * Drop connection, reporting
 * the specified error.
 */
void
ipx_drop(struct ipxpcb *ipxp, int errno)
{
	struct socket *so = ipxp->ipxp_socket;

	IPX_LIST_LOCK_ASSERT();
	IPX_LOCK_ASSERT(ipxp);

	/*
	 * someday, in the IPX world
	 * we will generate error protocol packets
	 * announcing that the socket has gone away.
	 *
	 * XXX Probably never. IPX does not have error packets.
	 */
	/*if (TCPS_HAVERCVDSYN(tp->t_state)) {
		tp->t_state = TCPS_CLOSED;
		tcp_output(tp);
	}*/
	so->so_error = errno;
	ipx_pcbdisconnect(ipxp);
	soisdisconnected(so);
}
Ejemplo n.º 2
0
void
spx_input(struct mbuf *m, struct ipxpcb *ipxp)
{
	struct spxpcb *cb;
	struct spx *si = mtod(m, struct spx *);
	struct socket *so;
	struct spx spx_savesi;
	int dropsocket = 0;
	short ostate = 0;

	spxstat.spxs_rcvtotal++;
	KASSERT(ipxp != NULL, ("spx_input: ipxpcb == NULL"));

	/*
	 * spx_input() assumes that the caller will hold both the pcb list
	 * lock and also the ipxp lock.  spx_input() will release both before
	 * returning, and may in fact trade in the ipxp lock for another pcb
	 * lock following sonewconn().
	 */
	IPX_LIST_LOCK_ASSERT();
	IPX_LOCK_ASSERT(ipxp);

	cb = ipxtospxpcb(ipxp);
	KASSERT(cb != NULL, ("spx_input: cb == NULL"));

	if (ipxp->ipxp_flags & IPXP_DROPPED)
		goto drop;

	if (m->m_len < sizeof(*si)) {
		if ((m = m_pullup(m, sizeof(*si))) == NULL) {
			IPX_UNLOCK(ipxp);
			IPX_LIST_UNLOCK();
			spxstat.spxs_rcvshort++;
			return;
		}
		si = mtod(m, struct spx *);
	}
	si->si_seq = ntohs(si->si_seq);
	si->si_ack = ntohs(si->si_ack);
	si->si_alo = ntohs(si->si_alo);

	so = ipxp->ipxp_socket;
	KASSERT(so != NULL, ("spx_input: so == NULL"));

#ifdef MAC
	if (mac_socket_check_deliver(so, m) != 0)
		goto drop;
#endif

	if (so->so_options & SO_DEBUG || traceallspxs) {
		ostate = cb->s_state;
		spx_savesi = *si;
	}
	if (so->so_options & SO_ACCEPTCONN) {
		struct spxpcb *ocb = cb;

		so = sonewconn(so, 0);
		if (so == NULL)
			goto drop;

		/*
		 * This is ugly, but ....
		 *
		 * Mark socket as temporary until we're committed to keeping
		 * it.  The code at ``drop'' and ``dropwithreset'' check the
		 * flag dropsocket to see if the temporary socket created
		 * here should be discarded.  We mark the socket as
		 * discardable until we're committed to it below in
		 * TCPS_LISTEN.
		 *
		 * XXXRW: In the new world order of real kernel parallelism,
		 * temporarily allocating the socket when we're "not sure"
		 * seems like a bad idea, as we might race to remove it if
		 * the listen socket is closed...?
		 *
		 * We drop the lock of the listen socket ipxp, and acquire
		 * the lock of the new socket ippx.
		 */
		dropsocket++;
		IPX_UNLOCK(ipxp);
		ipxp = (struct ipxpcb *)so->so_pcb;
		IPX_LOCK(ipxp);
		ipxp->ipxp_laddr = si->si_dna;
		cb = ipxtospxpcb(ipxp);
		cb->s_mtu = ocb->s_mtu;		/* preserve sockopts */
		cb->s_flags = ocb->s_flags;	/* preserve sockopts */
		cb->s_flags2 = ocb->s_flags2;	/* preserve sockopts */
		cb->s_state = TCPS_LISTEN;
	}
	IPX_LOCK_ASSERT(ipxp);

	/*
	 * Packet received on connection.  Reset idle time and keep-alive
	 * timer.
	 */
	cb->s_idle = 0;
	cb->s_timer[SPXT_KEEP] = SPXTV_KEEP;

	switch (cb->s_state) {
	case TCPS_LISTEN:{
		struct sockaddr_ipx *sipx, ssipx;
		struct ipx_addr laddr;

		/*
		 * If somebody here was carying on a conversation and went
		 * away, and his pen pal thinks he can still talk, we get the
		 * misdirected packet.
		 */
		if (spx_hardnosed && (si->si_did != 0 || si->si_seq != 0)) {
			spx_istat.gonawy++;
			goto dropwithreset;
		}
		sipx = &ssipx;
		bzero(sipx, sizeof *sipx);
		sipx->sipx_len = sizeof(*sipx);
		sipx->sipx_family = AF_IPX;
		sipx->sipx_addr = si->si_sna;
		laddr = ipxp->ipxp_laddr;
		if (ipx_nullhost(laddr))
			ipxp->ipxp_laddr = si->si_dna;
		if (ipx_pcbconnect(ipxp, (struct sockaddr *)sipx, &thread0)) {
			ipxp->ipxp_laddr = laddr;
			spx_istat.noconn++;
			goto drop;
		}
		spx_template(cb);
		dropsocket = 0;		/* committed to socket */
		cb->s_did = si->si_sid;
		cb->s_rack = si->si_ack;
		cb->s_ralo = si->si_alo;
#define THREEWAYSHAKE
#ifdef THREEWAYSHAKE
		cb->s_state = TCPS_SYN_RECEIVED;
		cb->s_force = 1 + SPXT_KEEP;
		spxstat.spxs_accepts++;
		cb->s_timer[SPXT_KEEP] = SPXTV_KEEP;
		}
		break;

	 case TCPS_SYN_RECEIVED: {
		/*
		 * This state means that we have heard a response to our
		 * acceptance of their connection.  It is probably logically
		 * unnecessary in this implementation.
		 */
		if (si->si_did != cb->s_sid) {
			spx_istat.wrncon++;
			goto drop;
		}
#endif
		ipxp->ipxp_fport =  si->si_sport;
		cb->s_timer[SPXT_REXMT] = 0;
		cb->s_timer[SPXT_KEEP] = SPXTV_KEEP;
		soisconnected(so);
		cb->s_state = TCPS_ESTABLISHED;
		spxstat.spxs_accepts++;
		}
		break;

	case TCPS_SYN_SENT:
		/*
		 * This state means that we have gotten a response to our
		 * attempt to establish a connection.  We fill in the data
		 * from the other side, telling us which port to respond to,
		 * instead of the well-known one we might have sent to in the
		 * first place.  We also require that this is a response to
		 * our connection id.
		 */
		if (si->si_did != cb->s_sid) {
			spx_istat.notme++;
			goto drop;
		}
		spxstat.spxs_connects++;
		cb->s_did = si->si_sid;
		cb->s_rack = si->si_ack;
		cb->s_ralo = si->si_alo;
		cb->s_dport = ipxp->ipxp_fport =  si->si_sport;
		cb->s_timer[SPXT_REXMT] = 0;
		cb->s_flags |= SF_ACKNOW;
		soisconnected(so);
		cb->s_state = TCPS_ESTABLISHED;

		/*
		 * Use roundtrip time of connection request for initial rtt.
		 */
		if (cb->s_rtt) {
			cb->s_srtt = cb->s_rtt << 3;
			cb->s_rttvar = cb->s_rtt << 1;
			SPXT_RANGESET(cb->s_rxtcur,
			    ((cb->s_srtt >> 2) + cb->s_rttvar) >> 1,
			    SPXTV_MIN, SPXTV_REXMTMAX);
			    cb->s_rtt = 0;
		}
	}