Ejemplo n.º 1
0
void handle_arpreq(struct sr_instance *sr, struct sr_arpreq *req) {
	time_t now = time(NULL);
	if (difftime(now, req->sent) >= 0.9) {
		if (req->times_sent >= 5) {
			struct sr_packet *pkt_pending = req->packets;
			struct sr_if *interface = sr_get_interface(sr, pkt_pending->iface);
			while (pkt_pending) {
				icmp_handler(sr, pkt_pending->buf, 0, interface->ip, HOST_UNREACHABLE);
				pkt_pending = pkt_pending->next;
			}
			sr_arpreq_destroy(&(sr->cache), req);
		}
		else {
			int packet_len = sizeof(sr_ethernet_hdr_t) + sizeof(sr_arp_hdr_t);
			uint8_t *pkt = malloc(packet_len);

			struct sr_ethernet_hdr *eth_hdr = (struct sr_ethernet_hdr *)pkt;
			struct sr_if *interface = sr_get_interface(sr, req->packets->iface);
			uint8_t hrd_addr[ETHER_ADDR_LEN] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
			enum sr_ethertype eth_arp = ethertype_arp;
			enum sr_ethertype eth_ip = ethertype_ip;

			memcpy(eth_hdr->ether_dhost, hrd_addr, ETHER_ADDR_LEN);
			memcpy(eth_hdr->ether_shost, interface->addr, ETHER_ADDR_LEN);
			eth_hdr->ether_type = htons(eth_arp);

			struct sr_arp_hdr *arp_hdr = (struct sr_arp_hdr *)(sizeof(sr_ethernet_hdr_t) + pkt);
			enum sr_arp_hrd_fmt hrd_eth = arp_hrd_ethernet;
			enum sr_arp_opcode arp_op_req = arp_op_request;

			arp_hdr->ar_hrd = htons(hrd_eth);
			arp_hdr->ar_pro = htons(eth_ip);
			arp_hdr->ar_hln = ETHER_ADDR_LEN;
			arp_hdr->ar_pln = 4;
			arp_hdr->ar_op = htons(arp_op_req);
			arp_hdr->ar_sip = interface->ip;
			arp_hdr->ar_tip = req->ip;
			memcpy(arp_hdr->ar_sha, interface->addr, ETHER_ADDR_LEN);
			memcpy(arp_hdr->ar_tha, hrd_addr, ETHER_ADDR_LEN);

			printf("Sending Packets.. [3].\n");

			sr_send_packet(sr, pkt, packet_len, interface->name);
			free(pkt);
			req->sent = now;
			req->times_sent++;
		}
	}
}
Ejemplo n.º 2
0
Archivo: ip.c Proyecto: lehoon/bvrouter
/*
 * @brief Handles ip packets
 * @param skb Pointer to the skb, whose data pointer must be set to ip header.
 * @return 0 on success. -1 on failure. The packet is freed in both cases
 */
int ip_handler(struct sk_buff *skb)
{
	int ret = -1;
	struct ip_hdr *iph;
	struct pal_dip *dip;

	if (!skb_ip_csum_ok(skb)) {
		PAL_DEBUG("skb ip csum error\n");
		pal_cur_thread_conf()->stats.ip.csum_err++;
		goto free_out;
	}

	iph = skb_ip_header(skb);

	if ((unsigned)iph->ihl < 5 || skb_len(skb) < (unsigned)iph->ihl * 4) {
		pal_cur_thread_conf()->stats.ip.trunc_pkts++;
		goto free_out;
	}

	dip = pal_ipg_find_ip(iph->daddr);
	if (dip == NULL) {
		pal_cur_thread_conf()->stats.ip.unknown_dst++;
		/* TODO: use default ip group. */
		PAL_DEBUG("dip "NIPQUAD_FMT" not found\n", NIPQUAD(iph->daddr));
		goto free_out;
	}

	switch (dip->type) {
	case PAL_DIP_USER:
		skb_pull(skb, iph->ihl * 4);
		skb_reset_l4_header(skb);
		switch (iph->protocol) {
		case PAL_IPPROTO_TCP:
			ret = tcp_dispatch(skb, dip);
			break;
		case PAL_IPPROTO_UDP:
			ret = udp_dispatch(skb, dip);
			break;
		case PAL_IPPROTO_ICMP:
			if (dip->ipg->flags & PAL_IPG_F_HANDLEICMP) {
				ret = icmp_dispatch(skb, dip);
			} else {
				ret = icmp_handler(skb);
			}
			break;
		default:
			pal_cur_thread_conf()->stats.ip.unknown_proto_pkts++;
			pal_cur_thread_conf()->stats.ip.unknown_proto_bytes += skb_l2_len(skb);
			PAL_DEBUG("UNKNOWN IP PKTS\n");
			if (dip->ipg->flags & PAL_IPG_F_HANDLEUNKNOWIPPROTO) {
				ret = dispatch_pkt(skb, dip);
			} else {
				ret = -1;
			}
			break;
		}

		if (ret >= 0) {
			pal_ipg_put_ip(dip->ip);
			return 0;
		}

		goto putdip_out;

	case PAL_DIP_VNIC:
		if (dip->port != skb->recv_if) {
			pal_cur_thread_conf()->stats.tap.port_err++;
			PAL_DEBUG("got a packet for wrong vnic\n");
			goto putdip_out;
		}

		/* push the data pointer to include the ethernet header */
		skb_push(skb, sizeof(struct eth_hdr));
		if (pal_send_to_vnic(dip->port, skb) == 0) {
            pal_skb_free(skb);
		    pal_ipg_put_ip(dip->ip);
			return 0;
		}
		goto putdip_out;

	default:
		pal_cur_thread_conf()->stats.ip.unknown_dst++;
		PAL_DEBUG("unknown\n");
		goto putdip_out;
	}

putdip_out:
	pal_ipg_put_ip(dip->ip);

free_out:
	pal_skb_free(skb);

	return ret;
}