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_subnet, subnet-mask, ISCSI_BOOT_ETH_SUBNET_MASK); 170 iscsi_boot_rd_attr(eth_origin, origin, ISCSI_BOOT_ETH_ORIGIN); 171 iscsi_boot_rd_attr(eth_gateway, gateway, ISCSI_BOOT_ETH_GATEWAY); 172 iscsi_boot_rd_attr(eth_primary_dns, primary-dns, ISCSI_BOOT_ETH_PRIMARY_DNS); 173 iscsi_boot_rd_attr(eth_secondary_dns, secondary-dns, 174 ISCSI_BOOT_ETH_SECONDARY_DNS); 175 iscsi_boot_rd_attr(eth_dhcp, dhcp, ISCSI_BOOT_ETH_DHCP); 176 iscsi_boot_rd_attr(eth_vlan, vlan, ISCSI_BOOT_ETH_VLAN); 177 iscsi_boot_rd_attr(eth_mac, mac, ISCSI_BOOT_ETH_MAC); 178 iscsi_boot_rd_attr(eth_hostname, hostname, ISCSI_BOOT_ETH_HOSTNAME); 179 180 static struct attribute *ethernet_attrs[] = { 181 &iscsi_boot_attr_eth_index.attr, 182 &iscsi_boot_attr_eth_flags.attr, 183 &iscsi_boot_attr_eth_ip.attr, 184 &iscsi_boot_attr_eth_subnet.attr, 185 &iscsi_boot_attr_eth_origin.attr, 186 &iscsi_boot_attr_eth_gateway.attr, 187 &iscsi_boot_attr_eth_primary_dns.attr, 188 &iscsi_boot_attr_eth_secondary_dns.attr, 189 &iscsi_boot_attr_eth_dhcp.attr, 190 &iscsi_boot_attr_eth_vlan.attr, 191 &iscsi_boot_attr_eth_mac.attr, 192 &iscsi_boot_attr_eth_hostname.attr, 193 NULL 194 }; 195 196 static umode_t iscsi_boot_eth_attr_is_visible(struct kobject *kobj, 197 struct attribute *attr, int i) 198 { 199 struct iscsi_boot_kobj *boot_kobj = 200 container_of(kobj, struct iscsi_boot_kobj, kobj); 201 202 if (attr == &iscsi_boot_attr_eth_index.attr) 203 return boot_kobj->is_visible(boot_kobj->data, 204 ISCSI_BOOT_ETH_INDEX); 205 else if (attr == &iscsi_boot_attr_eth_flags.attr) 206 return boot_kobj->is_visible(boot_kobj->data, 207 ISCSI_BOOT_ETH_FLAGS); 208 else if (attr == &iscsi_boot_attr_eth_ip.attr) 209 return boot_kobj->is_visible(boot_kobj->data, 210 ISCSI_BOOT_ETH_IP_ADDR); 211 else if (attr == &iscsi_boot_attr_eth_subnet.attr) 212 return boot_kobj->is_visible(boot_kobj->data, 213 ISCSI_BOOT_ETH_SUBNET_MASK); 214 else if (attr == &iscsi_boot_attr_eth_origin.attr) 215 return boot_kobj->is_visible(boot_kobj->data, 216 ISCSI_BOOT_ETH_ORIGIN); 217 else if (attr == &iscsi_boot_attr_eth_gateway.attr) 218 return boot_kobj->is_visible(boot_kobj->data, 219 ISCSI_BOOT_ETH_GATEWAY); 220 else if (attr == &iscsi_boot_attr_eth_primary_dns.attr) 221 return boot_kobj->is_visible(boot_kobj->data, 222 ISCSI_BOOT_ETH_PRIMARY_DNS); 223 else if (attr == &iscsi_boot_attr_eth_secondary_dns.attr) 224 return boot_kobj->is_visible(boot_kobj->data, 225 ISCSI_BOOT_ETH_SECONDARY_DNS); 226 else if (attr == &iscsi_boot_attr_eth_dhcp.attr) 227 return boot_kobj->is_visible(boot_kobj->data, 228 ISCSI_BOOT_ETH_DHCP); 229 else if (attr == &iscsi_boot_attr_eth_vlan.attr) 230 return boot_kobj->is_visible(boot_kobj->data, 231 ISCSI_BOOT_ETH_VLAN); 232 else if (attr == &iscsi_boot_attr_eth_mac.attr) 233 return boot_kobj->is_visible(boot_kobj->data, 234 ISCSI_BOOT_ETH_MAC); 235 else if (attr == &iscsi_boot_attr_eth_hostname.attr) 236 return boot_kobj->is_visible(boot_kobj->data, 237 ISCSI_BOOT_ETH_HOSTNAME); 238 return 0; 239 } 240 241 static struct attribute_group iscsi_boot_ethernet_attr_group = { 242 .attrs = ethernet_attrs, 243 .is_visible = iscsi_boot_eth_attr_is_visible, 244 }; 245 246 /* Initiator attrs */ 247 iscsi_boot_rd_attr(ini_index, index, ISCSI_BOOT_INI_INDEX); 248 iscsi_boot_rd_attr(ini_flags, flags, ISCSI_BOOT_INI_FLAGS); 249 iscsi_boot_rd_attr(ini_isns, isns-server, ISCSI_BOOT_INI_ISNS_SERVER); 250 iscsi_boot_rd_attr(ini_slp, slp-server, ISCSI_BOOT_INI_SLP_SERVER); 251 iscsi_boot_rd_attr(ini_primary_radius, pri-radius-server, 252 ISCSI_BOOT_INI_PRI_RADIUS_SERVER); 253 iscsi_boot_rd_attr(ini_secondary_radius, sec-radius-server, 254 ISCSI_BOOT_INI_SEC_RADIUS_SERVER); 255 iscsi_boot_rd_attr(ini_name, initiator-name, ISCSI_BOOT_INI_INITIATOR_NAME); 256 257 static struct attribute *initiator_attrs[] = { 258 &iscsi_boot_attr_ini_index.attr, 259 &iscsi_boot_attr_ini_flags.attr, 260 &iscsi_boot_attr_ini_isns.attr, 261 &iscsi_boot_attr_ini_slp.attr, 262 &iscsi_boot_attr_ini_primary_radius.attr, 263 &iscsi_boot_attr_ini_secondary_radius.attr, 264 &iscsi_boot_attr_ini_name.attr, 265 NULL 266 }; 267 268 static umode_t iscsi_boot_ini_attr_is_visible(struct kobject *kobj, 269 struct attribute *attr, int i) 270 { 271 struct iscsi_boot_kobj *boot_kobj = 272 container_of(kobj, struct iscsi_boot_kobj, kobj); 273 274 if (attr == &iscsi_boot_attr_ini_index.attr) 275 return boot_kobj->is_visible(boot_kobj->data, 276 ISCSI_BOOT_INI_INDEX); 277 if (attr == &iscsi_boot_attr_ini_flags.attr) 278 return boot_kobj->is_visible(boot_kobj->data, 279 ISCSI_BOOT_INI_FLAGS); 280 if (attr == &iscsi_boot_attr_ini_isns.attr) 281 return boot_kobj->is_visible(boot_kobj->data, 282 ISCSI_BOOT_INI_ISNS_SERVER); 283 if (attr == &iscsi_boot_attr_ini_slp.attr) 284 return boot_kobj->is_visible(boot_kobj->data, 285 ISCSI_BOOT_INI_SLP_SERVER); 286 if (attr == &iscsi_boot_attr_ini_primary_radius.attr) 287 return boot_kobj->is_visible(boot_kobj->data, 288 ISCSI_BOOT_INI_PRI_RADIUS_SERVER); 289 if (attr == &iscsi_boot_attr_ini_secondary_radius.attr) 290 return boot_kobj->is_visible(boot_kobj->data, 291 ISCSI_BOOT_INI_SEC_RADIUS_SERVER); 292 if (attr == &iscsi_boot_attr_ini_name.attr) 293 return boot_kobj->is_visible(boot_kobj->data, 294 ISCSI_BOOT_INI_INITIATOR_NAME); 295 296 return 0; 297 } 298 299 static struct attribute_group iscsi_boot_initiator_attr_group = { 300 .attrs = initiator_attrs, 301 .is_visible = iscsi_boot_ini_attr_is_visible, 302 }; 303 304 static struct iscsi_boot_kobj * 305 iscsi_boot_create_kobj(struct iscsi_boot_kset *boot_kset, 306 struct attribute_group *attr_group, 307 const char *name, int index, void *data, 308 ssize_t (*show) (void *data, int type, char *buf), 309 umode_t (*is_visible) (void *data, int type), 310 void (*release) (void *data)) 311 { 312 struct iscsi_boot_kobj *boot_kobj; 313 314 boot_kobj = kzalloc(sizeof(*boot_kobj), GFP_KERNEL); 315 if (!boot_kobj) 316 return NULL; 317 INIT_LIST_HEAD(&boot_kobj->list); 318 319 boot_kobj->kobj.kset = boot_kset->kset; 320 if (kobject_init_and_add(&boot_kobj->kobj, &iscsi_boot_ktype, 321 NULL, name, index)) { 322 kfree(boot_kobj); 323 return NULL; 324 } 325 boot_kobj->data = data; 326 boot_kobj->show = show; 327 boot_kobj->is_visible = is_visible; 328 boot_kobj->release = release; 329 330 if (sysfs_create_group(&boot_kobj->kobj, attr_group)) { 331 /* 332 * We do not want to free this because the caller 333 * will assume that since the creation call failed 334 * the boot kobj was not setup and the normal release 335 * path is not being run. 336 */ 337 boot_kobj->release = NULL; 338 kobject_put(&boot_kobj->kobj); 339 return NULL; 340 } 341 boot_kobj->attr_group = attr_group; 342 343 kobject_uevent(&boot_kobj->kobj, KOBJ_ADD); 344 /* Nothing broke so lets add it to the list. */ 345 list_add_tail(&boot_kobj->list, &boot_kset->kobj_list); 346 return boot_kobj; 347 } 348 349 static void iscsi_boot_remove_kobj(struct iscsi_boot_kobj *boot_kobj) 350 { 351 list_del(&boot_kobj->list); 352 sysfs_remove_group(&boot_kobj->kobj, boot_kobj->attr_group); 353 kobject_put(&boot_kobj->kobj); 354 } 355 356 /** 357 * iscsi_boot_create_target() - create boot target sysfs dir 358 * @boot_kset: boot kset 359 * @index: the target id 360 * @data: driver specific data for target 361 * @show: attr show function 362 * @is_visible: attr visibility function 363 * @release: release function 364 * 365 * Note: The boot sysfs lib will free the data passed in for the caller 366 * when all refs to the target kobject have been released. 367 */ 368 struct iscsi_boot_kobj * 369 iscsi_boot_create_target(struct iscsi_boot_kset *boot_kset, int index, 370 void *data, 371 ssize_t (*show) (void *data, int type, char *buf), 372 umode_t (*is_visible) (void *data, int type), 373 void (*release) (void *data)) 374 { 375 return iscsi_boot_create_kobj(boot_kset, &iscsi_boot_target_attr_group, 376 "target%d", index, data, show, is_visible, 377 release); 378 } 379 EXPORT_SYMBOL_GPL(iscsi_boot_create_target); 380 381 /** 382 * iscsi_boot_create_initiator() - create boot initiator sysfs dir 383 * @boot_kset: boot kset 384 * @index: the initiator id 385 * @data: driver specific data 386 * @show: attr show function 387 * @is_visible: attr visibility function 388 * @release: release function 389 * 390 * Note: The boot sysfs lib will free the data passed in for the caller 391 * when all refs to the initiator kobject have been released. 392 */ 393 struct iscsi_boot_kobj * 394 iscsi_boot_create_initiator(struct iscsi_boot_kset *boot_kset, int index, 395 void *data, 396 ssize_t (*show) (void *data, int type, char *buf), 397 umode_t (*is_visible) (void *data, int type), 398 void (*release) (void *data)) 399 { 400 return iscsi_boot_create_kobj(boot_kset, 401 &iscsi_boot_initiator_attr_group, 402 "initiator", index, data, show, 403 is_visible, release); 404 } 405 EXPORT_SYMBOL_GPL(iscsi_boot_create_initiator); 406 407 /** 408 * iscsi_boot_create_ethernet() - create boot ethernet sysfs dir 409 * @boot_kset: boot kset 410 * @index: the ethernet device id 411 * @data: driver specific data 412 * @show: attr show function 413 * @is_visible: attr visibility function 414 * @release: release function 415 * 416 * Note: The boot sysfs lib will free the data passed in for the caller 417 * when all refs to the ethernet kobject have been released. 418 */ 419 struct iscsi_boot_kobj * 420 iscsi_boot_create_ethernet(struct iscsi_boot_kset *boot_kset, int index, 421 void *data, 422 ssize_t (*show) (void *data, int type, char *buf), 423 umode_t (*is_visible) (void *data, int type), 424 void (*release) (void *data)) 425 { 426 return iscsi_boot_create_kobj(boot_kset, 427 &iscsi_boot_ethernet_attr_group, 428 "ethernet%d", index, data, show, 429 is_visible, release); 430 } 431 EXPORT_SYMBOL_GPL(iscsi_boot_create_ethernet); 432 433 /** 434 * iscsi_boot_create_kset() - creates root sysfs tree 435 * @set_name: name of root dir 436 */ 437 struct iscsi_boot_kset *iscsi_boot_create_kset(const char *set_name) 438 { 439 struct iscsi_boot_kset *boot_kset; 440 441 boot_kset = kzalloc(sizeof(*boot_kset), GFP_KERNEL); 442 if (!boot_kset) 443 return NULL; 444 445 boot_kset->kset = kset_create_and_add(set_name, NULL, firmware_kobj); 446 if (!boot_kset->kset) { 447 kfree(boot_kset); 448 return NULL; 449 } 450 451 INIT_LIST_HEAD(&boot_kset->kobj_list); 452 return boot_kset; 453 } 454 EXPORT_SYMBOL_GPL(iscsi_boot_create_kset); 455 456 /** 457 * iscsi_boot_create_host_kset() - creates root sysfs tree for a scsi host 458 * @hostno: host number of scsi host 459 */ 460 struct iscsi_boot_kset *iscsi_boot_create_host_kset(unsigned int hostno) 461 { 462 struct iscsi_boot_kset *boot_kset; 463 char *set_name; 464 465 set_name = kasprintf(GFP_KERNEL, "iscsi_boot%u", hostno); 466 if (!set_name) 467 return NULL; 468 469 boot_kset = iscsi_boot_create_kset(set_name); 470 kfree(set_name); 471 return boot_kset; 472 } 473 EXPORT_SYMBOL_GPL(iscsi_boot_create_host_kset); 474 475 /** 476 * iscsi_boot_destroy_kset() - destroy kset and kobjects under it 477 * @boot_kset: boot kset 478 * 479 * This will remove the kset and kobjects and attrs under it. 480 */ 481 void iscsi_boot_destroy_kset(struct iscsi_boot_kset *boot_kset) 482 { 483 struct iscsi_boot_kobj *boot_kobj, *tmp_kobj; 484 485 if (!boot_kset) 486 return; 487 488 list_for_each_entry_safe(boot_kobj, tmp_kobj, 489 &boot_kset->kobj_list, list) 490 iscsi_boot_remove_kobj(boot_kobj); 491 492 kset_unregister(boot_kset->kset); 493 } 494 EXPORT_SYMBOL_GPL(iscsi_boot_destroy_kset); 495