Exemplo n.º 1
0
static int icmp_hnd_dest_unreach(const struct icmphdr *icmph,
		const struct icmpbody_dest_unreach *dest_unreach,
		struct sk_buff *skb) {
	size_t len;

	switch (icmph->code) {
	default:
		skb_free(skb);
		return 0; /* error: bad code */
	case ICMP_NET_UNREACH:
	case ICMP_HOST_UNREACH:
	case ICMP_PROT_UNREACH:
	case ICMP_PORT_UNREACH:
	case ICMP_FRAG_NEEDED:
	case ICMP_SR_FAILED:
		break;
	}

	len = ip_data_length(ip_hdr(skb));
	if (sizeof *icmph + sizeof *dest_unreach > len) {
		skb_free(skb);
		return 0; /* error: invalid length */
	}
	len -= sizeof *icmph + sizeof *dest_unreach;

	return icmp_notify_an_error(icmph, &dest_unreach->msg[0], len,
			icmph->code == ICMP_FRAG_NEEDED
				? ntohs(dest_unreach->mtu) : 0,
			icmph->code == ICMP_FRAG_NEEDED, skb);
}
Exemplo n.º 2
0
static int icmp_hnd_param_prob(const struct icmphdr *icmph,
		const struct icmpbody_param_prob *param_prob,
		struct sk_buff *skb) {
	size_t len;

	switch (icmph->code) {
	default:
		skb_free(skb);
		return 0; /* error: bad code */
	case ICMP_PTR_ERROR:
	case ICMP_PTR_UNUSED:
		break;
	}

	len = ip_data_length(ip_hdr(skb));
	if (sizeof *icmph + sizeof *param_prob > len) {
		skb_free(skb);
		return 0; /* error: invalid length */
	}
	len -= sizeof *icmph + sizeof *param_prob;

	return icmp_notify_an_error(icmph, &param_prob->msg[0], len,
			icmph->code == ICMP_PTR_ERROR ? param_prob->ptr : 0,
			(icmph->code == ICMP_PTR_ERROR)
				&& (param_prob->ptr < IP_HEADER_SIZE(
						(const struct iphdr *)&param_prob->msg[0])),
			skb);
}
Exemplo n.º 3
0
static int icmp_hnd_timestamp_request(const struct icmphdr *icmph,
		const struct icmpbody_timestamp *tstamp_req,
		struct sk_buff *skb) {
	uint32_t msec_since_12am;
	struct icmpbody_timestamp *tstamp_rep;

	if (icmph->code != 0) {
		skb_free(skb);
		return 0; /* error: bad code */
	}

	if (sizeof *icmph + sizeof *tstamp_req
			!= ip_data_length(ip_hdr(skb))) {
		skb_free(skb);
		return 0; /* error: invalid length */
	}

	msec_since_12am = (ktime_get_ns() / NSEC_PER_MSEC) % (
				SEC_PER_DAY * MSEC_PER_SEC);

	tstamp_rep = &icmp_hdr(skb)->body[0].timestamp;
	tstamp_rep->orig = tstamp_req->trans;
	tstamp_rep->recv = tstamp_rep->trans = htonl(msec_since_12am);

	return icmp_send(ICMP_TIMESTAMP_REPLY, 0, tstamp_rep,
			sizeof *tstamp_rep, skb);
}
Exemplo n.º 4
0
static int icmp_send(uint8_t type, uint8_t code, const void *body,
		size_t body_sz, struct sk_buff *skb) {
	int ret;
	size_t size;

	if (ip_out_ops == NULL) {
		skb_free(skb);
		return -ENOSYS; /* error: not implemented */
	}

	size = sizeof *icmp_hdr(skb) + body_sz;
	assert(ip_out_ops->make_pack != NULL);
	ret = ip_out_ops->make_pack(NULL, NULL, &size, &skb);
	if (ret != 0) {
		skb_free(skb);
		return ret; /* error: see ret */
	}
	else if (size != sizeof *icmp_hdr(skb) + body_sz) {
		skb_free(skb);
		return -EMSGSIZE; /* error: message is too big */
	}

	icmp_build(icmp_hdr(skb), type, code, body, body_sz);
	icmp_set_check_field(icmp_hdr(skb), ip_hdr(skb));

	assert(ip_out_ops->snd_pack != NULL);
	return ip_out_ops->snd_pack(skb);
}
Exemplo n.º 5
0
static int icmp_hnd_echo_request(const struct icmphdr *icmph,
		const struct icmpbody_echo *echo_req,
		struct sk_buff *skb) {
	size_t len;
	struct icmpbody_echo *echo_rep;

	if (icmph->code != 0) {
		log_error("bad code 0x%x", icmph->code);
		skb_free(skb);
		return 0; /* error: bad code */
	}

	len = ip_data_length(ip_hdr(skb));
	if (sizeof *icmph + sizeof *echo_req > len) {
		log_error("invalid length %zu", len);
		skb_free(skb);
		return 0; /* error: invalid length */
	}
	len -= sizeof *icmph + sizeof *echo_req;

	echo_rep = &icmp_hdr(skb)->body[0].echo;

	return icmp_send(ICMP_ECHO_REPLY, 0, echo_rep,
			sizeof *echo_rep + len, skb);
}
Exemplo n.º 6
0
static int icmp_rcv(struct sk_buff *skb) {
	struct icmphdr *icmph;
	uint16_t old_check;

	log_debug("%p len %zu", skb, skb->len);
	if (sizeof *icmph > ip_data_length(ip_hdr(skb))) {
		log_error("invalid length (%zu > %zu)",
				sizeof *icmph, ip_data_length(ip_hdr(skb)));
		skb_free(skb);
		return 0; /* error: invalid length */
	}

	if (NULL == skb_declone(skb)) {
		log_error("can't declone data");
		skb_free(skb);
		return -ENOMEM; /* error: can't declone data */
	}

	icmph = icmp_hdr(skb);
	assert(icmph != NULL);

	old_check = icmph->check;
	icmp_set_check_field(icmph, ip_hdr(skb));
	if (old_check != icmph->check) {
		log_error("bad checksum");
		skb_free(skb);
		return 0; /* error: bad checksum */
	}

	switch (icmph->type) {
	default:
		log_error("icmp_rcv: unknown type: %hhu\n", icmph->type);
		break; /* error: unknown type */
	case ICMP_ECHO_REPLY:
	case ICMP_TIMESTAMP_REPLY:
	case ICMP_INFO_REPLY:
		break;
	case ICMP_DEST_UNREACH:
		return icmp_hnd_dest_unreach(icmph, &icmph->body[0].dest_unreach, skb);
	case ICMP_SOURCE_QUENCH:
		return icmp_hnd_source_quench(icmph,
				&icmph->body[0].source_quench, skb);
	case ICMP_REDIRECT:
	case ICMP_TIME_EXCEED:
	case ICMP_INFO_REQUEST:
		break; /* error: not implemented */
	case ICMP_ECHO_REQUEST:
		return icmp_hnd_echo_request(icmph, &icmph->body[0].echo, skb);
	case ICMP_PARAM_PROB:
		return icmp_hnd_param_prob(icmph, &icmph->body[0].param_prob, skb);
	case ICMP_TIMESTAMP_REQUEST:
		return icmp_hnd_timestamp_request(icmph,
				&icmph->body[0].timestamp, skb);
	}

	skb_free(skb);
	return 0;
}
Exemplo n.º 7
0
struct skbuff * ip_frag(struct net_device *dev, struct skbuff *skb)
{
	__u8 frag_num = 0;
	__u16 tot_len = ntohs(skb->nh.iph->tot_len);
	__u8 mtu = dev->mtu;
	__u8 half_mtu = (mtu+1)/2;
	frag_num = (tot_len - IPHDR_LEN + half_mtu)/(mtu - IPHDR_LEN - ETH_HLEN);/*计算分片的个数*/

