diff options
Diffstat (limited to 'net/ipv4')
31 files changed, 119 insertions, 110 deletions
diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c index dc206f1..0a27745 100644 --- a/net/ipv4/af_inet.c +++ b/net/ipv4/af_inet.c @@ -1257,7 +1257,7 @@ out_unregister_udp_proto: goto out; } -module_init(inet_init); +fs_initcall(inet_init); /* ------------------------------------------------------------------------ */ diff --git a/net/ipv4/arp.c b/net/ipv4/arp.c index 041dadd..4749d50 100644 --- a/net/ipv4/arp.c +++ b/net/ipv4/arp.c @@ -928,7 +928,8 @@ static void parp_redo(struct sk_buff *skb) * Receive an arp request from the device layer. */ -int arp_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt, struct net_device *orig_dev) +static int arp_rcv(struct sk_buff *skb, struct net_device *dev, + struct packet_type *pt, struct net_device *orig_dev) { struct arphdr *arp; @@ -1417,7 +1418,6 @@ static int __init arp_proc_init(void) EXPORT_SYMBOL(arp_broken_ops); EXPORT_SYMBOL(arp_find); -EXPORT_SYMBOL(arp_rcv); EXPORT_SYMBOL(arp_create); EXPORT_SYMBOL(arp_xmit); EXPORT_SYMBOL(arp_send); diff --git a/net/ipv4/devinet.c b/net/ipv4/devinet.c index 81c2f78..54419b2 100644 --- a/net/ipv4/devinet.c +++ b/net/ipv4/devinet.c @@ -1556,7 +1556,6 @@ void __init devinet_init(void) #endif } -EXPORT_SYMBOL(devinet_ioctl); EXPORT_SYMBOL(in_dev_finish_destroy); EXPORT_SYMBOL(inet_select_addr); EXPORT_SYMBOL(inetdev_by_index); diff --git a/net/ipv4/fib_frontend.c b/net/ipv4/fib_frontend.c index 4e3d381..cdde963 100644 --- a/net/ipv4/fib_frontend.c +++ b/net/ipv4/fib_frontend.c @@ -666,4 +666,3 @@ void __init ip_fib_init(void) } EXPORT_SYMBOL(inet_addr_type); -EXPORT_SYMBOL(ip_rt_ioctl); diff --git a/net/ipv4/inet_hashtables.c b/net/ipv4/inet_hashtables.c index ef7366f..ee9b551 100644 --- a/net/ipv4/inet_hashtables.c +++ b/net/ipv4/inet_hashtables.c @@ -43,8 +43,6 @@ struct inet_bind_bucket *inet_bind_bucket_create(kmem_cache_t *cachep, return tb; } -EXPORT_SYMBOL(inet_bind_bucket_create); - /* * Caller must hold hashbucket lock for this tb with local BH disabled */ @@ -64,8 +62,6 @@ void inet_bind_hash(struct sock *sk, struct inet_bind_bucket *tb, inet_csk(sk)->icsk_bind_hash = tb; } -EXPORT_SYMBOL(inet_bind_hash); - /* * Get rid of any references to a local port held by the given sock. */ diff --git a/net/ipv4/ip_input.c b/net/ipv4/ip_input.c index 18d7fad..c9026db 100644 --- a/net/ipv4/ip_input.c +++ b/net/ipv4/ip_input.c @@ -337,7 +337,7 @@ static inline int ip_rcv_finish(struct sk_buff *skb) * Initialise the virtual path cache for the packet. It describes * how the packet travels inside Linux networking. */ - if (likely(skb->dst == NULL)) { + if (skb->dst == NULL) { int err = ip_route_input(skb, iph->daddr, iph->saddr, iph->tos, skb->dev); if (unlikely(err)) { diff --git a/net/ipv4/ip_options.c b/net/ipv4/ip_options.c index 9bebad0..cbcae65 100644 --- a/net/ipv4/ip_options.c +++ b/net/ipv4/ip_options.c @@ -209,7 +209,7 @@ int ip_options_echo(struct ip_options * dopt, struct sk_buff * skb) void ip_options_fragment(struct sk_buff * skb) { - unsigned char * optptr = skb->nh.raw; + unsigned char * optptr = skb->nh.raw + sizeof(struct iphdr); struct ip_options * opt = &(IPCB(skb)->opt); int l = opt->optlen; int optlen; diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c index 8dcba38..cff9c3a 100644 --- a/net/ipv4/ip_output.c +++ b/net/ipv4/ip_output.c @@ -904,7 +904,7 @@ alloc_new_skb: * because we have no idea what fragment will be * the last. */ - if (datalen == length) + if (datalen == length + fraggap) alloclen += rt->u.dst.trailer_len; if (transhdrlen) { diff --git a/net/ipv4/ipcomp.c b/net/ipv4/ipcomp.c index 04a4294..95278b2 100644 --- a/net/ipv4/ipcomp.c +++ b/net/ipv4/ipcomp.c @@ -210,7 +210,7 @@ static void ipcomp4_err(struct sk_buff *skb, u32 info) skb->h.icmph->code != ICMP_FRAG_NEEDED) return; - spi = ntohl(ntohs(ipch->cpi)); + spi = htonl(ntohs(ipch->cpi)); x = xfrm_state_lookup((xfrm_address_t *)&iph->daddr, spi, IPPROTO_COMP, AF_INET); if (!x) @@ -290,11 +290,8 @@ static void ipcomp_free_scratches(void) if (!scratches) return; - for_each_possible_cpu(i) { - void *scratch = *per_cpu_ptr(scratches, i); - if (scratch) - vfree(scratch); - } + for_each_possible_cpu(i) + vfree(*per_cpu_ptr(scratches, i)); free_percpu(scratches); } diff --git a/net/ipv4/netfilter/Kconfig b/net/ipv4/netfilter/Kconfig index c60fd5c..d407253 100644 --- a/net/ipv4/netfilter/Kconfig +++ b/net/ipv4/netfilter/Kconfig @@ -170,8 +170,8 @@ config IP_NF_PPTP Documentation/modules.txt. If unsure, say `N'. config IP_NF_H323 - tristate 'H.323 protocol support' - depends on IP_NF_CONNTRACK + tristate 'H.323 protocol support (EXPERIMENTAL)' + depends on IP_NF_CONNTRACK && EXPERIMENTAL help H.323 is a VoIP signalling protocol from ITU-T. As one of the most important VoIP protocols, it is widely used by voice hardware and @@ -345,7 +345,7 @@ config IP_NF_TARGET_LOG To compile it as a module, choose M here. If unsure, say N. config IP_NF_TARGET_ULOG - tristate "ULOG target support (OBSOLETE)" + tristate "ULOG target support" depends on IP_NF_IPTABLES ---help--- diff --git a/net/ipv4/netfilter/arp_tables.c b/net/ipv4/netfilter/arp_tables.c index c2d92f9..d0d1919 100644 --- a/net/ipv4/netfilter/arp_tables.c +++ b/net/ipv4/netfilter/arp_tables.c @@ -948,7 +948,7 @@ static int do_add_counters(void __user *user, unsigned int len) write_lock_bh(&t->lock); private = t->private; - if (private->number != paddc->num_counters) { + if (private->number != tmp.num_counters) { ret = -EINVAL; goto unlock_up_free; } diff --git a/net/ipv4/netfilter/ip_conntrack_core.c b/net/ipv4/netfilter/ip_conntrack_core.c index 979a2ea..a297da7 100644 --- a/net/ipv4/netfilter/ip_conntrack_core.c +++ b/net/ipv4/netfilter/ip_conntrack_core.c @@ -1318,6 +1318,7 @@ getorigdst(struct sock *sk, int optval, void __user *user, int *len) .tuple.dst.u.tcp.port; sin.sin_addr.s_addr = ct->tuplehash[IP_CT_DIR_ORIGINAL] .tuple.dst.ip; + memset(sin.sin_zero, 0, sizeof(sin.sin_zero)); DEBUGP("SO_ORIGINAL_DST: %u.%u.%u.%u %u\n", NIPQUAD(sin.sin_addr.s_addr), ntohs(sin.sin_port)); diff --git a/net/ipv4/netfilter/ip_conntrack_helper_h323.c b/net/ipv4/netfilter/ip_conntrack_helper_h323.c index 2c2fb70..518f581 100644 --- a/net/ipv4/netfilter/ip_conntrack_helper_h323.c +++ b/net/ipv4/netfilter/ip_conntrack_helper_h323.c @@ -162,6 +162,8 @@ static int get_tpkt_data(struct sk_buff **pskb, struct ip_conntrack *ct, /* Validate TPKT length */ tpktlen = tpkt[2] * 256 + tpkt[3]; + if (tpktlen < 4) + goto clear_out; if (tpktlen > tcpdatalen) { if (tcpdatalen == 4) { /* Separate TPKT header */ /* Netmeeting sends TPKT header and data separately */ diff --git a/net/ipv4/netfilter/ip_conntrack_helper_h323_asn1.c b/net/ipv4/netfilter/ip_conntrack_helper_h323_asn1.c index 4807800..26dfeca 100644 --- a/net/ipv4/netfilter/ip_conntrack_helper_h323_asn1.c +++ b/net/ipv4/netfilter/ip_conntrack_helper_h323_asn1.c @@ -2,7 +2,7 @@ * ip_conntrack_helper_h323_asn1.c - BER and PER decoding library for H.323 * conntrack/NAT module. * - * Copyright (c) 2006 by Jing Min Zhao <zhaojingmin@hotmail.com> + * Copyright (c) 2006 by Jing Min Zhao <zhaojingmin@users.sourceforge.net> * * This source code is licensed under General Public License version 2. * @@ -528,14 +528,15 @@ int decode_seq(bitstr_t * bs, field_t * f, char *base, int level) /* Decode */ if ((err = (Decoders[son->type]) (bs, son, base, - level + 1)) > - H323_ERROR_STOP) + level + 1)) < + H323_ERROR_NONE) return err; bs->cur = beg + len; bs->bit = 0; } else if ((err = (Decoders[son->type]) (bs, son, base, - level + 1))) + level + 1)) < + H323_ERROR_NONE) return err; } @@ -554,7 +555,7 @@ int decode_seq(bitstr_t * bs, field_t * f, char *base, int level) /* Decode the extension components */ for (opt = 0; opt < bmp2_len; opt++, i++, son++) { - if (son->attr & STOP) { + if (i < f->ub && son->attr & STOP) { PRINT("%*.s%s\n", (level + 1) * TAB_SIZE, " ", son->name); return H323_ERROR_STOP; @@ -584,8 +585,8 @@ int decode_seq(bitstr_t * bs, field_t * f, char *base, int level) beg = bs->cur; if ((err = (Decoders[son->type]) (bs, son, base, - level + 1)) > - H323_ERROR_STOP) + level + 1)) < + H323_ERROR_NONE) return err; bs->cur = beg + len; @@ -660,18 +661,20 @@ int decode_seqof(bitstr_t * bs, field_t * f, char *base, int level) i < effective_count ? base : NULL, - level + 1)) > - H323_ERROR_STOP) + level + 1)) < + H323_ERROR_NONE) return err; bs->cur = beg + len; bs->bit = 0; } else - if ((err = (Decoders[son->type]) (bs, son, - i < effective_count ? - base : NULL, - level + 1))) - return err; + if ((err = (Decoders[son->type]) (bs, son, + i < + effective_count ? + base : NULL, + level + 1)) < + H323_ERROR_NONE) + return err; if (base) base += son->offset; @@ -703,6 +706,10 @@ int decode_choice(bitstr_t * bs, field_t * f, char *base, int level) type = get_bits(bs, f->sz); } + /* Write Type */ + if (base) + *(unsigned *) base = type; + /* Check Range */ if (type >= f->ub) { /* Newer version? */ BYTE_ALIGN(bs); @@ -712,10 +719,6 @@ int decode_choice(bitstr_t * bs, field_t * f, char *base, int level) return H323_ERROR_NONE; } - /* Write Type */ - if (base) - *(unsigned *) base = type; - /* Transfer to son level */ son = &f->fields[type]; if (son->attr & STOP) { @@ -735,13 +738,14 @@ int decode_choice(bitstr_t * bs, field_t * f, char *base, int level) } beg = bs->cur; - if ((err = (Decoders[son->type]) (bs, son, base, level + 1)) > - H323_ERROR_STOP) + if ((err = (Decoders[son->type]) (bs, son, base, level + 1)) < + H323_ERROR_NONE) return err; bs->cur = beg + len; bs->bit = 0; - } else if ((err = (Decoders[son->type]) (bs, son, base, level + 1))) + } else if ((err = (Decoders[son->type]) (bs, son, base, level + 1)) < + H323_ERROR_NONE) return err; return H323_ERROR_NONE; diff --git a/net/ipv4/netfilter/ip_conntrack_helper_pptp.c b/net/ipv4/netfilter/ip_conntrack_helper_pptp.c index 7d3ba43..8ccfe17 100644 --- a/net/ipv4/netfilter/ip_conntrack_helper_pptp.c +++ b/net/ipv4/netfilter/ip_conntrack_helper_pptp.c @@ -469,8 +469,8 @@ pptp_inbound_pkt(struct sk_buff **pskb, DEBUGP("%s but no session\n", pptp_msg_name[msg]); break; } - if (info->sstate != PPTP_CALL_IN_REP - && info->sstate != PPTP_CALL_IN_CONF) { + if (info->cstate != PPTP_CALL_IN_REP + && info->cstate != PPTP_CALL_IN_CONF) { DEBUGP("%s but never sent IN_CALL_REPLY\n", pptp_msg_name[msg]); break; diff --git a/net/ipv4/netfilter/ip_conntrack_proto_sctp.c b/net/ipv4/netfilter/ip_conntrack_proto_sctp.c index 5259abd..0416073 100644 --- a/net/ipv4/netfilter/ip_conntrack_proto_sctp.c +++ b/net/ipv4/netfilter/ip_conntrack_proto_sctp.c @@ -235,12 +235,15 @@ static int do_basic_checks(struct ip_conntrack *conntrack, flag = 1; } - /* Cookie Ack/Echo chunks not the first OR - Init / Init Ack / Shutdown compl chunks not the only chunks */ - if ((sch->type == SCTP_CID_COOKIE_ACK + /* + * Cookie Ack/Echo chunks not the first OR + * Init / Init Ack / Shutdown compl chunks not the only chunks + * OR zero-length. + */ + if (((sch->type == SCTP_CID_COOKIE_ACK || sch->type == SCTP_CID_COOKIE_ECHO || flag) - && count !=0 ) { + && count !=0) || !sch->length) { DEBUGP("Basic checks failed\n"); return 1; } diff --git a/net/ipv4/netfilter/ip_nat_proto_gre.c b/net/ipv4/netfilter/ip_nat_proto_gre.c index 6c4899d..96ceaba 100644 --- a/net/ipv4/netfilter/ip_nat_proto_gre.c +++ b/net/ipv4/netfilter/ip_nat_proto_gre.c @@ -49,15 +49,15 @@ gre_in_range(const struct ip_conntrack_tuple *tuple, const union ip_conntrack_manip_proto *min, const union ip_conntrack_manip_proto *max) { - u_int32_t key; + __be16 key; if (maniptype == IP_NAT_MANIP_SRC) key = tuple->src.u.gre.key; else key = tuple->dst.u.gre.key; - return ntohl(key) >= ntohl(min->gre.key) - && ntohl(key) <= ntohl(max->gre.key); + return ntohs(key) >= ntohs(min->gre.key) + && ntohs(key) <= ntohs(max->gre.key); } /* generate unique tuple ... */ @@ -81,14 +81,14 @@ gre_unique_tuple(struct ip_conntrack_tuple *tuple, min = 1; range_size = 0xffff; } else { - min = ntohl(range->min.gre.key); - range_size = ntohl(range->max.gre.key) - min + 1; + min = ntohs(range->min.gre.key); + range_size = ntohs(range->max.gre.key) - min + 1; } DEBUGP("min = %u, range_size = %u\n", min, range_size); for (i = 0; i < range_size; i++, key++) { - *keyptr = htonl(min + key % range_size); + *keyptr = htons(min + key % range_size); if (!ip_nat_used_tuple(tuple, conntrack)) return 1; } diff --git a/net/ipv4/netfilter/ip_nat_snmp_basic.c b/net/ipv4/netfilter/ip_nat_snmp_basic.c index c622538..c332442 100644 --- a/net/ipv4/netfilter/ip_nat_snmp_basic.c +++ b/net/ipv4/netfilter/ip_nat_snmp_basic.c @@ -768,6 +768,7 @@ static unsigned char snmp_object_decode(struct asn1_ctx *ctx, len *= sizeof(unsigned long); *obj = kmalloc(sizeof(struct snmp_object) + len, GFP_ATOMIC); if (*obj == NULL) { + kfree(lp); kfree(id); if (net_ratelimit()) printk("OOM in bsalg (%d)\n", __LINE__); @@ -1003,12 +1004,12 @@ static unsigned char snmp_trap_decode(struct asn1_ctx *ctx, return 1; +err_addr_free: + kfree((unsigned long *)trap->ip_address); + err_id_free: kfree(trap->id); -err_addr_free: - kfree((unsigned long *)trap->ip_address); - return 0; } @@ -1126,11 +1127,10 @@ static int snmp_parse_mangle(unsigned char *msg, struct snmp_v1_trap trap; unsigned char ret = snmp_trap_decode(&ctx, &trap, map, check); - /* Discard trap allocations regardless */ - kfree(trap.id); - kfree((unsigned long *)trap.ip_address); - - if (!ret) + if (ret) { + kfree(trap.id); + kfree((unsigned long *)trap.ip_address); + } else return ret; } else { diff --git a/net/ipv4/netfilter/ip_nat_standalone.c b/net/ipv4/netfilter/ip_nat_standalone.c index 8f760b2..67e6767 100644 --- a/net/ipv4/netfilter/ip_nat_standalone.c +++ b/net/ipv4/netfilter/ip_nat_standalone.c @@ -219,8 +219,10 @@ ip_nat_out(unsigned int hooknum, const struct net_device *out, int (*okfn)(struct sk_buff *)) { +#ifdef CONFIG_XFRM struct ip_conntrack *ct; enum ip_conntrack_info ctinfo; +#endif unsigned int ret; /* root is playing with raw sockets. */ diff --git a/net/ipv4/netfilter/ip_tables.c b/net/ipv4/netfilter/ip_tables.c index d25ac8b..cee3397 100644 --- a/net/ipv4/netfilter/ip_tables.c +++ b/net/ipv4/netfilter/ip_tables.c @@ -956,15 +956,16 @@ struct compat_ipt_standard_target compat_int_t verdict; }; -#define IPT_ST_OFFSET (sizeof(struct ipt_standard_target) - \ - sizeof(struct compat_ipt_standard_target)) - struct compat_ipt_standard { struct compat_ipt_entry entry; struct compat_ipt_standard_target target; }; +#define IPT_ST_LEN XT_ALIGN(sizeof(struct ipt_standard_target)) +#define IPT_ST_COMPAT_LEN COMPAT_XT_ALIGN(sizeof(struct compat_ipt_standard_target)) +#define IPT_ST_OFFSET (IPT_ST_LEN - IPT_ST_COMPAT_LEN) + static int compat_ipt_standard_fn(void *target, void **dstptr, int *size, int convert) { @@ -975,35 +976,29 @@ static int compat_ipt_standard_fn(void *target, ret = 0; switch (convert) { case COMPAT_TO_USER: - pst = (struct ipt_standard_target *)target; + pst = target; memcpy(&compat_st.target, &pst->target, - sizeof(struct ipt_entry_target)); + sizeof(compat_st.target)); compat_st.verdict = pst->verdict; if (compat_st.verdict > 0) compat_st.verdict -= compat_calc_jump(compat_st.verdict); - compat_st.target.u.user.target_size = - sizeof(struct compat_ipt_standard_target); - if (__copy_to_user(*dstptr, &compat_st, - sizeof(struct compat_ipt_standard_target))) + compat_st.target.u.user.target_size = IPT_ST_COMPAT_LEN; + if (copy_to_user(*dstptr, &compat_st, IPT_ST_COMPAT_LEN)) ret = -EFAULT; *size -= IPT_ST_OFFSET; - *dstptr += sizeof(struct compat_ipt_standard_target); + *dstptr += IPT_ST_COMPAT_LEN; break; case COMPAT_FROM_USER: - pcompat_st = - (struct compat_ipt_standard_target *)target; - memcpy(&st.target, &pcompat_st->target, - sizeof(struct ipt_entry_target)); + pcompat_st = target; + memcpy(&st.target, &pcompat_st->target, IPT_ST_COMPAT_LEN); st.verdict = pcompat_st->verdict; if (st.verdict > 0) st.verdict += compat_calc_jump(st.verdict); - st.target.u.user.target_size = - sizeof(struct ipt_standard_target); - memcpy(*dstptr, &st, - sizeof(struct ipt_standard_target)); + st.target.u.user.target_size = IPT_ST_LEN; + memcpy(*dstptr, &st, IPT_ST_LEN); *size += IPT_ST_OFFSET; - *dstptr += sizeof(struct ipt_standard_target); + *dstptr += IPT_ST_LEN; break; case COMPAT_CALC_SIZE: *size += IPT_ST_OFFSET; @@ -1446,7 +1441,7 @@ static int compat_copy_entry_to_user(struct ipt_entry *e, ret = -EFAULT; origsize = *size; ce = (struct compat_ipt_entry __user *)*dstptr; - if (__copy_to_user(ce, e, sizeof(struct ipt_entry))) + if (copy_to_user(ce, e, sizeof(struct ipt_entry))) goto out; *dstptr += sizeof(struct compat_ipt_entry); @@ -1464,9 +1459,9 @@ static int compat_copy_entry_to_user(struct ipt_entry *e, goto out; ret = -EFAULT; next_offset = e->next_offset - (origsize - *size); - if (__put_user(target_offset, &ce->target_offset)) + if (put_user(target_offset, &ce->target_offset)) goto out; - if (__put_user(next_offset, &ce->next_offset)) + if (put_user(next_offset, &ce->next_offset)) goto out; return 0; out: diff --git a/net/ipv4/netfilter/ipt_LOG.c b/net/ipv4/netfilter/ipt_LOG.c index 39fd4c2..b98f7b0 100644 --- a/net/ipv4/netfilter/ipt_LOG.c +++ b/net/ipv4/netfilter/ipt_LOG.c @@ -428,7 +428,7 @@ ipt_log_target(struct sk_buff **pskb, if (loginfo->logflags & IPT_LOG_NFLOG) nf_log_packet(PF_INET, hooknum, *pskb, in, out, &li, - loginfo->prefix); + "%s", loginfo->prefix); else ipt_log_packet(PF_INET, hooknum, *pskb, in, out, &li, loginfo->prefix); diff --git a/net/ipv4/netfilter/ipt_recent.c b/net/ipv4/netfilter/ipt_recent.c index 1438432..b847ee4 100644 --- a/net/ipv4/netfilter/ipt_recent.c +++ b/net/ipv4/netfilter/ipt_recent.c @@ -821,6 +821,7 @@ checkentry(const char *tablename, /* Create our proc 'status' entry. */ curr_table->status_proc = create_proc_entry(curr_table->name, ip_list_perms, proc_net_ipt_recent); if (!curr_table->status_proc) { + vfree(hold); printk(KERN_INFO RECENT_NAME ": checkentry: unable to allocate for /proc entry.\n"); /* Destroy the created table */ spin_lock_bh(&recent_lock); @@ -845,7 +846,6 @@ checkentry(const char *tablename, spin_unlock_bh(&recent_lock); vfree(curr_table->time_info); vfree(curr_table->hash_table); - vfree(hold); vfree(curr_table->table); vfree(curr_table); return 0; diff --git a/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c b/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c index 5bc9f64..77d9744 100644 --- a/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c +++ b/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c @@ -348,6 +348,7 @@ getorigdst(struct sock *sk, int optval, void __user *user, int *len) .tuple.dst.u.tcp.port; sin.sin_addr.s_addr = ct->tuplehash[IP_CT_DIR_ORIGINAL] .tuple.dst.u3.ip; + memset(sin.sin_zero, 0, sizeof(sin.sin_zero)); DEBUGP("SO_ORIGINAL_DST: %u.%u.%u.%u %u\n", NIPQUAD(sin.sin_addr.s_addr), ntohs(sin.sin_port)); diff --git a/net/ipv4/route.c b/net/ipv4/route.c index ff43482..cc9423d 100644 --- a/net/ipv4/route.c +++ b/net/ipv4/route.c @@ -2741,7 +2741,10 @@ int inet_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr* nlh, void *arg) /* Reserve room for dummy headers, this skb can pass through good chunk of routing engine. */ - skb->mac.raw = skb->data; + skb->mac.raw = skb->nh.raw = skb->data; + + /* Bugfix: need to give ip_route_input enough of an IP header to not gag. */ + skb->nh.iph->protocol = IPPROTO_ICMP; skb_reserve(skb, MAX_HEADER + sizeof(struct iphdr)); if (rta[RTA_SRC - 1]) diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c index 87f68e7..e2b7b80 100644 --- a/net/ipv4/tcp.c +++ b/net/ipv4/tcp.c @@ -1468,6 +1468,7 @@ void tcp_close(struct sock *sk, long timeout) { struct sk_buff *skb; int data_was_unread = 0; + int state; lock_sock(sk); sk->sk_shutdown = SHUTDOWN_MASK; @@ -1544,6 +1545,11 @@ void tcp_close(struct sock *sk, long timeout) sk_stream_wait_close(sk, timeout); adjudge_to_death: + state = sk->sk_state; + sock_hold(sk); + sock_orphan(sk); + atomic_inc(sk->sk_prot->orphan_count); + /* It is the last release_sock in its life. It will remove backlog. */ release_sock(sk); @@ -1555,8 +1561,9 @@ adjudge_to_death: bh_lock_sock(sk); BUG_TRAP(!sock_owned_by_user(sk)); - sock_hold(sk); - sock_orphan(sk); + /* Have we already been destroyed by a softirq or backlog? */ + if (state != TCP_CLOSE && sk->sk_state == TCP_CLOSE) + goto out; /* This is a (useful) BSD violating of the RFC. There is a * problem with TCP as specified in that the other end could @@ -1584,7 +1591,6 @@ adjudge_to_death: if (tmo > TCP_TIMEWAIT_LEN) { inet_csk_reset_keepalive_timer(sk, tcp_fin_time(sk)); } else { - atomic_inc(sk->sk_prot->orphan_count); tcp_time_wait(sk, TCP_FIN_WAIT2, tmo); goto out; } @@ -1603,7 +1609,6 @@ adjudge_to_death: NET_INC_STATS_BH(LINUX_MIB_TCPABORTONMEMORY); } } - atomic_inc(sk->sk_prot->orphan_count); if (sk->sk_state == TCP_CLOSE) inet_csk_destroy_sock(sk); diff --git a/net/ipv4/tcp_highspeed.c b/net/ipv4/tcp_highspeed.c index e0e9d13..ba7c63c 100644 --- a/net/ipv4/tcp_highspeed.c +++ b/net/ipv4/tcp_highspeed.c @@ -135,10 +135,11 @@ static void hstcp_cong_avoid(struct sock *sk, u32 adk, u32 rtt, /* Do additive increase */ if (tp->snd_cwnd < tp->snd_cwnd_clamp) { - tp->snd_cwnd_cnt += ca->ai; + /* cwnd = cwnd + a(w) / cwnd */ + tp->snd_cwnd_cnt += ca->ai + 1; if (tp->snd_cwnd_cnt >= tp->snd_cwnd) { - tp->snd_cwnd++; tp->snd_cwnd_cnt -= tp->snd_cwnd; + tp->snd_cwnd++; } } } diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index 195d835..4a538bc 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -1662,6 +1662,8 @@ static void tcp_update_scoreboard(struct sock *sk, struct tcp_sock *tp) if (!(TCP_SKB_CB(skb)->sacked&TCPCB_TAGBITS)) { TCP_SKB_CB(skb)->sacked |= TCPCB_LOST; tp->lost_out += tcp_skb_pcount(skb); + if (IsReno(tp)) + tcp_remove_reno_sacks(sk, tp, tcp_skb_pcount(skb) + 1); /* clear xmit_retrans hint */ if (tp->retransmit_skb_hint && @@ -4559,7 +4561,6 @@ discard: EXPORT_SYMBOL(sysctl_tcp_ecn); EXPORT_SYMBOL(sysctl_tcp_reordering); -EXPORT_SYMBOL(sysctl_tcp_abc); EXPORT_SYMBOL(tcp_parse_options); EXPORT_SYMBOL(tcp_rcv_established); EXPORT_SYMBOL(tcp_rcv_state_process); diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index 9e85c04..672950e 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c @@ -1859,5 +1859,4 @@ EXPORT_SYMBOL(tcp_proc_unregister); #endif EXPORT_SYMBOL(sysctl_local_port_range); EXPORT_SYMBOL(sysctl_tcp_low_latency); -EXPORT_SYMBOL(sysctl_tcp_tw_reuse); diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c index 9d79546..f33c9dd 100644 --- a/net/ipv4/tcp_output.c +++ b/net/ipv4/tcp_output.c @@ -59,9 +59,6 @@ int sysctl_tcp_tso_win_divisor = 3; int sysctl_tcp_mtu_probing = 0; int sysctl_tcp_base_mss = 512; -EXPORT_SYMBOL(sysctl_tcp_mtu_probing); -EXPORT_SYMBOL(sysctl_tcp_base_mss); - static void update_send_head(struct sock *sk, struct tcp_sock *tp, struct sk_buff *skb) { @@ -468,7 +465,7 @@ static int tcp_transmit_skb(struct sock *sk, struct sk_buff *skb, int clone_it, TCP_INC_STATS(TCP_MIB_OUTSEGS); err = icsk->icsk_af_ops->queue_xmit(skb, 0); - if (unlikely(err <= 0)) + if (likely(err <= 0)) return err; tcp_enter_cwr(sk); @@ -536,6 +533,7 @@ int tcp_fragment(struct sock *sk, struct sk_buff *skb, u32 len, unsigned int mss struct tcp_sock *tp = tcp_sk(sk); struct sk_buff *buff; int nsize, old_factor; + int nlen; u16 flags; BUG_ON(len > skb->len); @@ -554,7 +552,11 @@ int tcp_fragment(struct sock *sk, struct sk_buff *skb, u32 len, unsigned int mss buff = sk_stream_alloc_skb(sk, nsize, GFP_ATOMIC); if (buff == NULL) return -ENOMEM; /* We'll just try again later. */ + sk_charge_skb(sk, buff); + nlen = skb->len - len - nsize; + buff->truesize += nlen; + skb->truesize -= nlen; /* Correct the sequence numbers. */ TCP_SKB_CB(buff)->seq = TCP_SKB_CB(skb)->seq + len; @@ -640,7 +642,7 @@ int tcp_fragment(struct sock *sk, struct sk_buff *skb, u32 len, unsigned int mss * eventually). The difference is that pulled data not copied, but * immediately discarded. */ -static unsigned char *__pskb_trim_head(struct sk_buff *skb, int len) +static void __pskb_trim_head(struct sk_buff *skb, int len) { int i, k, eat; @@ -665,7 +667,6 @@ static unsigned char *__pskb_trim_head(struct sk_buff *skb, int len) skb->tail = skb->data; skb->data_len -= len; skb->len = skb->data_len; - return skb->tail; } int tcp_trim_head(struct sock *sk, struct sk_buff *skb, u32 len) @@ -674,12 +675,11 @@ int tcp_trim_head(struct sock *sk, struct sk_buff *skb, u32 len) pskb_expand_head(skb, 0, 0, GFP_ATOMIC)) return -ENOMEM; - if (len <= skb_headlen(skb)) { + /* If len == headlen, we avoid __skb_pull to preserve alignment. */ + if (unlikely(len < skb_headlen(skb))) __skb_pull(skb, len); - } else { - if (__pskb_trim_head(skb, len-skb_headlen(skb)) == NULL) - return -ENOMEM; - } + else + __pskb_trim_head(skb, len - skb_headlen(skb)); TCP_SKB_CB(skb)->seq += len; skb->ip_summed = CHECKSUM_HW; @@ -1040,7 +1040,8 @@ static int tso_fragment(struct sock *sk, struct sk_buff *skb, unsigned int len, if (unlikely(buff == NULL)) return -ENOMEM; - buff->truesize = nlen; + sk_charge_skb(sk, buff); + buff->truesize += nlen; skb->truesize -= nlen; /* Correct the sequence numbers. */ diff --git a/net/ipv4/xfrm4_output.c b/net/ipv4/xfrm4_output.c index 32ad229..4ef8efa 100644 --- a/net/ipv4/xfrm4_output.c +++ b/net/ipv4/xfrm4_output.c @@ -62,7 +62,7 @@ static void xfrm4_encap(struct sk_buff *skb) top_iph->frag_off = (flags & XFRM_STATE_NOPMTUDISC) ? 0 : (iph->frag_off & htons(IP_DF)); if (!top_iph->frag_off) - __ip_select_ident(top_iph, dst, 0); + __ip_select_ident(top_iph, dst->child, 0); top_iph->ttl = dst_metric(dst->child, RTAX_HOPLIMIT); diff --git a/net/ipv4/xfrm4_policy.c b/net/ipv4/xfrm4_policy.c index f285bbf..8604c74 100644 --- a/net/ipv4/xfrm4_policy.c +++ b/net/ipv4/xfrm4_policy.c @@ -221,7 +221,7 @@ _decode_session4(struct sk_buff *skb, struct flowi *fl) if (pskb_may_pull(skb, xprth + 4 - skb->data)) { u16 *ipcomp_hdr = (u16 *)xprth; - fl->fl_ipsec_spi = ntohl(ntohs(ipcomp_hdr[1])); + fl->fl_ipsec_spi = htonl(ntohs(ipcomp_hdr[1])); } break; default: |