aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
Diffstat (limited to 'net')
-rw-r--r--net/Kconfig2
-rw-r--r--net/Makefile1
-rw-r--r--net/ipv4/cipso_ipv4.c86
-rw-r--r--net/iucv/iucv.c7
-rw-r--r--net/netlabel/netlabel_cipso_v4.c61
-rw-r--r--net/netlabel/netlabel_domainhash.c67
-rw-r--r--net/netlabel/netlabel_domainhash.h4
-rw-r--r--net/netlabel/netlabel_kapi.c347
-rw-r--r--net/netlabel/netlabel_unlabeled.c26
-rw-r--r--net/netlabel/netlabel_unlabeled.h15
-rw-r--r--net/netlink/genetlink.c1
-rw-r--r--net/sctp/auth.c4
-rw-r--r--net/sctp/sm_statefuns.c6
-rw-r--r--net/sctp/socket.c2
-rw-r--r--net/sctp/tsnmap.c2
-rw-r--r--net/wimax/Kconfig38
-rw-r--r--net/wimax/Makefile13
-rw-r--r--net/wimax/debug-levels.h42
-rw-r--r--net/wimax/debugfs.c90
-rw-r--r--net/wimax/id-table.c142
-rw-r--r--net/wimax/op-msg.c421
-rw-r--r--net/wimax/op-reset.c143
-rw-r--r--net/wimax/op-rfkill.c532
-rw-r--r--net/wimax/stack.c599
-rw-r--r--net/wimax/wimax-internal.h91
25 files changed, 2594 insertions, 148 deletions
diff --git a/net/Kconfig b/net/Kconfig
index 6ec2cce7c16..bf2776018f7 100644
--- a/net/Kconfig
+++ b/net/Kconfig
@@ -254,6 +254,8 @@ source "net/mac80211/Kconfig"
254 254
255endif # WIRELESS 255endif # WIRELESS
256 256
257source "net/wimax/Kconfig"
258
257source "net/rfkill/Kconfig" 259source "net/rfkill/Kconfig"
258source "net/9p/Kconfig" 260source "net/9p/Kconfig"
259 261
diff --git a/net/Makefile b/net/Makefile
index ba4460432b7..0fcce89d716 100644
--- a/net/Makefile
+++ b/net/Makefile
@@ -63,3 +63,4 @@ endif
63ifeq ($(CONFIG_NET),y) 63ifeq ($(CONFIG_NET),y)
64obj-$(CONFIG_SYSCTL) += sysctl_net.o 64obj-$(CONFIG_SYSCTL) += sysctl_net.o
65endif 65endif
66obj-$(CONFIG_WIMAX) += wimax/
diff --git a/net/ipv4/cipso_ipv4.c b/net/ipv4/cipso_ipv4.c
index e52799047a5..6bb2635b5de 100644
--- a/net/ipv4/cipso_ipv4.c
+++ b/net/ipv4/cipso_ipv4.c
@@ -38,6 +38,7 @@
38#include <linux/spinlock.h> 38#include <linux/spinlock.h>
39#include <linux/string.h> 39#include <linux/string.h>
40#include <linux/jhash.h> 40#include <linux/jhash.h>
41#include <linux/audit.h>
41#include <net/ip.h> 42#include <net/ip.h>
42#include <net/icmp.h> 43#include <net/icmp.h>
43#include <net/tcp.h> 44#include <net/tcp.h>
@@ -449,6 +450,7 @@ static struct cipso_v4_doi *cipso_v4_doi_search(u32 doi)
449/** 450/**
450 * cipso_v4_doi_add - Add a new DOI to the CIPSO protocol engine 451 * cipso_v4_doi_add - Add a new DOI to the CIPSO protocol engine
451 * @doi_def: the DOI structure 452 * @doi_def: the DOI structure
453 * @audit_info: NetLabel audit information
452 * 454 *
453 * Description: 455 * Description:
454 * The caller defines a new DOI for use by the CIPSO engine and calls this 456 * The caller defines a new DOI for use by the CIPSO engine and calls this
@@ -458,50 +460,78 @@ static struct cipso_v4_doi *cipso_v4_doi_search(u32 doi)
458 * zero on success and non-zero on failure. 460 * zero on success and non-zero on failure.
459 * 461 *
460 */ 462 */
461int cipso_v4_doi_add(struct cipso_v4_doi *doi_def) 463int cipso_v4_doi_add(struct cipso_v4_doi *doi_def,
464 struct netlbl_audit *audit_info)
462{ 465{
466 int ret_val = -EINVAL;
463 u32 iter; 467 u32 iter;
468 u32 doi;
469 u32 doi_type;
470 struct audit_buffer *audit_buf;
471
472 doi = doi_def->doi;
473 doi_type = doi_def->type;
464 474
465 if (doi_def == NULL || doi_def->doi == CIPSO_V4_DOI_UNKNOWN) 475 if (doi_def == NULL || doi_def->doi == CIPSO_V4_DOI_UNKNOWN)
466 return -EINVAL; 476 goto doi_add_return;
467 for (iter = 0; iter < CIPSO_V4_TAG_MAXCNT; iter++) { 477 for (iter = 0; iter < CIPSO_V4_TAG_MAXCNT; iter++) {
468 switch (doi_def->tags[iter]) { 478 switch (doi_def->tags[iter]) {
469 case CIPSO_V4_TAG_RBITMAP: 479 case CIPSO_V4_TAG_RBITMAP:
470 break; 480 break;
471 case CIPSO_V4_TAG_RANGE: 481 case CIPSO_V4_TAG_RANGE:
472 if (doi_def->type != CIPSO_V4_MAP_PASS)
473 return -EINVAL;
474 break;
475 case CIPSO_V4_TAG_INVALID:
476 if (iter == 0)
477 return -EINVAL;
478 break;
479 case CIPSO_V4_TAG_ENUM: 482 case CIPSO_V4_TAG_ENUM:
480 if (doi_def->type != CIPSO_V4_MAP_PASS) 483 if (doi_def->type != CIPSO_V4_MAP_PASS)
481 return -EINVAL; 484 goto doi_add_return;
482 break; 485 break;
483 case CIPSO_V4_TAG_LOCAL: 486 case CIPSO_V4_TAG_LOCAL:
484 if (doi_def->type != CIPSO_V4_MAP_LOCAL) 487 if (doi_def->type != CIPSO_V4_MAP_LOCAL)
485 return -EINVAL; 488 goto doi_add_return;
489 break;
490 case CIPSO_V4_TAG_INVALID:
491 if (iter == 0)
492 goto doi_add_return;
486 break; 493 break;
487 default: 494 default:
488 return -EINVAL; 495 goto doi_add_return;
489 } 496 }
490 } 497 }
491 498
492 atomic_set(&doi_def->refcount, 1); 499 atomic_set(&doi_def->refcount, 1);
493 500
494 spin_lock(&cipso_v4_doi_list_lock); 501 spin_lock(&cipso_v4_doi_list_lock);
495 if (cipso_v4_doi_search(doi_def->doi) != NULL) 502 if (cipso_v4_doi_search(doi_def->doi) != NULL) {
496 goto doi_add_failure; 503 spin_unlock(&cipso_v4_doi_list_lock);
504 ret_val = -EEXIST;
505 goto doi_add_return;
506 }
497 list_add_tail_rcu(&doi_def->list, &cipso_v4_doi_list); 507 list_add_tail_rcu(&doi_def->list, &cipso_v4_doi_list);
498 spin_unlock(&cipso_v4_doi_list_lock); 508 spin_unlock(&cipso_v4_doi_list_lock);
509 ret_val = 0;
499 510
500 return 0; 511doi_add_return:
512 audit_buf = netlbl_audit_start(AUDIT_MAC_CIPSOV4_ADD, audit_info);
513 if (audit_buf != NULL) {
514 const char *type_str;
515 switch (doi_type) {
516 case CIPSO_V4_MAP_TRANS:
517 type_str = "trans";
518 break;
519 case CIPSO_V4_MAP_PASS:
520 type_str = "pass";
521 break;
522 case CIPSO_V4_MAP_LOCAL:
523 type_str = "local";
524 break;
525 default:
526 type_str = "(unknown)";
527 }
528 audit_log_format(audit_buf,
529 " cipso_doi=%u cipso_type=%s res=%u",
530 doi, type_str, ret_val == 0 ? 1 : 0);
531 audit_log_end(audit_buf);
532 }
501 533
502doi_add_failure: 534 return ret_val;
503 spin_unlock(&cipso_v4_doi_list_lock);
504 return -EEXIST;
505} 535}
506 536
507/** 537/**
@@ -559,25 +589,39 @@ static void cipso_v4_doi_free_rcu(struct rcu_head *entry)
559 */ 589 */
560int cipso_v4_doi_remove(u32 doi, struct netlbl_audit *audit_info) 590int cipso_v4_doi_remove(u32 doi, struct netlbl_audit *audit_info)
561{ 591{
592 int ret_val;
562 struct cipso_v4_doi *doi_def; 593 struct cipso_v4_doi *doi_def;
594 struct audit_buffer *audit_buf;
563 595
564 spin_lock(&cipso_v4_doi_list_lock); 596 spin_lock(&cipso_v4_doi_list_lock);
565 doi_def = cipso_v4_doi_search(doi); 597 doi_def = cipso_v4_doi_search(doi);
566 if (doi_def == NULL) { 598 if (doi_def == NULL) {
567 spin_unlock(&cipso_v4_doi_list_lock); 599 spin_unlock(&cipso_v4_doi_list_lock);
568 return -ENOENT; 600 ret_val = -ENOENT;
601 goto doi_remove_return;
569 } 602 }
570 if (!atomic_dec_and_test(&doi_def->refcount)) { 603 if (!atomic_dec_and_test(&doi_def->refcount)) {
571 spin_unlock(&cipso_v4_doi_list_lock); 604 spin_unlock(&cipso_v4_doi_list_lock);
572 return -EBUSY; 605 ret_val = -EBUSY;
606 goto doi_remove_return;
573 } 607 }
574 list_del_rcu(&doi_def->list); 608 list_del_rcu(&doi_def->list);
575 spin_unlock(&cipso_v4_doi_list_lock); 609 spin_unlock(&cipso_v4_doi_list_lock);
576 610
577 cipso_v4_cache_invalidate(); 611 cipso_v4_cache_invalidate();
578 call_rcu(&doi_def->rcu, cipso_v4_doi_free_rcu); 612 call_rcu(&doi_def->rcu, cipso_v4_doi_free_rcu);
613 ret_val = 0;
614
615doi_remove_return:
616 audit_buf = netlbl_audit_start(AUDIT_MAC_CIPSOV4_DEL, audit_info);
617 if (audit_buf != NULL) {
618 audit_log_format(audit_buf,
619 " cipso_doi=%u res=%u",
620 doi, ret_val == 0 ? 1 : 0);
621 audit_log_end(audit_buf);
622 }
579 623
580 return 0; 624 return ret_val;
581} 625}
582 626
583/** 627/**
diff --git a/net/iucv/iucv.c b/net/iucv/iucv.c
index 032f61e9859..a35240f61ec 100644
--- a/net/iucv/iucv.c
+++ b/net/iucv/iucv.c
@@ -50,7 +50,6 @@
50#include <asm/ebcdic.h> 50#include <asm/ebcdic.h>
51#include <asm/io.h> 51#include <asm/io.h>
52#include <asm/s390_ext.h> 52#include <asm/s390_ext.h>
53#include <asm/s390_rdev.h>
54#include <asm/smp.h> 53#include <asm/smp.h>
55 54
56/* 55/*
@@ -1696,7 +1695,7 @@ static int __init iucv_init(void)
1696 rc = register_external_interrupt(0x4000, iucv_external_interrupt); 1695 rc = register_external_interrupt(0x4000, iucv_external_interrupt);
1697 if (rc) 1696 if (rc)
1698 goto out; 1697 goto out;
1699 iucv_root = s390_root_dev_register("iucv"); 1698 iucv_root = root_device_register("iucv");
1700 if (IS_ERR(iucv_root)) { 1699 if (IS_ERR(iucv_root)) {
1701 rc = PTR_ERR(iucv_root); 1700 rc = PTR_ERR(iucv_root);
1702 goto out_int; 1701 goto out_int;
@@ -1740,7 +1739,7 @@ out_free:
1740 kfree(iucv_irq_data[cpu]); 1739 kfree(iucv_irq_data[cpu]);
1741 iucv_irq_data[cpu] = NULL; 1740 iucv_irq_data[cpu] = NULL;
1742 } 1741 }
1743 s390_root_dev_unregister(iucv_root); 1742 root_device_unregister(iucv_root);
1744out_int: 1743out_int:
1745 unregister_external_interrupt(0x4000, iucv_external_interrupt); 1744 unregister_external_interrupt(0x4000, iucv_external_interrupt);
1746out: 1745out:
@@ -1770,7 +1769,7 @@ static void __exit iucv_exit(void)
1770 kfree(iucv_irq_data[cpu]); 1769 kfree(iucv_irq_data[cpu]);
1771 iucv_irq_data[cpu] = NULL; 1770 iucv_irq_data[cpu] = NULL;
1772 } 1771 }
1773 s390_root_dev_unregister(iucv_root); 1772 root_device_unregister(iucv_root);
1774 bus_unregister(&iucv_bus); 1773 bus_unregister(&iucv_bus);
1775 unregister_external_interrupt(0x4000, iucv_external_interrupt); 1774 unregister_external_interrupt(0x4000, iucv_external_interrupt);
1776} 1775}
diff --git a/net/netlabel/netlabel_cipso_v4.c b/net/netlabel/netlabel_cipso_v4.c
index fff32b70efa..bf1ab1a6790 100644
--- a/net/netlabel/netlabel_cipso_v4.c
+++ b/net/netlabel/netlabel_cipso_v4.c
@@ -130,6 +130,7 @@ static int netlbl_cipsov4_add_common(struct genl_info *info,
130/** 130/**
131 * netlbl_cipsov4_add_std - Adds a CIPSO V4 DOI definition 131 * netlbl_cipsov4_add_std - Adds a CIPSO V4 DOI definition
132 * @info: the Generic NETLINK info block 132 * @info: the Generic NETLINK info block
133 * @audit_info: NetLabel audit information
133 * 134 *
134 * Description: 135 * Description:
135 * Create a new CIPSO_V4_MAP_TRANS DOI definition based on the given ADD 136 * Create a new CIPSO_V4_MAP_TRANS DOI definition based on the given ADD
@@ -137,7 +138,8 @@ static int netlbl_cipsov4_add_common(struct genl_info *info,
137 * non-zero on error. 138 * non-zero on error.
138 * 139 *
139 */ 140 */
140static int netlbl_cipsov4_add_std(struct genl_info *info) 141static int netlbl_cipsov4_add_std(struct genl_info *info,
142 struct netlbl_audit *audit_info)
141{ 143{
142 int ret_val = -EINVAL; 144 int ret_val = -EINVAL;
143 struct cipso_v4_doi *doi_def = NULL; 145 struct cipso_v4_doi *doi_def = NULL;
@@ -316,7 +318,7 @@ static int netlbl_cipsov4_add_std(struct genl_info *info)
316 } 318 }
317 } 319 }
318 320
319 ret_val = cipso_v4_doi_add(doi_def); 321 ret_val = cipso_v4_doi_add(doi_def, audit_info);
320 if (ret_val != 0) 322 if (ret_val != 0)
321 goto add_std_failure; 323 goto add_std_failure;
322 return 0; 324 return 0;
@@ -330,6 +332,7 @@ add_std_failure:
330/** 332/**
331 * netlbl_cipsov4_add_pass - Adds a CIPSO V4 DOI definition 333 * netlbl_cipsov4_add_pass - Adds a CIPSO V4 DOI definition
332 * @info: the Generic NETLINK info block 334 * @info: the Generic NETLINK info block
335 * @audit_info: NetLabel audit information
333 * 336 *
334 * Description: 337 * Description:
335 * Create a new CIPSO_V4_MAP_PASS DOI definition based on the given ADD message 338 * Create a new CIPSO_V4_MAP_PASS DOI definition based on the given ADD message
@@ -337,7 +340,8 @@ add_std_failure:
337 * error. 340 * error.
338 * 341 *
339 */ 342 */
340static int netlbl_cipsov4_add_pass(struct genl_info *info) 343static int netlbl_cipsov4_add_pass(struct genl_info *info,
344 struct netlbl_audit *audit_info)
341{ 345{
342 int ret_val; 346 int ret_val;
343 struct cipso_v4_doi *doi_def = NULL; 347 struct cipso_v4_doi *doi_def = NULL;
@@ -354,7 +358,7 @@ static int netlbl_cipsov4_add_pass(struct genl_info *info)
354 if (ret_val != 0) 358 if (ret_val != 0)
355 goto add_pass_failure; 359 goto add_pass_failure;
356 360
357 ret_val = cipso_v4_doi_add(doi_def); 361 ret_val = cipso_v4_doi_add(doi_def, audit_info);
358 if (ret_val != 0) 362 if (ret_val != 0)
359 goto add_pass_failure; 363 goto add_pass_failure;
360 return 0; 364 return 0;
@@ -367,6 +371,7 @@ add_pass_failure:
367/** 371/**
368 * netlbl_cipsov4_add_local - Adds a CIPSO V4 DOI definition 372 * netlbl_cipsov4_add_local - Adds a CIPSO V4 DOI definition
369 * @info: the Generic NETLINK info block 373 * @info: the Generic NETLINK info block
374 * @audit_info: NetLabel audit information
370 * 375 *
371 * Description: 376 * Description:
372 * Create a new CIPSO_V4_MAP_LOCAL DOI definition based on the given ADD 377 * Create a new CIPSO_V4_MAP_LOCAL DOI definition based on the given ADD
@@ -374,7 +379,8 @@ add_pass_failure:
374 * non-zero on error. 379 * non-zero on error.
375 * 380 *
376 */ 381 */
377static int netlbl_cipsov4_add_local(struct genl_info *info) 382static int netlbl_cipsov4_add_local(struct genl_info *info,
383 struct netlbl_audit *audit_info)
378{ 384{
379 int ret_val; 385 int ret_val;
380 struct cipso_v4_doi *doi_def = NULL; 386 struct cipso_v4_doi *doi_def = NULL;
@@ -391,7 +397,7 @@ static int netlbl_cipsov4_add_local(struct genl_info *info)
391 if (ret_val != 0) 397 if (ret_val != 0)
392 goto add_local_failure; 398 goto add_local_failure;
393 399
394 ret_val = cipso_v4_doi_add(doi_def); 400 ret_val = cipso_v4_doi_add(doi_def, audit_info);
395 if (ret_val != 0) 401 if (ret_val != 0)
396 goto add_local_failure; 402 goto add_local_failure;
397 return 0; 403 return 0;
@@ -415,48 +421,31 @@ static int netlbl_cipsov4_add(struct sk_buff *skb, struct genl_info *info)
415 421
416{ 422{
417 int ret_val = -EINVAL; 423 int ret_val = -EINVAL;
418 u32 type;
419 u32 doi;
420 const char *type_str = "(unknown)"; 424 const char *type_str = "(unknown)";
421 struct audit_buffer *audit_buf;
422 struct netlbl_audit audit_info; 425 struct netlbl_audit audit_info;
423 426
424 if (!info->attrs[NLBL_CIPSOV4_A_DOI] || 427 if (!info->attrs[NLBL_CIPSOV4_A_DOI] ||
425 !info->attrs[NLBL_CIPSOV4_A_MTYPE]) 428 !info->attrs[NLBL_CIPSOV4_A_MTYPE])
426 return -EINVAL; 429 return -EINVAL;
427 430
428 doi = nla_get_u32(info->attrs[NLBL_CIPSOV4_A_DOI]);
429 netlbl_netlink_auditinfo(skb, &audit_info); 431 netlbl_netlink_auditinfo(skb, &audit_info);
430 432 switch (nla_get_u32(info->attrs[NLBL_CIPSOV4_A_MTYPE])) {
431 type = nla_get_u32(info->attrs[NLBL_CIPSOV4_A_MTYPE]);
432 switch (type) {
433 case CIPSO_V4_MAP_TRANS: 433 case CIPSO_V4_MAP_TRANS:
434 type_str = "trans"; 434 type_str = "trans";
435 ret_val = netlbl_cipsov4_add_std(info); 435 ret_val = netlbl_cipsov4_add_std(info, &audit_info);
436 break; 436 break;
437 case CIPSO_V4_MAP_PASS: 437 case CIPSO_V4_MAP_PASS:
438 type_str = "pass"; 438 type_str = "pass";
439 ret_val = netlbl_cipsov4_add_pass(info); 439 ret_val = netlbl_cipsov4_add_pass(info, &audit_info);
440 break; 440 break;
441 case CIPSO_V4_MAP_LOCAL: 441 case CIPSO_V4_MAP_LOCAL:
442 type_str = "local"; 442 type_str = "local";
443 ret_val = netlbl_cipsov4_add_local(info); 443 ret_val = netlbl_cipsov4_add_local(info, &audit_info);
444 break; 444 break;
445 } 445 }
446 if (ret_val == 0) 446 if (ret_val == 0)
447 atomic_inc(&netlabel_mgmt_protocount); 447 atomic_inc(&netlabel_mgmt_protocount);
448 448
449 audit_buf = netlbl_audit_start_common(AUDIT_MAC_CIPSOV4_ADD,
450 &audit_info);
451 if (audit_buf != NULL) {
452 audit_log_format(audit_buf,
453 " cipso_doi=%u cipso_type=%s res=%u",
454 doi,
455 type_str,
456 ret_val == 0 ? 1 : 0);
457 audit_log_end(audit_buf);
458 }
459
460 return ret_val; 449 return ret_val;
461} 450}
462 451
@@ -725,9 +714,7 @@ static int netlbl_cipsov4_remove_cb(struct netlbl_dom_map *entry, void *arg)
725static int netlbl_cipsov4_remove(struct sk_buff *skb, struct genl_info *info) 714static int netlbl_cipsov4_remove(struct sk_buff *skb, struct genl_info *info)
726{ 715{
727 int ret_val = -EINVAL; 716 int ret_val = -EINVAL;
728 u32 doi = 0;
729 struct netlbl_domhsh_walk_arg cb_arg; 717 struct netlbl_domhsh_walk_arg cb_arg;
730 struct audit_buffer *audit_buf;
731 struct netlbl_audit audit_info; 718 struct netlbl_audit audit_info;
732 u32 skip_bkt = 0; 719 u32 skip_bkt = 0;
733 u32 skip_chain = 0; 720 u32 skip_chain = 0;
@@ -735,29 +722,17 @@ static int netlbl_cipsov4_remove(struct sk_buff *skb, struct genl_info *info)
735 if (!info->attrs[NLBL_CIPSOV4_A_DOI]) 722 if (!info->attrs[NLBL_CIPSOV4_A_DOI])
736 return -EINVAL; 723 return -EINVAL;
737 724
738 doi = nla_get_u32(info->attrs[NLBL_CIPSOV4_A_DOI]);
739 netlbl_netlink_auditinfo(skb, &audit_info); 725 netlbl_netlink_auditinfo(skb, &audit_info);
740 726 cb_arg.doi = nla_get_u32(info->attrs[NLBL_CIPSOV4_A_DOI]);
741 cb_arg.doi = doi;
742 cb_arg.audit_info = &audit_info; 727 cb_arg.audit_info = &audit_info;
743 ret_val = netlbl_domhsh_walk(&skip_bkt, &skip_chain, 728 ret_val = netlbl_domhsh_walk(&skip_bkt, &skip_chain,
744 netlbl_cipsov4_remove_cb, &cb_arg); 729 netlbl_cipsov4_remove_cb, &cb_arg);
745 if (ret_val == 0 || ret_val == -ENOENT) { 730 if (ret_val == 0 || ret_val == -ENOENT) {
746 ret_val = cipso_v4_doi_remove(doi, &audit_info); 731 ret_val = cipso_v4_doi_remove(cb_arg.doi, &audit_info);
747 if (ret_val == 0) 732 if (ret_val == 0)
748 atomic_dec(&netlabel_mgmt_protocount); 733 atomic_dec(&netlabel_mgmt_protocount);
749 } 734 }
750 735
751 audit_buf = netlbl_audit_start_common(AUDIT_MAC_CIPSOV4_DEL,
752 &audit_info);
753 if (audit_buf != NULL) {
754 audit_log_format(audit_buf,
755 " cipso_doi=%u res=%u",
756 doi,
757 ret_val == 0 ? 1 : 0);
758 audit_log_end(audit_buf);
759 }
760
761 return ret_val; 736 return ret_val;
762} 737}
763 738
diff --git a/net/netlabel/netlabel_domainhash.c b/net/netlabel/netlabel_domainhash.c
index 5fadf10e5dd..7a10bbe02c1 100644
--- a/net/netlabel/netlabel_domainhash.c
+++ b/net/netlabel/netlabel_domainhash.c
@@ -483,6 +483,73 @@ int netlbl_domhsh_remove_entry(struct netlbl_dom_map *entry,
483} 483}
484 484
485/** 485/**
486 * netlbl_domhsh_remove_af4 - Removes an address selector entry
487 * @domain: the domain
488 * @addr: IPv4 address
489 * @mask: IPv4 address mask
490 * @audit_info: NetLabel audit information
491 *
492 * Description:
493 * Removes an individual address selector from a domain mapping and potentially
494 * the entire mapping if it is empty. Returns zero on success, negative values
495 * on failure.
496 *
497 */
498int netlbl_domhsh_remove_af4(const char *domain,
499 const struct in_addr *addr,
500 const struct in_addr *mask,
501 struct netlbl_audit *audit_info)
502{
503 struct netlbl_dom_map *entry_map;
504 struct netlbl_af4list *entry_addr;
505 struct netlbl_af4list *iter4;
506#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
507 struct netlbl_af6list *iter6;
508#endif /* IPv6 */
509 struct netlbl_domaddr4_map *entry;
510
511 rcu_read_lock();
512
513 if (domain)
514 entry_map = netlbl_domhsh_search(domain);
515 else
516 entry_map = netlbl_domhsh_search_def(domain);
517 if (entry_map == NULL || entry_map->type != NETLBL_NLTYPE_ADDRSELECT)
518 goto remove_af4_failure;
519
520 spin_lock(&netlbl_domhsh_lock);
521 entry_addr = netlbl_af4list_remove(addr->s_addr, mask->s_addr,
522 &entry_map->type_def.addrsel->list4);
523 spin_unlock(&netlbl_domhsh_lock);
524
525 if (entry_addr == NULL)
526 goto remove_af4_failure;
527 netlbl_af4list_foreach_rcu(iter4, &entry_map->type_def.addrsel->list4)
528 goto remove_af4_single_addr;
529#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
530 netlbl_af6list_foreach_rcu(iter6, &entry_map->type_def.addrsel->list6)
531 goto remove_af4_single_addr;
532#endif /* IPv6 */
533 /* the domain mapping is empty so remove it from the mapping table */
534 netlbl_domhsh_remove_entry(entry_map, audit_info);
535
536remove_af4_single_addr:
537 rcu_read_unlock();
538 /* yick, we can't use call_rcu here because we don't have a rcu head
539 * pointer but hopefully this should be a rare case so the pause
540 * shouldn't be a problem */
541 synchronize_rcu();
542 entry = netlbl_domhsh_addr4_entry(entry_addr);
543 cipso_v4_doi_putdef(entry->type_def.cipsov4);
544 kfree(entry);
545 return 0;
546
547remove_af4_failure:
548 rcu_read_unlock();
549 return -ENOENT;
550}
551
552/**
486 * netlbl_domhsh_remove - Removes an entry from the domain hash table 553 * netlbl_domhsh_remove - Removes an entry from the domain hash table
487 * @domain: the domain to remove 554 * @domain: the domain to remove
488 * @audit_info: NetLabel audit information 555 * @audit_info: NetLabel audit information
diff --git a/net/netlabel/netlabel_domainhash.h b/net/netlabel/netlabel_domainhash.h
index bfcb6763a1a..0261dda3f2d 100644
--- a/net/netlabel/netlabel_domainhash.h
+++ b/net/netlabel/netlabel_domainhash.h
@@ -90,6 +90,10 @@ int netlbl_domhsh_add_default(struct netlbl_dom_map *entry,
90 struct netlbl_audit *audit_info); 90 struct netlbl_audit *audit_info);
91int netlbl_domhsh_remove_entry(struct netlbl_dom_map *entry, 91int netlbl_domhsh_remove_entry(struct netlbl_dom_map *entry,
92 struct netlbl_audit *audit_info); 92 struct netlbl_audit *audit_info);
93int netlbl_domhsh_remove_af4(const char *domain,
94 const struct in_addr *addr,
95 const struct in_addr *mask,
96 struct netlbl_audit *audit_info);
93int netlbl_domhsh_remove(const char *domain, struct netlbl_audit *audit_info); 97int netlbl_domhsh_remove(const char *domain, struct netlbl_audit *audit_info);
94int netlbl_domhsh_remove_default(struct netlbl_audit *audit_info); 98int netlbl_domhsh_remove_default(struct netlbl_audit *audit_info);
95struct netlbl_dom_map *netlbl_domhsh_getentry(const char *domain); 99struct netlbl_dom_map *netlbl_domhsh_getentry(const char *domain);
diff --git a/net/netlabel/netlabel_kapi.c b/net/netlabel/netlabel_kapi.c
index b32eceb3ab0..fd9229db075 100644
--- a/net/netlabel/netlabel_kapi.c
+++ b/net/netlabel/netlabel_kapi.c
@@ -31,7 +31,10 @@
31#include <linux/init.h> 31#include <linux/init.h>
32#include <linux/types.h> 32#include <linux/types.h>
33#include <linux/audit.h> 33#include <linux/audit.h>
34#include <linux/in.h>
35#include <linux/in6.h>
34#include <net/ip.h> 36#include <net/ip.h>
37#include <net/ipv6.h>
35#include <net/netlabel.h> 38#include <net/netlabel.h>
36#include <net/cipso_ipv4.h> 39#include <net/cipso_ipv4.h>
37#include <asm/bug.h> 40#include <asm/bug.h>
@@ -42,6 +45,7 @@
42#include "netlabel_cipso_v4.h" 45#include "netlabel_cipso_v4.h"
43#include "netlabel_user.h" 46#include "netlabel_user.h"
44#include "netlabel_mgmt.h" 47#include "netlabel_mgmt.h"
48#include "netlabel_addrlist.h"
45 49
46/* 50/*
47 * Configuration Functions 51 * Configuration Functions
@@ -50,6 +54,9 @@
50/** 54/**
51 * netlbl_cfg_map_del - Remove a NetLabel/LSM domain mapping 55 * netlbl_cfg_map_del - Remove a NetLabel/LSM domain mapping
52 * @domain: the domain mapping to remove 56 * @domain: the domain mapping to remove
57 * @family: address family
58 * @addr: IP address
59 * @mask: IP address mask
53 * @audit_info: NetLabel audit information 60 * @audit_info: NetLabel audit information
54 * 61 *
55 * Description: 62 * Description:
@@ -58,14 +65,32 @@
58 * values on failure. 65 * values on failure.
59 * 66 *
60 */ 67 */
61int netlbl_cfg_map_del(const char *domain, struct netlbl_audit *audit_info) 68int netlbl_cfg_map_del(const char *domain,
69 u16 family,
70 const void *addr,
71 const void *mask,
72 struct netlbl_audit *audit_info)
62{ 73{
63 return netlbl_domhsh_remove(domain, audit_info); 74 if (addr == NULL && mask == NULL) {
75 return netlbl_domhsh_remove(domain, audit_info);
76 } else if (addr != NULL && mask != NULL) {
77 switch (family) {
78 case AF_INET:
79 return netlbl_domhsh_remove_af4(domain, addr, mask,
80 audit_info);
81 default:
82 return -EPFNOSUPPORT;
83 }
84 } else
85 return -EINVAL;
64} 86}
65 87
66/** 88/**
67 * netlbl_cfg_unlbl_add_map - Add an unlabeled NetLabel/LSM domain mapping 89 * netlbl_cfg_unlbl_map_add - Add a new unlabeled mapping
68 * @domain: the domain mapping to add 90 * @domain: the domain mapping to add
91 * @family: address family
92 * @addr: IP address
93 * @mask: IP address mask
69 * @audit_info: NetLabel audit information 94 * @audit_info: NetLabel audit information
70 * 95 *
71 * Description: 96 * Description:
@@ -74,11 +99,19 @@ int netlbl_cfg_map_del(const char *domain, struct netlbl_audit *audit_info)
74 * negative values on failure. 99 * negative values on failure.
75 * 100 *
76 */ 101 */
77int netlbl_cfg_unlbl_add_map(const char *domain, 102int netlbl_cfg_unlbl_map_add(const char *domain,
103 u16 family,
104 const void *addr,
105 const void *mask,
78 struct netlbl_audit *audit_info) 106 struct netlbl_audit *audit_info)
79{ 107{
80 int ret_val = -ENOMEM; 108 int ret_val = -ENOMEM;
81 struct netlbl_dom_map *entry; 109 struct netlbl_dom_map *entry;
110 struct netlbl_domaddr_map *addrmap = NULL;
111 struct netlbl_domaddr4_map *map4 = NULL;
112 struct netlbl_domaddr6_map *map6 = NULL;
113 const struct in_addr *addr4, *mask4;
114 const struct in6_addr *addr6, *mask6;
82 115
83 entry = kzalloc(sizeof(*entry), GFP_ATOMIC); 116 entry = kzalloc(sizeof(*entry), GFP_ATOMIC);
84 if (entry == NULL) 117 if (entry == NULL)
@@ -86,49 +119,225 @@ int netlbl_cfg_unlbl_add_map(const char *domain,
86 if (domain != NULL) { 119 if (domain != NULL) {
87 entry->domain = kstrdup(domain, GFP_ATOMIC); 120 entry->domain = kstrdup(domain, GFP_ATOMIC);
88 if (entry->domain == NULL) 121 if (entry->domain == NULL)
89 goto cfg_unlbl_add_map_failure; 122 goto cfg_unlbl_map_add_failure;
123 }
124
125 if (addr == NULL && mask == NULL)
126 entry->type = NETLBL_NLTYPE_UNLABELED;
127 else if (addr != NULL && mask != NULL) {
128 addrmap = kzalloc(sizeof(*addrmap), GFP_ATOMIC);
129 if (addrmap == NULL)
130 goto cfg_unlbl_map_add_failure;
131 INIT_LIST_HEAD(&addrmap->list4);
132 INIT_LIST_HEAD(&addrmap->list6);
133
134 switch (family) {
135 case AF_INET:
136 addr4 = addr;
137 mask4 = mask;
138 map4 = kzalloc(sizeof(*map4), GFP_ATOMIC);
139 if (map4 == NULL)
140 goto cfg_unlbl_map_add_failure;
141 map4->type = NETLBL_NLTYPE_UNLABELED;
142 map4->list.addr = addr4->s_addr & mask4->s_addr;
143 map4->list.mask = mask4->s_addr;
144 map4->list.valid = 1;
145 ret_val = netlbl_af4list_add(&map4->list,
146 &addrmap->list4);
147 if (ret_val != 0)
148 goto cfg_unlbl_map_add_failure;
149 break;
150 case AF_INET6:
151 addr6 = addr;
152 mask6 = mask;
153 map6 = kzalloc(sizeof(*map6), GFP_ATOMIC);
154 if (map4 == NULL)
155 goto cfg_unlbl_map_add_failure;
156 map6->type = NETLBL_NLTYPE_UNLABELED;
157 ipv6_addr_copy(&map6->list.addr, addr6);
158 map6->list.addr.s6_addr32[0] &= mask6->s6_addr32[0];
159 map6->list.addr.s6_addr32[1] &= mask6->s6_addr32[1];
160 map6->list.addr.s6_addr32[2] &= mask6->s6_addr32[2];
161 map6->list.addr.s6_addr32[3] &= mask6->s6_addr32[3];
162 ipv6_addr_copy(&map6->list.mask, mask6);
163 map6->list.valid = 1;
164 ret_val = netlbl_af4list_add(&map4->list,
165 &addrmap->list4);
166 if (ret_val != 0)
167 goto cfg_unlbl_map_add_failure;
168 break;
169 default:
170 goto cfg_unlbl_map_add_failure;
171 break;
172 }
173
174 entry->type_def.addrsel = addrmap;
175 entry->type = NETLBL_NLTYPE_ADDRSELECT;
176 } else {
177 ret_val = -EINVAL;
178 goto cfg_unlbl_map_add_failure;
90 } 179 }
91 entry->type = NETLBL_NLTYPE_UNLABELED;
92 180
93 ret_val = netlbl_domhsh_add(entry, audit_info); 181 ret_val = netlbl_domhsh_add(entry, audit_info);
94 if (ret_val != 0) 182 if (ret_val != 0)
95 goto cfg_unlbl_add_map_failure; 183 goto cfg_unlbl_map_add_failure;
96 184
97 return 0; 185 return 0;
98 186
99cfg_unlbl_add_map_failure: 187cfg_unlbl_map_add_failure:
100 if (entry != NULL) 188 if (entry != NULL)
101 kfree(entry->domain); 189 kfree(entry->domain);
102 kfree(entry); 190 kfree(entry);
191 kfree(addrmap);
192 kfree(map4);
193 kfree(map6);
103 return ret_val; 194 return ret_val;
104} 195}
105 196
197
198/**
199 * netlbl_cfg_unlbl_static_add - Adds a new static label
200 * @net: network namespace
201 * @dev_name: interface name
202 * @addr: IP address in network byte order (struct in[6]_addr)
203 * @mask: address mask in network byte order (struct in[6]_addr)
204 * @family: address family
205 * @secid: LSM secid value for the entry
206 * @audit_info: NetLabel audit information
207 *
208 * Description:
209 * Adds a new NetLabel static label to be used when protocol provided labels
210 * are not present on incoming traffic. If @dev_name is NULL then the default
211 * interface will be used. Returns zero on success, negative values on failure.
212 *
213 */
214int netlbl_cfg_unlbl_static_add(struct net *net,
215 const char *dev_name,
216 const void *addr,
217 const void *mask,
218 u16 family,
219 u32 secid,
220 struct netlbl_audit *audit_info)
221{
222 u32 addr_len;
223
224 switch (family) {
225 case AF_INET:
226 addr_len = sizeof(struct in_addr);
227 break;
228 case AF_INET6:
229 addr_len = sizeof(struct in6_addr);
230 break;
231 default:
232 return -EPFNOSUPPORT;
233 }
234
235 return netlbl_unlhsh_add(net,
236 dev_name, addr, mask, addr_len,
237 secid, audit_info);
238}
239
240/**
241 * netlbl_cfg_unlbl_static_del - Removes an existing static label
242 * @net: network namespace
243 * @dev_name: interface name
244 * @addr: IP address in network byte order (struct in[6]_addr)
245 * @mask: address mask in network byte order (struct in[6]_addr)
246 * @family: address family
247 * @secid: LSM secid value for the entry
248 * @audit_info: NetLabel audit information
249 *
250 * Description:
251 * Removes an existing NetLabel static label used when protocol provided labels
252 * are not present on incoming traffic. If @dev_name is NULL then the default
253 * interface will be used. Returns zero on success, negative values on failure.
254 *
255 */
256int netlbl_cfg_unlbl_static_del(struct net *net,
257 const char *dev_name,
258 const void *addr,
259 const void *mask,
260 u16 family,
261 struct netlbl_audit *audit_info)
262{
263 u32 addr_len;
264
265 switch (family) {
266 case AF_INET:
267 addr_len = sizeof(struct in_addr);
268 break;
269 case AF_INET6:
270 addr_len = sizeof(struct in6_addr);
271 break;
272 default:
273 return -EPFNOSUPPORT;
274 }
275
276 return netlbl_unlhsh_remove(net,
277 dev_name, addr, mask, addr_len,
278 audit_info);
279}
280
281/**
282 * netlbl_cfg_cipsov4_add - Add a new CIPSOv4 DOI definition
283 * @doi_def: CIPSO DOI definition
284 * @audit_info: NetLabel audit information
285 *
286 * Description:
287 * Add a new CIPSO DOI definition as defined by @doi_def. Returns zero on
288 * success and negative values on failure.
289 *
290 */
291int netlbl_cfg_cipsov4_add(struct cipso_v4_doi *doi_def,
292 struct netlbl_audit *audit_info)
293{
294 return cipso_v4_doi_add(doi_def, audit_info);
295}
296
297/**
298 * netlbl_cfg_cipsov4_del - Remove an existing CIPSOv4 DOI definition
299 * @doi: CIPSO DOI
300 * @audit_info: NetLabel audit information
301 *
302 * Description:
303 * Remove an existing CIPSO DOI definition matching @doi. Returns zero on
304 * success and negative values on failure.
305 *
306 */
307void netlbl_cfg_cipsov4_del(u32 doi, struct netlbl_audit *audit_info)
308{
309 cipso_v4_doi_remove(doi, audit_info);
310}
311
106/** 312/**
107 * netlbl_cfg_cipsov4_add_map - Add a new CIPSOv4 DOI definition and mapping 313 * netlbl_cfg_cipsov4_map_add - Add a new CIPSOv4 DOI mapping
108 * @doi_def: the DOI definition 314 * @doi: the CIPSO DOI
109 * @domain: the domain mapping to add 315 * @domain: the domain mapping to add
316 * @addr: IP address
317 * @mask: IP address mask
110 * @audit_info: NetLabel audit information 318 * @audit_info: NetLabel audit information
111 * 319 *
112 * Description: 320 * Description:
113 * Add a new CIPSOv4 DOI definition and NetLabel/LSM domain mapping for this 321 * Add a new NetLabel/LSM domain mapping for the given CIPSO DOI to the NetLabel
114 * new DOI definition to the NetLabel subsystem. A @domain value of NULL adds 322 * subsystem. A @domain value of NULL adds a new default domain mapping.
115 * a new default domain mapping. Returns zero on success, negative values on 323 * Returns zero on success, negative values on failure.
116 * failure.
117 * 324 *
118 */ 325 */
119int netlbl_cfg_cipsov4_add_map(struct cipso_v4_doi *doi_def, 326int netlbl_cfg_cipsov4_map_add(u32 doi,
120 const char *domain, 327 const char *domain,
328 const struct in_addr *addr,
329 const struct in_addr *mask,
121 struct netlbl_audit *audit_info) 330 struct netlbl_audit *audit_info)
122{ 331{
123 int ret_val = -ENOMEM; 332 int ret_val = -ENOMEM;
124 u32 doi; 333 struct cipso_v4_doi *doi_def;
125 u32 doi_type;
126 struct netlbl_dom_map *entry; 334 struct netlbl_dom_map *entry;
127 const char *type_str; 335 struct netlbl_domaddr_map *addrmap = NULL;
128 struct audit_buffer *audit_buf; 336 struct netlbl_domaddr4_map *addrinfo = NULL;
129 337
130 doi = doi_def->doi; 338 doi_def = cipso_v4_doi_getdef(doi);
131 doi_type = doi_def->type; 339 if (doi_def == NULL)
340 return -ENOENT;
132 341
133 entry = kzalloc(sizeof(*entry), GFP_ATOMIC); 342 entry = kzalloc(sizeof(*entry), GFP_ATOMIC);
134 if (entry == NULL) 343 if (entry == NULL)
@@ -136,56 +345,52 @@ int netlbl_cfg_cipsov4_add_map(struct cipso_v4_doi *doi_def,
136 if (domain != NULL) { 345 if (domain != NULL) {
137 entry->domain = kstrdup(domain, GFP_ATOMIC); 346 entry->domain = kstrdup(domain, GFP_ATOMIC);
138 if (entry->domain == NULL) 347 if (entry->domain == NULL)
139 goto cfg_cipsov4_add_map_failure; 348 goto cfg_cipsov4_map_add_failure;
140 } 349 }
141 350
142 ret_val = cipso_v4_doi_add(doi_def); 351 if (addr == NULL && mask == NULL) {
143 if (ret_val != 0) 352 entry->type_def.cipsov4 = doi_def;
144 goto cfg_cipsov4_add_map_failure_remove_doi; 353 entry->type = NETLBL_NLTYPE_CIPSOV4;
145 entry->type = NETLBL_NLTYPE_CIPSOV4; 354 } else if (addr != NULL && mask != NULL) {
146 entry->type_def.cipsov4 = cipso_v4_doi_getdef(doi); 355 addrmap = kzalloc(sizeof(*addrmap), GFP_ATOMIC);
147 if (entry->type_def.cipsov4 == NULL) { 356 if (addrmap == NULL)
148 ret_val = -ENOENT; 357 goto cfg_cipsov4_map_add_failure;
149 goto cfg_cipsov4_add_map_failure_remove_doi; 358 INIT_LIST_HEAD(&addrmap->list4);
359 INIT_LIST_HEAD(&addrmap->list6);
360
361 addrinfo = kzalloc(sizeof(*addrinfo), GFP_ATOMIC);
362 if (addrinfo == NULL)
363 goto cfg_cipsov4_map_add_failure;
364 addrinfo->type_def.cipsov4 = doi_def;
365 addrinfo->type = NETLBL_NLTYPE_CIPSOV4;
366 addrinfo->list.addr = addr->s_addr & mask->s_addr;
367 addrinfo->list.mask = mask->s_addr;
368 addrinfo->list.valid = 1;
369 ret_val = netlbl_af4list_add(&addrinfo->list, &addrmap->list4);
370 if (ret_val != 0)
371 goto cfg_cipsov4_map_add_failure;
372
373 entry->type_def.addrsel = addrmap;
374 entry->type = NETLBL_NLTYPE_ADDRSELECT;
375 } else {
376 ret_val = -EINVAL;
377 goto cfg_cipsov4_map_add_failure;
150 } 378 }
379
151 ret_val = netlbl_domhsh_add(entry, audit_info); 380 ret_val = netlbl_domhsh_add(entry, audit_info);
152 if (ret_val != 0) 381 if (ret_val != 0)
153 goto cfg_cipsov4_add_map_failure_release_doi; 382 goto cfg_cipsov4_map_add_failure;
154
155cfg_cipsov4_add_map_return:
156 audit_buf = netlbl_audit_start_common(AUDIT_MAC_CIPSOV4_ADD,
157 audit_info);
158 if (audit_buf != NULL) {
159 switch (doi_type) {
160 case CIPSO_V4_MAP_TRANS:
161 type_str = "trans";
162 break;
163 case CIPSO_V4_MAP_PASS:
164 type_str = "pass";
165 break;
166 case CIPSO_V4_MAP_LOCAL:
167 type_str = "local";
168 break;
169 default:
170 type_str = "(unknown)";
171 }
172 audit_log_format(audit_buf,
173 " cipso_doi=%u cipso_type=%s res=%u",
174 doi, type_str, ret_val == 0 ? 1 : 0);
175 audit_log_end(audit_buf);
176 }
177 383
178 return ret_val; 384 return 0;
179 385
180cfg_cipsov4_add_map_failure_release_doi: 386cfg_cipsov4_map_add_failure:
181 cipso_v4_doi_putdef(doi_def); 387 cipso_v4_doi_putdef(doi_def);
182cfg_cipsov4_add_map_failure_remove_doi:
183 cipso_v4_doi_remove(doi, audit_info);
184cfg_cipsov4_add_map_failure:
185 if (entry != NULL) 388 if (entry != NULL)
186 kfree(entry->domain); 389 kfree(entry->domain);
187 kfree(entry); 390 kfree(entry);
188 goto cfg_cipsov4_add_map_return; 391 kfree(addrmap);
392 kfree(addrinfo);
393 return ret_val;
189} 394}
190 395
191/* 396/*
@@ -691,6 +896,28 @@ int netlbl_cache_add(const struct sk_buff *skb,
691} 896}
692 897
693/* 898/*
899 * Protocol Engine Functions
900 */
901
902/**
903 * netlbl_audit_start - Start an audit message
904 * @type: audit message type
905 * @audit_info: NetLabel audit information
906 *
907 * Description:
908 * Start an audit message using the type specified in @type and fill the audit
909 * message with some fields common to all NetLabel audit messages. This
910 * function should only be used by protocol engines, not LSMs. Returns a
911 * pointer to the audit buffer on success, NULL on failure.
912 *
913 */
914struct audit_buffer *netlbl_audit_start(int type,
915 struct netlbl_audit *audit_info)
916{
917 return netlbl_audit_start_common(type, audit_info);
918}
919
920/*
694 * Setup Functions 921 * Setup Functions
695 */ 922 */
696 923
diff --git a/net/netlabel/netlabel_unlabeled.c b/net/netlabel/netlabel_unlabeled.c
index 8c030803217..f3c5c68c684 100644
--- a/net/netlabel/netlabel_unlabeled.c
+++ b/net/netlabel/netlabel_unlabeled.c
@@ -450,13 +450,13 @@ add_iface_failure:
450 * success, negative values on failure. 450 * success, negative values on failure.
451 * 451 *
452 */ 452 */
453static int netlbl_unlhsh_add(struct net *net, 453int netlbl_unlhsh_add(struct net *net,
454 const char *dev_name, 454 const char *dev_name,
455 const void *addr, 455 const void *addr,
456 const void *mask, 456 const void *mask,
457 u32 addr_len, 457 u32 addr_len,
458 u32 secid, 458 u32 secid,
459 struct netlbl_audit *audit_info) 459 struct netlbl_audit *audit_info)
460{ 460{
461 int ret_val; 461 int ret_val;
462 int ifindex; 462 int ifindex;
@@ -720,12 +720,12 @@ unlhsh_condremove_failure:
720 * Returns zero on success, negative values on failure. 720 * Returns zero on success, negative values on failure.
721 * 721 *
722 */ 722 */
723static int netlbl_unlhsh_remove(struct net *net, 723int netlbl_unlhsh_remove(struct net *net,
724 const char *dev_name, 724 const char *dev_name,
725 const void *addr, 725 const void *addr,
726 const void *mask, 726 const void *mask,
727 u32 addr_len, 727 u32 addr_len,
728 struct netlbl_audit *audit_info) 728 struct netlbl_audit *audit_info)
729{ 729{
730 int ret_val; 730 int ret_val;
731 struct net_device *dev; 731 struct net_device *dev;
diff --git a/net/netlabel/netlabel_unlabeled.h b/net/netlabel/netlabel_unlabeled.h
index 06b1301ac07..7aba6359513 100644
--- a/net/netlabel/netlabel_unlabeled.h
+++ b/net/netlabel/netlabel_unlabeled.h
@@ -221,6 +221,21 @@ int netlbl_unlabel_genl_init(void);
221/* General Unlabeled init function */ 221/* General Unlabeled init function */
222int netlbl_unlabel_init(u32 size); 222int netlbl_unlabel_init(u32 size);
223 223
224/* Static/Fallback label management functions */
225int netlbl_unlhsh_add(struct net *net,
226 const char *dev_name,
227 const void *addr,
228 const void *mask,
229 u32 addr_len,
230 u32 secid,
231 struct netlbl_audit *audit_info);
232int netlbl_unlhsh_remove(struct net *net,
233 const char *dev_name,
234 const void *addr,
235 const void *mask,
236 u32 addr_len,
237 struct netlbl_audit *audit_info);
238
224/* Process Unlabeled incoming network packets */ 239/* Process Unlabeled incoming network packets */
225int netlbl_unlabel_getattr(const struct sk_buff *skb, 240int netlbl_unlabel_getattr(const struct sk_buff *skb,
226 u16 family, 241 u16 family,
diff --git a/net/netlink/genetlink.c b/net/netlink/genetlink.c
index 3e1191cecaf..1d3dd30099d 100644
--- a/net/netlink/genetlink.c
+++ b/net/netlink/genetlink.c
@@ -225,6 +225,7 @@ void genl_unregister_mc_group(struct genl_family *family,
225 __genl_unregister_mc_group(family, grp); 225 __genl_unregister_mc_group(family, grp);
226 genl_unlock(); 226 genl_unlock();
227} 227}
228EXPORT_SYMBOL(genl_unregister_mc_group);
228 229
229static void genl_unregister_mc_groups(struct genl_family *family) 230static void genl_unregister_mc_groups(struct genl_family *family)
230{ 231{
diff --git a/net/sctp/auth.c b/net/sctp/auth.c
index 52db5f60daa..20c576f530f 100644
--- a/net/sctp/auth.c
+++ b/net/sctp/auth.c
@@ -141,8 +141,8 @@ void sctp_auth_destroy_keys(struct list_head *keys)
141/* Compare two byte vectors as numbers. Return values 141/* Compare two byte vectors as numbers. Return values
142 * are: 142 * are:
143 * 0 - vectors are equal 143 * 0 - vectors are equal
144 * < 0 - vector 1 is smaller then vector2 144 * < 0 - vector 1 is smaller than vector2
145 * > 0 - vector 1 is greater then vector2 145 * > 0 - vector 1 is greater than vector2
146 * 146 *
147 * Algorithm is: 147 * Algorithm is:
148 * This is performed by selecting the numerically smaller key vector... 148 * This is performed by selecting the numerically smaller key vector...
diff --git a/net/sctp/sm_statefuns.c b/net/sctp/sm_statefuns.c
index 1c4e5d6c29c..3a0cd075914 100644
--- a/net/sctp/sm_statefuns.c
+++ b/net/sctp/sm_statefuns.c
@@ -4268,9 +4268,9 @@ nomem:
4268 4268
4269/* 4269/*
4270 * Handle a protocol violation when the chunk length is invalid. 4270 * Handle a protocol violation when the chunk length is invalid.
4271 * "Invalid" length is identified as smaller then the minimal length a 4271 * "Invalid" length is identified as smaller than the minimal length a
4272 * given chunk can be. For example, a SACK chunk has invalid length 4272 * given chunk can be. For example, a SACK chunk has invalid length
4273 * if it's length is set to be smaller then the size of sctp_sack_chunk_t. 4273 * if its length is set to be smaller than the size of sctp_sack_chunk_t.
4274 * 4274 *
4275 * We inform the other end by sending an ABORT with a Protocol Violation 4275 * We inform the other end by sending an ABORT with a Protocol Violation
4276 * error code. 4276 * error code.
@@ -4300,7 +4300,7 @@ static sctp_disposition_t sctp_sf_violation_chunklen(
4300 4300
4301/* 4301/*
4302 * Handle a protocol violation when the parameter length is invalid. 4302 * Handle a protocol violation when the parameter length is invalid.
4303 * "Invalid" length is identified as smaller then the minimal length a 4303 * "Invalid" length is identified as smaller than the minimal length a
4304 * given parameter can be. 4304 * given parameter can be.
4305 */ 4305 */
4306static sctp_disposition_t sctp_sf_violation_paramlen( 4306static sctp_disposition_t sctp_sf_violation_paramlen(
diff --git a/net/sctp/socket.c b/net/sctp/socket.c
index b14a8f33e42..ff0a8f88de0 100644
--- a/net/sctp/socket.c
+++ b/net/sctp/socket.c
@@ -2717,7 +2717,7 @@ static int sctp_setsockopt_associnfo(struct sock *sk, char __user *optval, int o
2717 paths++; 2717 paths++;
2718 } 2718 }
2719 2719
2720 /* Only validate asocmaxrxt if we have more then 2720 /* Only validate asocmaxrxt if we have more than
2721 * one path/transport. We do this because path 2721 * one path/transport. We do this because path
2722 * retransmissions are only counted when we have more 2722 * retransmissions are only counted when we have more
2723 * then one path. 2723 * then one path.
diff --git a/net/sctp/tsnmap.c b/net/sctp/tsnmap.c
index 35c73e82553..9bd64565021 100644
--- a/net/sctp/tsnmap.c
+++ b/net/sctp/tsnmap.c
@@ -227,7 +227,7 @@ void sctp_tsnmap_skip(struct sctp_tsnmap *map, __u32 tsn)
227 */ 227 */
228 bitmap_zero(map->tsn_map, map->len); 228 bitmap_zero(map->tsn_map, map->len);
229 } else { 229 } else {
230 /* If the gap is smaller then the map size, 230 /* If the gap is smaller than the map size,
231 * shift the map by 'gap' bits and update further. 231 * shift the map by 'gap' bits and update further.
232 */ 232 */
233 bitmap_shift_right(map->tsn_map, map->tsn_map, gap, map->len); 233 bitmap_shift_right(map->tsn_map, map->tsn_map, gap, map->len);
diff --git a/net/wimax/Kconfig b/net/wimax/Kconfig
new file mode 100644
index 00000000000..0bdbb692820
--- /dev/null
+++ b/net/wimax/Kconfig
@@ -0,0 +1,38 @@
1#
2# WiMAX LAN device configuration
3#
4
5menuconfig WIMAX
6 tristate "WiMAX Wireless Broadband support"
7 help
8
9 Select to configure support for devices that provide
10 wireless broadband connectivity using the WiMAX protocol
11 (IEEE 802.16).
12
13 Please note that most of these devices require signing up
14 for a service plan with a provider.
15
16 The different WiMAX drivers can be enabled in the menu entry
17
18 Device Drivers > Network device support > WiMAX Wireless
19 Broadband devices
20
21 If unsure, it is safe to select M (module).
22
23config WIMAX_DEBUG_LEVEL
24 int "WiMAX debug level"
25 depends on WIMAX
26 default 8
27 help
28
29 Select the maximum debug verbosity level to be compiled into
30 the WiMAX stack code.
31
32 By default, debug messages are disabled at runtime and can
33 be selectively enabled for different parts of the code using
34 the sysfs debug-levels file.
35
36 If set at zero, this will compile out all the debug code.
37
38 It is recommended that it is left at 8.
diff --git a/net/wimax/Makefile b/net/wimax/Makefile
new file mode 100644
index 00000000000..5b80b941c2c
--- /dev/null
+++ b/net/wimax/Makefile
@@ -0,0 +1,13 @@
1
2obj-$(CONFIG_WIMAX) += wimax.o
3
4wimax-y := \
5 id-table.o \
6 op-msg.o \
7 op-reset.o \
8 op-rfkill.o \
9 stack.o
10
11wimax-$(CONFIG_DEBUG_FS) += debugfs.o
12
13
diff --git a/net/wimax/debug-levels.h b/net/wimax/debug-levels.h
new file mode 100644
index 00000000000..1c29123a3aa
--- /dev/null
+++ b/net/wimax/debug-levels.h
@@ -0,0 +1,42 @@
1/*
2 * Linux WiMAX Stack
3 * Debug levels control file for the wimax module
4 *
5 *
6 * Copyright (C) 2007-2008 Intel Corporation <linux-wimax@intel.com>
7 * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
8 *
9 * This program is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU General Public License version
11 * 2 as published by the Free Software Foundation.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
21 * 02110-1301, USA.
22 */
23#ifndef __debug_levels__h__
24#define __debug_levels__h__
25
26/* Maximum compile and run time debug level for all submodules */
27#define D_MODULENAME wimax
28#define D_MASTER CONFIG_WIMAX_DEBUG_LEVEL
29
30#include <linux/wimax/debug.h>
31
32/* List of all the enabled modules */
33enum d_module {
34 D_SUBMODULE_DECLARE(debugfs),
35 D_SUBMODULE_DECLARE(id_table),
36 D_SUBMODULE_DECLARE(op_msg),
37 D_SUBMODULE_DECLARE(op_reset),
38 D_SUBMODULE_DECLARE(op_rfkill),
39 D_SUBMODULE_DECLARE(stack),
40};
41
42#endif /* #ifndef __debug_levels__h__ */
diff --git a/net/wimax/debugfs.c b/net/wimax/debugfs.c
new file mode 100644
index 00000000000..87cf4430079
--- /dev/null
+++ b/net/wimax/debugfs.c
@@ -0,0 +1,90 @@
1/*
2 * Linux WiMAX
3 * Debugfs support
4 *
5 *
6 * Copyright (C) 2005-2006 Intel Corporation <linux-wimax@intel.com>
7 * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
8 *
9 * This program is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU General Public License version
11 * 2 as published by the Free Software Foundation.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
21 * 02110-1301, USA.
22 */
23#include <linux/debugfs.h>
24#include <linux/wimax.h>
25#include "wimax-internal.h"
26
27#define D_SUBMODULE debugfs
28#include "debug-levels.h"
29
30
31/* Debug framework control of debug levels */
32struct d_level D_LEVEL[] = {
33 D_SUBMODULE_DEFINE(debugfs),
34 D_SUBMODULE_DEFINE(id_table),
35 D_SUBMODULE_DEFINE(op_msg),
36 D_SUBMODULE_DEFINE(op_reset),
37 D_SUBMODULE_DEFINE(op_rfkill),
38 D_SUBMODULE_DEFINE(stack),
39};
40size_t D_LEVEL_SIZE = ARRAY_SIZE(D_LEVEL);
41
42#define __debugfs_register(prefix, name, parent) \
43do { \
44 result = d_level_register_debugfs(prefix, name, parent); \
45 if (result < 0) \
46 goto error; \
47} while (0)
48
49
50int wimax_debugfs_add(struct wimax_dev *wimax_dev)
51{
52 int result;
53 struct net_device *net_dev = wimax_dev->net_dev;
54 struct device *dev = net_dev->dev.parent;
55 struct dentry *dentry;
56 char buf[128];
57
58 snprintf(buf, sizeof(buf), "wimax:%s", net_dev->name);
59 dentry = debugfs_create_dir(buf, NULL);
60 result = PTR_ERR(dentry);
61 if (IS_ERR(dentry)) {
62 if (result == -ENODEV)
63 result = 0; /* No debugfs support */
64 else
65 dev_err(dev, "Can't create debugfs dentry: %d\n",
66 result);
67 goto out;
68 }
69 wimax_dev->debugfs_dentry = dentry;
70 __debugfs_register("wimax_dl_", debugfs, dentry);
71 __debugfs_register("wimax_dl_", id_table, dentry);
72 __debugfs_register("wimax_dl_", op_msg, dentry);
73 __debugfs_register("wimax_dl_", op_reset, dentry);
74 __debugfs_register("wimax_dl_", op_rfkill, dentry);
75 __debugfs_register("wimax_dl_", stack, dentry);
76 result = 0;
77out:
78 return result;
79
80error:
81 debugfs_remove_recursive(wimax_dev->debugfs_dentry);
82 return result;
83}
84
85void wimax_debugfs_rm(struct wimax_dev *wimax_dev)
86{
87 debugfs_remove_recursive(wimax_dev->debugfs_dentry);
88}
89
90
diff --git a/net/wimax/id-table.c b/net/wimax/id-table.c
new file mode 100644
index 00000000000..d3b88558682
--- /dev/null
+++ b/net/wimax/id-table.c
@@ -0,0 +1,142 @@
1/*
2 * Linux WiMAX
3 * Mappping of generic netlink family IDs to net devices
4 *
5 *
6 * Copyright (C) 2005-2006 Intel Corporation <linux-wimax@intel.com>
7 * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
8 *
9 * This program is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU General Public License version
11 * 2 as published by the Free Software Foundation.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
21 * 02110-1301, USA.
22 *
23 *
24 * We assign a single generic netlink family ID to each device (to
25 * simplify lookup).
26 *
27 * We need a way to map family ID to a wimax_dev pointer.
28 *
29 * The idea is to use a very simple lookup. Using a netlink attribute
30 * with (for example) the interface name implies a heavier search over
31 * all the network devices; seemed kind of a waste given that we know
32 * we are looking for a WiMAX device and that most systems will have
33 * just a single WiMAX adapter.
34 *
35 * We put all the WiMAX devices in the system in a linked list and
36 * match the generic link family ID against the list.
37 *
38 * By using a linked list, the case of a single adapter in the system
39 * becomes (almost) no overhead, while still working for many more. If
40 * it ever goes beyond two, I'll be surprised.
41 */
42#include <linux/device.h>
43#include <net/genetlink.h>
44#include <linux/netdevice.h>
45#include <linux/list.h>
46#include <linux/wimax.h>
47#include "wimax-internal.h"
48
49
50#define D_SUBMODULE id_table
51#include "debug-levels.h"
52
53
54static DEFINE_SPINLOCK(wimax_id_table_lock);
55static struct list_head wimax_id_table = LIST_HEAD_INIT(wimax_id_table);
56
57
58/*
59 * wimax_id_table_add - add a gennetlink familiy ID / wimax_dev mapping
60 *
61 * @wimax_dev: WiMAX device descriptor to associate to the Generic
62 * Netlink family ID.
63 *
64 * Look for an empty spot in the ID table; if none found, double the
65 * table's size and get the first spot.
66 */
67void wimax_id_table_add(struct wimax_dev *wimax_dev)
68{
69 d_fnstart(3, NULL, "(wimax_dev %p)\n", wimax_dev);
70 spin_lock(&wimax_id_table_lock);
71 list_add(&wimax_dev->id_table_node, &wimax_id_table);
72 spin_unlock(&wimax_id_table_lock);
73 d_fnend(3, NULL, "(wimax_dev %p)\n", wimax_dev);
74}
75
76
77/*
78 * wimax_get_netdev_by_info - lookup a wimax_dev from the gennetlink info
79 *
80 * The generic netlink family ID has been filled out in the
81 * nlmsghdr->nlmsg_type field, so we pull it from there, look it up in
82 * the mapping table and reference the wimax_dev.
83 *
84 * When done, the reference should be dropped with
85 * 'dev_put(wimax_dev->net_dev)'.
86 */
87struct wimax_dev *wimax_dev_get_by_genl_info(
88 struct genl_info *info, int ifindex)
89{
90 struct wimax_dev *wimax_dev = NULL;
91
92 d_fnstart(3, NULL, "(info %p ifindex %d)\n", info, ifindex);
93 spin_lock(&wimax_id_table_lock);
94 list_for_each_entry(wimax_dev, &wimax_id_table, id_table_node) {
95 if (wimax_dev->net_dev->ifindex == ifindex) {
96 dev_hold(wimax_dev->net_dev);
97 break;
98 }
99 }
100 if (wimax_dev == NULL)
101 d_printf(1, NULL, "wimax: no devices found with ifindex %d\n",
102 ifindex);
103 spin_unlock(&wimax_id_table_lock);
104 d_fnend(3, NULL, "(info %p ifindex %d) = %p\n",
105 info, ifindex, wimax_dev);
106 return wimax_dev;
107}
108
109
110/*
111 * wimax_id_table_rm - Remove a gennetlink familiy ID / wimax_dev mapping
112 *
113 * @id: family ID to remove from the table
114 */
115void wimax_id_table_rm(struct wimax_dev *wimax_dev)
116{
117 spin_lock(&wimax_id_table_lock);
118 list_del_init(&wimax_dev->id_table_node);
119 spin_unlock(&wimax_id_table_lock);
120}
121
122
123/*
124 * Release the gennetlink family id / mapping table
125 *
126 * On debug, verify that the table is empty upon removal.
127 */
128void wimax_id_table_release(void)
129{
130#ifndef CONFIG_BUG
131 return;
132#endif
133 struct wimax_dev *wimax_dev;
134
135 spin_lock(&wimax_id_table_lock);
136 list_for_each_entry(wimax_dev, &wimax_id_table, id_table_node) {
137 printk(KERN_ERR "BUG: %s wimax_dev %p ifindex %d not cleared\n",
138 __func__, wimax_dev, wimax_dev->net_dev->ifindex);
139 WARN_ON(1);
140 }
141 spin_unlock(&wimax_id_table_lock);
142}
diff --git a/net/wimax/op-msg.c b/net/wimax/op-msg.c
new file mode 100644
index 00000000000..cb3b4ad5368
--- /dev/null
+++ b/net/wimax/op-msg.c
@@ -0,0 +1,421 @@
1/*
2 * Linux WiMAX
3 * Generic messaging interface between userspace and driver/device
4 *
5 *
6 * Copyright (C) 2007-2008 Intel Corporation <linux-wimax@intel.com>
7 * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
8 *
9 * This program is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU General Public License version
11 * 2 as published by the Free Software Foundation.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
21 * 02110-1301, USA.
22 *
23 *
24 * This implements a direct communication channel between user space and
25 * the driver/device, by which free form messages can be sent back and
26 * forth.
27 *
28 * This is intended for device-specific features, vendor quirks, etc.
29 *
30 * See include/net/wimax.h
31 *
32 * GENERIC NETLINK ENCODING AND CAPACITY
33 *
34 * A destination "pipe name" is added to each message; it is up to the
35 * drivers to assign or use those names (if using them at all).
36 *
37 * Messages are encoded as a binary netlink attribute using nla_put()
38 * using type NLA_UNSPEC (as some versions of libnl still in
39 * deployment don't yet understand NLA_BINARY).
40 *
41 * The maximum capacity of this transport is PAGESIZE per message (so
42 * the actual payload will be bit smaller depending on the
43 * netlink/generic netlink attributes and headers).
44 *
45 * RECEPTION OF MESSAGES
46 *
47 * When a message is received from user space, it is passed verbatim
48 * to the driver calling wimax_dev->op_msg_from_user(). The return
49 * value from this function is passed back to user space as an ack
50 * over the generic netlink protocol.
51 *
52 * The stack doesn't do any processing or interpretation of these
53 * messages.
54 *
55 * SENDING MESSAGES
56 *
57 * Messages can be sent with wimax_msg().
58 *
59 * If the message delivery needs to happen on a different context to
60 * that of its creation, wimax_msg_alloc() can be used to get a
61 * pointer to the message that can be delivered later on with
62 * wimax_msg_send().
63 *
64 * ROADMAP
65 *
66 * wimax_gnl_doit_msg_from_user() Process a message from user space
67 * wimax_dev_get_by_genl_info()
68 * wimax_dev->op_msg_from_user() Delivery of message to the driver
69 *
70 * wimax_msg() Send a message to user space
71 * wimax_msg_alloc()
72 * wimax_msg_send()
73 */
74#include <linux/device.h>
75#include <net/genetlink.h>
76#include <linux/netdevice.h>
77#include <linux/wimax.h>
78#include <linux/security.h>
79#include "wimax-internal.h"
80
81
82#define D_SUBMODULE op_msg
83#include "debug-levels.h"
84
85
86/**
87 * wimax_msg_alloc - Create a new skb for sending a message to userspace
88 *
89 * @wimax_dev: WiMAX device descriptor
90 * @pipe_name: "named pipe" the message will be sent to
91 * @msg: pointer to the message data to send
92 * @size: size of the message to send (in bytes), including the header.
93 * @gfp_flags: flags for memory allocation.
94 *
95 * Returns: %0 if ok, negative errno code on error
96 *
97 * Description:
98 *
99 * Allocates an skb that will contain the message to send to user
100 * space over the messaging pipe and initializes it, copying the
101 * payload.
102 *
103 * Once this call is done, you can deliver it with
104 * wimax_msg_send().
105 *
106 * IMPORTANT:
107 *
108 * Don't use skb_push()/skb_pull()/skb_reserve() on the skb, as
109 * wimax_msg_send() depends on skb->data being placed at the
110 * beginning of the user message.
111 */
112struct sk_buff *wimax_msg_alloc(struct wimax_dev *wimax_dev,
113 const char *pipe_name,
114 const void *msg, size_t size,
115 gfp_t gfp_flags)
116{
117 int result;
118 struct device *dev = wimax_dev->net_dev->dev.parent;
119 size_t msg_size;
120 void *genl_msg;
121 struct sk_buff *skb;
122
123 msg_size = nla_total_size(size)
124 + nla_total_size(sizeof(u32))
125 + (pipe_name ? nla_total_size(strlen(pipe_name)) : 0);
126 result = -ENOMEM;
127 skb = genlmsg_new(msg_size, gfp_flags);
128 if (skb == NULL)
129 goto error_new;
130 genl_msg = genlmsg_put(skb, 0, 0, &wimax_gnl_family,
131 0, WIMAX_GNL_OP_MSG_TO_USER);
132 if (genl_msg == NULL) {
133 dev_err(dev, "no memory to create generic netlink message\n");
134 goto error_genlmsg_put;
135 }
136 result = nla_put_u32(skb, WIMAX_GNL_MSG_IFIDX,
137 wimax_dev->net_dev->ifindex);
138 if (result < 0) {
139 dev_err(dev, "no memory to add ifindex attribute\n");
140 goto error_nla_put;
141 }
142 if (pipe_name) {
143 result = nla_put_string(skb, WIMAX_GNL_MSG_PIPE_NAME,
144 pipe_name);
145 if (result < 0) {
146 dev_err(dev, "no memory to add pipe_name attribute\n");
147 goto error_nla_put;
148 }
149 }
150 result = nla_put(skb, WIMAX_GNL_MSG_DATA, size, msg);
151 if (result < 0) {
152 dev_err(dev, "no memory to add payload in attribute\n");
153 goto error_nla_put;
154 }
155 genlmsg_end(skb, genl_msg);
156 return skb;
157
158error_nla_put:
159error_genlmsg_put:
160error_new:
161 nlmsg_free(skb);
162 return ERR_PTR(result);
163
164}
165EXPORT_SYMBOL_GPL(wimax_msg_alloc);
166
167
168/**
169 * wimax_msg_data_len - Return a pointer and size of a message's payload
170 *
171 * @msg: Pointer to a message created with wimax_msg_alloc()
172 * @size: Pointer to where to store the message's size
173 *
174 * Returns the pointer to the message data.
175 */
176const void *wimax_msg_data_len(struct sk_buff *msg, size_t *size)
177{
178 struct nlmsghdr *nlh = (void *) msg->head;
179 struct nlattr *nla;
180
181 nla = nlmsg_find_attr(nlh, sizeof(struct genlmsghdr),
182 WIMAX_GNL_MSG_DATA);
183 if (nla == NULL) {
184 printk(KERN_ERR "Cannot find attribute WIMAX_GNL_MSG_DATA\n");
185 return NULL;
186 }
187 *size = nla_len(nla);
188 return nla_data(nla);
189}
190EXPORT_SYMBOL_GPL(wimax_msg_data_len);
191
192
193/**
194 * wimax_msg_data - Return a pointer to a message's payload
195 *
196 * @msg: Pointer to a message created with wimax_msg_alloc()
197 */
198const void *wimax_msg_data(struct sk_buff *msg)
199{
200 struct nlmsghdr *nlh = (void *) msg->head;
201 struct nlattr *nla;
202
203 nla = nlmsg_find_attr(nlh, sizeof(struct genlmsghdr),
204 WIMAX_GNL_MSG_DATA);
205 if (nla == NULL) {
206 printk(KERN_ERR "Cannot find attribute WIMAX_GNL_MSG_DATA\n");
207 return NULL;
208 }
209 return nla_data(nla);
210}
211EXPORT_SYMBOL_GPL(wimax_msg_data);
212
213
214/**
215 * wimax_msg_len - Return a message's payload length
216 *
217 * @msg: Pointer to a message created with wimax_msg_alloc()
218 */
219ssize_t wimax_msg_len(struct sk_buff *msg)
220{
221 struct nlmsghdr *nlh = (void *) msg->head;
222 struct nlattr *nla;
223
224 nla = nlmsg_find_attr(nlh, sizeof(struct genlmsghdr),
225 WIMAX_GNL_MSG_DATA);
226 if (nla == NULL) {
227 printk(KERN_ERR "Cannot find attribute WIMAX_GNL_MSG_DATA\n");
228 return -EINVAL;
229 }
230 return nla_len(nla);
231}
232EXPORT_SYMBOL_GPL(wimax_msg_len);
233
234
235/**
236 * wimax_msg_send - Send a pre-allocated message to user space
237 *
238 * @wimax_dev: WiMAX device descriptor
239 *
240 * @skb: &struct sk_buff returned by wimax_msg_alloc(). Note the
241 * ownership of @skb is transferred to this function.
242 *
243 * Returns: 0 if ok, < 0 errno code on error
244 *
245 * Description:
246 *
247 * Sends a free-form message that was preallocated with
248 * wimax_msg_alloc() and filled up.
249 *
250 * Assumes that once you pass an skb to this function for sending, it
251 * owns it and will release it when done (on success).
252 *
253 * IMPORTANT:
254 *
255 * Don't use skb_push()/skb_pull()/skb_reserve() on the skb, as
256 * wimax_msg_send() depends on skb->data being placed at the
257 * beginning of the user message.
258 */
259int wimax_msg_send(struct wimax_dev *wimax_dev, struct sk_buff *skb)
260{
261 int result;
262 struct device *dev = wimax_dev->net_dev->dev.parent;
263 void *msg = skb->data;
264 size_t size = skb->len;
265 might_sleep();
266
267 d_printf(1, dev, "CTX: wimax msg, %zu bytes\n", size);
268 d_dump(2, dev, msg, size);
269 result = genlmsg_multicast(skb, 0, wimax_gnl_mcg.id, GFP_KERNEL);
270 d_printf(1, dev, "CTX: genl multicast result %d\n", result);
271 if (result == -ESRCH) /* Nobody connected, ignore it */
272 result = 0; /* btw, the skb is freed already */
273 return result;
274}
275EXPORT_SYMBOL_GPL(wimax_msg_send);
276
277
278/**
279 * wimax_msg - Send a message to user space
280 *
281 * @wimax_dev: WiMAX device descriptor (properly referenced)
282 * @pipe_name: "named pipe" the message will be sent to
283 * @buf: pointer to the message to send.
284 * @size: size of the buffer pointed to by @buf (in bytes).
285 * @gfp_flags: flags for memory allocation.
286 *
287 * Returns: %0 if ok, negative errno code on error.
288 *
289 * Description:
290 *
291 * Sends a free-form message to user space on the device @wimax_dev.
292 *
293 * NOTES:
294 *
295 * Once the @skb is given to this function, who will own it and will
296 * release it when done (unless it returns error).
297 */
298int wimax_msg(struct wimax_dev *wimax_dev, const char *pipe_name,
299 const void *buf, size_t size, gfp_t gfp_flags)
300{
301 int result = -ENOMEM;
302 struct sk_buff *skb;
303
304 skb = wimax_msg_alloc(wimax_dev, pipe_name, buf, size, gfp_flags);
305 if (skb == NULL)
306 goto error_msg_new;
307 result = wimax_msg_send(wimax_dev, skb);
308error_msg_new:
309 return result;
310}
311EXPORT_SYMBOL_GPL(wimax_msg);
312
313
314static const
315struct nla_policy wimax_gnl_msg_policy[WIMAX_GNL_ATTR_MAX + 1] = {
316 [WIMAX_GNL_MSG_IFIDX] = {
317 .type = NLA_U32,
318 },
319 [WIMAX_GNL_MSG_DATA] = {
320 .type = NLA_UNSPEC, /* libnl doesn't grok BINARY yet */
321 },
322};
323
324
325/*
326 * Relays a message from user space to the driver
327 *
328 * The skb is passed to the driver-specific function with the netlink
329 * and generic netlink headers already stripped.
330 *
331 * This call will block while handling/relaying the message.
332 */
333static
334int wimax_gnl_doit_msg_from_user(struct sk_buff *skb, struct genl_info *info)
335{
336 int result, ifindex;
337 struct wimax_dev *wimax_dev;
338 struct device *dev;
339 struct nlmsghdr *nlh = info->nlhdr;
340 char *pipe_name;
341 void *msg_buf;
342 size_t msg_len;
343
344 might_sleep();
345 d_fnstart(3, NULL, "(skb %p info %p)\n", skb, info);
346 result = -ENODEV;
347 if (info->attrs[WIMAX_GNL_MSG_IFIDX] == NULL) {
348 printk(KERN_ERR "WIMAX_GNL_MSG_FROM_USER: can't find IFIDX "
349 "attribute\n");
350 goto error_no_wimax_dev;
351 }
352 ifindex = nla_get_u32(info->attrs[WIMAX_GNL_MSG_IFIDX]);
353 wimax_dev = wimax_dev_get_by_genl_info(info, ifindex);
354 if (wimax_dev == NULL)
355 goto error_no_wimax_dev;
356 dev = wimax_dev_to_dev(wimax_dev);
357
358 /* Unpack arguments */
359 result = -EINVAL;
360 if (info->attrs[WIMAX_GNL_MSG_DATA] == NULL) {
361 dev_err(dev, "WIMAX_GNL_MSG_FROM_USER: can't find MSG_DATA "
362 "attribute\n");
363 goto error_no_data;
364 }
365 msg_buf = nla_data(info->attrs[WIMAX_GNL_MSG_DATA]);
366 msg_len = nla_len(info->attrs[WIMAX_GNL_MSG_DATA]);
367
368 if (info->attrs[WIMAX_GNL_MSG_PIPE_NAME] == NULL)
369 pipe_name = NULL;
370 else {
371 struct nlattr *attr = info->attrs[WIMAX_GNL_MSG_PIPE_NAME];
372 size_t attr_len = nla_len(attr);
373 /* libnl-1.1 does not yet support NLA_NUL_STRING */
374 result = -ENOMEM;
375 pipe_name = kstrndup(nla_data(attr), attr_len + 1, GFP_KERNEL);
376 if (pipe_name == NULL)
377 goto error_alloc;
378 pipe_name[attr_len] = 0;
379 }
380 mutex_lock(&wimax_dev->mutex);
381 result = wimax_dev_is_ready(wimax_dev);
382 if (result < 0)
383 goto error_not_ready;
384 result = -ENOSYS;
385 if (wimax_dev->op_msg_from_user == NULL)
386 goto error_noop;
387
388 d_printf(1, dev,
389 "CRX: nlmsghdr len %u type %u flags 0x%04x seq 0x%x pid %u\n",
390 nlh->nlmsg_len, nlh->nlmsg_type, nlh->nlmsg_flags,
391 nlh->nlmsg_seq, nlh->nlmsg_pid);
392 d_printf(1, dev, "CRX: wimax message %zu bytes\n", msg_len);
393 d_dump(2, dev, msg_buf, msg_len);
394
395 result = wimax_dev->op_msg_from_user(wimax_dev, pipe_name,
396 msg_buf, msg_len, info);
397error_noop:
398error_not_ready:
399 mutex_unlock(&wimax_dev->mutex);
400error_alloc:
401 kfree(pipe_name);
402error_no_data:
403 dev_put(wimax_dev->net_dev);
404error_no_wimax_dev:
405 d_fnend(3, NULL, "(skb %p info %p) = %d\n", skb, info, result);
406 return result;
407}
408
409
410/*
411 * Generic Netlink glue
412 */
413
414struct genl_ops wimax_gnl_msg_from_user = {
415 .cmd = WIMAX_GNL_OP_MSG_FROM_USER,
416 .flags = GENL_ADMIN_PERM,
417 .policy = wimax_gnl_msg_policy,
418 .doit = wimax_gnl_doit_msg_from_user,
419 .dumpit = NULL,
420};
421
diff --git a/net/wimax/op-reset.c b/net/wimax/op-reset.c
new file mode 100644
index 00000000000..ca269178c4d
--- /dev/null
+++ b/net/wimax/op-reset.c
@@ -0,0 +1,143 @@
1/*
2 * Linux WiMAX
3 * Implement and export a method for resetting a WiMAX device
4 *
5 *
6 * Copyright (C) 2008 Intel Corporation <linux-wimax@intel.com>
7 * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
8 *
9 * This program is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU General Public License version
11 * 2 as published by the Free Software Foundation.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
21 * 02110-1301, USA.
22 *
23 *
24 * This implements a simple synchronous call to reset a WiMAX device.
25 *
26 * Resets aim at being warm, keeping the device handles active;
27 * however, when that fails, it falls back to a cold reset (that will
28 * disconnect and reconnect the device).
29 */
30
31#include <net/wimax.h>
32#include <net/genetlink.h>
33#include <linux/wimax.h>
34#include <linux/security.h>
35#include "wimax-internal.h"
36
37#define D_SUBMODULE op_reset
38#include "debug-levels.h"
39
40
41/**
42 * wimax_reset - Reset a WiMAX device
43 *
44 * @wimax_dev: WiMAX device descriptor
45 *
46 * Returns:
47 *
48 * %0 if ok and a warm reset was done (the device still exists in
49 * the system).
50 *
51 * -%ENODEV if a cold/bus reset had to be done (device has
52 * disconnected and reconnected, so current handle is not valid
53 * any more).
54 *
55 * -%EINVAL if the device is not even registered.
56 *
57 * Any other negative error code shall be considered as
58 * non-recoverable.
59 *
60 * Description:
61 *
62 * Called when wanting to reset the device for any reason. Device is
63 * taken back to power on status.
64 *
65 * This call blocks; on succesful return, the device has completed the
66 * reset process and is ready to operate.
67 */
68int wimax_reset(struct wimax_dev *wimax_dev)
69{
70 int result = -EINVAL;
71 struct device *dev = wimax_dev_to_dev(wimax_dev);
72 enum wimax_st state;
73
74 might_sleep();
75 d_fnstart(3, dev, "(wimax_dev %p)\n", wimax_dev);
76 mutex_lock(&wimax_dev->mutex);
77 dev_hold(wimax_dev->net_dev);
78 state = wimax_dev->state;
79 mutex_unlock(&wimax_dev->mutex);
80
81 if (state >= WIMAX_ST_DOWN) {
82 mutex_lock(&wimax_dev->mutex_reset);
83 result = wimax_dev->op_reset(wimax_dev);
84 mutex_unlock(&wimax_dev->mutex_reset);
85 }
86 dev_put(wimax_dev->net_dev);
87
88 d_fnend(3, dev, "(wimax_dev %p) = %d\n", wimax_dev, result);
89 return result;
90}
91EXPORT_SYMBOL(wimax_reset);
92
93
94static const
95struct nla_policy wimax_gnl_reset_policy[WIMAX_GNL_ATTR_MAX + 1] = {
96 [WIMAX_GNL_RESET_IFIDX] = {
97 .type = NLA_U32,
98 },
99};
100
101
102/*
103 * Exporting to user space over generic netlink
104 *
105 * Parse the reset command from user space, return error code.
106 *
107 * No attributes.
108 */
109static
110int wimax_gnl_doit_reset(struct sk_buff *skb, struct genl_info *info)
111{
112 int result, ifindex;
113 struct wimax_dev *wimax_dev;
114 struct device *dev;
115
116 d_fnstart(3, NULL, "(skb %p info %p)\n", skb, info);
117 result = -ENODEV;
118 if (info->attrs[WIMAX_GNL_RESET_IFIDX] == NULL) {
119 printk(KERN_ERR "WIMAX_GNL_OP_RFKILL: can't find IFIDX "
120 "attribute\n");
121 goto error_no_wimax_dev;
122 }
123 ifindex = nla_get_u32(info->attrs[WIMAX_GNL_RESET_IFIDX]);
124 wimax_dev = wimax_dev_get_by_genl_info(info, ifindex);
125 if (wimax_dev == NULL)
126 goto error_no_wimax_dev;
127 dev = wimax_dev_to_dev(wimax_dev);
128 /* Execute the operation and send the result back to user space */
129 result = wimax_reset(wimax_dev);
130 dev_put(wimax_dev->net_dev);
131error_no_wimax_dev:
132 d_fnend(3, NULL, "(skb %p info %p) = %d\n", skb, info, result);
133 return result;
134}
135
136
137struct genl_ops wimax_gnl_reset = {
138 .cmd = WIMAX_GNL_OP_RESET,
139 .flags = GENL_ADMIN_PERM,
140 .policy = wimax_gnl_reset_policy,
141 .doit = wimax_gnl_doit_reset,
142 .dumpit = NULL,
143};
diff --git a/net/wimax/op-rfkill.c b/net/wimax/op-rfkill.c
new file mode 100644
index 00000000000..8745bac173f
--- /dev/null
+++ b/net/wimax/op-rfkill.c
@@ -0,0 +1,532 @@
1/*
2 * Linux WiMAX
3 * RF-kill framework integration
4 *
5 *
6 * Copyright (C) 2008 Intel Corporation <linux-wimax@intel.com>
7 * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
8 *
9 * This program is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU General Public License version
11 * 2 as published by the Free Software Foundation.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
21 * 02110-1301, USA.
22 *
23 *
24 * This integrates into the Linux Kernel rfkill susbystem so that the
25 * drivers just have to do the bare minimal work, which is providing a
26 * method to set the software RF-Kill switch and to report changes in
27 * the software and hardware switch status.
28 *
29 * A non-polled generic rfkill device is embedded into the WiMAX
30 * subsystem's representation of a device.
31 *
32 * FIXME: Need polled support? use a timer or add the implementation
33 * to the stack.
34 *
35 * All device drivers have to do is after wimax_dev_init(), call
36 * wimax_report_rfkill_hw() and wimax_report_rfkill_sw() to update
37 * initial state and then every time it changes. See wimax.h:struct
38 * wimax_dev for more information.
39 *
40 * ROADMAP
41 *
42 * wimax_gnl_doit_rfkill() User space calling wimax_rfkill()
43 * wimax_rfkill() Kernel calling wimax_rfkill()
44 * __wimax_rf_toggle_radio()
45 *
46 * wimax_rfkill_toggle_radio() RF-Kill subsytem calling
47 * __wimax_rf_toggle_radio()
48 *
49 * __wimax_rf_toggle_radio()
50 * wimax_dev->op_rfkill_sw_toggle() Driver backend
51 * __wimax_state_change()
52 *
53 * wimax_report_rfkill_sw() Driver reports state change
54 * __wimax_state_change()
55 *
56 * wimax_report_rfkill_hw() Driver reports state change
57 * __wimax_state_change()
58 *
59 * wimax_rfkill_add() Initialize/shutdown rfkill support
60 * wimax_rfkill_rm() [called by wimax_dev_add/rm()]
61 */
62
63#include <net/wimax.h>
64#include <net/genetlink.h>
65#include <linux/wimax.h>
66#include <linux/security.h>
67#include <linux/rfkill.h>
68#include <linux/input.h>
69#include "wimax-internal.h"
70
71#define D_SUBMODULE op_rfkill
72#include "debug-levels.h"
73
74#ifdef CONFIG_RFKILL
75
76
77/**
78 * wimax_report_rfkill_hw - Reports changes in the hardware RF switch
79 *
80 * @wimax_dev: WiMAX device descriptor
81 *
82 * @state: New state of the RF Kill switch. %WIMAX_RF_ON radio on,
83 * %WIMAX_RF_OFF radio off.
84 *
85 * When the device detects a change in the state of thehardware RF
86 * switch, it must call this function to let the WiMAX kernel stack
87 * know that the state has changed so it can be properly propagated.
88 *
89 * The WiMAX stack caches the state (the driver doesn't need to). As
90 * well, as the change is propagated it will come back as a request to
91 * change the software state to mirror the hardware state.
92 *
93 * If the device doesn't have a hardware kill switch, just report
94 * it on initialization as always on (%WIMAX_RF_ON, radio on).
95 */
96void wimax_report_rfkill_hw(struct wimax_dev *wimax_dev,
97 enum wimax_rf_state state)
98{
99 int result;
100 struct device *dev = wimax_dev_to_dev(wimax_dev);
101 enum wimax_st wimax_state;
102 enum rfkill_state rfkill_state;
103
104 d_fnstart(3, dev, "(wimax_dev %p state %u)\n", wimax_dev, state);
105 BUG_ON(state == WIMAX_RF_QUERY);
106 BUG_ON(state != WIMAX_RF_ON && state != WIMAX_RF_OFF);
107
108 mutex_lock(&wimax_dev->mutex);
109 result = wimax_dev_is_ready(wimax_dev);
110 if (result < 0)
111 goto error_not_ready;
112
113 if (state != wimax_dev->rf_hw) {
114 wimax_dev->rf_hw = state;
115 rfkill_state = state == WIMAX_RF_ON ?
116 RFKILL_STATE_OFF : RFKILL_STATE_ON;
117 if (wimax_dev->rf_hw == WIMAX_RF_ON
118 && wimax_dev->rf_sw == WIMAX_RF_ON)
119 wimax_state = WIMAX_ST_READY;
120 else
121 wimax_state = WIMAX_ST_RADIO_OFF;
122 __wimax_state_change(wimax_dev, wimax_state);
123 input_report_key(wimax_dev->rfkill_input, KEY_WIMAX,
124 rfkill_state);
125 }
126error_not_ready:
127 mutex_unlock(&wimax_dev->mutex);
128 d_fnend(3, dev, "(wimax_dev %p state %u) = void [%d]\n",
129 wimax_dev, state, result);
130}
131EXPORT_SYMBOL_GPL(wimax_report_rfkill_hw);
132
133
134/**
135 * wimax_report_rfkill_sw - Reports changes in the software RF switch
136 *
137 * @wimax_dev: WiMAX device descriptor
138 *
139 * @state: New state of the RF kill switch. %WIMAX_RF_ON radio on,
140 * %WIMAX_RF_OFF radio off.
141 *
142 * Reports changes in the software RF switch state to the the WiMAX
143 * stack.
144 *
145 * The main use is during initialization, so the driver can query the
146 * device for its current software radio kill switch state and feed it
147 * to the system.
148 *
149 * On the side, the device does not change the software state by
150 * itself. In practice, this can happen, as the device might decide to
151 * switch (in software) the radio off for different reasons.
152 */
153void wimax_report_rfkill_sw(struct wimax_dev *wimax_dev,
154 enum wimax_rf_state state)
155{
156 int result;
157 struct device *dev = wimax_dev_to_dev(wimax_dev);
158 enum wimax_st wimax_state;
159
160 d_fnstart(3, dev, "(wimax_dev %p state %u)\n", wimax_dev, state);
161 BUG_ON(state == WIMAX_RF_QUERY);
162 BUG_ON(state != WIMAX_RF_ON && state != WIMAX_RF_OFF);
163
164 mutex_lock(&wimax_dev->mutex);
165 result = wimax_dev_is_ready(wimax_dev);
166 if (result < 0)
167 goto error_not_ready;
168
169 if (state != wimax_dev->rf_sw) {
170 wimax_dev->rf_sw = state;
171 if (wimax_dev->rf_hw == WIMAX_RF_ON
172 && wimax_dev->rf_sw == WIMAX_RF_ON)
173 wimax_state = WIMAX_ST_READY;
174 else
175 wimax_state = WIMAX_ST_RADIO_OFF;
176 __wimax_state_change(wimax_dev, wimax_state);
177 }
178error_not_ready:
179 mutex_unlock(&wimax_dev->mutex);
180 d_fnend(3, dev, "(wimax_dev %p state %u) = void [%d]\n",
181 wimax_dev, state, result);
182}
183EXPORT_SYMBOL_GPL(wimax_report_rfkill_sw);
184
185
186/*
187 * Callback for the RF Kill toggle operation
188 *
189 * This function is called by:
190 *
191 * - The rfkill subsystem when the RF-Kill key is pressed in the
192 * hardware and the driver notifies through
193 * wimax_report_rfkill_hw(). The rfkill subsystem ends up calling back
194 * here so the software RF Kill switch state is changed to reflect
195 * the hardware switch state.
196 *
197 * - When the user sets the state through sysfs' rfkill/state file
198 *
199 * - When the user calls wimax_rfkill().
200 *
201 * This call blocks!
202 *
203 * WARNING! When we call rfkill_unregister(), this will be called with
204 * state 0!
205 *
206 * WARNING: wimax_dev must be locked
207 */
208static
209int __wimax_rf_toggle_radio(struct wimax_dev *wimax_dev,
210 enum wimax_rf_state state)
211{
212 int result = 0;
213 struct device *dev = wimax_dev_to_dev(wimax_dev);
214 enum wimax_st wimax_state;
215
216 might_sleep();
217 d_fnstart(3, dev, "(wimax_dev %p state %u)\n", wimax_dev, state);
218 if (wimax_dev->rf_sw == state)
219 goto out_no_change;
220 if (wimax_dev->op_rfkill_sw_toggle != NULL)
221 result = wimax_dev->op_rfkill_sw_toggle(wimax_dev, state);
222 else if (state == WIMAX_RF_OFF) /* No op? can't turn off */
223 result = -ENXIO;
224 else /* No op? can turn on */
225 result = 0; /* should never happen tho */
226 if (result >= 0) {
227 result = 0;
228 wimax_dev->rf_sw = state;
229 wimax_state = state == WIMAX_RF_ON ?
230 WIMAX_ST_READY : WIMAX_ST_RADIO_OFF;
231 __wimax_state_change(wimax_dev, wimax_state);
232 }
233out_no_change:
234 d_fnend(3, dev, "(wimax_dev %p state %u) = %d\n",
235 wimax_dev, state, result);
236 return result;
237}
238
239
240/*
241 * Translate from rfkill state to wimax state
242 *
243 * NOTE: Special state handling rules here
244 *
245 * Just pretend the call didn't happen if we are in a state where
246 * we know for sure it cannot be handled (WIMAX_ST_DOWN or
247 * __WIMAX_ST_QUIESCING). rfkill() needs it to register and
248 * unregister, as it will run this path.
249 *
250 * NOTE: This call will block until the operation is completed.
251 */
252static
253int wimax_rfkill_toggle_radio(void *data, enum rfkill_state state)
254{
255 int result;
256 struct wimax_dev *wimax_dev = data;
257 struct device *dev = wimax_dev_to_dev(wimax_dev);
258 enum wimax_rf_state rf_state;
259
260 d_fnstart(3, dev, "(wimax_dev %p state %u)\n", wimax_dev, state);
261 switch (state) {
262 case RFKILL_STATE_ON:
263 rf_state = WIMAX_RF_OFF;
264 break;
265 case RFKILL_STATE_OFF:
266 rf_state = WIMAX_RF_ON;
267 break;
268 default:
269 BUG();
270 }
271 mutex_lock(&wimax_dev->mutex);
272 if (wimax_dev->state <= __WIMAX_ST_QUIESCING)
273 result = 0; /* just pretend it didn't happen */
274 else
275 result = __wimax_rf_toggle_radio(wimax_dev, rf_state);
276 mutex_unlock(&wimax_dev->mutex);
277 d_fnend(3, dev, "(wimax_dev %p state %u) = %d\n",
278 wimax_dev, state, result);
279 return result;
280}
281
282
283/**
284 * wimax_rfkill - Set the software RF switch state for a WiMAX device
285 *
286 * @wimax_dev: WiMAX device descriptor
287 *
288 * @state: New RF state.
289 *
290 * Returns:
291 *
292 * >= 0 toggle state if ok, < 0 errno code on error. The toggle state
293 * is returned as a bitmap, bit 0 being the hardware RF state, bit 1
294 * the software RF state.
295 *
296 * 0 means disabled (%WIMAX_RF_ON, radio on), 1 means enabled radio
297 * off (%WIMAX_RF_OFF).
298 *
299 * Description:
300 *
301 * Called by the user when he wants to request the WiMAX radio to be
302 * switched on (%WIMAX_RF_ON) or off (%WIMAX_RF_OFF). With
303 * %WIMAX_RF_QUERY, just the current state is returned.
304 *
305 * NOTE:
306 *
307 * This call will block until the operation is complete.
308 */
309int wimax_rfkill(struct wimax_dev *wimax_dev, enum wimax_rf_state state)
310{
311 int result;
312 struct device *dev = wimax_dev_to_dev(wimax_dev);
313
314 d_fnstart(3, dev, "(wimax_dev %p state %u)\n", wimax_dev, state);
315 mutex_lock(&wimax_dev->mutex);
316 result = wimax_dev_is_ready(wimax_dev);
317 if (result < 0)
318 goto error_not_ready;
319 switch (state) {
320 case WIMAX_RF_ON:
321 case WIMAX_RF_OFF:
322 result = __wimax_rf_toggle_radio(wimax_dev, state);
323 if (result < 0)
324 goto error;
325 break;
326 case WIMAX_RF_QUERY:
327 break;
328 default:
329 result = -EINVAL;
330 goto error;
331 }
332 result = wimax_dev->rf_sw << 1 | wimax_dev->rf_hw;
333error:
334error_not_ready:
335 mutex_unlock(&wimax_dev->mutex);
336 d_fnend(3, dev, "(wimax_dev %p state %u) = %d\n",
337 wimax_dev, state, result);
338 return result;
339}
340EXPORT_SYMBOL(wimax_rfkill);
341
342
343/*
344 * Register a new WiMAX device's RF Kill support
345 *
346 * WARNING: wimax_dev->mutex must be unlocked
347 */
348int wimax_rfkill_add(struct wimax_dev *wimax_dev)
349{
350 int result;
351 struct rfkill *rfkill;
352 struct input_dev *input_dev;
353 struct device *dev = wimax_dev_to_dev(wimax_dev);
354
355 d_fnstart(3, dev, "(wimax_dev %p)\n", wimax_dev);
356 /* Initialize RF Kill */
357 result = -ENOMEM;
358 rfkill = rfkill_allocate(dev, RFKILL_TYPE_WIMAX);
359 if (rfkill == NULL)
360 goto error_rfkill_allocate;
361 wimax_dev->rfkill = rfkill;
362
363 rfkill->name = wimax_dev->name;
364 rfkill->state = RFKILL_STATE_OFF;
365 rfkill->data = wimax_dev;
366 rfkill->toggle_radio = wimax_rfkill_toggle_radio;
367 rfkill->user_claim_unsupported = 1;
368
369 /* Initialize the input device for the hw key */
370 input_dev = input_allocate_device();
371 if (input_dev == NULL)
372 goto error_input_allocate;
373 wimax_dev->rfkill_input = input_dev;
374 d_printf(1, dev, "rfkill %p input %p\n", rfkill, input_dev);
375
376 input_dev->name = wimax_dev->name;
377 /* FIXME: get a real device bus ID and stuff? do we care? */
378 input_dev->id.bustype = BUS_HOST;
379 input_dev->id.vendor = 0xffff;
380 input_dev->evbit[0] = BIT(EV_KEY);
381 set_bit(KEY_WIMAX, input_dev->keybit);
382
383 /* Register both */
384 result = input_register_device(wimax_dev->rfkill_input);
385 if (result < 0)
386 goto error_input_register;
387 result = rfkill_register(wimax_dev->rfkill);
388 if (result < 0)
389 goto error_rfkill_register;
390
391 /* If there is no SW toggle op, SW RFKill is always on */
392 if (wimax_dev->op_rfkill_sw_toggle == NULL)
393 wimax_dev->rf_sw = WIMAX_RF_ON;
394
395 d_fnend(3, dev, "(wimax_dev %p) = 0\n", wimax_dev);
396 return 0;
397
398 /* if rfkill_register() suceeds, can't use rfkill_free() any
399 * more, only rfkill_unregister() [it owns the refcount]; with
400 * the input device we have the same issue--hence the if. */
401error_rfkill_register:
402 input_unregister_device(wimax_dev->rfkill_input);
403 wimax_dev->rfkill_input = NULL;
404error_input_register:
405 if (wimax_dev->rfkill_input)
406 input_free_device(wimax_dev->rfkill_input);
407error_input_allocate:
408 rfkill_free(wimax_dev->rfkill);
409error_rfkill_allocate:
410 d_fnend(3, dev, "(wimax_dev %p) = %d\n", wimax_dev, result);
411 return result;
412}
413
414
415/*
416 * Deregister a WiMAX device's RF Kill support
417 *
418 * Ick, we can't call rfkill_free() after rfkill_unregister()...oh
419 * well.
420 *
421 * WARNING: wimax_dev->mutex must be unlocked
422 */
423void wimax_rfkill_rm(struct wimax_dev *wimax_dev)
424{
425 struct device *dev = wimax_dev_to_dev(wimax_dev);
426 d_fnstart(3, dev, "(wimax_dev %p)\n", wimax_dev);
427 rfkill_unregister(wimax_dev->rfkill); /* frees */
428 input_unregister_device(wimax_dev->rfkill_input);
429 d_fnend(3, dev, "(wimax_dev %p)\n", wimax_dev);
430}
431
432
433#else /* #ifdef CONFIG_RFKILL */
434
435void wimax_report_rfkill_hw(struct wimax_dev *wimax_dev,
436 enum wimax_rf_state state)
437{
438}
439EXPORT_SYMBOL_GPL(wimax_report_rfkill_hw);
440
441void wimax_report_rfkill_sw(struct wimax_dev *wimax_dev,
442 enum wimax_rf_state state)
443{
444}
445EXPORT_SYMBOL_GPL(wimax_report_rfkill_sw);
446
447int wimax_rfkill(struct wimax_dev *wimax_dev,
448 enum wimax_rf_state state)
449{
450 return WIMAX_RF_ON << 1 | WIMAX_RF_ON;
451}
452EXPORT_SYMBOL_GPL(wimax_rfkill);
453
454int wimax_rfkill_add(struct wimax_dev *wimax_dev)
455{
456 return 0;
457}
458
459void wimax_rfkill_rm(struct wimax_dev *wimax_dev)
460{
461}
462
463#endif /* #ifdef CONFIG_RFKILL */
464
465
466/*
467 * Exporting to user space over generic netlink
468 *
469 * Parse the rfkill command from user space, return a combination
470 * value that describe the states of the different toggles.
471 *
472 * Only one attribute: the new state requested (on, off or no change,
473 * just query).
474 */
475
476static const
477struct nla_policy wimax_gnl_rfkill_policy[WIMAX_GNL_ATTR_MAX + 1] = {
478 [WIMAX_GNL_RFKILL_IFIDX] = {
479 .type = NLA_U32,
480 },
481 [WIMAX_GNL_RFKILL_STATE] = {
482 .type = NLA_U32 /* enum wimax_rf_state */
483 },
484};
485
486
487static
488int wimax_gnl_doit_rfkill(struct sk_buff *skb, struct genl_info *info)
489{
490 int result, ifindex;
491 struct wimax_dev *wimax_dev;
492 struct device *dev;
493 enum wimax_rf_state new_state;
494
495 d_fnstart(3, NULL, "(skb %p info %p)\n", skb, info);
496 result = -ENODEV;
497 if (info->attrs[WIMAX_GNL_RFKILL_IFIDX] == NULL) {
498 printk(KERN_ERR "WIMAX_GNL_OP_RFKILL: can't find IFIDX "
499 "attribute\n");
500 goto error_no_wimax_dev;
501 }
502 ifindex = nla_get_u32(info->attrs[WIMAX_GNL_RFKILL_IFIDX]);
503 wimax_dev = wimax_dev_get_by_genl_info(info, ifindex);
504 if (wimax_dev == NULL)
505 goto error_no_wimax_dev;
506 dev = wimax_dev_to_dev(wimax_dev);
507 result = -EINVAL;
508 if (info->attrs[WIMAX_GNL_RFKILL_STATE] == NULL) {
509 dev_err(dev, "WIMAX_GNL_RFKILL: can't find RFKILL_STATE "
510 "attribute\n");
511 goto error_no_pid;
512 }
513 new_state = nla_get_u32(info->attrs[WIMAX_GNL_RFKILL_STATE]);
514
515 /* Execute the operation and send the result back to user space */
516 result = wimax_rfkill(wimax_dev, new_state);
517error_no_pid:
518 dev_put(wimax_dev->net_dev);
519error_no_wimax_dev:
520 d_fnend(3, NULL, "(skb %p info %p) = %d\n", skb, info, result);
521 return result;
522}
523
524
525struct genl_ops wimax_gnl_rfkill = {
526 .cmd = WIMAX_GNL_OP_RFKILL,
527 .flags = GENL_ADMIN_PERM,
528 .policy = wimax_gnl_rfkill_policy,
529 .doit = wimax_gnl_doit_rfkill,
530 .dumpit = NULL,
531};
532
diff --git a/net/wimax/stack.c b/net/wimax/stack.c
new file mode 100644
index 00000000000..d4da92f8981
--- /dev/null
+++ b/net/wimax/stack.c
@@ -0,0 +1,599 @@
1/*
2 * Linux WiMAX
3 * Initialization, addition and removal of wimax devices
4 *
5 *
6 * Copyright (C) 2005-2006 Intel Corporation <linux-wimax@intel.com>
7 * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
8 *
9 * This program is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU General Public License version
11 * 2 as published by the Free Software Foundation.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
21 * 02110-1301, USA.
22 *
23 *
24 * This implements:
25 *
26 * - basic life cycle of 'struct wimax_dev' [wimax_dev_*()]; on
27 * addition/registration initialize all subfields and allocate
28 * generic netlink resources for user space communication. On
29 * removal/unregistration, undo all that.
30 *
31 * - device state machine [wimax_state_change()] and support to send
32 * reports to user space when the state changes
33 * [wimax_gnl_re_state_change*()].
34 *
35 * See include/net/wimax.h for rationales and design.
36 *
37 * ROADMAP
38 *
39 * [__]wimax_state_change() Called by drivers to update device's state
40 * wimax_gnl_re_state_change_alloc()
41 * wimax_gnl_re_state_change_send()
42 *
43 * wimax_dev_init() Init a device
44 * wimax_dev_add() Register
45 * wimax_rfkill_add()
46 * wimax_gnl_add() Register all the generic netlink resources.
47 * wimax_id_table_add()
48 * wimax_dev_rm() Unregister
49 * wimax_id_table_rm()
50 * wimax_gnl_rm()
51 * wimax_rfkill_rm()
52 */
53#include <linux/device.h>
54#include <net/genetlink.h>
55#include <linux/netdevice.h>
56#include <linux/wimax.h>
57#include "wimax-internal.h"
58
59
60#define D_SUBMODULE stack
61#include "debug-levels.h"
62
63/*
64 * Authoritative source for the RE_STATE_CHANGE attribute policy
65 *
66 * We don't really use it here, but /me likes to keep the definition
67 * close to where the data is generated.
68 */
69/*
70static const
71struct nla_policy wimax_gnl_re_status_change[WIMAX_GNL_ATTR_MAX + 1] = {
72 [WIMAX_GNL_STCH_STATE_OLD] = { .type = NLA_U8 },
73 [WIMAX_GNL_STCH_STATE_NEW] = { .type = NLA_U8 },
74};
75*/
76
77
78/*
79 * Allocate a Report State Change message
80 *
81 * @header: save it, you need it for _send()
82 *
83 * Creates and fills a basic state change message; different code
84 * paths can then add more attributes to the message as needed.
85 *
86 * Use wimax_gnl_re_state_change_send() to send the returned skb.
87 *
88 * Returns: skb with the genl message if ok, IS_ERR() ptr on error
89 * with an errno code.
90 */
91static
92struct sk_buff *wimax_gnl_re_state_change_alloc(
93 struct wimax_dev *wimax_dev,
94 enum wimax_st new_state, enum wimax_st old_state,
95 void **header)
96{
97 int result;
98 struct device *dev = wimax_dev_to_dev(wimax_dev);
99 void *data;
100 struct sk_buff *report_skb;
101
102 d_fnstart(3, dev, "(wimax_dev %p new_state %u old_state %u)\n",
103 wimax_dev, new_state, old_state);
104 result = -ENOMEM;
105 report_skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
106 if (report_skb == NULL) {
107 dev_err(dev, "RE_STCH: can't create message\n");
108 goto error_new;
109 }
110 data = genlmsg_put(report_skb, 0, wimax_gnl_mcg.id, &wimax_gnl_family,
111 0, WIMAX_GNL_RE_STATE_CHANGE);
112 if (data == NULL) {
113 dev_err(dev, "RE_STCH: can't put data into message\n");
114 goto error_put;
115 }
116 *header = data;
117
118 result = nla_put_u8(report_skb, WIMAX_GNL_STCH_STATE_OLD, old_state);
119 if (result < 0) {
120 dev_err(dev, "RE_STCH: Error adding OLD attr: %d\n", result);
121 goto error_put;
122 }
123 result = nla_put_u8(report_skb, WIMAX_GNL_STCH_STATE_NEW, new_state);
124 if (result < 0) {
125 dev_err(dev, "RE_STCH: Error adding NEW attr: %d\n", result);
126 goto error_put;
127 }
128 result = nla_put_u32(report_skb, WIMAX_GNL_STCH_IFIDX,
129 wimax_dev->net_dev->ifindex);
130 if (result < 0) {
131 dev_err(dev, "RE_STCH: Error adding IFINDEX attribute\n");
132 goto error_put;
133 }
134 d_fnend(3, dev, "(wimax_dev %p new_state %u old_state %u) = %p\n",
135 wimax_dev, new_state, old_state, report_skb);
136 return report_skb;
137
138error_put:
139 nlmsg_free(report_skb);
140error_new:
141 d_fnend(3, dev, "(wimax_dev %p new_state %u old_state %u) = %d\n",
142 wimax_dev, new_state, old_state, result);
143 return ERR_PTR(result);
144}
145
146
147/*
148 * Send a Report State Change message (as created with _alloc).
149 *
150 * @report_skb: as returned by wimax_gnl_re_state_change_alloc()
151 * @header: as returned by wimax_gnl_re_state_change_alloc()
152 *
153 * Returns: 0 if ok, < 0 errno code on error.
154 *
155 * If the message is NULL, pretend it didn't happen.
156 */
157static
158int wimax_gnl_re_state_change_send(
159 struct wimax_dev *wimax_dev, struct sk_buff *report_skb,
160 void *header)
161{
162 int result = 0;
163 struct device *dev = wimax_dev_to_dev(wimax_dev);
164 d_fnstart(3, dev, "(wimax_dev %p report_skb %p)\n",
165 wimax_dev, report_skb);
166 if (report_skb == NULL)
167 goto out;
168 genlmsg_end(report_skb, header);
169 result = genlmsg_multicast(report_skb, 0, wimax_gnl_mcg.id, GFP_KERNEL);
170 if (result == -ESRCH) /* Nobody connected, ignore it */
171 result = 0; /* btw, the skb is freed already */
172 if (result < 0) {
173 dev_err(dev, "RE_STCH: Error sending: %d\n", result);
174 nlmsg_free(report_skb);
175 }
176out:
177 d_fnend(3, dev, "(wimax_dev %p report_skb %p) = %d\n",
178 wimax_dev, report_skb, result);
179 return result;
180}
181
182
183static
184void __check_new_state(enum wimax_st old_state, enum wimax_st new_state,
185 unsigned allowed_states_bm)
186{
187 if (WARN_ON(((1 << new_state) & allowed_states_bm) == 0)) {
188 printk(KERN_ERR "SW BUG! Forbidden state change %u -> %u\n",
189 old_state, new_state);
190 }
191}
192
193
194/*
195 * Set the current state of a WiMAX device [unlocking version of
196 * wimax_state_change().
197 */
198void __wimax_state_change(struct wimax_dev *wimax_dev, enum wimax_st new_state)
199{
200 struct device *dev = wimax_dev_to_dev(wimax_dev);
201 enum wimax_st old_state = wimax_dev->state;
202 struct sk_buff *stch_skb;
203 void *header;
204
205 d_fnstart(3, dev, "(wimax_dev %p new_state %u [old %u])\n",
206 wimax_dev, new_state, old_state);
207
208 if (WARN_ON(new_state >= __WIMAX_ST_INVALID)) {
209 dev_err(dev, "SW BUG: requesting invalid state %u\n",
210 new_state);
211 goto out;
212 }
213 if (old_state == new_state)
214 goto out;
215 header = NULL; /* gcc complains? can't grok why */
216 stch_skb = wimax_gnl_re_state_change_alloc(
217 wimax_dev, new_state, old_state, &header);
218
219 /* Verify the state transition and do exit-from-state actions */
220 switch (old_state) {
221 case __WIMAX_ST_NULL:
222 __check_new_state(old_state, new_state,
223 1 << WIMAX_ST_DOWN);
224 break;
225 case WIMAX_ST_DOWN:
226 __check_new_state(old_state, new_state,
227 1 << __WIMAX_ST_QUIESCING
228 | 1 << WIMAX_ST_UNINITIALIZED
229 | 1 << WIMAX_ST_RADIO_OFF);
230 break;
231 case __WIMAX_ST_QUIESCING:
232 __check_new_state(old_state, new_state, 1 << WIMAX_ST_DOWN);
233 break;
234 case WIMAX_ST_UNINITIALIZED:
235 __check_new_state(old_state, new_state,
236 1 << __WIMAX_ST_QUIESCING
237 | 1 << WIMAX_ST_RADIO_OFF);
238 break;
239 case WIMAX_ST_RADIO_OFF:
240 __check_new_state(old_state, new_state,
241 1 << __WIMAX_ST_QUIESCING
242 | 1 << WIMAX_ST_READY);
243 break;
244 case WIMAX_ST_READY:
245 __check_new_state(old_state, new_state,
246 1 << __WIMAX_ST_QUIESCING
247 | 1 << WIMAX_ST_RADIO_OFF
248 | 1 << WIMAX_ST_SCANNING
249 | 1 << WIMAX_ST_CONNECTING
250 | 1 << WIMAX_ST_CONNECTED);
251 break;
252 case WIMAX_ST_SCANNING:
253 __check_new_state(old_state, new_state,
254 1 << __WIMAX_ST_QUIESCING
255 | 1 << WIMAX_ST_RADIO_OFF
256 | 1 << WIMAX_ST_READY
257 | 1 << WIMAX_ST_CONNECTING
258 | 1 << WIMAX_ST_CONNECTED);
259 break;
260 case WIMAX_ST_CONNECTING:
261 __check_new_state(old_state, new_state,
262 1 << __WIMAX_ST_QUIESCING
263 | 1 << WIMAX_ST_RADIO_OFF
264 | 1 << WIMAX_ST_READY
265 | 1 << WIMAX_ST_SCANNING
266 | 1 << WIMAX_ST_CONNECTED);
267 break;
268 case WIMAX_ST_CONNECTED:
269 __check_new_state(old_state, new_state,
270 1 << __WIMAX_ST_QUIESCING
271 | 1 << WIMAX_ST_RADIO_OFF
272 | 1 << WIMAX_ST_READY);
273 netif_tx_disable(wimax_dev->net_dev);
274 netif_carrier_off(wimax_dev->net_dev);
275 break;
276 case __WIMAX_ST_INVALID:
277 default:
278 dev_err(dev, "SW BUG: wimax_dev %p is in unknown state %u\n",
279 wimax_dev, wimax_dev->state);
280 WARN_ON(1);
281 goto out;
282 }
283
284 /* Execute the actions of entry to the new state */
285 switch (new_state) {
286 case __WIMAX_ST_NULL:
287 dev_err(dev, "SW BUG: wimax_dev %p entering NULL state "
288 "from %u\n", wimax_dev, wimax_dev->state);
289 WARN_ON(1); /* Nobody can enter this state */
290 break;
291 case WIMAX_ST_DOWN:
292 break;
293 case __WIMAX_ST_QUIESCING:
294 break;
295 case WIMAX_ST_UNINITIALIZED:
296 break;
297 case WIMAX_ST_RADIO_OFF:
298 break;
299 case WIMAX_ST_READY:
300 break;
301 case WIMAX_ST_SCANNING:
302 break;
303 case WIMAX_ST_CONNECTING:
304 break;
305 case WIMAX_ST_CONNECTED:
306 netif_carrier_on(wimax_dev->net_dev);
307 netif_wake_queue(wimax_dev->net_dev);
308 break;
309 case __WIMAX_ST_INVALID:
310 default:
311 BUG();
312 }
313 __wimax_state_set(wimax_dev, new_state);
314 if (stch_skb)
315 wimax_gnl_re_state_change_send(wimax_dev, stch_skb, header);
316out:
317 d_fnend(3, dev, "(wimax_dev %p new_state %u [old %u]) = void\n",
318 wimax_dev, new_state, old_state);
319 return;
320}
321
322
323/**
324 * wimax_state_change - Set the current state of a WiMAX device
325 *
326 * @wimax_dev: WiMAX device descriptor (properly referenced)
327 * @new_state: New state to switch to
328 *
329 * This implements the state changes for the wimax devices. It will
330 *
331 * - verify that the state transition is legal (for now it'll just
332 * print a warning if not) according to the table in
333 * linux/wimax.h's documentation for 'enum wimax_st'.
334 *
335 * - perform the actions needed for leaving the current state and
336 * whichever are needed for entering the new state.
337 *
338 * - issue a report to user space indicating the new state (and an
339 * optional payload with information about the new state).
340 *
341 * NOTE: @wimax_dev must be locked
342 */
343void wimax_state_change(struct wimax_dev *wimax_dev, enum wimax_st new_state)
344{
345 mutex_lock(&wimax_dev->mutex);
346 __wimax_state_change(wimax_dev, new_state);
347 mutex_unlock(&wimax_dev->mutex);
348 return;
349}
350EXPORT_SYMBOL_GPL(wimax_state_change);
351
352
353/**
354 * wimax_state_get() - Return the current state of a WiMAX device
355 *
356 * @wimax_dev: WiMAX device descriptor
357 *
358 * Returns: Current state of the device according to its driver.
359 */
360enum wimax_st wimax_state_get(struct wimax_dev *wimax_dev)
361{
362 enum wimax_st state;
363 mutex_lock(&wimax_dev->mutex);
364 state = wimax_dev->state;
365 mutex_unlock(&wimax_dev->mutex);
366 return state;
367}
368EXPORT_SYMBOL_GPL(wimax_state_get);
369
370
371/**
372 * wimax_dev_init - initialize a newly allocated instance
373 *
374 * @wimax_dev: WiMAX device descriptor to initialize.
375 *
376 * Initializes fields of a freshly allocated @wimax_dev instance. This
377 * function assumes that after allocation, the memory occupied by
378 * @wimax_dev was zeroed.
379 */
380void wimax_dev_init(struct wimax_dev *wimax_dev)
381{
382 INIT_LIST_HEAD(&wimax_dev->id_table_node);
383 __wimax_state_set(wimax_dev, WIMAX_ST_UNINITIALIZED);
384 mutex_init(&wimax_dev->mutex);
385 mutex_init(&wimax_dev->mutex_reset);
386}
387EXPORT_SYMBOL_GPL(wimax_dev_init);
388
389/*
390 * This extern is declared here because it's easier to keep track --
391 * both declarations are a list of the same
392 */
393extern struct genl_ops
394 wimax_gnl_msg_from_user,
395 wimax_gnl_reset,
396 wimax_gnl_rfkill;
397
398static
399struct genl_ops *wimax_gnl_ops[] = {
400 &wimax_gnl_msg_from_user,
401 &wimax_gnl_reset,
402 &wimax_gnl_rfkill,
403};
404
405
406static
407size_t wimax_addr_scnprint(char *addr_str, size_t addr_str_size,
408 unsigned char *addr, size_t addr_len)
409{
410 unsigned cnt, total;
411 for (total = cnt = 0; cnt < addr_len; cnt++)
412 total += scnprintf(addr_str + total, addr_str_size - total,
413 "%02x%c", addr[cnt],
414 cnt == addr_len - 1 ? '\0' : ':');
415 return total;
416}
417
418
419/**
420 * wimax_dev_add - Register a new WiMAX device
421 *
422 * @wimax_dev: WiMAX device descriptor (as embedded in your @net_dev's
423 * priv data). You must have called wimax_dev_init() on it before.
424 *
425 * @net_dev: net device the @wimax_dev is associated with. The
426 * function expects SET_NETDEV_DEV() and register_netdev() were
427 * already called on it.
428 *
429 * Registers the new WiMAX device, sets up the user-kernel control
430 * interface (generic netlink) and common WiMAX infrastructure.
431 *
432 * Note that the parts that will allow interaction with user space are
433 * setup at the very end, when the rest is in place, as once that
434 * happens, the driver might get user space control requests via
435 * netlink or from debugfs that might translate into calls into
436 * wimax_dev->op_*().
437 */
438int wimax_dev_add(struct wimax_dev *wimax_dev, struct net_device *net_dev)
439{
440 int result;
441 struct device *dev = net_dev->dev.parent;
442 char addr_str[32];
443
444 d_fnstart(3, dev, "(wimax_dev %p net_dev %p)\n", wimax_dev, net_dev);
445
446 /* Do the RFKILL setup before locking, as RFKILL will call
447 * into our functions. */
448 wimax_dev->net_dev = net_dev;
449 result = wimax_rfkill_add(wimax_dev);
450 if (result < 0)
451 goto error_rfkill_add;
452
453 /* Set up user-space interaction */
454 mutex_lock(&wimax_dev->mutex);
455 wimax_id_table_add(wimax_dev);
456 result = wimax_debugfs_add(wimax_dev);
457 if (result < 0) {
458 dev_err(dev, "cannot initialize debugfs: %d\n",
459 result);
460 goto error_debugfs_add;
461 }
462
463 __wimax_state_set(wimax_dev, WIMAX_ST_DOWN);
464 mutex_unlock(&wimax_dev->mutex);
465
466 wimax_addr_scnprint(addr_str, sizeof(addr_str),
467 net_dev->dev_addr, net_dev->addr_len);
468 dev_err(dev, "WiMAX interface %s (%s) ready\n",
469 net_dev->name, addr_str);
470 d_fnend(3, dev, "(wimax_dev %p net_dev %p) = 0\n", wimax_dev, net_dev);
471 return 0;
472
473error_debugfs_add:
474 wimax_id_table_rm(wimax_dev);
475 mutex_unlock(&wimax_dev->mutex);
476 wimax_rfkill_rm(wimax_dev);
477error_rfkill_add:
478 d_fnend(3, dev, "(wimax_dev %p net_dev %p) = %d\n",
479 wimax_dev, net_dev, result);
480 return result;
481}
482EXPORT_SYMBOL_GPL(wimax_dev_add);
483
484
485/**
486 * wimax_dev_rm - Unregister an existing WiMAX device
487 *
488 * @wimax_dev: WiMAX device descriptor
489 *
490 * Unregisters a WiMAX device previously registered for use with
491 * wimax_add_rm().
492 *
493 * IMPORTANT! Must call before calling unregister_netdev().
494 *
495 * After this function returns, you will not get any more user space
496 * control requests (via netlink or debugfs) and thus to wimax_dev->ops.
497 *
498 * Reentrancy control is ensured by setting the state to
499 * %__WIMAX_ST_QUIESCING. rfkill operations coming through
500 * wimax_*rfkill*() will be stopped by the quiescing state; ops coming
501 * from the rfkill subsystem will be stopped by the support being
502 * removed by wimax_rfkill_rm().
503 */
504void wimax_dev_rm(struct wimax_dev *wimax_dev)
505{
506 d_fnstart(3, NULL, "(wimax_dev %p)\n", wimax_dev);
507
508 mutex_lock(&wimax_dev->mutex);
509 __wimax_state_change(wimax_dev, __WIMAX_ST_QUIESCING);
510 wimax_debugfs_rm(wimax_dev);
511 wimax_id_table_rm(wimax_dev);
512 __wimax_state_change(wimax_dev, WIMAX_ST_DOWN);
513 mutex_unlock(&wimax_dev->mutex);
514 wimax_rfkill_rm(wimax_dev);
515 d_fnend(3, NULL, "(wimax_dev %p) = void\n", wimax_dev);
516}
517EXPORT_SYMBOL_GPL(wimax_dev_rm);
518
519struct genl_family wimax_gnl_family = {
520 .id = GENL_ID_GENERATE,
521 .name = "WiMAX",
522 .version = WIMAX_GNL_VERSION,
523 .hdrsize = 0,
524 .maxattr = WIMAX_GNL_ATTR_MAX,
525};
526
527struct genl_multicast_group wimax_gnl_mcg = {
528 .name = "msg",
529};
530
531
532
533/* Shutdown the wimax stack */
534static
535int __init wimax_subsys_init(void)
536{
537 int result, cnt;
538
539 d_fnstart(4, NULL, "()\n");
540 snprintf(wimax_gnl_family.name, sizeof(wimax_gnl_family.name),
541 "WiMAX");
542 result = genl_register_family(&wimax_gnl_family);
543 if (unlikely(result < 0)) {
544 printk(KERN_ERR "cannot register generic netlink family: %d\n",
545 result);
546 goto error_register_family;
547 }
548
549 for (cnt = 0; cnt < ARRAY_SIZE(wimax_gnl_ops); cnt++) {
550 result = genl_register_ops(&wimax_gnl_family,
551 wimax_gnl_ops[cnt]);
552 d_printf(4, NULL, "registering generic netlink op code "
553 "%u: %d\n", wimax_gnl_ops[cnt]->cmd, result);
554 if (unlikely(result < 0)) {
555 printk(KERN_ERR "cannot register generic netlink op "
556 "code %u: %d\n",
557 wimax_gnl_ops[cnt]->cmd, result);
558 goto error_register_ops;
559 }
560 }
561
562 result = genl_register_mc_group(&wimax_gnl_family, &wimax_gnl_mcg);
563 if (result < 0)
564 goto error_mc_group;
565 d_fnend(4, NULL, "() = 0\n");
566 return 0;
567
568error_mc_group:
569error_register_ops:
570 for (cnt--; cnt >= 0; cnt--)
571 genl_unregister_ops(&wimax_gnl_family,
572 wimax_gnl_ops[cnt]);
573 genl_unregister_family(&wimax_gnl_family);
574error_register_family:
575 d_fnend(4, NULL, "() = %d\n", result);
576 return result;
577
578}
579module_init(wimax_subsys_init);
580
581
582/* Shutdown the wimax stack */
583static
584void __exit wimax_subsys_exit(void)
585{
586 int cnt;
587 wimax_id_table_release();
588 genl_unregister_mc_group(&wimax_gnl_family, &wimax_gnl_mcg);
589 for (cnt = ARRAY_SIZE(wimax_gnl_ops) - 1; cnt >= 0; cnt--)
590 genl_unregister_ops(&wimax_gnl_family,
591 wimax_gnl_ops[cnt]);
592 genl_unregister_family(&wimax_gnl_family);
593}
594module_exit(wimax_subsys_exit);
595
596MODULE_AUTHOR("Intel Corporation <linux-wimax@intel.com>");
597MODULE_DESCRIPTION("Linux WiMAX stack");
598MODULE_LICENSE("GPL");
599
diff --git a/net/wimax/wimax-internal.h b/net/wimax/wimax-internal.h
new file mode 100644
index 00000000000..1e743d21485
--- /dev/null
+++ b/net/wimax/wimax-internal.h
@@ -0,0 +1,91 @@
1/*
2 * Linux WiMAX
3 * Internal API for kernel space WiMAX stack
4 *
5 *
6 * Copyright (C) 2007 Intel Corporation <linux-wimax@intel.com>
7 * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
8 *
9 * This program is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU General Public License version
11 * 2 as published by the Free Software Foundation.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
21 * 02110-1301, USA.
22 *
23 *
24 * This header file is for declarations and definitions internal to
25 * the WiMAX stack. For public APIs and documentation, see
26 * include/net/wimax.h and include/linux/wimax.h.
27 */
28
29#ifndef __WIMAX_INTERNAL_H__
30#define __WIMAX_INTERNAL_H__
31#ifdef __KERNEL__
32
33#include <linux/device.h>
34#include <net/wimax.h>
35
36
37/*
38 * Decide if a (locked) device is ready for use
39 *
40 * Before using the device structure, it must be locked
41 * (wimax_dev->mutex). As well, most operations need to call this
42 * function to check if the state is the right one.
43 *
44 * An error value will be returned if the state is not the right
45 * one. In that case, the caller should not attempt to use the device
46 * and just unlock it.
47 */
48static inline __must_check
49int wimax_dev_is_ready(struct wimax_dev *wimax_dev)
50{
51 if (wimax_dev->state == __WIMAX_ST_NULL)
52 return -EINVAL; /* Device is not even registered! */
53 if (wimax_dev->state == WIMAX_ST_DOWN)
54 return -ENOMEDIUM;
55 if (wimax_dev->state == __WIMAX_ST_QUIESCING)
56 return -ESHUTDOWN;
57 return 0;
58}
59
60
61static inline
62void __wimax_state_set(struct wimax_dev *wimax_dev, enum wimax_st state)
63{
64 wimax_dev->state = state;
65}
66extern void __wimax_state_change(struct wimax_dev *, enum wimax_st);
67
68#ifdef CONFIG_DEBUG_FS
69extern int wimax_debugfs_add(struct wimax_dev *);
70extern void wimax_debugfs_rm(struct wimax_dev *);
71#else
72static inline int wimax_debugfs_add(struct wimax_dev *wimax_dev)
73{
74 return 0;
75}
76static inline void wimax_debugfs_rm(struct wimax_dev *wimax_dev) {}
77#endif
78
79extern void wimax_id_table_add(struct wimax_dev *);
80extern struct wimax_dev *wimax_dev_get_by_genl_info(struct genl_info *, int);
81extern void wimax_id_table_rm(struct wimax_dev *);
82extern void wimax_id_table_release(void);
83
84extern int wimax_rfkill_add(struct wimax_dev *);
85extern void wimax_rfkill_rm(struct wimax_dev *);
86
87extern struct genl_family wimax_gnl_family;
88extern struct genl_multicast_group wimax_gnl_mcg;
89
90#endif /* #ifdef __KERNEL__ */
91#endif /* #ifndef __WIMAX_INTERNAL_H__ */