tmp = ip_route_connect(&rt, nexthop, inet->saddr,
RT_CONN_FLAGS(sk), sk->sk_bound_dev_if,
IPPROTO_DCCP,
- inet->sport, usin->sin_port, sk);
+ inet->sport, usin->sin_port, sk, 1);
if (tmp < 0)
return tmp;
goto failure;
err = ip_route_newports(&rt, IPPROTO_DCCP, inet->sport, inet->dport,
- sk);
+ sk);
if (err != 0)
goto failure;
/* We don't check in the destentry if pmtu discovery is forbidden
* on this route. We just assume that no packet_to_big packets
* are send back when pmtu discovery is not active.
- * There is a small race when the user changes this flag in the
+ * There is a small race when the user changes this flag in the
* route, but I think that's acceptable.
*/
if ((dst = __sk_dst_check(sk, 0)) == NULL)
(iph->ihl << 2));
struct dccp_sock *dp;
struct inet_sock *inet;
- const int type = skb->h.icmph->type;
- const int code = skb->h.icmph->code;
+ const int type = icmp_hdr(skb)->type;
+ const int code = icmp_hdr(skb)->code;
struct sock *sk;
__u64 seq;
int err;
goto out;
dp = dccp_sk(sk);
- seq = dccp_hdr_seq(skb);
- if (sk->sk_state != DCCP_LISTEN &&
+ seq = dccp_hdr_seq(dh);
+ if ((1 << sk->sk_state) & ~(DCCPF_REQUESTING | DCCPF_LISTEN) &&
!between48(seq, dp->dccps_swl, dp->dccps_swh)) {
- NET_INC_STATS(LINUX_MIB_OUTOFWINDOWICMPS);
+ NET_INC_STATS_BH(LINUX_MIB_OUTOFWINDOWICMPS);
goto out;
}
sock_put(sk);
}
-static inline u16 dccp_v4_csum_finish(struct sk_buff *skb,
+static inline __sum16 dccp_v4_csum_finish(struct sk_buff *skb,
__be32 src, __be32 dst)
{
return csum_tcpudp_magic(src, dst, skb->len, IPPROTO_DCCP, skb->csum);
static inline u64 dccp_v4_init_sequence(const struct sk_buff *skb)
{
- return secure_dccp_sequence_number(skb->nh.iph->daddr,
- skb->nh.iph->saddr,
+ return secure_dccp_sequence_number(ip_hdr(skb)->daddr,
+ ip_hdr(skb)->saddr,
dccp_hdr(skb)->dccph_dport,
dccp_hdr(skb)->dccph_sport);
}
{
struct inet_request_sock *ireq;
struct inet_sock *newinet;
- struct dccp_sock *newdp;
struct sock *newsk;
if (sk_acceptq_is_full(sk))
sk_setup_caps(newsk, dst);
- newdp = dccp_sk(newsk);
newinet = inet_sk(newsk);
ireq = inet_rsk(req);
newinet->daddr = ireq->rmt_addr;
newinet->opt = ireq->opt;
ireq->opt = NULL;
newinet->mc_index = inet_iif(skb);
- newinet->mc_ttl = skb->nh.iph->ttl;
+ newinet->mc_ttl = ip_hdr(skb)->ttl;
newinet->id = jiffies;
dccp_sync_mss(newsk, dst_mtu(dst));
static struct sock *dccp_v4_hnd_req(struct sock *sk, struct sk_buff *skb)
{
const struct dccp_hdr *dh = dccp_hdr(skb);
- const struct iphdr *iph = skb->nh.iph;
+ const struct iphdr *iph = ip_hdr(skb);
struct sock *nsk;
struct request_sock **prev;
/* Find possible connection requests. */
struct rtable *rt;
struct flowi fl = { .oif = ((struct rtable *)skb->dst)->rt_iif,
.nl_u = { .ip4_u =
- { .daddr = skb->nh.iph->saddr,
- .saddr = skb->nh.iph->daddr,
+ { .daddr = ip_hdr(skb)->saddr,
+ .saddr = ip_hdr(skb)->daddr,
.tos = RT_CONN_FLAGS(sk) } },
.proto = sk->sk_protocol,
.uli_u = { .ports =
{ .sport = dccp_hdr(skb)->dccph_dport,
.dport = dccp_hdr(skb)->dccph_sport }
- }
+ }
};
security_skb_classify_flow(skb, &fl);
struct sk_buff *skb;
/* First, grab a route. */
-
+
if (dst == NULL && (dst = inet_csk_route_req(sk, req)) == NULL)
goto out;
static void dccp_v4_ctl_send_reset(struct sock *sk, struct sk_buff *rxskb)
{
int err;
- struct dccp_hdr *rxdh = dccp_hdr(rxskb), *dh;
- const int dccp_hdr_reset_len = sizeof(struct dccp_hdr) +
- sizeof(struct dccp_hdr_ext) +
- sizeof(struct dccp_hdr_reset);
+ const struct iphdr *rxiph;
struct sk_buff *skb;
struct dst_entry *dst;
- u64 seqno = 0;
/* Never send a reset in response to a reset. */
- if (rxdh->dccph_type == DCCP_PKT_RESET)
+ if (dccp_hdr(rxskb)->dccph_type == DCCP_PKT_RESET)
return;
if (((struct rtable *)rxskb->dst)->rt_type != RTN_LOCAL)
if (dst == NULL)
return;
- skb = alloc_skb(dccp_v4_ctl_socket->sk->sk_prot->max_header,
- GFP_ATOMIC);
+ skb = dccp_ctl_make_reset(dccp_v4_ctl_socket, rxskb);
if (skb == NULL)
goto out;
- /* Reserve space for headers. */
- skb_reserve(skb, dccp_v4_ctl_socket->sk->sk_prot->max_header);
+ rxiph = ip_hdr(rxskb);
+ dccp_hdr(skb)->dccph_checksum = dccp_v4_csum_finish(skb, rxiph->saddr,
+ rxiph->daddr);
skb->dst = dst_clone(dst);
- dh = dccp_zeroed_hdr(skb, dccp_hdr_reset_len);
-
- /* Build DCCP header and checksum it. */
- dh->dccph_type = DCCP_PKT_RESET;
- dh->dccph_sport = rxdh->dccph_dport;
- 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;
-
- /* See "8.3.1. Abnormal Termination" in RFC 4340 */
- 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);
-
- dccp_csum_outgoing(skb);
- dh->dccph_checksum = dccp_v4_csum_finish(skb, rxskb->nh.iph->saddr,
- rxskb->nh.iph->daddr);
-
bh_lock_sock(dccp_v4_ctl_socket->sk);
err = ip_build_and_send_pkt(skb, dccp_v4_ctl_socket->sk,
- rxskb->nh.iph->daddr,
- rxskb->nh.iph->saddr, NULL);
+ rxiph->daddr, rxiph->saddr, NULL);
bh_unlock_sock(dccp_v4_ctl_socket->sk);
if (net_xmit_eval(err) == 0) {
struct inet_request_sock *ireq;
struct request_sock *req;
struct dccp_request_sock *dreq;
- const __be32 service = dccp_hdr_request(skb)->dccph_req_service;
+ const __be32 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;
/* Never answer to DCCP_PKT_REQUESTs send to broadcast or multicast */
if (((struct rtable *)skb->dst)->rt_flags &
- (RTCF_BROADCAST | RTCF_MULTICAST)) {
- reset_code = DCCP_RESET_CODE_NO_CONNECTION;
- goto drop;
- }
+ (RTCF_BROADCAST | RTCF_MULTICAST))
+ return 0; /* discard, don't send a reset here */
if (dccp_bad_service_code(sk, service)) {
- reset_code = DCCP_RESET_CODE_BAD_SERVICE_CODE;
+ dcb->dccpd_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
* evidently real one.
*/
+ dcb->dccpd_reset_code = DCCP_RESET_CODE_TOO_BUSY;
if (inet_csk_reqsk_queue_is_full(sk))
goto drop;
goto drop_and_free;
ireq = inet_rsk(req);
- ireq->loc_addr = skb->nh.iph->daddr;
- ireq->rmt_addr = skb->nh.iph->saddr;
+ ireq->loc_addr = ip_hdr(skb)->daddr;
+ ireq->rmt_addr = ip_hdr(skb)->saddr;
ireq->opt = NULL;
- /*
+ /*
* Step 3: Process LISTEN state
*
* Set S.ISR, S.GSR, S.SWL, S.SWH from packet or Init Cookie
reqsk_free(req);
drop:
DCCP_INC_STATS_BH(DCCP_MIB_ATTEMPTFAILS);
- dcb->dccpd_reset_code = reset_code;
return -1;
}
/* If the packet is shorter than 12 bytes, drop packet and return */
if (!pskb_may_pull(skb, sizeof(struct dccp_hdr))) {
- LIMIT_NETDEBUG(KERN_WARNING "DCCP: pskb_may_pull failed\n");
+ DCCP_WARN("pskb_may_pull failed\n");
return 1;
}
/* If P.type is not understood, drop packet and return */
if (dh->dccph_type >= DCCP_PKT_INVALID) {
- LIMIT_NETDEBUG(KERN_WARNING "DCCP: invalid packet type\n");
+ DCCP_WARN("invalid packet type\n");
return 1;
}
* If P.Data Offset is too small for packet type, drop packet and return
*/
if (dh->dccph_doff < dccp_hdr_len(skb) / sizeof(u32)) {
- LIMIT_NETDEBUG(KERN_WARNING "DCCP: P.Data Offset(%u) "
- "too small\n", dh->dccph_doff);
+ DCCP_WARN("P.Data Offset(%u) too small\n", dh->dccph_doff);
return 1;
}
/*
* If P.Data Offset is too too large for packet, drop packet and return
*/
if (!pskb_may_pull(skb, dh->dccph_doff * sizeof(u32))) {
- LIMIT_NETDEBUG(KERN_WARNING "DCCP: P.Data Offset(%u) "
- "too large\n", dh->dccph_doff);
+ DCCP_WARN("P.Data Offset(%u) too large\n", dh->dccph_doff);
return 1;
}
*/
if (dh->dccph_type >= DCCP_PKT_DATA &&
dh->dccph_type <= DCCP_PKT_DATAACK && dh->dccph_x == 0) {
- LIMIT_NETDEBUG(KERN_WARNING "DCCP: P.type (%s) not Data||Ack||"
- "DataAck, while P.X == 0\n",
- dccp_packet_name(dh->dccph_type));
+ DCCP_WARN("P.type (%s) not Data || [Data]Ack, while P.X == 0\n",
+ dccp_packet_name(dh->dccph_type));
return 1;
}
*/
cscov = dccp_csum_coverage(skb);
if (cscov > skb->len) {
- LIMIT_NETDEBUG(KERN_WARNING
- "DCCP: P.CsCov %u exceeds packet length %d\n",
- dh->dccph_cscov, skb->len);
+ DCCP_WARN("P.CsCov %u exceeds packet length %d\n",
+ dh->dccph_cscov, skb->len);
return 1;
}
static int dccp_v4_rcv(struct sk_buff *skb)
{
const struct dccp_hdr *dh;
+ const struct iphdr *iph;
struct sock *sk;
int min_cov;
if (dccp_invalid_packet(skb))
goto discard_it;
+ iph = ip_hdr(skb);
/* Step 1: If header checksum is incorrect, drop packet and return */
- if (dccp_v4_csum_finish(skb, skb->nh.iph->saddr, skb->nh.iph->daddr)) {
- LIMIT_NETDEBUG(KERN_WARNING
- "%s: dropped packet with invalid checksum\n",
- __FUNCTION__);
+ if (dccp_v4_csum_finish(skb, iph->saddr, iph->daddr)) {
+ DCCP_WARN("dropped packet with invalid checksum\n");
goto discard_it;
}
dh = dccp_hdr(skb);
- DCCP_SKB_CB(skb)->dccpd_seq = dccp_hdr_seq(skb);
+ DCCP_SKB_CB(skb)->dccpd_seq = dccp_hdr_seq(dh);
DCCP_SKB_CB(skb)->dccpd_type = dh->dccph_type;
dccp_pr_debug("%8.8s "
"src=%u.%u.%u.%u@%-5d "
"dst=%u.%u.%u.%u@%-5d seq=%llu",
dccp_packet_name(dh->dccph_type),
- NIPQUAD(skb->nh.iph->saddr), ntohs(dh->dccph_sport),
- NIPQUAD(skb->nh.iph->daddr), ntohs(dh->dccph_dport),
+ NIPQUAD(iph->saddr), ntohs(dh->dccph_sport),
+ NIPQUAD(iph->daddr), ntohs(dh->dccph_dport),
(unsigned long long) DCCP_SKB_CB(skb)->dccpd_seq);
if (dccp_packet_without_ack(skb)) {
}
/* Step 2:
- * Look up flow ID in table and get corresponding socket */
+ * Look up flow ID in table and get corresponding socket */
sk = __inet_lookup(&dccp_hashinfo,
- skb->nh.iph->saddr, dh->dccph_sport,
- skb->nh.iph->daddr, dh->dccph_dport,
- inet_iif(skb));
-
- /*
+ iph->saddr, dh->dccph_sport,
+ iph->daddr, dh->dccph_dport, inet_iif(skb));
+ /*
* Step 2:
- * If no socket ...
+ * If no socket ...
*/
if (sk == NULL) {
dccp_pr_debug("failed to look up flow ID in table and "
goto no_dccp_socket;
}
- /*
+ /*
* Step 2:
- * ... or S.state == TIMEWAIT,
+ * ... or S.state == TIMEWAIT,
* Generate Reset(No Connection) unless P.type == Reset
* Drop packet and return
*/
/*
* RFC 4340, sec. 9.2.1: Minimum Checksum Coverage
- * o if MinCsCov = 0, only packets with CsCov = 0 are accepted
- * o if MinCsCov > 0, also accept packets with CsCov >= MinCsCov
+ * o if MinCsCov = 0, only packets with CsCov = 0 are accepted
+ * o if MinCsCov > 0, also accept packets with CsCov >= MinCsCov
*/
min_cov = dccp_sk(sk)->dccps_pcrlen;
if (dh->dccph_cscov && (min_cov == 0 || dh->dccph_cscov < min_cov)) {
goto discard_and_relse;
nf_reset(skb);
- return sk_receive_skb(sk, skb);
+ return sk_receive_skb(sk, skb, 1);
no_dccp_socket:
if (!xfrm4_policy_check(NULL, XFRM_POLICY_IN, skb))
goto discard_it;
/*
* Step 2:
- * If no socket ...
+ * If no socket ...
* Generate Reset(No Connection) unless P.type == Reset
* Drop packet and return
*/
.twsk_obj_size = sizeof(struct inet_timewait_sock),
};
+DEFINE_PROTO_INUSE(dccp_v4)
+
static struct proto dccp_v4_prot = {
.name = "DCCP",
.owner = THIS_MODULE,
.compat_setsockopt = compat_dccp_setsockopt,
.compat_getsockopt = compat_dccp_getsockopt,
#endif
+ REF_PROTO_INUSE(dccp_v4)
};
static struct net_protocol dccp_v4_protocol = {
* values directly, Also cover the case where the protocol is not specified,
* i.e. net-pf-PF_INET-proto-0-type-SOCK_DCCP
*/
-MODULE_ALIAS("net-pf-" __stringify(PF_INET) "-proto-33-type-6");
-MODULE_ALIAS("net-pf-" __stringify(PF_INET) "-proto-0-type-6");
+MODULE_ALIAS_NET_PF_PROTO_TYPE(PF_INET, 33, 6);
+MODULE_ALIAS_NET_PF_PROTO_TYPE(PF_INET, 0, 6);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Arnaldo Carvalho de Melo <acme@mandriva.com>");
MODULE_DESCRIPTION("DCCP - Datagram Congestion Controlled Protocol");