	__u16 i = 0;
	struct skbuff *skb_h = NULL,*skb_t = NULL,*skb_c = NULL;
	for(i = 0,skb->tail = skb->head; i<frag_num;i++)
	{
		if(i ==0){													/*第一个分片*/
			skb_t = skb_alloc(mtu);									/*申请内存*/
			skb_t->phy.raw = skb_put(skb_t, ETH_HLEN);					/*物理层*/
			skb_t->nh.raw = skb_put(skb_t, IPHDR_LEN);					/*网络层*/
			
			memcpy(skb_t->head, skb->head, mtu);						/*拷贝数据*/
			skb_put(skb,mtu);										/*增加数据长度len值*/
			skb_t->nh.iph->frag_off = htons(0x2000);						/*设置偏移标记值*/
			skb_t->nh.iph->tot_len = htons(mtu-ETH_HLEN);				/*设置IP头部总长度*/
			skb_t->nh.iph->check = 0;									/*设置校验和为0*/
			skb_t->nh.iph->check = SIP_Chksum(skb_t->nh.raw, IPHDR_LEN);/*计算校验和*/

			skb_h = skb_c =skb_t;										/*头部分片指针设置*/
		}else if(i==frag_num -1){										/*最后一个分片*/
			skb_t = skb_alloc(mtu);									/*申请内存*/
			skb_t->phy.raw = skb_put(skb_t, ETH_HLEN);					/*物理层*/
			skb_t->nh.raw = skb_put(skb_t, IPHDR_LEN);					/*网络层*/
			
			memcpy(skb_t->head, skb->head, ETH_HLEN + IPHDR_LEN);		/*拷贝数据*/
			memcpy(skb_t->head + ETH_HLEN + IPHDR_LEN, skb->tail, skb->end - skb->tail);/*增加数据长度len值*/
			skb_t->nh.iph->frag_off = htons(i*(mtu - ETH_HLEN - IPHDR_LEN) + IPHDR_LEN);/*设置偏移标记值*/
			skb_t->nh.iph->tot_len = htons(skb->end - skb->tail + IPHDR_LEN);/*设置IP头部总长度*/
			skb_t->nh.iph->check = 0;									/*设置校验和为0*/
			skb_t->nh.iph->check = SIP_Chksum(skb_t->nh.raw, IPHDR_LEN);/*计算校验和*/

			skb_c->next=skb_t;										/*挂接此分片*/
		}else{
			skb_t = skb_alloc(mtu);
			skb_t->phy.raw = skb_put(skb_t, ETH_HLEN);
			skb_t->nh.raw = skb_put(skb_t, IPHDR_LEN);
			
			memcpy(skb_t->head, skb->head, ETH_HLEN + IPHDR_LEN);
			memcpy(skb_t->head + ETH_HLEN + IPHDR_LEN, skb->tail, mtu - ETH_HLEN - IPHDR_LEN);
			skb_put(skb_t, mtu - ETH_HLEN - IPHDR_LEN);
			skb_t->nh.iph->frag_off = htons((i*(mtu - ETH_HLEN - IPHDR_LEN) + IPHDR_LEN)|0x2000);
			skb_t->nh.iph->tot_len = htons(mtu - ETH_HLEN);
			skb_t->nh.iph->check = 0;
			skb_t->nh.iph->check = SIP_Chksum(skb_t->nh.raw, IPHDR_LEN);

			skb_c->next=skb_t;
			skb_c = skb_t;
		}
		skb_t->ip_summed = 1;										/*已经进行了IP校验和计算*/
	}

	skb_free(skb);													/*释放原来的网络数据*/
	return skb_h;													/*返回分片的头部指针*/
}
Exemplo n.º 8
0
static int send_request(struct net_device *dev, uint16_t pro,
		uint8_t pln, const void *spa, const void *tpa) {
	int ret;
	struct sk_buff *skb;
	struct net_header_info hdr_info;

	skb = skb_alloc(dev->hdr_len
			+ ARP_CALC_HEADER_SIZE(dev->addr_len, pln));
	if (skb == NULL) {
		return -ENOMEM;
	}

	skb->dev = dev;
	skb->nh.raw = skb->mac.raw + dev->hdr_len;

	hdr_info.type = ETH_P_ARP;
	hdr_info.src_hw = &dev->dev_addr[0];
	hdr_info.dst_hw = &dev->broadcast[0];
	assert(dev->ops != NULL);
	assert(dev->ops->build_hdr != NULL);
	ret = dev->ops->build_hdr(skb, &hdr_info);
	if (ret != 0) {
		skb_free(skb);
		return ret;
	}

	arp_build(arp_hdr(skb), dev->type, pro, dev->addr_len, pln,
			ARP_OP_REQUEST, &dev->dev_addr[0], spa,
			&dev->broadcast[0], tpa);

	return net_tx(skb, NULL);
}
Exemplo n.º 9
0
int sock_dgram_recvmsg(struct sock *sk, struct msghdr *msg, int flags) {
	const unsigned long timeout = sock_calc_timeout(sk);
	struct sk_buff *skb;
	int err, nrecv;

	assert(sk != NULL);

	skb = sock_get_skb(sk, timeout, &err);

	if (!skb) {
		assert(err);
		return err;
	}

	nrecv = skb_iovec_buf(msg->msg_iov, msg->msg_iovlen,
			skb->p_data, skb->p_data_end - skb->p_data);

	sk->rx_data_len -= skb->p_data_end - skb->p_data;

	assert(sk->p_ops != NULL);
	if (sk->p_ops->fillmsg && msg->msg_name) {
		sk->p_ops->fillmsg(sk, msg, skb);
	}

	skb_free(skb);

	return nrecv;
}
main(int argc, char **argv)
{
	struct uld *uld;
	struct sk_buff *skb;
	int i;
	pcap_t *p;
	pcap_dumper_t *pd;
	struct pcap_pkthdr ph;
	char *ifname;
	
	ifname = NULL;
	if (argc == 2) {
		ifname = argv[1];
	}
	uld = uld_open(ifname, 0, 0, 0, 0);
	if (uld == NULL)
		exit(1);

	p = pcap_open_dead(DLT_EN10MB, 65535);
	if (!p) fprintf(stderr, "pcap_open_dead failed\n");
	pd = pcap_dump_open(p, "-");
	if (!pd) fprintf(stderr, "pcap_dump_open failed\n");
	for(;;) {
		skb = uld_skb_read(uld, 1);
		if (skb == NULL)
			continue;
		ph.ts.tv_sec = skb->tstamp.tv_sec;
		ph.ts.tv_usec = skb->tstamp.tv_nsec/1000;
		ph.len = ph.caplen = skb->len;
		pcap_dump((void *)pd, &ph, skb->data);
		pcap_dump_flush(pd);
		skb_free(skb);
	}
}
Exemplo n.º 11
0
static int icmp_notify_an_error(const struct icmphdr *icmph,
		const void *msg, size_t msg_sz, uint16_t extra_info,
		int only_raw, struct sk_buff *skb) {
	const struct iphdr *emb_iph;
	uint32_t error_info;

	emb_iph = msg;
	assert(emb_iph != NULL);

	if ((msg_sz < IP_MIN_HEADER_SIZE)
			|| (IP_HEADER_SIZE(emb_iph) < IP_MIN_HEADER_SIZE)
			|| (ntohs(emb_iph->tot_len) < IP_HEADER_SIZE(emb_iph))
			|| (msg_sz < IP_HEADER_SIZE(emb_iph))) {
		log_error("invalid length");
		skb_free(skb);
		return 0; /* error: invalid length */
	}

	if (!ip_check_version(emb_iph)) {
		log_error("not ipv4");
		skb_free(skb);
		return 0; /* error: not ipv4 */
	}

	if (ip_hdr(skb)->daddr != emb_iph->saddr) {
		log_error("not my embedded packet");
		skb_free(skb);
		return 0; /* error: not my embedded packet */
	}

	error_info = extra_info << 16 | icmph->code << 8 | icmph->type;

	raw_err(skb, error_info);

	if (!only_raw) {
		const struct net_proto *nproto;
		nproto = net_proto_lookup(ETH_P_IP, emb_iph->proto);
		if (nproto != NULL) {
			assert(nproto->handle_error != NULL);
			nproto->handle_error(skb, error_info);
		}
	}

	return 0;
}
Exemplo n.º 12
0
static int icmp_hnd_source_quench(const struct icmphdr *icmph,
		const struct icmpbody_source_quench *source_quench,
		struct sk_buff *skb) {
	size_t len;

	if (icmph->code != 0) {
		skb_free(skb);
		return 0; /* error: bad code */
	}

	len = ip_data_length(ip_hdr(skb));
	if (sizeof *icmph + sizeof *source_quench > len) {
		skb_free(skb);
		return 0; /* error: invalid length */
	}
	len -= sizeof *icmph + sizeof *source_quench;

	return icmp_notify_an_error(icmph, &source_quench->msg[0],
			len, 0, 0, skb);
}
Exemplo n.º 13
0
static int udp_sendmsg(struct sock *sk, struct msghdr *msg, int flags) {
	int ret;
	size_t data_len, total_len, actual_len;
	struct sk_buff *skb;
	const struct sockaddr_in *to;
	const struct sockaddr *sockaddr;

	assert(sk);
	assert(sk->o_ops);
	assert(sk->o_ops->make_pack);
	assert(msg);
	assert(msg->msg_iov);
	assert(msg->msg_iov->iov_base);

	data_len = msg->msg_iov->iov_len;
	total_len = actual_len = UDP_HEADER_SIZE + data_len;
	skb = NULL;
	sockaddr = (const struct sockaddr *)msg->msg_name;

	ret = sk->o_ops->make_pack(sk, sockaddr, &actual_len, &skb);
	if (ret != 0) {
		return ret;
	}

#if 0
	if (actual_len < total_len) {
		skb_free(skb);
		return -EMSGSIZE;
	}
#endif

	if (msg->msg_name != NULL) {
		to = (const struct sockaddr_in *)msg->msg_name;
	} else {
		to = (const struct sockaddr_in *)&to_inet_sock(sk)->dst_in;
	}

	assert(skb);
	assert(skb->h.uh);

	udp_build(skb->h.uh, sock_inet_get_src_port(sk), to->sin_port, total_len);

	memcpy(skb->h.uh + 1, msg->msg_iov->iov_base, data_len);

	udp4_set_check_field(skb->h.uh, skb->nh.iph);

	assert(sk->o_ops->snd_pack);
	ret = sk->o_ops->snd_pack(skb);
	if (0 > ret) {
		return ret;
	}
	return data_len;
}
Exemplo n.º 14
0
static int ip6_rcv(struct sk_buff *skb, struct net_device *dev) {
	ip6hdr_t *ip6h = ip6_hdr(skb);
	const struct net_proto *nproto;

	if (ip6h->version != 6) {
		dev->stats.rx_err++;
		skb_free(skb);
		return 0; /* error: invalid hdr */
	}

	if (skb->dev->hdr_len + IP6_HEADER_SIZE
			+ ntohs(ip6h->payload_len) > skb->len) {
		dev->stats.rx_length_errors++;
		skb_free(skb);
		return 0; /* error: invalid length */
	}

	/* Check recipiant */
	assert(skb->dev != NULL);
	assert(inetdev_get_by_dev(skb->dev) != NULL);
	if (0 != memcmp(&inetdev_get_by_dev(skb->dev)->ifa6_address,
				&skb->nh.ip6h->daddr, sizeof(struct in6_addr))) {
//		skb_free(skb);
//		return 0; /* error: not for us */
	}

	/* Setup transport layer header */
	skb->h.raw = skb->nh.raw + IP6_HEADER_SIZE;

	nproto = net_proto_lookup(ETH_P_IPV6, ip6h->nexthdr);
	if (nproto != NULL) {
		return nproto->handle(skb);
	}

//	printk("ipv6 packet accepted, %#x\n", ip6h->nexthdr);

	skb_free(skb);
	return 0; /* error: nobody wants this packet */
}
Exemplo n.º 15
0
static int mipsnet_xmit(struct net_device *dev, struct sk_buff *skb) {
	struct mipsnet_regs *regs;
	int i;
	uint8_t *pdata;

	show_packet(skb->mac.raw, skb->len, "xmit");

	regs = (struct mipsnet_regs *)dev->base_addr;
	pdata = skb->mac.raw;

	out32(skb->len, &regs->txDataCount);
	for(i = 0; i < skb->len; i++) {
		out32((uint32_t)*pdata, &regs->txDataBuffer);
		pdata++;
	}

	skb_free(skb);
	return 0;
}
Exemplo n.º 16
0
//TODO this function call from stack (may be place it to other file)
void sock_rcv(struct sock *sk, struct sk_buff *skb,
		unsigned char *p_data, size_t size) {
	if ((sk == NULL) || (skb == NULL) || (p_data == NULL)) {
		return; /* error: invalid argument */
	}

	if (sk->shutdown_flag & (SHUT_RD + 1)) {
		skb_free(skb);
		return; /* error: socket is down */
	}

	skb->p_data = p_data;
	skb->p_data_end = p_data + size;

	skb_queue_push(&sk->rx_queue, skb);
	sk->rx_data_len += size;

	sock_notify(sk, POLLIN);
}
Exemplo n.º 17
0
ssize_t sip_recvfrom(int s, void *buf, size_t len, int flags,
                        struct sockaddr *from, socklen_t *fromlen)   
{
	struct sip_socket *socket;
	struct skbuff      *skb;
	struct sockaddr_in *f = (struct sockaddr_in *)from;
	int len_copy = 0;

	socket = get_socket(s);					/*获得socket类型映射*/
	if (!socket)
		return -1;

	if(!socket->lastdata){						/*lastdata中没有有剩余数据*/
		socket->lastdata =(struct skbuff*) SIP_SockRecv(socket->sock);/*接收数据*/
		socket->lastoffset = 0;					/*偏离量为0*/
	}

	skb = socket->lastdata;					/*skbuff指针*/

	/*填充用户出入参数*/
	*fromlen = sizeof(struct sockaddr_in);		/*地址结构长度*/
	f->sin_family = AF_INET;					/*地址类型*/
	f->sin_addr.s_addr = skb->nh.iph->saddr;	/*来源IP地址*/
	f->sin_port = skb->th.udph->source;			/*来源端口*/

	len_copy = skb->len - socket->lastoffset;		/*计算lastdata中剩余的数据*/
	if(len > len_copy)	{						/*用户缓冲区可以放下所有数据*/
		memcpy(buf, 							/*全部拷贝到用户缓冲区*/
			skb->data+socket->lastoffset, 
			len_copy);
		skb_free(skb);						/*释放此结构*/
		socket->lastdata = NULL;				/*清空网络数据结构指针*/
		socket->lastoffset = 0;					/*偏移量重新设置为0*/
	}else{									/*用户缓冲区放不下整个数据*/
		len_copy = len;						/*仅拷贝缓冲区大小的数据*/
		memcpy(buf, 							/*拷贝*/
			skb+socket->lastoffset, 
			len_copy);
		socket->lastoffset += len_copy;			/*偏移量增加*/
	}	

