⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 myip_output.c

📁 一个基于linux的TCP/IP协议栈的实现
💻 C
📖 第 1 页 / 共 2 页
字号:
extern struct ipstats_mib *myip_statistics[2]; #define MYIP_INC_STATS(field)		SNMP_INC_STATS(myip_statistics, field)int sysctl_ip_default_ttl = IPDEFTTL;void __init myip_init(void){	myip_rt_init();	myinet_initpeers();#if defined(CONFIG_IP_MULTICAST) && defined(CONFIG_PROC_FS)	myigmp_mc_proc_init();#endif}void __exit myip_exit(void){#if defined(CONFIG_IP_MULTICAST) && defined(CONFIG_PROC_FS)	myigmp_mc_proc_exit();#endif	myinetpeers_exit();	myip_rt_exit();}static inline int myip_select_ttl(struct inet_sock *inet, struct dst_entry *dst){	int ttl = inet->uc_ttl;	if (ttl < 0)		ttl = dst_metric(dst, RTAX_HOPLIMIT);	return ttl;}static inline int myip_ufo_append_data(struct sock *sk,			int getfrag(void *from, char *to, int offset, int len,			       int odd, struct sk_buff *skb),			void *from, int length, int hh_len, int fragheaderlen,			int transhdrlen, int mtu,unsigned int flags){	struct sk_buff *skb;	int err;	if( (skb = skb_peek_tail(&sk->sk_write_queue)) == NULL ){		skb = sock_alloc_send_skb(sk, hh_len + fragheaderlen + transhdrlen + 20,						(flags & MSG_DONTWAIT), &err);		if (skb == NULL)			return err;		skb_reserve(skb, hh_len);		skb_put(skb,fragheaderlen + transhdrlen);		skb->nh.raw = skb->data;		skb->h.raw = skb->data + fragheaderlen;		skb->ip_summed = CHECKSUM_HW;		skb->csum = 0;		sk->sk_sndmsg_off = 0;	}	err = skb_append_datato_frags(sk,skb, getfrag, from,(length - transhdrlen));	if (!err) {		skb_shinfo(skb)->ufo_size = (mtu - fragheaderlen);		__skb_queue_tail(&sk->sk_write_queue, skb);		return 0;	}	kfree_skb(skb);	return err;}int myip_generic_getfrag(void *from, char *to, int offset, int len, int odd, struct sk_buff *skb){	struct iovec *iov = from;	if (skb->ip_summed == CHECKSUM_HW) {		if (memcpy_fromiovecend(to, iov, offset, len) < 0)			return -EFAULT;	} else {		unsigned int csum = 0;		if (csum_partial_copy_fromiovecend(to, iov, offset, len, &csum) < 0)			return -EFAULT;		skb->csum = csum_block_add(skb->csum, csum, odd);	}	return 0;}int myip_append_data(struct sock *sk, int getfrag(void *from, char *to, int offset, int len,			       int odd, struct sk_buff *skb), void *from, int length, int transhdrlen,		   struct ipcm_cookie *ipc, struct rtable *rt, unsigned int flags){	struct inet_sock *inet = inet_sk(sk);	struct sk_buff *skb;	struct ip_options *opt = NULL;	int hh_len;	int exthdrlen;	int mtu;	int copy;	int err;	int offset = 0;	unsigned int maxfraglen, fragheaderlen;	int csummode = CHECKSUM_NONE;	if( flags & MSG_PROBE )		return 0;	if( skb_queue_empty(&sk->sk_write_queue) ){		opt = ipc->opt;		if( opt ){			if( inet->cork.opt == NULL ){				inet->cork.opt = kmalloc(sizeof(struct ip_options) + 40, sk->sk_allocation);				if( unlikely(inet->cork.opt == NULL) )					return -ENOBUFS;			}			memcpy( inet->cork.opt, opt, sizeof(struct ip_options) + opt->optlen );			inet->cork.flags |= IPCORK_OPT;			inet->cork.addr = ipc->addr;		}		dst_hold(&rt->u.dst);		inet->cork.fragsize = mtu = dst_mtu(rt->u.dst.path);		inet->cork.rt = rt;		inet->cork.length = 0;		sk->sk_sndmsg_page = NULL;		sk->sk_sndmsg_off = 0;		if ((exthdrlen = rt->u.dst.header_len) != 0) {			length += exthdrlen;			transhdrlen += exthdrlen;		}	}else{		rt = inet->cork.rt;		if (inet->cork.flags & IPCORK_OPT)			opt = inet->cork.opt;		transhdrlen = 0;		exthdrlen = 0;		mtu = inet->cork.fragsize;	}	hh_len = LL_RESERVED_SPACE(rt->u.dst.dev);	fragheaderlen = sizeof(struct iphdr) + (opt ? opt->optlen : 0);	maxfraglen = ((mtu - fragheaderlen) & ~7) + fragheaderlen;		if( inet->cork.length + length > 0xFFFF - fragheaderlen ){		myip_local_error(sk, EMSGSIZE, rt->rt_dst, inet->dport, mtu-exthdrlen);		return -EMSGSIZE;	}	if (transhdrlen && length + fragheaderlen <= mtu &&	    rt->u.dst.dev->features & (NETIF_F_IP_CSUM|NETIF_F_NO_CSUM|NETIF_F_HW_CSUM) &&	    !exthdrlen)		csummode = CHECKSUM_HW;	inet->cork.length += length;	if( ((length > mtu) && (sk->sk_protocol == MY_IPPROTO_UDP)) &&		(rt->u.dst.dev->features & NETIF_F_UFO) ){		err = myip_ufo_append_data( sk, getfrag, from, length, hh_len,						fragheaderlen, transhdrlen, mtu, flags );		if (err)			goto error;		return 0;	}	if( (skb = skb_peek_tail(&sk->sk_write_queue)) == NULL )		goto alloc_new_skb;		while (length > 0) {		copy = mtu - skb->len;		if (copy < length)			copy = maxfraglen - skb->len;		if (copy <= 0) {			char *data;			unsigned int datalen;			unsigned int fraglen;			unsigned int fraggap;			unsigned int alloclen;			struct sk_buff *skb_prev;alloc_new_skb:			skb_prev = skb;			if (skb_prev)				fraggap = skb_prev->len - maxfraglen;			else				fraggap = 0;			datalen = length + fraggap;			if (datalen > mtu - fragheaderlen)				datalen = maxfraglen - fragheaderlen;			fraglen = datalen + fragheaderlen;			if( (flags & MSG_MORE) && !(rt->u.dst.dev->features & NETIF_F_SG) )				alloclen = mtu;			else				alloclen = datalen + fragheaderlen;			if (datalen == length)				alloclen += rt->u.dst.trailer_len;			printk(KERN_INFO "data len: %d\n", datalen);			printk(KERN_INFO "maxfraglen: %d\n", maxfraglen);			printk(KERN_INFO "fragheaderlen: %d\n", fragheaderlen);			printk(KERN_INFO "fraglen: %d\n", fraglen);			printk(KERN_INFO "alloclen: %d\n", alloclen);			printk(KERN_INFO "transhdrlen: %d\n", transhdrlen);			printk(KERN_INFO "exthdrlen: %d\n", exthdrlen);			printk(KERN_INFO "hh_len: %d\n", hh_len );			if( transhdrlen ){				skb = sock_alloc_send_skb( sk, alloclen + hh_len + 15,						(flags & MSG_DONTWAIT), &err );			}else{				skb = NULL;				if( atomic_read(&sk->sk_wmem_alloc) <= 2 * sk->sk_sndbuf )					skb = sock_wmalloc(sk, alloclen + hh_len + 15, 1,sk->sk_allocation);				if (unlikely(skb == NULL))					err = -ENOBUFS;			}			if (skb == NULL)				goto error;			printk(KERN_INFO "wmem: %d, sndbuf: %d\n", atomic_read(&sk->sk_wmem_alloc), sk->sk_sndbuf);			printk(KERN_INFO "sk_buff len: %d\n", sizeof(struct sk_buff) );			skb->ip_summed = csummode;			skb->csum = 0;			skb_reserve(skb, hh_len);						data = skb_put(skb, fraglen);			skb->nh.raw = data + exthdrlen;			data += fragheaderlen;			skb->h.raw = data + exthdrlen;			if (fraggap) {				skb->csum = skb_copy_and_csum_bits( skb_prev, maxfraglen,								data + transhdrlen, fraggap, 0);				skb_prev->csum = csum_sub( skb_prev->csum,								skb->csum );				data += fraggap;				skb_trim(skb_prev, maxfraglen);			}			copy = datalen - transhdrlen - fraggap;			if (copy > 0 && getfrag(from, data + transhdrlen, offset, copy, fraggap, skb) < 0) {				err = -EFAULT;				kfree_skb(skb);				goto error;			}			offset += copy;			length -= datalen - fraggap;			transhdrlen = 0;			exthdrlen = 0;			csummode = CHECKSUM_NONE;			printk(KERN_INFO "offset: %d, length: %d\n", offset, length);			__skb_queue_tail(&sk->sk_write_queue, skb);			continue;		}		if( copy > length ) copy = length;		if( !(rt->u.dst.dev->features & NETIF_F_SG) ){			unsigned int off;			off = skb->len;			if( getfrag(from, skb_put(skb, copy), offset, copy, off, skb) < 0 ){				__skb_trim( skb, off );				err = -EFAULT;				goto error;			}		}else{			int i = skb_shinfo(skb)->nr_frags;			skb_frag_t *frag = &skb_shinfo(skb)->frags[i-1];			struct page *page = sk->sk_sndmsg_page;			int off = sk->sk_sndmsg_off;			unsigned int left;			if (page && (left = PAGE_SIZE - off) > 0) {				if( copy >= left ) copy = left;				if( page != frag->page ){					if( i == MAX_SKB_FRAGS ){						err = -EMSGSIZE;						goto error;					}					get_page(page);	 				skb_fill_page_desc(skb, i, page, sk->sk_sndmsg_off, 0);					frag = &skb_shinfo(skb)->frags[i];				}			}else if( i < MAX_SKB_FRAGS ){				if (copy > PAGE_SIZE) copy = PAGE_SIZE;				page = alloc_pages(sk->sk_allocation, 0);				if (page == NULL)  {					err = -ENOMEM;					goto error;				}				sk->sk_sndmsg_page = page;				sk->sk_sndmsg_off = 0;				skb_fill_page_desc(skb, i, page, 0, 0);				frag = &skb_shinfo(skb)->frags[i];				skb->truesize += PAGE_SIZE;				atomic_add(PAGE_SIZE, &sk->sk_wmem_alloc);			}else{				err = -EMSGSIZE;				goto error;			}			if( getfrag(from, page_address(frag->page)+frag->page_offset+frag->size, 									offset, copy, skb->len, skb) < 0 ){				err = -EFAULT;				goto error;			}			sk->sk_sndmsg_off += copy;			frag->size += copy;			skb->len += copy;			skb->data_len += copy;		}		offset += copy;		length -= copy;	}	return 0;error:	inet->cork.length -= length;	MYIP_INC_STATS(IPSTATS_MIB_OUTDISCARDS);	return err; }int myip_queue_xmit(struct sk_buff *skb, int ipfragok){	struct sock *sk = skb->sk;	struct inet_sock *inet = inet_sk(sk);	struct ip_options *opt = inet->opt;	struct rtable *rt;	struct iphdr *iph;	rt = (struct rtable *) skb->dst;	if (rt != NULL)		goto packet_routed;	rt = (struct rtable *)__sk_dst_check(sk, 0);	if (rt == NULL) {		u32 daddr;		daddr = inet->daddr;		if(opt && opt->srr)			daddr = opt->faddr;		{			struct flowi fl = { .oif = sk->sk_bound_dev_if,					.nl_u = { .ip4_u =							{ .daddr = daddr,									.saddr = inet->saddr,									.tos = RT_CONN_FLAGS(sk) } },					.proto = sk->sk_protocol,					.uli_u = { .ports =							{ .sport = inet->sport,									.dport = inet->dport } } };			if( myip_route_output_flow(&rt, &fl, sk, 0) )				goto no_route;		}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -