diff options
Diffstat (limited to 'net/dccp')
-rw-r--r-- | net/dccp/ackvec.c | 29 | ||||
-rw-r--r-- | net/dccp/ccids/ccid2.c | 2 | ||||
-rw-r--r-- | net/dccp/ccids/ccid3.c | 31 | ||||
-rw-r--r-- | net/dccp/ccids/lib/tfrc.c | 8 | ||||
-rw-r--r-- | net/dccp/ccids/lib/tfrc.h | 25 | ||||
-rw-r--r-- | net/dccp/ccids/lib/tfrc_equation.c | 8 | ||||
-rw-r--r-- | net/dccp/dccp.h | 14 | ||||
-rw-r--r-- | net/dccp/feat.c | 2 | ||||
-rw-r--r-- | net/dccp/ipv4.c | 87 | ||||
-rw-r--r-- | net/dccp/ipv6.c | 94 | ||||
-rw-r--r-- | net/dccp/minisocks.c | 10 | ||||
-rw-r--r-- | net/dccp/options.c | 4 | ||||
-rw-r--r-- | net/dccp/output.c | 9 | ||||
-rw-r--r-- | net/dccp/probe.c | 21 | ||||
-rw-r--r-- | net/dccp/proto.c | 31 |
15 files changed, 183 insertions, 192 deletions
diff --git a/net/dccp/ackvec.c b/net/dccp/ackvec.c index 6de4bd195d2..1e8be246ad1 100644 --- a/net/dccp/ackvec.c +++ b/net/dccp/ackvec.c @@ -290,12 +290,12 @@ int dccp_ackvec_add(struct dccp_ackvec *av, const struct sock *sk, while (1) { const u8 len = dccp_ackvec_len(av, index); - const u8 state = dccp_ackvec_state(av, index); + const u8 av_state = dccp_ackvec_state(av, index); /* * valid packets not yet in av_buf have a reserved * entry, with a len equal to 0. */ - if (state == DCCP_ACKVEC_STATE_NOT_RECEIVED && + if (av_state == DCCP_ACKVEC_STATE_NOT_RECEIVED && len == 0 && delta == 0) { /* Found our reserved seat! */ dccp_pr_debug("Found %llu reserved seat!\n", @@ -325,31 +325,6 @@ out_duplicate: return -EILSEQ; } -#ifdef CONFIG_IP_DCCP_DEBUG -void dccp_ackvector_print(const u64 ackno, const unsigned char *vector, int len) -{ - dccp_pr_debug_cat("ACK vector len=%d, ackno=%llu |", len, - (unsigned long long)ackno); - - while (len--) { - const u8 state = (*vector & DCCP_ACKVEC_STATE_MASK) >> 6; - const u8 rl = *vector & DCCP_ACKVEC_LEN_MASK; - - dccp_pr_debug_cat("%d,%d|", state, rl); - ++vector; - } - - dccp_pr_debug_cat("\n"); -} - -void dccp_ackvec_print(const struct dccp_ackvec *av) -{ - dccp_ackvector_print(av->av_buf_ackno, - av->av_buf + av->av_buf_head, - av->av_vec_len); -} -#endif - static void dccp_ackvec_throw_record(struct dccp_ackvec *av, struct dccp_ackvec_record *avr) { diff --git a/net/dccp/ccids/ccid2.c b/net/dccp/ccids/ccid2.c index b5b52ebb269..8e958087421 100644 --- a/net/dccp/ccids/ccid2.c +++ b/net/dccp/ccids/ccid2.c @@ -716,7 +716,7 @@ static int ccid2_hc_tx_init(struct ccid *ccid, struct sock *sk) * packets for new connections, following the rules from [RFC3390]". * We need to convert the bytes of RFC3390 into the packets of RFC 4341. */ - hctx->ccid2hctx_cwnd = min(4U, max(2U, 4380U / dp->dccps_mss_cache)); + hctx->ccid2hctx_cwnd = clamp(4380U / dp->dccps_mss_cache, 2U, 4U); /* Make sure that Ack Ratio is enabled and within bounds. */ max_ratio = DIV_ROUND_UP(hctx->ccid2hctx_cwnd, 2); diff --git a/net/dccp/ccids/ccid3.c b/net/dccp/ccids/ccid3.c index e76f460af0e..a1929f33d70 100644 --- a/net/dccp/ccids/ccid3.c +++ b/net/dccp/ccids/ccid3.c @@ -88,8 +88,8 @@ static void ccid3_hc_tx_set_state(struct sock *sk, static inline u64 rfc3390_initial_rate(struct sock *sk) { const struct ccid3_hc_tx_sock *hctx = ccid3_hc_tx_sk(sk); - const __u32 w_init = min_t(__u32, 4 * hctx->ccid3hctx_s, - max_t(__u32, 2 * hctx->ccid3hctx_s, 4380)); + const __u32 w_init = clamp_t(__u32, 4380U, + 2 * hctx->ccid3hctx_s, 4 * hctx->ccid3hctx_s); return scaled_div(w_init << 6, hctx->ccid3hctx_rtt); } @@ -159,8 +159,8 @@ static void ccid3_hc_tx_update_x(struct sock *sk, ktime_t *stamp) } else if (ktime_us_delta(now, hctx->ccid3hctx_t_ld) - (s64)hctx->ccid3hctx_rtt >= 0) { - hctx->ccid3hctx_x = - max(min(2 * hctx->ccid3hctx_x, min_rate), + hctx->ccid3hctx_x = min(2 * hctx->ccid3hctx_x, min_rate); + hctx->ccid3hctx_x = max(hctx->ccid3hctx_x, scaled_div(((__u64)hctx->ccid3hctx_s) << 6, hctx->ccid3hctx_rtt)); hctx->ccid3hctx_t_ld = now; @@ -193,22 +193,17 @@ static inline void ccid3_hc_tx_update_s(struct ccid3_hc_tx_sock *hctx, int len) /* * Update Window Counter using the algorithm from [RFC 4342, 8.1]. - * The algorithm is not applicable if RTT < 4 microseconds. + * As elsewhere, RTT > 0 is assumed by using dccp_sample_rtt(). */ static inline void ccid3_hc_tx_update_win_count(struct ccid3_hc_tx_sock *hctx, ktime_t now) { - u32 quarter_rtts; - - if (unlikely(hctx->ccid3hctx_rtt < 4)) /* avoid divide-by-zero */ - return; - - quarter_rtts = ktime_us_delta(now, hctx->ccid3hctx_t_last_win_count); - quarter_rtts /= hctx->ccid3hctx_rtt / 4; + u32 delta = ktime_us_delta(now, hctx->ccid3hctx_t_last_win_count), + quarter_rtts = (4 * delta) / hctx->ccid3hctx_rtt; if (quarter_rtts > 0) { hctx->ccid3hctx_t_last_win_count = now; - hctx->ccid3hctx_last_win_count += min_t(u32, quarter_rtts, 5); + hctx->ccid3hctx_last_win_count += min(quarter_rtts, 5U); hctx->ccid3hctx_last_win_count &= 0xF; /* mod 16 */ } } @@ -334,8 +329,14 @@ static int ccid3_hc_tx_send_packet(struct sock *sk, struct sk_buff *skb) hctx->ccid3hctx_x = rfc3390_initial_rate(sk); hctx->ccid3hctx_t_ld = now; } else { - /* Sender does not have RTT sample: X_pps = 1 pkt/sec */ - hctx->ccid3hctx_x = hctx->ccid3hctx_s; + /* + * Sender does not have RTT sample: + * - set fallback RTT (RFC 4340, 3.4) since a RTT value + * is needed in several parts (e.g. window counter); + * - set sending rate X_pps = 1pps as per RFC 3448, 4.2. + */ + hctx->ccid3hctx_rtt = DCCP_FALLBACK_RTT; + hctx->ccid3hctx_x = hctx->ccid3hctx_s; hctx->ccid3hctx_x <<= 6; } ccid3_update_send_interval(hctx); diff --git a/net/dccp/ccids/lib/tfrc.c b/net/dccp/ccids/lib/tfrc.c index d1dfbb8de64..97ecec0a8e7 100644 --- a/net/dccp/ccids/lib/tfrc.c +++ b/net/dccp/ccids/lib/tfrc.c @@ -14,14 +14,6 @@ module_param(tfrc_debug, bool, 0444); MODULE_PARM_DESC(tfrc_debug, "Enable debug messages"); #endif -extern int tfrc_tx_packet_history_init(void); -extern void tfrc_tx_packet_history_exit(void); -extern int tfrc_rx_packet_history_init(void); -extern void tfrc_rx_packet_history_exit(void); - -extern int tfrc_li_init(void); -extern void tfrc_li_exit(void); - static int __init tfrc_module_init(void) { int rc = tfrc_li_init(); diff --git a/net/dccp/ccids/lib/tfrc.h b/net/dccp/ccids/lib/tfrc.h index 1fb1187bbf1..ed9857527ac 100644 --- a/net/dccp/ccids/lib/tfrc.h +++ b/net/dccp/ccids/lib/tfrc.h @@ -15,7 +15,7 @@ * (at your option) any later version. */ #include <linux/types.h> -#include <asm/div64.h> +#include <linux/math64.h> #include "../../dccp.h" /* internal includes that this module exports: */ #include "loss_interval.h" @@ -29,21 +29,19 @@ extern int tfrc_debug; #endif /* integer-arithmetic divisions of type (a * 1000000)/b */ -static inline u64 scaled_div(u64 a, u32 b) +static inline u64 scaled_div(u64 a, u64 b) { BUG_ON(b==0); - a *= 1000000; - do_div(a, b); - return a; + return div64_u64(a * 1000000, b); } -static inline u32 scaled_div32(u64 a, u32 b) +static inline u32 scaled_div32(u64 a, u64 b) { u64 result = scaled_div(a, b); if (result > UINT_MAX) { - DCCP_CRIT("Overflow: a(%llu)/b(%u) > ~0U", - (unsigned long long)a, b); + DCCP_CRIT("Overflow: %llu/%llu > UINT_MAX", + (unsigned long long)a, (unsigned long long)b); return UINT_MAX; } return result; @@ -58,7 +56,14 @@ static inline u32 tfrc_ewma(const u32 avg, const u32 newval, const u8 weight) return avg ? (weight * avg + (10 - weight) * newval) / 10 : newval; } -extern u32 tfrc_calc_x(u16 s, u32 R, u32 p); -extern u32 tfrc_calc_x_reverse_lookup(u32 fvalue); +extern u32 tfrc_calc_x(u16 s, u32 R, u32 p); +extern u32 tfrc_calc_x_reverse_lookup(u32 fvalue); +extern int tfrc_tx_packet_history_init(void); +extern void tfrc_tx_packet_history_exit(void); +extern int tfrc_rx_packet_history_init(void); +extern void tfrc_rx_packet_history_exit(void); + +extern int tfrc_li_init(void); +extern void tfrc_li_exit(void); #endif /* _TFRC_H_ */ diff --git a/net/dccp/ccids/lib/tfrc_equation.c b/net/dccp/ccids/lib/tfrc_equation.c index e4e64b76c10..2f20a29cffe 100644 --- a/net/dccp/ccids/lib/tfrc_equation.c +++ b/net/dccp/ccids/lib/tfrc_equation.c @@ -661,7 +661,7 @@ u32 tfrc_calc_x(u16 s, u32 R, u32 p) EXPORT_SYMBOL_GPL(tfrc_calc_x); -/* +/** * tfrc_calc_x_reverse_lookup - try to find p given f(p) * * @fvalue: function value to match, scaled by 1000000 @@ -676,11 +676,11 @@ u32 tfrc_calc_x_reverse_lookup(u32 fvalue) /* Error cases. */ if (fvalue < tfrc_calc_x_lookup[0][1]) { - DCCP_WARN("fvalue %d smaller than resolution\n", fvalue); - return tfrc_calc_x_lookup[0][1]; + DCCP_WARN("fvalue %u smaller than resolution\n", fvalue); + return TFRC_SMALLEST_P; } if (fvalue > tfrc_calc_x_lookup[TFRC_CALC_X_ARRSIZE - 1][0]) { - DCCP_WARN("fvalue %d exceeds bounds!\n", fvalue); + DCCP_WARN("fvalue %u exceeds bounds!\n", fvalue); return 1000000; } diff --git a/net/dccp/dccp.h b/net/dccp/dccp.h index 287a62bc2e0..f44d492d3b7 100644 --- a/net/dccp/dccp.h +++ b/net/dccp/dccp.h @@ -23,9 +23,9 @@ * DCCP - specific warning and debugging macros. */ #define DCCP_WARN(fmt, a...) LIMIT_NETDEBUG(KERN_WARNING "%s: " fmt, \ - __FUNCTION__, ##a) + __func__, ##a) #define DCCP_CRIT(fmt, a...) printk(KERN_CRIT fmt " at %s:%d/%s()\n", ##a, \ - __FILE__, __LINE__, __FUNCTION__) + __FILE__, __LINE__, __func__) #define DCCP_BUG(a...) do { DCCP_CRIT("BUG: " a); dump_stack(); } while(0) #define DCCP_BUG_ON(cond) do { if (unlikely((cond) != 0)) \ DCCP_BUG("\"%s\" holds (exception!)", \ @@ -36,7 +36,7 @@ printk(fmt, ##args); \ } while(0) #define DCCP_PR_DEBUG(enable, fmt, a...) DCCP_PRINTK(enable, KERN_DEBUG \ - "%s: " fmt, __FUNCTION__, ##a) + "%s: " fmt, __func__, ##a) #ifdef CONFIG_IP_DCCP_DEBUG extern int dccp_debug; @@ -296,7 +296,7 @@ extern unsigned int dccp_poll(struct file *file, struct socket *sock, extern int dccp_v4_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len); -extern struct sk_buff *dccp_ctl_make_reset(struct socket *ctl, +extern struct sk_buff *dccp_ctl_make_reset(struct sock *sk, struct sk_buff *skb); extern int dccp_send_reset(struct sock *sk, enum dccp_reset_codes code); extern void dccp_send_close(struct sock *sk, const int active); @@ -325,6 +325,12 @@ static inline int dccp_bad_service_code(const struct sock *sk, * This is used for transmission as well as for reception. */ struct dccp_skb_cb { + union { + struct inet_skb_parm h4; +#if defined(CONFIG_IPV6) || defined (CONFIG_IPV6_MODULE) + struct inet6_skb_parm h6; +#endif + } header; __u8 dccpd_type:4; __u8 dccpd_ccval:4; __u8 dccpd_reset_code, diff --git a/net/dccp/feat.c b/net/dccp/feat.c index 4a4f6ce4498..933a0ecf8d4 100644 --- a/net/dccp/feat.c +++ b/net/dccp/feat.c @@ -32,7 +32,7 @@ int dccp_feat_change(struct dccp_minisock *dmsk, u8 type, u8 feature, if (len > 3) { DCCP_WARN("invalid length %d\n", len); - return 1; + return -EINVAL; } /* XXX add further sanity checks */ diff --git a/net/dccp/ipv4.c b/net/dccp/ipv4.c index 474075adbde..37d27bcb361 100644 --- a/net/dccp/ipv4.c +++ b/net/dccp/ipv4.c @@ -32,11 +32,10 @@ #include "feat.h" /* - * This is the global socket data structure used for responding to + * The per-net dccp.v4_ctl_sk socket is used for responding to * the Out-of-the-blue (OOTB) packets. A control sock will be created * for this socket at the initialization time. */ -static struct socket *dccp_v4_ctl_socket; int dccp_v4_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len) { @@ -212,8 +211,9 @@ static void dccp_v4_err(struct sk_buff *skb, u32 info) return; } - sk = inet_lookup(&init_net, &dccp_hashinfo, iph->daddr, dh->dccph_dport, - iph->saddr, dh->dccph_sport, inet_iif(skb)); + sk = inet_lookup(dev_net(skb->dev), &dccp_hashinfo, + iph->daddr, dh->dccph_dport, + iph->saddr, dh->dccph_sport, inet_iif(skb)); if (sk == NULL) { ICMP_INC_STATS_BH(ICMP_MIB_INERRORS); return; @@ -430,7 +430,7 @@ static struct sock *dccp_v4_hnd_req(struct sock *sk, struct sk_buff *skb) if (req != NULL) return dccp_check_req(sk, skb, req, prev); - nsk = inet_lookup_established(&init_net, &dccp_hashinfo, + nsk = inet_lookup_established(sock_net(sk), &dccp_hashinfo, iph->saddr, dh->dccph_sport, iph->daddr, dh->dccph_dport, inet_iif(skb)); @@ -446,11 +446,11 @@ static struct sock *dccp_v4_hnd_req(struct sock *sk, struct sk_buff *skb) return sk; } -static struct dst_entry* dccp_v4_route_skb(struct sock *sk, +static struct dst_entry* dccp_v4_route_skb(struct net *net, struct sock *sk, struct sk_buff *skb) { struct rtable *rt; - struct flowi fl = { .oif = ((struct rtable *)skb->dst)->rt_iif, + struct flowi fl = { .oif = skb->rtable->rt_iif, .nl_u = { .ip4_u = { .daddr = ip_hdr(skb)->saddr, .saddr = ip_hdr(skb)->daddr, @@ -463,7 +463,7 @@ static struct dst_entry* dccp_v4_route_skb(struct sock *sk, }; security_skb_classify_flow(skb, &fl); - if (ip_route_output_flow(&init_net, &rt, &fl, sk, 0)) { + if (ip_route_output_flow(net, &rt, &fl, sk, 0)) { IP_INC_STATS_BH(IPSTATS_MIB_OUTNOROUTES); return NULL; } @@ -471,15 +471,14 @@ static struct dst_entry* dccp_v4_route_skb(struct sock *sk, return &rt->u.dst; } -static int dccp_v4_send_response(struct sock *sk, struct request_sock *req, - struct dst_entry *dst) +static int dccp_v4_send_response(struct sock *sk, struct request_sock *req) { int err = -1; struct sk_buff *skb; + struct dst_entry *dst; - /* First, grab a route. */ - - if (dst == NULL && (dst = inet_csk_route_req(sk, req)) == NULL) + dst = inet_csk_route_req(sk, req); + if (dst == NULL) goto out; skb = dccp_make_response(sk, dst, req); @@ -489,7 +488,6 @@ static int dccp_v4_send_response(struct sock *sk, struct request_sock *req, dh->dccph_checksum = dccp_v4_csum_finish(skb, ireq->loc_addr, ireq->rmt_addr); - memset(&(IPCB(skb)->opt), 0, sizeof(IPCB(skb)->opt)); err = ip_build_and_send_pkt(skb, sk, ireq->loc_addr, ireq->rmt_addr, ireq->opt); @@ -507,19 +505,21 @@ static void dccp_v4_ctl_send_reset(struct sock *sk, struct sk_buff *rxskb) const struct iphdr *rxiph; struct sk_buff *skb; struct dst_entry *dst; + struct net *net = dev_net(rxskb->dst->dev); + struct sock *ctl_sk = net->dccp.v4_ctl_sk; /* Never send a reset in response to a reset. */ if (dccp_hdr(rxskb)->dccph_type == DCCP_PKT_RESET) return; - if (((struct rtable *)rxskb->dst)->rt_type != RTN_LOCAL) + if (rxskb->rtable->rt_type != RTN_LOCAL) return; - dst = dccp_v4_route_skb(dccp_v4_ctl_socket->sk, rxskb); + dst = dccp_v4_route_skb(net, ctl_sk, rxskb); if (dst == NULL) return; - skb = dccp_ctl_make_reset(dccp_v4_ctl_socket, rxskb); + skb = dccp_ctl_make_reset(ctl_sk, rxskb); if (skb == NULL) goto out; @@ -528,10 +528,10 @@ static void dccp_v4_ctl_send_reset(struct sock *sk, struct sk_buff *rxskb) rxiph->daddr); skb->dst = dst_clone(dst); - bh_lock_sock(dccp_v4_ctl_socket->sk); - err = ip_build_and_send_pkt(skb, dccp_v4_ctl_socket->sk, + bh_lock_sock(ctl_sk); + err = ip_build_and_send_pkt(skb, ctl_sk, rxiph->daddr, rxiph->saddr, NULL); - bh_unlock_sock(dccp_v4_ctl_socket->sk); + bh_unlock_sock(ctl_sk); if (net_xmit_eval(err) == 0) { DCCP_INC_STATS_BH(DCCP_MIB_OUTSEGS); @@ -564,8 +564,7 @@ int dccp_v4_conn_request(struct sock *sk, struct sk_buff *skb) struct dccp_skb_cb *dcb = DCCP_SKB_CB(skb); /* Never answer to DCCP_PKT_REQUESTs send to broadcast or multicast */ - if (((struct rtable *)skb->dst)->rt_flags & - (RTCF_BROADCAST | RTCF_MULTICAST)) + if (skb->rtable->rt_flags & (RTCF_BROADCAST | RTCF_MULTICAST)) return 0; /* discard, don't send a reset here */ if (dccp_bad_service_code(sk, service)) { @@ -590,7 +589,7 @@ int dccp_v4_conn_request(struct sock *sk, struct sk_buff *skb) if (sk_acceptq_is_full(sk) && inet_csk_reqsk_queue_young(sk) > 1) goto drop; - req = reqsk_alloc(&dccp_request_sock_ops); + req = inet_reqsk_alloc(&dccp_request_sock_ops); if (req == NULL) goto drop; @@ -606,7 +605,6 @@ int dccp_v4_conn_request(struct sock *sk, struct sk_buff *skb) ireq = inet_rsk(req); ireq->loc_addr = ip_hdr(skb)->daddr; ireq->rmt_addr = ip_hdr(skb)->saddr; - ireq->opt = NULL; /* * Step 3: Process LISTEN state @@ -620,7 +618,7 @@ int dccp_v4_conn_request(struct sock *sk, struct sk_buff *skb) dreq->dreq_iss = dccp_v4_init_sequence(skb); dreq->dreq_service = service; - if (dccp_v4_send_response(sk, req, NULL)) + if (dccp_v4_send_response(sk, req)) goto drop_and_free; inet_csk_reqsk_queue_hash_add(sk, req, DCCP_TIMEOUT_INIT); @@ -740,8 +738,8 @@ int dccp_invalid_packet(struct sk_buff *skb) * If P.type is not Data, Ack, or DataAck and P.X == 0 (the packet * has short sequence numbers), drop packet and return */ - if (dh->dccph_type >= DCCP_PKT_DATA && - dh->dccph_type <= DCCP_PKT_DATAACK && dh->dccph_x == 0) { + if ((dh->dccph_type < DCCP_PKT_DATA || + dh->dccph_type > DCCP_PKT_DATAACK) && dh->dccph_x == 0) { DCCP_WARN("P.type (%s) not Data || [Data]Ack, while P.X == 0\n", dccp_packet_name(dh->dccph_type)); return 1; @@ -811,7 +809,7 @@ static int dccp_v4_rcv(struct sk_buff *skb) /* Step 2: * Look up flow ID in table and get corresponding socket */ - sk = __inet_lookup(&init_net, &dccp_hashinfo, + sk = __inet_lookup(dev_net(skb->dst->dev), &dccp_hashinfo, iph->saddr, dh->dccph_sport, iph->daddr, dh->dccph_dport, inet_iif(skb)); /* @@ -917,8 +915,6 @@ static struct timewait_sock_ops dccp_timewait_sock_ops = { .twsk_obj_size = sizeof(struct inet_timewait_sock), }; -DEFINE_PROTO_INUSE(dccp_v4) - static struct proto dccp_v4_prot = { .name = "DCCP", .owner = THIS_MODULE, @@ -943,18 +939,18 @@ static struct proto dccp_v4_prot = { .obj_size = sizeof(struct dccp_sock), .rsk_prot = &dccp_request_sock_ops, .twsk_prot = &dccp_timewait_sock_ops, - .hashinfo = &dccp_hashinfo, + .h.hashinfo = &dccp_hashinfo, #ifdef CONFIG_COMPAT .compat_setsockopt = compat_dccp_setsockopt, .compat_getsockopt = compat_dccp_getsockopt, #endif - REF_PROTO_INUSE(dccp_v4) }; static struct net_protocol dccp_v4_protocol = { .handler = dccp_v4_rcv, .err_handler = dccp_v4_err, .no_policy = 1, + .netns_ok = 1, }; static const struct proto_ops inet_dccp_ops = { @@ -994,6 +990,25 @@ static struct inet_protosw dccp_v4_protosw = { .flags = INET_PROTOSW_ICSK, }; +static int dccp_v4_init_net(struct net *net) +{ + int err; + + err = inet_ctl_sock_create(&net->dccp.v4_ctl_sk, PF_INET, + SOCK_DCCP, IPPROTO_DCCP, net); + return err; +} + +static void dccp_v4_exit_net(struct net *net) +{ + inet_ctl_sock_destroy(net->dccp.v4_ctl_sk); +} + +static struct pernet_operations dccp_v4_ops = { + .init = dccp_v4_init_net, + .exit = dccp_v4_exit_net, +}; + static int __init dccp_v4_init(void) { int err = proto_register(&dccp_v4_prot, 1); @@ -1007,13 +1022,12 @@ static int __init dccp_v4_init(void) inet_register_protosw(&dccp_v4_protosw); - err = inet_csk_ctl_sock_create(&dccp_v4_ctl_socket, PF_INET, - SOCK_DCCP, IPPROTO_DCCP); + err = register_pernet_subsys(&dccp_v4_ops); if (err) - goto out_unregister_protosw; + goto out_destroy_ctl_sock; out: return err; -out_unregister_protosw: +out_destroy_ctl_sock: inet_unregister_protosw(&dccp_v4_protosw); inet_del_protocol(&dccp_v4_protocol, IPPROTO_DCCP); out_proto_unregister: @@ -1023,6 +1037,7 @@ out_proto_unregister: static void __exit dccp_v4_exit(void) { + unregister_pernet_subsys(&dccp_v4_ops); inet_unregister_protosw(&dccp_v4_protosw); inet_del_protocol(&dccp_v4_protocol, IPPROTO_DCCP); proto_unregister(&dccp_v4_prot); diff --git a/net/dccp/ipv6.c b/net/dccp/ipv6.c index 490333d47c7..f7fe2a572d7 100644 --- a/net/dccp/ipv6.c +++ b/net/dccp/ipv6.c @@ -33,8 +33,7 @@ #include "ipv6.h" #include "feat.h" -/* Socket used for sending RSTs and ACKs */ -static struct socket *dccp_v6_ctl_socket; +/* The per-net dccp.v6_ctl_sk is used for sending RSTs and ACKs */ static struct inet_connection_sock_af_ops dccp_ipv6_mapped; static struct inet_connection_sock_af_ops dccp_ipv6_af_ops; @@ -95,7 +94,8 @@ static void dccp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, int err; __u64 seq; - sk = inet6_lookup(&init_net, &dccp_hashinfo, &hdr->daddr, dh->dccph_dport, + sk = inet6_lookup(dev_net(skb->dev), &dccp_hashinfo, + &hdr->daddr, dh->dccph_dport, &hdr->saddr, dh->dccph_sport, inet6_iif(skb)); if (sk == NULL) { @@ -224,8 +224,7 @@ out: } -static int dccp_v6_send_response(struct sock *sk, struct request_sock *req, - struct dst_entry *dst) +static int dccp_v6_send_response(struct sock *sk, struct request_sock *req) { struct inet6_request_sock *ireq6 = inet6_rsk(req); struct ipv6_pinfo *np = inet6_sk(sk); @@ -234,6 +233,7 @@ static int dccp_v6_send_response(struct sock *sk, struct request_sock *req, struct in6_addr *final_p = NULL, final; struct flowi fl; int err = -1; + struct dst_entry *dst; memset(&fl, 0, sizeof(fl)); fl.proto = IPPROTO_DCCP; @@ -245,28 +245,26 @@ static int dccp_v6_send_response(struct sock *sk, struct request_sock *req, fl.fl_ip_sport = inet_sk(sk)->sport; security_req_classify_flow(req, &fl); - if (dst == NULL) { - opt = np->opt; + opt = np->opt; - if (opt != NULL && opt->srcrt != NULL) { - const struct rt0_hdr *rt0 = (struct rt0_hdr *)opt->srcrt; + if (opt != NULL && opt->srcrt != NULL) { + const struct rt0_hdr *rt0 = (struct rt0_hdr *)opt->srcrt; - ipv6_addr_copy(&final, &fl.fl6_dst); - ipv6_addr_copy(&fl.fl6_dst, rt0->addr); - final_p = &final; - } + ipv6_addr_copy(&final, &fl.fl6_dst); + ipv6_addr_copy(&fl.fl6_dst, rt0->addr); + final_p = &final; + } - err = ip6_dst_lookup(sk, &dst, &fl); - if (err) - goto done; + err = ip6_dst_lookup(sk, &dst, &fl); + if (err) + goto done; - if (final_p) - ipv6_addr_copy(&fl.fl6_dst, final_p); + if (final_p) + ipv6_addr_copy(&fl.fl6_dst, final_p); - err = xfrm_lookup(&dst, &fl, sk, 0); - if (err < 0) - goto done; - } + err = xfrm_lookup(&dst, &fl, sk, 0); + if (err < 0) + goto done; skb = dccp_make_response(sk, dst, req); if (skb != NULL) { @@ -298,6 +296,8 @@ static void dccp_v6_ctl_send_reset(struct sock *sk, struct sk_buff *rxskb) struct ipv6hdr *rxip6h; struct sk_buff *skb; struct flowi fl; + struct net *net = dev_net(rxskb->dst->dev); + struct sock *ctl_sk = net->dccp.v6_ctl_sk; if (dccp_hdr(rxskb)->dccph_type == DCCP_PKT_RESET) return; @@ -305,7 +305,7 @@ static void dccp_v6_ctl_send_reset(struct sock *sk, struct sk_buff *rxskb) if (!ipv6_unicast_destination(rxskb)) return; - skb = dccp_ctl_make_reset(dccp_v6_ctl_socket, rxskb); + skb = dccp_ctl_make_reset(ctl_sk, rxskb); if (skb == NULL) return; @@ -324,9 +324,9 @@ static void dccp_v6_ctl_send_reset(struct sock *sk, struct sk_buff *rxskb) security_skb_classify_flow(rxskb, &fl); /* sk = NULL, but it is safe for now. RST socket required. */ - if (!ip6_dst_lookup(NULL, &skb->dst, &fl)) { + if (!ip6_dst_lookup(ctl_sk, &skb->dst, &fl)) { if (xfrm_lookup(&skb->dst, &fl, NULL, 0) >= 0) { - ip6_xmit(dccp_v6_ctl_socket->sk, skb, &fl, NULL, 0); + ip6_xmit(ctl_sk, skb, &fl, NULL, 0); DCCP_INC_STATS_BH(DCCP_MIB_OUTSEGS); DCCP_INC_STATS_BH(DCCP_MIB_OUTRSTS); return; @@ -360,7 +360,7 @@ static struct sock *dccp_v6_hnd_req(struct sock *sk,struct sk_buff *skb) if (req != NULL) return dccp_check_req(sk, skb, req, prev); - nsk = __inet6_lookup_established(&init_net, &dccp_hashinfo, + nsk = __inet6_lookup_established(sock_net(sk), &dccp_hashinfo, &iph->saddr, dh->dccph_sport, &iph->daddr, ntohs(dh->dccph_dport), inet6_iif(skb)); @@ -421,7 +421,6 @@ static int dccp_v6_conn_request(struct sock *sk, struct sk_buff *skb) ireq6 = inet6_rsk(req); ipv6_addr_copy(&ireq6->rmt_addr, &ipv6_hdr(skb)->saddr); ipv6_addr_copy(&ireq6->loc_addr, &ipv6_hdr(skb)->daddr); - ireq6->pktopts = NULL; if (ipv6_opt_accepted(sk, skb) || np->rxopt.bits.rxinfo || np->rxopt.bits.rxoinfo || @@ -448,7 +447,7 @@ static int dccp_v6_conn_request(struct sock *sk, struct sk_buff *skb) dreq->dreq_iss = dccp_v6_init_sequence(skb); dreq->dreq_service = service; - if (dccp_v6_send_response(sk, req, NULL)) + if (dccp_v6_send_response(sk, req)) goto drop_and_free; inet6_csk_reqsk_queue_hash_add(sk, req, DCCP_TIMEOUT_INIT); @@ -625,7 +624,7 @@ static struct sock *dccp_v6_request_recv_sock(struct sock *sk, newinet->daddr = newinet->saddr = newinet->rcv_saddr = LOOPBACK4_IPV6; __inet6_hash(newsk); - inet_inherit_port(sk, newsk); + __inet_inherit_port(sk, newsk); return newsk; @@ -791,8 +790,8 @@ static int dccp_v6_rcv(struct sk_buff *skb) /* Step 2: * Look up flow ID in table and get corresponding socket */ - sk = __inet6_lookup(&init_net, &dccp_hashinfo, &ipv6_hdr(skb)->saddr, - dh->dccph_sport, + sk = __inet6_lookup(dev_net(skb->dst->dev), &dccp_hashinfo, + &ipv6_hdr(skb)->saddr, dh->dccph_sport, &ipv6_hdr(skb)->daddr, ntohs(dh->dccph_dport), inet6_iif(skb)); /* @@ -1102,8 +1101,6 @@ static struct timewait_sock_ops dccp6_timewait_sock_ops = { .twsk_obj_size = sizeof(struct dccp6_timewait_sock), }; -DEFINE_PROTO_INUSE(dccp_v6) - static struct proto dccp_v6_prot = { .name = "DCCPv6", .owner = THIS_MODULE, @@ -1128,12 +1125,11 @@ static struct proto dccp_v6_prot = { .obj_size = sizeof(struct dccp6_sock), .rsk_prot = &dccp6_request_sock_ops, .twsk_prot = &dccp6_timewait_sock_ops, - .hashinfo = &dccp_hashinfo, + .h.hashinfo = &dccp_hashinfo, #ifdef CONFIG_COMPAT .compat_setsockopt = compat_dccp_setsockopt, .compat_getsockopt = compat_dccp_getsockopt, #endif - REF_PROTO_INUSE(dccp_v6) }; static struct inet6_protocol dccp_v6_protocol = { @@ -1176,6 +1172,25 @@ static struct inet_protosw dccp_v6_protosw = { .flags = INET_PROTOSW_ICSK, }; +static int dccp_v6_init_net(struct net *net) +{ + int err; + + err = inet_ctl_sock_create(&net->dccp.v6_ctl_sk, PF_INET6, + SOCK_DCCP, IPPROTO_DCCP, net); + return err; +} + +static void dccp_v6_exit_net(struct net *net) +{ + inet_ctl_sock_destroy(net->dccp.v6_ctl_sk); +} + +static struct pernet_operations dccp_v6_ops = { + .init = dccp_v6_init_net, + .exit = dccp_v6_exit_net, +}; + static int __init dccp_v6_init(void) { int err = proto_register(&dccp_v6_prot, 1); @@ -1189,13 +1204,13 @@ static int __init dccp_v6_init(void) inet6_register_protosw(&dccp_v6_protosw); - err = inet_csk_ctl_sock_create(&dccp_v6_ctl_socket, PF_INET6, - SOCK_DCCP, IPPROTO_DCCP); + err = register_pernet_subsys(&dccp_v6_ops); if (err != 0) - goto out_unregister_protosw; + goto out_destroy_ctl_sock; out: return err; -out_unregister_protosw: + +out_destroy_ctl_sock: inet6_del_protocol(&dccp_v6_protocol, IPPROTO_DCCP); inet6_unregister_protosw(&dccp_v6_protosw); out_unregister_proto: @@ -1205,6 +1220,7 @@ out_unregister_proto: static void __exit dccp_v6_exit(void) { + unregister_pernet_subsys(&dccp_v6_ops); inet6_del_protocol(&dccp_v6_protocol, IPPROTO_DCCP); inet6_unregister_protosw(&dccp_v6_protosw); proto_unregister(&dccp_v6_prot); diff --git a/net/dccp/minisocks.c b/net/dccp/minisocks.c index 027d1814e1a..66dca5bba85 100644 --- a/net/dccp/minisocks.c +++ b/net/dccp/minisocks.c @@ -165,12 +165,12 @@ out_free: /* See dccp_v4_conn_request */ newdmsk->dccpms_sequence_window = req->rcv_wnd; - newdp->dccps_gar = newdp->dccps_isr = dreq->dreq_isr; - dccp_update_gsr(newsk, dreq->dreq_isr); - - newdp->dccps_iss = dreq->dreq_iss; + newdp->dccps_gar = newdp->dccps_iss = dreq->dreq_iss; dccp_update_gss(newsk, dreq->dreq_iss); + newdp->dccps_isr = dreq->dreq_isr; + dccp_update_gsr(newsk, dreq->dreq_isr); + /* * SWL and AWL are initially adjusted so that they are not less than * the initial Sequence Numbers received and sent, respectively: @@ -216,7 +216,7 @@ struct sock *dccp_check_req(struct sock *sk, struct sk_buff *skb, * counter (backoff, monitored by dccp_response_timer). */ req->retrans++; - req->rsk_ops->rtx_syn_ack(sk, req, NULL); + req->rsk_ops->rtx_syn_ack(sk, req); } /* Network Duplicate, discard packet */ return NULL; diff --git a/net/dccp/options.c b/net/dccp/options.c index d2a84a2fece..43bc24e761d 100644 --- a/net/dccp/options.c +++ b/net/dccp/options.c @@ -107,9 +107,11 @@ int dccp_parse_options(struct sock *sk, struct dccp_request_sock *dreq, * * CCID-specific options are ignored during connection setup, as * negotiation may still be in progress (see RFC 4340, 10.3). + * The same applies to Ack Vectors, as these depend on the CCID. * */ - if (dreq != NULL && opt >= 128) + if (dreq != NULL && (opt >= 128 || + opt == DCCPO_ACK_VECTOR_0 || opt == DCCPO_ACK_VECTOR_1)) goto ignore_option; switch (opt) { diff --git a/net/dccp/output.c b/net/dccp/output.c index 3b763db3d86..fe20068c5d8 100644 --- a/net/dccp/output.c +++ b/net/dccp/output.c @@ -126,7 +126,6 @@ static int dccp_transmit_skb(struct sock *sk, struct sk_buff *skb) DCCP_INC_STATS(DCCP_MIB_OUTSEGS); - memset(&(IPCB(skb)->opt), 0, sizeof(IPCB(skb)->opt)); err = icsk->icsk_af_ops->queue_xmit(skb, 0); return net_xmit_eval(err); } @@ -348,7 +347,7 @@ struct sk_buff *dccp_make_response(struct sock *sk, struct dst_entry *dst, EXPORT_SYMBOL_GPL(dccp_make_response); /* answer offending packet in @rcv_skb with Reset from control socket @ctl */ -struct sk_buff *dccp_ctl_make_reset(struct socket *ctl, struct sk_buff *rcv_skb) +struct sk_buff *dccp_ctl_make_reset(struct sock *sk, struct sk_buff *rcv_skb) { struct dccp_hdr *rxdh = dccp_hdr(rcv_skb), *dh; struct dccp_skb_cb *dcb = DCCP_SKB_CB(rcv_skb); @@ -358,11 +357,11 @@ struct sk_buff *dccp_ctl_make_reset(struct socket *ctl, struct sk_buff *rcv_skb) struct dccp_hdr_reset *dhr; struct sk_buff *skb; - skb = alloc_skb(ctl->sk->sk_prot->max_header, GFP_ATOMIC); + skb = alloc_skb(sk->sk_prot->max_header, GFP_ATOMIC); if (skb == NULL) return NULL; - skb_reserve(skb, ctl->sk->sk_prot->max_header); + skb_reserve(skb, sk->sk_prot->max_header); /* Swap the send and the receive. */ dh = dccp_zeroed_hdr(skb, dccp_hdr_reset_len); @@ -509,6 +508,7 @@ void dccp_send_ack(struct sock *sk) EXPORT_SYMBOL_GPL(dccp_send_ack); +#if 0 /* FIXME: Is this still necessary (11.3) - currently nowhere used by DCCP. */ void dccp_send_delayed_ack(struct sock *sk) { @@ -539,6 +539,7 @@ void dccp_send_delayed_ack(struct sock *sk) icsk->icsk_ack.timeout = timeout; sk_reset_timer(sk, &icsk->icsk_delack_timer, timeout); } +#endif void dccp_send_sync(struct sock *sk, const u64 ackno, const enum dccp_pkt_type pkt_type) diff --git a/net/dccp/probe.c b/net/dccp/probe.c index 7053bb827bc..81368a7f537 100644 --- a/net/dccp/probe.c +++ b/net/dccp/probe.c @@ -42,33 +42,28 @@ static int bufsize = 64 * 1024; static const char procname[] = "dccpprobe"; -struct { +static struct { struct kfifo *fifo; spinlock_t lock; wait_queue_head_t wait; - struct timeval tstart; + struct timespec tstart; } dccpw; static void printl(const char *fmt, ...) { va_list args; int len; - struct timeval now; + struct timespec now; char tbuf[256]; va_start(args, fmt); - do_gettimeofday(&now); + getnstimeofday(&now); - now.tv_sec -= dccpw.tstart.tv_sec; - now.tv_usec -= dccpw.tstart.tv_usec; - if (now.tv_usec < 0) { - --now.tv_sec; - now.tv_usec += 1000000; - } + now = timespec_sub(now, dccpw.tstart); len = sprintf(tbuf, "%lu.%06lu ", (unsigned long) now.tv_sec, - (unsigned long) now.tv_usec); + (unsigned long) now.tv_nsec / NSEC_PER_USEC); len += vscnprintf(tbuf+len, sizeof(tbuf)-len, fmt, args); va_end(args); @@ -119,7 +114,7 @@ static struct jprobe dccp_send_probe = { static int dccpprobe_open(struct inode *inode, struct file *file) { kfifo_reset(dccpw.fifo); - do_gettimeofday(&dccpw.tstart); + getnstimeofday(&dccpw.tstart); return 0; } @@ -145,7 +140,7 @@ static ssize_t dccpprobe_read(struct file *file, char __user *buf, goto out_free; cnt = kfifo_get(dccpw.fifo, tbuf, len); - error = copy_to_user(buf, tbuf, cnt); + error = copy_to_user(buf, tbuf, cnt) ? -EFAULT : 0; out_free: vfree(tbuf); diff --git a/net/dccp/proto.c b/net/dccp/proto.c index e3f5d37b84b..9dfe2470962 100644 --- a/net/dccp/proto.c +++ b/net/dccp/proto.c @@ -27,7 +27,6 @@ #include <net/xfrm.h> #include <asm/ioctls.h> -#include <asm/semaphore.h> #include <linux/spinlock.h> #include <linux/timer.h> #include <linux/delay.h> @@ -1010,33 +1009,14 @@ void dccp_shutdown(struct sock *sk, int how) EXPORT_SYMBOL_GPL(dccp_shutdown); -static int __init dccp_mib_init(void) +static inline int dccp_mib_init(void) { - int rc = -ENOMEM; - - dccp_statistics[0] = alloc_percpu(struct dccp_mib); - if (dccp_statistics[0] == NULL) - goto out; - - dccp_statistics[1] = alloc_percpu(struct dccp_mib); - if (dccp_statistics[1] == NULL) - goto out_free_one; - - rc = 0; -out: - return rc; -out_free_one: - free_percpu(dccp_statistics[0]); - dccp_statistics[0] = NULL; - goto out; - + return snmp_mib_init((void**)dccp_statistics, sizeof(struct dccp_mib)); } -static void dccp_mib_exit(void) +static inline void dccp_mib_exit(void) { - free_percpu(dccp_statistics[0]); - free_percpu(dccp_statistics[1]); - dccp_statistics[0] = dccp_statistics[1] = NULL; + snmp_mib_free((void**)dccp_statistics); } static int thash_entries; @@ -1057,6 +1037,9 @@ static int __init dccp_init(void) int ehash_order, bhash_order, i; int rc = -ENOBUFS; + BUILD_BUG_ON(sizeof(struct dccp_skb_cb) > + FIELD_SIZEOF(struct sk_buff, cb)); + dccp_hashinfo.bind_bucket_cachep = kmem_cache_create("dccp_bind_bucket", sizeof(struct inet_bind_bucket), 0, |