1d15c345fSPaul Moore /* 2d15c345fSPaul Moore * NetLabel Management Support 3d15c345fSPaul Moore * 4d15c345fSPaul Moore * This file defines the management functions for the NetLabel system. The 5d15c345fSPaul Moore * NetLabel system manages static and dynamic label mappings for network 6d15c345fSPaul Moore * protocols such as CIPSO and RIPSO. 7d15c345fSPaul Moore * 8d15c345fSPaul Moore * Author: Paul Moore <paul.moore@hp.com> 9d15c345fSPaul Moore * 10d15c345fSPaul Moore */ 11d15c345fSPaul Moore 12d15c345fSPaul Moore /* 13d15c345fSPaul Moore * (c) Copyright Hewlett-Packard Development Company, L.P., 2006 14d15c345fSPaul Moore * 15d15c345fSPaul Moore * This program is free software; you can redistribute it and/or modify 16d15c345fSPaul Moore * it under the terms of the GNU General Public License as published by 17d15c345fSPaul Moore * the Free Software Foundation; either version 2 of the License, or 18d15c345fSPaul Moore * (at your option) any later version. 19d15c345fSPaul Moore * 20d15c345fSPaul Moore * This program is distributed in the hope that it will be useful, 21d15c345fSPaul Moore * but WITHOUT ANY WARRANTY; without even the implied warranty of 22d15c345fSPaul Moore * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See 23d15c345fSPaul Moore * the GNU General Public License for more details. 24d15c345fSPaul Moore * 25d15c345fSPaul Moore * You should have received a copy of the GNU General Public License 26d15c345fSPaul Moore * along with this program; if not, write to the Free Software 27d15c345fSPaul Moore * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 28d15c345fSPaul Moore * 29d15c345fSPaul Moore */ 30d15c345fSPaul Moore 31d15c345fSPaul Moore #include <linux/types.h> 32d15c345fSPaul Moore #include <linux/socket.h> 33d15c345fSPaul Moore #include <linux/string.h> 34d15c345fSPaul Moore #include <linux/skbuff.h> 35d15c345fSPaul Moore #include <net/sock.h> 36d15c345fSPaul Moore #include <net/netlink.h> 37d15c345fSPaul Moore #include <net/genetlink.h> 38d15c345fSPaul Moore #include <net/netlabel.h> 39d15c345fSPaul Moore #include <net/cipso_ipv4.h> 40d15c345fSPaul Moore 41d15c345fSPaul Moore #include "netlabel_domainhash.h" 42d15c345fSPaul Moore #include "netlabel_user.h" 43d15c345fSPaul Moore #include "netlabel_mgmt.h" 44d15c345fSPaul Moore 45fd385855SPaul Moore /* Argument struct for netlbl_domhsh_walk() */ 46fd385855SPaul Moore struct netlbl_domhsh_walk_arg { 47fd385855SPaul Moore struct netlink_callback *nl_cb; 48fd385855SPaul Moore struct sk_buff *skb; 49fd385855SPaul Moore u32 seq; 50fd385855SPaul Moore }; 51fd385855SPaul Moore 52d15c345fSPaul Moore /* NetLabel Generic NETLINK CIPSOv4 family */ 53d15c345fSPaul Moore static struct genl_family netlbl_mgmt_gnl_family = { 54d15c345fSPaul Moore .id = GENL_ID_GENERATE, 55d15c345fSPaul Moore .hdrsize = 0, 56d15c345fSPaul Moore .name = NETLBL_NLTYPE_MGMT_NAME, 57d15c345fSPaul Moore .version = NETLBL_PROTO_VERSION, 58fd385855SPaul Moore .maxattr = NLBL_MGMT_A_MAX, 59d15c345fSPaul Moore }; 60d15c345fSPaul Moore 61fd385855SPaul Moore /* NetLabel Netlink attribute policy */ 62ef7c79edSPatrick McHardy static const struct nla_policy netlbl_mgmt_genl_policy[NLBL_MGMT_A_MAX + 1] = { 63fd385855SPaul Moore [NLBL_MGMT_A_DOMAIN] = { .type = NLA_NUL_STRING }, 64fd385855SPaul Moore [NLBL_MGMT_A_PROTOCOL] = { .type = NLA_U32 }, 65fd385855SPaul Moore [NLBL_MGMT_A_VERSION] = { .type = NLA_U32 }, 66fd385855SPaul Moore [NLBL_MGMT_A_CV4DOI] = { .type = NLA_U32 }, 67fd385855SPaul Moore }; 68d15c345fSPaul Moore 69d15c345fSPaul Moore /* 70d15c345fSPaul Moore * NetLabel Command Handlers 71d15c345fSPaul Moore */ 72d15c345fSPaul Moore 73d15c345fSPaul Moore /** 74d15c345fSPaul Moore * netlbl_mgmt_add - Handle an ADD message 75d15c345fSPaul Moore * @skb: the NETLINK buffer 76d15c345fSPaul Moore * @info: the Generic NETLINK info block 77d15c345fSPaul Moore * 78d15c345fSPaul Moore * Description: 79d15c345fSPaul Moore * Process a user generated ADD message and add the domains from the message 80d15c345fSPaul Moore * to the hash table. See netlabel.h for a description of the message format. 81d15c345fSPaul Moore * Returns zero on success, negative values on failure. 82d15c345fSPaul Moore * 83d15c345fSPaul Moore */ 84d15c345fSPaul Moore static int netlbl_mgmt_add(struct sk_buff *skb, struct genl_info *info) 85d15c345fSPaul Moore { 86d15c345fSPaul Moore int ret_val = -EINVAL; 87d15c345fSPaul Moore struct netlbl_dom_map *entry = NULL; 88fd385855SPaul Moore size_t tmp_size; 89d15c345fSPaul Moore u32 tmp_val; 9095d4e6beSPaul Moore struct netlbl_audit audit_info; 91d15c345fSPaul Moore 92fd385855SPaul Moore if (!info->attrs[NLBL_MGMT_A_DOMAIN] || 93fd385855SPaul Moore !info->attrs[NLBL_MGMT_A_PROTOCOL]) 94d15c345fSPaul Moore goto add_failure; 95d15c345fSPaul Moore 9695d4e6beSPaul Moore netlbl_netlink_auditinfo(skb, &audit_info); 9795d4e6beSPaul Moore 98d15c345fSPaul Moore entry = kzalloc(sizeof(*entry), GFP_KERNEL); 99d15c345fSPaul Moore if (entry == NULL) { 100d15c345fSPaul Moore ret_val = -ENOMEM; 101d15c345fSPaul Moore goto add_failure; 102d15c345fSPaul Moore } 103fd385855SPaul Moore tmp_size = nla_len(info->attrs[NLBL_MGMT_A_DOMAIN]); 104d15c345fSPaul Moore entry->domain = kmalloc(tmp_size, GFP_KERNEL); 105d15c345fSPaul Moore if (entry->domain == NULL) { 106d15c345fSPaul Moore ret_val = -ENOMEM; 107d15c345fSPaul Moore goto add_failure; 108d15c345fSPaul Moore } 109fd385855SPaul Moore entry->type = nla_get_u32(info->attrs[NLBL_MGMT_A_PROTOCOL]); 110fd385855SPaul Moore nla_strlcpy(entry->domain, info->attrs[NLBL_MGMT_A_DOMAIN], tmp_size); 111d15c345fSPaul Moore 112fd385855SPaul Moore switch (entry->type) { 113d15c345fSPaul Moore case NETLBL_NLTYPE_UNLABELED: 11495d4e6beSPaul Moore ret_val = netlbl_domhsh_add(entry, &audit_info); 115d15c345fSPaul Moore break; 116d15c345fSPaul Moore case NETLBL_NLTYPE_CIPSOV4: 117fd385855SPaul Moore if (!info->attrs[NLBL_MGMT_A_CV4DOI]) 118d15c345fSPaul Moore goto add_failure; 119fd385855SPaul Moore 120fd385855SPaul Moore tmp_val = nla_get_u32(info->attrs[NLBL_MGMT_A_CV4DOI]); 121fd385855SPaul Moore /* We should be holding a rcu_read_lock() here while we hold 122fd385855SPaul Moore * the result but since the entry will always be deleted when 123fd385855SPaul Moore * the CIPSO DOI is deleted we aren't going to keep the 124fd385855SPaul Moore * lock. */ 125d15c345fSPaul Moore rcu_read_lock(); 126d15c345fSPaul Moore entry->type_def.cipsov4 = cipso_v4_doi_getdef(tmp_val); 127d15c345fSPaul Moore if (entry->type_def.cipsov4 == NULL) { 128d15c345fSPaul Moore rcu_read_unlock(); 129d15c345fSPaul Moore goto add_failure; 130d15c345fSPaul Moore } 13195d4e6beSPaul Moore ret_val = netlbl_domhsh_add(entry, &audit_info); 132d15c345fSPaul Moore rcu_read_unlock(); 133d15c345fSPaul Moore break; 134d15c345fSPaul Moore default: 135fd385855SPaul Moore goto add_failure; 136d15c345fSPaul Moore } 137d15c345fSPaul Moore if (ret_val != 0) 138d15c345fSPaul Moore goto add_failure; 139d15c345fSPaul Moore 140d15c345fSPaul Moore return 0; 141d15c345fSPaul Moore 142d15c345fSPaul Moore add_failure: 143d15c345fSPaul Moore if (entry) 144d15c345fSPaul Moore kfree(entry->domain); 145d15c345fSPaul Moore kfree(entry); 146d15c345fSPaul Moore return ret_val; 147d15c345fSPaul Moore } 148d15c345fSPaul Moore 149d15c345fSPaul Moore /** 150d15c345fSPaul Moore * netlbl_mgmt_remove - Handle a REMOVE message 151d15c345fSPaul Moore * @skb: the NETLINK buffer 152d15c345fSPaul Moore * @info: the Generic NETLINK info block 153d15c345fSPaul Moore * 154d15c345fSPaul Moore * Description: 155d15c345fSPaul Moore * Process a user generated REMOVE message and remove the specified domain 156d15c345fSPaul Moore * mappings. Returns zero on success, negative values on failure. 157d15c345fSPaul Moore * 158d15c345fSPaul Moore */ 159d15c345fSPaul Moore static int netlbl_mgmt_remove(struct sk_buff *skb, struct genl_info *info) 160d15c345fSPaul Moore { 161fd385855SPaul Moore char *domain; 16295d4e6beSPaul Moore struct netlbl_audit audit_info; 163d15c345fSPaul Moore 164fd385855SPaul Moore if (!info->attrs[NLBL_MGMT_A_DOMAIN]) 165fd385855SPaul Moore return -EINVAL; 166d15c345fSPaul Moore 16795d4e6beSPaul Moore netlbl_netlink_auditinfo(skb, &audit_info); 16895d4e6beSPaul Moore 169fd385855SPaul Moore domain = nla_data(info->attrs[NLBL_MGMT_A_DOMAIN]); 17095d4e6beSPaul Moore return netlbl_domhsh_remove(domain, &audit_info); 171d15c345fSPaul Moore } 172d15c345fSPaul Moore 173fd385855SPaul Moore /** 174fd385855SPaul Moore * netlbl_mgmt_listall_cb - netlbl_domhsh_walk() callback for LISTALL 175fd385855SPaul Moore * @entry: the domain mapping hash table entry 176fd385855SPaul Moore * @arg: the netlbl_domhsh_walk_arg structure 177fd385855SPaul Moore * 178fd385855SPaul Moore * Description: 179fd385855SPaul Moore * This function is designed to be used as a callback to the 180fd385855SPaul Moore * netlbl_domhsh_walk() function for use in generating a response for a LISTALL 181fd385855SPaul Moore * message. Returns the size of the message on success, negative values on 182fd385855SPaul Moore * failure. 183fd385855SPaul Moore * 184fd385855SPaul Moore */ 185fd385855SPaul Moore static int netlbl_mgmt_listall_cb(struct netlbl_dom_map *entry, void *arg) 186fd385855SPaul Moore { 187fd385855SPaul Moore int ret_val = -ENOMEM; 188fd385855SPaul Moore struct netlbl_domhsh_walk_arg *cb_arg = arg; 189fd385855SPaul Moore void *data; 190d15c345fSPaul Moore 19117c157c8SThomas Graf data = genlmsg_put(cb_arg->skb, NETLINK_CB(cb_arg->nl_cb->skb).pid, 19217c157c8SThomas Graf cb_arg->seq, &netlbl_mgmt_gnl_family, 19317c157c8SThomas Graf NLM_F_MULTI, NLBL_MGMT_C_LISTALL); 194fd385855SPaul Moore if (data == NULL) 195fd385855SPaul Moore goto listall_cb_failure; 196fd385855SPaul Moore 197fd385855SPaul Moore ret_val = nla_put_string(cb_arg->skb, 198fd385855SPaul Moore NLBL_MGMT_A_DOMAIN, 199fd385855SPaul Moore entry->domain); 200fd385855SPaul Moore if (ret_val != 0) 201fd385855SPaul Moore goto listall_cb_failure; 202fd385855SPaul Moore ret_val = nla_put_u32(cb_arg->skb, NLBL_MGMT_A_PROTOCOL, entry->type); 203fd385855SPaul Moore if (ret_val != 0) 204fd385855SPaul Moore goto listall_cb_failure; 205fd385855SPaul Moore switch (entry->type) { 206fd385855SPaul Moore case NETLBL_NLTYPE_CIPSOV4: 207fd385855SPaul Moore ret_val = nla_put_u32(cb_arg->skb, 208fd385855SPaul Moore NLBL_MGMT_A_CV4DOI, 209fd385855SPaul Moore entry->type_def.cipsov4->doi); 210fd385855SPaul Moore if (ret_val != 0) 211fd385855SPaul Moore goto listall_cb_failure; 212fd385855SPaul Moore break; 213fd385855SPaul Moore } 214fd385855SPaul Moore 215fd385855SPaul Moore cb_arg->seq++; 216fd385855SPaul Moore return genlmsg_end(cb_arg->skb, data); 217fd385855SPaul Moore 218fd385855SPaul Moore listall_cb_failure: 219fd385855SPaul Moore genlmsg_cancel(cb_arg->skb, data); 220d15c345fSPaul Moore return ret_val; 221d15c345fSPaul Moore } 222d15c345fSPaul Moore 223d15c345fSPaul Moore /** 224fd385855SPaul Moore * netlbl_mgmt_listall - Handle a LISTALL message 225d15c345fSPaul Moore * @skb: the NETLINK buffer 226fd385855SPaul Moore * @cb: the NETLINK callback 227d15c345fSPaul Moore * 228d15c345fSPaul Moore * Description: 229fd385855SPaul Moore * Process a user generated LISTALL message and dumps the domain hash table in 230fd385855SPaul Moore * a form suitable for use in a kernel generated LISTALL message. Returns zero 231fd385855SPaul Moore * on success, negative values on failure. 232d15c345fSPaul Moore * 233d15c345fSPaul Moore */ 234fd385855SPaul Moore static int netlbl_mgmt_listall(struct sk_buff *skb, 235fd385855SPaul Moore struct netlink_callback *cb) 236d15c345fSPaul Moore { 237fd385855SPaul Moore struct netlbl_domhsh_walk_arg cb_arg; 238fd385855SPaul Moore u32 skip_bkt = cb->args[0]; 239fd385855SPaul Moore u32 skip_chain = cb->args[1]; 240d15c345fSPaul Moore 241fd385855SPaul Moore cb_arg.nl_cb = cb; 242fd385855SPaul Moore cb_arg.skb = skb; 243fd385855SPaul Moore cb_arg.seq = cb->nlh->nlmsg_seq; 244d15c345fSPaul Moore 245fd385855SPaul Moore netlbl_domhsh_walk(&skip_bkt, 246fd385855SPaul Moore &skip_chain, 247fd385855SPaul Moore netlbl_mgmt_listall_cb, 248fd385855SPaul Moore &cb_arg); 249d15c345fSPaul Moore 250fd385855SPaul Moore cb->args[0] = skip_bkt; 251fd385855SPaul Moore cb->args[1] = skip_chain; 252fd385855SPaul Moore return skb->len; 253d15c345fSPaul Moore } 254d15c345fSPaul Moore 255d15c345fSPaul Moore /** 256d15c345fSPaul Moore * netlbl_mgmt_adddef - Handle an ADDDEF message 257d15c345fSPaul Moore * @skb: the NETLINK buffer 258d15c345fSPaul Moore * @info: the Generic NETLINK info block 259d15c345fSPaul Moore * 260d15c345fSPaul Moore * Description: 261d15c345fSPaul Moore * Process a user generated ADDDEF message and respond accordingly. Returns 262d15c345fSPaul Moore * zero on success, negative values on failure. 263d15c345fSPaul Moore * 264d15c345fSPaul Moore */ 265d15c345fSPaul Moore static int netlbl_mgmt_adddef(struct sk_buff *skb, struct genl_info *info) 266d15c345fSPaul Moore { 267d15c345fSPaul Moore int ret_val = -EINVAL; 268d15c345fSPaul Moore struct netlbl_dom_map *entry = NULL; 269d15c345fSPaul Moore u32 tmp_val; 27095d4e6beSPaul Moore struct netlbl_audit audit_info; 271d15c345fSPaul Moore 272fd385855SPaul Moore if (!info->attrs[NLBL_MGMT_A_PROTOCOL]) 273d15c345fSPaul Moore goto adddef_failure; 274d15c345fSPaul Moore 27595d4e6beSPaul Moore netlbl_netlink_auditinfo(skb, &audit_info); 27695d4e6beSPaul Moore 277d15c345fSPaul Moore entry = kzalloc(sizeof(*entry), GFP_KERNEL); 278d15c345fSPaul Moore if (entry == NULL) { 279d15c345fSPaul Moore ret_val = -ENOMEM; 280d15c345fSPaul Moore goto adddef_failure; 281d15c345fSPaul Moore } 282fd385855SPaul Moore entry->type = nla_get_u32(info->attrs[NLBL_MGMT_A_PROTOCOL]); 283d15c345fSPaul Moore 284d15c345fSPaul Moore switch (entry->type) { 285d15c345fSPaul Moore case NETLBL_NLTYPE_UNLABELED: 28695d4e6beSPaul Moore ret_val = netlbl_domhsh_add_default(entry, &audit_info); 287d15c345fSPaul Moore break; 288d15c345fSPaul Moore case NETLBL_NLTYPE_CIPSOV4: 289fd385855SPaul Moore if (!info->attrs[NLBL_MGMT_A_CV4DOI]) 290d15c345fSPaul Moore goto adddef_failure; 291fd385855SPaul Moore 292fd385855SPaul Moore tmp_val = nla_get_u32(info->attrs[NLBL_MGMT_A_CV4DOI]); 293fd385855SPaul Moore /* We should be holding a rcu_read_lock() here while we hold 294fd385855SPaul Moore * the result but since the entry will always be deleted when 295fd385855SPaul Moore * the CIPSO DOI is deleted we aren't going to keep the 296fd385855SPaul Moore * lock. */ 297d15c345fSPaul Moore rcu_read_lock(); 298d15c345fSPaul Moore entry->type_def.cipsov4 = cipso_v4_doi_getdef(tmp_val); 299d15c345fSPaul Moore if (entry->type_def.cipsov4 == NULL) { 300d15c345fSPaul Moore rcu_read_unlock(); 301d15c345fSPaul Moore goto adddef_failure; 302d15c345fSPaul Moore } 30395d4e6beSPaul Moore ret_val = netlbl_domhsh_add_default(entry, &audit_info); 304d15c345fSPaul Moore rcu_read_unlock(); 305d15c345fSPaul Moore break; 306d15c345fSPaul Moore default: 307fd385855SPaul Moore goto adddef_failure; 308d15c345fSPaul Moore } 309d15c345fSPaul Moore if (ret_val != 0) 310d15c345fSPaul Moore goto adddef_failure; 311d15c345fSPaul Moore 312d15c345fSPaul Moore return 0; 313d15c345fSPaul Moore 314d15c345fSPaul Moore adddef_failure: 315d15c345fSPaul Moore kfree(entry); 316d15c345fSPaul Moore return ret_val; 317d15c345fSPaul Moore } 318d15c345fSPaul Moore 319d15c345fSPaul Moore /** 320d15c345fSPaul Moore * netlbl_mgmt_removedef - Handle a REMOVEDEF message 321d15c345fSPaul Moore * @skb: the NETLINK buffer 322d15c345fSPaul Moore * @info: the Generic NETLINK info block 323d15c345fSPaul Moore * 324d15c345fSPaul Moore * Description: 325d15c345fSPaul Moore * Process a user generated REMOVEDEF message and remove the default domain 326d15c345fSPaul Moore * mapping. Returns zero on success, negative values on failure. 327d15c345fSPaul Moore * 328d15c345fSPaul Moore */ 329d15c345fSPaul Moore static int netlbl_mgmt_removedef(struct sk_buff *skb, struct genl_info *info) 330d15c345fSPaul Moore { 33195d4e6beSPaul Moore struct netlbl_audit audit_info; 33295d4e6beSPaul Moore 33395d4e6beSPaul Moore netlbl_netlink_auditinfo(skb, &audit_info); 33495d4e6beSPaul Moore 33595d4e6beSPaul Moore return netlbl_domhsh_remove_default(&audit_info); 336d15c345fSPaul Moore } 337d15c345fSPaul Moore 338d15c345fSPaul Moore /** 339d15c345fSPaul Moore * netlbl_mgmt_listdef - Handle a LISTDEF message 340d15c345fSPaul Moore * @skb: the NETLINK buffer 341d15c345fSPaul Moore * @info: the Generic NETLINK info block 342d15c345fSPaul Moore * 343d15c345fSPaul Moore * Description: 344d15c345fSPaul Moore * Process a user generated LISTDEF message and dumps the default domain 345d15c345fSPaul Moore * mapping in a form suitable for use in a kernel generated LISTDEF message. 346d15c345fSPaul Moore * Returns zero on success, negative values on failure. 347d15c345fSPaul Moore * 348d15c345fSPaul Moore */ 349d15c345fSPaul Moore static int netlbl_mgmt_listdef(struct sk_buff *skb, struct genl_info *info) 350d15c345fSPaul Moore { 351d15c345fSPaul Moore int ret_val = -ENOMEM; 352fd385855SPaul Moore struct sk_buff *ans_skb = NULL; 353fd385855SPaul Moore void *data; 354fd385855SPaul Moore struct netlbl_dom_map *entry; 355d15c345fSPaul Moore 356339bf98fSThomas Graf ans_skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); 357d15c345fSPaul Moore if (ans_skb == NULL) 358fd385855SPaul Moore return -ENOMEM; 35917c157c8SThomas Graf data = genlmsg_put_reply(ans_skb, info, &netlbl_mgmt_gnl_family, 36017c157c8SThomas Graf 0, NLBL_MGMT_C_LISTDEF); 361fd385855SPaul Moore if (data == NULL) 362fd385855SPaul Moore goto listdef_failure; 363d15c345fSPaul Moore 364fd385855SPaul Moore rcu_read_lock(); 365fd385855SPaul Moore entry = netlbl_domhsh_getentry(NULL); 366fd385855SPaul Moore if (entry == NULL) { 367fd385855SPaul Moore ret_val = -ENOENT; 368fd385855SPaul Moore goto listdef_failure_lock; 369fd385855SPaul Moore } 370fd385855SPaul Moore ret_val = nla_put_u32(ans_skb, NLBL_MGMT_A_PROTOCOL, entry->type); 371fd385855SPaul Moore if (ret_val != 0) 372fd385855SPaul Moore goto listdef_failure_lock; 373fd385855SPaul Moore switch (entry->type) { 374fd385855SPaul Moore case NETLBL_NLTYPE_CIPSOV4: 375fd385855SPaul Moore ret_val = nla_put_u32(ans_skb, 376fd385855SPaul Moore NLBL_MGMT_A_CV4DOI, 377fd385855SPaul Moore entry->type_def.cipsov4->doi); 378fd385855SPaul Moore if (ret_val != 0) 379fd385855SPaul Moore goto listdef_failure_lock; 380fd385855SPaul Moore break; 381fd385855SPaul Moore } 382fd385855SPaul Moore rcu_read_unlock(); 383fd385855SPaul Moore 384fd385855SPaul Moore genlmsg_end(ans_skb, data); 385fd385855SPaul Moore 38681878d27SThomas Graf ret_val = genlmsg_reply(ans_skb, info); 387d15c345fSPaul Moore if (ret_val != 0) 388d15c345fSPaul Moore goto listdef_failure; 389d15c345fSPaul Moore return 0; 390d15c345fSPaul Moore 391fd385855SPaul Moore listdef_failure_lock: 392fd385855SPaul Moore rcu_read_unlock(); 393d15c345fSPaul Moore listdef_failure: 394fd385855SPaul Moore kfree_skb(ans_skb); 395d15c345fSPaul Moore return ret_val; 396d15c345fSPaul Moore } 397d15c345fSPaul Moore 398d15c345fSPaul Moore /** 399fd385855SPaul Moore * netlbl_mgmt_protocols_cb - Write an individual PROTOCOL message response 400fd385855SPaul Moore * @skb: the skb to write to 401fd385855SPaul Moore * @seq: the NETLINK sequence number 402fd385855SPaul Moore * @cb: the NETLINK callback 403fd385855SPaul Moore * @protocol: the NetLabel protocol to use in the message 404d15c345fSPaul Moore * 405d15c345fSPaul Moore * Description: 406fd385855SPaul Moore * This function is to be used in conjunction with netlbl_mgmt_protocols() to 407fd385855SPaul Moore * answer a application's PROTOCOLS message. Returns the size of the message 408fd385855SPaul Moore * on success, negative values on failure. 409d15c345fSPaul Moore * 410d15c345fSPaul Moore */ 411fd385855SPaul Moore static int netlbl_mgmt_protocols_cb(struct sk_buff *skb, 412fd385855SPaul Moore struct netlink_callback *cb, 413fd385855SPaul Moore u32 protocol) 414d15c345fSPaul Moore { 415d15c345fSPaul Moore int ret_val = -ENOMEM; 416fd385855SPaul Moore void *data; 417d15c345fSPaul Moore 41817c157c8SThomas Graf data = genlmsg_put(skb, NETLINK_CB(cb->skb).pid, cb->nlh->nlmsg_seq, 41917c157c8SThomas Graf &netlbl_mgmt_gnl_family, NLM_F_MULTI, 420fd385855SPaul Moore NLBL_MGMT_C_PROTOCOLS); 421fd385855SPaul Moore if (data == NULL) 422fd385855SPaul Moore goto protocols_cb_failure; 423d15c345fSPaul Moore 424fd385855SPaul Moore ret_val = nla_put_u32(skb, NLBL_MGMT_A_PROTOCOL, protocol); 425d15c345fSPaul Moore if (ret_val != 0) 426fd385855SPaul Moore goto protocols_cb_failure; 427d15c345fSPaul Moore 428fd385855SPaul Moore return genlmsg_end(skb, data); 429d15c345fSPaul Moore 430fd385855SPaul Moore protocols_cb_failure: 431fd385855SPaul Moore genlmsg_cancel(skb, data); 432d15c345fSPaul Moore return ret_val; 433d15c345fSPaul Moore } 434d15c345fSPaul Moore 435d15c345fSPaul Moore /** 436fd385855SPaul Moore * netlbl_mgmt_protocols - Handle a PROTOCOLS message 437fd385855SPaul Moore * @skb: the NETLINK buffer 438fd385855SPaul Moore * @cb: the NETLINK callback 439fd385855SPaul Moore * 440fd385855SPaul Moore * Description: 441fd385855SPaul Moore * Process a user generated PROTOCOLS message and respond accordingly. 442fd385855SPaul Moore * 443fd385855SPaul Moore */ 444fd385855SPaul Moore static int netlbl_mgmt_protocols(struct sk_buff *skb, 445fd385855SPaul Moore struct netlink_callback *cb) 446fd385855SPaul Moore { 447fd385855SPaul Moore u32 protos_sent = cb->args[0]; 448fd385855SPaul Moore 449fd385855SPaul Moore if (protos_sent == 0) { 450fd385855SPaul Moore if (netlbl_mgmt_protocols_cb(skb, 451fd385855SPaul Moore cb, 452fd385855SPaul Moore NETLBL_NLTYPE_UNLABELED) < 0) 453fd385855SPaul Moore goto protocols_return; 454fd385855SPaul Moore protos_sent++; 455fd385855SPaul Moore } 456fd385855SPaul Moore if (protos_sent == 1) { 457fd385855SPaul Moore if (netlbl_mgmt_protocols_cb(skb, 458fd385855SPaul Moore cb, 459fd385855SPaul Moore NETLBL_NLTYPE_CIPSOV4) < 0) 460fd385855SPaul Moore goto protocols_return; 461fd385855SPaul Moore protos_sent++; 462fd385855SPaul Moore } 463fd385855SPaul Moore 464fd385855SPaul Moore protocols_return: 465fd385855SPaul Moore cb->args[0] = protos_sent; 466fd385855SPaul Moore return skb->len; 467fd385855SPaul Moore } 468fd385855SPaul Moore 469fd385855SPaul Moore /** 470d15c345fSPaul Moore * netlbl_mgmt_version - Handle a VERSION message 471d15c345fSPaul Moore * @skb: the NETLINK buffer 472d15c345fSPaul Moore * @info: the Generic NETLINK info block 473d15c345fSPaul Moore * 474d15c345fSPaul Moore * Description: 475d15c345fSPaul Moore * Process a user generated VERSION message and respond accordingly. Returns 476d15c345fSPaul Moore * zero on success, negative values on failure. 477d15c345fSPaul Moore * 478d15c345fSPaul Moore */ 479d15c345fSPaul Moore static int netlbl_mgmt_version(struct sk_buff *skb, struct genl_info *info) 480d15c345fSPaul Moore { 481d15c345fSPaul Moore int ret_val = -ENOMEM; 482d15c345fSPaul Moore struct sk_buff *ans_skb = NULL; 483fd385855SPaul Moore void *data; 484d15c345fSPaul Moore 485339bf98fSThomas Graf ans_skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); 486d15c345fSPaul Moore if (ans_skb == NULL) 487fd385855SPaul Moore return -ENOMEM; 48817c157c8SThomas Graf data = genlmsg_put_reply(ans_skb, info, &netlbl_mgmt_gnl_family, 48917c157c8SThomas Graf 0, NLBL_MGMT_C_VERSION); 490fd385855SPaul Moore if (data == NULL) 491d15c345fSPaul Moore goto version_failure; 492d15c345fSPaul Moore 493fd385855SPaul Moore ret_val = nla_put_u32(ans_skb, 494fd385855SPaul Moore NLBL_MGMT_A_VERSION, 495fd385855SPaul Moore NETLBL_PROTO_VERSION); 496d15c345fSPaul Moore if (ret_val != 0) 497d15c345fSPaul Moore goto version_failure; 498d15c345fSPaul Moore 499fd385855SPaul Moore genlmsg_end(ans_skb, data); 500fd385855SPaul Moore 50181878d27SThomas Graf ret_val = genlmsg_reply(ans_skb, info); 502d15c345fSPaul Moore if (ret_val != 0) 503d15c345fSPaul Moore goto version_failure; 504d15c345fSPaul Moore return 0; 505d15c345fSPaul Moore 506d15c345fSPaul Moore version_failure: 507d15c345fSPaul Moore kfree_skb(ans_skb); 508d15c345fSPaul Moore return ret_val; 509d15c345fSPaul Moore } 510d15c345fSPaul Moore 511d15c345fSPaul Moore 512d15c345fSPaul Moore /* 513d15c345fSPaul Moore * NetLabel Generic NETLINK Command Definitions 514d15c345fSPaul Moore */ 515d15c345fSPaul Moore 516d15c345fSPaul Moore static struct genl_ops netlbl_mgmt_genl_c_add = { 517d15c345fSPaul Moore .cmd = NLBL_MGMT_C_ADD, 518fd385855SPaul Moore .flags = GENL_ADMIN_PERM, 519fd385855SPaul Moore .policy = netlbl_mgmt_genl_policy, 520d15c345fSPaul Moore .doit = netlbl_mgmt_add, 521d15c345fSPaul Moore .dumpit = NULL, 522d15c345fSPaul Moore }; 523d15c345fSPaul Moore 524d15c345fSPaul Moore static struct genl_ops netlbl_mgmt_genl_c_remove = { 525d15c345fSPaul Moore .cmd = NLBL_MGMT_C_REMOVE, 526fd385855SPaul Moore .flags = GENL_ADMIN_PERM, 527fd385855SPaul Moore .policy = netlbl_mgmt_genl_policy, 528d15c345fSPaul Moore .doit = netlbl_mgmt_remove, 529d15c345fSPaul Moore .dumpit = NULL, 530d15c345fSPaul Moore }; 531d15c345fSPaul Moore 532fd385855SPaul Moore static struct genl_ops netlbl_mgmt_genl_c_listall = { 533fd385855SPaul Moore .cmd = NLBL_MGMT_C_LISTALL, 534d15c345fSPaul Moore .flags = 0, 535fd385855SPaul Moore .policy = netlbl_mgmt_genl_policy, 536fd385855SPaul Moore .doit = NULL, 537fd385855SPaul Moore .dumpit = netlbl_mgmt_listall, 538d15c345fSPaul Moore }; 539d15c345fSPaul Moore 540d15c345fSPaul Moore static struct genl_ops netlbl_mgmt_genl_c_adddef = { 541d15c345fSPaul Moore .cmd = NLBL_MGMT_C_ADDDEF, 542fd385855SPaul Moore .flags = GENL_ADMIN_PERM, 543fd385855SPaul Moore .policy = netlbl_mgmt_genl_policy, 544d15c345fSPaul Moore .doit = netlbl_mgmt_adddef, 545d15c345fSPaul Moore .dumpit = NULL, 546d15c345fSPaul Moore }; 547d15c345fSPaul Moore 548d15c345fSPaul Moore static struct genl_ops netlbl_mgmt_genl_c_removedef = { 549d15c345fSPaul Moore .cmd = NLBL_MGMT_C_REMOVEDEF, 550fd385855SPaul Moore .flags = GENL_ADMIN_PERM, 551fd385855SPaul Moore .policy = netlbl_mgmt_genl_policy, 552d15c345fSPaul Moore .doit = netlbl_mgmt_removedef, 553d15c345fSPaul Moore .dumpit = NULL, 554d15c345fSPaul Moore }; 555d15c345fSPaul Moore 556d15c345fSPaul Moore static struct genl_ops netlbl_mgmt_genl_c_listdef = { 557d15c345fSPaul Moore .cmd = NLBL_MGMT_C_LISTDEF, 558d15c345fSPaul Moore .flags = 0, 559fd385855SPaul Moore .policy = netlbl_mgmt_genl_policy, 560d15c345fSPaul Moore .doit = netlbl_mgmt_listdef, 561d15c345fSPaul Moore .dumpit = NULL, 562d15c345fSPaul Moore }; 563d15c345fSPaul Moore 564fd385855SPaul Moore static struct genl_ops netlbl_mgmt_genl_c_protocols = { 565fd385855SPaul Moore .cmd = NLBL_MGMT_C_PROTOCOLS, 566d15c345fSPaul Moore .flags = 0, 567fd385855SPaul Moore .policy = netlbl_mgmt_genl_policy, 568fd385855SPaul Moore .doit = NULL, 569fd385855SPaul Moore .dumpit = netlbl_mgmt_protocols, 570d15c345fSPaul Moore }; 571d15c345fSPaul Moore 572d15c345fSPaul Moore static struct genl_ops netlbl_mgmt_genl_c_version = { 573d15c345fSPaul Moore .cmd = NLBL_MGMT_C_VERSION, 574d15c345fSPaul Moore .flags = 0, 575fd385855SPaul Moore .policy = netlbl_mgmt_genl_policy, 576d15c345fSPaul Moore .doit = netlbl_mgmt_version, 577d15c345fSPaul Moore .dumpit = NULL, 578d15c345fSPaul Moore }; 579d15c345fSPaul Moore 580d15c345fSPaul Moore /* 581d15c345fSPaul Moore * NetLabel Generic NETLINK Protocol Functions 582d15c345fSPaul Moore */ 583d15c345fSPaul Moore 584d15c345fSPaul Moore /** 585d15c345fSPaul Moore * netlbl_mgmt_genl_init - Register the NetLabel management component 586d15c345fSPaul Moore * 587d15c345fSPaul Moore * Description: 588d15c345fSPaul Moore * Register the NetLabel management component with the Generic NETLINK 589d15c345fSPaul Moore * mechanism. Returns zero on success, negative values on failure. 590d15c345fSPaul Moore * 591d15c345fSPaul Moore */ 592d15c345fSPaul Moore int netlbl_mgmt_genl_init(void) 593d15c345fSPaul Moore { 594d15c345fSPaul Moore int ret_val; 595d15c345fSPaul Moore 596d15c345fSPaul Moore ret_val = genl_register_family(&netlbl_mgmt_gnl_family); 597d15c345fSPaul Moore if (ret_val != 0) 598d15c345fSPaul Moore return ret_val; 599d15c345fSPaul Moore 600d15c345fSPaul Moore ret_val = genl_register_ops(&netlbl_mgmt_gnl_family, 601d15c345fSPaul Moore &netlbl_mgmt_genl_c_add); 602d15c345fSPaul Moore if (ret_val != 0) 603d15c345fSPaul Moore return ret_val; 604d15c345fSPaul Moore ret_val = genl_register_ops(&netlbl_mgmt_gnl_family, 605d15c345fSPaul Moore &netlbl_mgmt_genl_c_remove); 606d15c345fSPaul Moore if (ret_val != 0) 607d15c345fSPaul Moore return ret_val; 608d15c345fSPaul Moore ret_val = genl_register_ops(&netlbl_mgmt_gnl_family, 609fd385855SPaul Moore &netlbl_mgmt_genl_c_listall); 610d15c345fSPaul Moore if (ret_val != 0) 611d15c345fSPaul Moore return ret_val; 612d15c345fSPaul Moore ret_val = genl_register_ops(&netlbl_mgmt_gnl_family, 613d15c345fSPaul Moore &netlbl_mgmt_genl_c_adddef); 614d15c345fSPaul Moore if (ret_val != 0) 615d15c345fSPaul Moore return ret_val; 616d15c345fSPaul Moore ret_val = genl_register_ops(&netlbl_mgmt_gnl_family, 617d15c345fSPaul Moore &netlbl_mgmt_genl_c_removedef); 618d15c345fSPaul Moore if (ret_val != 0) 619d15c345fSPaul Moore return ret_val; 620d15c345fSPaul Moore ret_val = genl_register_ops(&netlbl_mgmt_gnl_family, 621d15c345fSPaul Moore &netlbl_mgmt_genl_c_listdef); 622d15c345fSPaul Moore if (ret_val != 0) 623d15c345fSPaul Moore return ret_val; 624d15c345fSPaul Moore ret_val = genl_register_ops(&netlbl_mgmt_gnl_family, 625fd385855SPaul Moore &netlbl_mgmt_genl_c_protocols); 626d15c345fSPaul Moore if (ret_val != 0) 627d15c345fSPaul Moore return ret_val; 628d15c345fSPaul Moore ret_val = genl_register_ops(&netlbl_mgmt_gnl_family, 629d15c345fSPaul Moore &netlbl_mgmt_genl_c_version); 630d15c345fSPaul Moore if (ret_val != 0) 631d15c345fSPaul Moore return ret_val; 632d15c345fSPaul Moore 633d15c345fSPaul Moore return 0; 634d15c345fSPaul Moore } 635