X-Git-Url: https://err.no/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=net%2Fdccp%2Fipv4.c;h=3fc75dbee4b8e4d068a0b4598fc96900c5a90842;hb=c07e02db76940c75fc92f2f2c9adcdbb09ed70d0;hp=d3770aed3b153a3f5b2a1dc21738cc18a76750a1;hpb=540722ffc3a0d7e11d97a13e1ce6f3bc23b061c1;p=linux-2.6 diff --git a/net/dccp/ipv4.c b/net/dccp/ipv4.c index d3770aed3b..3fc75dbee4 100644 --- a/net/dccp/ipv4.c +++ b/net/dccp/ipv4.c @@ -29,7 +29,7 @@ struct inet_hashinfo __cacheline_aligned dccp_hashinfo = { .lhash_lock = RW_LOCK_UNLOCKED, .lhash_users = ATOMIC_INIT(0), - .lhash_wait = __WAIT_QUEUE_HEAD_INITIALIZER(dccp_hashinfo.lhash_wait), + .lhash_wait = __WAIT_QUEUE_HEAD_INITIALIZER(dccp_hashinfo.lhash_wait), .portalloc_lock = SPIN_LOCK_UNLOCKED, .port_rover = 1024 - 1, }; @@ -61,7 +61,8 @@ static int __dccp_v4_check_established(struct sock *sk, const __u16 lport, const int dif = sk->sk_bound_dev_if; INET_ADDR_COOKIE(acookie, saddr, daddr) const __u32 ports = INET_COMBINED_PORTS(inet->dport, lport); - const int hash = inet_ehashfn(daddr, lport, saddr, inet->dport, dccp_hashinfo.ehash_size); + const int hash = inet_ehashfn(daddr, lport, saddr, inet->dport, + dccp_hashinfo.ehash_size); struct inet_ehash_bucket *head = &dccp_hashinfo.ehash[hash]; const struct sock *sk2; const struct hlist_node *node; @@ -133,11 +134,12 @@ static int dccp_v4_hash_connect(struct sock *sk) local_bh_disable(); /* TODO. Actually it is not so bad idea to remove - * dccp_hashinfo.portalloc_lock before next submission to Linus. + * dccp_hashinfo.portalloc_lock before next submission to + * Linus. * As soon as we touch this place at all it is time to think. * - * Now it protects single _advisory_ variable dccp_hashinfo.port_rover, - * hence it is mostly useless. + * Now it protects single _advisory_ variable + * dccp_hashinfo.port_rover, hence it is mostly useless. * Code will work nicely if we just delete it, but * I am afraid in contented case it will work not better or * even worse: another cpu just will hit the same bucket @@ -152,7 +154,8 @@ static int dccp_v4_hash_connect(struct sock *sk) rover++; if ((rover < low) || (rover > high)) rover = low; - head = &dccp_hashinfo.bhash[inet_bhashfn(rover, dccp_hashinfo.bhash_size)]; + head = &dccp_hashinfo.bhash[inet_bhashfn(rover, + dccp_hashinfo.bhash_size)]; spin_lock(&head->lock); /* Does not bother with rcv_saddr checks, @@ -172,7 +175,8 @@ static int dccp_v4_hash_connect(struct sock *sk) } } - tb = inet_bind_bucket_create(dccp_hashinfo.bind_bucket_cachep, head, rover); + tb = inet_bind_bucket_create(dccp_hashinfo.bind_bucket_cachep, + head, rover); if (tb == NULL) { spin_unlock(&head->lock); break; @@ -211,7 +215,8 @@ ok: goto out; } - head = &dccp_hashinfo.bhash[inet_bhashfn(snum, dccp_hashinfo.bhash_size)]; + head = &dccp_hashinfo.bhash[inet_bhashfn(snum, + dccp_hashinfo.bhash_size)]; tb = inet_csk(sk)->icsk_bind_hash; spin_lock_bh(&head->lock); if (sk_head(&tb->owners) == sk && sk->sk_bind_node.next == NULL) { @@ -304,6 +309,16 @@ static int dccp_v4_connect(struct sock *sk, struct sockaddr *uaddr, usin->sin_port); dccp_update_gss(sk, dp->dccps_iss); + /* + * SWL and AWL are initially adjusted so that they are not less than + * the initial Sequence Numbers received and sent, respectively: + * SWL := max(GSR + 1 - floor(W/4), ISR), + * AWL := max(GSS - W' + 1, ISS). + * These adjustments MUST be applied only at the beginning of the + * connection. + */ + dccp_set_seqno(&dp->dccps_awl, max48(dp->dccps_awl, dp->dccps_iss)); + inet->id = dp->dccps_iss ^ jiffies; err = dccp_connect(sk); @@ -313,7 +328,9 @@ static int dccp_v4_connect(struct sock *sk, struct sockaddr *uaddr, out: return err; failure: - /* This unhashes the socket and releases the local port, if necessary. */ + /* + * This unhashes the socket and releases the local port, if necessary. + */ dccp_set_state(sk, DCCP_CLOSED); ip_rt_put(rt); sk->sk_route_caps = 0; @@ -365,10 +382,11 @@ static inline void dccp_do_pmtu_discovery(struct sock *sk, /* * From: draft-ietf-dccp-spec-11.txt * - * DCCP-Sync packets are the best choice for upward probing, - * since DCCP-Sync probes do not risk application data loss. + * DCCP-Sync packets are the best choice for upward + * probing, since DCCP-Sync probes do not risk application + * data loss. */ - dccp_send_sync(sk, dp->dccps_gsr); + dccp_send_sync(sk, dp->dccps_gsr, DCCP_PKT_SYNC); } /* else let the usual retransmit timer handle it */ } @@ -405,11 +423,13 @@ static void dccp_v4_ctl_send_ack(struct sk_buff *rxskb) dh->dccph_x = 1; dccp_hdr_set_seq(dh, DCCP_SKB_CB(rxskb)->dccpd_ack_seq); - dccp_hdr_set_ack(dccp_hdr_ack_bits(skb), DCCP_SKB_CB(rxskb)->dccpd_seq); + dccp_hdr_set_ack(dccp_hdr_ack_bits(skb), + DCCP_SKB_CB(rxskb)->dccpd_seq); bh_lock_sock(dccp_ctl_socket->sk); err = ip_build_and_send_pkt(skb, dccp_ctl_socket->sk, - rxskb->nh.iph->daddr, rxskb->nh.iph->saddr, NULL); + rxskb->nh.iph->daddr, + rxskb->nh.iph->saddr, NULL); bh_unlock_sock(dccp_ctl_socket->sk); if (err == NET_XMIT_CN || err == 0) { @@ -418,7 +438,8 @@ static void dccp_v4_ctl_send_ack(struct sk_buff *rxskb) } } -static void dccp_v4_reqsk_send_ack(struct sk_buff *skb, struct request_sock *req) +static void dccp_v4_reqsk_send_ack(struct sk_buff *skb, + struct request_sock *req) { dccp_v4_ctl_send_ack(skb); } @@ -465,7 +486,8 @@ out: void dccp_v4_err(struct sk_buff *skb, u32 info) { const struct iphdr *iph = (struct iphdr *)skb->data; - const struct dccp_hdr *dh = (struct dccp_hdr *)(skb->data + (iph->ihl << 2)); + const struct dccp_hdr *dh = (struct dccp_hdr *)(skb->data + + (iph->ihl << 2)); struct dccp_sock *dp; struct inet_sock *inet; const int type = skb->h.icmph->type; @@ -605,8 +627,6 @@ out: sock_put(sk); } -extern struct sk_buff *dccp_make_reset(struct sock *sk, struct dst_entry *dst, enum dccp_reset_codes code); - int dccp_v4_send_reset(struct sock *sk, enum dccp_reset_codes code) { struct sk_buff *skb; @@ -689,7 +709,8 @@ int dccp_v4_conn_request(struct sock *sk, struct sk_buff *skb) ireq->loc_addr = daddr; ireq->rmt_addr = saddr; /* FIXME: Merge Aristeu's option parsing code when ready */ - req->rcv_wnd = 100; /* Fake, option parsing will get the right value */ + req->rcv_wnd = 100; /* Fake, option parsing will get the + right value */ ireq->opt = NULL; /* @@ -804,7 +825,8 @@ static struct sock *dccp_v4_hnd_req(struct sock *sk, struct sk_buff *skb) return sk; } -int dccp_v4_checksum(const struct sk_buff *skb, const u32 saddr, const u32 daddr) +int dccp_v4_checksum(const struct sk_buff *skb, const u32 saddr, + const u32 daddr) { const struct dccp_hdr* dh = dccp_hdr(skb); int checksum_len; @@ -814,11 +836,13 @@ int dccp_v4_checksum(const struct sk_buff *skb, const u32 saddr, const u32 daddr checksum_len = skb->len; else { checksum_len = (dh->dccph_cscov + dh->dccph_x) * sizeof(u32); - checksum_len = checksum_len < skb->len ? checksum_len : skb->len; + checksum_len = checksum_len < skb->len ? checksum_len : + skb->len; } tmp = csum_partial((unsigned char *)dh, checksum_len, 0); - return csum_tcpudp_magic(saddr, daddr, checksum_len, IPPROTO_DCCP, tmp); + return csum_tcpudp_magic(saddr, daddr, checksum_len, + IPPROTO_DCCP, tmp); } static int dccp_v4_verify_checksum(struct sk_buff *skb, @@ -832,10 +856,12 @@ static int dccp_v4_verify_checksum(struct sk_buff *skb, checksum_len = skb->len; else { checksum_len = (dh->dccph_cscov + dh->dccph_x) * sizeof(u32); - checksum_len = checksum_len < skb->len ? checksum_len : skb->len; + checksum_len = checksum_len < skb->len ? checksum_len : + skb->len; } tmp = csum_partial((unsigned char *)dh, checksum_len, 0); - return csum_tcpudp_magic(saddr, daddr, checksum_len, IPPROTO_DCCP, tmp) == 0 ? 0 : -1; + return csum_tcpudp_magic(saddr, daddr, checksum_len, + IPPROTO_DCCP, tmp) == 0 ? 0 : -1; } static struct dst_entry* dccp_v4_route_skb(struct sock *sk, @@ -850,7 +876,9 @@ static struct dst_entry* dccp_v4_route_skb(struct sock *sk, .proto = sk->sk_protocol, .uli_u = { .ports = { .sport = dccp_hdr(skb)->dccph_dport, - .dport = dccp_hdr(skb)->dccph_sport } } }; + .dport = dccp_hdr(skb)->dccph_sport } + } + }; if (ip_route_output_flow(&rt, &fl, sk, 0)) { IP_INC_STATS_BH(IPSTATS_MIB_OUTNOROUTES); @@ -860,7 +888,7 @@ static struct dst_entry* dccp_v4_route_skb(struct sock *sk, return &rt->u.dst; } -void dccp_v4_ctl_send_reset(struct sk_buff *rxskb) +static void dccp_v4_ctl_send_reset(struct sk_buff *rxskb) { int err; struct dccp_hdr *rxdh = dccp_hdr(rxskb), *dh; @@ -869,6 +897,7 @@ void dccp_v4_ctl_send_reset(struct sk_buff *rxskb) sizeof(struct dccp_hdr_reset); struct sk_buff *skb; struct dst_entry *dst; + u64 seqno; /* Never send a reset in response to a reset. */ if (rxdh->dccph_type == DCCP_PKT_RESET) @@ -899,17 +928,25 @@ void dccp_v4_ctl_send_reset(struct sk_buff *rxskb) dh->dccph_dport = rxdh->dccph_sport; dh->dccph_doff = dccp_hdr_reset_len / 4; dh->dccph_x = 1; - dccp_hdr_reset(skb)->dccph_reset_code = DCCP_SKB_CB(rxskb)->dccpd_reset_code; + dccp_hdr_reset(skb)->dccph_reset_code = + DCCP_SKB_CB(rxskb)->dccpd_reset_code; - dccp_hdr_set_seq(dh, DCCP_SKB_CB(rxskb)->dccpd_ack_seq); - dccp_hdr_set_ack(dccp_hdr_ack_bits(skb), DCCP_SKB_CB(rxskb)->dccpd_seq); + /* See "8.3.1. Abnormal Termination" in draft-ietf-dccp-spec-11 */ + seqno = 0; + if (DCCP_SKB_CB(rxskb)->dccpd_ack_seq != DCCP_PKT_WITHOUT_ACK_SEQ) + dccp_set_seqno(&seqno, DCCP_SKB_CB(rxskb)->dccpd_ack_seq + 1); + + dccp_hdr_set_seq(dh, seqno); + dccp_hdr_set_ack(dccp_hdr_ack_bits(skb), + DCCP_SKB_CB(rxskb)->dccpd_seq); dh->dccph_checksum = dccp_v4_checksum(skb, rxskb->nh.iph->saddr, rxskb->nh.iph->daddr); bh_lock_sock(dccp_ctl_socket->sk); err = ip_build_and_send_pkt(skb, dccp_ctl_socket->sk, - rxskb->nh.iph->daddr, rxskb->nh.iph->saddr, NULL); + rxskb->nh.iph->daddr, + rxskb->nh.iph->saddr, NULL); bh_unlock_sock(dccp_ctl_socket->sk); if (err == NET_XMIT_CN || err == 0) { @@ -933,7 +970,8 @@ int dccp_v4_do_rcv(struct sock *sk, struct sk_buff *skb) /* * Step 3: Process LISTEN state * If S.state == LISTEN, - * If P.type == Request or P contains a valid Init Cookie option, + * If P.type == Request or P contains a valid Init Cookie + * option, * * Must scan the packet's options to check for an Init * Cookie. Only the Init Cookie is processed here, * however; other options are processed in Step 8. This @@ -950,7 +988,8 @@ int dccp_v4_do_rcv(struct sock *sk, struct sk_buff *skb) * Generate Reset(No Connection) unless P.type == Reset * Drop packet and return * - * NOTE: the check for the packet types is done in dccp_rcv_state_process + * NOTE: the check for the packet types is done in + * dccp_rcv_state_process */ if (sk->sk_state == DCCP_LISTEN) { struct sock *nsk = dccp_v4_hnd_req(sk, skb); @@ -985,7 +1024,7 @@ static inline int dccp_invalid_packet(struct sk_buff *skb) return 1; if (!pskb_may_pull(skb, sizeof(struct dccp_hdr))) { - dccp_pr_debug("pskb_may_pull failed\n"); + LIMIT_NETDEBUG(KERN_WARNING "DCCP: pskb_may_pull failed\n"); return 1; } @@ -993,7 +1032,7 @@ static inline int dccp_invalid_packet(struct sk_buff *skb) /* If the packet type is not understood, drop packet and return */ if (dh->dccph_type >= DCCP_PKT_INVALID) { - dccp_pr_debug("invalid packet type\n"); + LIMIT_NETDEBUG(KERN_WARNING "DCCP: invalid packet type\n"); return 1; } @@ -1002,12 +1041,16 @@ static inline int dccp_invalid_packet(struct sk_buff *skb) * packet, drop packet and return */ if (dh->dccph_doff < dccp_hdr_len(skb) / sizeof(u32)) { - dccp_pr_debug("Offset(%u) too small 1\n", dh->dccph_doff); + LIMIT_NETDEBUG(KERN_WARNING "DCCP: P.Data Offset(%u) " + "too small 1\n", + dh->dccph_doff); return 1; } if (!pskb_may_pull(skb, dh->dccph_doff * sizeof(u32))) { - dccp_pr_debug("P.Data Offset(%u) too small 2\n", dh->dccph_doff); + LIMIT_NETDEBUG(KERN_WARNING "DCCP: P.Data Offset(%u) " + "too small 2\n", + dh->dccph_doff); return 1; } @@ -1021,15 +1064,17 @@ static inline int dccp_invalid_packet(struct sk_buff *skb) dh->dccph_type != DCCP_PKT_DATA && dh->dccph_type != DCCP_PKT_ACK && dh->dccph_type != DCCP_PKT_DATAACK) { - dccp_pr_debug("P.type (%s) not Data, Ack nor DataAck and P.X == 0\n", - dccp_packet_name(dh->dccph_type)); + LIMIT_NETDEBUG(KERN_WARNING "DCCP: P.type (%s) not Data, Ack " + "nor DataAck and P.X == 0\n", + dccp_packet_name(dh->dccph_type)); return 1; } /* If the header checksum is incorrect, drop packet and return */ if (dccp_v4_verify_checksum(skb, skb->nh.iph->saddr, skb->nh.iph->daddr) < 0) { - dccp_pr_debug("header checksum is incorrect\n"); + LIMIT_NETDEBUG(KERN_WARNING "DCCP: header checksum is " + "incorrect\n"); return 1; } @@ -1055,10 +1100,11 @@ int dccp_v4_rcv(struct sk_buff *skb) * dccp_ackpkts_add, you'll get something like this on a session that * sends 10 DATA/DATAACK packets: * - * dccp_ackpkts_print: 281473596467422 |0,0|3,0|0,0|3,0|0,0|3,0|0,0|3,0|0,1| + * ackpkts_print: 281473596467422 |0,0|3,0|0,0|3,0|0,0|3,0|0,0|3,0|0,1| * * 0, 0 means: DCCP_ACKPKTS_STATE_RECEIVED, RLE == just this packet - * 0, 1 means: DCCP_ACKPKTS_STATE_RECEIVED, RLE == two adjacent packets with the same state + * 0, 1 means: DCCP_ACKPKTS_STATE_RECEIVED, RLE == two adjacent packets + * with the same state * 3, 0 means: DCCP_ACKPKTS_STATE_NOT_RECEIVED, RLE == just this packet * * So... @@ -1072,10 +1118,12 @@ int dccp_v4_rcv(struct sk_buff *skb) * 281473596467416 was received * 281473596467415 was not received * 281473596467414 was received - * 281473596467413 was received (this one was the 3way handshake RESPONSE) + * 281473596467413 was received (this one was the 3way handshake + * RESPONSE) * */ - if (dh->dccph_type == DCCP_PKT_DATA || dh->dccph_type == DCCP_PKT_DATAACK) { + if (dh->dccph_type == DCCP_PKT_DATA || + dh->dccph_type == DCCP_PKT_DATAACK) { static int discard = 0; if (discard) { @@ -1170,7 +1218,8 @@ no_dccp_socket: * Drop packet and return */ if (dh->dccph_type != DCCP_PKT_RESET) { - DCCP_SKB_CB(skb)->dccpd_reset_code = DCCP_RESET_CODE_NO_CONNECTION; + DCCP_SKB_CB(skb)->dccpd_reset_code = + DCCP_RESET_CODE_NO_CONNECTION; dccp_v4_ctl_send_reset(skb); } @@ -1196,8 +1245,9 @@ static int dccp_v4_init_sock(struct sock *sk) dccp_options_init(&dp->dccps_options); if (dp->dccps_options.dccpo_send_ack_vector) { - dp->dccps_hc_rx_ackpkts = dccp_ackpkts_alloc(DCCP_MAX_ACK_VECTOR_LEN, - GFP_KERNEL); + dp->dccps_hc_rx_ackpkts = + dccp_ackpkts_alloc(DCCP_MAX_ACK_VECTOR_LEN, + GFP_KERNEL); if (dp->dccps_hc_rx_ackpkts == NULL) return -ENOMEM; @@ -1211,8 +1261,10 @@ static int dccp_v4_init_sock(struct sock *sk) * setsockopt(CCIDs-I-want/accept). -acme */ if (likely(!dccp_ctl_socket_init)) { - dp->dccps_hc_rx_ccid = ccid_init(dp->dccps_options.dccpo_ccid, sk); - dp->dccps_hc_tx_ccid = ccid_init(dp->dccps_options.dccpo_ccid, sk); + dp->dccps_hc_rx_ccid = ccid_init(dp->dccps_options.dccpo_ccid, + sk); + dp->dccps_hc_tx_ccid = ccid_init(dp->dccps_options.dccpo_ccid, + sk); if (dp->dccps_hc_rx_ccid == NULL || dp->dccps_hc_tx_ccid == NULL) { ccid_exit(dp->dccps_hc_rx_ccid, sk); @@ -1228,13 +1280,14 @@ static int dccp_v4_init_sock(struct sock *sk) dccp_init_xmit_timers(sk); inet_csk(sk)->icsk_rto = DCCP_TIMEOUT_INIT; sk->sk_state = DCCP_CLOSED; + sk->sk_write_space = dccp_write_space; dp->dccps_mss_cache = 536; dp->dccps_role = DCCP_ROLE_UNDEFINED; return 0; } -int dccp_v4_destroy_sock(struct sock *sk) +static int dccp_v4_destroy_sock(struct sock *sk) { struct dccp_sock *dp = dccp_sk(sk); @@ -1251,6 +1304,8 @@ int dccp_v4_destroy_sock(struct sock *sk) if (inet_csk(sk)->icsk_bind_hash != NULL) inet_put_port(&dccp_hashinfo, sk); + ccid_hc_rx_exit(dp->dccps_hc_rx_ccid, sk); + ccid_hc_tx_exit(dp->dccps_hc_tx_ccid, sk); dccp_ackpkts_free(dp->dccps_hc_rx_ackpkts); dp->dccps_hc_rx_ackpkts = NULL; ccid_exit(dp->dccps_hc_rx_ccid, sk);