00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020 #include <netlink-generic.h>
00021 #include <netlink/netlink.h>
00022 #include <netlink/genl/genl.h>
00023 #include <netlink/genl/family.h>
00024 #include <netlink/genl/mngt.h>
00025 #include <netlink/genl/ctrl.h>
00026 #include <netlink/utils.h>
00027
00028
00029 #define CTRL_VERSION 0x0001
00030
00031 static struct nl_cache_ops genl_ctrl_ops;
00032
00033
00034 static int ctrl_request_update(struct nl_cache *c, struct nl_sock *h)
00035 {
00036 return genl_send_simple(h, GENL_ID_CTRL, CTRL_CMD_GETFAMILY,
00037 CTRL_VERSION, NLM_F_DUMP);
00038 }
00039
00040 static struct nla_policy ctrl_policy[CTRL_ATTR_MAX+1] = {
00041 [CTRL_ATTR_FAMILY_ID] = { .type = NLA_U16 },
00042 [CTRL_ATTR_FAMILY_NAME] = { .type = NLA_STRING,
00043 .maxlen = GENL_NAMSIZ },
00044 [CTRL_ATTR_VERSION] = { .type = NLA_U32 },
00045 [CTRL_ATTR_HDRSIZE] = { .type = NLA_U32 },
00046 [CTRL_ATTR_MAXATTR] = { .type = NLA_U32 },
00047 [CTRL_ATTR_OPS] = { .type = NLA_NESTED },
00048 };
00049
00050 static struct nla_policy family_op_policy[CTRL_ATTR_OP_MAX+1] = {
00051 [CTRL_ATTR_OP_ID] = { .type = NLA_U32 },
00052 [CTRL_ATTR_OP_FLAGS] = { .type = NLA_U32 },
00053 };
00054
00055 static int ctrl_msg_parser(struct nl_cache_ops *ops, struct genl_cmd *cmd,
00056 struct genl_info *info, void *arg)
00057 {
00058 struct genl_family *family;
00059 struct nl_parser_param *pp = arg;
00060 int err;
00061
00062 family = genl_family_alloc();
00063 if (family == NULL) {
00064 err = -NLE_NOMEM;
00065 goto errout;
00066 }
00067
00068 if (info->attrs[CTRL_ATTR_FAMILY_NAME] == NULL) {
00069 err = -NLE_MISSING_ATTR;
00070 goto errout;
00071 }
00072
00073 if (info->attrs[CTRL_ATTR_FAMILY_ID] == NULL) {
00074 err = -NLE_MISSING_ATTR;
00075 goto errout;
00076 }
00077
00078 family->ce_msgtype = info->nlh->nlmsg_type;
00079 genl_family_set_id(family,
00080 nla_get_u16(info->attrs[CTRL_ATTR_FAMILY_ID]));
00081 genl_family_set_name(family,
00082 nla_get_string(info->attrs[CTRL_ATTR_FAMILY_NAME]));
00083
00084 if (info->attrs[CTRL_ATTR_VERSION]) {
00085 uint32_t version = nla_get_u32(info->attrs[CTRL_ATTR_VERSION]);
00086 genl_family_set_version(family, version);
00087 }
00088
00089 if (info->attrs[CTRL_ATTR_HDRSIZE]) {
00090 uint32_t hdrsize = nla_get_u32(info->attrs[CTRL_ATTR_HDRSIZE]);
00091 genl_family_set_hdrsize(family, hdrsize);
00092 }
00093
00094 if (info->attrs[CTRL_ATTR_MAXATTR]) {
00095 uint32_t maxattr = nla_get_u32(info->attrs[CTRL_ATTR_MAXATTR]);
00096 genl_family_set_maxattr(family, maxattr);
00097 }
00098
00099 if (info->attrs[CTRL_ATTR_OPS]) {
00100 struct nlattr *nla, *nla_ops;
00101 int remaining;
00102
00103 nla_ops = info->attrs[CTRL_ATTR_OPS];
00104 nla_for_each_nested(nla, nla_ops, remaining) {
00105 struct nlattr *tb[CTRL_ATTR_OP_MAX+1];
00106 int flags = 0, id;
00107
00108 err = nla_parse_nested(tb, CTRL_ATTR_OP_MAX, nla,
00109 family_op_policy);
00110 if (err < 0)
00111 goto errout;
00112
00113 if (tb[CTRL_ATTR_OP_ID] == NULL) {
00114 err = -NLE_MISSING_ATTR;
00115 goto errout;
00116 }
00117
00118 id = nla_get_u32(tb[CTRL_ATTR_OP_ID]);
00119
00120 if (tb[CTRL_ATTR_OP_FLAGS])
00121 flags = nla_get_u32(tb[CTRL_ATTR_OP_FLAGS]);
00122
00123 err = genl_family_add_op(family, id, flags);
00124 if (err < 0)
00125 goto errout;
00126
00127 }
00128 }
00129
00130 err = pp->pp_cb((struct nl_object *) family, pp);
00131 errout:
00132 genl_family_put(family);
00133 return err;
00134 }
00135
00136
00137
00138
00139
00140
00141 int genl_ctrl_alloc_cache(struct nl_sock *sock, struct nl_cache **result)
00142 {
00143 return nl_cache_alloc_and_fill(&genl_ctrl_ops, sock, result);
00144 }
00145
00146
00147
00148
00149
00150
00151
00152
00153
00154
00155
00156
00157
00158 struct genl_family *genl_ctrl_search(struct nl_cache *cache, int id)
00159 {
00160 struct genl_family *fam;
00161
00162 if (cache->c_ops != &genl_ctrl_ops)
00163 BUG();
00164
00165 nl_list_for_each_entry(fam, &cache->c_items, ce_list) {
00166 if (fam->gf_id == id) {
00167 nl_object_get((struct nl_object *) fam);
00168 return fam;
00169 }
00170 }
00171
00172 return NULL;
00173 }
00174
00175
00176
00177
00178
00179
00180
00181
00182
00183
00184
00185
00186
00187
00188
00189
00190
00191
00192 struct genl_family *genl_ctrl_search_by_name(struct nl_cache *cache,
00193 const char *name)
00194 {
00195 struct genl_family *fam;
00196
00197 if (cache->c_ops != &genl_ctrl_ops)
00198 BUG();
00199
00200 nl_list_for_each_entry(fam, &cache->c_items, ce_list) {
00201 if (!strcmp(name, fam->gf_name)) {
00202 nl_object_get((struct nl_object *) fam);
00203 return fam;
00204 }
00205 }
00206
00207 return NULL;
00208 }
00209
00210
00211
00212
00213
00214
00215
00216
00217
00218
00219
00220
00221
00222 int genl_ctrl_resolve(struct nl_sock *sk, const char *name)
00223 {
00224 struct nl_cache *cache;
00225 struct genl_family *family;
00226 int err;
00227
00228 if ((err = genl_ctrl_alloc_cache(sk, &cache)) < 0)
00229 return err;
00230
00231 family = genl_ctrl_search_by_name(cache, name);
00232 if (family == NULL) {
00233 err = -NLE_OBJ_NOTFOUND;
00234 goto errout;
00235 }
00236
00237 err = genl_family_get_id(family);
00238 genl_family_put(family);
00239 errout:
00240 nl_cache_free(cache);
00241
00242 return err;
00243 }
00244
00245
00246
00247 static struct genl_cmd genl_cmds[] = {
00248 {
00249 .c_id = CTRL_CMD_NEWFAMILY,
00250 .c_name = "NEWFAMILY" ,
00251 .c_maxattr = CTRL_ATTR_MAX,
00252 .c_attr_policy = ctrl_policy,
00253 .c_msg_parser = ctrl_msg_parser,
00254 },
00255 {
00256 .c_id = CTRL_CMD_DELFAMILY,
00257 .c_name = "DELFAMILY" ,
00258 },
00259 {
00260 .c_id = CTRL_CMD_GETFAMILY,
00261 .c_name = "GETFAMILY" ,
00262 },
00263 {
00264 .c_id = CTRL_CMD_NEWOPS,
00265 .c_name = "NEWOPS" ,
00266 },
00267 {
00268 .c_id = CTRL_CMD_DELOPS,
00269 .c_name = "DELOPS" ,
00270 },
00271 };
00272
00273 static struct genl_ops genl_ops = {
00274 .o_cmds = genl_cmds,
00275 .o_ncmds = ARRAY_SIZE(genl_cmds),
00276 };
00277
00278
00279 extern struct nl_object_ops genl_family_ops;
00280
00281
00282 static struct nl_cache_ops genl_ctrl_ops = {
00283 .co_name = "genl/family",
00284 .co_hdrsize = GENL_HDRSIZE(0),
00285 .co_msgtypes = GENL_FAMILY(GENL_ID_CTRL, "nlctrl"),
00286 .co_genl = &genl_ops,
00287 .co_protocol = NETLINK_GENERIC,
00288 .co_request_update = ctrl_request_update,
00289 .co_obj_ops = &genl_family_ops,
00290 };
00291
00292 static void __init ctrl_init(void)
00293 {
00294 genl_register(&genl_ctrl_ops);
00295 }
00296
00297 static void __exit ctrl_exit(void)
00298 {
00299 genl_unregister(&genl_ctrl_ops);
00300 }
00301
00302