Пример #1
0
int tcp_bind(struct tcp_pcb * __tp, in_addr_t __addr, uint16_t __port) 
{
	if (__tp == NULL) {
		DCC_LOG(LOG_WARNING, "NULL pointer");
		/* FIXME: not a socket? The semantic here is not exactly the same
		   as the sockets API. */
		return -ENOTSOCK;
	}

	if (pcb_find((struct pcb *)__tp, &__tcp__.closed) < 0) {
		DCC_LOG1(LOG_ERROR, "<%04x> pcb_find()", (int)__tp);
		return -ENOTSOCK;
	}

	tcpip_net_lock();

	if (__port == 0) {
		do {
			/* generate an ephemeral port number from 1024 to 33791 */
			__port = ntohs(((__tcp__.port_seq++) & 0x7fff) + 1024);
		} while (!can_bind(__addr, __port));
	} else {
		if (!can_bind(__addr, __port)) {
		DCC_LOG3(LOG_WARNING, "<%04x> %I:%d in use", 
				 (int)__tp, __addr, ntohs(__port));
			return -EADDRINUSE;
		}
	}

	DCC_LOG3(LOG_TRACE, "<%05x> %I:%d", (int)__tp, __addr, ntohs(__port));

	__tp->t_lport = __port;
	__tp->t_laddr = __addr;

	tcpip_net_unlock();

	return 0;
}
Пример #2
0
int tcp_close(struct tcp_pcb * __tp)
{
	int ret;

	if (__tp == NULL) {
		DCC_LOG(LOG_WARNING, "NULL pointer");
		return -1;
	}

	tcpip_net_lock();

#ifdef ENABLE_SANITY
	if ((pcb_find((struct pcb *)__tp, &__tcp__.active) < 0) && 
		(pcb_find((struct pcb *)__tp, &__tcp__.listen) < 0) &&
		pcb_find((struct pcb *)__tp, &__tcp__.closed) < 0) {
		DBG(DBG_ERROR, "<%05x> pcb_find()", (int)__tp);
		tcpip_net_unlock();
		return -1;
	}
#endif

	switch(__tp->t_state) {
		case TCPS_LISTEN: {
			ret = tcp_pcb_free(__tp);
			tcpip_net_unlock();
			return ret;
		}

		case TCPS_TIME_WAIT:
		case TCPS_CLOSED:  
		case TCPS_SYN_SENT:
			DCC_LOG2(LOG_TRACE, "<%05x> [%s]", (int)__tp, 
					 __tcp_state[__tp->t_state]);
			if (__tp->t_cond >= 0) {
				__os_cond_free(__tp->t_cond);
				__tp->t_cond = -1;
			}
			ret = tcp_pcb_free(__tp);
			tcpip_net_unlock();
			return ret;

		/* active close */
		case TCPS_SYN_RCVD:
		case TCPS_ESTABLISHED:
			/* Close the receive window */
			/*
			 * XXX: if we close the receive window we may stuck at
			 * FIN_WAIT_2 state...
			 */
//			__tp->rcv_wnd = 0;
			__tp->t_state = TCPS_FIN_WAIT_1;
			DCC_LOG1(LOG_TRACE, "<%05x> [FIN_WAIT_1]", (int)__tp);
			break;

		/* passive close */
		case TCPS_CLOSE_WAIT:
			__tp->t_state = TCPS_LAST_ACK;
			DCC_LOG1(LOG_TRACE, "<%05x> [LAST_ACK]", (int)__tp);
			/* discard the data 
			 *  TODO: check whether both buffers must be 
			 * released or not. Probably they where released already.
			 */
			/* discards unsent data */
			__tp->snd_off -= __tp->snd_q.len;
			__tp->snd_max -= __tp->snd_q.len;
			mbuf_queue_free(&__tp->snd_q);
			mbuf_queue_free(&__tp->rcv_q);
			/*  notify the upper layer that we are closed */
			break;

		default: {
			DCC_LOG2(LOG_ERROR, "<%05x> state=[%s]", (int)__tp, 
				__tcp_state[__tp->t_state]);
			tcpip_net_unlock();
			return -1;
		}

	}

	/* ACK now */
	__tp->t_flags |= TF_ACKNOW;
	/* schedule output */
	tcp_output_sched(__tp);

	tcpip_net_unlock();
	return 0;
}
Пример #3
0
int tcp_recv(struct tcp_pcb * __tp, void * __buf, int __len)
{
    int n;

    if (__tp == NULL) {
        DCC_LOG(LOG_WARNING, "NULL pointer");
        return -1;
    }

    if (__len == 0) {
        /* invalid argument */
        DCC_LOG(LOG_WARNING, "invalid argument");
        return -1;
    }

    tcpip_net_lock();

#ifdef ENABLE_SANITY_CHECK
    if (pcb_find((struct pcb *)__tp, &__tcp__.active) < 0) {
        DCC_LOG1(LOG_ERROR, "<%05x> pcb_find()", (int)__tp);
        tcpip_net_unlock();
        return -1;
    }
#endif

    for (;;) {
        if ((__tp->t_state == TCPS_CLOSED)) {
            DCC_LOG(LOG_WARNING, "closed!");
            tcpip_net_unlock();
            return -1;
        }

        if ((__tp->t_state == TCPS_TIME_WAIT) ||
                (__tp->t_state == TCPS_CLOSING) ||
                (__tp->t_state == TCPS_LAST_ACK)) {
            tcpip_net_unlock();
            return 0;
        }

        if (__tp->rcv_q.len)
            break;

        if (__tp->t_state == TCPS_CLOSE_WAIT) {
            tcpip_net_unlock();
            return 0;
        }

        DCC_LOG2(LOG_MSG, "<%05x> wait [%d]", (int)__tp, __tp->t_cond);

        thinkos_cond_wait(__tp->t_cond, net_mutex);
    }

    n = mbuf_queue_remove(&__tp->rcv_q, __buf, __len);

    DCC_LOG1(LOG_INFO, "len=%d", n);

    /* Half close: don't reopen the receiver window, i'm not sure
       whether it is a rule break or not, but it may prevent
       resources been consumed by an about to die connection! */
    if ((__tp->t_state == TCPS_FIN_WAIT_1) ||
            (__tp->t_state == TCPS_FIN_WAIT_2)) {
        DCC_LOG1(LOG_TRACE, "<%05x> FIN_WAIT", (int)__tp);
        tcpip_net_unlock();
        return n;
    }

    /* XXX: revisit this ... */
//	if ((__tp->rcv_q.len == 0) || (__tp->t_flags & TF_DELACK)) {
    if ((__tp->rcv_q.len == 0)) {
        if (__tp->t_flags & TF_DELACK) {
            __tp->t_flags |= TF_ACKNOW;
        }

        DCC_LOG(LOG_INFO, "empty queue, call tcp_out.");

        tcp_output_sched(__tp);
    }

    tcpip_net_unlock();

    return n;
}
Пример #4
0
int tcp_send(struct tcp_pcb * __tp, const void * __buf, 
	int __len, int __flags)
{
	uint8_t * src;
	int rem;
	int n;
	int m;

	if (__tp == NULL) {
		DCC_LOG(LOG_WARNING, "NULL pointer");
		return -1;
	}

#ifdef ENABLE_SANITY
	if (__buf == NULL) {
		DCC_LOG1(LOG_WARNING, "<%04x> NULL pointer:", (int)__tp);
		return -1;
	}

	if (__len < 0) {
		DCC_LOG2(LOG_WARNING, "<%04x> invalid length: %d", (int)__tp, __len);
		return -1;
	}
#endif

	tcpip_net_lock();

#ifdef ENABLE_SANITY
	if (pcb_find((struct pcb *)__tp, &__tcp__.active) < 0) {
		DCC_LOG(LOG_ERROR, "<%04x> pcb_find()", (int)__tp);
		tcpip_net_unlock();
		return -1;
	}
#endif

	DCC_LOG3(LOG_INFO, "<%05x> buf=%05x len=%d", (int)__tp, (int)__buf, __len);

	src = (uint8_t *)__buf;
	rem = __len;

again:
	if (__tp->t_state != TCPS_ESTABLISHED)  {
/*
	if ((__tp->t_state != TCPS_ESTABLISHED) &&
		(__tp->t_state != TCPS_CLOSE_WAIT)) {
*/
		DCC_LOG2(LOG_WARNING, "<%05x> [%s]", (int)__tp, 
				 __tcp_state[__tp->t_state]);

		if (__tp->t_state == TCPS_SYN_RCVD) {
			DCC_LOG1(LOG_TRACE, "<%05x> wait", (int)__tp);
			__os_cond_wait(__tp->t_cond, net_mutex);
			DCC_LOG2(LOG_TRACE, "<%05x> again [%s]",
					 (int)__tp, __tcp_state[__tp->t_state]);
			goto again;
		} 
		

		DCC_LOG(LOG_TRACE, "done.");

		tcpip_net_unlock();
		return -1;
	}

	while (rem) {
		/* buffer limit ... */
		m = tcp_maxsnd - __tp->snd_q.len;
		if (m <= 0) {
			DCC_LOG1(LOG_INFO, "<%05x> queue limit", (int)__tp);
			__tp->t_flags |= TF_ACKNOW;
			
			DCC_LOG(LOG_INFO, "output request.");
			tcp_output_sched(__tp);
		
			DCC_LOG(LOG_INFO, "waiting for buffer space.");
			__os_cond_wait(__tp->t_cond, net_mutex);

			goto again;
		}

		m = MIN(m, rem);

		if ((n = mbuf_queue_add(&__tp->snd_q, src, m)) == 0) {
			DCC_LOG(LOG_TRACE, "mbuf_wait...");
			mbuf_wait(net_mutex);
			goto again;
		}
		rem -= n;
		src += n;
	}

#if 0
	/* FIXME: Set retransmit timer if not currently set,
	   and not doing an ack or a keepalive probe.
	   Initial value for retransmit is smoothed
	   round-trip time + 2 * round-trip time variance.
	   Initialize counter which is used for backoff
	   :of retransmit time. */
	if ((__tp->t_rxmt_tmr == 0) && (__tp->snd_una != 0)) {
		__tp->t_rxmt_tmr = tcp_rxmtintvl[0];
		__tp->t_rxmt_cnt = 0;
		/* tp->t_flags &= ~TF_IDLE; */
	}
#endif

	if (__len > 0) {
		/* TCP_SEND_NOWAIT flag set or one maximum segment size pending for
		   send then send now */
		if ((__flags & TCP_SEND_NOWAIT) || 
			((__tp->snd_q.len - (int)__tp->snd_q.offs) >= __tp->t_maxseg)) {
			DCC_LOG(LOG_INFO, "output request.");
			tcp_output_sched(__tp);
//			if (tcp_output(__tp) < 0) {
				/* if the reason to fail was an arp failure
				   try query an address pending for resolution ... */
//				arp_query_pending();
//			}
		} else  {
			__tp->t_flags |= TF_DELACK;
		}
	}

	DCC_LOG(LOG_INFO, "done.");

	tcpip_net_unlock();

	return __len;
}
Пример #5
0
int udp_sendto(struct udp_pcb * __up, void * __buf, int __len, 
			   const struct sockaddr_in * __sin)
{
	struct iphdr * ip;
	struct udphdr * uh;
	in_addr_t daddr;
	int dport;
	in_addr_t saddr;
	struct route * rt;
#if (ENABLE_NET_UDP_CHECKSUM)
	unsigned int sum;
#endif
	uint8_t * ptr;
	int mtu;
	struct ifnet * ifn;
	int ret;
	int retry = 0;

	DCC_LOG2(LOG_INFO, "<%05x> len=%d", (int)__up, __len);
	
	if (__up == NULL) {
		DCC_LOG1(LOG_WARNING, "<%05x> invalid pcb", (int)__up);
		return -EFAULT;
	}

	if (__buf == NULL) {
		DCC_LOG1(LOG_WARNING, "<%05x> invalid buffer", (int)__up);
		return -EFAULT;
	}

	tcpip_net_lock();

#if (ENABLE_NET_SANITY_CHECK)
	if (pcb_find((struct pcb *)__up, &__udp__.pcb) < 0) {
		DCC_LOG1(LOG_ERROR, "<%05x> pcb_find()", (int)__up);
		tcpip_net_unlock();
		/* TODO: errno */
		return -1;
	}
#endif

	if ((__up->u_lport) == 0) {
		DCC_LOG1(LOG_WARNING, "<%05x> not bound", (int)__up);
		tcpip_net_unlock();
		/* TODO: errno */
		return -3;
	}

	if (__sin == NULL) {
		if ((dport = __up->u_fport) == 0) {
			DCC_LOG1(LOG_WARNING, "<%05x> connection refused", (int)__up);
			tcpip_net_unlock();
			return -ECONNREFUSED;
		}

		if ((daddr = __up->u_faddr) == INADDR_ANY) {
			DCC_LOG1(LOG_WARNING, "<%05x> not connected", (int)__up);
			tcpip_net_unlock();
			return -ENOTCONN;
		}
	} else {
		if ((dport = __sin->sin_port) == 0) {
			DCC_LOG1(LOG_WARNING, "<%05x> invalid port", (int)__up);
			tcpip_net_unlock();
			return -ECONNREFUSED;
		}

		if ((daddr = __sin->sin_addr.s_addr) == INADDR_ANY) {
			DCC_LOG1(LOG_WARNING, "<%05x> invalid address", (int)__up);
			tcpip_net_unlock();
			return -EDESTADDRREQ;
		}
	}

	if ((rt = __route_lookup(daddr)) == NULL) {
		DCC_LOG2(LOG_WARNING, "<%05x> no route to host: %I", (int)__up, daddr);
		tcpip_net_unlock();
		UDP_PROTO_STAT_ADD(tx_drop, 1);
		UDP_PROTO_STAT_ADD(tx_err, 1);
		return -EHOSTUNREACH;
	}

	ifn = (struct ifnet *)rt->rt_ifn;
	mtu = ifn->if_mtu - sizeof(struct iphdr);

	if ((__len <= 0) || (__len > mtu)) {
		DCC_LOG3(LOG_WARNING, "<%04x> invalid length %d (max: %d)", 
				 (int)__up, __len, mtu);
		tcpip_net_unlock();
		/* TODO: errno */
		return -7;
	}

	/* get the source address */
	if ((saddr = __up->u_laddr) == INADDR_ANY) {
		saddr = ifn->if_ipv4_addr;
	}

again:
	ip = (struct iphdr *)ifn_mmap(ifn, sizeof(struct iphdr) + 
								  sizeof(struct udphdr) + __len);

	if (ip == NULL) {
		DCC_LOG1(LOG_WARNING, "<%04x> ifn_mmap() fail", (int)__up);
		tcpip_net_unlock();
		/* TODO: errno */
		return -1;
	}
	DCC_LOG2(LOG_TRACE, "<%05x> ip=%p", (int)__up, ip);

	iph_template(ip, IPPROTO_UDP, udp_def_ttl, udp_def_tos);
	uh = (struct udphdr *)ip->opt;
	
	/* build the ip header */
	ip = mk_iphdr(ip, saddr, daddr, sizeof(struct udphdr) + __len);

	/* fill the udp header fields */
	uh = (struct udphdr *)ip->opt;
	uh->dport = dport;
	uh->sport = __up->u_lport;
	uh->len = htons(__len + sizeof(struct udphdr));
#if (ENABLE_NET_UDP_CHECKSUM)
	/* initialize the udp checksum */
	sum = uh->len << 1;
	sum += uh->dport;
	sum += uh->sport;
	sum += (IPPROTO_UDP << 8);
	sum += ((uint16_t *)(void *)&(ip->saddr))[0] + 
		((uint16_t *)(void *)&(ip->saddr))[1];
	sum += ((uint16_t *)(void *)&(ip->daddr))[0] + 
		((uint16_t *)(void *)&(ip->daddr))[1];
#endif
	
	ptr = (uint8_t *)uh + sizeof(struct udphdr);
	memcpy(ptr, __buf, __len);

#if (ENABLE_NET_UDP_CHECKSUM)
	if (__len) {
		sum = in_chksum(sum, ptr, __len);
	}
	uh->chksum = ~sum;
#else
	uh->chksum = 0;
#endif

#if 0
	DCC_LOG(LOG_INFO, "IP %d.%d.%d.%d:%d > %d.%d.%d.%d:%d: %d", 
		IP4_ADDR1(ip->saddr), IP4_ADDR2(ip->saddr), IP4_ADDR3(ip->saddr), 
		IP4_ADDR4(ip->saddr), ntohs(uh->sport), IP4_ADDR1(ip->daddr), 
		IP4_ADDR2(ip->daddr), IP4_ADDR3(ip->daddr), IP4_ADDR4(ip->daddr), 
		ntohs(uh->dport), ntohs(uh->len)); 
#endif

	if ((ret = ip_output(ifn, rt, ip)) < 0) {
		ifn_munmap(ifn, ip);
		/* if the reason to fail was an arp failure
		   try query an address pending for resolution ... */
		if ((ret == -EAGAIN) && (retry < 10)) {
			etharp_query_pending();
			tcpip_net_unlock();
			DCC_LOG2(LOG_WARNING, "<%05x> again, retry=%d!", (int)__up, retry);
			thinkos_sleep(10 + retry * 10);
			retry++;
			tcpip_net_lock();
			goto again;
		}
		DCC_LOG1(LOG_ERROR, "<%05x> ip_output() fail!", (int)__up);
		UDP_PROTO_STAT_ADD(tx_drop, 1);
	} else {
		UDP_PROTO_STAT_ADD(tx_ok, 1);
		DCC_LOG5(LOG_INFO, "IP %I:%d > %I:%d: %d", 
				 ip->saddr, ntohs(uh->sport), ip->daddr, 
				 ntohs(uh->dport), ntohs(uh->len)); 
#if (LOG_LEVEL < LOG_INFO)
		DCC_LOG(LOG_INFO, "sent.");
#endif
		ret = __len;
	}

	tcpip_net_unlock();

	return ret;
}