1 /* 2 * Export the iSCSI boot info to userland via sysfs. 3 * 4 * Copyright (C) 2010 Red Hat, Inc. All rights reserved. 5 * Copyright (C) 2010 Mike Christie 6 * 7 * This program is free software; you can redistribute it and/or modify 8 * it under the terms of the GNU General Public License v2.0 as published by 9 * the Free Software Foundation 10 * 11 * This program is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 * GNU General Public License for more details. 15 */ 16 17 #include <linux/module.h> 18 #include <linux/string.h> 19 #include <linux/slab.h> 20 #include <linux/sysfs.h> 21 #include <linux/capability.h> 22 #include <linux/iscsi_boot_sysfs.h> 23 24 25 MODULE_AUTHOR("Mike Christie <michaelc@cs.wisc.edu>"); 26 MODULE_DESCRIPTION("sysfs interface and helpers to export iSCSI boot information"); 27 MODULE_LICENSE("GPL"); 28 /* 29 * The kobject and attribute structures. 30 */ 31 struct iscsi_boot_attr { 32 struct attribute attr; 33 int type; 34 ssize_t (*show) (void *data, int type, char *buf); 35 }; 36 37 /* 38 * The routine called for all sysfs attributes. 39 */ 40 static ssize_t iscsi_boot_show_attribute(struct kobject *kobj, 41 struct attribute *attr, char *buf) 42 { 43 struct iscsi_boot_kobj *boot_kobj = 44 container_of(kobj, struct iscsi_boot_kobj, kobj); 45 struct iscsi_boot_attr *boot_attr = 46 container_of(attr, struct iscsi_boot_attr, attr); 47 ssize_t ret = -EIO; 48 char *str = buf; 49 50 if (!capable(CAP_SYS_ADMIN)) 51 return -EACCES; 52 53 if (boot_kobj->show) 54 ret = boot_kobj->show(boot_kobj->data, boot_attr->type, str); 55 return ret; 56 } 57 58 static const struct sysfs_ops iscsi_boot_attr_ops = { 59 .show = iscsi_boot_show_attribute, 60 }; 61 62 static void iscsi_boot_kobj_release(struct kobject *kobj) 63 { 64 struct iscsi_boot_kobj *boot_kobj = 65 container_of(kobj, struct iscsi_boot_kobj, kobj); 66 67 kfree(boot_kobj->data); 68 kfree(boot_kobj); 69 } 70 71 static struct kobj_type iscsi_boot_ktype = { 72 .release = iscsi_boot_kobj_release, 73 .sysfs_ops = &iscsi_boot_attr_ops, 74 }; 75 76 #define iscsi_boot_rd_attr(fnname, sysfs_name, attr_type) \ 77 static struct iscsi_boot_attr iscsi_boot_attr_##fnname = { \ 78 .attr = { .name = __stringify(sysfs_name), .mode = 0444 }, \ 79 .type = attr_type, \ 80 } 81 82 /* Target attrs */ 83 iscsi_boot_rd_attr(tgt_index, index, ISCSI_BOOT_TGT_INDEX); 84 iscsi_boot_rd_attr(tgt_flags, flags, ISCSI_BOOT_TGT_FLAGS); 85 iscsi_boot_rd_attr(tgt_ip, ip-addr, ISCSI_BOOT_TGT_IP_ADDR); 86 iscsi_boot_rd_attr(tgt_port, port, ISCSI_BOOT_TGT_PORT); 87 iscsi_boot_rd_attr(tgt_lun, lun, ISCSI_BOOT_TGT_LUN); 88 iscsi_boot_rd_attr(tgt_chap, chap-type, ISCSI_BOOT_TGT_CHAP_TYPE); 89 iscsi_boot_rd_attr(tgt_nic, nic-assoc, ISCSI_BOOT_TGT_NIC_ASSOC); 90 iscsi_boot_rd_attr(tgt_name, target-name, ISCSI_BOOT_TGT_NAME); 91 iscsi_boot_rd_attr(tgt_chap_name, chap-name, ISCSI_BOOT_TGT_CHAP_NAME); 92 iscsi_boot_rd_attr(tgt_chap_secret, chap-secret, ISCSI_BOOT_TGT_CHAP_SECRET); 93 iscsi_boot_rd_attr(tgt_chap_rev_name, rev-chap-name, 94 ISCSI_BOOT_TGT_REV_CHAP_NAME); 95 iscsi_boot_rd_attr(tgt_chap_rev_secret, rev-chap-name-secret, 96 ISCSI_BOOT_TGT_REV_CHAP_SECRET); 97 98 static struct attribute *target_attrs[] = { 99 &iscsi_boot_attr_tgt_index.attr, 100 &iscsi_boot_attr_tgt_flags.attr, 101 &iscsi_boot_attr_tgt_ip.attr, 102 &iscsi_boot_attr_tgt_port.attr, 103 &iscsi_boot_attr_tgt_lun.attr, 104 &iscsi_boot_attr_tgt_chap.attr, 105 &iscsi_boot_attr_tgt_nic.attr, 106 &iscsi_boot_attr_tgt_name.attr, 107 &iscsi_boot_attr_tgt_chap_name.attr, 108 &iscsi_boot_attr_tgt_chap_secret.attr, 109 &iscsi_boot_attr_tgt_chap_rev_name.attr, 110 &iscsi_boot_attr_tgt_chap_rev_secret.attr, 111 NULL 112 }; 113 114 static mode_t iscsi_boot_tgt_attr_is_visible(struct kobject *kobj, 115 struct attribute *attr, int i) 116 { 117 struct iscsi_boot_kobj *boot_kobj = 118 container_of(kobj, struct iscsi_boot_kobj, kobj); 119 120 if (attr == &iscsi_boot_attr_tgt_index.attr) 121 return boot_kobj->is_visible(boot_kobj->data, 122 ISCSI_BOOT_TGT_INDEX); 123 else if (attr == &iscsi_boot_attr_tgt_flags.attr) 124 return boot_kobj->is_visible(boot_kobj->data, 125 ISCSI_BOOT_TGT_FLAGS); 126 else if (attr == &iscsi_boot_attr_tgt_ip.attr) 127 return boot_kobj->is_visible(boot_kobj->data, 128 ISCSI_BOOT_TGT_IP_ADDR); 129 else if (attr == &iscsi_boot_attr_tgt_port.attr) 130 return boot_kobj->is_visible(boot_kobj->data, 131 ISCSI_BOOT_TGT_PORT); 132 else if (attr == &iscsi_boot_attr_tgt_lun.attr) 133 return boot_kobj->is_visible(boot_kobj->data, 134 ISCSI_BOOT_TGT_LUN); 135 else if (attr == &iscsi_boot_attr_tgt_chap.attr) 136 return boot_kobj->is_visible(boot_kobj->data, 137 ISCSI_BOOT_TGT_CHAP_TYPE); 138 else if (attr == &iscsi_boot_attr_tgt_nic.attr) 139 return boot_kobj->is_visible(boot_kobj->data, 140 ISCSI_BOOT_TGT_NIC_ASSOC); 141 else if (attr == &iscsi_boot_attr_tgt_name.attr) 142 return boot_kobj->is_visible(boot_kobj->data, 143 ISCSI_BOOT_TGT_NAME); 144 else if (attr == &iscsi_boot_attr_tgt_chap_name.attr) 145 return boot_kobj->is_visible(boot_kobj->data, 146 ISCSI_BOOT_TGT_CHAP_NAME); 147 else if (attr == &iscsi_boot_attr_tgt_chap_secret.attr) 148 return boot_kobj->is_visible(boot_kobj->data, 149 ISCSI_BOOT_TGT_CHAP_SECRET); 150 else if (attr == &iscsi_boot_attr_tgt_chap_rev_name.attr) 151 return boot_kobj->is_visible(boot_kobj->data, 152 ISCSI_BOOT_TGT_REV_CHAP_NAME); 153 else if (attr == &iscsi_boot_attr_tgt_chap_rev_secret.attr) 154 return boot_kobj->is_visible(boot_kobj->data, 155 ISCSI_BOOT_TGT_REV_CHAP_SECRET); 156 return 0; 157 } 158 159 static struct attribute_group iscsi_boot_target_attr_group = { 160 .attrs = target_attrs, 161 .is_visible = iscsi_boot_tgt_attr_is_visible, 162 }; 163 164 /* Ethernet attrs */ 165 iscsi_boot_rd_attr(eth_index, index, ISCSI_BOOT_ETH_INDEX); 166 iscsi_boot_rd_attr(eth_flags, flags, ISCSI_BOOT_ETH_FLAGS); 167 iscsi_boot_rd_attr(eth_ip, ip-addr, ISCSI_BOOT_ETH_IP_ADDR); 168 iscsi_boot_rd_attr(eth_subnet, subnet-mask, ISCSI_BOOT_ETH_SUBNET_MASK); 169 iscsi_boot_rd_attr(eth_origin, origin, ISCSI_BOOT_ETH_ORIGIN); 170 iscsi_boot_rd_attr(eth_gateway, gateway, ISCSI_BOOT_ETH_GATEWAY); 171 iscsi_boot_rd_attr(eth_primary_dns, primary-dns, ISCSI_BOOT_ETH_PRIMARY_DNS); 172 iscsi_boot_rd_attr(eth_secondary_dns, secondary-dns, 173 ISCSI_BOOT_ETH_SECONDARY_DNS); 174 iscsi_boot_rd_attr(eth_dhcp, dhcp, ISCSI_BOOT_ETH_DHCP); 175 iscsi_boot_rd_attr(eth_vlan, vlan, ISCSI_BOOT_ETH_VLAN); 176 iscsi_boot_rd_attr(eth_mac, mac, ISCSI_BOOT_ETH_MAC); 177 iscsi_boot_rd_attr(eth_hostname, hostname, ISCSI_BOOT_ETH_HOSTNAME); 178 179 static struct attribute *ethernet_attrs[] = { 180 &iscsi_boot_attr_eth_index.attr, 181 &iscsi_boot_attr_eth_flags.attr, 182 &iscsi_boot_attr_eth_ip.attr, 183 &iscsi_boot_attr_eth_subnet.attr, 184 &iscsi_boot_attr_eth_origin.attr, 185 &iscsi_boot_attr_eth_gateway.attr, 186 &iscsi_boot_attr_eth_primary_dns.attr, 187 &iscsi_boot_attr_eth_secondary_dns.attr, 188 &iscsi_boot_attr_eth_dhcp.attr, 189 &iscsi_boot_attr_eth_vlan.attr, 190 &iscsi_boot_attr_eth_mac.attr, 191 &iscsi_boot_attr_eth_hostname.attr, 192 NULL 193 }; 194 195 static mode_t iscsi_boot_eth_attr_is_visible(struct kobject *kobj, 196 struct attribute *attr, int i) 197 { 198 struct iscsi_boot_kobj *boot_kobj = 199 container_of(kobj, struct iscsi_boot_kobj, kobj); 200 201 if (attr == &iscsi_boot_attr_eth_index.attr) 202 return boot_kobj->is_visible(boot_kobj->data, 203 ISCSI_BOOT_ETH_INDEX); 204 else if (attr == &iscsi_boot_attr_eth_flags.attr) 205 return boot_kobj->is_visible(boot_kobj->data, 206 ISCSI_BOOT_ETH_FLAGS); 207 else if (attr == &iscsi_boot_attr_eth_ip.attr) 208 return boot_kobj->is_visible(boot_kobj->data, 209 ISCSI_BOOT_ETH_IP_ADDR); 210 else if (attr == &iscsi_boot_attr_eth_subnet.attr) 211 return boot_kobj->is_visible(boot_kobj->data, 212 ISCSI_BOOT_ETH_SUBNET_MASK); 213 else if (attr == &iscsi_boot_attr_eth_origin.attr) 214 return boot_kobj->is_visible(boot_kobj->data, 215 ISCSI_BOOT_ETH_ORIGIN); 216 else if (attr == &iscsi_boot_attr_eth_gateway.attr) 217 return boot_kobj->is_visible(boot_kobj->data, 218 ISCSI_BOOT_ETH_GATEWAY); 219 else if (attr == &iscsi_boot_attr_eth_primary_dns.attr) 220 return boot_kobj->is_visible(boot_kobj->data, 221 ISCSI_BOOT_ETH_PRIMARY_DNS); 222 else if (attr == &iscsi_boot_attr_eth_secondary_dns.attr) 223 return boot_kobj->is_visible(boot_kobj->data, 224 ISCSI_BOOT_ETH_SECONDARY_DNS); 225 else if (attr == &iscsi_boot_attr_eth_dhcp.attr) 226 return boot_kobj->is_visible(boot_kobj->data, 227 ISCSI_BOOT_ETH_DHCP); 228 else if (attr == &iscsi_boot_attr_eth_vlan.attr) 229 return boot_kobj->is_visible(boot_kobj->data, 230 ISCSI_BOOT_ETH_VLAN); 231 else if (attr == &iscsi_boot_attr_eth_mac.attr) 232 return boot_kobj->is_visible(boot_kobj->data, 233 ISCSI_BOOT_ETH_MAC); 234 else if (attr == &iscsi_boot_attr_eth_hostname.attr) 235 return boot_kobj->is_visible(boot_kobj->data, 236 ISCSI_BOOT_ETH_HOSTNAME); 237 return 0; 238 } 239 240 static struct attribute_group iscsi_boot_ethernet_attr_group = { 241 .attrs = ethernet_attrs, 242 .is_visible = iscsi_boot_eth_attr_is_visible, 243 }; 244 245 /* Initiator attrs */ 246 iscsi_boot_rd_attr(ini_index, index, ISCSI_BOOT_INI_INDEX); 247 iscsi_boot_rd_attr(ini_flags, flags, ISCSI_BOOT_INI_FLAGS); 248 iscsi_boot_rd_attr(ini_isns, isns-server, ISCSI_BOOT_INI_ISNS_SERVER); 249 iscsi_boot_rd_attr(ini_slp, slp-server, ISCSI_BOOT_INI_SLP_SERVER); 250 iscsi_boot_rd_attr(ini_primary_radius, pri-radius-server, 251 ISCSI_BOOT_INI_PRI_RADIUS_SERVER); 252 iscsi_boot_rd_attr(ini_secondary_radius, sec-radius-server, 253 ISCSI_BOOT_INI_SEC_RADIUS_SERVER); 254 iscsi_boot_rd_attr(ini_name, initiator-name, ISCSI_BOOT_INI_INITIATOR_NAME); 255 256 static struct attribute *initiator_attrs[] = { 257 &iscsi_boot_attr_ini_index.attr, 258 &iscsi_boot_attr_ini_flags.attr, 259 &iscsi_boot_attr_ini_isns.attr, 260 &iscsi_boot_attr_ini_slp.attr, 261 &iscsi_boot_attr_ini_primary_radius.attr, 262 &iscsi_boot_attr_ini_secondary_radius.attr, 263 &iscsi_boot_attr_ini_name.attr, 264 NULL 265 }; 266 267 static mode_t iscsi_boot_ini_attr_is_visible(struct kobject *kobj, 268 struct attribute *attr, int i) 269 { 270 struct iscsi_boot_kobj *boot_kobj = 271 container_of(kobj, struct iscsi_boot_kobj, kobj); 272 273 if (attr == &iscsi_boot_attr_ini_index.attr) 274 return boot_kobj->is_visible(boot_kobj->data, 275 ISCSI_BOOT_INI_INDEX); 276 if (attr == &iscsi_boot_attr_ini_flags.attr) 277 return boot_kobj->is_visible(boot_kobj->data, 278 ISCSI_BOOT_INI_FLAGS); 279 if (attr == &iscsi_boot_attr_ini_isns.attr) 280 return boot_kobj->is_visible(boot_kobj->data, 281 ISCSI_BOOT_INI_ISNS_SERVER); 282 if (attr == &iscsi_boot_attr_ini_slp.attr) 283 return boot_kobj->is_visible(boot_kobj->data, 284 ISCSI_BOOT_INI_SLP_SERVER); 285 if (attr == &iscsi_boot_attr_ini_primary_radius.attr) 286 return boot_kobj->is_visible(boot_kobj->data, 287 ISCSI_BOOT_INI_PRI_RADIUS_SERVER); 288 if (attr == &iscsi_boot_attr_ini_secondary_radius.attr) 289 return boot_kobj->is_visible(boot_kobj->data, 290 ISCSI_BOOT_INI_SEC_RADIUS_SERVER); 291 if (attr == &iscsi_boot_attr_ini_name.attr) 292 return boot_kobj->is_visible(boot_kobj->data, 293 ISCSI_BOOT_INI_INITIATOR_NAME); 294 295 return 0; 296 } 297 298 static struct attribute_group iscsi_boot_initiator_attr_group = { 299 .attrs = initiator_attrs, 300 .is_visible = iscsi_boot_ini_attr_is_visible, 301 }; 302 303 static struct iscsi_boot_kobj * 304 iscsi_boot_create_kobj(struct iscsi_boot_kset *boot_kset, 305 struct attribute_group *attr_group, 306 const char *name, int index, void *data, 307 ssize_t (*show) (void *data, int type, char *buf), 308 mode_t (*is_visible) (void *data, int type)) 309 { 310 struct iscsi_boot_kobj *boot_kobj; 311 312 boot_kobj = kzalloc(sizeof(*boot_kobj), GFP_KERNEL); 313 if (!boot_kobj) 314 return NULL; 315 INIT_LIST_HEAD(&boot_kobj->list); 316 317 boot_kobj->kobj.kset = boot_kset->kset; 318 if (kobject_init_and_add(&boot_kobj->kobj, &iscsi_boot_ktype, 319 NULL, name, index)) { 320 kfree(boot_kobj); 321 return NULL; 322 } 323 boot_kobj->data = data; 324 boot_kobj->show = show; 325 boot_kobj->is_visible = is_visible; 326 327 if (sysfs_create_group(&boot_kobj->kobj, attr_group)) { 328 /* 329 * We do not want to free this because the caller 330 * will assume that since the creation call failed 331 * the boot kobj was not setup and the normal release 332 * path is not being run. 333 */ 334 boot_kobj->data = NULL; 335 kobject_put(&boot_kobj->kobj); 336 return NULL; 337 } 338 boot_kobj->attr_group = attr_group; 339 340 kobject_uevent(&boot_kobj->kobj, KOBJ_ADD); 341 /* Nothing broke so lets add it to the list. */ 342 list_add_tail(&boot_kobj->list, &boot_kset->kobj_list); 343 return boot_kobj; 344 } 345 346 static void iscsi_boot_remove_kobj(struct iscsi_boot_kobj *boot_kobj) 347 { 348 list_del(&boot_kobj->list); 349 sysfs_remove_group(&boot_kobj->kobj, boot_kobj->attr_group); 350 kobject_put(&boot_kobj->kobj); 351 } 352 353 /** 354 * iscsi_boot_create_target() - create boot target sysfs dir 355 * @boot_kset: boot kset 356 * @index: the target id 357 * @data: driver specific data for target 358 * @show: attr show function 359 * @is_visible: attr visibility function 360 * 361 * Note: The boot sysfs lib will free the data passed in for the caller 362 * when all refs to the target kobject have been released. 363 */ 364 struct iscsi_boot_kobj * 365 iscsi_boot_create_target(struct iscsi_boot_kset *boot_kset, int index, 366 void *data, 367 ssize_t (*show) (void *data, int type, char *buf), 368 mode_t (*is_visible) (void *data, int type)) 369 { 370 return iscsi_boot_create_kobj(boot_kset, &iscsi_boot_target_attr_group, 371 "target%d", index, data, show, is_visible); 372 } 373 EXPORT_SYMBOL_GPL(iscsi_boot_create_target); 374 375 /** 376 * iscsi_boot_create_initiator() - create boot initiator sysfs dir 377 * @boot_kset: boot kset 378 * @index: the initiator id 379 * @data: driver specific data 380 * @show: attr show function 381 * @is_visible: attr visibility function 382 * 383 * Note: The boot sysfs lib will free the data passed in for the caller 384 * when all refs to the initiator kobject have been released. 385 */ 386 struct iscsi_boot_kobj * 387 iscsi_boot_create_initiator(struct iscsi_boot_kset *boot_kset, int index, 388 void *data, 389 ssize_t (*show) (void *data, int type, char *buf), 390 mode_t (*is_visible) (void *data, int type)) 391 { 392 return iscsi_boot_create_kobj(boot_kset, 393 &iscsi_boot_initiator_attr_group, 394 "initiator", index, data, show, 395 is_visible); 396 } 397 EXPORT_SYMBOL_GPL(iscsi_boot_create_initiator); 398 399 /** 400 * iscsi_boot_create_ethernet() - create boot ethernet sysfs dir 401 * @boot_kset: boot kset 402 * @index: the ethernet device id 403 * @data: driver specific data 404 * @show: attr show function 405 * @is_visible: attr visibility function 406 * 407 * Note: The boot sysfs lib will free the data passed in for the caller 408 * when all refs to the ethernet kobject have been released. 409 */ 410 struct iscsi_boot_kobj * 411 iscsi_boot_create_ethernet(struct iscsi_boot_kset *boot_kset, int index, 412 void *data, 413 ssize_t (*show) (void *data, int type, char *buf), 414 mode_t (*is_visible) (void *data, int type)) 415 { 416 return iscsi_boot_create_kobj(boot_kset, 417 &iscsi_boot_ethernet_attr_group, 418 "ethernet%d", index, data, show, 419 is_visible); 420 } 421 EXPORT_SYMBOL_GPL(iscsi_boot_create_ethernet); 422 423 /** 424 * iscsi_boot_create_kset() - creates root sysfs tree 425 * @set_name: name of root dir 426 */ 427 struct iscsi_boot_kset *iscsi_boot_create_kset(const char *set_name) 428 { 429 struct iscsi_boot_kset *boot_kset; 430 431 boot_kset = kzalloc(sizeof(*boot_kset), GFP_KERNEL); 432 if (!boot_kset) 433 return NULL; 434 435 boot_kset->kset = kset_create_and_add(set_name, NULL, firmware_kobj); 436 if (!boot_kset->kset) { 437 kfree(boot_kset); 438 return NULL; 439 } 440 441 INIT_LIST_HEAD(&boot_kset->kobj_list); 442 return boot_kset; 443 } 444 EXPORT_SYMBOL_GPL(iscsi_boot_create_kset); 445 446 /** 447 * iscsi_boot_create_host_kset() - creates root sysfs tree for a scsi host 448 * @hostno: host number of scsi host 449 */ 450 struct iscsi_boot_kset *iscsi_boot_create_host_kset(unsigned int hostno) 451 { 452 struct iscsi_boot_kset *boot_kset; 453 char *set_name; 454 455 set_name = kasprintf(GFP_KERNEL, "iscsi_boot%u", hostno); 456 if (!set_name) 457 return NULL; 458 459 boot_kset = iscsi_boot_create_kset(set_name); 460 kfree(set_name); 461 return boot_kset; 462 } 463 EXPORT_SYMBOL_GPL(iscsi_boot_create_host_kset); 464 465 /** 466 * iscsi_boot_destroy_kset() - destroy kset and kobjects under it 467 * @boot_kset: boot kset 468 * 469 * This will remove the kset and kobjects and attrs under it. 470 */ 471 void iscsi_boot_destroy_kset(struct iscsi_boot_kset *boot_kset) 472 { 473 struct iscsi_boot_kobj *boot_kobj, *tmp_kobj; 474 475 list_for_each_entry_safe(boot_kobj, tmp_kobj, 476 &boot_kset->kobj_list, list) 477 iscsi_boot_remove_kobj(boot_kobj); 478 479 kset_unregister(boot_kset->kset); 480 } 481 EXPORT_SYMBOL_GPL(iscsi_boot_destroy_kset); 482