Commit 4fb09a87 authored by David S. Miller's avatar David S. Miller

Merge branch 'genetlink'

Johannes Berg says:

====================
genetlink: reduce ops size and complexity (v2)

As before - reduce the complexity and data/code size of genetlink ops
by making them an array rather than a linked list. Most users already
use an array thanks to genl_register_family_with_ops(), so convert the
remaining ones allowing us to get rid of the list head in each op.

Also make them const, this just makes sense at that point and the security
people like making function pointers const as well :-)
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 1e9f3d6f 3f5ccd06
......@@ -2644,7 +2644,7 @@ static int team_nl_cmd_port_list_get(struct sk_buff *skb,
return err;
}
static struct genl_ops team_nl_ops[] = {
static const struct genl_ops team_nl_ops[] = {
{
.cmd = TEAM_CMD_NOOP,
.doit = team_nl_cmd_noop,
......
......@@ -2097,7 +2097,7 @@ static int hwsim_register_received_nl(struct sk_buff *skb_2,
}
/* Generic Netlink operations array */
static struct genl_ops hwsim_ops[] = {
static const struct genl_ops hwsim_ops[] = {
{
.cmd = HWSIM_CMD_REGISTER,
.policy = hwsim_genl_policy,
......
......@@ -39,9 +39,10 @@ struct genl_info;
* @post_doit: called after an operation's doit callback, it may
* undo operations done by pre_doit, for example release locks
* @attrbuf: buffer to store parsed attributes
* @ops_list: list of all assigned operations
* @family_list: family list
* @mcast_groups: multicast groups list
* @ops: the operations supported by this family (private)
* @n_ops: number of operations supported by this family (private)
*/
struct genl_family {
unsigned int id;
......@@ -51,14 +52,15 @@ struct genl_family {
unsigned int maxattr;
bool netnsok;
bool parallel_ops;
int (*pre_doit)(struct genl_ops *ops,
int (*pre_doit)(const struct genl_ops *ops,
struct sk_buff *skb,
struct genl_info *info);
void (*post_doit)(struct genl_ops *ops,
void (*post_doit)(const struct genl_ops *ops,
struct sk_buff *skb,
struct genl_info *info);
struct nlattr ** attrbuf; /* private */
struct list_head ops_list; /* private */
const struct genl_ops * ops; /* private */
unsigned int n_ops; /* private */
struct list_head family_list; /* private */
struct list_head mcast_groups; /* private */
struct module *module;
......@@ -110,16 +112,15 @@ static inline void genl_info_net_set(struct genl_info *info, struct net *net)
* @ops_list: operations list
*/
struct genl_ops {
u8 cmd;
u8 internal_flags;
unsigned int flags;
const struct nla_policy *policy;
int (*doit)(struct sk_buff *skb,
struct genl_info *info);
int (*dumpit)(struct sk_buff *skb,
struct netlink_callback *cb);
int (*done)(struct netlink_callback *cb);
struct list_head ops_list;
u8 cmd;
u8 internal_flags;
u8 flags;
};
int __genl_register_family(struct genl_family *family);
......@@ -131,18 +132,16 @@ static inline int genl_register_family(struct genl_family *family)
}
int __genl_register_family_with_ops(struct genl_family *family,
struct genl_ops *ops, size_t n_ops);
const struct genl_ops *ops, size_t n_ops);
static inline int genl_register_family_with_ops(struct genl_family *family,
struct genl_ops *ops, size_t n_ops)
const struct genl_ops *ops, size_t n_ops)
{
family->module = THIS_MODULE;
return __genl_register_family_with_ops(family, ops, n_ops);
}
int genl_unregister_family(struct genl_family *family);
int genl_register_ops(struct genl_family *, struct genl_ops *ops);
int genl_unregister_ops(struct genl_family *, struct genl_ops *ops);
int genl_register_mc_group(struct genl_family *family,
struct genl_multicast_group *grp);
void genl_unregister_mc_group(struct genl_family *family,
......
......@@ -673,17 +673,18 @@ void taskstats_exit(struct task_struct *tsk, int group_dead)
nlmsg_free(rep_skb);
}
static struct genl_ops taskstats_ops = {
.cmd = TASKSTATS_CMD_GET,
.doit = taskstats_user_cmd,
.policy = taskstats_cmd_get_policy,
.flags = GENL_ADMIN_PERM,
};
static struct genl_ops cgroupstats_ops = {
.cmd = CGROUPSTATS_CMD_GET,
.doit = cgroupstats_user_cmd,
.policy = cgroupstats_cmd_get_policy,
static const struct genl_ops taskstats_ops[] = {
{
.cmd = TASKSTATS_CMD_GET,
.doit = taskstats_user_cmd,
.policy = taskstats_cmd_get_policy,
.flags = GENL_ADMIN_PERM,
},
{
.cmd = CGROUPSTATS_CMD_GET,
.doit = cgroupstats_user_cmd,
.policy = cgroupstats_cmd_get_policy,
},
};
/* Needed early in initialization */
......@@ -702,26 +703,14 @@ static int __init taskstats_init(void)
{
int rc;
rc = genl_register_family(&family);
rc = genl_register_family_with_ops(&family, taskstats_ops,
ARRAY_SIZE(taskstats_ops));
if (rc)
return rc;
rc = genl_register_ops(&family, &taskstats_ops);
if (rc < 0)
goto err;
rc = genl_register_ops(&family, &cgroupstats_ops);
if (rc < 0)
goto err_cgroup_ops;
family_registered = 1;
pr_info("registered taskstats version %d\n", TASKSTATS_GENL_VERSION);
return 0;
err_cgroup_ops:
genl_unregister_ops(&family, &taskstats_ops);
err:
genl_unregister_family(&family);
return rc;
}
/*
......
......@@ -333,7 +333,7 @@ static int dropmon_net_event(struct notifier_block *ev_block,
return NOTIFY_DONE;
}
static struct genl_ops dropmon_ops[] = {
static const struct genl_ops dropmon_ops[] = {
{
.cmd = NET_DM_CMD_CONFIG,
.doit = net_dm_cmd_config,
......
......@@ -306,15 +306,6 @@ static int hsr_get_node_status(struct sk_buff *skb_in, struct genl_info *info)
return res;
}
static struct genl_ops hsr_ops_get_node_status = {
.cmd = HSR_C_GET_NODE_STATUS,
.flags = 0,
.policy = hsr_genl_policy,
.doit = hsr_get_node_status,
.dumpit = NULL,
};
/* Get a list of MacAddressA of all nodes known to this node (other than self).
*/
static int hsr_get_node_list(struct sk_buff *skb_in, struct genl_info *info)
......@@ -398,12 +389,21 @@ static int hsr_get_node_list(struct sk_buff *skb_in, struct genl_info *info)
}
static struct genl_ops hsr_ops_get_node_list = {
.cmd = HSR_C_GET_NODE_LIST,
.flags = 0,
.policy = hsr_genl_policy,
.doit = hsr_get_node_list,
.dumpit = NULL,
static const struct genl_ops hsr_ops[] = {
{
.cmd = HSR_C_GET_NODE_STATUS,
.flags = 0,
.policy = hsr_genl_policy,
.doit = hsr_get_node_status,
.dumpit = NULL,
},
{
.cmd = HSR_C_GET_NODE_LIST,
.flags = 0,
.policy = hsr_genl_policy,
.doit = hsr_get_node_list,
.dumpit = NULL,
},
};
int __init hsr_netlink_init(void)
......@@ -414,18 +414,11 @@ int __init hsr_netlink_init(void)
if (rc)
goto fail_rtnl_link_register;
rc = genl_register_family(&hsr_genl_family);
rc = genl_register_family_with_ops(&hsr_genl_family, hsr_ops,
ARRAY_SIZE(hsr_ops));
if (rc)
goto fail_genl_register_family;
rc = genl_register_ops(&hsr_genl_family, &hsr_ops_get_node_status);
if (rc)
goto fail_genl_register_ops;
rc = genl_register_ops(&hsr_genl_family, &hsr_ops_get_node_list);
if (rc)
goto fail_genl_register_ops_node_list;
rc = genl_register_mc_group(&hsr_genl_family, &hsr_network_genl_mcgrp);
if (rc)
goto fail_genl_register_mc_group;
......@@ -433,10 +426,6 @@ int __init hsr_netlink_init(void)
return 0;
fail_genl_register_mc_group:
genl_unregister_ops(&hsr_genl_family, &hsr_ops_get_node_list);
fail_genl_register_ops_node_list:
genl_unregister_ops(&hsr_genl_family, &hsr_ops_get_node_status);
fail_genl_register_ops:
genl_unregister_family(&hsr_genl_family);
fail_genl_register_family:
rtnl_link_unregister(&hsr_link_ops);
......@@ -448,7 +437,6 @@ int __init hsr_netlink_init(void)
void __exit hsr_netlink_exit(void)
{
genl_unregister_mc_group(&hsr_genl_family, &hsr_network_genl_mcgrp);
genl_unregister_ops(&hsr_genl_family, &hsr_ops_get_node_status);
genl_unregister_family(&hsr_genl_family);
rtnl_link_unregister(&hsr_link_ops);
......
......@@ -47,7 +47,22 @@ struct sk_buff *ieee802154_nl_new_reply(struct genl_info *info,
int ieee802154_nl_reply(struct sk_buff *msg, struct genl_info *info);
extern struct genl_family nl802154_family;
int nl802154_mac_register(void);
int nl802154_phy_register(void);
/* genetlink ops/groups */
int ieee802154_list_phy(struct sk_buff *skb, struct genl_info *info);
int ieee802154_dump_phy(struct sk_buff *skb, struct netlink_callback *cb);
int ieee802154_add_iface(struct sk_buff *skb, struct genl_info *info);
int ieee802154_del_iface(struct sk_buff *skb, struct genl_info *info);
extern struct genl_multicast_group ieee802154_coord_mcgrp;
extern struct genl_multicast_group ieee802154_beacon_mcgrp;
int ieee802154_associate_req(struct sk_buff *skb, struct genl_info *info);
int ieee802154_associate_resp(struct sk_buff *skb, struct genl_info *info);
int ieee802154_disassociate_req(struct sk_buff *skb, struct genl_info *info);
int ieee802154_scan_req(struct sk_buff *skb, struct genl_info *info);
int ieee802154_start_req(struct sk_buff *skb, struct genl_info *info);
int ieee802154_list_iface(struct sk_buff *skb, struct genl_info *info);
int ieee802154_dump_iface(struct sk_buff *skb, struct netlink_callback *cb);
#endif
......@@ -109,24 +109,39 @@ int ieee802154_nl_reply(struct sk_buff *msg, struct genl_info *info)
return -ENOBUFS;
}
static const struct genl_ops ieee8021154_ops[] = {
/* see nl-phy.c */
IEEE802154_DUMP(IEEE802154_LIST_PHY, ieee802154_list_phy,
ieee802154_dump_phy),
IEEE802154_OP(IEEE802154_ADD_IFACE, ieee802154_add_iface),
IEEE802154_OP(IEEE802154_DEL_IFACE, ieee802154_del_iface),
/* see nl-mac.c */
IEEE802154_OP(IEEE802154_ASSOCIATE_REQ, ieee802154_associate_req),
IEEE802154_OP(IEEE802154_ASSOCIATE_RESP, ieee802154_associate_resp),
IEEE802154_OP(IEEE802154_DISASSOCIATE_REQ, ieee802154_disassociate_req),
IEEE802154_OP(IEEE802154_SCAN_REQ, ieee802154_scan_req),
IEEE802154_OP(IEEE802154_START_REQ, ieee802154_start_req),
IEEE802154_DUMP(IEEE802154_LIST_IFACE, ieee802154_list_iface,
ieee802154_dump_iface),
};
int __init ieee802154_nl_init(void)
{
int rc;
rc = genl_register_family(&nl802154_family);
rc = genl_register_family_with_ops(&nl802154_family, ieee8021154_ops,
ARRAY_SIZE(ieee8021154_ops));
if (rc)
goto fail;
return rc;
rc = nl802154_mac_register();
rc = genl_register_mc_group(&nl802154_family, &ieee802154_coord_mcgrp);
if (rc)
goto fail;
rc = nl802154_phy_register();
rc = genl_register_mc_group(&nl802154_family, &ieee802154_beacon_mcgrp);
if (rc)
goto fail;
return 0;
fail:
genl_unregister_family(&nl802154_family);
return rc;
......@@ -136,4 +151,3 @@ void __exit ieee802154_nl_exit(void)
{
genl_unregister_family(&nl802154_family);
}
......@@ -39,11 +39,11 @@
#include "ieee802154.h"
static struct genl_multicast_group ieee802154_coord_mcgrp = {
struct genl_multicast_group ieee802154_coord_mcgrp = {
.name = IEEE802154_MCAST_COORD_NAME,
};
static struct genl_multicast_group ieee802154_beacon_mcgrp = {
struct genl_multicast_group ieee802154_beacon_mcgrp = {
.name = IEEE802154_MCAST_BEACON_NAME,
};
......@@ -309,8 +309,7 @@ static struct net_device *ieee802154_nl_get_dev(struct genl_info *info)
return dev;
}
static int ieee802154_associate_req(struct sk_buff *skb,
struct genl_info *info)
int ieee802154_associate_req(struct sk_buff *skb, struct genl_info *info)
{
struct net_device *dev;
struct ieee802154_addr addr;
......@@ -357,8 +356,7 @@ static int ieee802154_associate_req(struct sk_buff *skb,
return ret;
}
static int ieee802154_associate_resp(struct sk_buff *skb,
struct genl_info *info)
int ieee802154_associate_resp(struct sk_buff *skb, struct genl_info *info)
{
struct net_device *dev;
struct ieee802154_addr addr;
......@@ -390,8 +388,7 @@ static int ieee802154_associate_resp(struct sk_buff *skb,
return ret;
}
static int ieee802154_disassociate_req(struct sk_buff *skb,
struct genl_info *info)
int ieee802154_disassociate_req(struct sk_buff *skb, struct genl_info *info)
{
struct net_device *dev;
struct ieee802154_addr addr;
......@@ -433,7 +430,7 @@ static int ieee802154_disassociate_req(struct sk_buff *skb,
* PAN_coordinator, battery_life_extension = 0,
* coord_realignment = 0, security_enable = 0
*/
static int ieee802154_start_req(struct sk_buff *skb, struct genl_info *info)
int ieee802154_start_req(struct sk_buff *skb, struct genl_info *info)
{
struct net_device *dev;
struct ieee802154_addr addr;
......@@ -492,7 +489,7 @@ static int ieee802154_start_req(struct sk_buff *skb, struct genl_info *info)
return ret;
}
static int ieee802154_scan_req(struct sk_buff *skb, struct genl_info *info)
int ieee802154_scan_req(struct sk_buff *skb, struct genl_info *info)
{
struct net_device *dev;
int ret = -EOPNOTSUPP;
......@@ -530,8 +527,7 @@ static int ieee802154_scan_req(struct sk_buff *skb, struct genl_info *info)
return ret;
}
static int ieee802154_list_iface(struct sk_buff *skb,
struct genl_info *info)
int ieee802154_list_iface(struct sk_buff *skb, struct genl_info *info)
{
/* Request for interface name, index, type, IEEE address,
PAN Id, short address */
......@@ -565,8 +561,7 @@ static int ieee802154_list_iface(struct sk_buff *skb,
}
static int ieee802154_dump_iface(struct sk_buff *skb,
struct netlink_callback *cb)
int ieee802154_dump_iface(struct sk_buff *skb, struct netlink_callback *cb)
{
struct net *net = sock_net(skb->sk);
struct net_device *dev;
......@@ -590,41 +585,3 @@ static int ieee802154_dump_iface(struct sk_buff *skb,
return skb->len;
}
static struct genl_ops ieee802154_coordinator_ops[] = {
IEEE802154_OP(IEEE802154_ASSOCIATE_REQ, ieee802154_associate_req),
IEEE802154_OP(IEEE802154_ASSOCIATE_RESP, ieee802154_associate_resp),
IEEE802154_OP(IEEE802154_DISASSOCIATE_REQ, ieee802154_disassociate_req),
IEEE802154_OP(IEEE802154_SCAN_REQ, ieee802154_scan_req),
IEEE802154_OP(IEEE802154_START_REQ, ieee802154_start_req),
IEEE802154_DUMP(IEEE802154_LIST_IFACE, ieee802154_list_iface,
ieee802154_dump_iface),
};
/*
* No need to unregister as family unregistration will do it.
*/
int nl802154_mac_register(void)
{
int i;
int rc;
rc = genl_register_mc_group(&nl802154_family,
&ieee802154_coord_mcgrp);
if (rc)
return rc;
rc = genl_register_mc_group(&nl802154_family,
&ieee802154_beacon_mcgrp);
if (rc)
return rc;
for (i = 0; i < ARRAY_SIZE(ieee802154_coordinator_ops); i++) {
rc = genl_register_ops(&nl802154_family,
&ieee802154_coordinator_ops[i]);
if (rc)
return rc;
}
return 0;
}
......@@ -77,8 +77,7 @@ static int ieee802154_nl_fill_phy(struct sk_buff *msg, u32 portid,
return -EMSGSIZE;
}
static int ieee802154_list_phy(struct sk_buff *skb,
struct genl_info *info)
int ieee802154_list_phy(struct sk_buff *skb, struct genl_info *info)
{
/* Request for interface name, index, type, IEEE address,
PAN Id, short address */
......@@ -151,8 +150,7 @@ static int ieee802154_dump_phy_iter(struct wpan_phy *phy, void *_data)
return 0;
}
static int ieee802154_dump_phy(struct sk_buff *skb,
struct netlink_callback *cb)
int ieee802154_dump_phy(struct sk_buff *skb, struct netlink_callback *cb)
{
struct dump_phy_data data = {
.cb = cb,
......@@ -170,8 +168,7 @@ static int ieee802154_dump_phy(struct sk_buff *skb,
return skb->len;
}
static int ieee802154_add_iface(struct sk_buff *skb,
struct genl_info *info)
int ieee802154_add_iface(struct sk_buff *skb, struct genl_info *info)
{
struct sk_buff *msg;
struct wpan_phy *phy;
......@@ -273,8 +270,7 @@ static int ieee802154_add_iface(struct sk_buff *skb,
return rc;
}
static int ieee802154_del_iface(struct sk_buff *skb,
struct genl_info *info)
int ieee802154_del_iface(struct sk_buff *skb, struct genl_info *info)
{
struct sk_buff *msg;
struct wpan_phy *phy;
......@@ -356,28 +352,3 @@ static int ieee802154_del_iface(struct sk_buff *skb,
return rc;
}
static struct genl_ops ieee802154_phy_ops[] = {
IEEE802154_DUMP(IEEE802154_LIST_PHY, ieee802154_list_phy,
ieee802154_dump_phy),
IEEE802154_OP(IEEE802154_ADD_IFACE, ieee802154_add_iface),
IEEE802154_OP(IEEE802154_DEL_IFACE, ieee802154_del_iface),
};
/*
* No need to unregister as family unregistration will do it.
*/
int nl802154_phy_register(void)
{
int i;
int rc;
for (i = 0; i < ARRAY_SIZE(ieee802154_phy_ops); i++) {
rc = genl_register_ops(&nl802154_family,
&ieee802154_phy_ops[i]);
if (rc)
return rc;
}
return 0;
}
......@@ -991,7 +991,7 @@ static int tcp_metrics_nl_cmd_del(struct sk_buff *skb, struct genl_info *info)
return 0;
}
static struct genl_ops tcp_metrics_nl_ops[] = {
static const struct genl_ops tcp_metrics_nl_ops[] = {
{
.cmd = TCP_METRICS_CMD_GET,
.doit = tcp_metrics_nl_cmd_get,
......
......@@ -131,7 +131,7 @@ static const struct nla_policy irda_nl_policy[IRDA_NL_ATTR_MAX + 1] = {
[IRDA_NL_ATTR_MODE] = { .type = NLA_U32 },
};
static struct genl_ops irda_nl_ops[] = {
static const struct genl_ops irda_nl_ops[] = {
{
.cmd = IRDA_NL_CMD_SET_MODE,
.doit = irda_nl_set_mode,
......
......@@ -793,7 +793,7 @@ static struct nla_policy l2tp_nl_policy[L2TP_ATTR_MAX + 1] = {
},
};
static struct genl_ops l2tp_nl_ops[] = {
static const struct genl_ops l2tp_nl_ops[] = {
{
.cmd = L2TP_CMD_NOOP,
.doit = l2tp_nl_cmd_noop,
......
......@@ -3567,7 +3567,7 @@ static int ip_vs_genl_get_cmd(struct sk_buff *skb, struct genl_info *info)
}
static struct genl_ops ip_vs_genl_ops[] __read_mostly = {
static const struct genl_ops ip_vs_genl_ops[] __read_mostly = {
{
.cmd = IPVS_CMD_NEW_SERVICE,
.flags = GENL_ADMIN_PERM,
......
......@@ -737,7 +737,7 @@ static int netlbl_cipsov4_remove(struct sk_buff *skb, struct genl_info *info)
* NetLabel Generic NETLINK Command Definitions
*/
static struct genl_ops netlbl_cipsov4_ops[] = {
static const struct genl_ops netlbl_cipsov4_ops[] = {
{
.cmd = NLBL_CIPSOV4_C_ADD,
.flags = GENL_ADMIN_PERM,
......
......@@ -705,7 +705,7 @@ static int netlbl_mgmt_version(struct sk_buff *skb, struct genl_info *info)
* NetLabel Generic NETLINK Command Definitions
*/
static struct genl_ops netlbl_mgmt_genl_ops[] = {
static const struct genl_ops netlbl_mgmt_genl_ops[] = {
{
.cmd = NLBL_MGMT_C_ADD,
.flags = GENL_ADMIN_PERM,
......
......@@ -1323,7 +1323,7 @@ static int netlbl_unlabel_staticlistdef(struct sk_buff *skb,
* NetLabel Generic NETLINK Command Definitions
*/
static struct genl_ops netlbl_unlabel_genl_ops[] = {
static const struct genl_ops netlbl_unlabel_genl_ops[] = {
{
.cmd = NLBL_UNLABEL_C_STATICADD,
.flags = GENL_ADMIN_PERM,
......
......@@ -106,13 +106,13 @@ static struct genl_family *genl_family_find_byname(char *name)
return NULL;
}
static struct genl_ops *genl_get_cmd(u8 cmd, struct genl_family *family)
static const struct genl_ops *genl_get_cmd(u8 cmd, struct genl_family *family)
{
struct genl_ops *ops;
int i;
list_for_each_entry(ops, &family->ops_list, ops_list)
if (ops->cmd == cmd)
return ops;
for (i = 0; i < family->n_ops; i++)
if (family->ops[i].cmd == cmd)
return &family->ops[i];
return NULL;
}
......@@ -283,85 +283,26 @@ static void genl_unregister_mc_groups(struct genl_family *family)
__genl_unregister_mc_group(family, grp);
}
/**
* genl_register_ops - register generic netlink operations
* @family: generic netlink family
* @ops: operations to be registered
*
* Registers the specified operations and assigns them to the specified
* family. Either a doit or dumpit callback must be specified or the
* operation will fail. Only one operation structure per command
* identifier may be registered.
*
* See include/net/genetlink.h for more documenation on the operations
* structure.
*
* Returns 0 on success or a negative error code.
*/
int genl_register_ops(struct genl_family *family, struct genl_ops *ops)
static int genl_validate_add_ops(struct genl_family *family,
const struct genl_ops *ops,
unsigned int n_ops)
{
int err = -EINVAL;
if (ops->dumpit == NULL && ops->doit == NULL)
goto errout;
if (genl_get_cmd(ops->cmd, family)) {
err = -EEXIST;
goto errout;
int i, j;
for (i = 0; i < n_ops; i++) {
if (ops[i].dumpit == NULL && ops[i].doit == NULL)
return -EINVAL;
for (j = i + 1; j < n_ops; j++)
if (ops[i].cmd == ops[j].cmd)
return -EINVAL;
}
if (ops->dumpit)
ops->flags |= GENL_CMD_CAP_DUMP;
if (ops->doit)
ops->flags |= GENL_CMD_CAP_DO;
if (ops->policy)
ops->flags |= GENL_CMD_CAP_HASPOL;
genl_lock_all();
list_add_tail(&ops->ops_list, &family->ops_list);
genl_unlock_all();
genl_ctrl_event(CTRL_CMD_NEWOPS, ops);
err = 0;
errout:
return err;
}
EXPORT_SYMBOL(genl_register_ops);
/**
* genl_unregister_ops - unregister generic netlink operations
* @family: generic netlink family
* @ops: operations to be unregistered
*
* Unregisters the specified operations and unassigns them from the
* specified family. The operation blocks until the current message
* processing has finished and doesn't start again until the
* unregister process has finished.
*
* Note: It is not necessary to unregister all operations before
* unregistering the family, unregistering the family will cause
* all assigned operations to be unregistered automatically.
*
* Returns 0 on success or a negative error code.
*/
int genl_unregister_ops(struct genl_family *family, struct genl_ops *ops)
{
struct genl_ops *rc;
/* family is not registered yet, so no locking needed */
family->ops = ops;
family->n_ops = n_ops;
genl_lock_all();
list_for_each_entry(rc, &family->ops_list, ops_list) {
if (rc == ops) {
list_del(&ops->ops_list);
genl_unlock_all();
genl_ctrl_event(CTRL_CMD_DELOPS, ops);
return 0;
}
}
genl_unlock_all();
return -ENOENT;
return 0;
}
EXPORT_SYMBOL(genl_unregister_ops);
/**
* __genl_register_family - register a generic netlink family
......@@ -384,7 +325,6 @@ int __genl_register_family(struct genl_family *family)
if (family->id > GENL_MAX_ID)
goto errout;
INIT_LIST_HEAD(&family->ops_list);
INIT_LIST_HEAD(&family->mcast_groups);
genl_lock_all();
......@@ -451,30 +391,18 @@ EXPORT_SYMBOL(__genl_register_family);
* See include/net/genetlink.h for more documenation on the operations
* structure.
*
* This is equivalent to calling genl_register_family() followed by
* genl_register_ops() for every operation entry in the table taking
* care to unregister the family on error path.
*
* Return 0 on success or a negative error code.
*/
int __genl_register_family_with_ops(struct genl_family *family,
struct genl_ops *ops, size_t n_ops)
const struct genl_ops *ops, size_t n_ops)
{
int err, i;
int err;
err = __genl_register_family(family);
err = genl_validate_add_ops(family, ops, n_ops);
if (err)
return err;
for (i = 0; i < n_ops; ++i, ++ops) {
err = genl_register_ops(family, ops);
if (err)
goto err_out;
}
return 0;
err_out:
genl_unregister_family(family);
return err;
return __genl_register_family(family);
}
EXPORT_SYMBOL(__genl_register_family_with_ops);
......@@ -499,7 +427,7 @@ int genl_unregister_family(struct genl_family *family)
continue;
list_del(&rc->family_list);
INIT_LIST_HEAD(&family->ops_list);
family->n_ops = 0;
genl_unlock_all();
kfree(family->attrbuf);
......@@ -546,7 +474,8 @@ EXPORT_SYMBOL(genlmsg_put);
static int genl_lock_dumpit(struct sk_buff *skb, struct netlink_callback *cb)
{
struct genl_ops *ops = cb->data;
/* our ops are always const - netlink API doesn't propagate that */
const struct genl_ops *ops = cb->data;
int rc;
genl_lock();
......@@ -557,7 +486,8 @@ static int genl_lock_dumpit(struct sk_buff *skb, struct netlink_callback *cb)
static int genl_lock_done(struct netlink_callback *cb)
{
struct genl_ops *ops = cb->data;
/* our ops are always const - netlink API doesn't propagate that */
const struct genl_ops *ops = cb->data;
int rc = 0;
if (ops->done) {
......@@ -572,7 +502,7 @@ static int genl_family_rcv_msg(struct genl_family *family,
struct sk_buff *skb,
struct nlmsghdr *nlh)
{
struct genl_ops *ops;
const struct genl_ops *ops;
struct net *net = sock_net(skb->sk);
struct genl_info info;
struct genlmsghdr *hdr = nlmsg_data(nlh);
......@@ -604,7 +534,8 @@ static int genl_family_rcv_msg(struct genl_family *family,
if (!family->parallel_ops) {
struct netlink_dump_control c = {
.module = family->module,
.data = ops,
/* we have const, but the netlink API doesn't */
.data = (void *)ops,
.dump = genl_lock_dumpit,
.done = genl_lock_done,
};
......@@ -726,24 +657,32 @@ static int ctrl_fill_info(struct genl_family *family, u32 portid, u32 seq,
nla_put_u32(skb, CTRL_ATTR_MAXATTR, family->maxattr))
goto nla_put_failure;
if (!list_empty(&family->ops_list)) {
if (family->n_ops) {
struct nlattr *nla_ops;
struct genl_ops *ops;
int idx = 1;
int i;
nla_ops = nla_nest_start(skb, CTRL_ATTR_OPS);
if (nla_ops == NULL)
goto nla_put_failure;
list_for_each_entry(ops, &family->ops_list, ops_list) {
for (i = 0; i < family->n_ops; i++) {
struct nlattr *nest;
const struct genl_ops *ops = &family->ops[i];
u32 flags = ops->flags;
nest = nla_nest_start(skb, idx++);
if (ops->dumpit)
flags |= GENL_CMD_CAP_DUMP;
if (ops->doit)
flags |= GENL_CMD_CAP_DO;
if (ops->policy)
flags |= GENL_CMD_CAP_HASPOL;
nest = nla_nest_start(skb, i + 1);
if (nest == NULL)
goto nla_put_failure;
if (nla_put_u32(skb, CTRL_ATTR_OP_ID, ops->cmd) ||
nla_put_u32(skb, CTRL_ATTR_OP_FLAGS, ops->flags))
nla_put_u32(skb, CTRL_ATTR_OP_FLAGS, flags))
goto nla_put_failure;
nla_nest_end(skb, nest);
......
......@@ -1364,7 +1364,7 @@ static int nfc_genl_se_io(struct sk_buff *skb, struct genl_info *info)
return dev->ops->se_io(dev, se_idx, apdu, apdu_len, se_io_cb, ctx);
}
static struct genl_ops nfc_genl_ops[] = {
static const struct genl_ops nfc_genl_ops[] = {
{
.cmd = NFC_CMD_GET_DEVICE,
.doit = nfc_genl_get_device,
......
......@@ -557,7 +557,7 @@ static const struct nla_policy packet_policy[OVS_PACKET_ATTR_MAX + 1] = {
[OVS_PACKET_ATTR_ACTIONS] = { .type = NLA_NESTED },
};
static struct genl_ops dp_packet_genl_ops[] = {
static const struct genl_ops dp_packet_genl_ops[] = {
{ .cmd = OVS_PACKET_CMD_EXECUTE,
.flags = GENL_ADMIN_PERM, /* Requires CAP_NET_ADMIN privilege. */
.policy = packet_policy,
......@@ -1034,7 +1034,7 @@ static int ovs_flow_cmd_dump(struct sk_buff *skb, struct netlink_callback *cb)
return skb->len;
}
static struct genl_ops dp_flow_genl_ops[] = {
static const struct genl_ops dp_flow_genl_ops[] = {
{ .cmd = OVS_FLOW_CMD_NEW,
.flags = GENL_ADMIN_PERM, /* Requires CAP_NET_ADMIN privilege. */
.policy = flow_policy,
......@@ -1392,7 +1392,7 @@ static int ovs_dp_cmd_dump(struct sk_buff *skb, struct netlink_callback *cb)
return skb->len;
}
static struct genl_ops dp_datapath_genl_ops[] = {
static const struct genl_ops dp_datapath_genl_ops[] = {
{ .cmd = OVS_DP_CMD_NEW,
.flags = GENL_ADMIN_PERM, /* Requires CAP_NET_ADMIN privilege. */
.policy = datapath_policy,
......@@ -1753,7 +1753,7 @@ static int ovs_vport_cmd_dump(struct sk_buff *skb, struct netlink_callback *cb)
return skb->len;
}
static struct genl_ops dp_vport_genl_ops[] = {
static const struct genl_ops dp_vport_genl_ops[] = {
{ .cmd = OVS_VPORT_CMD_NEW,
.flags = GENL_ADMIN_PERM, /* Requires CAP_NET_ADMIN privilege. */
.policy = vport_policy,
......@@ -1779,7 +1779,7 @@ static struct genl_ops dp_vport_genl_ops[] = {
struct genl_family_and_ops {
struct genl_family *family;
struct genl_ops *ops;
const struct genl_ops *ops;
int n_ops;
struct genl_multicast_group *group;
};
......
......@@ -321,17 +321,6 @@ int wimax_msg(struct wimax_dev *wimax_dev, const char *pipe_name,
}
EXPORT_SYMBOL_GPL(wimax_msg);
static const struct nla_policy wimax_gnl_msg_policy[WIMAX_GNL_ATTR_MAX + 1] = {
[WIMAX_GNL_MSG_IFIDX] = {
.type = NLA_U32,
},
[WIMAX_GNL_MSG_DATA] = {
.type = NLA_UNSPEC, /* libnl doesn't grok BINARY yet */
},
};
/*
* Relays a message from user space to the driver
*
......@@ -340,7 +329,6 @@ static const struct nla_policy wimax_gnl_msg_policy[WIMAX_GNL_ATTR_MAX + 1] = {
*
* This call will block while handling/relaying the message.
*/
static
int wimax_gnl_doit_msg_from_user(struct sk_buff *skb, struct genl_info *info)
{
int result, ifindex;
......@@ -418,16 +406,3 @@ int wimax_gnl_doit_msg_from_user(struct sk_buff *skb, struct genl_info *info)
return result;
}
/*
* Generic Netlink glue
*/
struct genl_ops wimax_gnl_msg_from_user = {
.cmd = WIMAX_GNL_OP_MSG_FROM_USER,
.flags = GENL_ADMIN_PERM,
.policy = wimax_gnl_msg_policy,
.doit = wimax_gnl_doit_msg_from_user,
.dumpit = NULL,
};
......@@ -92,13 +92,6 @@ int wimax_reset(struct wimax_dev *wimax_dev)
EXPORT_SYMBOL(wimax_reset);
static const struct nla_policy wimax_gnl_reset_policy[WIMAX_GNL_ATTR_MAX + 1] = {
[WIMAX_GNL_RESET_IFIDX] = {
.type = NLA_U32,
},
};
/*
* Exporting to user space over generic netlink
*
......@@ -106,7 +99,6 @@ static const struct nla_policy wimax_gnl_reset_policy[WIMAX_GNL_ATTR_MAX + 1] =
*
* No attributes.
*/
static
int wimax_gnl_doit_reset(struct sk_buff *skb, struct genl_info *info)
{
int result, ifindex;
......@@ -130,12 +122,3 @@ int wimax_gnl_doit_reset(struct sk_buff *skb, struct genl_info *info)
d_fnend(3, NULL, "(skb %p info %p) = %d\n", skb, info, result);
return result;
}
struct genl_ops wimax_gnl_reset = {
.cmd = WIMAX_GNL_OP_RESET,
.flags = GENL_ADMIN_PERM,
.policy = wimax_gnl_reset_policy,
.doit = wimax_gnl_doit_reset,
.dumpit = NULL,
};
......@@ -411,17 +411,6 @@ void wimax_rfkill_rm(struct wimax_dev *wimax_dev)
* just query).
*/
static const struct nla_policy wimax_gnl_rfkill_policy[WIMAX_GNL_ATTR_MAX + 1] = {
[WIMAX_GNL_RFKILL_IFIDX] = {
.type = NLA_U32,
},
[WIMAX_GNL_RFKILL_STATE] = {
.type = NLA_U32 /* enum wimax_rf_state */
},
};
static
int wimax_gnl_doit_rfkill(struct sk_buff *skb, struct genl_info *info)
{
int result, ifindex;
......@@ -457,13 +446,3 @@ int wimax_gnl_doit_rfkill(struct sk_buff *skb, struct genl_info *info)
d_fnend(3, NULL, "(skb %p info %p) = %d\n", skb, info, result);
return result;
}
struct genl_ops wimax_gnl_rfkill = {
.cmd = WIMAX_GNL_OP_RFKILL,
.flags = GENL_ADMIN_PERM,
.policy = wimax_gnl_rfkill_policy,
.doit = wimax_gnl_doit_rfkill,
.dumpit = NULL,
};
......@@ -33,13 +33,6 @@
#include "debug-levels.h"
static const struct nla_policy wimax_gnl_state_get_policy[WIMAX_GNL_ATTR_MAX + 1] = {
[WIMAX_GNL_STGET_IFIDX] = {
.type = NLA_U32,
},
};
/*
* Exporting to user space over generic netlink
*
......@@ -48,7 +41,6 @@ static const struct nla_policy wimax_gnl_state_get_policy[WIMAX_GNL_ATTR_MAX + 1
*
* No attributes.
*/
static
int wimax_gnl_doit_state_get(struct sk_buff *skb, struct genl_info *info)
{
int result, ifindex;
......@@ -72,12 +64,3 @@ int wimax_gnl_doit_state_get(struct sk_buff *skb, struct genl_info *info)
d_fnend(3, NULL, "(skb %p info %p) = %d\n", skb, info, result);
return result;
}
struct genl_ops wimax_gnl_state_get = {
.cmd = WIMAX_GNL_OP_STATE_GET,
.flags = GENL_ADMIN_PERM,
.policy = wimax_gnl_state_get_policy,
.doit = wimax_gnl_doit_state_get,
.dumpit = NULL,
};
......@@ -402,22 +402,44 @@ void wimax_dev_init(struct wimax_dev *wimax_dev)
}
EXPORT_SYMBOL_GPL(wimax_dev_init);
/*
* This extern is declared here because it's easier to keep track --
* both declarations are a list of the same
*/
extern struct genl_ops
wimax_gnl_msg_from_user,
wimax_gnl_reset,
wimax_gnl_rfkill,
wimax_gnl_state_get;
static const struct nla_policy wimax_gnl_policy[WIMAX_GNL_ATTR_MAX + 1] = {
[WIMAX_GNL_RESET_IFIDX] = { .type = NLA_U32, },
[WIMAX_GNL_RFKILL_IFIDX] = { .type = NLA_U32, },
[WIMAX_GNL_RFKILL_STATE] = {
.type = NLA_U32 /* enum wimax_rf_state */
},
[WIMAX_GNL_STGET_IFIDX] = { .type = NLA_U32, },
[WIMAX_GNL_MSG_IFIDX] = { .type = NLA_U32, },
[WIMAX_GNL_MSG_DATA] = {
.type = NLA_UNSPEC, /* libnl doesn't grok BINARY yet */
},
};
static
struct genl_ops *wimax_gnl_ops[] = {
&wimax_gnl_msg_from_user,
&wimax_gnl_reset,
&wimax_gnl_rfkill,
&wimax_gnl_state_get,
static const struct genl_ops wimax_gnl_ops[] = {
{
.cmd = WIMAX_GNL_OP_MSG_FROM_USER,
.flags = GENL_ADMIN_PERM,
.policy = wimax_gnl_policy,
.doit = wimax_gnl_doit_msg_from_user,
},
{
.cmd = WIMAX_GNL_OP_RESET,
.flags = GENL_ADMIN_PERM,
.policy = wimax_gnl_policy,
.doit = wimax_gnl_doit_reset,
},
{
.cmd = WIMAX_GNL_OP_RFKILL,
.flags = GENL_ADMIN_PERM,
.policy = wimax_gnl_policy,
.doit = wimax_gnl_doit_rfkill,
},
{
.cmd = WIMAX_GNL_OP_STATE_GET,
.flags = GENL_ADMIN_PERM,
.policy = wimax_gnl_policy,
.doit = wimax_gnl_doit_state_get,
},
};
......@@ -567,7 +589,7 @@ struct genl_multicast_group wimax_gnl_mcg = {
static
int __init wimax_subsys_init(void)
{
int result, cnt;
int result;
d_fnstart(4, NULL, "()\n");
d_parse_params(D_LEVEL, D_LEVEL_SIZE, wimax_debug_params,
......@@ -575,26 +597,14 @@ int __init wimax_subsys_init(void)
snprintf(wimax_gnl_family.name, sizeof(wimax_gnl_family.name),
"WiMAX");
result = genl_register_family(&wimax_gnl_family);
result = genl_register_family_with_ops(&wimax_gnl_family, wimax_gnl_ops,
ARRAY_SIZE(wimax_gnl_ops));
if (unlikely(result < 0)) {
printk(KERN_ERR "cannot register generic netlink family: %d\n",
result);
goto error_register_family;
}
for (cnt = 0; cnt < ARRAY_SIZE(wimax_gnl_ops); cnt++) {
result = genl_register_ops(&wimax_gnl_family,
wimax_gnl_ops[cnt]);
d_printf(4, NULL, "registering generic netlink op code "
"%u: %d\n", wimax_gnl_ops[cnt]->cmd, result);
if (unlikely(result < 0)) {
printk(KERN_ERR "cannot register generic netlink op "
"code %u: %d\n",
wimax_gnl_ops[cnt]->cmd, result);
goto error_register_ops;
}
}
result = genl_register_mc_group(&wimax_gnl_family, &wimax_gnl_mcg);
if (result < 0)
goto error_mc_group;
......@@ -602,10 +612,6 @@ int __init wimax_subsys_init(void)
return 0;
error_mc_group:
error_register_ops:
for (cnt--; cnt >= 0; cnt--)
genl_unregister_ops(&wimax_gnl_family,
wimax_gnl_ops[cnt]);
genl_unregister_family(&wimax_gnl_family);
error_register_family:
d_fnend(4, NULL, "() = %d\n", result);
......@@ -619,12 +625,7 @@ module_init(wimax_subsys_init);
static
void __exit wimax_subsys_exit(void)
{
int cnt;
wimax_id_table_release();
genl_unregister_mc_group(&wimax_gnl_family, &wimax_gnl_mcg);
for (cnt = ARRAY_SIZE(wimax_gnl_ops) - 1; cnt >= 0; cnt--)
genl_unregister_ops(&wimax_gnl_family,
wimax_gnl_ops[cnt]);
genl_unregister_family(&wimax_gnl_family);
}
module_exit(wimax_subsys_exit);
......
......@@ -84,8 +84,15 @@ void wimax_id_table_release(void);
int wimax_rfkill_add(struct wimax_dev *);
void wimax_rfkill_rm(struct wimax_dev *);
/* generic netlink */
extern struct genl_family wimax_gnl_family;
extern struct genl_multicast_group wimax_gnl_mcg;
/* ops */
int wimax_gnl_doit_msg_from_user(struct sk_buff *skb, struct genl_info *info);
int wimax_gnl_doit_reset(struct sk_buff *skb, struct genl_info *info);
int wimax_gnl_doit_rfkill(struct sk_buff *skb, struct genl_info *info);
int wimax_gnl_doit_state_get(struct sk_buff *skb, struct genl_info *info);
#endif /* #ifdef __KERNEL__ */
#endif /* #ifndef __WIMAX_INTERNAL_H__ */
......@@ -30,9 +30,9 @@ static int nl80211_crypto_settings(struct cfg80211_registered_device *rdev,
struct cfg80211_crypto_settings *settings,
int cipher_limit);
static int nl80211_pre_doit(struct genl_ops *ops, struct sk_buff *skb,
static int nl80211_pre_doit(const struct genl_ops *ops, struct sk_buff *skb,
struct genl_info *info);
static void nl80211_post_doit(struct genl_ops *ops, struct sk_buff *skb,
static void nl80211_post_doit(const struct genl_ops *ops, struct sk_buff *skb,
struct genl_info *info);
/* the netlink family */
......@@ -8851,7 +8851,7 @@ static int nl80211_crit_protocol_stop(struct sk_buff *skb,
#define NL80211_FLAG_NEED_WDEV_UP (NL80211_FLAG_NEED_WDEV |\
NL80211_FLAG_CHECK_NETDEV_UP)
static int nl80211_pre_doit(struct genl_ops *ops, struct sk_buff *skb,
static int nl80211_pre_doit(const struct genl_ops *ops, struct sk_buff *skb,
struct genl_info *info)
{
struct cfg80211_registered_device *rdev;
......@@ -8920,7 +8920,7 @@ static int nl80211_pre_doit(struct genl_ops *ops, struct sk_buff *skb,
return 0;
}
static void nl80211_post_doit(struct genl_ops *ops, struct sk_buff *skb,
static void nl80211_post_doit(const struct genl_ops *ops, struct sk_buff *skb,
struct genl_info *info)
{
if (info->user_ptr[1]) {
......@@ -8937,7 +8937,7 @@ static void nl80211_post_doit(struct genl_ops *ops, struct sk_buff *skb,
rtnl_unlock();
}
static struct genl_ops nl80211_ops[] = {
static const struct genl_ops nl80211_ops[] = {
{
.cmd = NL80211_CMD_GET_WIPHY,
.doit = nl80211_get_wiphy,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment