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