linux/net/tipc/udp_media.c
<<
>>
Prefs
   1/* net/tipc/udp_media.c: IP bearer support for TIPC
   2 *
   3 * Copyright (c) 2015, Ericsson AB
   4 * All rights reserved.
   5 *
   6 * Redistribution and use in source and binary forms, with or without
   7 * modification, are permitted provided that the following conditions are met:
   8 *
   9 * 1. Redistributions of source code must retain the above copyright
  10 *    notice, this list of conditions and the following disclaimer.
  11 * 2. Redistributions in binary form must reproduce the above copyright
  12 *    notice, this list of conditions and the following disclaimer in the
  13 *    documentation and/or other materials provided with the distribution.
  14 * 3. Neither the names of the copyright holders nor the names of its
  15 *    contributors may be used to endorse or promote products derived from
  16 *    this software without specific prior written permission.
  17 *
  18 * Alternatively, this software may be distributed under the terms of the
  19 * GNU General Public License ("GPL") version 2 as published by the Free
  20 * Software Foundation.
  21 *
  22 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  23 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  25 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
  26 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  27 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
  28 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  29 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
  30 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  31 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  32 * POSSIBILITY OF SUCH DAMAGE.
  33 */
  34
  35#include <linux/socket.h>
  36#include <linux/ip.h>
  37#include <linux/udp.h>
  38#include <linux/inet.h>
  39#include <linux/inetdevice.h>
  40#include <linux/igmp.h>
  41#include <linux/kernel.h>
  42#include <linux/workqueue.h>
  43#include <linux/list.h>
  44#include <net/sock.h>
  45#include <net/ip.h>
  46#include <net/udp_tunnel.h>
  47#include <net/addrconf.h>
  48#include <linux/tipc_netlink.h>
  49#include "core.h"
  50#include "bearer.h"
  51#include "netlink.h"
  52
  53/* IANA assigned UDP port */
  54#define UDP_PORT_DEFAULT        6118
  55
  56#define UDP_MIN_HEADROOM        48
  57
  58/**
  59 * struct udp_media_addr - IP/UDP addressing information
  60 *
  61 * This is the bearer level originating address used in neighbor discovery
  62 * messages, and all fields should be in network byte order
  63 */
  64struct udp_media_addr {
  65        __be16  proto;
  66        __be16  port;
  67        union {
  68                struct in_addr ipv4;
  69                struct in6_addr ipv6;
  70        };
  71};
  72
  73/**
  74 * struct udp_bearer - ip/udp bearer data structure
  75 * @bearer:     associated generic tipc bearer
  76 * @ubsock:     bearer associated socket
  77 * @ifindex:    local address scope
  78 * @work:       used to schedule deferred work on a bearer
  79 */
  80struct udp_bearer {
  81        struct tipc_bearer __rcu *bearer;
  82        struct socket *ubsock;
  83        u32 ifindex;
  84        struct work_struct work;
  85};
  86
  87/* udp_media_addr_set - convert a ip/udp address to a TIPC media address */
  88static void tipc_udp_media_addr_set(struct tipc_media_addr *addr,
  89                                    struct udp_media_addr *ua)
  90{
  91        memset(addr, 0, sizeof(struct tipc_media_addr));
  92        addr->media_id = TIPC_MEDIA_TYPE_UDP;
  93        memcpy(addr->value, ua, sizeof(struct udp_media_addr));
  94        if (ntohs(ua->proto) == ETH_P_IP) {
  95                if (ipv4_is_multicast(ua->ipv4.s_addr))
  96                        addr->broadcast = 1;
  97        } else if (ntohs(ua->proto) == ETH_P_IPV6) {
  98                if (ipv6_addr_type(&ua->ipv6) & IPV6_ADDR_MULTICAST)
  99                        addr->broadcast = 1;
 100        } else {
 101                pr_err("Invalid UDP media address\n");
 102        }
 103}
 104
 105/* tipc_udp_addr2str - convert ip/udp address to string */
 106static int tipc_udp_addr2str(struct tipc_media_addr *a, char *buf, int size)
 107{
 108        struct udp_media_addr *ua = (struct udp_media_addr *)&a->value;
 109
 110        if (ntohs(ua->proto) == ETH_P_IP)
 111                snprintf(buf, size, "%pI4:%u", &ua->ipv4, ntohs(ua->port));
 112        else if (ntohs(ua->proto) == ETH_P_IPV6)
 113                snprintf(buf, size, "%pI6:%u", &ua->ipv6, ntohs(ua->port));
 114        else
 115                pr_err("Invalid UDP media address\n");
 116        return 0;
 117}
 118
 119/* tipc_udp_msg2addr - extract an ip/udp address from a TIPC ndisc message */
 120static int tipc_udp_msg2addr(struct tipc_bearer *b, struct tipc_media_addr *a,
 121                             char *msg)
 122{
 123        struct udp_media_addr *ua;
 124
 125        ua = (struct udp_media_addr *) (msg + TIPC_MEDIA_ADDR_OFFSET);
 126        if (msg[TIPC_MEDIA_TYPE_OFFSET] != TIPC_MEDIA_TYPE_UDP)
 127                return -EINVAL;
 128        tipc_udp_media_addr_set(a, ua);
 129        return 0;
 130}
 131
 132/* tipc_udp_addr2msg - write an ip/udp address to a TIPC ndisc message */
 133static int tipc_udp_addr2msg(char *msg, struct tipc_media_addr *a)
 134{
 135        memset(msg, 0, TIPC_MEDIA_INFO_SIZE);
 136        msg[TIPC_MEDIA_TYPE_OFFSET] = TIPC_MEDIA_TYPE_UDP;
 137        memcpy(msg + TIPC_MEDIA_ADDR_OFFSET, a->value,
 138               sizeof(struct udp_media_addr));
 139        return 0;
 140}
 141
 142/* tipc_send_msg - enqueue a send request */
 143static int tipc_udp_send_msg(struct net *net, struct sk_buff *skb,
 144                             struct tipc_bearer *b,
 145                             struct tipc_media_addr *dest)
 146{
 147        int ttl, err = 0;
 148        struct udp_bearer *ub;
 149        struct udp_media_addr *dst = (struct udp_media_addr *)&dest->value;
 150        struct udp_media_addr *src = (struct udp_media_addr *)&b->addr.value;
 151        struct rtable *rt;
 152
 153        if (skb_headroom(skb) < UDP_MIN_HEADROOM) {
 154                err = pskb_expand_head(skb, UDP_MIN_HEADROOM, 0, GFP_ATOMIC);
 155                if (err)
 156                        goto tx_error;
 157        }
 158
 159        skb_set_inner_protocol(skb, htons(ETH_P_TIPC));
 160        ub = rcu_dereference_rtnl(b->media_ptr);
 161        if (!ub) {
 162                err = -ENODEV;
 163                goto tx_error;
 164        }
 165        if (dst->proto == htons(ETH_P_IP)) {
 166                struct flowi4 fl = {
 167                        .daddr = dst->ipv4.s_addr,
 168                        .saddr = src->ipv4.s_addr,
 169                        .flowi4_mark = skb->mark,
 170                        .flowi4_proto = IPPROTO_UDP
 171                };
 172                rt = ip_route_output_key(net, &fl);
 173                if (IS_ERR(rt)) {
 174                        err = PTR_ERR(rt);
 175                        goto tx_error;
 176                }
 177
 178                skb->dev = rt->dst.dev;
 179                ttl = ip4_dst_hoplimit(&rt->dst);
 180                udp_tunnel_xmit_skb(rt, ub->ubsock->sk, skb, src->ipv4.s_addr,
 181                                    dst->ipv4.s_addr, 0, ttl, 0, src->port,
 182                                    dst->port, false, true);
 183#if IS_ENABLED(CONFIG_IPV6)
 184        } else {
 185                struct dst_entry *ndst;
 186                struct flowi6 fl6 = {
 187                        .flowi6_oif = ub->ifindex,
 188                        .daddr = dst->ipv6,
 189                        .saddr = src->ipv6,
 190                        .flowi6_proto = IPPROTO_UDP
 191                };
 192                err = ipv6_stub->ipv6_dst_lookup(net, ub->ubsock->sk, &ndst,
 193                                                 &fl6);
 194                if (err)
 195                        goto tx_error;
 196                ttl = ip6_dst_hoplimit(ndst);
 197                err = udp_tunnel6_xmit_skb(ndst, ub->ubsock->sk, skb,
 198                                           ndst->dev, &src->ipv6,
 199                                           &dst->ipv6, 0, ttl, 0, src->port,
 200                                           dst->port, false);
 201#endif
 202        }
 203        return err;
 204
 205tx_error:
 206        kfree_skb(skb);
 207        return err;
 208}
 209
 210/* tipc_udp_recv - read data from bearer socket */
 211static int tipc_udp_recv(struct sock *sk, struct sk_buff *skb)
 212{
 213        struct udp_bearer *ub;
 214        struct tipc_bearer *b;
 215
 216        ub = rcu_dereference_sk_user_data(sk);
 217        if (!ub) {
 218                pr_err_ratelimited("Failed to get UDP bearer reference");
 219                kfree_skb(skb);
 220                return 0;
 221        }
 222
 223        skb_pull(skb, sizeof(struct udphdr));
 224        rcu_read_lock();
 225        b = rcu_dereference_rtnl(ub->bearer);
 226
 227        if (b) {
 228                tipc_rcv(sock_net(sk), skb, b);
 229                rcu_read_unlock();
 230                return 0;
 231        }
 232        rcu_read_unlock();
 233        kfree_skb(skb);
 234        return 0;
 235}
 236
 237static int enable_mcast(struct udp_bearer *ub, struct udp_media_addr *remote)
 238{
 239        int err = 0;
 240        struct ip_mreqn mreqn;
 241        struct sock *sk = ub->ubsock->sk;
 242
 243        if (ntohs(remote->proto) == ETH_P_IP) {
 244                if (!ipv4_is_multicast(remote->ipv4.s_addr))
 245                        return 0;
 246                mreqn.imr_multiaddr = remote->ipv4;
 247                mreqn.imr_ifindex = ub->ifindex;
 248                err = ip_mc_join_group(sk, &mreqn);
 249#if IS_ENABLED(CONFIG_IPV6)
 250        } else {
 251                if (!ipv6_addr_is_multicast(&remote->ipv6))
 252                        return 0;
 253                err = ipv6_stub->ipv6_sock_mc_join(sk, ub->ifindex,
 254                                                   &remote->ipv6);
 255#endif
 256        }
 257        return err;
 258}
 259
 260/**
 261 * parse_options - build local/remote addresses from configuration
 262 * @attrs:      netlink config data
 263 * @ub:         UDP bearer instance
 264 * @local:      local bearer IP address/port
 265 * @remote:     peer or multicast IP/port
 266 */
 267static int parse_options(struct nlattr *attrs[], struct udp_bearer *ub,
 268                         struct udp_media_addr *local,
 269                         struct udp_media_addr *remote)
 270{
 271        struct nlattr *opts[TIPC_NLA_UDP_MAX + 1];
 272        struct sockaddr_storage sa_local, sa_remote;
 273
 274        if (!attrs[TIPC_NLA_BEARER_UDP_OPTS])
 275                goto err;
 276        if (nla_parse_nested(opts, TIPC_NLA_UDP_MAX,
 277                             attrs[TIPC_NLA_BEARER_UDP_OPTS],
 278                             tipc_nl_udp_policy))
 279                goto err;
 280        if (opts[TIPC_NLA_UDP_LOCAL] && opts[TIPC_NLA_UDP_REMOTE]) {
 281                nla_memcpy(&sa_local, opts[TIPC_NLA_UDP_LOCAL],
 282                           sizeof(sa_local));
 283                nla_memcpy(&sa_remote, opts[TIPC_NLA_UDP_REMOTE],
 284                           sizeof(sa_remote));
 285        } else {
 286err:
 287                pr_err("Invalid UDP bearer configuration");
 288                return -EINVAL;
 289        }
 290        if ((sa_local.ss_family & sa_remote.ss_family) == AF_INET) {
 291                struct sockaddr_in *ip4;
 292
 293                ip4 = (struct sockaddr_in *)&sa_local;
 294                local->proto = htons(ETH_P_IP);
 295                local->port = ip4->sin_port;
 296                local->ipv4.s_addr = ip4->sin_addr.s_addr;
 297
 298                ip4 = (struct sockaddr_in *)&sa_remote;
 299                remote->proto = htons(ETH_P_IP);
 300                remote->port = ip4->sin_port;
 301                remote->ipv4.s_addr = ip4->sin_addr.s_addr;
 302                return 0;
 303
 304#if IS_ENABLED(CONFIG_IPV6)
 305        } else if ((sa_local.ss_family & sa_remote.ss_family) == AF_INET6) {
 306                int atype;
 307                struct sockaddr_in6 *ip6;
 308
 309                ip6 = (struct sockaddr_in6 *)&sa_local;
 310                atype = ipv6_addr_type(&ip6->sin6_addr);
 311                if (__ipv6_addr_needs_scope_id(atype) && !ip6->sin6_scope_id)
 312                        return -EINVAL;
 313
 314                local->proto = htons(ETH_P_IPV6);
 315                local->port = ip6->sin6_port;
 316                memcpy(&local->ipv6, &ip6->sin6_addr, sizeof(struct in6_addr));
 317                ub->ifindex = ip6->sin6_scope_id;
 318
 319                ip6 = (struct sockaddr_in6 *)&sa_remote;
 320                remote->proto = htons(ETH_P_IPV6);
 321                remote->port = ip6->sin6_port;
 322                memcpy(&remote->ipv6, &ip6->sin6_addr, sizeof(struct in6_addr));
 323                return 0;
 324#endif
 325        }
 326        return -EADDRNOTAVAIL;
 327}
 328
 329/**
 330 * tipc_udp_enable - callback to create a new udp bearer instance
 331 * @net:        network namespace
 332 * @b:          pointer to generic tipc_bearer
 333 * @attrs:      netlink bearer configuration
 334 *
 335 * validate the bearer parameters and initialize the udp bearer
 336 * rtnl_lock should be held
 337 */
 338static int tipc_udp_enable(struct net *net, struct tipc_bearer *b,
 339                           struct nlattr *attrs[])
 340{
 341        int err = -EINVAL;
 342        struct udp_bearer *ub;
 343        struct udp_media_addr *remote;
 344        struct udp_media_addr local = {0};
 345        struct udp_port_cfg udp_conf = {0};
 346        struct udp_tunnel_sock_cfg tuncfg = {NULL};
 347
 348        ub = kzalloc(sizeof(*ub), GFP_ATOMIC);
 349        if (!ub)
 350                return -ENOMEM;
 351
 352        remote = (struct udp_media_addr *)&b->bcast_addr.value;
 353        memset(remote, 0, sizeof(struct udp_media_addr));
 354        err = parse_options(attrs, ub, &local, remote);
 355        if (err)
 356                goto err;
 357
 358        b->bcast_addr.media_id = TIPC_MEDIA_TYPE_UDP;
 359        b->bcast_addr.broadcast = 1;
 360        rcu_assign_pointer(b->media_ptr, ub);
 361        rcu_assign_pointer(ub->bearer, b);
 362        tipc_udp_media_addr_set(&b->addr, &local);
 363        if (local.proto == htons(ETH_P_IP)) {
 364                struct net_device *dev;
 365
 366                dev = __ip_dev_find(net, local.ipv4.s_addr, false);
 367                if (!dev) {
 368                        err = -ENODEV;
 369                        goto err;
 370                }
 371                udp_conf.family = AF_INET;
 372                udp_conf.local_ip.s_addr = htonl(INADDR_ANY);
 373                udp_conf.use_udp_checksums = false;
 374                ub->ifindex = dev->ifindex;
 375                b->mtu = dev->mtu - sizeof(struct iphdr)
 376                        - sizeof(struct udphdr);
 377#if IS_ENABLED(CONFIG_IPV6)
 378        } else if (local.proto == htons(ETH_P_IPV6)) {
 379                udp_conf.family = AF_INET6;
 380                udp_conf.use_udp6_tx_checksums = true;
 381                udp_conf.use_udp6_rx_checksums = true;
 382                udp_conf.local_ip6 = in6addr_any;
 383                b->mtu = 1280;
 384#endif
 385        } else {
 386                err = -EAFNOSUPPORT;
 387                goto err;
 388        }
 389        udp_conf.local_udp_port = local.port;
 390        err = udp_sock_create(net, &udp_conf, &ub->ubsock);
 391        if (err)
 392                goto err;
 393        tuncfg.sk_user_data = ub;
 394        tuncfg.encap_type = 1;
 395        tuncfg.encap_rcv = tipc_udp_recv;
 396        tuncfg.encap_destroy = NULL;
 397        setup_udp_tunnel_sock(net, ub->ubsock, &tuncfg);
 398
 399        err = enable_mcast(ub, remote);
 400        if (err)
 401                goto err;
 402        return 0;
 403err:
 404        if (ub->ubsock)
 405                udp_tunnel_sock_release(ub->ubsock);
 406        kfree(ub);
 407        return err;
 408}
 409
 410/* cleanup_bearer - break the socket/bearer association */
 411static void cleanup_bearer(struct work_struct *work)
 412{
 413        struct udp_bearer *ub = container_of(work, struct udp_bearer, work);
 414
 415        if (ub->ubsock)
 416                udp_tunnel_sock_release(ub->ubsock);
 417        synchronize_net();
 418        kfree(ub);
 419}
 420
 421/* tipc_udp_disable - detach bearer from socket */
 422static void tipc_udp_disable(struct tipc_bearer *b)
 423{
 424        struct udp_bearer *ub;
 425
 426        ub = rcu_dereference_rtnl(b->media_ptr);
 427        if (!ub) {
 428                pr_err("UDP bearer instance not found\n");
 429                return;
 430        }
 431        if (ub->ubsock)
 432                sock_set_flag(ub->ubsock->sk, SOCK_DEAD);
 433        RCU_INIT_POINTER(ub->bearer, NULL);
 434
 435        /* sock_release need to be done outside of rtnl lock */
 436        INIT_WORK(&ub->work, cleanup_bearer);
 437        schedule_work(&ub->work);
 438}
 439
 440struct tipc_media udp_media_info = {
 441        .send_msg       = tipc_udp_send_msg,
 442        .enable_media   = tipc_udp_enable,
 443        .disable_media  = tipc_udp_disable,
 444        .addr2str       = tipc_udp_addr2str,
 445        .addr2msg       = tipc_udp_addr2msg,
 446        .msg2addr       = tipc_udp_msg2addr,
 447        .priority       = TIPC_DEF_LINK_PRI,
 448        .tolerance      = TIPC_DEF_LINK_TOL,
 449        .window         = TIPC_DEF_LINK_WIN,
 450        .type_id        = TIPC_MEDIA_TYPE_UDP,
 451        .hwaddr_len     = 0,
 452        .name           = "udp"
 453};
 454