	return len_copy;							/*返回拷贝的值*/
}
Exemplo n.º 18
0
void arp_queue_try_insert(struct sk_buff *skb)
{
	if (skb->arp_try_times == 0)
	{
		printf("arp request too many times\n");
		goto drop;
	}
	if (skb_queue_len(&arp_queue) > MAX_SKB_QUEUE_SIZE)
	{
		printf("arp queue is full\n");
		goto drop;
	}
	
	skb->arp_try_times--;
	skb_queue_tail(&arp_queue, skb);
	return;
drop:
	skb_free(skb);
}
Exemplo n.º 19
0
int sock_stream_recvmsg(struct sock *sk, struct msghdr *msg, int flags) {
	void *buf, *bufend, *bp;
	struct sk_buff *skb;
	unsigned long timeout;
	int err;

	assert(msg->msg_iovlen == 1);
	buf = msg->msg_iov->iov_base;
	bufend = buf + msg->msg_iov->iov_len;

	/* TODO I think here should be a check if stream connection is closed forcibly.
	 * See "RETURN VALUE" http://pubs.opengroup.org/onlinepubs/009695399/functions/recvfrom.html
	 * --Alexander */

	timeout = sock_calc_timeout(sk);
	bp = buf;
	err = 0;
	while (bp < bufend) {
		size_t len;

		skb = sock_get_skb(sk, timeout, &err);
		if (!skb) {
			break;
		}

		len = skb_read(skb, bp, bufend - bp);
		bp += len;

		if (skb->p_data == skb->p_data_end) {
			skb_free(skb);
		}

		timeout = 0;
	}

	if (bp == buf) {
		return err;
	}

	sk->rx_data_len -= bp - buf;
	return bp - buf;
}
Exemplo n.º 20
0
int sip_close(int s)
{
	struct sip_socket *socket;

	socket = get_socket(s);					/*获得socket类型映射*/
	if (!socket) 								/*失败*/
	{
		return -1;
	}

	SIP_SockDelete(socket->sock);			/*释放sock结构*/

	if (socket->lastdata) 
	{
		skb_free(socket->lastdata);			/*释放socket上挂接的网络数据*/
	}
	socket->lastdata   = NULL;					/*清空socket结构的网络数据*/
	socket->sock       = NULL;					/*清空sock指针*/

	return 0;
}
Exemplo n.º 21
0
static int udp_rcv(struct sk_buff *skb) {
	struct sock *sk;

	assert(skb != NULL);
	assert(ip_check_version(ip_hdr(skb))
			|| ip6_check_version(ip6_hdr(skb)));

	/* Check CRC */
	if (MODOPS_VERIFY_CHKSUM) {
		uint16_t old_check;
		old_check = skb->h.uh->check;
		udp_set_check_field(skb->h.uh, skb->nh.raw);
		if (old_check != skb->h.uh->check) {
			return 0; /* error: bad checksum */
		}
	}

	sk = sock_lookup(NULL, udp_sock_ops,
			ip_check_version(ip_hdr(skb))
				? udp4_rcv_tester : udp6_rcv_tester,
			skb);
	if (sk != NULL) {
		if (ip_check_version(ip_hdr(skb))
				? udp4_accept_dst(sk, skb)
				: udp6_accept_dst(sk, skb)) {
			sock_rcv(sk, skb, skb->h.raw + UDP_HEADER_SIZE,
					udp_data_length(udp_hdr(skb)));
		}
		else {
			skb_free(skb);
		}
	}
	else {
		icmp_discard(skb, ICMP_DEST_UNREACH, ICMP_PORT_UNREACH);
	}

	return 0;
}
Exemplo n.º 22
0
void arp_rcv(struct sk_buff *skb)
{
	struct arppkt *ap;
	struct ethhdr *eh;
	unsigned int tip, sip;
	struct arptab *h;
	int hl;
	struct net_device *nic;

	hl = sizeof(struct ethhdr);
	skb->len -= hl;
	ap = (struct arppkt *) skb->data;
	skb->nh.arph = (struct arphdr *) skb->data;
	eh = (struct ethhdr *) (skb->data - hl);
	nic = skb->nic;

	/* skb->data += sizeof(struct arphdr); */

	printf("--- ARP: packet received\n");

	if (ap->ar_hrd != htons(ARPHRD_ETHER) || ap->ar_pro != htons(ETHERTYPE_IP)
	    || ap->ar_hln != ETH_ALEN || ap->ar_pln != 4)
		goto bad;

	switch (ntohs(ap->ar_op)) {
	case ARPOP_REQUEST:
		tip = *(unsigned int *)ap->__ar_tip;
		sip = *(unsigned int *)ap->__ar_sip;
		if (tip != skb->nic->ip)
			goto drop;
		ap->ar_op = htons(ARPOP_REPLY);
		*(unsigned int *)ap->__ar_sip = skb->nic->ip;
		*(unsigned int *)ap->__ar_tip = sip;
		memcpy(ap->__ar_sha, skb->nic->dev_addr, ETH_ALEN);
		memcpy(ap->__ar_tha, eh->h_source, ETH_ALEN);
		memcpy(eh->h_dest, eh->h_source, ETH_ALEN);
		memcpy(eh->h_source, skb->nic->dev_addr, ETH_ALEN);
                skb->len +=14;
		skb->ip_summed = 0;
		skb->protocol = ETHERTYPE_ARP;
		dev_send(skb);
		goto reused;
		break;
	case ARPOP_REPLY:
		sip = *(unsigned int *)ap->__ar_sip;
		tip = *(unsigned int *)ap->__ar_tip;

		pthread_spin_lock(&arp_lock);
		h = &arp_table[arp_hash(sip)];

		if (/* h->ip == sip && */ nic->ip == tip)
		{
			if (ap->__ar_sha[0] & 1) /* why? */
				goto unlock_bad;
			memcpy(h->mac, ap->__ar_sha, ETH_ALEN);
			/* if (h->hold && (tv.tv_sec - h->time > ARP_MAX_HOLD)) */
			/* { */
			/* 	skb_free(h->hold); */
			/* 	h->hold = NULL; */
			/* } */
			h->time = get_second();
			if (h->status == ARP_STATUS_REQUEST)
			{
				h->status = ARP_STATUS_OK;
				pthread_spin_unlock(&arp_lock);
				pthread_cond_signal(&arp_queue_check);
			}
			else
			{
				/* received broadcast reply who was not requested */
				h->status = ARP_STATUS_OK;
				pthread_spin_unlock(&arp_lock);
			}
			/* if ((skb = h->hold)) */
			/* { */
			/* 	h->hold = NULL; */
			/* 	memcpy(eh->h_dest, h->mac, ETH_ALEN); */
			/* 	pthread_spin_unlock(&arp_lock); */
			/* 	/\* fragmentation? *\/ */
			/* 	dev_send(skb); */
			/* } */
			/* else */
			/* 	pthread_spin_unlock(&arp_lock); */
		} else {
			goto unlock_bad;
		}
		break;
	default:
		goto bad;
	}

reused:
	return;
bad:
	printf("arp: packet invalid\n");
drop:
	skb_free(skb);
	return;
unlock_bad:
	pthread_spin_unlock(&arp_lock);
	skb_free(skb);
}
Exemplo n.º 23
0
static int ip_rcv(struct sk_buff *skb, struct net_device *dev) {
	net_device_stats_t *stats = &dev->stats;
	const struct net_proto *nproto;
	iphdr_t *iph = ip_hdr(skb);
	__u16 old_check;
	size_t ip_len;
	int optlen;
	sk_buff_t *complete_skb;

	/**
	 *   RFC1122: 3.1.2.2 MUST silently discard any IP frame that fails the checksum.
	 *   Is the datagram acceptable?
	 *   1.  Length at least the size of an ip header
	 *   2.  Version of 4
	 *   3.  Checksums correctly. [Speed optimisation for later, skip loopback checksums]
	 *   4.  Doesn't have a bogus length
	 */
	if (skb->len < dev->hdr_len + IP_MIN_HEADER_SIZE
			|| IP_HEADER_SIZE(iph) < IP_MIN_HEADER_SIZE
			|| skb->len < dev->hdr_len + IP_HEADER_SIZE(iph)) {
		DBG(printk("ip_rcv: invalid IPv4 header length\n"));
		stats->rx_length_errors++;
		skb_free(skb);
		return 0; /* error: invalid header length */
	}


	if (iph->version != 4) {
		DBG(printk("ip_rcv: invalid IPv4 version\n"));
		stats->rx_err++;
		skb_free(skb);
		return 0; /* error: not ipv4 */
	}

	old_check = iph->check;
	ip_set_check_field(iph);
	if (old_check != iph->check) {
		DBG(printk("ip_rcv: invalid checksum %hx(%hx)\n",
				ntohs(old_check), ntohs(iph->check)));
		stats->rx_crc_errors++;
		skb_free(skb);
		return 0; /* error: invalid crc */
	}

	ip_len = ntohs(iph->tot_len);
	if (ip_len < IP_HEADER_SIZE(iph)
			|| skb->len < dev->hdr_len + ip_len) {
		DBG(printk("ip_rcv: invalid IPv4 length\n"));
		stats->rx_length_errors++;
		skb_free(skb);
		return 0; /* error: invalid length */
	}

	/* Setup transport layer (L4) header */
	skb->h.raw = skb->nh.raw + IP_HEADER_SIZE(iph);

	/* Validating */
	if (0 != nf_test_skb(NF_CHAIN_INPUT, NF_TARGET_ACCEPT, skb)) {
		DBG(printk("ip_rcv: dropped by input netfilter\n"));
		stats->rx_dropped++;
		skb_free(skb);
		return 0; /* error: dropped */
	}

	/* Forwarding */
	assert(skb->dev);
	assert(inetdev_get_by_dev(skb->dev));
	if (inetdev_get_by_dev(skb->dev)->ifa_address != 0) {
		/**
		 * FIXME
		 * This check needed for BOOTP protocol
		 * disable forwarding if interface is not set yet
		 */
		/**
		 * Check the destination address, and if it doesn't match
		 * any of own addresses, retransmit packet according to the routing table.
		 */
		if (!ip_is_local(iph->daddr, IP_LOCAL_BROADCAST)) {
			if (0 != nf_test_skb(NF_CHAIN_FORWARD, NF_TARGET_ACCEPT, skb)) {
				DBG(printk("ip_rcv: dropped by forward netfilter\n"));
				stats->rx_dropped++;
				skb_free(skb);
				return 0; /* error: dropped */
			}
			return ip_forward(skb);
		}
	}

	memset(skb->cb, 0, sizeof(skb->cb));
	optlen = IP_HEADER_SIZE(iph) - IP_MIN_HEADER_SIZE;
	if (optlen > 0) {
		/* NOTE : maybe it'd be better to copy skb here,
		 * 'cause options may cause modifications
		 * but smart people who wrote linux kernel
		 * say that this is extremely rarely needed
		 */
		ip_options_t *opts = (ip_options_t*)(skb->cb);

		memset(skb->cb, 0, sizeof(skb->cb));
		opts->optlen = optlen;
		if (ip_options_compile(skb, opts)) {
			DBG(printk("ip_rcv: invalid options\n"));
			stats->rx_err++;
			skb_free(skb);
			return 0; /* error: bad ops */
		}
		if (ip_options_handle_srr(skb)) {
			DBG(printk("ip_rcv: can't handle options\n"));
			stats->tx_err++;
			skb_free(skb);
			return 0; /* error: can't handle ops */
		}
	}

	/* It's very useful for us to have complete packet even for forwarding
	 * (we may apply any filter, we may perform NAT etc),
	 * but it'll break routing if different parts of a fragmented
	 * packet will use different routes. So they can't be assembled.
	 * See RFC 1812 for details
	 */
	if (ntohs(skb->nh.iph->frag_off) & (IP_MF | IP_OFFSET)) {
		if ((complete_skb = ip_defrag(skb)) == NULL) {
			if (skb == NULL) {
				return 0; /* error: */
			}
			return 0;
		} else {
			skb = complete_skb;
			iph = ip_hdr(complete_skb);
		}
	}

	/* When a packet is received, it is passed to any raw sockets
	 * which have been bound to its protocol or to socket with concrete protocol */
	raw_rcv(skb);

	nproto = net_proto_lookup(ETH_P_IP, iph->proto);
	if (nproto != NULL) {
		return nproto->handle(skb);
	}

	DBG(printk("ip_rcv: unknown protocol\n"));
	skb_free(skb);
	return 0; /* error: nobody wants this packet */
}
Exemplo n.º 24
0
int icmp_discard(struct sk_buff *skb, uint8_t type, uint8_t code,
		...) {
	struct {
		union {
			struct icmpbody_dest_unreach dest_unreach;
			struct icmpbody_source_quench source_quench;
			struct icmpbody_redirect redirect;
			struct icmpbody_time_exceed time_exceed;
			struct icmpbody_param_prob param_prob;
		} __attribute__((packed));
		char __body_msg_storage[ICMP_DISCARD_MAX_SIZE];
	} __attribute__((packed)) body;
	va_list extra;
	uint8_t *body_msg;
	size_t body_msg_sz;

	if (!(ip_is_local(ip_hdr(skb)->saddr, 0)
				|| ip_is_local(ip_hdr(skb)->daddr, 0))
			|| (ip_hdr(skb)->frag_off & htons(IP_OFFSET))
			|| (ip_data_length(ip_hdr(skb)) < ICMP_DISCARD_MIN_SIZE)
			|| (ip_hdr(skb)->proto != IPPROTO_ICMP)
			|| (skb->h.raw = skb->nh.raw + IP_HEADER_SIZE(ip_hdr(skb)),
				ICMP_TYPE_ERROR(icmp_hdr(skb)->type))) {
		skb_free(skb);
		return 0; /* error: inappropriate packet */
	}

	switch (type) {
	default:
		assertf(0, "bad type for discard");
		body_msg = (uint8_t *)&body.__body_msg_storage[0];
		break; /* error: bad type for discard */
	case ICMP_DEST_UNREACH:
		assertf(code < __ICMP_DEST_UNREACH_MAX,
				"incorrect code for type");
		va_start(extra, code);
		body.dest_unreach.zero = 0;
		body.dest_unreach.mtu = code != ICMP_FRAG_NEEDED ? 0
				: htons((uint16_t)va_arg(extra, int));
		va_end(extra);
		body_msg = &body.dest_unreach.msg[0];
		break;
	case ICMP_SOURCE_QUENCH:
		assertf(code == 0, "incorrect code for type");
		body.source_quench.zero = 0;
		body_msg = &body.source_quench.msg[0];
		break;
	case ICMP_REDIRECT:
		assertf(code < __ICMP_REDIRECT_MAX,
				"incorrect code for type");
		va_start(extra, code);
		memcpy(&body.redirect.gateway,
				va_arg(extra, struct in_addr *),
				sizeof body.redirect.gateway);
		va_end(extra);
		body_msg = &body.redirect.msg[0];
		break;
	case ICMP_TIME_EXCEED:
		assertf(code < __ICMP_TIME_EXCEED_MAX,
				"incorrect code for type");
		body.time_exceed.zero = 0;
		body_msg = &body.time_exceed.msg[0];
		break;
	case ICMP_PARAM_PROB:
		assertf(code < __ICMP_PARAM_PROB_MAX,
				"incorrect code for type");
		va_start(extra, code);
		body.param_prob.ptr = code != ICMP_PTR_ERROR ? 0
				: (uint8_t)va_arg(extra, int);
		body.param_prob.zero1 = body.param_prob.zero2 = 0;
		va_end(extra);
		body_msg = &body.param_prob.msg[0];
		break;
	}

	body_msg_sz = min(ip_data_length(ip_hdr(skb)),
			sizeof body.__body_msg_storage);
	memcpy(body_msg, ip_hdr(skb), body_msg_sz);

	if (NULL == skb_declone(skb)) {
		skb_free(skb);
		return -ENOMEM; /* error: can't declone data */
	}

	return icmp_send(type, code, &body, sizeof body
				- sizeof body.__body_msg_storage + body_msg_sz,
			skb);
}
Exemplo n.º 25
0
int net_tx(struct sk_buff *skb,
           struct net_header_info *hdr_info) {
    int ret;
    size_t skb_len;
    struct net_device *dev;

    assert(skb != NULL);

    dev = skb->dev;
    assert(dev != NULL);

    if (!(dev->flags & IFF_UP)) {
        log_error("net_tx: device is down\n");
        skb_free(skb);
        return -ENETDOWN;
    }

    if (0 != nt_build_hdr(skb, hdr_info, dev)) {
        assert(hdr_info != NULL);
        ret = neighbour_send_after_resolve(hdr_info->type,
                                           hdr_info->dst_p, hdr_info->p_len,
                                           dev, skb);
        if (ret != 0)
            log_debug("net_tx: neighbour_send_after_resolve = %d\n", ret);

        return ret;
    }

    skb_len = skb->len;

    log_debug("net_tx: skb %p[%zu] type %#.6hx\n", skb, skb->len, ntohs(skb->mac.ethh->h_proto));

    /*
     * http://www.linuxfoundation.org/collaborate/workgroups/networking/kernel_flow#Transmission_path
     * Search for:
     * dev_hard_start_xmit() calls the hard_start_xmit virtual method for the net_device.
     * But first, it calls dev_queue_xmit_nit(), which checks if a packet handler has been registered
     * for the ETH_P_ALL protocol. This is used for tcpdump.
     */
    sock_packet_add(skb, htons(ETH_P_ALL));

    skb = net_encrypt(skb);
    if (skb == NULL) {
        return 0;
    }

    assert(dev->drv_ops != NULL);
    assert(dev->drv_ops->xmit != NULL);
    ret = dev->drv_ops->xmit(dev, skb);
    if (ret != 0) {
        log_debug("net_tx: xmit = %d\n", ret);
        skb_free(skb);
        dev->stats.tx_err++;
        return ret;
    }

    dev->stats.tx_packets++;
    dev->stats.tx_bytes += skb_len;

    return 0;
}
Exemplo n.º 26
0
#include "sip.h"

