📄 myip_output.c
字号:
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 + -