linux/net/caif/chnl_net.c
<<
>>
Prefs
   1/*
   2 * Copyright (C) ST-Ericsson AB 2010
   3 * Authors:     Sjur Brendeland/sjur.brandeland@stericsson.com
   4 *              Daniel Martensson / Daniel.Martensson@stericsson.com
   5 * License terms: GNU General Public License (GPL) version 2
   6 */
   7
   8#include <linux/version.h>
   9#include <linux/fs.h>
  10#include <linux/init.h>
  11#include <linux/module.h>
  12#include <linux/netdevice.h>
  13#include <linux/if_ether.h>
  14#include <linux/moduleparam.h>
  15#include <linux/ip.h>
  16#include <linux/sched.h>
  17#include <linux/sockios.h>
  18#include <linux/caif/if_caif.h>
  19#include <net/rtnetlink.h>
  20#include <net/caif/caif_layer.h>
  21#include <net/caif/cfcnfg.h>
  22#include <net/caif/cfpkt.h>
  23#include <net/caif/caif_dev.h>
  24
  25/* GPRS PDP connection has MTU to 1500 */
  26#define SIZE_MTU 1500
  27/* 5 sec. connect timeout */
  28#define CONNECT_TIMEOUT (5 * HZ)
  29#define CAIF_NET_DEFAULT_QUEUE_LEN 500
  30
  31#undef pr_debug
  32#define pr_debug pr_warning
  33
  34/*This list is protected by the rtnl lock. */
  35static LIST_HEAD(chnl_net_list);
  36
  37MODULE_LICENSE("GPL");
  38MODULE_ALIAS_RTNL_LINK("caif");
  39
  40enum caif_states {
  41        CAIF_CONNECTED          = 1,
  42        CAIF_CONNECTING,
  43        CAIF_DISCONNECTED,
  44        CAIF_SHUTDOWN
  45};
  46
  47struct chnl_net {
  48        struct cflayer chnl;
  49        struct net_device_stats stats;
  50        struct caif_connect_request conn_req;
  51        struct list_head list_field;
  52        struct net_device *netdev;
  53        char name[256];
  54        wait_queue_head_t netmgmt_wq;
  55        /* Flow status to remember and control the transmission. */
  56        bool flowenabled;
  57        enum caif_states state;
  58};
  59
  60static void robust_list_del(struct list_head *delete_node)
  61{
  62        struct list_head *list_node;
  63        struct list_head *n;
  64        ASSERT_RTNL();
  65        list_for_each_safe(list_node, n, &chnl_net_list) {
  66                if (list_node == delete_node) {
  67                        list_del(list_node);
  68                        return;
  69                }
  70        }
  71        WARN_ON(1);
  72}
  73
  74static int chnl_recv_cb(struct cflayer *layr, struct cfpkt *pkt)
  75{
  76        struct sk_buff *skb;
  77        struct chnl_net *priv  = container_of(layr, struct chnl_net, chnl);
  78        int pktlen;
  79        int err = 0;
  80
  81        priv = container_of(layr, struct chnl_net, chnl);
  82
  83        if (!priv)
  84                return -EINVAL;
  85
  86        /* Get length of CAIF packet. */
  87        pktlen = cfpkt_getlen(pkt);
  88
  89        skb = (struct sk_buff *) cfpkt_tonative(pkt);
  90        /* Pass some minimum information and
  91         * send the packet to the net stack.
  92         */
  93        skb->dev = priv->netdev;
  94        skb->protocol = htons(ETH_P_IP);
  95
  96        /* If we change the header in loop mode, the checksum is corrupted. */
  97        if (priv->conn_req.protocol == CAIFPROTO_DATAGRAM_LOOP)
  98                skb->ip_summed = CHECKSUM_UNNECESSARY;
  99        else
 100                skb->ip_summed = CHECKSUM_NONE;
 101
 102        if (in_interrupt())
 103                netif_rx(skb);
 104        else
 105                netif_rx_ni(skb);
 106
 107        /* Update statistics. */
 108        priv->netdev->stats.rx_packets++;
 109        priv->netdev->stats.rx_bytes += pktlen;
 110
 111        return err;
 112}
 113
 114static int delete_device(struct chnl_net *dev)
 115{
 116        ASSERT_RTNL();
 117        if (dev->netdev)
 118                unregister_netdevice(dev->netdev);
 119        return 0;
 120}
 121
 122static void close_work(struct work_struct *work)
 123{
 124        struct chnl_net *dev = NULL;
 125        struct list_head *list_node;
 126        struct list_head *_tmp;
 127        /* May be called with or without RTNL lock held */
 128        int islocked = rtnl_is_locked();
 129        if (!islocked)
 130                rtnl_lock();
 131        list_for_each_safe(list_node, _tmp, &chnl_net_list) {
 132                dev = list_entry(list_node, struct chnl_net, list_field);
 133                if (dev->state == CAIF_SHUTDOWN)
 134                        dev_close(dev->netdev);
 135        }
 136        if (!islocked)
 137                rtnl_unlock();
 138}
 139static DECLARE_WORK(close_worker, close_work);
 140
 141static void chnl_flowctrl_cb(struct cflayer *layr, enum caif_ctrlcmd flow,
 142                                int phyid)
 143{
 144        struct chnl_net *priv = container_of(layr, struct chnl_net, chnl);
 145        pr_debug("CAIF: %s(): NET flowctrl func called flow: %s\n",
 146                __func__,
 147                flow == CAIF_CTRLCMD_FLOW_ON_IND ? "ON" :
 148                flow == CAIF_CTRLCMD_INIT_RSP ? "INIT" :
 149                flow == CAIF_CTRLCMD_FLOW_OFF_IND ? "OFF" :
 150                flow == CAIF_CTRLCMD_DEINIT_RSP ? "CLOSE/DEINIT" :
 151                flow == CAIF_CTRLCMD_INIT_FAIL_RSP ? "OPEN_FAIL" :
 152                flow == CAIF_CTRLCMD_REMOTE_SHUTDOWN_IND ?
 153                 "REMOTE_SHUTDOWN" : "UKNOWN CTRL COMMAND");
 154
 155
 156
 157        switch (flow) {
 158        case CAIF_CTRLCMD_FLOW_OFF_IND:
 159                priv->flowenabled = false;
 160                netif_stop_queue(priv->netdev);
 161                break;
 162        case CAIF_CTRLCMD_DEINIT_RSP:
 163                priv->state = CAIF_DISCONNECTED;
 164                break;
 165        case CAIF_CTRLCMD_INIT_FAIL_RSP:
 166                priv->state = CAIF_DISCONNECTED;
 167                wake_up_interruptible(&priv->netmgmt_wq);
 168                break;
 169        case CAIF_CTRLCMD_REMOTE_SHUTDOWN_IND:
 170                priv->state = CAIF_SHUTDOWN;
 171                netif_tx_disable(priv->netdev);
 172                schedule_work(&close_worker);
 173                break;
 174        case CAIF_CTRLCMD_FLOW_ON_IND:
 175                priv->flowenabled = true;
 176                netif_wake_queue(priv->netdev);
 177                break;
 178        case CAIF_CTRLCMD_INIT_RSP:
 179                priv->state = CAIF_CONNECTED;
 180                priv->flowenabled = true;
 181                netif_wake_queue(priv->netdev);
 182                wake_up_interruptible(&priv->netmgmt_wq);
 183                break;
 184        default:
 185                break;
 186        }
 187}
 188
 189static int chnl_net_start_xmit(struct sk_buff *skb, struct net_device *dev)
 190{
 191        struct chnl_net *priv;
 192        struct cfpkt *pkt = NULL;
 193        int len;
 194        int result = -1;
 195        /* Get our private data. */
 196        priv = netdev_priv(dev);
 197
 198        if (skb->len > priv->netdev->mtu) {
 199                pr_warning("CAIF: %s(): Size of skb exceeded MTU\n", __func__);
 200                return -ENOSPC;
 201        }
 202
 203        if (!priv->flowenabled) {
 204                pr_debug("CAIF: %s(): dropping packets flow off\n", __func__);
 205                return NETDEV_TX_BUSY;
 206        }
 207
 208        if (priv->conn_req.protocol == CAIFPROTO_DATAGRAM_LOOP)
 209                swap(ip_hdr(skb)->saddr, ip_hdr(skb)->daddr);
 210
 211        /* Store original SKB length. */
 212        len = skb->len;
 213
 214        pkt = cfpkt_fromnative(CAIF_DIR_OUT, (void *) skb);
 215
 216        /* Send the packet down the stack. */
 217        result = priv->chnl.dn->transmit(priv->chnl.dn, pkt);
 218        if (result) {
 219                if (result == -EAGAIN)
 220                        result = NETDEV_TX_BUSY;
 221                return result;
 222        }
 223
 224        /* Update statistics. */
 225        dev->stats.tx_packets++;
 226        dev->stats.tx_bytes += len;
 227
 228        return NETDEV_TX_OK;
 229}
 230
 231static int chnl_net_open(struct net_device *dev)
 232{
 233        struct chnl_net *priv = NULL;
 234        int result = -1;
 235        ASSERT_RTNL();
 236        priv = netdev_priv(dev);
 237        if (!priv) {
 238                pr_debug("CAIF: %s(): chnl_net_open: no priv\n", __func__);
 239                return -ENODEV;
 240        }
 241
 242        if (priv->state != CAIF_CONNECTING) {
 243                priv->state = CAIF_CONNECTING;
 244                result = caif_connect_client(&priv->conn_req, &priv->chnl);
 245                if (result != 0) {
 246                                priv->state = CAIF_DISCONNECTED;
 247                                pr_debug("CAIF: %s(): err: "
 248                                        "Unable to register and open device,"
 249                                        " Err:%d\n",
 250                                        __func__,
 251                                        result);
 252                                return result;
 253                }
 254        }
 255
 256        result = wait_event_interruptible_timeout(priv->netmgmt_wq,
 257                                                priv->state != CAIF_CONNECTING,
 258                                                CONNECT_TIMEOUT);
 259
 260        if (result == -ERESTARTSYS) {
 261                pr_debug("CAIF: %s(): wait_event_interruptible"
 262                         " woken by a signal\n", __func__);
 263                return -ERESTARTSYS;
 264        }
 265        if (result == 0) {
 266                pr_debug("CAIF: %s(): connect timeout\n", __func__);
 267                caif_disconnect_client(&priv->chnl);
 268                priv->state = CAIF_DISCONNECTED;
 269                pr_debug("CAIF: %s(): state disconnected\n", __func__);
 270                return -ETIMEDOUT;
 271        }
 272
 273        if (priv->state != CAIF_CONNECTED) {
 274                pr_debug("CAIF: %s(): connect failed\n", __func__);
 275                return -ECONNREFUSED;
 276        }
 277        pr_debug("CAIF: %s(): CAIF Netdevice connected\n", __func__);
 278        return 0;
 279}
 280
 281static int chnl_net_stop(struct net_device *dev)
 282{
 283        struct chnl_net *priv;
 284
 285        ASSERT_RTNL();
 286        priv = netdev_priv(dev);
 287        priv->state = CAIF_DISCONNECTED;
 288        caif_disconnect_client(&priv->chnl);
 289        return 0;
 290}
 291
 292static int chnl_net_init(struct net_device *dev)
 293{
 294        struct chnl_net *priv;
 295        ASSERT_RTNL();
 296        priv = netdev_priv(dev);
 297        strncpy(priv->name, dev->name, sizeof(priv->name));
 298        return 0;
 299}
 300
 301static void chnl_net_uninit(struct net_device *dev)
 302{
 303        struct chnl_net *priv;
 304        ASSERT_RTNL();
 305        priv = netdev_priv(dev);
 306        robust_list_del(&priv->list_field);
 307}
 308
 309static const struct net_device_ops netdev_ops = {
 310        .ndo_open = chnl_net_open,
 311        .ndo_stop = chnl_net_stop,
 312        .ndo_init = chnl_net_init,
 313        .ndo_uninit = chnl_net_uninit,
 314        .ndo_start_xmit = chnl_net_start_xmit,
 315};
 316
 317static void ipcaif_net_setup(struct net_device *dev)
 318{
 319        struct chnl_net *priv;
 320        dev->netdev_ops = &netdev_ops;
 321        dev->destructor = free_netdev;
 322        dev->flags |= IFF_NOARP;
 323        dev->flags |= IFF_POINTOPOINT;
 324        dev->needed_headroom = CAIF_NEEDED_HEADROOM;
 325        dev->needed_tailroom = CAIF_NEEDED_TAILROOM;
 326        dev->mtu = SIZE_MTU;
 327        dev->tx_queue_len = CAIF_NET_DEFAULT_QUEUE_LEN;
 328
 329        priv = netdev_priv(dev);
 330        priv->chnl.receive = chnl_recv_cb;
 331        priv->chnl.ctrlcmd = chnl_flowctrl_cb;
 332        priv->netdev = dev;
 333        priv->conn_req.protocol = CAIFPROTO_DATAGRAM;
 334        priv->conn_req.link_selector = CAIF_LINK_HIGH_BANDW;
 335        priv->conn_req.priority = CAIF_PRIO_LOW;
 336        /* Insert illegal value */
 337        priv->conn_req.sockaddr.u.dgm.connection_id = -1;
 338        priv->flowenabled = false;
 339
 340        ASSERT_RTNL();
 341        init_waitqueue_head(&priv->netmgmt_wq);
 342        list_add(&priv->list_field, &chnl_net_list);
 343}
 344
 345
 346static int ipcaif_fill_info(struct sk_buff *skb, const struct net_device *dev)
 347{
 348        struct chnl_net *priv;
 349        u8 loop;
 350        priv = netdev_priv(dev);
 351        NLA_PUT_U32(skb, IFLA_CAIF_IPV4_CONNID,
 352                    priv->conn_req.sockaddr.u.dgm.connection_id);
 353        NLA_PUT_U32(skb, IFLA_CAIF_IPV6_CONNID,
 354                    priv->conn_req.sockaddr.u.dgm.connection_id);
 355        loop = priv->conn_req.protocol == CAIFPROTO_DATAGRAM_LOOP;
 356        NLA_PUT_U8(skb, IFLA_CAIF_LOOPBACK, loop);
 357
 358
 359        return 0;
 360nla_put_failure:
 361        return -EMSGSIZE;
 362
 363}
 364
 365static void caif_netlink_parms(struct nlattr *data[],
 366                                struct caif_connect_request *conn_req)
 367{
 368        if (!data) {
 369                pr_warning("CAIF: %s: no params data found\n", __func__);
 370                return;
 371        }
 372        if (data[IFLA_CAIF_IPV4_CONNID])
 373                conn_req->sockaddr.u.dgm.connection_id =
 374                        nla_get_u32(data[IFLA_CAIF_IPV4_CONNID]);
 375        if (data[IFLA_CAIF_IPV6_CONNID])
 376                conn_req->sockaddr.u.dgm.connection_id =
 377                        nla_get_u32(data[IFLA_CAIF_IPV6_CONNID]);
 378        if (data[IFLA_CAIF_LOOPBACK]) {
 379                if (nla_get_u8(data[IFLA_CAIF_LOOPBACK]))
 380                        conn_req->protocol = CAIFPROTO_DATAGRAM_LOOP;
 381                else
 382                        conn_req->protocol = CAIFPROTO_DATAGRAM;
 383        }
 384}
 385
 386static int ipcaif_newlink(struct net *src_net, struct net_device *dev,
 387                          struct nlattr *tb[], struct nlattr *data[])
 388{
 389        int ret;
 390        struct chnl_net *caifdev;
 391        ASSERT_RTNL();
 392        caifdev = netdev_priv(dev);
 393        caif_netlink_parms(data, &caifdev->conn_req);
 394        dev_net_set(caifdev->netdev, src_net);
 395
 396        ret = register_netdevice(dev);
 397        if (ret)
 398                pr_warning("CAIF: %s(): device rtml registration failed\n",
 399                           __func__);
 400        return ret;
 401}
 402
 403static int ipcaif_changelink(struct net_device *dev, struct nlattr *tb[],
 404                                struct nlattr *data[])
 405{
 406        struct chnl_net *caifdev;
 407        ASSERT_RTNL();
 408        caifdev = netdev_priv(dev);
 409        caif_netlink_parms(data, &caifdev->conn_req);
 410        netdev_state_change(dev);
 411        return 0;
 412}
 413
 414static size_t ipcaif_get_size(const struct net_device *dev)
 415{
 416        return
 417                /* IFLA_CAIF_IPV4_CONNID */
 418                nla_total_size(4) +
 419                /* IFLA_CAIF_IPV6_CONNID */
 420                nla_total_size(4) +
 421                /* IFLA_CAIF_LOOPBACK */
 422                nla_total_size(2) +
 423                0;
 424}
 425
 426static const struct nla_policy ipcaif_policy[IFLA_CAIF_MAX + 1] = {
 427        [IFLA_CAIF_IPV4_CONNID]       = { .type = NLA_U32 },
 428        [IFLA_CAIF_IPV6_CONNID]       = { .type = NLA_U32 },
 429        [IFLA_CAIF_LOOPBACK]          = { .type = NLA_U8 }
 430};
 431
 432
 433static struct rtnl_link_ops ipcaif_link_ops __read_mostly = {
 434        .kind           = "caif",
 435        .priv_size      = sizeof(struct chnl_net),
 436        .setup          = ipcaif_net_setup,
 437        .maxtype        = IFLA_CAIF_MAX,
 438        .policy         = ipcaif_policy,
 439        .newlink        = ipcaif_newlink,
 440        .changelink     = ipcaif_changelink,
 441        .get_size       = ipcaif_get_size,
 442        .fill_info      = ipcaif_fill_info,
 443
 444};
 445
 446static int __init chnl_init_module(void)
 447{
 448        return rtnl_link_register(&ipcaif_link_ops);
 449}
 450
 451static void __exit chnl_exit_module(void)
 452{
 453        struct chnl_net *dev = NULL;
 454        struct list_head *list_node;
 455        struct list_head *_tmp;
 456        rtnl_link_unregister(&ipcaif_link_ops);
 457        rtnl_lock();
 458        list_for_each_safe(list_node, _tmp, &chnl_net_list) {
 459                dev = list_entry(list_node, struct chnl_net, list_field);
 460                list_del(list_node);
 461                delete_device(dev);
 462        }
 463        rtnl_unlock();
 464}
 465
 466module_init(chnl_init_module);
 467module_exit(chnl_exit_module);
 468