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 if (boot_kobj->release) 68 boot_kobj->release(boot_kobj->data); 69 kfree(boot_kobj); 70 } 71 72 static struct kobj_type iscsi_boot_ktype = { 73 .release = iscsi_boot_kobj_release, 74 .sysfs_ops = &iscsi_boot_attr_ops, 75 }; 76 77 #define iscsi_boot_rd_attr(fnname, sysfs_name, attr_type) \ 78 static struct iscsi_boot_attr iscsi_boot_attr_##fnname = { \ 79 .attr = { .name = __stringify(sysfs_name), .mode = 0444 }, \ 80 .type = attr_type, \ 81 } 82 83 /* Target attrs */ 84 iscsi_boot_rd_attr(tgt_index, index, ISCSI_BOOT_TGT_INDEX); 85 iscsi_boot_rd_attr(tgt_flags, flags, ISCSI_BOOT_TGT_FLAGS); 86 iscsi_boot_rd_attr(tgt_ip, ip-addr, ISCSI_BOOT_TGT_IP_ADDR); 87 iscsi_boot_rd_attr(tgt_port, port, ISCSI_BOOT_TGT_PORT); 88 iscsi_boot_rd_attr(tgt_lun, lun, ISCSI_BOOT_TGT_LUN); 89 iscsi_boot_rd_attr(tgt_chap, chap-type, ISCSI_BOOT_TGT_CHAP_TYPE); 90 iscsi_boot_rd_attr(tgt_nic, nic-assoc, ISCSI_BOOT_TGT_NIC_ASSOC); 91 iscsi_boot_rd_attr(tgt_name, target-name, ISCSI_BOOT_TGT_NAME); 92 iscsi_boot_rd_attr(tgt_chap_name, chap-name, ISCSI_BOOT_TGT_CHAP_NAME); 93 iscsi_boot_rd_attr(tgt_chap_secret, chap-secret, ISCSI_BOOT_TGT_CHAP_SECRET); 94 iscsi_boot_rd_attr(tgt_chap_rev_name, rev-chap-name, 95 ISCSI_BOOT_TGT_REV_CHAP_NAME); 96 iscsi_boot_rd_attr(tgt_chap_rev_secret, rev-chap-name-secret, 97 ISCSI_BOOT_TGT_REV_CHAP_SECRET); 98 99 static struct attribute *target_attrs[] = { 100 &iscsi_boot_attr_tgt_index.attr, 101 &iscsi_boot_attr_tgt_flags.attr, 102 &iscsi_boot_attr_tgt_ip.attr, 103 &iscsi_boot_attr_tgt_port.attr, 104 &iscsi_boot_attr_tgt_lun.attr, 105 &iscsi_boot_attr_tgt_chap.attr, 106 &iscsi_boot_attr_tgt_nic.attr, 107 &iscsi_boot_attr_tgt_name.attr, 108 &iscsi_boot_attr_tgt_chap_name.attr, 109 &iscsi_boot_attr_tgt_chap_secret.attr, 110 &iscsi_boot_attr_tgt_chap_rev_name.attr, 111 &iscsi_boot_attr_tgt_chap_rev_secret.attr, 112 NULL 113 }; 114 115 static umode_t iscsi_boot_tgt_attr_is_visible(struct kobject *kobj, 116 struct attribute *attr, int i) 117 { 118 struct iscsi_boot_kobj *boot_kobj = 119 container_of(kobj, struct iscsi_boot_kobj, kobj); 120 121 if (attr == &iscsi_boot_attr_tgt_index.attr) 122 return boot_kobj->is_visible(boot_kobj->data, 123 ISCSI_BOOT_TGT_INDEX); 124 else if (attr == &iscsi_boot_attr_tgt_flags.attr) 125 return boot_kobj->is_visible(boot_kobj->data, 126 ISCSI_BOOT_TGT_FLAGS); 127 else if (attr == &iscsi_boot_attr_tgt_ip.attr) 128 return boot_kobj->is_visible(boot_kobj->data, 129 ISCSI_BOOT_TGT_IP_ADDR); 130 else if (attr == &iscsi_boot_attr_tgt_port.attr) 131 return boot_kobj->is_visible(boot_kobj->data, 132 ISCSI_BOOT_TGT_PORT); 133 else if (attr == &iscsi_boot_attr_tgt_lun.attr) 134 return boot_kobj->is_visible(boot_kobj->data, 135 ISCSI_BOOT_TGT_LUN); 136 else if (attr == &iscsi_boot_attr_tgt_chap.attr) 137 return boot_kobj->is_visible(boot_kobj->data, 138 ISCSI_BOOT_TGT_CHAP_TYPE); 139 else if (attr == &iscsi_boot_attr_tgt_nic.attr) 140 return boot_kobj->is_visible(boot_kobj->data, 141 ISCSI_BOOT_TGT_NIC_ASSOC); 142 else if (attr == &iscsi_boot_attr_tgt_name.attr) 143 return boot_kobj->is_visible(boot_kobj->data, 144 ISCSI_BOOT_TGT_NAME); 145 else if (attr == &iscsi_boot_attr_tgt_chap_name.attr) 146 return boot_kobj->is_visible(boot_kobj->data, 147 ISCSI_BOOT_TGT_CHAP_NAME); 148 else if (attr == &iscsi_boot_attr_tgt_chap_secret.attr) 149 return boot_kobj->is_visible(boot_kobj->data, 150 ISCSI_BOOT_TGT_CHAP_SECRET); 151 else if (attr == &iscsi_boot_attr_tgt_chap_rev_name.attr) 152 return boot_kobj->is_visible(boot_kobj->data, 153 ISCSI_BOOT_TGT_REV_CHAP_NAME); 154 else if (attr == &iscsi_boot_attr_tgt_chap_rev_secret.attr) 155 return boot_kobj->is_visible(boot_kobj->data, 156 ISCSI_BOOT_TGT_REV_CHAP_SECRET); 157 return 0; 158 } 159 160 static struct attribute_group iscsi_boot_target_attr_group = { 161 .attrs = target_attrs, 162 .is_visible = iscsi_boot_tgt_attr_is_visible, 163 }; 164 165 /* Ethernet attrs */ 166 iscsi_boot_rd_attr(eth_index, index, ISCSI_BOOT_ETH_INDEX); 167 iscsi_boot_rd_attr(eth_flags, flags, ISCSI_BOOT_ETH_FLAGS); 168 iscsi_boot_rd_attr(eth_ip, ip-addr, ISCSI_BOOT_ETH_IP_ADDR); 169 iscsi_boot_rd_attr(eth_prefix, prefix-len, ISCSI_BOOT_ETH_PREFIX_LEN); 170 iscsi_boot_rd_attr(eth_subnet, subnet-mask, ISCSI_BOOT_ETH_SUBNET_MASK); 171 iscsi_boot_rd_attr(eth_origin, origin, ISCSI_BOOT_ETH_ORIGIN); 172 iscsi_boot_rd_attr(eth_gateway, gateway, ISCSI_BOOT_ETH_GATEWAY); 173 iscsi_boot_rd_attr(eth_primary_dns, primary-dns, ISCSI_BOOT_ETH_PRIMARY_DNS); 174 iscsi_boot_rd_attr(eth_secondary_dns, secondary-dns, 175 ISCSI_BOOT_ETH_SECONDARY_DNS); 176 iscsi_boot_rd_attr(eth_dhcp, dhcp, ISCSI_BOOT_ETH_DHCP); 177 iscsi_boot_rd_attr(eth_vlan, vlan, ISCSI_BOOT_ETH_VLAN); 178 iscsi_boot_rd_attr(eth_mac, mac, ISCSI_BOOT_ETH_MAC); 179 iscsi_boot_rd_attr(eth_hostname, hostname, ISCSI_BOOT_ETH_HOSTNAME); 180 181 static struct attribute *ethernet_attrs[] = { 182 &iscsi_boot_attr_eth_index.attr, 183 &iscsi_boot_attr_eth_flags.attr, 184 &iscsi_boot_attr_eth_ip.attr, 185 &iscsi_boot_attr_eth_prefix.attr, 186 &iscsi_boot_attr_eth_subnet.attr, 187 &iscsi_boot_attr_eth_origin.attr, 188 &iscsi_boot_attr_eth_gateway.attr, 189 &iscsi_boot_attr_eth_primary_dns.attr, 190 &iscsi_boot_attr_eth_secondary_dns.attr, 191 &iscsi_boot_attr_eth_dhcp.attr, 192 &iscsi_boot_attr_eth_vlan.attr, 193 &iscsi_boot_attr_eth_mac.attr, 194 &iscsi_boot_attr_eth_hostname.attr, 195 NULL 196 }; 197 198 static umode_t iscsi_boot_eth_attr_is_visible(struct kobject *kobj, 199 struct attribute *attr, int i) 200 { 201 struct iscsi_boot_kobj *boot_kobj = 202 container_of(kobj, struct iscsi_boot_kobj, kobj); 203 204 if (attr == &iscsi_boot_attr_eth_index.attr) 205 return boot_kobj->is_visible(boot_kobj->data, 206 ISCSI_BOOT_ETH_INDEX); 207 else if (attr == &iscsi_boot_attr_eth_flags.attr) 208 return boot_kobj->is_visible(boot_kobj->data, 209 ISCSI_BOOT_ETH_FLAGS); 210 else if (attr == &iscsi_boot_attr_eth_ip.attr) 211 return boot_kobj->is_visible(boot_kobj->data, 212 ISCSI_BOOT_ETH_IP_ADDR); 213 else if (attr == &iscsi_boot_attr_eth_prefix.attr) 214 return boot_kobj->is_visible(boot_kobj->data, 215 ISCSI_BOOT_ETH_PREFIX_LEN); 216 else if (attr == &iscsi_boot_attr_eth_subnet.attr) 217 return boot_kobj->is_visible(boot_kobj->data, 218 ISCSI_BOOT_ETH_SUBNET_MASK); 219 else if (attr == &iscsi_boot_attr_eth_origin.attr) 220 return boot_kobj->is_visible(boot_kobj->data, 221 ISCSI_BOOT_ETH_ORIGIN); 222 else if (attr == &iscsi_boot_attr_eth_gateway.attr) 223 return boot_kobj->is_visible(boot_kobj->data, 224 ISCSI_BOOT_ETH_GATEWAY); 225 else if (attr == &iscsi_boot_attr_eth_primary_dns.attr) 226 return boot_kobj->is_visible(boot_kobj->data, 227 ISCSI_BOOT_ETH_PRIMARY_DNS); 228 else if (attr == &iscsi_boot_attr_eth_secondary_dns.attr) 229 return boot_kobj->is_visible(boot_kobj->data, 230 ISCSI_BOOT_ETH_SECONDARY_DNS); 231 else if (attr == &iscsi_boot_attr_eth_dhcp.attr) 232 return boot_kobj->is_visible(boot_kobj->data, 233 ISCSI_BOOT_ETH_DHCP); 234 else if (attr == &iscsi_boot_attr_eth_vlan.attr) 235 return boot_kobj->is_visible(boot_kobj->data, 236 ISCSI_BOOT_ETH_VLAN); 237 else if (attr == &iscsi_boot_attr_eth_mac.attr) 238 return boot_kobj->is_visible(boot_kobj->data, 239 ISCSI_BOOT_ETH_MAC); 240 else if (attr == &iscsi_boot_attr_eth_hostname.attr) 241 return boot_kobj->is_visible(boot_kobj->data, 242 ISCSI_BOOT_ETH_HOSTNAME); 243 return 0; 244 } 245 246 static struct attribute_group iscsi_boot_ethernet_attr_group = { 247 .attrs = ethernet_attrs, 248 .is_visible = iscsi_boot_eth_attr_is_visible, 249 }; 250 251 /* Initiator attrs */ 252 iscsi_boot_rd_attr(ini_index, index, ISCSI_BOOT_INI_INDEX); 253 iscsi_boot_rd_attr(ini_flags, flags, ISCSI_BOOT_INI_FLAGS); 254 iscsi_boot_rd_attr(ini_isns, isns-server, ISCSI_BOOT_INI_ISNS_SERVER); 255 iscsi_boot_rd_attr(ini_slp, slp-server, ISCSI_BOOT_INI_SLP_SERVER); 256 iscsi_boot_rd_attr(ini_primary_radius, pri-radius-server, 257 ISCSI_BOOT_INI_PRI_RADIUS_SERVER); 258 iscsi_boot_rd_attr(ini_secondary_radius, sec-radius-server, 259 ISCSI_BOOT_INI_SEC_RADIUS_SERVER); 260 iscsi_boot_rd_attr(ini_name, initiator-name, ISCSI_BOOT_INI_INITIATOR_NAME); 261 262 static struct attribute *initiator_attrs[] = { 263 &iscsi_boot_attr_ini_index.attr, 264 &iscsi_boot_attr_ini_flags.attr, 265 &iscsi_boot_attr_ini_isns.attr, 266 &iscsi_boot_attr_ini_slp.attr, 267 &iscsi_boot_attr_ini_primary_radius.attr, 268 &iscsi_boot_attr_ini_secondary_radius.attr, 269 &iscsi_boot_attr_ini_name.attr, 270 NULL 271 }; 272 273 static umode_t iscsi_boot_ini_attr_is_visible(struct kobject *kobj, 274 struct attribute *attr, int i) 275 { 276 struct iscsi_boot_kobj *boot_kobj = 277 container_of(kobj, struct iscsi_boot_kobj, kobj); 278 279 if (attr == &iscsi_boot_attr_ini_index.attr) 280 return boot_kobj->is_visible(boot_kobj->data, 281 ISCSI_BOOT_INI_INDEX); 282 if (attr == &iscsi_boot_attr_ini_flags.attr) 283 return boot_kobj->is_visible(boot_kobj->data, 284 ISCSI_BOOT_INI_FLAGS); 285 if (attr == &iscsi_boot_attr_ini_isns.attr) 286 return boot_kobj->is_visible(boot_kobj->data, 287 ISCSI_BOOT_INI_ISNS_SERVER); 288 if (attr == &iscsi_boot_attr_ini_slp.attr) 289 return boot_kobj->is_visible(boot_kobj->data, 290 ISCSI_BOOT_INI_SLP_SERVER); 291 if (attr == &iscsi_boot_attr_ini_primary_radius.attr) 292 return boot_kobj->is_visible(boot_kobj->data, 293 ISCSI_BOOT_INI_PRI_RADIUS_SERVER); 294 if (attr == &iscsi_boot_attr_ini_secondary_radius.attr) 295 return boot_kobj->is_visible(boot_kobj->data, 296 ISCSI_BOOT_INI_SEC_RADIUS_SERVER); 297 if (attr == &iscsi_boot_attr_ini_name.attr) 298 return boot_kobj->is_visible(boot_kobj->data, 299 ISCSI_BOOT_INI_INITIATOR_NAME); 300 301 return 0; 302 } 303 304 static struct attribute_group iscsi_boot_initiator_attr_group = { 305 .attrs = initiator_attrs, 306 .is_visible = iscsi_boot_ini_attr_is_visible, 307 }; 308 309 static struct iscsi_boot_kobj * 310 iscsi_boot_create_kobj(struct iscsi_boot_kset *boot_kset, 311 struct attribute_group *attr_group, 312 const char *name, int index, void *data, 313 ssize_t (*show) (void *data, int type, char *buf), 314 umode_t (*is_visible) (void *data, int type), 315 void (*release) (void *data)) 316 { 317 struct iscsi_boot_kobj *boot_kobj; 318 319 boot_kobj = kzalloc(sizeof(*boot_kobj), GFP_KERNEL); 320 if (!boot_kobj) 321 return NULL; 322 INIT_LIST_HEAD(&boot_kobj->list); 323 324 boot_kobj->kobj.kset = boot_kset->kset; 325 if (kobject_init_and_add(&boot_kobj->kobj, &iscsi_boot_ktype, 326 NULL, name, index)) { 327 kfree(boot_kobj); 328 return NULL; 329 } 330 boot_kobj->data = data; 331 boot_kobj->show = show; 332 boot_kobj->is_visible = is_visible; 333 boot_kobj->release = release; 334 335 if (sysfs_create_group(&boot_kobj->kobj, attr_group)) { 336 /* 337 * We do not want to free this because the caller 338 * will assume that since the creation call failed 339 * the boot kobj was not setup and the normal release 340 * path is not being run. 341 */ 342 boot_kobj->release = NULL; 343 kobject_put(&boot_kobj->kobj); 344 return NULL; 345 } 346 boot_kobj->attr_group = attr_group; 347 348 kobject_uevent(&boot_kobj->kobj, KOBJ_ADD); 349 /* Nothing broke so lets add it to the list. */ 350 list_add_tail(&boot_kobj->list, &boot_kset->kobj_list); 351 return boot_kobj; 352 } 353 354 static void iscsi_boot_remove_kobj(struct iscsi_boot_kobj *boot_kobj) 355 { 356 list_del(&boot_kobj->list); 357 sysfs_remove_group(&boot_kobj->kobj, boot_kobj->attr_group); 358 kobject_put(&boot_kobj->kobj); 359 } 360 361 /** 362 * iscsi_boot_create_target() - create boot target sysfs dir 363 * @boot_kset: boot kset 364 * @index: the target id 365 * @data: driver specific data for target 366 * @show: attr show function 367 * @is_visible: attr visibility function 368 * @release: release function 369 * 370 * Note: The boot sysfs lib will free the data passed in for the caller 371 * when all refs to the target kobject have been released. 372 */ 373 struct iscsi_boot_kobj * 374 iscsi_boot_create_target(struct iscsi_boot_kset *boot_kset, int index, 375 void *data, 376 ssize_t (*show) (void *data, int type, char *buf), 377 umode_t (*is_visible) (void *data, int type), 378 void (*release) (void *data)) 379 { 380 return iscsi_boot_create_kobj(boot_kset, &iscsi_boot_target_attr_group, 381 "target%d", index, data, show, is_visible, 382 release); 383 } 384 EXPORT_SYMBOL_GPL(iscsi_boot_create_target); 385 386 /** 387 * iscsi_boot_create_initiator() - create boot initiator sysfs dir 388 * @boot_kset: boot kset 389 * @index: the initiator id 390 * @data: driver specific data 391 * @show: attr show function 392 * @is_visible: attr visibility function 393 * @release: release function 394 * 395 * Note: The boot sysfs lib will free the data passed in for the caller 396 * when all refs to the initiator kobject have been released. 397 */ 398 struct iscsi_boot_kobj * 399 iscsi_boot_create_initiator(struct iscsi_boot_kset *boot_kset, int index, 400 void *data, 401 ssize_t (*show) (void *data, int type, char *buf), 402 umode_t (*is_visible) (void *data, int type), 403 void (*release) (void *data)) 404 { 405 return iscsi_boot_create_kobj(boot_kset, 406 &iscsi_boot_initiator_attr_group, 407 "initiator", index, data, show, 408 is_visible, release); 409 } 410 EXPORT_SYMBOL_GPL(iscsi_boot_create_initiator); 411 412 /** 413 * iscsi_boot_create_ethernet() - create boot ethernet sysfs dir 414 * @boot_kset: boot kset 415 * @index: the ethernet device id 416 * @data: driver specific data 417 * @show: attr show function 418 * @is_visible: attr visibility function 419 * @release: release function 420 * 421 * Note: The boot sysfs lib will free the data passed in for the caller 422 * when all refs to the ethernet kobject have been released. 423 */ 424 struct iscsi_boot_kobj * 425 iscsi_boot_create_ethernet(struct iscsi_boot_kset *boot_kset, int index, 426 void *data, 427 ssize_t (*show) (void *data, int type, char *buf), 428 umode_t (*is_visible) (void *data, int type), 429 void (*release) (void *data)) 430 { 431 return iscsi_boot_create_kobj(boot_kset, 432 &iscsi_boot_ethernet_attr_group, 433 "ethernet%d", index, data, show, 434 is_visible, release); 435 } 436 EXPORT_SYMBOL_GPL(iscsi_boot_create_ethernet); 437 438 /** 439 * iscsi_boot_create_kset() - creates root sysfs tree 440 * @set_name: name of root dir 441 */ 442 struct iscsi_boot_kset *iscsi_boot_create_kset(const char *set_name) 443 { 444 struct iscsi_boot_kset *boot_kset; 445 446 boot_kset = kzalloc(sizeof(*boot_kset), GFP_KERNEL); 447 if (!boot_kset) 448 return NULL; 449 450 boot_kset->kset = kset_create_and_add(set_name, NULL, firmware_kobj); 451 if (!boot_kset->kset) { 452 kfree(boot_kset); 453 return NULL; 454 } 455 456 INIT_LIST_HEAD(&boot_kset->kobj_list); 457 return boot_kset; 458 } 459 EXPORT_SYMBOL_GPL(iscsi_boot_create_kset); 460 461 /** 462 * iscsi_boot_create_host_kset() - creates root sysfs tree for a scsi host 463 * @hostno: host number of scsi host 464 */ 465 struct iscsi_boot_kset *iscsi_boot_create_host_kset(unsigned int hostno) 466 { 467 struct iscsi_boot_kset *boot_kset; 468 char *set_name; 469 470 set_name = kasprintf(GFP_KERNEL, "iscsi_boot%u", hostno); 471 if (!set_name) 472 return NULL; 473 474 boot_kset = iscsi_boot_create_kset(set_name); 475 kfree(set_name); 476 return boot_kset; 477 } 478 EXPORT_SYMBOL_GPL(iscsi_boot_create_host_kset); 479 480 /** 481 * iscsi_boot_destroy_kset() - destroy kset and kobjects under it 482 * @boot_kset: boot kset 483 * 484 * This will remove the kset and kobjects and attrs under it. 485 */ 486 void iscsi_boot_destroy_kset(struct iscsi_boot_kset *boot_kset) 487 { 488 struct iscsi_boot_kobj *boot_kobj, *tmp_kobj; 489 490 if (!boot_kset) 491 return; 492 493 list_for_each_entry_safe(boot_kobj, tmp_kobj, 494 &boot_kset->kobj_list, list) 495 iscsi_boot_remove_kobj(boot_kobj); 496 497 kset_unregister(boot_kset->kset); 498 kfree(boot_kset); 499 } 500 EXPORT_SYMBOL_GPL(iscsi_boot_destroy_kset); 501