linux/net/irda/irnetlink.c
<<
>>
Prefs
   1/*
   2 * IrDA netlink layer, for stack configuration.
   3 *
   4 * Copyright (c) 2007 Samuel Ortiz <samuel@sortiz.org>
   5 *
   6 * Partly based on the 802.11 nelink implementation
   7 * (see net/wireless/nl80211.c) which is:
   8 * Copyright 2006 Johannes Berg <johannes@sipsolutions.net>
   9 *
  10 * This program is free software; you can redistribute it and/or modify
  11 * it under the terms of the GNU General Public License version 2 as
  12 * published by the Free Software Foundation.
  13 *
  14 */
  15
  16#include <linux/socket.h>
  17#include <linux/irda.h>
  18#include <net/net_namespace.h>
  19#include <net/sock.h>
  20#include <net/irda/irda.h>
  21#include <net/irda/irlap.h>
  22#include <net/genetlink.h>
  23
  24
  25
  26static struct genl_family irda_nl_family = {
  27        .id = GENL_ID_GENERATE,
  28        .name = IRDA_NL_NAME,
  29        .hdrsize = 0,
  30        .version = IRDA_NL_VERSION,
  31        .maxattr = IRDA_NL_CMD_MAX,
  32};
  33
  34static struct net_device * ifname_to_netdev(struct net *net, struct genl_info *info)
  35{
  36        char * ifname;
  37
  38        if (!info->attrs[IRDA_NL_ATTR_IFNAME])
  39                return NULL;
  40
  41        ifname = nla_data(info->attrs[IRDA_NL_ATTR_IFNAME]);
  42
  43        IRDA_DEBUG(5, "%s(): Looking for %s\n", __func__, ifname);
  44
  45        return dev_get_by_name(net, ifname);
  46}
  47
  48static int irda_nl_set_mode(struct sk_buff *skb, struct genl_info *info)
  49{
  50        struct net_device * dev;
  51        struct irlap_cb * irlap;
  52        u32 mode;
  53
  54        if (!info->attrs[IRDA_NL_ATTR_MODE])
  55                return -EINVAL;
  56
  57        mode = nla_get_u32(info->attrs[IRDA_NL_ATTR_MODE]);
  58
  59        IRDA_DEBUG(5, "%s(): Switching to mode: %d\n", __func__, mode);
  60
  61        dev = ifname_to_netdev(&init_net, info);
  62        if (!dev)
  63                return -ENODEV;
  64
  65        irlap = (struct irlap_cb *)dev->atalk_ptr;
  66        if (!irlap) {
  67                dev_put(dev);
  68                return -ENODEV;
  69        }
  70
  71        irlap->mode = mode;
  72
  73        dev_put(dev);
  74
  75        return 0;
  76}
  77
  78static int irda_nl_get_mode(struct sk_buff *skb, struct genl_info *info)
  79{
  80        struct net_device * dev;
  81        struct irlap_cb * irlap;
  82        struct sk_buff *msg;
  83        void *hdr;
  84        int ret = -ENOBUFS;
  85
  86        dev = ifname_to_netdev(&init_net, info);
  87        if (!dev)
  88                return -ENODEV;
  89
  90        msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
  91        if (!msg) {
  92                dev_put(dev);
  93                return -ENOMEM;
  94        }
  95
  96        irlap = (struct irlap_cb *)dev->atalk_ptr;
  97        if (!irlap) {
  98                ret = -ENODEV;
  99                goto err_out;
 100        }
 101
 102        hdr = genlmsg_put(msg, info->snd_pid, info->snd_seq,
 103                          &irda_nl_family, 0,  IRDA_NL_CMD_GET_MODE);
 104        if (hdr == NULL) {
 105                ret = -EMSGSIZE;
 106                goto err_out;
 107        }
 108
 109        if(nla_put_string(msg, IRDA_NL_ATTR_IFNAME,
 110                          dev->name))
 111                goto err_out;
 112
 113        if(nla_put_u32(msg, IRDA_NL_ATTR_MODE, irlap->mode))
 114                goto err_out;
 115
 116        genlmsg_end(msg, hdr);
 117
 118        return genlmsg_reply(msg, info);
 119
 120 err_out:
 121        nlmsg_free(msg);
 122        dev_put(dev);
 123
 124        return ret;
 125}
 126
 127static struct nla_policy irda_nl_policy[IRDA_NL_ATTR_MAX + 1] = {
 128        [IRDA_NL_ATTR_IFNAME] = { .type = NLA_NUL_STRING,
 129                                  .len = IFNAMSIZ-1 },
 130        [IRDA_NL_ATTR_MODE] = { .type = NLA_U32 },
 131};
 132
 133static struct genl_ops irda_nl_ops[] = {
 134        {
 135                .cmd = IRDA_NL_CMD_SET_MODE,
 136                .doit = irda_nl_set_mode,
 137                .policy = irda_nl_policy,
 138                .flags = GENL_ADMIN_PERM,
 139        },
 140        {
 141                .cmd = IRDA_NL_CMD_GET_MODE,
 142                .doit = irda_nl_get_mode,
 143                .policy = irda_nl_policy,
 144                /* can be retrieved by unprivileged users */
 145        },
 146
 147};
 148
 149int irda_nl_register(void)
 150{
 151        return genl_register_family_with_ops(&irda_nl_family,
 152                irda_nl_ops, ARRAY_SIZE(irda_nl_ops));
 153}
 154
 155void irda_nl_unregister(void)
 156{
 157        genl_unregister_family(&irda_nl_family);
 158}
 159