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 <linux/gfp.h>
  19#include <net/net_namespace.h>
  20#include <net/sock.h>
  21#include <net/irda/irda.h>
  22#include <net/irda/irlap.h>
  23#include <net/genetlink.h>
  24
  25
  26
  27static struct genl_family irda_nl_family = {
  28        .id = GENL_ID_GENERATE,
  29        .name = IRDA_NL_NAME,
  30        .hdrsize = 0,
  31        .version = IRDA_NL_VERSION,
  32        .maxattr = IRDA_NL_CMD_MAX,
  33};
  34
  35static struct net_device * ifname_to_netdev(struct net *net, struct genl_info *info)
  36{
  37        char * ifname;
  38
  39        if (!info->attrs[IRDA_NL_ATTR_IFNAME])
  40                return NULL;
  41
  42        ifname = nla_data(info->attrs[IRDA_NL_ATTR_IFNAME]);
  43
  44        IRDA_DEBUG(5, "%s(): Looking for %s\n", __func__, ifname);
  45
  46        return dev_get_by_name(net, ifname);
  47}
  48
  49static int irda_nl_set_mode(struct sk_buff *skb, struct genl_info *info)
  50{
  51        struct net_device * dev;
  52        struct irlap_cb * irlap;
  53        u32 mode;
  54
  55        if (!info->attrs[IRDA_NL_ATTR_MODE])
  56                return -EINVAL;
  57
  58        mode = nla_get_u32(info->attrs[IRDA_NL_ATTR_MODE]);
  59
  60        IRDA_DEBUG(5, "%s(): Switching to mode: %d\n", __func__, mode);
  61
  62        dev = ifname_to_netdev(&init_net, info);
  63        if (!dev)
  64                return -ENODEV;
  65
  66        irlap = (struct irlap_cb *)dev->atalk_ptr;
  67        if (!irlap) {
  68                dev_put(dev);
  69                return -ENODEV;
  70        }
  71
  72        irlap->mode = mode;
  73
  74        dev_put(dev);
  75
  76        return 0;
  77}
  78
  79static int irda_nl_get_mode(struct sk_buff *skb, struct genl_info *info)
  80{
  81        struct net_device * dev;
  82        struct irlap_cb * irlap;
  83        struct sk_buff *msg;
  84        void *hdr;
  85        int ret = -ENOBUFS;
  86
  87        dev = ifname_to_netdev(&init_net, info);
  88        if (!dev)
  89                return -ENODEV;
  90
  91        msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
  92        if (!msg) {
  93                dev_put(dev);
  94                return -ENOMEM;
  95        }
  96
  97        irlap = (struct irlap_cb *)dev->atalk_ptr;
  98        if (!irlap) {
  99                ret = -ENODEV;
 100                goto err_out;
 101        }
 102
 103        hdr = genlmsg_put(msg, info->snd_portid, info->snd_seq,
 104                          &irda_nl_family, 0,  IRDA_NL_CMD_GET_MODE);
 105        if (hdr == NULL) {
 106                ret = -EMSGSIZE;
 107                goto err_out;
 108        }
 109
 110        if(nla_put_string(msg, IRDA_NL_ATTR_IFNAME,
 111                          dev->name))
 112                goto err_out;
 113
 114        if(nla_put_u32(msg, IRDA_NL_ATTR_MODE, irlap->mode))
 115                goto err_out;
 116
 117        genlmsg_end(msg, hdr);
 118
 119        return genlmsg_reply(msg, info);
 120
 121 err_out:
 122        nlmsg_free(msg);
 123        dev_put(dev);
 124
 125        return ret;
 126}
 127
 128static const struct nla_policy irda_nl_policy[IRDA_NL_ATTR_MAX + 1] = {
 129        [IRDA_NL_ATTR_IFNAME] = { .type = NLA_NUL_STRING,
 130                                  .len = IFNAMSIZ-1 },
 131        [IRDA_NL_ATTR_MODE] = { .type = NLA_U32 },
 132};
 133
 134static struct genl_ops irda_nl_ops[] = {
 135        {
 136                .cmd = IRDA_NL_CMD_SET_MODE,
 137                .doit = irda_nl_set_mode,
 138                .policy = irda_nl_policy,
 139                .flags = GENL_ADMIN_PERM,
 140        },
 141        {
 142                .cmd = IRDA_NL_CMD_GET_MODE,
 143                .doit = irda_nl_get_mode,
 144                .policy = irda_nl_policy,
 145                /* can be retrieved by unprivileged users */
 146        },
 147
 148};
 149
 150int irda_nl_register(void)
 151{
 152        return genl_register_family_with_ops(&irda_nl_family,
 153                irda_nl_ops, ARRAY_SIZE(irda_nl_ops));
 154}
 155
 156void irda_nl_unregister(void)
 157{
 158        genl_unregister_family(&irda_nl_family);
 159}
 160