LCOV - code coverage report
Current view: top level - net/ipv6 - inet6_connection_sock.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 8 96 8.3 %
Date: 2014-04-07 Functions: 1 9 11.1 %
Branches: 8 70 11.4 %

           Branch data     Line data    Source code
       1                 :            : /*
       2                 :            :  * INET        An implementation of the TCP/IP protocol suite for the LINUX
       3                 :            :  *             operating system.  INET is implemented using the  BSD Socket
       4                 :            :  *             interface as the means of communication with the user level.
       5                 :            :  *
       6                 :            :  *             Support for INET6 connection oriented protocols.
       7                 :            :  *
       8                 :            :  * Authors:    See the TCPv6 sources
       9                 :            :  *
      10                 :            :  *             This program is free software; you can redistribute it and/or
      11                 :            :  *             modify it under the terms of the GNU General Public License
      12                 :            :  *             as published by the Free Software Foundation; either version
      13                 :            :  *             2 of the License, or(at your option) any later version.
      14                 :            :  */
      15                 :            : 
      16                 :            : #include <linux/module.h>
      17                 :            : #include <linux/in6.h>
      18                 :            : #include <linux/ipv6.h>
      19                 :            : #include <linux/jhash.h>
      20                 :            : #include <linux/slab.h>
      21                 :            : 
      22                 :            : #include <net/addrconf.h>
      23                 :            : #include <net/inet_connection_sock.h>
      24                 :            : #include <net/inet_ecn.h>
      25                 :            : #include <net/inet_hashtables.h>
      26                 :            : #include <net/ip6_route.h>
      27                 :            : #include <net/sock.h>
      28                 :            : #include <net/inet6_connection_sock.h>
      29                 :            : 
      30                 :          0 : int inet6_csk_bind_conflict(const struct sock *sk,
      31                 :            :                             const struct inet_bind_bucket *tb, bool relax)
      32                 :            : {
      33                 :            :         const struct sock *sk2;
      34                 :          1 :         int reuse = sk->sk_reuse;
      35                 :          1 :         int reuseport = sk->sk_reuseport;
      36                 :          1 :         kuid_t uid = sock_i_uid((struct sock *)sk);
      37                 :            : 
      38                 :            :         /* We must walk the whole port owner list in this case. -DaveM */
      39                 :            :         /*
      40                 :            :          * See comment in inet_csk_bind_conflict about sock lookup
      41                 :            :          * vs net namespaces issues.
      42                 :            :          */
      43 [ +  - ][ #  # ]:          1 :         sk_for_each_bound(sk2, &tb->owners) {
                 [ +  - ]
      44 [ +  - ][ -  + ]:          1 :                 if (sk != sk2 &&
      45         [ #  # ]:          0 :                     (!sk->sk_bound_dev_if ||
      46         [ #  # ]:          0 :                      !sk2->sk_bound_dev_if ||
      47                 :            :                      sk->sk_bound_dev_if == sk2->sk_bound_dev_if)) {
      48 [ +  - ][ +  - ]:          1 :                         if ((!reuse || !sk2->sk_reuse ||
                 [ +  - ]
      49         [ #  # ]:          1 :                              sk2->sk_state == TCP_LISTEN) &&
      50 [ #  # ][ #  # ]:          0 :                             (!reuseport || !sk2->sk_reuseport ||
      51         [ #  # ]:          0 :                              (sk2->sk_state != TCP_TIME_WAIT &&
      52                 :          0 :                               !uid_eq(uid,
      53                 :            :                                       sock_i_uid((struct sock *)sk2))))) {
      54         [ -  + ]:          0 :                                 if (ipv6_rcv_saddr_equal(sk, sk2))
      55                 :            :                                         break;
      56                 :            :                         }
      57 [ #  # ][ #  # ]:          0 :                         if (!relax && reuse && sk2->sk_reuse &&
                 [ #  # ]
      58         [ #  # ]:          0 :                             sk2->sk_state != TCP_LISTEN &&
      59                 :          0 :                             ipv6_rcv_saddr_equal(sk, sk2))
      60                 :            :                                 break;
      61                 :            :                 }
      62                 :            :         }
      63                 :            : 
      64                 :          1 :         return sk2 != NULL;
      65                 :            : }
      66                 :            : 
      67                 :            : EXPORT_SYMBOL_GPL(inet6_csk_bind_conflict);
      68                 :            : 
      69                 :          0 : struct dst_entry *inet6_csk_route_req(struct sock *sk,
      70                 :            :                                       struct flowi6 *fl6,
      71                 :            :                                       const struct request_sock *req)
      72                 :            : {
      73                 :            :         struct inet_request_sock *ireq = inet_rsk(req);
      74                 :            :         struct ipv6_pinfo *np = inet6_sk(sk);
      75                 :            :         struct in6_addr *final_p, final;
      76                 :            :         struct dst_entry *dst;
      77                 :            : 
      78                 :          0 :         memset(fl6, 0, sizeof(*fl6));
      79                 :          0 :         fl6->flowi6_proto = IPPROTO_TCP;
      80                 :          0 :         fl6->daddr = ireq->ir_v6_rmt_addr;
      81                 :          0 :         final_p = fl6_update_dst(fl6, np->opt, &final);
      82                 :          0 :         fl6->saddr = ireq->ir_v6_loc_addr;
      83                 :          0 :         fl6->flowi6_oif = ireq->ir_iif;
      84                 :          0 :         fl6->flowi6_mark = sk->sk_mark;
      85                 :          0 :         fl6->fl6_dport = ireq->ir_rmt_port;
      86         [ #  # ]:          0 :         fl6->fl6_sport = htons(ireq->ir_num);
      87                 :          0 :         security_req_classify_flow(req, flowi6_to_flowi(fl6));
      88                 :            : 
      89                 :          0 :         dst = ip6_dst_lookup_flow(sk, fl6, final_p, false);
      90         [ #  # ]:          0 :         if (IS_ERR(dst))
      91                 :            :                 return NULL;
      92                 :            : 
      93                 :          0 :         return dst;
      94                 :            : }
      95                 :            : 
      96                 :            : /*
      97                 :            :  * request_sock (formerly open request) hash tables.
      98                 :            :  */
      99                 :          0 : static u32 inet6_synq_hash(const struct in6_addr *raddr, const __be16 rport,
     100                 :            :                            const u32 rnd, const u32 synq_hsize)
     101                 :            : {
     102                 :            :         u32 c;
     103                 :            : 
     104                 :          0 :         c = jhash_3words((__force u32)raddr->s6_addr32[0],
     105                 :            :                          (__force u32)raddr->s6_addr32[1],
     106                 :            :                          (__force u32)raddr->s6_addr32[2],
     107                 :            :                          rnd);
     108                 :            : 
     109                 :          0 :         c = jhash_2words((__force u32)raddr->s6_addr32[3],
     110                 :            :                          (__force u32)rport,
     111                 :            :                          c);
     112                 :            : 
     113                 :          0 :         return c & (synq_hsize - 1);
     114                 :            : }
     115                 :            : 
     116                 :          0 : struct request_sock *inet6_csk_search_req(const struct sock *sk,
     117                 :            :                                           struct request_sock ***prevp,
     118                 :            :                                           const __be16 rport,
     119                 :            :                                           const struct in6_addr *raddr,
     120                 :            :                                           const struct in6_addr *laddr,
     121                 :            :                                           const int iif)
     122                 :            : {
     123                 :            :         const struct inet_connection_sock *icsk = inet_csk(sk);
     124                 :          0 :         struct listen_sock *lopt = icsk->icsk_accept_queue.listen_opt;
     125                 :            :         struct request_sock *req, **prev;
     126                 :            : 
     127         [ #  # ]:          0 :         for (prev = &lopt->syn_table[inet6_synq_hash(raddr, rport,
     128                 :            :                                                      lopt->hash_rnd,
     129                 :            :                                                      lopt->nr_table_entries)];
     130                 :          0 :              (req = *prev) != NULL;
     131                 :          0 :              prev = &req->dl_next) {
     132                 :            :                 const struct inet_request_sock *ireq = inet_rsk(req);
     133                 :            : 
     134 [ #  # ][ #  # ]:          0 :                 if (ireq->ir_rmt_port == rport &&
     135         [ #  # ]:          0 :                     req->rsk_ops->family == AF_INET6 &&
     136         [ #  # ]:          0 :                     ipv6_addr_equal(&ireq->ir_v6_rmt_addr, raddr) &&
     137         [ #  # ]:          0 :                     ipv6_addr_equal(&ireq->ir_v6_loc_addr, laddr) &&
     138         [ #  # ]:          0 :                     (!ireq->ir_iif || ireq->ir_iif == iif)) {
     139         [ #  # ]:          0 :                         WARN_ON(req->sk != NULL);
     140                 :          0 :                         *prevp = prev;
     141                 :          0 :                         return req;
     142                 :            :                 }
     143                 :            :         }
     144                 :            : 
     145                 :            :         return NULL;
     146                 :            : }
     147                 :            : 
     148                 :            : EXPORT_SYMBOL_GPL(inet6_csk_search_req);
     149                 :            : 
     150                 :          0 : void inet6_csk_reqsk_queue_hash_add(struct sock *sk,
     151                 :            :                                     struct request_sock *req,
     152                 :            :                                     const unsigned long timeout)
     153                 :            : {
     154                 :            :         struct inet_connection_sock *icsk = inet_csk(sk);
     155                 :          0 :         struct listen_sock *lopt = icsk->icsk_accept_queue.listen_opt;
     156                 :          0 :         const u32 h = inet6_synq_hash(&inet_rsk(req)->ir_v6_rmt_addr,
     157                 :            :                                       inet_rsk(req)->ir_rmt_port,
     158                 :            :                                       lopt->hash_rnd, lopt->nr_table_entries);
     159                 :            : 
     160                 :            :         reqsk_queue_hash_req(&icsk->icsk_accept_queue, h, req, timeout);
     161                 :            :         inet_csk_reqsk_queue_added(sk, timeout);
     162                 :          0 : }
     163                 :            : 
     164                 :            : EXPORT_SYMBOL_GPL(inet6_csk_reqsk_queue_hash_add);
     165                 :            : 
     166                 :          0 : void inet6_csk_addr2sockaddr(struct sock *sk, struct sockaddr * uaddr)
     167                 :            : {
     168                 :            :         struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *) uaddr;
     169                 :            : 
     170                 :          0 :         sin6->sin6_family = AF_INET6;
     171                 :          0 :         sin6->sin6_addr = sk->sk_v6_daddr;
     172                 :          0 :         sin6->sin6_port      = inet_sk(sk)->inet_dport;
     173                 :            :         /* We do not store received flowlabel for TCP */
     174                 :          0 :         sin6->sin6_flowinfo = 0;
     175                 :          0 :         sin6->sin6_scope_id = ipv6_iface_scope_id(&sin6->sin6_addr,
     176                 :            :                                                   sk->sk_bound_dev_if);
     177                 :          0 : }
     178                 :            : 
     179                 :            : EXPORT_SYMBOL_GPL(inet6_csk_addr2sockaddr);
     180                 :            : 
     181                 :            : static inline
     182                 :            : void __inet6_csk_dst_store(struct sock *sk, struct dst_entry *dst,
     183                 :            :                            const struct in6_addr *daddr,
     184                 :            :                            const struct in6_addr *saddr)
     185                 :            : {
     186                 :            :         __ip6_dst_store(sk, dst, daddr, saddr);
     187                 :            : }
     188                 :            : 
     189                 :            : static inline
     190                 :            : struct dst_entry *__inet6_csk_dst_check(struct sock *sk, u32 cookie)
     191                 :            : {
     192                 :          0 :         return __sk_dst_check(sk, cookie);
     193                 :            : }
     194                 :            : 
     195                 :          0 : static struct dst_entry *inet6_csk_route_socket(struct sock *sk,
     196                 :            :                                                 struct flowi6 *fl6)
     197                 :            : {
     198                 :            :         struct inet_sock *inet = inet_sk(sk);
     199                 :            :         struct ipv6_pinfo *np = inet6_sk(sk);
     200                 :            :         struct in6_addr *final_p, final;
     201                 :            :         struct dst_entry *dst;
     202                 :            : 
     203                 :          0 :         memset(fl6, 0, sizeof(*fl6));
     204                 :          0 :         fl6->flowi6_proto = sk->sk_protocol;
     205                 :          0 :         fl6->daddr = sk->sk_v6_daddr;
     206                 :          0 :         fl6->saddr = np->saddr;
     207                 :          0 :         fl6->flowlabel = np->flow_label;
     208         [ #  # ]:          0 :         IP6_ECN_flow_xmit(sk, fl6->flowlabel);
     209                 :          0 :         fl6->flowi6_oif = sk->sk_bound_dev_if;
     210                 :          0 :         fl6->flowi6_mark = sk->sk_mark;
     211                 :          0 :         fl6->fl6_sport = inet->inet_sport;
     212                 :          0 :         fl6->fl6_dport = inet->inet_dport;
     213                 :          0 :         security_sk_classify_flow(sk, flowi6_to_flowi(fl6));
     214                 :            : 
     215                 :          0 :         final_p = fl6_update_dst(fl6, np->opt, &final);
     216                 :            : 
     217                 :          0 :         dst = __inet6_csk_dst_check(sk, np->dst_cookie);
     218         [ #  # ]:          0 :         if (!dst) {
     219                 :          0 :                 dst = ip6_dst_lookup_flow(sk, fl6, final_p, false);
     220                 :            : 
     221         [ #  # ]:          0 :                 if (!IS_ERR(dst))
     222                 :            :                         __inet6_csk_dst_store(sk, dst, NULL, NULL);
     223                 :            :         }
     224                 :          0 :         return dst;
     225                 :            : }
     226                 :            : 
     227                 :          0 : int inet6_csk_xmit(struct sk_buff *skb, struct flowi *fl_unused)
     228                 :            : {
     229                 :          0 :         struct sock *sk = skb->sk;
     230                 :            :         struct ipv6_pinfo *np = inet6_sk(sk);
     231                 :            :         struct flowi6 fl6;
     232                 :            :         struct dst_entry *dst;
     233                 :            :         int res;
     234                 :            : 
     235                 :          0 :         dst = inet6_csk_route_socket(sk, &fl6);
     236         [ #  # ]:          0 :         if (IS_ERR(dst)) {
     237                 :          0 :                 sk->sk_err_soft = -PTR_ERR(dst);
     238                 :          0 :                 sk->sk_route_caps = 0;
     239                 :          0 :                 kfree_skb(skb);
     240                 :          0 :                 return PTR_ERR(dst);
     241                 :            :         }
     242                 :            : 
     243                 :            :         rcu_read_lock();
     244                 :            :         skb_dst_set_noref(skb, dst);
     245                 :            : 
     246                 :            :         /* Restore final destination back after routing done */
     247                 :          0 :         fl6.daddr = sk->sk_v6_daddr;
     248                 :            : 
     249                 :          0 :         res = ip6_xmit(sk, skb, &fl6, np->opt, np->tclass);
     250                 :            :         rcu_read_unlock();
     251                 :          0 :         return res;
     252                 :            : }
     253                 :            : EXPORT_SYMBOL_GPL(inet6_csk_xmit);
     254                 :            : 
     255                 :          0 : struct dst_entry *inet6_csk_update_pmtu(struct sock *sk, u32 mtu)
     256                 :            : {
     257                 :            :         struct flowi6 fl6;
     258                 :          0 :         struct dst_entry *dst = inet6_csk_route_socket(sk, &fl6);
     259                 :            : 
     260         [ #  # ]:          0 :         if (IS_ERR(dst))
     261                 :            :                 return NULL;
     262                 :          0 :         dst->ops->update_pmtu(dst, sk, NULL, mtu);
     263                 :            : 
     264                 :          0 :         dst = inet6_csk_route_socket(sk, &fl6);
     265         [ #  # ]:          0 :         return IS_ERR(dst) ? NULL : dst;
     266                 :            : }
     267                 :            : EXPORT_SYMBOL_GPL(inet6_csk_update_pmtu);

Generated by: LCOV version 1.9