Beispiel #1
0
int ipv4_arp_query(in_addr_t __ipaddr)
{
	struct route * rt;
	struct ifnet * ifn;
	int ret = -ENOENT;

	tcpip_net_lock();

	DCC_LOG1(LOG_TRACE, "route lookup %I", __ipaddr);

	/* lookup for the interface of the local address */
	if (((rt = __route_lookup(__ipaddr)) != NULL) && 
		(rt->rt_gateway == INADDR_ANY)) {

		/* get interface */
		ifn = rt->rt_ifn;

		/* ARP request */
		ret = ifn_arpquery(ifn, __ipaddr);
	}

	tcpip_net_unlock();

	return ret;
}
Beispiel #2
0
int ipv4_arp_lookup(in_addr_t __ipaddr, struct ipv4_arp * __arp)
{
	struct route * rt;
	struct ifnet * ifn;
	int ret = -ENOENT;

	tcpip_net_lock();

	/* lookup for the interface of the local address */
	if (((rt = __route_lookup(__ipaddr)) != NULL) && 
		(rt->rt_gateway = INADDR_ANY)) {
		void * hwaddr;

		/* get interface */
		ifn = rt->rt_ifn;
		hwaddr = ifn_arplookup(ifn, __ipaddr);
		if (hwaddr != NULL) {
			/* FIXME: other than ethernet interface ... */
			__arp->type = ARPHRD_ETHER;
			__arp->flags = 0;
			__arp->ipaddr = __ipaddr;
			__arp->ifn = ifn;
			memcpy(__arp->hwaddr, hwaddr, ETH_ADDR_LEN);
			ret = 0;
		}
	}

	tcpip_net_unlock();

	return ret;
}
Beispiel #3
0
/*
  return value:
    < 0 : error not processed.
    = 0 : ok processed, packet can be released.
    > 0 : ok processed, packet reused, don't release.
*/
int icmp_echoreplay(struct ifnet * __if, struct iphdr * __ip, 
					struct icmphdr * __icmp, int __len)
{
	struct ifnet * ifn;
	struct route * rt;
	unsigned int tmp;
//	int pkt_len;
	int ret;

	ICMP_PROTO_STAT_ADD(tx_ok, 1);

	__icmp->type = ICMP_ECHOREPLY;

	/* adjust the checksum */
    if (__icmp->chksum >= HTONS((0xffff - (ICMP_ECHO << 8)))) {
		__icmp->chksum += HTONS(ICMP_ECHO << 8) + 1;
	} else {
		 __icmp->chksum += + HTONS(ICMP_ECHO << 8);
	}

	if ((rt = __route_lookup(__ip->daddr)) == NULL) {
		DCC_LOG1(LOG_WARNING, "no route to host: %I", __ip->daddr);
		ICMP_PROTO_STAT_ADD(tx_drop, 1);
		return -1;
	}
	ifn = (struct ifnet *)rt->rt_ifn;

	/* swap addresses in the ip header */
	tmp = __ip->saddr;
	__ip->saddr = __ip->daddr;
	__ip->daddr = tmp;

#if 0
	struct iphdr * ip;
	pkt_len = sizeof(struct iphdr) + sizeof(struct icmphdr) + __len;
	ip = (struct iphdr *)ifn_mmap(ifn, pkt_len);
	if (ip == NULL) {
		return -1;
	}

	memcpy(ip, __ip, pkt_len);
#endif

	if ((ret = ip_output(ifn, rt, __ip)) < 0) {
//		ifn_munmap(ifn, ip);
		DCC_LOG(LOG_ERROR, "ip_output() fail!");
		ICMP_PROTO_STAT_ADD(tx_drop, 1);
		if (ret == -EAGAIN) {
			/* FIXME: non ethernet type interfaces */
			etharp_query_pending();
		}
		return -1;
	}
	
