static int dccp_v4_send_response(struct sock *sk, struct request_sock *req, struct dst_entry *dst) { int err = -1; struct sk_buff *skb; /* First, grab a route. */ if (dst == NULL && (dst = inet_csk_route_req(sk, req)) == NULL) goto out; skb = dccp_make_response(sk, dst, req); if (skb != NULL) { const struct inet_request_sock *ireq = inet_rsk(req); struct dccp_hdr *dh = dccp_hdr(skb); dh->dccph_checksum = dccp_v4_checksum(skb, ireq->loc_addr, ireq->rmt_addr); memset(&(IPCB(skb)->opt), 0, sizeof(IPCB(skb)->opt)); err = ip_build_and_send_pkt(skb, sk, ireq->loc_addr, ireq->rmt_addr, ireq->opt); if (err == NET_XMIT_CN) err = 0; } out: dst_release(dst); return err; }
static struct dst_entry* dccp_v4_route_skb(struct net *net, struct sock *sk, struct sk_buff *skb) { struct rtable *rt; const struct iphdr *iph = ip_hdr(skb); struct flowi4 fl4 = { .flowi4_oif = inet_iif(skb), .daddr = iph->saddr, .saddr = iph->daddr, .flowi4_tos = RT_CONN_FLAGS(sk), .flowi4_proto = sk->sk_protocol, .fl4_sport = dccp_hdr(skb)->dccph_dport, .fl4_dport = dccp_hdr(skb)->dccph_sport, }; security_skb_classify_flow(skb, flowi4_to_flowi(&fl4)); rt = ip_route_output_flow(net, &fl4, sk); if (IS_ERR(rt)) { IP_INC_STATS(net, IPSTATS_MIB_OUTNOROUTES); return NULL; } return &rt->dst; } static int dccp_v4_send_response(const struct sock *sk, struct request_sock *req) { int err = -1; struct sk_buff *skb; struct dst_entry *dst; struct flowi4 fl4; dst = inet_csk_route_req(sk, &fl4, req); if (dst == NULL) goto out; skb = dccp_make_response(sk, dst, req); if (skb != NULL) { const struct inet_request_sock *ireq = inet_rsk(req); struct dccp_hdr *dh = dccp_hdr(skb); dh->dccph_checksum = dccp_v4_csum_finish(skb, ireq->ir_loc_addr, ireq->ir_rmt_addr); rcu_read_lock(); err = ip_build_and_send_pkt(skb, sk, ireq->ir_loc_addr, ireq->ir_rmt_addr, rcu_dereference(ireq->ireq_opt)); rcu_read_unlock(); err = net_xmit_eval(err); } out: dst_release(dst); return err; }
/* * The three way handshake has completed - we got a valid ACK or DATAACK - * now create the new socket. * * This is the equivalent of TCP's tcp_v4_syn_recv_sock */ struct sock *dccp_v4_request_recv_sock(struct sock *sk, struct sk_buff *skb, struct request_sock *req, struct dst_entry *dst) { struct inet_request_sock *ireq; struct inet_sock *newinet; struct sock *newsk; if (sk_acceptq_is_full(sk)) goto exit_overflow; if (dst == NULL && (dst = inet_csk_route_req(sk, req)) == NULL) goto exit; newsk = dccp_create_openreq_child(sk, req, skb); if (newsk == NULL) goto exit_nonewsk; sk_setup_caps(newsk, dst); newinet = inet_sk(newsk); ireq = inet_rsk(req); newinet->inet_daddr = ireq->rmt_addr; newinet->inet_rcv_saddr = ireq->loc_addr; newinet->inet_saddr = ireq->loc_addr; newinet->opt = ireq->opt; ireq->opt = NULL; newinet->mc_index = inet_iif(skb); newinet->mc_ttl = ip_hdr(skb)->ttl; newinet->inet_id = jiffies; dccp_sync_mss(newsk, dst_mtu(dst)); if (__inet_inherit_port(sk, newsk) < 0) { sock_put(newsk); goto exit; } __inet_hash_nolisten(newsk, NULL); return newsk; exit_overflow: NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_LISTENOVERFLOWS); exit_nonewsk: dst_release(dst); exit: NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_LISTENDROPS); return NULL; }
/* * The three way handshake has completed - we got a valid ACK or DATAACK - * now create the new socket. * * This is the equivalent of TCP's tcp_v4_syn_recv_sock */ struct sock *dccp_v4_request_recv_sock(struct sock *sk, struct sk_buff *skb, struct request_sock *req, struct dst_entry *dst) { struct inet_request_sock *ireq; struct inet_sock *newinet; struct dccp_sock *newdp; struct sock *newsk; if (sk_acceptq_is_full(sk)) goto exit_overflow; if (dst == NULL && (dst = inet_csk_route_req(sk, req)) == NULL) goto exit; newsk = dccp_create_openreq_child(sk, req, skb); if (newsk == NULL) goto exit; sk_setup_caps(newsk, dst); newdp = dccp_sk(newsk); newinet = inet_sk(newsk); ireq = inet_rsk(req); newinet->daddr = ireq->rmt_addr; newinet->rcv_saddr = ireq->loc_addr; newinet->saddr = ireq->loc_addr; newinet->opt = ireq->opt; ireq->opt = NULL; newinet->mc_index = inet_iif(skb); newinet->mc_ttl = skb->nh.iph->ttl; newinet->id = jiffies; dccp_sync_mss(newsk, dst_mtu(dst)); __inet_hash(&dccp_hashinfo, newsk, 0); __inet_inherit_port(&dccp_hashinfo, sk, newsk); return newsk; exit_overflow: NET_INC_STATS_BH(LINUX_MIB_LISTENOVERFLOWS); exit: NET_INC_STATS_BH(LINUX_MIB_LISTENDROPS); dst_release(dst); return NULL; }