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,
};
+EXPORT_SYMBOL_GPL(dccp_hashinfo);
+
static int dccp_v4_get_port(struct sock *sk, const unsigned short snum)
{
return inet_csk_get_port(&dccp_hashinfo, sk, snum);
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;
NET_INC_STATS_BH(LINUX_MIB_TIMEWAITRECYCLED);
} else if (tw != NULL) {
/* Silly. Should hash-dance instead... */
- dccp_tw_deschedule(tw);
+ inet_twsk_deschedule(tw, &dccp_death_row);
NET_INC_STATS_BH(LINUX_MIB_TIMEWAITRECYCLED);
inet_twsk_put(tw);
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
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,
}
}
- 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;
spin_unlock(&head->lock);
if (tw != NULL) {
- dccp_tw_deschedule(tw);
+ inet_twsk_deschedule(tw, &dccp_death_row);
inet_twsk_put(tw);
}
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) {
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);
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;
/*
* 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 */
}
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) {
}
}
-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);
}
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;
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;
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;
/*
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;
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,
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,
.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);
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;
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)
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) {
/*
* 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
* 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);
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;
}
/* 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;
}
* 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;
}
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;
}
* 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...
* 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) {
*/
if (sk->sk_state == DCCP_TIME_WAIT) {
- dccp_pr_debug("sk->sk_state == DCCP_TIME_WAIT: discard_and_relse\n");
- goto discard_and_relse;
+ dccp_pr_debug("sk->sk_state == DCCP_TIME_WAIT: "
+ "do_time_wait\n");
+ goto do_time_wait;
}
if (!xfrm4_policy_check(sk, XFRM_POLICY_IN, skb)) {
* 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);
}
discard_and_relse:
sock_put(sk);
goto discard_it;
+
+do_time_wait:
+ inet_twsk_put((struct inet_timewait_sock *)sk);
+ goto no_dccp_socket;
}
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;
* 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);
dccp_ctl_socket_init = 0;
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);
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);
.max_header = MAX_DCCP_HEADER,
.obj_size = sizeof(struct dccp_sock),
.rsk_prot = &dccp_request_sock_ops,
- .twsk_obj_size = sizeof(struct inet_timewait_sock), /* FIXME! create dccp_timewait_sock */
+ .twsk_obj_size = sizeof(struct inet_timewait_sock),
};