	return 1;
}
Beispiel #4
0
int icmp_send(struct iphdr * __ip, struct icmp * __icp, int __len)
{
	struct route * rt;
	uint32_t saddr;
	uint32_t daddr;
	int ret;

	ICMP_PROTO_STAT_ADD(tx_ok, 1);

	__len += ICMP_MINLEN;
	saddr = __ip->daddr;
	daddr = __ip->saddr;

	/* build the ip header (swap addresses) */
	iph_template(__ip, IPPROTO_ICMP, ip_defttl, ip_deftos);
	mk_iphdr(__ip, saddr, daddr, __len);

	__icp->icmp_chksum = 0;
	__icp->icmp_chksum = ~in_chksum(0, (uint8_t *)__icp, __len);

	DCC_LOG3(LOG_INFO, "ICMP %I > %I (%d)", 
			 __ip->saddr, __ip->daddr, __len); 

	if ((rt = __route_lookup(daddr)) == NULL) {
		ICMP_PROTO_STAT_ADD(tx_drop, 1);
		DCC_LOG1(LOG_WARNING, "no route to host: %I", daddr);
		return -1;
	}

	if ((ret = ip_output(rt->rt_ifn, rt, __ip)) < 0) {
		DCC_LOG(LOG_ERROR, "ip_output() fail!");
		/* XXX:  */
		ICMP_PROTO_STAT_ADD(tx_drop, 1);

		if (ret == -EAGAIN) {
			/* FIXME: non ethernet type interfaces */
			etharp_query_pending();
		}
		return -1;
	}

	return 0;
}
Beispiel #5
0
int icmp_echoreplay(struct ifnet * __if, struct iphdr * __ip,
                    struct icmphdr * __icmp, int __len)
{
    struct route * rt;
    uint32_t tmp;
    int ret;

    ICMP_PROTO_STAT_ADD(tx_ok, 1);

    __icmp->type = ICMP_ECHOREPLY;

    /* adjust the checksum */
    if (__icmp->chksum >= HTONS((0xffff - (ICMP_ECHO << 8)))) {
        __icmp->chksum += HTONS(ICMP_ECHO << 8) + 1;
    } else {
        __icmp->chksum += + HTONS(ICMP_ECHO << 8);
    }

    /* swap addresses in the ip header */
    tmp = __ip->daddr;
    __ip->daddr = __ip->saddr;
    __ip->saddr = tmp;

    if ((rt = __route_lookup(__ip->daddr)) == NULL) {
        DCC_LOG1(LOG_WARNING, "no route to host: %I", __ip->daddr);
        ICMP_PROTO_STAT_ADD(tx_drop, 1);
        return -1;
    }

    if ((ret = ip_output(rt, __ip)) < 0) {
        DCC_LOG(LOG_ERROR, "ip_output() fail!");
        ICMP_PROTO_STAT_ADD(tx_drop, 1);
        if (ret == -EAGAIN) {
            /* FIXME: non ethernet type interfaces */
            etharp_query_pending();
        }
        return -1;
    }

