diff options
author | David S. Miller <davem@sunset.davemloft.net> | 2005-09-18 03:17:10 -0400 |
---|---|---|
committer | David S. Miller <davem@sunset.davemloft.net> | 2005-09-18 03:17:10 -0400 |
commit | 21f130a2370ba837cdfc5204ebe52e7c664fec3d (patch) | |
tree | 7f8a30088d8d39eab9350c59b6638661309ffe89 /net | |
parent | bc5e8fdfc622b03acf5ac974a1b8b26da6511c99 (diff) | |
parent | c58ec93245a1fb7354f9e331960380827b9f41db (diff) |
Merge master.kernel.org:/pub/scm/linux/kernel/git/davem/net-2.6
Diffstat (limited to 'net')
-rw-r--r-- | net/Kconfig | 3 | ||||
-rw-r--r-- | net/dccp/dccp.h | 9 | ||||
-rw-r--r-- | net/dccp/input.c | 22 | ||||
-rw-r--r-- | net/dccp/ipv4.c | 38 | ||||
-rw-r--r-- | net/dccp/minisocks.c | 6 | ||||
-rw-r--r-- | net/dccp/output.c | 14 | ||||
-rw-r--r-- | net/dccp/proto.c | 85 | ||||
-rw-r--r-- | net/ipv4/netfilter/Kconfig | 16 | ||||
-rw-r--r-- | net/ipv4/netfilter/ip_conntrack_core.c | 5 | ||||
-rw-r--r-- | net/ipv4/netfilter/ipt_CLUSTERIP.c | 223 | ||||
-rw-r--r-- | net/socket.c | 3 |
11 files changed, 282 insertions, 142 deletions
diff --git a/net/Kconfig b/net/Kconfig index 2bdd5623fdd5..60f6f321bd76 100644 --- a/net/Kconfig +++ b/net/Kconfig | |||
@@ -140,6 +140,7 @@ config BRIDGE_NETFILTER | |||
140 | 140 | ||
141 | If unsure, say N. | 141 | If unsure, say N. |
142 | 142 | ||
143 | source "net/netfilter/Kconfig" | ||
143 | source "net/ipv4/netfilter/Kconfig" | 144 | source "net/ipv4/netfilter/Kconfig" |
144 | source "net/ipv6/netfilter/Kconfig" | 145 | source "net/ipv6/netfilter/Kconfig" |
145 | source "net/decnet/netfilter/Kconfig" | 146 | source "net/decnet/netfilter/Kconfig" |
@@ -206,8 +207,6 @@ config NET_PKTGEN | |||
206 | To compile this code as a module, choose M here: the | 207 | To compile this code as a module, choose M here: the |
207 | module will be called pktgen. | 208 | module will be called pktgen. |
208 | 209 | ||
209 | source "net/netfilter/Kconfig" | ||
210 | |||
211 | endmenu | 210 | endmenu |
212 | 211 | ||
213 | endmenu | 212 | endmenu |
diff --git a/net/dccp/dccp.h b/net/dccp/dccp.h index 95c4630b3b18..be7a660b6b24 100644 --- a/net/dccp/dccp.h +++ b/net/dccp/dccp.h | |||
@@ -258,13 +258,12 @@ extern int dccp_v4_send_reset(struct sock *sk, | |||
258 | extern void dccp_send_close(struct sock *sk, const int active); | 258 | extern void dccp_send_close(struct sock *sk, const int active); |
259 | 259 | ||
260 | struct dccp_skb_cb { | 260 | struct dccp_skb_cb { |
261 | __u8 dccpd_type; | 261 | __u8 dccpd_type:4; |
262 | __u8 dccpd_reset_code; | 262 | __u8 dccpd_ccval:4; |
263 | __u8 dccpd_service; | 263 | __u8 dccpd_reset_code; |
264 | __u8 dccpd_ccval; | 264 | __u16 dccpd_opt_len; |
265 | __u64 dccpd_seq; | 265 | __u64 dccpd_seq; |
266 | __u64 dccpd_ack_seq; | 266 | __u64 dccpd_ack_seq; |
267 | int dccpd_opt_len; | ||
268 | }; | 267 | }; |
269 | 268 | ||
270 | #define DCCP_SKB_CB(__skb) ((struct dccp_skb_cb *)&((__skb)->cb[0])) | 269 | #define DCCP_SKB_CB(__skb) ((struct dccp_skb_cb *)&((__skb)->cb[0])) |
diff --git a/net/dccp/input.c b/net/dccp/input.c index c74034cf7ede..062e9f8359d0 100644 --- a/net/dccp/input.c +++ b/net/dccp/input.c | |||
@@ -384,9 +384,9 @@ static int dccp_rcv_request_sent_state_process(struct sock *sk, | |||
384 | } | 384 | } |
385 | 385 | ||
386 | out_invalid_packet: | 386 | out_invalid_packet: |
387 | return 1; /* dccp_v4_do_rcv will send a reset, but... | 387 | /* dccp_v4_do_rcv will send a reset */ |
388 | FIXME: the reset code should be | 388 | DCCP_SKB_CB(skb)->dccpd_reset_code = DCCP_RESET_CODE_PACKET_ERROR; |
389 | DCCP_RESET_CODE_PACKET_ERROR */ | 389 | return 1; |
390 | } | 390 | } |
391 | 391 | ||
392 | static int dccp_rcv_respond_partopen_state_process(struct sock *sk, | 392 | static int dccp_rcv_respond_partopen_state_process(struct sock *sk, |
@@ -433,6 +433,7 @@ int dccp_rcv_state_process(struct sock *sk, struct sk_buff *skb, | |||
433 | struct dccp_hdr *dh, unsigned len) | 433 | struct dccp_hdr *dh, unsigned len) |
434 | { | 434 | { |
435 | struct dccp_sock *dp = dccp_sk(sk); | 435 | struct dccp_sock *dp = dccp_sk(sk); |
436 | struct dccp_skb_cb *dcb = DCCP_SKB_CB(skb); | ||
436 | const int old_state = sk->sk_state; | 437 | const int old_state = sk->sk_state; |
437 | int queued = 0; | 438 | int queued = 0; |
438 | 439 | ||
@@ -473,7 +474,8 @@ int dccp_rcv_state_process(struct sock *sk, struct sk_buff *skb, | |||
473 | if (dh->dccph_type == DCCP_PKT_RESET) | 474 | if (dh->dccph_type == DCCP_PKT_RESET) |
474 | goto discard; | 475 | goto discard; |
475 | 476 | ||
476 | /* Caller (dccp_v4_do_rcv) will send Reset(No Connection)*/ | 477 | /* Caller (dccp_v4_do_rcv) will send Reset */ |
478 | dcb->dccpd_reset_code = DCCP_RESET_CODE_NO_CONNECTION; | ||
477 | return 1; | 479 | return 1; |
478 | } | 480 | } |
479 | 481 | ||
@@ -487,8 +489,7 @@ int dccp_rcv_state_process(struct sock *sk, struct sk_buff *skb, | |||
487 | if (dccp_parse_options(sk, skb)) | 489 | if (dccp_parse_options(sk, skb)) |
488 | goto discard; | 490 | goto discard; |
489 | 491 | ||
490 | if (DCCP_SKB_CB(skb)->dccpd_ack_seq != | 492 | if (dcb->dccpd_ack_seq != DCCP_PKT_WITHOUT_ACK_SEQ) |
491 | DCCP_PKT_WITHOUT_ACK_SEQ) | ||
492 | dccp_event_ack_recv(sk, skb); | 493 | dccp_event_ack_recv(sk, skb); |
493 | 494 | ||
494 | ccid_hc_rx_packet_recv(dp->dccps_hc_rx_ccid, sk, skb); | 495 | ccid_hc_rx_packet_recv(dp->dccps_hc_rx_ccid, sk, skb); |
@@ -500,7 +501,7 @@ int dccp_rcv_state_process(struct sock *sk, struct sk_buff *skb, | |||
500 | */ | 501 | */ |
501 | if (dp->dccps_options.dccpo_send_ack_vector) { | 502 | if (dp->dccps_options.dccpo_send_ack_vector) { |
502 | if (dccp_ackpkts_add(dp->dccps_hc_rx_ackpkts, sk, | 503 | if (dccp_ackpkts_add(dp->dccps_hc_rx_ackpkts, sk, |
503 | DCCP_SKB_CB(skb)->dccpd_seq, | 504 | dcb->dccpd_seq, |
504 | DCCP_ACKPKTS_STATE_RECEIVED)) | 505 | DCCP_ACKPKTS_STATE_RECEIVED)) |
505 | goto discard; | 506 | goto discard; |
506 | /* | 507 | /* |
@@ -551,8 +552,7 @@ int dccp_rcv_state_process(struct sock *sk, struct sk_buff *skb, | |||
551 | dh->dccph_type == DCCP_PKT_REQUEST) || | 552 | dh->dccph_type == DCCP_PKT_REQUEST) || |
552 | (sk->sk_state == DCCP_RESPOND && | 553 | (sk->sk_state == DCCP_RESPOND && |
553 | dh->dccph_type == DCCP_PKT_DATA)) { | 554 | dh->dccph_type == DCCP_PKT_DATA)) { |
554 | dccp_send_sync(sk, DCCP_SKB_CB(skb)->dccpd_seq, | 555 | dccp_send_sync(sk, dcb->dccpd_seq, DCCP_PKT_SYNC); |
555 | DCCP_PKT_SYNC); | ||
556 | goto discard; | 556 | goto discard; |
557 | } else if (dh->dccph_type == DCCP_PKT_CLOSEREQ) { | 557 | } else if (dh->dccph_type == DCCP_PKT_CLOSEREQ) { |
558 | dccp_rcv_closereq(sk, skb); | 558 | dccp_rcv_closereq(sk, skb); |
@@ -563,13 +563,13 @@ int dccp_rcv_state_process(struct sock *sk, struct sk_buff *skb, | |||
563 | } | 563 | } |
564 | 564 | ||
565 | if (unlikely(dh->dccph_type == DCCP_PKT_SYNC)) { | 565 | if (unlikely(dh->dccph_type == DCCP_PKT_SYNC)) { |
566 | dccp_send_sync(sk, DCCP_SKB_CB(skb)->dccpd_seq, | 566 | dccp_send_sync(sk, dcb->dccpd_seq, DCCP_PKT_SYNCACK); |
567 | DCCP_PKT_SYNCACK); | ||
568 | goto discard; | 567 | goto discard; |
569 | } | 568 | } |
570 | 569 | ||
571 | switch (sk->sk_state) { | 570 | switch (sk->sk_state) { |
572 | case DCCP_CLOSED: | 571 | case DCCP_CLOSED: |
572 | dcb->dccpd_reset_code = DCCP_RESET_CODE_NO_CONNECTION; | ||
573 | return 1; | 573 | return 1; |
574 | 574 | ||
575 | case DCCP_REQUESTING: | 575 | case DCCP_REQUESTING: |
diff --git a/net/dccp/ipv4.c b/net/dccp/ipv4.c index 2afaa464e7f0..94a440b2685b 100644 --- a/net/dccp/ipv4.c +++ b/net/dccp/ipv4.c | |||
@@ -246,6 +246,9 @@ static int dccp_v4_connect(struct sock *sk, struct sockaddr *uaddr, | |||
246 | 246 | ||
247 | dp->dccps_role = DCCP_ROLE_CLIENT; | 247 | dp->dccps_role = DCCP_ROLE_CLIENT; |
248 | 248 | ||
249 | if (dccp_service_not_initialized(sk)) | ||
250 | return -EPROTO; | ||
251 | |||
249 | if (addr_len < sizeof(struct sockaddr_in)) | 252 | if (addr_len < sizeof(struct sockaddr_in)) |
250 | return -EINVAL; | 253 | return -EINVAL; |
251 | 254 | ||
@@ -661,6 +664,16 @@ static inline u64 dccp_v4_init_sequence(const struct sock *sk, | |||
661 | dccp_hdr(skb)->dccph_sport); | 664 | dccp_hdr(skb)->dccph_sport); |
662 | } | 665 | } |
663 | 666 | ||
667 | static inline int dccp_bad_service_code(const struct sock *sk, | ||
668 | const __u32 service) | ||
669 | { | ||
670 | const struct dccp_sock *dp = dccp_sk(sk); | ||
671 | |||
672 | if (dp->dccps_service == service) | ||
673 | return 0; | ||
674 | return !dccp_list_has_service(dp->dccps_service_list, service); | ||
675 | } | ||
676 | |||
664 | int dccp_v4_conn_request(struct sock *sk, struct sk_buff *skb) | 677 | int dccp_v4_conn_request(struct sock *sk, struct sk_buff *skb) |
665 | { | 678 | { |
666 | struct inet_request_sock *ireq; | 679 | struct inet_request_sock *ireq; |
@@ -669,13 +682,22 @@ int dccp_v4_conn_request(struct sock *sk, struct sk_buff *skb) | |||
669 | struct dccp_request_sock *dreq; | 682 | struct dccp_request_sock *dreq; |
670 | const __u32 saddr = skb->nh.iph->saddr; | 683 | const __u32 saddr = skb->nh.iph->saddr; |
671 | const __u32 daddr = skb->nh.iph->daddr; | 684 | const __u32 daddr = skb->nh.iph->daddr; |
685 | const __u32 service = dccp_hdr_request(skb)->dccph_req_service; | ||
686 | struct dccp_skb_cb *dcb = DCCP_SKB_CB(skb); | ||
687 | __u8 reset_code = DCCP_RESET_CODE_TOO_BUSY; | ||
672 | struct dst_entry *dst = NULL; | 688 | struct dst_entry *dst = NULL; |
673 | 689 | ||
674 | /* Never answer to DCCP_PKT_REQUESTs send to broadcast or multicast */ | 690 | /* Never answer to DCCP_PKT_REQUESTs send to broadcast or multicast */ |
675 | if (((struct rtable *)skb->dst)->rt_flags & | 691 | if (((struct rtable *)skb->dst)->rt_flags & |
676 | (RTCF_BROADCAST | RTCF_MULTICAST)) | 692 | (RTCF_BROADCAST | RTCF_MULTICAST)) { |
693 | reset_code = DCCP_RESET_CODE_NO_CONNECTION; | ||
677 | goto drop; | 694 | goto drop; |
695 | } | ||
678 | 696 | ||
697 | if (dccp_bad_service_code(sk, service)) { | ||
698 | reset_code = DCCP_RESET_CODE_BAD_SERVICE_CODE; | ||
699 | goto drop; | ||
700 | } | ||
679 | /* | 701 | /* |
680 | * TW buckets are converted to open requests without | 702 | * TW buckets are converted to open requests without |
681 | * limitations, they conserve resources and peer is | 703 | * limitations, they conserve resources and peer is |
@@ -718,9 +740,9 @@ int dccp_v4_conn_request(struct sock *sk, struct sk_buff *skb) | |||
718 | * dccp_create_openreq_child. | 740 | * dccp_create_openreq_child. |
719 | */ | 741 | */ |
720 | dreq = dccp_rsk(req); | 742 | dreq = dccp_rsk(req); |
721 | dreq->dreq_isr = DCCP_SKB_CB(skb)->dccpd_seq; | 743 | dreq->dreq_isr = dcb->dccpd_seq; |
722 | dreq->dreq_iss = dccp_v4_init_sequence(sk, skb); | 744 | dreq->dreq_iss = dccp_v4_init_sequence(sk, skb); |
723 | dreq->dreq_service = dccp_hdr_request(skb)->dccph_req_service; | 745 | dreq->dreq_service = service; |
724 | 746 | ||
725 | if (dccp_v4_send_response(sk, req, dst)) | 747 | if (dccp_v4_send_response(sk, req, dst)) |
726 | goto drop_and_free; | 748 | goto drop_and_free; |
@@ -735,6 +757,7 @@ drop_and_free: | |||
735 | __reqsk_free(req); | 757 | __reqsk_free(req); |
736 | drop: | 758 | drop: |
737 | DCCP_INC_STATS_BH(DCCP_MIB_ATTEMPTFAILS); | 759 | DCCP_INC_STATS_BH(DCCP_MIB_ATTEMPTFAILS); |
760 | dcb->dccpd_reset_code = reset_code; | ||
738 | return -1; | 761 | return -1; |
739 | } | 762 | } |
740 | 763 | ||
@@ -1005,7 +1028,6 @@ int dccp_v4_do_rcv(struct sock *sk, struct sk_buff *skb) | |||
1005 | return 0; | 1028 | return 0; |
1006 | 1029 | ||
1007 | reset: | 1030 | reset: |
1008 | DCCP_SKB_CB(skb)->dccpd_reset_code = DCCP_RESET_CODE_NO_CONNECTION; | ||
1009 | dccp_v4_ctl_send_reset(skb); | 1031 | dccp_v4_ctl_send_reset(skb); |
1010 | discard: | 1032 | discard: |
1011 | kfree_skb(skb); | 1033 | kfree_skb(skb); |
@@ -1280,6 +1302,7 @@ static int dccp_v4_init_sock(struct sock *sk) | |||
1280 | sk->sk_write_space = dccp_write_space; | 1302 | sk->sk_write_space = dccp_write_space; |
1281 | dp->dccps_mss_cache = 536; | 1303 | dp->dccps_mss_cache = 536; |
1282 | dp->dccps_role = DCCP_ROLE_UNDEFINED; | 1304 | dp->dccps_role = DCCP_ROLE_UNDEFINED; |
1305 | dp->dccps_service = DCCP_SERVICE_INVALID_VALUE; | ||
1283 | 1306 | ||
1284 | return 0; | 1307 | return 0; |
1285 | } | 1308 | } |
@@ -1301,6 +1324,11 @@ static int dccp_v4_destroy_sock(struct sock *sk) | |||
1301 | if (inet_csk(sk)->icsk_bind_hash != NULL) | 1324 | if (inet_csk(sk)->icsk_bind_hash != NULL) |
1302 | inet_put_port(&dccp_hashinfo, sk); | 1325 | inet_put_port(&dccp_hashinfo, sk); |
1303 | 1326 | ||
1327 | if (dp->dccps_service_list != NULL) { | ||
1328 | kfree(dp->dccps_service_list); | ||
1329 | dp->dccps_service_list = NULL; | ||
1330 | } | ||
1331 | |||
1304 | ccid_hc_rx_exit(dp->dccps_hc_rx_ccid, sk); | 1332 | ccid_hc_rx_exit(dp->dccps_hc_rx_ccid, sk); |
1305 | ccid_hc_tx_exit(dp->dccps_hc_tx_ccid, sk); | 1333 | ccid_hc_tx_exit(dp->dccps_hc_tx_ccid, sk); |
1306 | dccp_ackpkts_free(dp->dccps_hc_rx_ackpkts); | 1334 | dccp_ackpkts_free(dp->dccps_hc_rx_ackpkts); |
diff --git a/net/dccp/minisocks.c b/net/dccp/minisocks.c index 18461bc04cbe..933e10db1789 100644 --- a/net/dccp/minisocks.c +++ b/net/dccp/minisocks.c | |||
@@ -93,9 +93,11 @@ struct sock *dccp_create_openreq_child(struct sock *sk, | |||
93 | struct inet_connection_sock *newicsk = inet_csk(sk); | 93 | struct inet_connection_sock *newicsk = inet_csk(sk); |
94 | struct dccp_sock *newdp = dccp_sk(newsk); | 94 | struct dccp_sock *newdp = dccp_sk(newsk); |
95 | 95 | ||
96 | newdp->dccps_role = DCCP_ROLE_SERVER; | ||
96 | newdp->dccps_hc_rx_ackpkts = NULL; | 97 | newdp->dccps_hc_rx_ackpkts = NULL; |
97 | newdp->dccps_role = DCCP_ROLE_SERVER; | 98 | newdp->dccps_service_list = NULL; |
98 | newicsk->icsk_rto = DCCP_TIMEOUT_INIT; | 99 | newdp->dccps_service = dreq->dreq_service; |
100 | newicsk->icsk_rto = DCCP_TIMEOUT_INIT; | ||
99 | do_gettimeofday(&newdp->dccps_epoch); | 101 | do_gettimeofday(&newdp->dccps_epoch); |
100 | 102 | ||
101 | if (newdp->dccps_options.dccpo_send_ack_vector) { | 103 | if (newdp->dccps_options.dccpo_send_ack_vector) { |
diff --git a/net/dccp/output.c b/net/dccp/output.c index ea6d0e91e511..156b1d29a156 100644 --- a/net/dccp/output.c +++ b/net/dccp/output.c | |||
@@ -85,7 +85,7 @@ int dccp_transmit_skb(struct sock *sk, struct sk_buff *skb) | |||
85 | switch (dcb->dccpd_type) { | 85 | switch (dcb->dccpd_type) { |
86 | case DCCP_PKT_REQUEST: | 86 | case DCCP_PKT_REQUEST: |
87 | dccp_hdr_request(skb)->dccph_req_service = | 87 | dccp_hdr_request(skb)->dccph_req_service = |
88 | dcb->dccpd_service; | 88 | dp->dccps_service; |
89 | break; | 89 | break; |
90 | case DCCP_PKT_RESET: | 90 | case DCCP_PKT_RESET: |
91 | dccp_hdr_reset(skb)->dccph_reset_code = | 91 | dccp_hdr_reset(skb)->dccph_reset_code = |
@@ -270,6 +270,7 @@ struct sk_buff *dccp_make_response(struct sock *sk, struct dst_entry *dst, | |||
270 | struct request_sock *req) | 270 | struct request_sock *req) |
271 | { | 271 | { |
272 | struct dccp_hdr *dh; | 272 | struct dccp_hdr *dh; |
273 | struct dccp_request_sock *dreq; | ||
273 | const int dccp_header_size = sizeof(struct dccp_hdr) + | 274 | const int dccp_header_size = sizeof(struct dccp_hdr) + |
274 | sizeof(struct dccp_hdr_ext) + | 275 | sizeof(struct dccp_hdr_ext) + |
275 | sizeof(struct dccp_hdr_response); | 276 | sizeof(struct dccp_hdr_response); |
@@ -285,8 +286,9 @@ struct sk_buff *dccp_make_response(struct sock *sk, struct dst_entry *dst, | |||
285 | skb->dst = dst_clone(dst); | 286 | skb->dst = dst_clone(dst); |
286 | skb->csum = 0; | 287 | skb->csum = 0; |
287 | 288 | ||
289 | dreq = dccp_rsk(req); | ||
288 | DCCP_SKB_CB(skb)->dccpd_type = DCCP_PKT_RESPONSE; | 290 | DCCP_SKB_CB(skb)->dccpd_type = DCCP_PKT_RESPONSE; |
289 | DCCP_SKB_CB(skb)->dccpd_seq = dccp_rsk(req)->dreq_iss; | 291 | DCCP_SKB_CB(skb)->dccpd_seq = dreq->dreq_iss; |
290 | dccp_insert_options(sk, skb); | 292 | dccp_insert_options(sk, skb); |
291 | 293 | ||
292 | skb->h.raw = skb_push(skb, dccp_header_size); | 294 | skb->h.raw = skb_push(skb, dccp_header_size); |
@@ -300,8 +302,9 @@ struct sk_buff *dccp_make_response(struct sock *sk, struct dst_entry *dst, | |||
300 | DCCP_SKB_CB(skb)->dccpd_opt_len) / 4; | 302 | DCCP_SKB_CB(skb)->dccpd_opt_len) / 4; |
301 | dh->dccph_type = DCCP_PKT_RESPONSE; | 303 | dh->dccph_type = DCCP_PKT_RESPONSE; |
302 | dh->dccph_x = 1; | 304 | dh->dccph_x = 1; |
303 | dccp_hdr_set_seq(dh, dccp_rsk(req)->dreq_iss); | 305 | dccp_hdr_set_seq(dh, dreq->dreq_iss); |
304 | dccp_hdr_set_ack(dccp_hdr_ack_bits(skb), dccp_rsk(req)->dreq_isr); | 306 | dccp_hdr_set_ack(dccp_hdr_ack_bits(skb), dreq->dreq_isr); |
307 | dccp_hdr_response(skb)->dccph_resp_service = dreq->dreq_service; | ||
305 | 308 | ||
306 | dh->dccph_checksum = dccp_v4_checksum(skb, inet_rsk(req)->loc_addr, | 309 | dh->dccph_checksum = dccp_v4_checksum(skb, inet_rsk(req)->loc_addr, |
307 | inet_rsk(req)->rmt_addr); | 310 | inet_rsk(req)->rmt_addr); |
@@ -397,9 +400,6 @@ int dccp_connect(struct sock *sk) | |||
397 | skb_reserve(skb, MAX_DCCP_HEADER); | 400 | skb_reserve(skb, MAX_DCCP_HEADER); |
398 | 401 | ||
399 | DCCP_SKB_CB(skb)->dccpd_type = DCCP_PKT_REQUEST; | 402 | DCCP_SKB_CB(skb)->dccpd_type = DCCP_PKT_REQUEST; |
400 | /* FIXME: set service to something meaningful, coming | ||
401 | * from userspace*/ | ||
402 | DCCP_SKB_CB(skb)->dccpd_service = 0; | ||
403 | skb->csum = 0; | 403 | skb->csum = 0; |
404 | skb_set_owner_w(skb, sk); | 404 | skb_set_owner_w(skb, sk); |
405 | 405 | ||
diff --git a/net/dccp/proto.c b/net/dccp/proto.c index 18a0e69c9dc7..9bda2868eba6 100644 --- a/net/dccp/proto.c +++ b/net/dccp/proto.c | |||
@@ -94,7 +94,15 @@ EXPORT_SYMBOL_GPL(dccp_state_name); | |||
94 | 94 | ||
95 | static inline int dccp_listen_start(struct sock *sk) | 95 | static inline int dccp_listen_start(struct sock *sk) |
96 | { | 96 | { |
97 | dccp_sk(sk)->dccps_role = DCCP_ROLE_LISTEN; | 97 | struct dccp_sock *dp = dccp_sk(sk); |
98 | |||
99 | dp->dccps_role = DCCP_ROLE_LISTEN; | ||
100 | /* | ||
101 | * Apps need to use setsockopt(DCCP_SOCKOPT_SERVICE) | ||
102 | * before calling listen() | ||
103 | */ | ||
104 | if (dccp_service_not_initialized(sk)) | ||
105 | return -EPROTO; | ||
98 | return inet_csk_listen_start(sk, TCP_SYNQ_HSIZE); | 106 | return inet_csk_listen_start(sk, TCP_SYNQ_HSIZE); |
99 | } | 107 | } |
100 | 108 | ||
@@ -202,6 +210,42 @@ int dccp_ioctl(struct sock *sk, int cmd, unsigned long arg) | |||
202 | return -ENOIOCTLCMD; | 210 | return -ENOIOCTLCMD; |
203 | } | 211 | } |
204 | 212 | ||
213 | static int dccp_setsockopt_service(struct sock *sk, const u32 service, | ||
214 | char __user *optval, int optlen) | ||
215 | { | ||
216 | struct dccp_sock *dp = dccp_sk(sk); | ||
217 | struct dccp_service_list *sl = NULL; | ||
218 | |||
219 | if (service == DCCP_SERVICE_INVALID_VALUE || | ||
220 | optlen > DCCP_SERVICE_LIST_MAX_LEN * sizeof(u32)) | ||
221 | return -EINVAL; | ||
222 | |||
223 | if (optlen > sizeof(service)) { | ||
224 | sl = kmalloc(optlen, GFP_KERNEL); | ||
225 | if (sl == NULL) | ||
226 | return -ENOMEM; | ||
227 | |||
228 | sl->dccpsl_nr = optlen / sizeof(u32) - 1; | ||
229 | if (copy_from_user(sl->dccpsl_list, | ||
230 | optval + sizeof(service), | ||
231 | optlen - sizeof(service)) || | ||
232 | dccp_list_has_service(sl, DCCP_SERVICE_INVALID_VALUE)) { | ||
233 | kfree(sl); | ||
234 | return -EFAULT; | ||
235 | } | ||
236 | } | ||
237 | |||
238 | lock_sock(sk); | ||
239 | dp->dccps_service = service; | ||
240 | |||
241 | if (dp->dccps_service_list != NULL) | ||
242 | kfree(dp->dccps_service_list); | ||
243 | |||
244 | dp->dccps_service_list = sl; | ||
245 | release_sock(sk); | ||
246 | return 0; | ||
247 | } | ||
248 | |||
205 | int dccp_setsockopt(struct sock *sk, int level, int optname, | 249 | int dccp_setsockopt(struct sock *sk, int level, int optname, |
206 | char __user *optval, int optlen) | 250 | char __user *optval, int optlen) |
207 | { | 251 | { |
@@ -218,8 +262,10 @@ int dccp_setsockopt(struct sock *sk, int level, int optname, | |||
218 | if (get_user(val, (int __user *)optval)) | 262 | if (get_user(val, (int __user *)optval)) |
219 | return -EFAULT; | 263 | return -EFAULT; |
220 | 264 | ||
221 | lock_sock(sk); | 265 | if (optname == DCCP_SOCKOPT_SERVICE) |
266 | return dccp_setsockopt_service(sk, val, optval, optlen); | ||
222 | 267 | ||
268 | lock_sock(sk); | ||
223 | dp = dccp_sk(sk); | 269 | dp = dccp_sk(sk); |
224 | err = 0; | 270 | err = 0; |
225 | 271 | ||
@@ -236,6 +282,37 @@ int dccp_setsockopt(struct sock *sk, int level, int optname, | |||
236 | return err; | 282 | return err; |
237 | } | 283 | } |
238 | 284 | ||
285 | static int dccp_getsockopt_service(struct sock *sk, int len, | ||
286 | u32 __user *optval, | ||
287 | int __user *optlen) | ||
288 | { | ||
289 | const struct dccp_sock *dp = dccp_sk(sk); | ||
290 | const struct dccp_service_list *sl; | ||
291 | int err = -ENOENT, slen = 0, total_len = sizeof(u32); | ||
292 | |||
293 | lock_sock(sk); | ||
294 | if (dccp_service_not_initialized(sk)) | ||
295 | goto out; | ||
296 | |||
297 | if ((sl = dp->dccps_service_list) != NULL) { | ||
298 | slen = sl->dccpsl_nr * sizeof(u32); | ||
299 | total_len += slen; | ||
300 | } | ||
301 | |||
302 | err = -EINVAL; | ||
303 | if (total_len > len) | ||
304 | goto out; | ||
305 | |||
306 | err = 0; | ||
307 | if (put_user(total_len, optlen) || | ||
308 | put_user(dp->dccps_service, optval) || | ||
309 | (sl != NULL && copy_to_user(optval + 1, sl->dccpsl_list, slen))) | ||
310 | err = -EFAULT; | ||
311 | out: | ||
312 | release_sock(sk); | ||
313 | return err; | ||
314 | } | ||
315 | |||
239 | int dccp_getsockopt(struct sock *sk, int level, int optname, | 316 | int dccp_getsockopt(struct sock *sk, int level, int optname, |
240 | char __user *optval, int __user *optlen) | 317 | char __user *optval, int __user *optlen) |
241 | { | 318 | { |
@@ -248,6 +325,10 @@ int dccp_getsockopt(struct sock *sk, int level, int optname, | |||
248 | if (get_user(len, optlen)) | 325 | if (get_user(len, optlen)) |
249 | return -EFAULT; | 326 | return -EFAULT; |
250 | 327 | ||
328 | if (optname == DCCP_SOCKOPT_SERVICE) | ||
329 | return dccp_getsockopt_service(sk, len, | ||
330 | (u32 __user *)optval, optlen); | ||
331 | |||
251 | len = min_t(unsigned int, len, sizeof(int)); | 332 | len = min_t(unsigned int, len, sizeof(int)); |
252 | if (len < 0) | 333 | if (len < 0) |
253 | return -EINVAL; | 334 | return -EINVAL; |
diff --git a/net/ipv4/netfilter/Kconfig b/net/ipv4/netfilter/Kconfig index 30aa8e2ee214..85190de5710a 100644 --- a/net/ipv4/netfilter/Kconfig +++ b/net/ipv4/netfilter/Kconfig | |||
@@ -8,6 +8,7 @@ menu "IP: Netfilter Configuration" | |||
8 | # connection tracking, helpers and protocols | 8 | # connection tracking, helpers and protocols |
9 | config IP_NF_CONNTRACK | 9 | config IP_NF_CONNTRACK |
10 | tristate "Connection tracking (required for masq/NAT)" | 10 | tristate "Connection tracking (required for masq/NAT)" |
11 | select NETFILTER_NETLINK if IP_NF_CONNTRACK_NETLINK!=n | ||
11 | ---help--- | 12 | ---help--- |
12 | Connection tracking keeps a record of what packets have passed | 13 | Connection tracking keeps a record of what packets have passed |
13 | through your machine, in order to figure out how they are related | 14 | through your machine, in order to figure out how they are related |
@@ -51,6 +52,15 @@ config IP_NF_CONNTRACK_EVENTS | |||
51 | 52 | ||
52 | IF unsure, say `N'. | 53 | IF unsure, say `N'. |
53 | 54 | ||
55 | config IP_NF_CONNTRACK_NETLINK | ||
56 | tristate 'Connection tracking netlink interface' | ||
57 | depends on IP_NF_CONNTRACK && NETFILTER_NETLINK | ||
58 | default IP_NF_CONNTRACK if NETFILTER_NETLINK=y | ||
59 | default m if NETFILTER_NETLINK=m | ||
60 | help | ||
61 | This option enables support for a netlink-based userspace interface | ||
62 | |||
63 | |||
54 | config IP_NF_CT_PROTO_SCTP | 64 | config IP_NF_CT_PROTO_SCTP |
55 | tristate 'SCTP protocol connection tracking support (EXPERIMENTAL)' | 65 | tristate 'SCTP protocol connection tracking support (EXPERIMENTAL)' |
56 | depends on IP_NF_CONNTRACK && EXPERIMENTAL | 66 | depends on IP_NF_CONNTRACK && EXPERIMENTAL |
@@ -774,11 +784,5 @@ config IP_NF_ARP_MANGLE | |||
774 | Allows altering the ARP packet payload: source and destination | 784 | Allows altering the ARP packet payload: source and destination |
775 | hardware and network addresses. | 785 | hardware and network addresses. |
776 | 786 | ||
777 | config IP_NF_CONNTRACK_NETLINK | ||
778 | tristate 'Connection tracking netlink interface' | ||
779 | depends on IP_NF_CONNTRACK && NETFILTER_NETLINK | ||
780 | help | ||
781 | This option enables support for a netlink-based userspace interface | ||
782 | |||
783 | endmenu | 787 | endmenu |
784 | 788 | ||
diff --git a/net/ipv4/netfilter/ip_conntrack_core.c b/net/ipv4/netfilter/ip_conntrack_core.c index 19cba16e6e1e..f8cd8e42961e 100644 --- a/net/ipv4/netfilter/ip_conntrack_core.c +++ b/net/ipv4/netfilter/ip_conntrack_core.c | |||
@@ -1143,7 +1143,10 @@ void ip_ct_refresh_acct(struct ip_conntrack *ct, | |||
1143 | if (del_timer(&ct->timeout)) { | 1143 | if (del_timer(&ct->timeout)) { |
1144 | ct->timeout.expires = jiffies + extra_jiffies; | 1144 | ct->timeout.expires = jiffies + extra_jiffies; |
1145 | add_timer(&ct->timeout); | 1145 | add_timer(&ct->timeout); |
1146 | ip_conntrack_event_cache(IPCT_REFRESH, skb); | 1146 | /* FIXME: We loose some REFRESH events if this function |
1147 | * is called without an skb. I'll fix this later -HW */ | ||
1148 | if (skb) | ||
1149 | ip_conntrack_event_cache(IPCT_REFRESH, skb); | ||
1147 | } | 1150 | } |
1148 | ct_add_counters(ct, ctinfo, skb); | 1151 | ct_add_counters(ct, ctinfo, skb); |
1149 | write_unlock_bh(&ip_conntrack_lock); | 1152 | write_unlock_bh(&ip_conntrack_lock); |
diff --git a/net/ipv4/netfilter/ipt_CLUSTERIP.c b/net/ipv4/netfilter/ipt_CLUSTERIP.c index 7d38913754b1..9bcb398fbc1f 100644 --- a/net/ipv4/netfilter/ipt_CLUSTERIP.c +++ b/net/ipv4/netfilter/ipt_CLUSTERIP.c | |||
@@ -13,6 +13,7 @@ | |||
13 | #include <linux/config.h> | 13 | #include <linux/config.h> |
14 | #include <linux/proc_fs.h> | 14 | #include <linux/proc_fs.h> |
15 | #include <linux/jhash.h> | 15 | #include <linux/jhash.h> |
16 | #include <linux/bitops.h> | ||
16 | #include <linux/skbuff.h> | 17 | #include <linux/skbuff.h> |
17 | #include <linux/ip.h> | 18 | #include <linux/ip.h> |
18 | #include <linux/tcp.h> | 19 | #include <linux/tcp.h> |
@@ -30,7 +31,7 @@ | |||
30 | #include <linux/netfilter_ipv4/ipt_CLUSTERIP.h> | 31 | #include <linux/netfilter_ipv4/ipt_CLUSTERIP.h> |
31 | #include <linux/netfilter_ipv4/ip_conntrack.h> | 32 | #include <linux/netfilter_ipv4/ip_conntrack.h> |
32 | 33 | ||
33 | #define CLUSTERIP_VERSION "0.7" | 34 | #define CLUSTERIP_VERSION "0.8" |
34 | 35 | ||
35 | #define DEBUG_CLUSTERIP | 36 | #define DEBUG_CLUSTERIP |
36 | 37 | ||
@@ -49,13 +50,14 @@ MODULE_DESCRIPTION("iptables target for CLUSTERIP"); | |||
49 | struct clusterip_config { | 50 | struct clusterip_config { |
50 | struct list_head list; /* list of all configs */ | 51 | struct list_head list; /* list of all configs */ |
51 | atomic_t refcount; /* reference count */ | 52 | atomic_t refcount; /* reference count */ |
53 | atomic_t entries; /* number of entries/rules | ||
54 | * referencing us */ | ||
52 | 55 | ||
53 | u_int32_t clusterip; /* the IP address */ | 56 | u_int32_t clusterip; /* the IP address */ |
54 | u_int8_t clustermac[ETH_ALEN]; /* the MAC address */ | 57 | u_int8_t clustermac[ETH_ALEN]; /* the MAC address */ |
55 | struct net_device *dev; /* device */ | 58 | struct net_device *dev; /* device */ |
56 | u_int16_t num_total_nodes; /* total number of nodes */ | 59 | u_int16_t num_total_nodes; /* total number of nodes */ |
57 | u_int16_t num_local_nodes; /* number of local nodes */ | 60 | unsigned long local_nodes; /* node number array */ |
58 | u_int16_t local_nodes[CLUSTERIP_MAX_NODES]; /* node number array */ | ||
59 | 61 | ||
60 | #ifdef CONFIG_PROC_FS | 62 | #ifdef CONFIG_PROC_FS |
61 | struct proc_dir_entry *pde; /* proc dir entry */ | 63 | struct proc_dir_entry *pde; /* proc dir entry */ |
@@ -66,8 +68,7 @@ struct clusterip_config { | |||
66 | 68 | ||
67 | static LIST_HEAD(clusterip_configs); | 69 | static LIST_HEAD(clusterip_configs); |
68 | 70 | ||
69 | /* clusterip_lock protects the clusterip_configs list _AND_ the configurable | 71 | /* clusterip_lock protects the clusterip_configs list */ |
70 | * data within all structurses (num_local_nodes, local_nodes[]) */ | ||
71 | static DEFINE_RWLOCK(clusterip_lock); | 72 | static DEFINE_RWLOCK(clusterip_lock); |
72 | 73 | ||
73 | #ifdef CONFIG_PROC_FS | 74 | #ifdef CONFIG_PROC_FS |
@@ -76,23 +77,48 @@ static struct proc_dir_entry *clusterip_procdir; | |||
76 | #endif | 77 | #endif |
77 | 78 | ||
78 | static inline void | 79 | static inline void |
79 | clusterip_config_get(struct clusterip_config *c) { | 80 | clusterip_config_get(struct clusterip_config *c) |
81 | { | ||
80 | atomic_inc(&c->refcount); | 82 | atomic_inc(&c->refcount); |
81 | } | 83 | } |
82 | 84 | ||
83 | static inline void | 85 | static inline void |
84 | clusterip_config_put(struct clusterip_config *c) { | 86 | clusterip_config_put(struct clusterip_config *c) |
85 | if (atomic_dec_and_test(&c->refcount)) { | 87 | { |
88 | if (atomic_dec_and_test(&c->refcount)) | ||
89 | kfree(c); | ||
90 | } | ||
91 | |||
92 | /* increase the count of entries(rules) using/referencing this config */ | ||
93 | static inline void | ||
94 | clusterip_config_entry_get(struct clusterip_config *c) | ||
95 | { | ||
96 | atomic_inc(&c->entries); | ||
97 | } | ||
98 | |||
99 | /* decrease the count of entries using/referencing this config. If last | ||
100 | * entry(rule) is removed, remove the config from lists, but don't free it | ||
101 | * yet, since proc-files could still be holding references */ | ||
102 | static inline void | ||
103 | clusterip_config_entry_put(struct clusterip_config *c) | ||
104 | { | ||
105 | if (atomic_dec_and_test(&c->entries)) { | ||
86 | write_lock_bh(&clusterip_lock); | 106 | write_lock_bh(&clusterip_lock); |
87 | list_del(&c->list); | 107 | list_del(&c->list); |
88 | write_unlock_bh(&clusterip_lock); | 108 | write_unlock_bh(&clusterip_lock); |
109 | |||
89 | dev_mc_delete(c->dev, c->clustermac, ETH_ALEN, 0); | 110 | dev_mc_delete(c->dev, c->clustermac, ETH_ALEN, 0); |
90 | dev_put(c->dev); | 111 | dev_put(c->dev); |
91 | kfree(c); | 112 | |
113 | /* In case anyone still accesses the file, the open/close | ||
114 | * functions are also incrementing the refcount on their own, | ||
115 | * so it's safe to remove the entry even if it's in use. */ | ||
116 | #ifdef CONFIG_PROC_FS | ||
117 | remove_proc_entry(c->pde->name, c->pde->parent); | ||
118 | #endif | ||
92 | } | 119 | } |
93 | } | 120 | } |
94 | 121 | ||
95 | |||
96 | static struct clusterip_config * | 122 | static struct clusterip_config * |
97 | __clusterip_config_find(u_int32_t clusterip) | 123 | __clusterip_config_find(u_int32_t clusterip) |
98 | { | 124 | { |
@@ -111,7 +137,7 @@ __clusterip_config_find(u_int32_t clusterip) | |||
111 | } | 137 | } |
112 | 138 | ||
113 | static inline struct clusterip_config * | 139 | static inline struct clusterip_config * |
114 | clusterip_config_find_get(u_int32_t clusterip) | 140 | clusterip_config_find_get(u_int32_t clusterip, int entry) |
115 | { | 141 | { |
116 | struct clusterip_config *c; | 142 | struct clusterip_config *c; |
117 | 143 | ||
@@ -122,11 +148,24 @@ clusterip_config_find_get(u_int32_t clusterip) | |||
122 | return NULL; | 148 | return NULL; |
123 | } | 149 | } |
124 | atomic_inc(&c->refcount); | 150 | atomic_inc(&c->refcount); |
151 | if (entry) | ||
152 | atomic_inc(&c->entries); | ||
125 | read_unlock_bh(&clusterip_lock); | 153 | read_unlock_bh(&clusterip_lock); |
126 | 154 | ||
127 | return c; | 155 | return c; |
128 | } | 156 | } |
129 | 157 | ||
158 | static void | ||
159 | clusterip_config_init_nodelist(struct clusterip_config *c, | ||
160 | const struct ipt_clusterip_tgt_info *i) | ||
161 | { | ||
162 | int n; | ||
163 | |||
164 | for (n = 0; n < i->num_local_nodes; n++) { | ||
165 | set_bit(i->local_nodes[n] - 1, &c->local_nodes); | ||
166 | } | ||
167 | } | ||
168 | |||
130 | static struct clusterip_config * | 169 | static struct clusterip_config * |
131 | clusterip_config_init(struct ipt_clusterip_tgt_info *i, u_int32_t ip, | 170 | clusterip_config_init(struct ipt_clusterip_tgt_info *i, u_int32_t ip, |
132 | struct net_device *dev) | 171 | struct net_device *dev) |
@@ -143,11 +182,11 @@ clusterip_config_init(struct ipt_clusterip_tgt_info *i, u_int32_t ip, | |||
143 | c->clusterip = ip; | 182 | c->clusterip = ip; |
144 | memcpy(&c->clustermac, &i->clustermac, ETH_ALEN); | 183 | memcpy(&c->clustermac, &i->clustermac, ETH_ALEN); |
145 | c->num_total_nodes = i->num_total_nodes; | 184 | c->num_total_nodes = i->num_total_nodes; |
146 | c->num_local_nodes = i->num_local_nodes; | 185 | clusterip_config_init_nodelist(c, i); |
147 | memcpy(&c->local_nodes, &i->local_nodes, sizeof(c->local_nodes)); | ||
148 | c->hash_mode = i->hash_mode; | 186 | c->hash_mode = i->hash_mode; |
149 | c->hash_initval = i->hash_initval; | 187 | c->hash_initval = i->hash_initval; |
150 | atomic_set(&c->refcount, 1); | 188 | atomic_set(&c->refcount, 1); |
189 | atomic_set(&c->entries, 1); | ||
151 | 190 | ||
152 | #ifdef CONFIG_PROC_FS | 191 | #ifdef CONFIG_PROC_FS |
153 | /* create proc dir entry */ | 192 | /* create proc dir entry */ |
@@ -171,53 +210,28 @@ clusterip_config_init(struct ipt_clusterip_tgt_info *i, u_int32_t ip, | |||
171 | static int | 210 | static int |
172 | clusterip_add_node(struct clusterip_config *c, u_int16_t nodenum) | 211 | clusterip_add_node(struct clusterip_config *c, u_int16_t nodenum) |
173 | { | 212 | { |
174 | int i; | ||
175 | |||
176 | write_lock_bh(&clusterip_lock); | ||
177 | 213 | ||
178 | if (c->num_local_nodes >= CLUSTERIP_MAX_NODES | 214 | if (nodenum == 0 || |
179 | || nodenum > CLUSTERIP_MAX_NODES) { | 215 | nodenum > c->num_total_nodes) |
180 | write_unlock_bh(&clusterip_lock); | ||
181 | return 1; | 216 | return 1; |
182 | } | ||
183 | |||
184 | /* check if we alrady have this number in our array */ | ||
185 | for (i = 0; i < c->num_local_nodes; i++) { | ||
186 | if (c->local_nodes[i] == nodenum) { | ||
187 | write_unlock_bh(&clusterip_lock); | ||
188 | return 1; | ||
189 | } | ||
190 | } | ||
191 | 217 | ||
192 | c->local_nodes[c->num_local_nodes++] = nodenum; | 218 | /* check if we already have this number in our bitfield */ |
219 | if (test_and_set_bit(nodenum - 1, &c->local_nodes)) | ||
220 | return 1; | ||
193 | 221 | ||
194 | write_unlock_bh(&clusterip_lock); | ||
195 | return 0; | 222 | return 0; |
196 | } | 223 | } |
197 | 224 | ||
198 | static int | 225 | static int |
199 | clusterip_del_node(struct clusterip_config *c, u_int16_t nodenum) | 226 | clusterip_del_node(struct clusterip_config *c, u_int16_t nodenum) |
200 | { | 227 | { |
201 | int i; | 228 | if (nodenum == 0 || |
202 | 229 | nodenum > c->num_total_nodes) | |
203 | write_lock_bh(&clusterip_lock); | ||
204 | |||
205 | if (c->num_local_nodes <= 1 || nodenum > CLUSTERIP_MAX_NODES) { | ||
206 | write_unlock_bh(&clusterip_lock); | ||
207 | return 1; | 230 | return 1; |
208 | } | ||
209 | 231 | ||
210 | for (i = 0; i < c->num_local_nodes; i++) { | 232 | if (test_and_clear_bit(nodenum - 1, &c->local_nodes)) |
211 | if (c->local_nodes[i] == nodenum) { | 233 | return 0; |
212 | int size = sizeof(u_int16_t)*(c->num_local_nodes-(i+1)); | ||
213 | memmove(&c->local_nodes[i], &c->local_nodes[i+1], size); | ||
214 | c->num_local_nodes--; | ||
215 | write_unlock_bh(&clusterip_lock); | ||
216 | return 0; | ||
217 | } | ||
218 | } | ||
219 | 234 | ||
220 | write_unlock_bh(&clusterip_lock); | ||
221 | return 1; | 235 | return 1; |
222 | } | 236 | } |
223 | 237 | ||
@@ -285,25 +299,7 @@ clusterip_hashfn(struct sk_buff *skb, struct clusterip_config *config) | |||
285 | static inline int | 299 | static inline int |
286 | clusterip_responsible(struct clusterip_config *config, u_int32_t hash) | 300 | clusterip_responsible(struct clusterip_config *config, u_int32_t hash) |
287 | { | 301 | { |
288 | int i; | 302 | return test_bit(hash - 1, &config->local_nodes); |
289 | |||
290 | read_lock_bh(&clusterip_lock); | ||
291 | |||
292 | if (config->num_local_nodes == 0) { | ||
293 | read_unlock_bh(&clusterip_lock); | ||
294 | return 0; | ||
295 | } | ||
296 | |||
297 | for (i = 0; i < config->num_local_nodes; i++) { | ||
298 | if (config->local_nodes[i] == hash) { | ||
299 | read_unlock_bh(&clusterip_lock); | ||
300 | return 1; | ||
301 | } | ||
302 | } | ||
303 | |||
304 | read_unlock_bh(&clusterip_lock); | ||
305 | |||
306 | return 0; | ||
307 | } | 303 | } |
308 | 304 | ||
309 | /*********************************************************************** | 305 | /*********************************************************************** |
@@ -415,8 +411,26 @@ checkentry(const char *tablename, | |||
415 | 411 | ||
416 | /* FIXME: further sanity checks */ | 412 | /* FIXME: further sanity checks */ |
417 | 413 | ||
418 | config = clusterip_config_find_get(e->ip.dst.s_addr); | 414 | config = clusterip_config_find_get(e->ip.dst.s_addr, 1); |
419 | if (!config) { | 415 | if (config) { |
416 | if (cipinfo->config != NULL) { | ||
417 | /* Case A: This is an entry that gets reloaded, since | ||
418 | * it still has a cipinfo->config pointer. Simply | ||
419 | * increase the entry refcount and return */ | ||
420 | if (cipinfo->config != config) { | ||
421 | printk(KERN_ERR "CLUSTERIP: Reloaded entry " | ||
422 | "has invalid config pointer!\n"); | ||
423 | return 0; | ||
424 | } | ||
425 | clusterip_config_entry_get(cipinfo->config); | ||
426 | } else { | ||
427 | /* Case B: This is a new rule referring to an existing | ||
428 | * clusterip config. */ | ||
429 | cipinfo->config = config; | ||
430 | clusterip_config_entry_get(cipinfo->config); | ||
431 | } | ||
432 | } else { | ||
433 | /* Case C: This is a completely new clusterip config */ | ||
420 | if (!(cipinfo->flags & CLUSTERIP_FLAG_NEW)) { | 434 | if (!(cipinfo->flags & CLUSTERIP_FLAG_NEW)) { |
421 | printk(KERN_WARNING "CLUSTERIP: no config found for %u.%u.%u.%u, need 'new'\n", NIPQUAD(e->ip.dst.s_addr)); | 435 | printk(KERN_WARNING "CLUSTERIP: no config found for %u.%u.%u.%u, need 'new'\n", NIPQUAD(e->ip.dst.s_addr)); |
422 | return 0; | 436 | return 0; |
@@ -443,10 +457,9 @@ checkentry(const char *tablename, | |||
443 | } | 457 | } |
444 | dev_mc_add(config->dev,config->clustermac, ETH_ALEN, 0); | 458 | dev_mc_add(config->dev,config->clustermac, ETH_ALEN, 0); |
445 | } | 459 | } |
460 | cipinfo->config = config; | ||
446 | } | 461 | } |
447 | 462 | ||
448 | cipinfo->config = config; | ||
449 | |||
450 | return 1; | 463 | return 1; |
451 | } | 464 | } |
452 | 465 | ||
@@ -455,13 +468,10 @@ static void destroy(void *matchinfo, unsigned int matchinfosize) | |||
455 | { | 468 | { |
456 | struct ipt_clusterip_tgt_info *cipinfo = matchinfo; | 469 | struct ipt_clusterip_tgt_info *cipinfo = matchinfo; |
457 | 470 | ||
458 | /* we first remove the proc entry and then drop the reference | 471 | /* if no more entries are referencing the config, remove it |
459 | * count. In case anyone still accesses the file, the open/close | 472 | * from the list and destroy the proc entry */ |
460 | * functions are also incrementing the refcount on their own */ | 473 | clusterip_config_entry_put(cipinfo->config); |
461 | #ifdef CONFIG_PROC_FS | 474 | |
462 | remove_proc_entry(cipinfo->config->pde->name, | ||
463 | cipinfo->config->pde->parent); | ||
464 | #endif | ||
465 | clusterip_config_put(cipinfo->config); | 475 | clusterip_config_put(cipinfo->config); |
466 | } | 476 | } |
467 | 477 | ||
@@ -533,7 +543,7 @@ arp_mangle(unsigned int hook, | |||
533 | 543 | ||
534 | /* if there is no clusterip configuration for the arp reply's | 544 | /* if there is no clusterip configuration for the arp reply's |
535 | * source ip, we don't want to mangle it */ | 545 | * source ip, we don't want to mangle it */ |
536 | c = clusterip_config_find_get(payload->src_ip); | 546 | c = clusterip_config_find_get(payload->src_ip, 0); |
537 | if (!c) | 547 | if (!c) |
538 | return NF_ACCEPT; | 548 | return NF_ACCEPT; |
539 | 549 | ||
@@ -574,56 +584,69 @@ static struct nf_hook_ops cip_arp_ops = { | |||
574 | 584 | ||
575 | #ifdef CONFIG_PROC_FS | 585 | #ifdef CONFIG_PROC_FS |
576 | 586 | ||
587 | struct clusterip_seq_position { | ||
588 | unsigned int pos; /* position */ | ||
589 | unsigned int weight; /* number of bits set == size */ | ||
590 | unsigned int bit; /* current bit */ | ||
591 | unsigned long val; /* current value */ | ||
592 | }; | ||
593 | |||
577 | static void *clusterip_seq_start(struct seq_file *s, loff_t *pos) | 594 | static void *clusterip_seq_start(struct seq_file *s, loff_t *pos) |
578 | { | 595 | { |
579 | struct proc_dir_entry *pde = s->private; | 596 | struct proc_dir_entry *pde = s->private; |
580 | struct clusterip_config *c = pde->data; | 597 | struct clusterip_config *c = pde->data; |
581 | unsigned int *nodeidx; | 598 | unsigned int weight; |
582 | 599 | u_int32_t local_nodes; | |
583 | read_lock_bh(&clusterip_lock); | 600 | struct clusterip_seq_position *idx; |
584 | if (*pos >= c->num_local_nodes) | 601 | |
602 | /* FIXME: possible race */ | ||
603 | local_nodes = c->local_nodes; | ||
604 | weight = hweight32(local_nodes); | ||
605 | if (*pos >= weight) | ||
585 | return NULL; | 606 | return NULL; |
586 | 607 | ||
587 | nodeidx = kmalloc(sizeof(unsigned int), GFP_KERNEL); | 608 | idx = kmalloc(sizeof(struct clusterip_seq_position), GFP_KERNEL); |
588 | if (!nodeidx) | 609 | if (!idx) |
589 | return ERR_PTR(-ENOMEM); | 610 | return ERR_PTR(-ENOMEM); |
590 | 611 | ||
591 | *nodeidx = *pos; | 612 | idx->pos = *pos; |
592 | return nodeidx; | 613 | idx->weight = weight; |
614 | idx->bit = ffs(local_nodes); | ||
615 | idx->val = local_nodes; | ||
616 | clear_bit(idx->bit - 1, &idx->val); | ||
617 | |||
618 | return idx; | ||
593 | } | 619 | } |
594 | 620 | ||
595 | static void *clusterip_seq_next(struct seq_file *s, void *v, loff_t *pos) | 621 | static void *clusterip_seq_next(struct seq_file *s, void *v, loff_t *pos) |
596 | { | 622 | { |
597 | struct proc_dir_entry *pde = s->private; | 623 | struct clusterip_seq_position *idx = (struct clusterip_seq_position *)v; |
598 | struct clusterip_config *c = pde->data; | ||
599 | unsigned int *nodeidx = (unsigned int *)v; | ||
600 | 624 | ||
601 | *pos = ++(*nodeidx); | 625 | *pos = ++idx->pos; |
602 | if (*pos >= c->num_local_nodes) { | 626 | if (*pos >= idx->weight) { |
603 | kfree(v); | 627 | kfree(v); |
604 | return NULL; | 628 | return NULL; |
605 | } | 629 | } |
606 | return nodeidx; | 630 | idx->bit = ffs(idx->val); |
631 | clear_bit(idx->bit - 1, &idx->val); | ||
632 | return idx; | ||
607 | } | 633 | } |
608 | 634 | ||
609 | static void clusterip_seq_stop(struct seq_file *s, void *v) | 635 | static void clusterip_seq_stop(struct seq_file *s, void *v) |
610 | { | 636 | { |
611 | kfree(v); | 637 | kfree(v); |
612 | |||
613 | read_unlock_bh(&clusterip_lock); | ||
614 | } | 638 | } |
615 | 639 | ||
616 | static int clusterip_seq_show(struct seq_file *s, void *v) | 640 | static int clusterip_seq_show(struct seq_file *s, void *v) |
617 | { | 641 | { |
618 | struct proc_dir_entry *pde = s->private; | 642 | struct clusterip_seq_position *idx = (struct clusterip_seq_position *)v; |
619 | struct clusterip_config *c = pde->data; | ||
620 | unsigned int *nodeidx = (unsigned int *)v; | ||
621 | 643 | ||
622 | if (*nodeidx != 0) | 644 | if (idx->pos != 0) |
623 | seq_putc(s, ','); | 645 | seq_putc(s, ','); |
624 | seq_printf(s, "%u", c->local_nodes[*nodeidx]); | ||
625 | 646 | ||
626 | if (*nodeidx == c->num_local_nodes-1) | 647 | seq_printf(s, "%u", idx->bit); |
648 | |||
649 | if (idx->pos == idx->weight - 1) | ||
627 | seq_putc(s, '\n'); | 650 | seq_putc(s, '\n'); |
628 | 651 | ||
629 | return 0; | 652 | return 0; |
diff --git a/net/socket.c b/net/socket.c index c699e93c33d7..f9264472377f 100644 --- a/net/socket.c +++ b/net/socket.c | |||
@@ -1862,7 +1862,8 @@ asmlinkage long sys_recvmsg(int fd, struct msghdr __user *msg, unsigned int flag | |||
1862 | if (err < 0) | 1862 | if (err < 0) |
1863 | goto out_freeiov; | 1863 | goto out_freeiov; |
1864 | } | 1864 | } |
1865 | err = __put_user(msg_sys.msg_flags, COMPAT_FLAGS(msg)); | 1865 | err = __put_user((msg_sys.msg_flags & ~MSG_CMSG_COMPAT), |
1866 | COMPAT_FLAGS(msg)); | ||
1866 | if (err) | 1867 | if (err) |
1867 | goto out_freeiov; | 1868 | goto out_freeiov; |
1868 | if (MSG_CMSG_COMPAT & flags) | 1869 | if (MSG_CMSG_COMPAT & flags) |