inline int IP_IS_BROADCAST(struct net_device *dev, __be32 ip)
{
	int retval = 1;
	
	if((ip == IP_ADDR_ANY_VALUE) 						/*IP地址为本地任意IP地址*/
		||(~ip == IP_ADDR_ANY_VALUE))				/*或者为按位取反IP地址*/
	{
		DBGPRINT(DBG_LEVEL_NOTES, "IP is ANY ip\n");
		retval = 1;									/*是广播地址*/
		goto EXITin_addr_isbroadcast;					/*退出*/
	}else if(ip == dev->ip_host.s_addr)	{				/*IP地址为本地地址*/
		DBGPRINT(DBG_LEVEL_NOTES, "IP is local ip\n");
		retval = 0;									/*不是广播地址*/
		goto EXITin_addr_isbroadcast;					/*退出*/
	}else if(((ip&dev->ip_netmask.s_addr) 				/*IP地址为本子网内地址*/
					== (dev->ip_host.s_addr &dev->ip_netmask.s_addr))
		&& ((ip & ~dev->ip_netmask.s_addr) 			/*与广播地址同网段*/
					==(IP_ADDR_BROADCAST_VALUE & ~dev->ip_netmask.s_addr))){
		DBGPRINT(DBG_LEVEL_NOTES, "IP is ANY ip\n");
		retval =1;									/*是广播地址*/
		goto EXITin_addr_isbroadcast;					/*退出*/
	}else{											/*不是广播IP地址*/
		retval = 0;
	}
EXITin_addr_isbroadcast:
	return retval;
}

