aboutsummaryrefslogtreecommitdiff
path: root/net/dccp/ipv4.c
diff options
context:
space:
mode:
authorDavid S. Miller <davem@sunset.davemloft.net>2005-09-18 00:17:10 -0700
committerDavid S. Miller <davem@sunset.davemloft.net>2005-09-18 00:17:10 -0700
commit21f130a2370ba837cdfc5204ebe52e7c664fec3d (patch)
tree7f8a30088d8d39eab9350c59b6638661309ffe89 /net/dccp/ipv4.c
parentbc5e8fdfc622b03acf5ac974a1b8b26da6511c99 (diff)
parentc58ec93245a1fb7354f9e331960380827b9f41db (diff)
Merge master.kernel.org:/pub/scm/linux/kernel/git/davem/net-2.6
Diffstat (limited to 'net/dccp/ipv4.c')
-rw-r--r--net/dccp/ipv4.c38
1 files changed, 33 insertions, 5 deletions
diff --git a/net/dccp/ipv4.c b/net/dccp/ipv4.c
index 2afaa464e7f..94a440b2685 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,
dp->dccps_role = DCCP_ROLE_CLIENT;
+ if (dccp_service_not_initialized(sk))
+ return -EPROTO;
+
if (addr_len < sizeof(struct sockaddr_in))
return -EINVAL;
@@ -661,6 +664,16 @@ static inline u64 dccp_v4_init_sequence(const struct sock *sk,
dccp_hdr(skb)->dccph_sport);
}
+static inline int dccp_bad_service_code(const struct sock *sk,
+ const __u32 service)
+{
+ const struct dccp_sock *dp = dccp_sk(sk);
+
+ if (dp->dccps_service == service)
+ return 0;
+ return !dccp_list_has_service(dp->dccps_service_list, service);
+}
+
int dccp_v4_conn_request(struct sock *sk, struct sk_buff *skb)
{
struct inet_request_sock *ireq;
@@ -669,13 +682,22 @@ int dccp_v4_conn_request(struct sock *sk, struct sk_buff *skb)
struct dccp_request_sock *dreq;
const __u32 saddr = skb->nh.iph->saddr;
const __u32 daddr = skb->nh.iph->daddr;
+ const __u32 service = dccp_hdr_request(skb)->dccph_req_service;
+ struct dccp_skb_cb *dcb = DCCP_SKB_CB(skb);
+ __u8 reset_code = DCCP_RESET_CODE_TOO_BUSY;
struct dst_entry *dst = NULL;
/* Never answer to DCCP_PKT_REQUESTs send to broadcast or multicast */
if (((struct rtable *)skb->dst)->rt_flags &
- (RTCF_BROADCAST | RTCF_MULTICAST))
+ (RTCF_BROADCAST | RTCF_MULTICAST)) {
+ reset_code = DCCP_RESET_CODE_NO_CONNECTION;
goto drop;
+ }
+ if (dccp_bad_service_code(sk, service)) {
+ reset_code = DCCP_RESET_CODE_BAD_SERVICE_CODE;
+ goto drop;
+ }
/*
* TW buckets are converted to open requests without
* limitations, they conserve resources and peer is
@@ -718,9 +740,9 @@ int dccp_v4_conn_request(struct sock *sk, struct sk_buff *skb)
* dccp_create_openreq_child.
*/
dreq = dccp_rsk(req);
- dreq->dreq_isr = DCCP_SKB_CB(skb)->dccpd_seq;
- dreq->dreq_iss = dccp_v4_init_sequence(sk, skb);
- dreq->dreq_service = dccp_hdr_request(skb)->dccph_req_service;
+ dreq->dreq_isr = dcb->dccpd_seq;
+ dreq->dreq_iss = dccp_v4_init_sequence(sk, skb);
+ dreq->dreq_service = service;
if (dccp_v4_send_response(sk, req, dst))
goto drop_and_free;
@@ -735,6 +757,7 @@ drop_and_free:
__reqsk_free(req);
drop:
DCCP_INC_STATS_BH(DCCP_MIB_ATTEMPTFAILS);
+ dcb->dccpd_reset_code = reset_code;
return -1;
}
@@ -1005,7 +1028,6 @@ int dccp_v4_do_rcv(struct sock *sk, struct sk_buff *skb)
return 0;
reset:
- DCCP_SKB_CB(skb)->dccpd_reset_code = DCCP_RESET_CODE_NO_CONNECTION;
dccp_v4_ctl_send_reset(skb);
discard:
kfree_skb(skb);
@@ -1280,6 +1302,7 @@ static int dccp_v4_init_sock(struct sock *sk)
sk->sk_write_space = dccp_write_space;
dp->dccps_mss_cache = 536;
dp->dccps_role = DCCP_ROLE_UNDEFINED;
+ dp->dccps_service = DCCP_SERVICE_INVALID_VALUE;
return 0;
}
@@ -1301,6 +1324,11 @@ static int dccp_v4_destroy_sock(struct sock *sk)
if (inet_csk(sk)->icsk_bind_hash != NULL)
inet_put_port(&dccp_hashinfo, sk);
+ if (dp->dccps_service_list != NULL) {
+ kfree(dp->dccps_service_list);
+ dp->dccps_service_list = NULL;
+ }
+
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);