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 */ 62fd385855SPaul Moore static 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 191fd385855SPaul Moore data = netlbl_netlink_hdr_put(cb_arg->skb, 192fd385855SPaul Moore NETLINK_CB(cb_arg->nl_cb->skb).pid, 193fd385855SPaul Moore cb_arg->seq, 194d15c345fSPaul Moore netlbl_mgmt_gnl_family.id, 195fd385855SPaul Moore NLM_F_MULTI, 196fd385855SPaul Moore NLBL_MGMT_C_LISTALL); 197fd385855SPaul Moore if (data == NULL) 198fd385855SPaul Moore goto listall_cb_failure; 199fd385855SPaul Moore 200fd385855SPaul Moore ret_val = nla_put_string(cb_arg->skb, 201fd385855SPaul Moore NLBL_MGMT_A_DOMAIN, 202fd385855SPaul Moore entry->domain); 203fd385855SPaul Moore if (ret_val != 0) 204fd385855SPaul Moore goto listall_cb_failure; 205fd385855SPaul Moore ret_val = nla_put_u32(cb_arg->skb, NLBL_MGMT_A_PROTOCOL, entry->type); 206fd385855SPaul Moore if (ret_val != 0) 207fd385855SPaul Moore goto listall_cb_failure; 208fd385855SPaul Moore switch (entry->type) { 209fd385855SPaul Moore case NETLBL_NLTYPE_CIPSOV4: 210fd385855SPaul Moore ret_val = nla_put_u32(cb_arg->skb, 211fd385855SPaul Moore NLBL_MGMT_A_CV4DOI, 212fd385855SPaul Moore entry->type_def.cipsov4->doi); 213fd385855SPaul Moore if (ret_val != 0) 214fd385855SPaul Moore goto listall_cb_failure; 215fd385855SPaul Moore break; 216fd385855SPaul Moore } 217fd385855SPaul Moore 218fd385855SPaul Moore cb_arg->seq++; 219fd385855SPaul Moore return genlmsg_end(cb_arg->skb, data); 220fd385855SPaul Moore 221fd385855SPaul Moore listall_cb_failure: 222fd385855SPaul Moore genlmsg_cancel(cb_arg->skb, data); 223d15c345fSPaul Moore return ret_val; 224d15c345fSPaul Moore } 225d15c345fSPaul Moore 226d15c345fSPaul Moore /** 227fd385855SPaul Moore * netlbl_mgmt_listall - Handle a LISTALL message 228d15c345fSPaul Moore * @skb: the NETLINK buffer 229fd385855SPaul Moore * @cb: the NETLINK callback 230d15c345fSPaul Moore * 231d15c345fSPaul Moore * Description: 232fd385855SPaul Moore * Process a user generated LISTALL message and dumps the domain hash table in 233fd385855SPaul Moore * a form suitable for use in a kernel generated LISTALL message. Returns zero 234fd385855SPaul Moore * on success, negative values on failure. 235d15c345fSPaul Moore * 236d15c345fSPaul Moore */ 237fd385855SPaul Moore static int netlbl_mgmt_listall(struct sk_buff *skb, 238fd385855SPaul Moore struct netlink_callback *cb) 239d15c345fSPaul Moore { 240fd385855SPaul Moore struct netlbl_domhsh_walk_arg cb_arg; 241fd385855SPaul Moore u32 skip_bkt = cb->args[0]; 242fd385855SPaul Moore u32 skip_chain = cb->args[1]; 243d15c345fSPaul Moore 244fd385855SPaul Moore cb_arg.nl_cb = cb; 245fd385855SPaul Moore cb_arg.skb = skb; 246fd385855SPaul Moore cb_arg.seq = cb->nlh->nlmsg_seq; 247d15c345fSPaul Moore 248fd385855SPaul Moore netlbl_domhsh_walk(&skip_bkt, 249fd385855SPaul Moore &skip_chain, 250fd385855SPaul Moore netlbl_mgmt_listall_cb, 251fd385855SPaul Moore &cb_arg); 252d15c345fSPaul Moore 253fd385855SPaul Moore cb->args[0] = skip_bkt; 254fd385855SPaul Moore cb->args[1] = skip_chain; 255fd385855SPaul Moore return skb->len; 256d15c345fSPaul Moore } 257d15c345fSPaul Moore 258d15c345fSPaul Moore /** 259d15c345fSPaul Moore * netlbl_mgmt_adddef - Handle an ADDDEF message 260d15c345fSPaul Moore * @skb: the NETLINK buffer 261d15c345fSPaul Moore * @info: the Generic NETLINK info block 262d15c345fSPaul Moore * 263d15c345fSPaul Moore * Description: 264d15c345fSPaul Moore * Process a user generated ADDDEF message and respond accordingly. Returns 265d15c345fSPaul Moore * zero on success, negative values on failure. 266d15c345fSPaul Moore * 267d15c345fSPaul Moore */ 268d15c345fSPaul Moore static int netlbl_mgmt_adddef(struct sk_buff *skb, struct genl_info *info) 269d15c345fSPaul Moore { 270d15c345fSPaul Moore int ret_val = -EINVAL; 271d15c345fSPaul Moore struct netlbl_dom_map *entry = NULL; 272d15c345fSPaul Moore u32 tmp_val; 27395d4e6beSPaul Moore struct netlbl_audit audit_info; 274d15c345fSPaul Moore 275fd385855SPaul Moore if (!info->attrs[NLBL_MGMT_A_PROTOCOL]) 276d15c345fSPaul Moore goto adddef_failure; 277d15c345fSPaul Moore 27895d4e6beSPaul Moore netlbl_netlink_auditinfo(skb, &audit_info); 27995d4e6beSPaul Moore 280d15c345fSPaul Moore entry = kzalloc(sizeof(*entry), GFP_KERNEL); 281d15c345fSPaul Moore if (entry == NULL) { 282d15c345fSPaul Moore ret_val = -ENOMEM; 283d15c345fSPaul Moore goto adddef_failure; 284d15c345fSPaul Moore } 285fd385855SPaul Moore entry->type = nla_get_u32(info->attrs[NLBL_MGMT_A_PROTOCOL]); 286d15c345fSPaul Moore 287d15c345fSPaul Moore switch (entry->type) { 288d15c345fSPaul Moore case NETLBL_NLTYPE_UNLABELED: 28995d4e6beSPaul Moore ret_val = netlbl_domhsh_add_default(entry, &audit_info); 290d15c345fSPaul Moore break; 291d15c345fSPaul Moore case NETLBL_NLTYPE_CIPSOV4: 292fd385855SPaul Moore if (!info->attrs[NLBL_MGMT_A_CV4DOI]) 293d15c345fSPaul Moore goto adddef_failure; 294fd385855SPaul Moore 295fd385855SPaul Moore tmp_val = nla_get_u32(info->attrs[NLBL_MGMT_A_CV4DOI]); 296fd385855SPaul Moore /* We should be holding a rcu_read_lock() here while we hold 297fd385855SPaul Moore * the result but since the entry will always be deleted when 298fd385855SPaul Moore * the CIPSO DOI is deleted we aren't going to keep the 299fd385855SPaul Moore * lock. */ 300d15c345fSPaul Moore rcu_read_lock(); 301d15c345fSPaul Moore entry->type_def.cipsov4 = cipso_v4_doi_getdef(tmp_val); 302d15c345fSPaul Moore if (entry->type_def.cipsov4 == NULL) { 303d15c345fSPaul Moore rcu_read_unlock(); 304d15c345fSPaul Moore goto adddef_failure; 305d15c345fSPaul Moore } 30695d4e6beSPaul Moore ret_val = netlbl_domhsh_add_default(entry, &audit_info); 307d15c345fSPaul Moore rcu_read_unlock(); 308d15c345fSPaul Moore break; 309d15c345fSPaul Moore default: 310fd385855SPaul Moore goto adddef_failure; 311d15c345fSPaul Moore } 312d15c345fSPaul Moore if (ret_val != 0) 313d15c345fSPaul Moore goto adddef_failure; 314d15c345fSPaul Moore 315d15c345fSPaul Moore return 0; 316d15c345fSPaul Moore 317d15c345fSPaul Moore adddef_failure: 318d15c345fSPaul Moore kfree(entry); 319d15c345fSPaul Moore return ret_val; 320d15c345fSPaul Moore } 321d15c345fSPaul Moore 322d15c345fSPaul Moore /** 323d15c345fSPaul Moore * netlbl_mgmt_removedef - Handle a REMOVEDEF message 324d15c345fSPaul Moore * @skb: the NETLINK buffer 325d15c345fSPaul Moore * @info: the Generic NETLINK info block 326d15c345fSPaul Moore * 327d15c345fSPaul Moore * Description: 328d15c345fSPaul Moore * Process a user generated REMOVEDEF message and remove the default domain 329d15c345fSPaul Moore * mapping. Returns zero on success, negative values on failure. 330d15c345fSPaul Moore * 331d15c345fSPaul Moore */ 332d15c345fSPaul Moore static int netlbl_mgmt_removedef(struct sk_buff *skb, struct genl_info *info) 333d15c345fSPaul Moore { 33495d4e6beSPaul Moore struct netlbl_audit audit_info; 33595d4e6beSPaul Moore 33695d4e6beSPaul Moore netlbl_netlink_auditinfo(skb, &audit_info); 33795d4e6beSPaul Moore 33895d4e6beSPaul Moore return netlbl_domhsh_remove_default(&audit_info); 339d15c345fSPaul Moore } 340d15c345fSPaul Moore 341d15c345fSPaul Moore /** 342d15c345fSPaul Moore * netlbl_mgmt_listdef - Handle a LISTDEF message 343d15c345fSPaul Moore * @skb: the NETLINK buffer 344d15c345fSPaul Moore * @info: the Generic NETLINK info block 345d15c345fSPaul Moore * 346d15c345fSPaul Moore * Description: 347d15c345fSPaul Moore * Process a user generated LISTDEF message and dumps the default domain 348d15c345fSPaul Moore * mapping in a form suitable for use in a kernel generated LISTDEF message. 349d15c345fSPaul Moore * Returns zero on success, negative values on failure. 350d15c345fSPaul Moore * 351d15c345fSPaul Moore */ 352d15c345fSPaul Moore static int netlbl_mgmt_listdef(struct sk_buff *skb, struct genl_info *info) 353d15c345fSPaul Moore { 354d15c345fSPaul Moore int ret_val = -ENOMEM; 355fd385855SPaul Moore struct sk_buff *ans_skb = NULL; 356fd385855SPaul Moore void *data; 357fd385855SPaul Moore struct netlbl_dom_map *entry; 358d15c345fSPaul Moore 359fd385855SPaul Moore ans_skb = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); 360d15c345fSPaul Moore if (ans_skb == NULL) 361fd385855SPaul Moore return -ENOMEM; 362fd385855SPaul Moore data = netlbl_netlink_hdr_put(ans_skb, 363d15c345fSPaul Moore info->snd_pid, 364fd385855SPaul Moore info->snd_seq, 365d15c345fSPaul Moore netlbl_mgmt_gnl_family.id, 366fd385855SPaul Moore 0, 367d15c345fSPaul Moore NLBL_MGMT_C_LISTDEF); 368fd385855SPaul Moore if (data == NULL) 369fd385855SPaul Moore goto listdef_failure; 370d15c345fSPaul Moore 371fd385855SPaul Moore rcu_read_lock(); 372fd385855SPaul Moore entry = netlbl_domhsh_getentry(NULL); 373fd385855SPaul Moore if (entry == NULL) { 374fd385855SPaul Moore ret_val = -ENOENT; 375fd385855SPaul Moore goto listdef_failure_lock; 376fd385855SPaul Moore } 377fd385855SPaul Moore ret_val = nla_put_u32(ans_skb, NLBL_MGMT_A_PROTOCOL, entry->type); 378fd385855SPaul Moore if (ret_val != 0) 379fd385855SPaul Moore goto listdef_failure_lock; 380fd385855SPaul Moore switch (entry->type) { 381fd385855SPaul Moore case NETLBL_NLTYPE_CIPSOV4: 382fd385855SPaul Moore ret_val = nla_put_u32(ans_skb, 383fd385855SPaul Moore NLBL_MGMT_A_CV4DOI, 384fd385855SPaul Moore entry->type_def.cipsov4->doi); 385fd385855SPaul Moore if (ret_val != 0) 386fd385855SPaul Moore goto listdef_failure_lock; 387fd385855SPaul Moore break; 388fd385855SPaul Moore } 389fd385855SPaul Moore rcu_read_unlock(); 390fd385855SPaul Moore 391fd385855SPaul Moore genlmsg_end(ans_skb, data); 392fd385855SPaul Moore 393fd385855SPaul Moore ret_val = genlmsg_unicast(ans_skb, info->snd_pid); 394d15c345fSPaul Moore if (ret_val != 0) 395d15c345fSPaul Moore goto listdef_failure; 396d15c345fSPaul Moore return 0; 397d15c345fSPaul Moore 398fd385855SPaul Moore listdef_failure_lock: 399fd385855SPaul Moore rcu_read_unlock(); 400d15c345fSPaul Moore listdef_failure: 401fd385855SPaul Moore kfree_skb(ans_skb); 402d15c345fSPaul Moore return ret_val; 403d15c345fSPaul Moore } 404d15c345fSPaul Moore 405d15c345fSPaul Moore /** 406fd385855SPaul Moore * netlbl_mgmt_protocols_cb - Write an individual PROTOCOL message response 407fd385855SPaul Moore * @skb: the skb to write to 408fd385855SPaul Moore * @seq: the NETLINK sequence number 409fd385855SPaul Moore * @cb: the NETLINK callback 410fd385855SPaul Moore * @protocol: the NetLabel protocol to use in the message 411d15c345fSPaul Moore * 412d15c345fSPaul Moore * Description: 413fd385855SPaul Moore * This function is to be used in conjunction with netlbl_mgmt_protocols() to 414fd385855SPaul Moore * answer a application's PROTOCOLS message. Returns the size of the message 415fd385855SPaul Moore * on success, negative values on failure. 416d15c345fSPaul Moore * 417d15c345fSPaul Moore */ 418fd385855SPaul Moore static int netlbl_mgmt_protocols_cb(struct sk_buff *skb, 419fd385855SPaul Moore struct netlink_callback *cb, 420fd385855SPaul Moore u32 protocol) 421d15c345fSPaul Moore { 422d15c345fSPaul Moore int ret_val = -ENOMEM; 423fd385855SPaul Moore void *data; 424d15c345fSPaul Moore 425fd385855SPaul Moore data = netlbl_netlink_hdr_put(skb, 426fd385855SPaul Moore NETLINK_CB(cb->skb).pid, 427fd385855SPaul Moore cb->nlh->nlmsg_seq, 428d15c345fSPaul Moore netlbl_mgmt_gnl_family.id, 429fd385855SPaul Moore NLM_F_MULTI, 430fd385855SPaul Moore NLBL_MGMT_C_PROTOCOLS); 431fd385855SPaul Moore if (data == NULL) 432fd385855SPaul Moore goto protocols_cb_failure; 433d15c345fSPaul Moore 434fd385855SPaul Moore ret_val = nla_put_u32(skb, NLBL_MGMT_A_PROTOCOL, protocol); 435d15c345fSPaul Moore if (ret_val != 0) 436fd385855SPaul Moore goto protocols_cb_failure; 437d15c345fSPaul Moore 438fd385855SPaul Moore return genlmsg_end(skb, data); 439d15c345fSPaul Moore 440fd385855SPaul Moore protocols_cb_failure: 441fd385855SPaul Moore genlmsg_cancel(skb, data); 442d15c345fSPaul Moore return ret_val; 443d15c345fSPaul Moore } 444d15c345fSPaul Moore 445d15c345fSPaul Moore /** 446fd385855SPaul Moore * netlbl_mgmt_protocols - Handle a PROTOCOLS message 447fd385855SPaul Moore * @skb: the NETLINK buffer 448fd385855SPaul Moore * @cb: the NETLINK callback 449fd385855SPaul Moore * 450fd385855SPaul Moore * Description: 451fd385855SPaul Moore * Process a user generated PROTOCOLS message and respond accordingly. 452fd385855SPaul Moore * 453fd385855SPaul Moore */ 454fd385855SPaul Moore static int netlbl_mgmt_protocols(struct sk_buff *skb, 455fd385855SPaul Moore struct netlink_callback *cb) 456fd385855SPaul Moore { 457fd385855SPaul Moore u32 protos_sent = cb->args[0]; 458fd385855SPaul Moore 459fd385855SPaul Moore if (protos_sent == 0) { 460fd385855SPaul Moore if (netlbl_mgmt_protocols_cb(skb, 461fd385855SPaul Moore cb, 462fd385855SPaul Moore NETLBL_NLTYPE_UNLABELED) < 0) 463fd385855SPaul Moore goto protocols_return; 464fd385855SPaul Moore protos_sent++; 465fd385855SPaul Moore } 466fd385855SPaul Moore if (protos_sent == 1) { 467fd385855SPaul Moore if (netlbl_mgmt_protocols_cb(skb, 468fd385855SPaul Moore cb, 469fd385855SPaul Moore NETLBL_NLTYPE_CIPSOV4) < 0) 470fd385855SPaul Moore goto protocols_return; 471fd385855SPaul Moore protos_sent++; 472fd385855SPaul Moore } 473fd385855SPaul Moore 474fd385855SPaul Moore protocols_return: 475fd385855SPaul Moore cb->args[0] = protos_sent; 476fd385855SPaul Moore return skb->len; 477fd385855SPaul Moore } 478fd385855SPaul Moore 479fd385855SPaul Moore /** 480d15c345fSPaul Moore * netlbl_mgmt_version - Handle a VERSION message 481d15c345fSPaul Moore * @skb: the NETLINK buffer 482d15c345fSPaul Moore * @info: the Generic NETLINK info block 483d15c345fSPaul Moore * 484d15c345fSPaul Moore * Description: 485d15c345fSPaul Moore * Process a user generated VERSION message and respond accordingly. Returns 486d15c345fSPaul Moore * zero on success, negative values on failure. 487d15c345fSPaul Moore * 488d15c345fSPaul Moore */ 489d15c345fSPaul Moore static int netlbl_mgmt_version(struct sk_buff *skb, struct genl_info *info) 490d15c345fSPaul Moore { 491d15c345fSPaul Moore int ret_val = -ENOMEM; 492d15c345fSPaul Moore struct sk_buff *ans_skb = NULL; 493fd385855SPaul Moore void *data; 494d15c345fSPaul Moore 495fd385855SPaul Moore ans_skb = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); 496d15c345fSPaul Moore if (ans_skb == NULL) 497fd385855SPaul Moore return -ENOMEM; 498fd385855SPaul Moore data = netlbl_netlink_hdr_put(ans_skb, 499d15c345fSPaul Moore info->snd_pid, 500fd385855SPaul Moore info->snd_seq, 501d15c345fSPaul Moore netlbl_mgmt_gnl_family.id, 502fd385855SPaul Moore 0, 503fd385855SPaul Moore NLBL_MGMT_C_VERSION); 504fd385855SPaul Moore if (data == NULL) 505d15c345fSPaul Moore goto version_failure; 506d15c345fSPaul Moore 507fd385855SPaul Moore ret_val = nla_put_u32(ans_skb, 508fd385855SPaul Moore NLBL_MGMT_A_VERSION, 509fd385855SPaul Moore NETLBL_PROTO_VERSION); 510d15c345fSPaul Moore if (ret_val != 0) 511d15c345fSPaul Moore goto version_failure; 512d15c345fSPaul Moore 513fd385855SPaul Moore genlmsg_end(ans_skb, data); 514fd385855SPaul Moore 515fd385855SPaul Moore ret_val = genlmsg_unicast(ans_skb, info->snd_pid); 516d15c345fSPaul Moore if (ret_val != 0) 517d15c345fSPaul Moore goto version_failure; 518d15c345fSPaul Moore return 0; 519d15c345fSPaul Moore 520d15c345fSPaul Moore version_failure: 521d15c345fSPaul Moore kfree_skb(ans_skb); 522d15c345fSPaul Moore return ret_val; 523d15c345fSPaul Moore } 524d15c345fSPaul Moore 525d15c345fSPaul Moore 526d15c345fSPaul Moore /* 527d15c345fSPaul Moore * NetLabel Generic NETLINK Command Definitions 528d15c345fSPaul Moore */ 529d15c345fSPaul Moore 530d15c345fSPaul Moore static struct genl_ops netlbl_mgmt_genl_c_add = { 531d15c345fSPaul Moore .cmd = NLBL_MGMT_C_ADD, 532fd385855SPaul Moore .flags = GENL_ADMIN_PERM, 533fd385855SPaul Moore .policy = netlbl_mgmt_genl_policy, 534d15c345fSPaul Moore .doit = netlbl_mgmt_add, 535d15c345fSPaul Moore .dumpit = NULL, 536d15c345fSPaul Moore }; 537d15c345fSPaul Moore 538d15c345fSPaul Moore static struct genl_ops netlbl_mgmt_genl_c_remove = { 539d15c345fSPaul Moore .cmd = NLBL_MGMT_C_REMOVE, 540fd385855SPaul Moore .flags = GENL_ADMIN_PERM, 541fd385855SPaul Moore .policy = netlbl_mgmt_genl_policy, 542d15c345fSPaul Moore .doit = netlbl_mgmt_remove, 543d15c345fSPaul Moore .dumpit = NULL, 544d15c345fSPaul Moore }; 545d15c345fSPaul Moore 546fd385855SPaul Moore static struct genl_ops netlbl_mgmt_genl_c_listall = { 547fd385855SPaul Moore .cmd = NLBL_MGMT_C_LISTALL, 548d15c345fSPaul Moore .flags = 0, 549fd385855SPaul Moore .policy = netlbl_mgmt_genl_policy, 550fd385855SPaul Moore .doit = NULL, 551fd385855SPaul Moore .dumpit = netlbl_mgmt_listall, 552d15c345fSPaul Moore }; 553d15c345fSPaul Moore 554d15c345fSPaul Moore static struct genl_ops netlbl_mgmt_genl_c_adddef = { 555d15c345fSPaul Moore .cmd = NLBL_MGMT_C_ADDDEF, 556fd385855SPaul Moore .flags = GENL_ADMIN_PERM, 557fd385855SPaul Moore .policy = netlbl_mgmt_genl_policy, 558d15c345fSPaul Moore .doit = netlbl_mgmt_adddef, 559d15c345fSPaul Moore .dumpit = NULL, 560d15c345fSPaul Moore }; 561d15c345fSPaul Moore 562d15c345fSPaul Moore static struct genl_ops netlbl_mgmt_genl_c_removedef = { 563d15c345fSPaul Moore .cmd = NLBL_MGMT_C_REMOVEDEF, 564fd385855SPaul Moore .flags = GENL_ADMIN_PERM, 565fd385855SPaul Moore .policy = netlbl_mgmt_genl_policy, 566d15c345fSPaul Moore .doit = netlbl_mgmt_removedef, 567d15c345fSPaul Moore .dumpit = NULL, 568d15c345fSPaul Moore }; 569d15c345fSPaul Moore 570d15c345fSPaul Moore static struct genl_ops netlbl_mgmt_genl_c_listdef = { 571d15c345fSPaul Moore .cmd = NLBL_MGMT_C_LISTDEF, 572d15c345fSPaul Moore .flags = 0, 573fd385855SPaul Moore .policy = netlbl_mgmt_genl_policy, 574d15c345fSPaul Moore .doit = netlbl_mgmt_listdef, 575d15c345fSPaul Moore .dumpit = NULL, 576d15c345fSPaul Moore }; 577d15c345fSPaul Moore 578fd385855SPaul Moore static struct genl_ops netlbl_mgmt_genl_c_protocols = { 579fd385855SPaul Moore .cmd = NLBL_MGMT_C_PROTOCOLS, 580d15c345fSPaul Moore .flags = 0, 581fd385855SPaul Moore .policy = netlbl_mgmt_genl_policy, 582fd385855SPaul Moore .doit = NULL, 583fd385855SPaul Moore .dumpit = netlbl_mgmt_protocols, 584d15c345fSPaul Moore }; 585d15c345fSPaul Moore 586d15c345fSPaul Moore static struct genl_ops netlbl_mgmt_genl_c_version = { 587d15c345fSPaul Moore .cmd = NLBL_MGMT_C_VERSION, 588d15c345fSPaul Moore .flags = 0, 589fd385855SPaul Moore .policy = netlbl_mgmt_genl_policy, 590d15c345fSPaul Moore .doit = netlbl_mgmt_version, 591d15c345fSPaul Moore .dumpit = NULL, 592d15c345fSPaul Moore }; 593d15c345fSPaul Moore 594d15c345fSPaul Moore /* 595d15c345fSPaul Moore * NetLabel Generic NETLINK Protocol Functions 596d15c345fSPaul Moore */ 597d15c345fSPaul Moore 598d15c345fSPaul Moore /** 599d15c345fSPaul Moore * netlbl_mgmt_genl_init - Register the NetLabel management component 600d15c345fSPaul Moore * 601d15c345fSPaul Moore * Description: 602d15c345fSPaul Moore * Register the NetLabel management component with the Generic NETLINK 603d15c345fSPaul Moore * mechanism. Returns zero on success, negative values on failure. 604d15c345fSPaul Moore * 605d15c345fSPaul Moore */ 606d15c345fSPaul Moore int netlbl_mgmt_genl_init(void) 607d15c345fSPaul Moore { 608d15c345fSPaul Moore int ret_val; 609d15c345fSPaul Moore 610d15c345fSPaul Moore ret_val = genl_register_family(&netlbl_mgmt_gnl_family); 611d15c345fSPaul Moore if (ret_val != 0) 612d15c345fSPaul Moore return ret_val; 613d15c345fSPaul Moore 614d15c345fSPaul Moore ret_val = genl_register_ops(&netlbl_mgmt_gnl_family, 615d15c345fSPaul Moore &netlbl_mgmt_genl_c_add); 616d15c345fSPaul Moore if (ret_val != 0) 617d15c345fSPaul Moore return ret_val; 618d15c345fSPaul Moore ret_val = genl_register_ops(&netlbl_mgmt_gnl_family, 619d15c345fSPaul Moore &netlbl_mgmt_genl_c_remove); 620d15c345fSPaul Moore if (ret_val != 0) 621d15c345fSPaul Moore return ret_val; 622d15c345fSPaul Moore ret_val = genl_register_ops(&netlbl_mgmt_gnl_family, 623fd385855SPaul Moore &netlbl_mgmt_genl_c_listall); 624d15c345fSPaul Moore if (ret_val != 0) 625d15c345fSPaul Moore return ret_val; 626d15c345fSPaul Moore ret_val = genl_register_ops(&netlbl_mgmt_gnl_family, 627d15c345fSPaul Moore &netlbl_mgmt_genl_c_adddef); 628d15c345fSPaul Moore if (ret_val != 0) 629d15c345fSPaul Moore return ret_val; 630d15c345fSPaul Moore ret_val = genl_register_ops(&netlbl_mgmt_gnl_family, 631d15c345fSPaul Moore &netlbl_mgmt_genl_c_removedef); 632d15c345fSPaul Moore if (ret_val != 0) 633d15c345fSPaul Moore return ret_val; 634d15c345fSPaul Moore ret_val = genl_register_ops(&netlbl_mgmt_gnl_family, 635d15c345fSPaul Moore &netlbl_mgmt_genl_c_listdef); 636d15c345fSPaul Moore if (ret_val != 0) 637d15c345fSPaul Moore return ret_val; 638d15c345fSPaul Moore ret_val = genl_register_ops(&netlbl_mgmt_gnl_family, 639fd385855SPaul Moore &netlbl_mgmt_genl_c_protocols); 640d15c345fSPaul Moore if (ret_val != 0) 641d15c345fSPaul Moore return ret_val; 642d15c345fSPaul Moore ret_val = genl_register_ops(&netlbl_mgmt_gnl_family, 643d15c345fSPaul Moore &netlbl_mgmt_genl_c_version); 644d15c345fSPaul Moore if (ret_val != 0) 645d15c345fSPaul Moore return ret_val; 646d15c345fSPaul Moore 647d15c345fSPaul Moore return 0; 648d15c345fSPaul Moore } 649