#define IP_FREE_REASS(ipr)				\
do{										\
	struct skbuff *skb=NULL,*skb_prev=NULL;	\
	for(skb_prev = skb = ipr->skb; 			\
		skb != NULL; 						\
		skb_prev = skb, 					\
		skb = skb->next,					\
		skb_free(skb_prev));				\
		free(ipr);						\
}while(0);


#define IPREASS_TIMEOUT 3							/*IP分组重组的超时时间为3秒*/
static struct sip_reass *ip_reass_list = NULL;				/*IP重组的链表*/
struct skbuff *sip_reassemble(struct skbuff* skb)
{
	struct sip_iphdr *fraghdr = skb->nh.iph;
	int retval = 0;
	__u16 offset, len;
	int found = 0;

	offset = (fraghdr->frag_off & 0x1FFF)<<3;				/*取得IP分组偏移地址,32位长*/
	len = fraghdr->tot_len - fraghdr->ihl<<2;				/*IP分组的数据长度*/

	struct sip_reass *ipr = NULL,*ipr_prev = NULL;	
	for(ipr_prev = ipr= ip_reass_list; ipr != NULL;	)	
	{
		if(time(NULL) -ipr->timer > IPREASS_TIMEOUT)	/*此分组是超时?*/
		{
			if(ipr_prev == NULL)						/*第一个分片?*/
			{
				ipr_prev = ipr;						/*更新守护的指针为本分组*/
				ip_reass_list->next = ipr = ipr->next;	/*将超时的分片从重组链表上取下来*/
				ipr = ipr->next;						/*更新当前的分组指针*/
				IP_FREE_REASS(ipr_prev);				/*释放资源*/
				ipr_prev->next =NULL;					/*重置指针为空*/

				continue;							/*继续查找合适的分组*/
			}
			else										/*不是第一个分组*/
			{
				ipr_prev->next = ipr->next;				/*从分片链表上摘除当前链*/
				IP_FREE_REASS(ipr);					/*释放当前重组链*/
				ipr = ipr_prev->next;					/*更新当前链的指针*/
				continue;							/*继续查找*/
			}			
		}

		/*分片是否输入此条链*/
		if(ipr->iphdr.daddr == fraghdr->daddr 			/*目的IP地址匹配*/
			&&ipr->iphdr.saddr == fraghdr->saddr		/*源IP地址匹配*/
			&&ipr->iphdr.id == fraghdr->id)				/*分片的ID匹配*/
		{
			found = 1;								/*属于这条链*/
			break;
		}
	}

	if(!found)										/*没有找到合适的分组链?*/
	{
		ipr_prev = NULL;								/*初始化为空*/
		ipr = (struct sip_reass*)malloc(sizeof(struct sip_reass));/*申请一个分组数据结构*/
		if(!ipr)										/*申请失败*/
		{
			retval = -1;								/*返回值-1*/
			goto freeskb;							/*退出*/
		}

		memset(ipr, 0, sizeof(struct sip_reass));			/*初始化分组结构*/

		ipr->next = ip_reass_list;						/*将当前分组结构挂接到分组链的头部*/
		ip_reass_list = ipr;	

		memcpy(&ipr->iphdr, skb->nh.raw, sizeof(IPHDR_LEN));/*拷贝IP的数据头部,便于之后的分片匹配*/
	}else{											/*找到合适的分组链*/
		if(((fraghdr->frag_off & 0x1FFF) == 0)			/*当前数据位于分片第一个*/
			&&((ipr->iphdr.frag_off & 0x1FFF) != 0))		/*分组链上的头部不是第一个分片*/
		{
			memcpy(&ipr->iphdr, fraghdr, IPHDR_LEN);	/*更新重组中的IP头部结构*/
		}		
	}

	/* 检查是否为最后一个分组*/
	if( (fraghdr->frag_off & htons(0x2000)) == 0) {		/*没有更多分组*/
		#define IP_REASS_FLAG_LASTFRAG 0x01		

	  	ipr->flags |= IP_REASS_FLAG_LASTFRAG;			/*设置最后分组标志*/
		ipr->datagram_len = offset + len;				/*设置IP数据报文的全长*/
  	}


	/*将当前的数据放到重组链上,并更新状态*/
	struct skbuff *skb_prev=NULL, *skb_cur=NULL;
	int finish =0;
	void *pos = NULL;
	__u32 length = 0;
#define FRAG_OFFSET(iph) (ntohs(iph->frag_off & 0x1FFF)<<3)
#define FRAG_LENGTH(iph) (ntohs(iph->tot_len) - IPHDR_LEN)
	for(skb_prev =NULL, skb_cur=ipr->skb,length = 0,found = 0;
		skb_cur != NULL && !found;
		skb_prev=skb_cur,skb_cur = skb_cur->next)
	{
		if(skb_prev !=NULL)									/*不是第一个分片*/
		{
			if((offset  < FRAG_OFFSET(skb_cur->nh.iph))			/*接收数据的偏移值位于前后两个之间*/
				&&(offset > FRAG_OFFSET(skb_prev->nh.iph)))
			{				
				skb->next = skb_cur;							/*将接收到的数据放到此位置*/
				skb_prev->next = skb;

				if(offset + len > FRAG_OFFSET(skb_cur->nh.iph))	/*当前数据与后面的分片数据覆盖?*/
				{
					__u16 modify = FRAG_OFFSET(skb_cur->nh.iph) - offset + IPHDR_LEN;/*计算当前链的数据长度修改值*/
					skb->nh.iph->tot_len = htons(modify);		/*更新当前链长度*/
				}

				if(FRAG_OFFSET(skb_prev->nh.iph) 				/*前面的分片长度覆盖当前数据?*/
					+ FRAG_LENGTH(skb_prev->nh.iph) 
						> FRAG_OFFSET(skb_cur->nh.iph))
				{
					__u16 modify = FRAG_OFFSET(skb_prev->nh.iph) - offset + IPHDR_LEN;/*计算前面数据长度的更改之*/
					skb_prev->nh.iph->tot_len = htons(modify);	/*修改前一片的数据长度*/
				}

				found = 1;									/*找到合适的分片插入位置*/
			}
		}
		else													/*为重组链上的头部*/
		{
			if(offset  < FRAG_OFFSET(skb_cur->nh.iph)){			/*当前链的偏移量小于第一个分片的偏移长度*/
				skb->next = ipr->skb;							/*挂接到重组链的头部*/
				ipr->skb = skb;								
				if(offset + len + IPHDR_LEN 						/*查看是否覆盖后面分片的数据*/
					> FRAG_OFFSET(skb_cur->nh.iph))
					{
					__u16 modify = FRAG_OFFSET(skb_cur->nh.iph) - offset + IPHDR_LEN;/*修改分片的数据长度*/
					if(!offset)								/*偏离量为0*/
						modify -= IPHDR_LEN;					/*包含头部,所以数据段长度需要减去IP头部长度*/

					skb->nh.iph->tot_len = htons(modify);		/*设置分片中修改后的长度*/
				}
			}
		}
		
		length += skb_cur->nh.iph->tot_len - IPHDR_LEN;			/*当前链表中的数据长度*/
	}