    return __len;
}
Beispiel #6
0
int raw_sendto(struct raw_pcb * __raw, void * __buf, int __len, 
			   const struct sockaddr_in * __sin)
{
	struct iphdr * ip;
	in_addr_t daddr;
	in_addr_t saddr;
	struct route * rt;
	uint8_t * ptr;
	int mtu;
	struct ifnet * ifn;

	DCC_LOG2(LOG_TRACE, "<%05x> len=%d", (int)__raw, __len);
	
	tcpip_net_lock();

	DCC_LOG2(LOG_INFO, "<%05x> lock [%d]", (int)__raw, net_mutex);
	
	if (__raw == NULL) {
		DCC_LOG(LOG_WARNING, "invalid pcb");
		tcpip_net_unlock();
		return -EFAULT;
	}

	if (__buf == NULL) {
		DCC_LOG(LOG_WARNING, "invalid buffer");
		tcpip_net_unlock();
		return -EFAULT;
	}

	daddr = __sin->sin_addr.s_addr;

	if ((rt = __route_lookup(daddr)) == NULL) {
		DCC_LOG1(LOG_WARNING, "no route to host: %I", daddr);
		tcpip_net_unlock();
		return -1;
	}

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

	if ((__len <= 0) || (__len > mtu)) {
		DCC_LOG3(LOG_WARNING, "<%05x> invalid length %d (max: %d)", (int)__raw, 
			__len, __raw->r_mtu);
		tcpip_net_unlock();
		return 0;
	}


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

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

	iph_template(ip, __raw->r_protocol, ip_defttl, __raw->r_tos);
	ptr = (uint8_t *)ip->opt;
	
	/* build the ip header */
	mk_iphdr(ip, saddr, daddr, __len);

	memcpy(ptr, __buf, __len);

	DCC_LOG3(LOG_TRACE, "IP %I > %I (%d)", ip->saddr, ip->daddr, __len); 

	if (ip_output(rt, ip) < 0) {
		DCC_LOG1(LOG_ERROR, "<%05x> ip_output() fail!", (int)__raw);
		/* if the reason to fail was an arp failure
		   try query an address pending for resolution ... */
		etharp_query_pending();
		tcpip_net_unlock();
		return -1;
	}

	tcpip_net_unlock();

	return __len;
}
Beispiel #7
0
struct tcp_pcb * tcp_passive_open(struct tcp_listen_pcb * mux, 
								  struct iphdr * iph,
								  struct tcphdr * th, 
								  unsigned int optlen)
{
	struct tcp_pcb * tp;
	struct route * rt;
	int new_head;
	int cond;

	new_head = mux->t_head + 1;
	if (new_head == mux->t_max)
		new_head = 0;

	if (mux->t_tail == new_head) {
		DCC_LOG(LOG_WARNING, "backlog limit");
		return NULL;
	}

	if ((cond = thinkos_cond_alloc()) < 0) {
		DCC_LOG(LOG_WARNING, "thinkos_cond_alloc()");
		return NULL;
	}

	if ((tp = tcp_pcb_new(&__tcp__.active)) == NULL) {
		DCC_LOG(LOG_WARNING, "tcp_pcb_new() failed!");
		return NULL;
	}

	/* Set up the new PCB. */
	tp->t_lport = th->th_dport;
	tp->t_laddr = iph->daddr;
	tp->t_fport = th->th_sport; 
	tp->t_faddr = iph->saddr;
	tp->t_cond = cond;
	/*
	 * TODO: max queue size...
	 */
	mbuf_queue_init(&tp->rcv_q);
	mbuf_queue_init(&tp->snd_q);

	if ((rt = __route_lookup(tp->t_faddr)) == NULL) {
		DCC_LOG(LOG_WARNING, "no route to host");			
		tp->t_maxseg = tcp_defmss;
	} else {
		/* default mss to the network interface mtu. */
		tp->t_route = rt;
		tp->t_maxseg = rt->rt_ifn->if_mtu - (sizeof(struct tcphdr) + 
											 sizeof(struct iphdr));
	}

	if (tp->t_maxseg > tcp_maxmss)
		tp->t_maxseg = tcp_maxmss;

	/* TODO: calculate the amount of space in receive window */
//	tp->rcv_wnd = MIN(tcp_maxrcv, tcp_maxwin);
	/* advertised window */
//	tp->t_adv_wnd = 0;

	if (optlen)
		tcp_parse_options(tp, th, th->th_opt, optlen);

	/* update the sequence numbers */
	tp->rcv_nxt = ntohl(th->th_seq) + 1;

	tp->snd_seq = (++__tcp__.iss << 20);
	tp->snd_off = 0;
	tp->snd_max = 0;

	/* set the connection-establishment timer to 75 seconds  */
	tp->t_conn_tmr = tcp_conn_est_tmo;
	tp->snd_wnd = ntohs(th->th_win);

	DCC_LOG2(LOG_INFO, "maxseg=%d snd_wnd=%d", 
			 tp->t_maxseg, tp->snd_wnd);			

	/* TODO: initialization of receive urgent pointer */

	tp->t_state = TCPS_SYN_RCVD;

	DCC_LOG3(LOG_INFO, "<%05x> %I:%d [SYN_RCVD]", 
			 (int)tp, tp->t_faddr, ntohs(tp->t_fport));

	/* XXX: don't respond now - the upper layer must call the tcp_accept()
	   function to send back the SYNC and finish handshaking. */
	tp->t_flags = TF_ACKNOW;

	/* insert into backlog */
	mux->t_backlog[mux->t_head] = tp;
	mux->t_head = new_head;
	thinkos_sem_post(mux->t_sem);

	return tp;
}
Beispiel #8
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;
}