	/*重新计算重组链上的总数据长度*/
	for(skb_cur=ipr->skb,length = 0;
		skb_cur != NULL;
		skb_cur = skb_cur->next)
	{
		length += skb_cur->nh.iph->tot_len - IPHDR_LEN;
	}
	length += IPHDR_LEN;
	
	/*全部的IP分片都已经接收到后进行数据报文的重新组合
	数据拷贝到一个新的数据结构中,原来的数据接收都释放掉
	并从分组链中取出,将重组后的数据结构指针返回*/
	if(length == ipr->datagram_len )							/*分组全部接收到?*/
	{
		ipr->datagram_len += IPHDR_LEN;					/*计算数据报文的实际长度长度*/
		skb = skb_alloc(ipr->datagram_len + ETH_HLEN);		/*申请空间*/

		skb->phy.raw = skb_put(skb, ETH_HLEN);			/*物理层*/
		skb->nh.raw = skb_put(skb, IPHDR_LEN);			/*网络层*/
		memcpy(skb->nh.raw, & ipr->iphdr, sizeof(ipr->iphdr));	/*向新数据结构中拷贝IP头*/
		skb->nh.iph->tot_len = htons(ipr->datagram_len);		/*新结构中的tot_len*/
		
		for(skb_prev=skb_cur=ipr->skb;skb_cur != NULL;)		/*遍历重组数据链*/
		{
			int size = skb_cur->end - skb_cur->tail;			/*计算拷贝数据源的长度*/
			pos = skb_put(skb, size);						/*计算拷贝目的地址位置*/
			memcpy(pos, 									/*将一个分片拷贝到新结构中*/
				skb_cur->tail, 
				skb_cur->nh.iph->tot_len - skb_cur->nh.iph->ihl<<2);
		}

		/*一下从重组链中摘除数据并释放,然后设置新结构中的几个IP头部参数*/
		ipr_prev->next = ipr->next;							/*将此数据报文从重组链中摘除*/
		IP_FREE_REASS(ipr);								/*释放此报文的重组连*/
		skb->nh.iph->check = 0;							/*设置校验值为0*/
		skb->nh.iph->frag_off = 0;							/*偏移值为0*/
		skb->nh.iph->check = SIP_Chksum(skb->nh.raw, skb->nh.iph->tot_len);/*计算IP头部校验和*/
	}
	
normal:
	return skb;
freeskb:
	skb_free(skb);
	return NULL;
}
Exemplo n.º 27
0
int ip_input(struct net_device *dev, struct skbuff *skb)
{
	DBGPRINT(DBG_LEVEL_TRACE,"==>ip_input\n");
	struct sip_iphdr *iph = skb->nh.iph;
	int retval = 0;
	printf("len = %d, version = %d, hlen = %d\n", skb->len, iph->version, iph->ihl<<2);
	if(skb->len < 0)									/*网络数据长度不合法*/
	{	
		skb_free(skb);								/*释放结构*/
		retval = -1;									/*设置返回值*/
		goto EXITip_input;							/*退出*/
	}

	if(iph->version != 4)								/*IP版本不合适,不是IPv4*/
	{
		skb_free(skb);								
		retval = -1;									
		goto EXITip_input;							
	}

	__u16 hlen = iph->ihl<<2;							/*计算IP头部长度*/
	if(hlen < IPHDR_LEN)								/*长度国小*/
	{
		skb_free(skb);								
		retval = -1;								
		goto EXITip_input;							
	}
	printf("tol_len = %d\n", skb->tot_len);
	if(skb->tot_len - ETH_HLEN < ntohs(iph->tot_len))		/*计算总长度是否合法*/
	{
		skb_free(skb);
		retval = -1;
		goto EXITip_input;
	}


	if(SIP_Chksum(skb->nh.raw, IPHDR_LEN))			/*计算IP头部的校验和,是否正确,为0*/
	{
		DBGPRINT(DBG_LEVEL_ERROR, "IP check sum error\n");
		skb_free(skb);
		retval= -1;
		goto EXITip_input;
	}
	else												/*校验和合法*/
	{
		skb->ip_summed = CHECKSUM_HW;				/*设置IP校验标记*/
		DBGPRINT(DBG_LEVEL_NOTES, "IP check sum success\n");
	}

	if((iph->daddr != dev->ip_host.s_addr 				/*不是发往本地*/
		&& !IP_IS_BROADCAST(dev, iph->daddr)		/*目的地址不是广播地址*/
		||IP_IS_BROADCAST(dev, iph->saddr)))		/*源地址不是广播地址*/
	{
		DBGPRINT(DBG_LEVEL_NOTES, "IP address INVALID\n");
		skb_free( skb);
		retval= -1;
		goto EXITip_input;
	}

	if((ntohs(iph->frag_off) & 0x3FFF) !=0)				/*有偏移,是一个分片*/
	{
		printf("call sip_reassemble \n");
		skb = sip_reassemble(skb);					/*进行分片重组*/
		if(!skb){									/*重组不成功*/
			retval = 0;
			goto EXITip_input;
		}
	}
	
	switch(iph->protocol)								/*IP协议类型*/
	{
		
		case IPPROTO_ICMP:							/*ICMP协议*/
			skb->th.icmph = 							/*ICMP头部指针获取*/
				(struct sip_icmphdr*)skb_put(skb, sizeof(struct sip_icmphdr));
			icmp_input(dev, skb);					/*转给ICMP模块处理*/
			printf("ip IPPROTO_ICMP = %d\n",iph->protocol);
			break;
		case IPPROTO_UDP:							/*UDP协议*/
			skb->th.udph = 							/*UDP头部指针获取*/
				(struct sip_udphdr*)skb_put(skb, sizeof(struct sip_udphdr));
			SIP_UDPInput(dev, skb);					/*转给UDP模块处理*/
			printf("ip IPPROTO_UDP = %d\n",iph->protocol);
			break;
		default:
			break;
	}
EXITip_input:	
	DBGPRINT(DBG_LEVEL_TRACE,"<==ip_input\n");
	return retval;
}