diff options
Diffstat (limited to 'net/sctp')
-rw-r--r-- | net/sctp/associola.c | 8 | ||||
-rw-r--r-- | net/sctp/bind_addr.c | 17 | ||||
-rw-r--r-- | net/sctp/input.c | 3 | ||||
-rw-r--r-- | net/sctp/ipv6.c | 2 | ||||
-rw-r--r-- | net/sctp/output.c | 8 | ||||
-rw-r--r-- | net/sctp/outqueue.c | 19 | ||||
-rw-r--r-- | net/sctp/protocol.c | 155 | ||||
-rw-r--r-- | net/sctp/sm_make_chunk.c | 55 | ||||
-rw-r--r-- | net/sctp/sm_sideeffect.c | 7 | ||||
-rw-r--r-- | net/sctp/sm_statefuns.c | 57 | ||||
-rw-r--r-- | net/sctp/socket.c | 202 | ||||
-rw-r--r-- | net/sctp/sysctl.c | 20 |
12 files changed, 469 insertions, 84 deletions
diff --git a/net/sctp/associola.c b/net/sctp/associola.c index 4a62888f2e4..49814827f81 100644 --- a/net/sctp/associola.c +++ b/net/sctp/associola.c | |||
@@ -173,7 +173,7 @@ static struct sctp_association *sctp_association_init(struct sctp_association *a | |||
173 | asoc->timeouts[SCTP_EVENT_TIMEOUT_HEARTBEAT] = 0; | 173 | asoc->timeouts[SCTP_EVENT_TIMEOUT_HEARTBEAT] = 0; |
174 | asoc->timeouts[SCTP_EVENT_TIMEOUT_SACK] = asoc->sackdelay; | 174 | asoc->timeouts[SCTP_EVENT_TIMEOUT_SACK] = asoc->sackdelay; |
175 | asoc->timeouts[SCTP_EVENT_TIMEOUT_AUTOCLOSE] = | 175 | asoc->timeouts[SCTP_EVENT_TIMEOUT_AUTOCLOSE] = |
176 | (unsigned long)sp->autoclose * HZ; | 176 | min_t(unsigned long, sp->autoclose, sctp_max_autoclose) * HZ; |
177 | 177 | ||
178 | /* Initializes the timers */ | 178 | /* Initializes the timers */ |
179 | for (i = SCTP_EVENT_TIMEOUT_NONE; i < SCTP_NUM_TIMEOUT_TYPES; ++i) | 179 | for (i = SCTP_EVENT_TIMEOUT_NONE; i < SCTP_NUM_TIMEOUT_TYPES; ++i) |
@@ -280,6 +280,8 @@ static struct sctp_association *sctp_association_init(struct sctp_association *a | |||
280 | asoc->peer.asconf_capable = 0; | 280 | asoc->peer.asconf_capable = 0; |
281 | if (sctp_addip_noauth) | 281 | if (sctp_addip_noauth) |
282 | asoc->peer.asconf_capable = 1; | 282 | asoc->peer.asconf_capable = 1; |
283 | asoc->asconf_addr_del_pending = NULL; | ||
284 | asoc->src_out_of_asoc_ok = 0; | ||
283 | 285 | ||
284 | /* Create an input queue. */ | 286 | /* Create an input queue. */ |
285 | sctp_inq_init(&asoc->base.inqueue); | 287 | sctp_inq_init(&asoc->base.inqueue); |
@@ -446,6 +448,10 @@ void sctp_association_free(struct sctp_association *asoc) | |||
446 | 448 | ||
447 | sctp_asconf_queue_teardown(asoc); | 449 | sctp_asconf_queue_teardown(asoc); |
448 | 450 | ||
451 | /* Free pending address space being deleted */ | ||
452 | if (asoc->asconf_addr_del_pending != NULL) | ||
453 | kfree(asoc->asconf_addr_del_pending); | ||
454 | |||
449 | /* AUTH - Free the endpoint shared keys */ | 455 | /* AUTH - Free the endpoint shared keys */ |
450 | sctp_auth_destroy_keys(&asoc->endpoint_shared_keys); | 456 | sctp_auth_destroy_keys(&asoc->endpoint_shared_keys); |
451 | 457 | ||
diff --git a/net/sctp/bind_addr.c b/net/sctp/bind_addr.c index 83e3011c19c..4ece451c8d2 100644 --- a/net/sctp/bind_addr.c +++ b/net/sctp/bind_addr.c | |||
@@ -430,7 +430,7 @@ union sctp_addr *sctp_find_unmatch_addr(struct sctp_bind_addr *bp, | |||
430 | list_for_each_entry(laddr, &bp->address_list, list) { | 430 | list_for_each_entry(laddr, &bp->address_list, list) { |
431 | addr_buf = (union sctp_addr *)addrs; | 431 | addr_buf = (union sctp_addr *)addrs; |
432 | for (i = 0; i < addrcnt; i++) { | 432 | for (i = 0; i < addrcnt; i++) { |
433 | addr = (union sctp_addr *)addr_buf; | 433 | addr = addr_buf; |
434 | af = sctp_get_af_specific(addr->v4.sin_family); | 434 | af = sctp_get_af_specific(addr->v4.sin_family); |
435 | if (!af) | 435 | if (!af) |
436 | break; | 436 | break; |
@@ -534,6 +534,21 @@ int sctp_in_scope(const union sctp_addr *addr, sctp_scope_t scope) | |||
534 | return 0; | 534 | return 0; |
535 | } | 535 | } |
536 | 536 | ||
537 | int sctp_is_ep_boundall(struct sock *sk) | ||
538 | { | ||
539 | struct sctp_bind_addr *bp; | ||
540 | struct sctp_sockaddr_entry *addr; | ||
541 | |||
542 | bp = &sctp_sk(sk)->ep->base.bind_addr; | ||
543 | if (sctp_list_single_entry(&bp->address_list)) { | ||
544 | addr = list_entry(bp->address_list.next, | ||
545 | struct sctp_sockaddr_entry, list); | ||
546 | if (sctp_is_any(sk, &addr->a)) | ||
547 | return 1; | ||
548 | } | ||
549 | return 0; | ||
550 | } | ||
551 | |||
537 | /******************************************************************** | 552 | /******************************************************************** |
538 | * 3rd Level Abstractions | 553 | * 3rd Level Abstractions |
539 | ********************************************************************/ | 554 | ********************************************************************/ |
diff --git a/net/sctp/input.c b/net/sctp/input.c index 741ed164883..b7692aab6e9 100644 --- a/net/sctp/input.c +++ b/net/sctp/input.c | |||
@@ -510,8 +510,7 @@ struct sock *sctp_err_lookup(int family, struct sk_buff *skb, | |||
510 | * discard the packet. | 510 | * discard the packet. |
511 | */ | 511 | */ |
512 | if (vtag == 0) { | 512 | if (vtag == 0) { |
513 | chunkhdr = (struct sctp_init_chunk *)((void *)sctphdr | 513 | chunkhdr = (void *)sctphdr + sizeof(struct sctphdr); |
514 | + sizeof(struct sctphdr)); | ||
515 | if (len < sizeof(struct sctphdr) + sizeof(sctp_chunkhdr_t) | 514 | if (len < sizeof(struct sctphdr) + sizeof(sctp_chunkhdr_t) |
516 | + sizeof(__be32) || | 515 | + sizeof(__be32) || |
517 | chunkhdr->chunk_hdr.type != SCTP_CID_INIT || | 516 | chunkhdr->chunk_hdr.type != SCTP_CID_INIT || |
diff --git a/net/sctp/ipv6.c b/net/sctp/ipv6.c index 0bb0d7cb9f1..aabaee41dd3 100644 --- a/net/sctp/ipv6.c +++ b/net/sctp/ipv6.c | |||
@@ -112,6 +112,7 @@ static int sctp_inet6addr_event(struct notifier_block *this, unsigned long ev, | |||
112 | addr->valid = 1; | 112 | addr->valid = 1; |
113 | spin_lock_bh(&sctp_local_addr_lock); | 113 | spin_lock_bh(&sctp_local_addr_lock); |
114 | list_add_tail_rcu(&addr->list, &sctp_local_addr_list); | 114 | list_add_tail_rcu(&addr->list, &sctp_local_addr_list); |
115 | sctp_addr_wq_mgmt(addr, SCTP_ADDR_NEW); | ||
115 | spin_unlock_bh(&sctp_local_addr_lock); | 116 | spin_unlock_bh(&sctp_local_addr_lock); |
116 | } | 117 | } |
117 | break; | 118 | break; |
@@ -122,6 +123,7 @@ static int sctp_inet6addr_event(struct notifier_block *this, unsigned long ev, | |||
122 | if (addr->a.sa.sa_family == AF_INET6 && | 123 | if (addr->a.sa.sa_family == AF_INET6 && |
123 | ipv6_addr_equal(&addr->a.v6.sin6_addr, | 124 | ipv6_addr_equal(&addr->a.v6.sin6_addr, |
124 | &ifa->addr)) { | 125 | &ifa->addr)) { |
126 | sctp_addr_wq_mgmt(addr, SCTP_ADDR_DEL); | ||
125 | found = 1; | 127 | found = 1; |
126 | addr->valid = 0; | 128 | addr->valid = 0; |
127 | list_del_rcu(&addr->list); | 129 | list_del_rcu(&addr->list); |
diff --git a/net/sctp/output.c b/net/sctp/output.c index 08b3cead650..817174eb5f4 100644 --- a/net/sctp/output.c +++ b/net/sctp/output.c | |||
@@ -697,13 +697,7 @@ static void sctp_packet_append_data(struct sctp_packet *packet, | |||
697 | /* Keep track of how many bytes are in flight to the receiver. */ | 697 | /* Keep track of how many bytes are in flight to the receiver. */ |
698 | asoc->outqueue.outstanding_bytes += datasize; | 698 | asoc->outqueue.outstanding_bytes += datasize; |
699 | 699 | ||
700 | /* Update our view of the receiver's rwnd. Include sk_buff overhead | 700 | /* Update our view of the receiver's rwnd. */ |
701 | * while updating peer.rwnd so that it reduces the chances of a | ||
702 | * receiver running out of receive buffer space even when receive | ||
703 | * window is still open. This can happen when a sender is sending | ||
704 | * sending small messages. | ||
705 | */ | ||
706 | datasize += sizeof(struct sk_buff); | ||
707 | if (datasize < rwnd) | 701 | if (datasize < rwnd) |
708 | rwnd -= datasize; | 702 | rwnd -= datasize; |
709 | else | 703 | else |
diff --git a/net/sctp/outqueue.c b/net/sctp/outqueue.c index d03682109b7..6edd7deb1ad 100644 --- a/net/sctp/outqueue.c +++ b/net/sctp/outqueue.c | |||
@@ -411,8 +411,7 @@ void sctp_retransmit_mark(struct sctp_outq *q, | |||
411 | chunk->transport->flight_size -= | 411 | chunk->transport->flight_size -= |
412 | sctp_data_size(chunk); | 412 | sctp_data_size(chunk); |
413 | q->outstanding_bytes -= sctp_data_size(chunk); | 413 | q->outstanding_bytes -= sctp_data_size(chunk); |
414 | q->asoc->peer.rwnd += (sctp_data_size(chunk) + | 414 | q->asoc->peer.rwnd += sctp_data_size(chunk); |
415 | sizeof(struct sk_buff)); | ||
416 | } | 415 | } |
417 | continue; | 416 | continue; |
418 | } | 417 | } |
@@ -432,8 +431,7 @@ void sctp_retransmit_mark(struct sctp_outq *q, | |||
432 | * (Section 7.2.4)), add the data size of those | 431 | * (Section 7.2.4)), add the data size of those |
433 | * chunks to the rwnd. | 432 | * chunks to the rwnd. |
434 | */ | 433 | */ |
435 | q->asoc->peer.rwnd += (sctp_data_size(chunk) + | 434 | q->asoc->peer.rwnd += sctp_data_size(chunk); |
436 | sizeof(struct sk_buff)); | ||
437 | q->outstanding_bytes -= sctp_data_size(chunk); | 435 | q->outstanding_bytes -= sctp_data_size(chunk); |
438 | if (chunk->transport) | 436 | if (chunk->transport) |
439 | transport->flight_size -= sctp_data_size(chunk); | 437 | transport->flight_size -= sctp_data_size(chunk); |
@@ -754,6 +752,16 @@ static int sctp_outq_flush(struct sctp_outq *q, int rtx_timeout) | |||
754 | */ | 752 | */ |
755 | 753 | ||
756 | list_for_each_entry_safe(chunk, tmp, &q->control_chunk_list, list) { | 754 | list_for_each_entry_safe(chunk, tmp, &q->control_chunk_list, list) { |
755 | /* RFC 5061, 5.3 | ||
756 | * F1) This means that until such time as the ASCONF | ||
757 | * containing the add is acknowledged, the sender MUST | ||
758 | * NOT use the new IP address as a source for ANY SCTP | ||
759 | * packet except on carrying an ASCONF Chunk. | ||
760 | */ | ||
761 | if (asoc->src_out_of_asoc_ok && | ||
762 | chunk->chunk_hdr->type != SCTP_CID_ASCONF) | ||
763 | continue; | ||
764 | |||
757 | list_del_init(&chunk->list); | 765 | list_del_init(&chunk->list); |
758 | 766 | ||
759 | /* Pick the right transport to use. */ | 767 | /* Pick the right transport to use. */ |
@@ -881,6 +889,9 @@ static int sctp_outq_flush(struct sctp_outq *q, int rtx_timeout) | |||
881 | } | 889 | } |
882 | } | 890 | } |
883 | 891 | ||
892 | if (q->asoc->src_out_of_asoc_ok) | ||
893 | goto sctp_flush_out; | ||
894 | |||
884 | /* Is it OK to send data chunks? */ | 895 | /* Is it OK to send data chunks? */ |
885 | switch (asoc->state) { | 896 | switch (asoc->state) { |
886 | case SCTP_STATE_COOKIE_ECHOED: | 897 | case SCTP_STATE_COOKIE_ECHOED: |
diff --git a/net/sctp/protocol.c b/net/sctp/protocol.c index 207175b2f40..48cb7b98b11 100644 --- a/net/sctp/protocol.c +++ b/net/sctp/protocol.c | |||
@@ -503,7 +503,9 @@ static void sctp_v4_get_dst(struct sctp_transport *t, union sctp_addr *saddr, | |||
503 | sctp_v4_dst_saddr(&dst_saddr, fl4, htons(bp->port)); | 503 | sctp_v4_dst_saddr(&dst_saddr, fl4, htons(bp->port)); |
504 | rcu_read_lock(); | 504 | rcu_read_lock(); |
505 | list_for_each_entry_rcu(laddr, &bp->address_list, list) { | 505 | list_for_each_entry_rcu(laddr, &bp->address_list, list) { |
506 | if (!laddr->valid || (laddr->state != SCTP_ADDR_SRC)) | 506 | if (!laddr->valid || (laddr->state == SCTP_ADDR_DEL) || |
507 | (laddr->state != SCTP_ADDR_SRC && | ||
508 | !asoc->src_out_of_asoc_ok)) | ||
507 | continue; | 509 | continue; |
508 | if (sctp_v4_cmp_addr(&dst_saddr, &laddr->a)) | 510 | if (sctp_v4_cmp_addr(&dst_saddr, &laddr->a)) |
509 | goto out_unlock; | 511 | goto out_unlock; |
@@ -623,6 +625,143 @@ static void sctp_v4_ecn_capable(struct sock *sk) | |||
623 | INET_ECN_xmit(sk); | 625 | INET_ECN_xmit(sk); |
624 | } | 626 | } |
625 | 627 | ||
628 | void sctp_addr_wq_timeout_handler(unsigned long arg) | ||
629 | { | ||
630 | struct sctp_sockaddr_entry *addrw, *temp; | ||
631 | struct sctp_sock *sp; | ||
632 | |||
633 | spin_lock_bh(&sctp_addr_wq_lock); | ||
634 | |||
635 | list_for_each_entry_safe(addrw, temp, &sctp_addr_waitq, list) { | ||
636 | SCTP_DEBUG_PRINTK_IPADDR("sctp_addrwq_timo_handler: the first ent in wq %p is ", | ||
637 | " for cmd %d at entry %p\n", &sctp_addr_waitq, &addrw->a, addrw->state, | ||
638 | addrw); | ||
639 | |||
640 | #if defined(CONFIG_IPV6) || defined (CONFIG_IPV6_MODULE) | ||
641 | /* Now we send an ASCONF for each association */ | ||
642 | /* Note. we currently don't handle link local IPv6 addressees */ | ||
643 | if (addrw->a.sa.sa_family == AF_INET6) { | ||
644 | struct in6_addr *in6; | ||
645 | |||
646 | if (ipv6_addr_type(&addrw->a.v6.sin6_addr) & | ||
647 | IPV6_ADDR_LINKLOCAL) | ||
648 | goto free_next; | ||
649 | |||
650 | in6 = (struct in6_addr *)&addrw->a.v6.sin6_addr; | ||
651 | if (ipv6_chk_addr(&init_net, in6, NULL, 0) == 0 && | ||
652 | addrw->state == SCTP_ADDR_NEW) { | ||
653 | unsigned long timeo_val; | ||
654 | |||
655 | SCTP_DEBUG_PRINTK("sctp_timo_handler: this is on DAD, trying %d sec later\n", | ||
656 | SCTP_ADDRESS_TICK_DELAY); | ||
657 | timeo_val = jiffies; | ||
658 | timeo_val += msecs_to_jiffies(SCTP_ADDRESS_TICK_DELAY); | ||
659 | mod_timer(&sctp_addr_wq_timer, timeo_val); | ||
660 | break; | ||
661 | } | ||
662 | } | ||
663 | #endif | ||
664 | list_for_each_entry(sp, &sctp_auto_asconf_splist, auto_asconf_list) { | ||
665 | struct sock *sk; | ||
666 | |||
667 | sk = sctp_opt2sk(sp); | ||
668 | /* ignore bound-specific endpoints */ | ||
669 | if (!sctp_is_ep_boundall(sk)) | ||
670 | continue; | ||
671 | sctp_bh_lock_sock(sk); | ||
672 | if (sctp_asconf_mgmt(sp, addrw) < 0) | ||
673 | SCTP_DEBUG_PRINTK("sctp_addrwq_timo_handler: sctp_asconf_mgmt failed\n"); | ||
674 | sctp_bh_unlock_sock(sk); | ||
675 | } | ||
676 | free_next: | ||
677 | list_del(&addrw->list); | ||
678 | kfree(addrw); | ||
679 | } | ||
680 | spin_unlock_bh(&sctp_addr_wq_lock); | ||
681 | } | ||
682 | |||
683 | static void sctp_free_addr_wq(void) | ||
684 | { | ||
685 | struct sctp_sockaddr_entry *addrw; | ||
686 | struct sctp_sockaddr_entry *temp; | ||
687 | |||
688 | spin_lock_bh(&sctp_addr_wq_lock); | ||
689 | del_timer(&sctp_addr_wq_timer); | ||
690 | list_for_each_entry_safe(addrw, temp, &sctp_addr_waitq, list) { | ||
691 | list_del(&addrw->list); | ||
692 | kfree(addrw); | ||
693 | } | ||
694 | spin_unlock_bh(&sctp_addr_wq_lock); | ||
695 | } | ||
696 | |||
697 | /* lookup the entry for the same address in the addr_waitq | ||
698 | * sctp_addr_wq MUST be locked | ||
699 | */ | ||
700 | static struct sctp_sockaddr_entry *sctp_addr_wq_lookup(struct sctp_sockaddr_entry *addr) | ||
701 | { | ||
702 | struct sctp_sockaddr_entry *addrw; | ||
703 | |||
704 | list_for_each_entry(addrw, &sctp_addr_waitq, list) { | ||
705 | if (addrw->a.sa.sa_family != addr->a.sa.sa_family) | ||
706 | continue; | ||
707 | if (addrw->a.sa.sa_family == AF_INET) { | ||
708 | if (addrw->a.v4.sin_addr.s_addr == | ||
709 | addr->a.v4.sin_addr.s_addr) | ||
710 | return addrw; | ||
711 | } else if (addrw->a.sa.sa_family == AF_INET6) { | ||
712 | if (ipv6_addr_equal(&addrw->a.v6.sin6_addr, | ||
713 | &addr->a.v6.sin6_addr)) | ||
714 | return addrw; | ||
715 | } | ||
716 | } | ||
717 | return NULL; | ||
718 | } | ||
719 | |||
720 | void sctp_addr_wq_mgmt(struct sctp_sockaddr_entry *addr, int cmd) | ||
721 | { | ||
722 | struct sctp_sockaddr_entry *addrw; | ||
723 | unsigned long timeo_val; | ||
724 | |||
725 | /* first, we check if an opposite message already exist in the queue. | ||
726 | * If we found such message, it is removed. | ||
727 | * This operation is a bit stupid, but the DHCP client attaches the | ||
728 | * new address after a couple of addition and deletion of that address | ||
729 | */ | ||
730 | |||
731 | spin_lock_bh(&sctp_addr_wq_lock); | ||
732 | /* Offsets existing events in addr_wq */ | ||
733 | addrw = sctp_addr_wq_lookup(addr); | ||
734 | if (addrw) { | ||
735 | if (addrw->state != cmd) { | ||
736 | SCTP_DEBUG_PRINTK_IPADDR("sctp_addr_wq_mgmt offsets existing entry for %d ", | ||
737 | " in wq %p\n", addrw->state, &addrw->a, | ||
738 | &sctp_addr_waitq); | ||
739 | list_del(&addrw->list); | ||
740 | kfree(addrw); | ||
741 | } | ||
742 | spin_unlock_bh(&sctp_addr_wq_lock); | ||
743 | return; | ||
744 | } | ||
745 | |||
746 | /* OK, we have to add the new address to the wait queue */ | ||
747 | addrw = kmemdup(addr, sizeof(struct sctp_sockaddr_entry), GFP_ATOMIC); | ||
748 | if (addrw == NULL) { | ||
749 | spin_unlock_bh(&sctp_addr_wq_lock); | ||
750 | return; | ||
751 | } | ||
752 | addrw->state = cmd; | ||
753 | list_add_tail(&addrw->list, &sctp_addr_waitq); | ||
754 | SCTP_DEBUG_PRINTK_IPADDR("sctp_addr_wq_mgmt add new entry for cmd:%d ", | ||
755 | " in wq %p\n", addrw->state, &addrw->a, &sctp_addr_waitq); | ||
756 | |||
757 | if (!timer_pending(&sctp_addr_wq_timer)) { | ||
758 | timeo_val = jiffies; | ||
759 | timeo_val += msecs_to_jiffies(SCTP_ADDRESS_TICK_DELAY); | ||
760 | mod_timer(&sctp_addr_wq_timer, timeo_val); | ||
761 | } | ||
762 | spin_unlock_bh(&sctp_addr_wq_lock); | ||
763 | } | ||
764 | |||
626 | /* Event handler for inet address addition/deletion events. | 765 | /* Event handler for inet address addition/deletion events. |
627 | * The sctp_local_addr_list needs to be protocted by a spin lock since | 766 | * The sctp_local_addr_list needs to be protocted by a spin lock since |
628 | * multiple notifiers (say IPv4 and IPv6) may be running at the same | 767 | * multiple notifiers (say IPv4 and IPv6) may be running at the same |
@@ -650,6 +789,7 @@ static int sctp_inetaddr_event(struct notifier_block *this, unsigned long ev, | |||
650 | addr->valid = 1; | 789 | addr->valid = 1; |
651 | spin_lock_bh(&sctp_local_addr_lock); | 790 | spin_lock_bh(&sctp_local_addr_lock); |
652 | list_add_tail_rcu(&addr->list, &sctp_local_addr_list); | 791 | list_add_tail_rcu(&addr->list, &sctp_local_addr_list); |
792 | sctp_addr_wq_mgmt(addr, SCTP_ADDR_NEW); | ||
653 | spin_unlock_bh(&sctp_local_addr_lock); | 793 | spin_unlock_bh(&sctp_local_addr_lock); |
654 | } | 794 | } |
655 | break; | 795 | break; |
@@ -660,6 +800,7 @@ static int sctp_inetaddr_event(struct notifier_block *this, unsigned long ev, | |||
660 | if (addr->a.sa.sa_family == AF_INET && | 800 | if (addr->a.sa.sa_family == AF_INET && |
661 | addr->a.v4.sin_addr.s_addr == | 801 | addr->a.v4.sin_addr.s_addr == |
662 | ifa->ifa_local) { | 802 | ifa->ifa_local) { |
803 | sctp_addr_wq_mgmt(addr, SCTP_ADDR_DEL); | ||
663 | found = 1; | 804 | found = 1; |
664 | addr->valid = 0; | 805 | addr->valid = 0; |
665 | list_del_rcu(&addr->list); | 806 | list_del_rcu(&addr->list); |
@@ -1144,6 +1285,9 @@ SCTP_STATIC __init int sctp_init(void) | |||
1144 | sctp_max_instreams = SCTP_DEFAULT_INSTREAMS; | 1285 | sctp_max_instreams = SCTP_DEFAULT_INSTREAMS; |
1145 | sctp_max_outstreams = SCTP_DEFAULT_OUTSTREAMS; | 1286 | sctp_max_outstreams = SCTP_DEFAULT_OUTSTREAMS; |
1146 | 1287 | ||
1288 | /* Initialize maximum autoclose timeout. */ | ||
1289 | sctp_max_autoclose = INT_MAX / HZ; | ||
1290 | |||
1147 | /* Initialize handle used for association ids. */ | 1291 | /* Initialize handle used for association ids. */ |
1148 | idr_init(&sctp_assocs_id); | 1292 | idr_init(&sctp_assocs_id); |
1149 | 1293 | ||
@@ -1233,6 +1377,7 @@ SCTP_STATIC __init int sctp_init(void) | |||
1233 | /* Disable ADDIP by default. */ | 1377 | /* Disable ADDIP by default. */ |
1234 | sctp_addip_enable = 0; | 1378 | sctp_addip_enable = 0; |
1235 | sctp_addip_noauth = 0; | 1379 | sctp_addip_noauth = 0; |
1380 | sctp_default_auto_asconf = 0; | ||
1236 | 1381 | ||
1237 | /* Enable PR-SCTP by default. */ | 1382 | /* Enable PR-SCTP by default. */ |
1238 | sctp_prsctp_enable = 1; | 1383 | sctp_prsctp_enable = 1; |
@@ -1257,6 +1402,13 @@ SCTP_STATIC __init int sctp_init(void) | |||
1257 | spin_lock_init(&sctp_local_addr_lock); | 1402 | spin_lock_init(&sctp_local_addr_lock); |
1258 | sctp_get_local_addr_list(); | 1403 | sctp_get_local_addr_list(); |
1259 | 1404 | ||
1405 | /* Initialize the address event list */ | ||
1406 | INIT_LIST_HEAD(&sctp_addr_waitq); | ||
1407 | INIT_LIST_HEAD(&sctp_auto_asconf_splist); | ||
1408 | spin_lock_init(&sctp_addr_wq_lock); | ||
1409 | sctp_addr_wq_timer.expires = 0; | ||
1410 | setup_timer(&sctp_addr_wq_timer, sctp_addr_wq_timeout_handler, 0); | ||
1411 | |||
1260 | status = sctp_v4_protosw_init(); | 1412 | status = sctp_v4_protosw_init(); |
1261 | 1413 | ||
1262 | if (status) | 1414 | if (status) |
@@ -1328,6 +1480,7 @@ SCTP_STATIC __exit void sctp_exit(void) | |||
1328 | /* Unregister with inet6/inet layers. */ | 1480 | /* Unregister with inet6/inet layers. */ |
1329 | sctp_v6_del_protocol(); | 1481 | sctp_v6_del_protocol(); |
1330 | sctp_v4_del_protocol(); | 1482 | sctp_v4_del_protocol(); |
1483 | sctp_free_addr_wq(); | ||
1331 | 1484 | ||
1332 | /* Free the control endpoint. */ | 1485 | /* Free the control endpoint. */ |
1333 | inet_ctl_sock_destroy(sctp_ctl_sock); | 1486 | inet_ctl_sock_destroy(sctp_ctl_sock); |
diff --git a/net/sctp/sm_make_chunk.c b/net/sctp/sm_make_chunk.c index 58eb27fed4b..81db4e38535 100644 --- a/net/sctp/sm_make_chunk.c +++ b/net/sctp/sm_make_chunk.c | |||
@@ -2768,11 +2768,12 @@ struct sctp_chunk *sctp_make_asconf_update_ip(struct sctp_association *asoc, | |||
2768 | int addr_param_len = 0; | 2768 | int addr_param_len = 0; |
2769 | int totallen = 0; | 2769 | int totallen = 0; |
2770 | int i; | 2770 | int i; |
2771 | int del_pickup = 0; | ||
2771 | 2772 | ||
2772 | /* Get total length of all the address parameters. */ | 2773 | /* Get total length of all the address parameters. */ |
2773 | addr_buf = addrs; | 2774 | addr_buf = addrs; |
2774 | for (i = 0; i < addrcnt; i++) { | 2775 | for (i = 0; i < addrcnt; i++) { |
2775 | addr = (union sctp_addr *)addr_buf; | 2776 | addr = addr_buf; |
2776 | af = sctp_get_af_specific(addr->v4.sin_family); | 2777 | af = sctp_get_af_specific(addr->v4.sin_family); |
2777 | addr_param_len = af->to_addr_param(addr, &addr_param); | 2778 | addr_param_len = af->to_addr_param(addr, &addr_param); |
2778 | 2779 | ||
@@ -2780,6 +2781,13 @@ struct sctp_chunk *sctp_make_asconf_update_ip(struct sctp_association *asoc, | |||
2780 | totallen += addr_param_len; | 2781 | totallen += addr_param_len; |
2781 | 2782 | ||
2782 | addr_buf += af->sockaddr_len; | 2783 | addr_buf += af->sockaddr_len; |
2784 | if (asoc->asconf_addr_del_pending && !del_pickup) { | ||
2785 | /* reuse the parameter length from the same scope one */ | ||
2786 | totallen += paramlen; | ||
2787 | totallen += addr_param_len; | ||
2788 | del_pickup = 1; | ||
2789 | SCTP_DEBUG_PRINTK("mkasconf_update_ip: picked same-scope del_pending addr, totallen for all addresses is %d\n", totallen); | ||
2790 | } | ||
2783 | } | 2791 | } |
2784 | 2792 | ||
2785 | /* Create an asconf chunk with the required length. */ | 2793 | /* Create an asconf chunk with the required length. */ |
@@ -2790,7 +2798,7 @@ struct sctp_chunk *sctp_make_asconf_update_ip(struct sctp_association *asoc, | |||
2790 | /* Add the address parameters to the asconf chunk. */ | 2798 | /* Add the address parameters to the asconf chunk. */ |
2791 | addr_buf = addrs; | 2799 | addr_buf = addrs; |
2792 | for (i = 0; i < addrcnt; i++) { | 2800 | for (i = 0; i < addrcnt; i++) { |
2793 | addr = (union sctp_addr *)addr_buf; | 2801 | addr = addr_buf; |
2794 | af = sctp_get_af_specific(addr->v4.sin_family); | 2802 | af = sctp_get_af_specific(addr->v4.sin_family); |
2795 | addr_param_len = af->to_addr_param(addr, &addr_param); | 2803 | addr_param_len = af->to_addr_param(addr, &addr_param); |
2796 | param.param_hdr.type = flags; | 2804 | param.param_hdr.type = flags; |
@@ -2802,6 +2810,17 @@ struct sctp_chunk *sctp_make_asconf_update_ip(struct sctp_association *asoc, | |||
2802 | 2810 | ||
2803 | addr_buf += af->sockaddr_len; | 2811 | addr_buf += af->sockaddr_len; |
2804 | } | 2812 | } |
2813 | if (flags == SCTP_PARAM_ADD_IP && del_pickup) { | ||
2814 | addr = asoc->asconf_addr_del_pending; | ||
2815 | af = sctp_get_af_specific(addr->v4.sin_family); | ||
2816 | addr_param_len = af->to_addr_param(addr, &addr_param); | ||
2817 | param.param_hdr.type = SCTP_PARAM_DEL_IP; | ||
2818 | param.param_hdr.length = htons(paramlen + addr_param_len); | ||
2819 | param.crr_id = i; | ||
2820 | |||
2821 | sctp_addto_chunk(retval, paramlen, ¶m); | ||
2822 | sctp_addto_chunk(retval, addr_param_len, &addr_param); | ||
2823 | } | ||
2805 | return retval; | 2824 | return retval; |
2806 | } | 2825 | } |
2807 | 2826 | ||
@@ -2939,8 +2958,7 @@ static __be16 sctp_process_asconf_param(struct sctp_association *asoc, | |||
2939 | union sctp_addr addr; | 2958 | union sctp_addr addr; |
2940 | union sctp_addr_param *addr_param; | 2959 | union sctp_addr_param *addr_param; |
2941 | 2960 | ||
2942 | addr_param = (union sctp_addr_param *) | 2961 | addr_param = (void *)asconf_param + sizeof(sctp_addip_param_t); |
2943 | ((void *)asconf_param + sizeof(sctp_addip_param_t)); | ||
2944 | 2962 | ||
2945 | if (asconf_param->param_hdr.type != SCTP_PARAM_ADD_IP && | 2963 | if (asconf_param->param_hdr.type != SCTP_PARAM_ADD_IP && |
2946 | asconf_param->param_hdr.type != SCTP_PARAM_DEL_IP && | 2964 | asconf_param->param_hdr.type != SCTP_PARAM_DEL_IP && |
@@ -3014,7 +3032,7 @@ static __be16 sctp_process_asconf_param(struct sctp_association *asoc, | |||
3014 | * an Error Cause TLV set to the new error code 'Request to | 3032 | * an Error Cause TLV set to the new error code 'Request to |
3015 | * Delete Source IP Address' | 3033 | * Delete Source IP Address' |
3016 | */ | 3034 | */ |
3017 | if (sctp_cmp_addr_exact(sctp_source(asconf), &addr)) | 3035 | if (sctp_cmp_addr_exact(&asconf->source, &addr)) |
3018 | return SCTP_ERROR_DEL_SRC_IP; | 3036 | return SCTP_ERROR_DEL_SRC_IP; |
3019 | 3037 | ||
3020 | /* Section 4.2.2 | 3038 | /* Section 4.2.2 |
@@ -3125,7 +3143,7 @@ struct sctp_chunk *sctp_process_asconf(struct sctp_association *asoc, | |||
3125 | * asconf parameter. | 3143 | * asconf parameter. |
3126 | */ | 3144 | */ |
3127 | length = ntohs(addr_param->p.length); | 3145 | length = ntohs(addr_param->p.length); |
3128 | asconf_param = (sctp_addip_param_t *)((void *)addr_param + length); | 3146 | asconf_param = (void *)addr_param + length; |
3129 | chunk_len -= length; | 3147 | chunk_len -= length; |
3130 | 3148 | ||
3131 | /* create an ASCONF_ACK chunk. | 3149 | /* create an ASCONF_ACK chunk. |
@@ -3166,8 +3184,7 @@ struct sctp_chunk *sctp_process_asconf(struct sctp_association *asoc, | |||
3166 | 3184 | ||
3167 | /* Move to the next ASCONF param. */ | 3185 | /* Move to the next ASCONF param. */ |
3168 | length = ntohs(asconf_param->param_hdr.length); | 3186 | length = ntohs(asconf_param->param_hdr.length); |
3169 | asconf_param = (sctp_addip_param_t *)((void *)asconf_param + | 3187 | asconf_param = (void *)asconf_param + length; |
3170 | length); | ||
3171 | chunk_len -= length; | 3188 | chunk_len -= length; |
3172 | } | 3189 | } |
3173 | 3190 | ||
@@ -3197,8 +3214,7 @@ static void sctp_asconf_param_success(struct sctp_association *asoc, | |||
3197 | struct sctp_transport *transport; | 3214 | struct sctp_transport *transport; |
3198 | struct sctp_sockaddr_entry *saddr; | 3215 | struct sctp_sockaddr_entry *saddr; |
3199 | 3216 | ||
3200 | addr_param = (union sctp_addr_param *) | 3217 | addr_param = (void *)asconf_param + sizeof(sctp_addip_param_t); |
3201 | ((void *)asconf_param + sizeof(sctp_addip_param_t)); | ||
3202 | 3218 | ||
3203 | /* We have checked the packet before, so we do not check again. */ | 3219 | /* We have checked the packet before, so we do not check again. */ |
3204 | af = sctp_get_af_specific(param_type2af(addr_param->p.type)); | 3220 | af = sctp_get_af_specific(param_type2af(addr_param->p.type)); |
@@ -3224,6 +3240,11 @@ static void sctp_asconf_param_success(struct sctp_association *asoc, | |||
3224 | case SCTP_PARAM_DEL_IP: | 3240 | case SCTP_PARAM_DEL_IP: |
3225 | local_bh_disable(); | 3241 | local_bh_disable(); |
3226 | sctp_del_bind_addr(bp, &addr); | 3242 | sctp_del_bind_addr(bp, &addr); |
3243 | if (asoc->asconf_addr_del_pending != NULL && | ||
3244 | sctp_cmp_addr_exact(asoc->asconf_addr_del_pending, &addr)) { | ||
3245 | kfree(asoc->asconf_addr_del_pending); | ||
3246 | asoc->asconf_addr_del_pending = NULL; | ||
3247 | } | ||
3227 | local_bh_enable(); | 3248 | local_bh_enable(); |
3228 | list_for_each_entry(transport, &asoc->peer.transport_addr_list, | 3249 | list_for_each_entry(transport, &asoc->peer.transport_addr_list, |
3229 | transports) { | 3250 | transports) { |
@@ -3278,8 +3299,7 @@ static __be16 sctp_get_asconf_response(struct sctp_chunk *asconf_ack, | |||
3278 | return SCTP_ERROR_NO_ERROR; | 3299 | return SCTP_ERROR_NO_ERROR; |
3279 | case SCTP_PARAM_ERR_CAUSE: | 3300 | case SCTP_PARAM_ERR_CAUSE: |
3280 | length = sizeof(sctp_addip_param_t); | 3301 | length = sizeof(sctp_addip_param_t); |
3281 | err_param = (sctp_errhdr_t *) | 3302 | err_param = (void *)asconf_ack_param + length; |
3282 | ((void *)asconf_ack_param + length); | ||
3283 | asconf_ack_len -= length; | 3303 | asconf_ack_len -= length; |
3284 | if (asconf_ack_len > 0) | 3304 | if (asconf_ack_len > 0) |
3285 | return err_param->cause; | 3305 | return err_param->cause; |
@@ -3292,8 +3312,7 @@ static __be16 sctp_get_asconf_response(struct sctp_chunk *asconf_ack, | |||
3292 | } | 3312 | } |
3293 | 3313 | ||
3294 | length = ntohs(asconf_ack_param->param_hdr.length); | 3314 | length = ntohs(asconf_ack_param->param_hdr.length); |
3295 | asconf_ack_param = (sctp_addip_param_t *) | 3315 | asconf_ack_param = (void *)asconf_ack_param + length; |
3296 | ((void *)asconf_ack_param + length); | ||
3297 | asconf_ack_len -= length; | 3316 | asconf_ack_len -= length; |
3298 | } | 3317 | } |
3299 | 3318 | ||
@@ -3325,7 +3344,7 @@ int sctp_process_asconf_ack(struct sctp_association *asoc, | |||
3325 | * pointer to the first asconf parameter. | 3344 | * pointer to the first asconf parameter. |
3326 | */ | 3345 | */ |
3327 | length = ntohs(addr_param->p.length); | 3346 | length = ntohs(addr_param->p.length); |
3328 | asconf_param = (sctp_addip_param_t *)((void *)addr_param + length); | 3347 | asconf_param = (void *)addr_param + length; |
3329 | asconf_len -= length; | 3348 | asconf_len -= length; |
3330 | 3349 | ||
3331 | /* ADDIP 4.1 | 3350 | /* ADDIP 4.1 |
@@ -3376,11 +3395,13 @@ int sctp_process_asconf_ack(struct sctp_association *asoc, | |||
3376 | * one. | 3395 | * one. |
3377 | */ | 3396 | */ |
3378 | length = ntohs(asconf_param->param_hdr.length); | 3397 | length = ntohs(asconf_param->param_hdr.length); |
3379 | asconf_param = (sctp_addip_param_t *)((void *)asconf_param + | 3398 | asconf_param = (void *)asconf_param + length; |
3380 | length); | ||
3381 | asconf_len -= length; | 3399 | asconf_len -= length; |
3382 | } | 3400 | } |
3383 | 3401 | ||
3402 | if (no_err && asoc->src_out_of_asoc_ok) | ||
3403 | asoc->src_out_of_asoc_ok = 0; | ||
3404 | |||
3384 | /* Free the cached last sent asconf chunk. */ | 3405 | /* Free the cached last sent asconf chunk. */ |
3385 | list_del_init(&asconf->transmitted_list); | 3406 | list_del_init(&asconf->transmitted_list); |
3386 | sctp_chunk_free(asconf); | 3407 | sctp_chunk_free(asconf); |
diff --git a/net/sctp/sm_sideeffect.c b/net/sctp/sm_sideeffect.c index 6e0f88295aa..76388b083f2 100644 --- a/net/sctp/sm_sideeffect.c +++ b/net/sctp/sm_sideeffect.c | |||
@@ -1210,7 +1210,7 @@ static int sctp_cmd_interpreter(sctp_event_t event_type, | |||
1210 | int local_cork = 0; | 1210 | int local_cork = 0; |
1211 | 1211 | ||
1212 | if (SCTP_EVENT_T_TIMEOUT != event_type) | 1212 | if (SCTP_EVENT_T_TIMEOUT != event_type) |
1213 | chunk = (struct sctp_chunk *) event_arg; | 1213 | chunk = event_arg; |
1214 | 1214 | ||
1215 | /* Note: This whole file is a huge candidate for rework. | 1215 | /* Note: This whole file is a huge candidate for rework. |
1216 | * For example, each command could either have its own handler, so | 1216 | * For example, each command could either have its own handler, so |
@@ -1689,6 +1689,11 @@ static int sctp_cmd_interpreter(sctp_event_t event_type, | |||
1689 | case SCTP_CMD_PURGE_ASCONF_QUEUE: | 1689 | case SCTP_CMD_PURGE_ASCONF_QUEUE: |
1690 | sctp_asconf_queue_teardown(asoc); | 1690 | sctp_asconf_queue_teardown(asoc); |
1691 | break; | 1691 | break; |
1692 | |||
1693 | case SCTP_CMD_SET_ASOC: | ||
1694 | asoc = cmd->obj.asoc; | ||
1695 | break; | ||
1696 | |||
1692 | default: | 1697 | default: |
1693 | pr_warn("Impossible command: %u, %p\n", | 1698 | pr_warn("Impossible command: %u, %p\n", |
1694 | cmd->verb, cmd->obj.ptr); | 1699 | cmd->verb, cmd->obj.ptr); |
diff --git a/net/sctp/sm_statefuns.c b/net/sctp/sm_statefuns.c index 246117142b5..a0f31e6c1c6 100644 --- a/net/sctp/sm_statefuns.c +++ b/net/sctp/sm_statefuns.c | |||
@@ -2047,6 +2047,12 @@ sctp_disposition_t sctp_sf_do_5_2_4_dupcook(const struct sctp_endpoint *ep, | |||
2047 | sctp_add_cmd_sf(commands, SCTP_CMD_NEW_ASOC, SCTP_ASOC(new_asoc)); | 2047 | sctp_add_cmd_sf(commands, SCTP_CMD_NEW_ASOC, SCTP_ASOC(new_asoc)); |
2048 | sctp_add_cmd_sf(commands, SCTP_CMD_DELETE_TCB, SCTP_NULL()); | 2048 | sctp_add_cmd_sf(commands, SCTP_CMD_DELETE_TCB, SCTP_NULL()); |
2049 | 2049 | ||
2050 | /* Restore association pointer to provide SCTP command interpeter | ||
2051 | * with a valid context in case it needs to manipulate | ||
2052 | * the queues */ | ||
2053 | sctp_add_cmd_sf(commands, SCTP_CMD_SET_ASOC, | ||
2054 | SCTP_ASOC((struct sctp_association *)asoc)); | ||
2055 | |||
2050 | return retval; | 2056 | return retval; |
2051 | 2057 | ||
2052 | nomem: | 2058 | nomem: |
@@ -4008,31 +4014,32 @@ sctp_disposition_t sctp_sf_eat_auth(const struct sctp_endpoint *ep, | |||
4008 | auth_hdr = (struct sctp_authhdr *)chunk->skb->data; | 4014 | auth_hdr = (struct sctp_authhdr *)chunk->skb->data; |
4009 | error = sctp_sf_authenticate(ep, asoc, type, chunk); | 4015 | error = sctp_sf_authenticate(ep, asoc, type, chunk); |
4010 | switch (error) { | 4016 | switch (error) { |
4011 | case SCTP_IERROR_AUTH_BAD_HMAC: | 4017 | case SCTP_IERROR_AUTH_BAD_HMAC: |
4012 | /* Generate the ERROR chunk and discard the rest | 4018 | /* Generate the ERROR chunk and discard the rest |
4013 | * of the packet | 4019 | * of the packet |
4014 | */ | 4020 | */ |
4015 | err_chunk = sctp_make_op_error(asoc, chunk, | 4021 | err_chunk = sctp_make_op_error(asoc, chunk, |
4016 | SCTP_ERROR_UNSUP_HMAC, | 4022 | SCTP_ERROR_UNSUP_HMAC, |
4017 | &auth_hdr->hmac_id, | 4023 | &auth_hdr->hmac_id, |
4018 | sizeof(__u16), 0); | 4024 | sizeof(__u16), 0); |
4019 | if (err_chunk) { | 4025 | if (err_chunk) { |
4020 | sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, | 4026 | sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, |
4021 | SCTP_CHUNK(err_chunk)); | 4027 | SCTP_CHUNK(err_chunk)); |
4022 | } | 4028 | } |
4023 | /* Fall Through */ | 4029 | /* Fall Through */ |
4024 | case SCTP_IERROR_AUTH_BAD_KEYID: | 4030 | case SCTP_IERROR_AUTH_BAD_KEYID: |
4025 | case SCTP_IERROR_BAD_SIG: | 4031 | case SCTP_IERROR_BAD_SIG: |
4026 | return sctp_sf_pdiscard(ep, asoc, type, arg, commands); | 4032 | return sctp_sf_pdiscard(ep, asoc, type, arg, commands); |
4027 | break; | 4033 | |
4028 | case SCTP_IERROR_PROTO_VIOLATION: | 4034 | case SCTP_IERROR_PROTO_VIOLATION: |
4029 | return sctp_sf_violation_chunklen(ep, asoc, type, arg, | 4035 | return sctp_sf_violation_chunklen(ep, asoc, type, arg, |
4030 | commands); | 4036 | commands); |
4031 | break; | 4037 | |
4032 | case SCTP_IERROR_NOMEM: | 4038 | case SCTP_IERROR_NOMEM: |
4033 | return SCTP_DISPOSITION_NOMEM; | 4039 | return SCTP_DISPOSITION_NOMEM; |
4034 | default: | 4040 | |
4035 | break; | 4041 | default: /* Prevent gcc warnings */ |
4042 | break; | ||
4036 | } | 4043 | } |
4037 | 4044 | ||
4038 | if (asoc->active_key_id != ntohs(auth_hdr->shkey_id)) { | 4045 | if (asoc->active_key_id != ntohs(auth_hdr->shkey_id)) { |
diff --git a/net/sctp/socket.c b/net/sctp/socket.c index d3ccf7973c5..4760f4e65b8 100644 --- a/net/sctp/socket.c +++ b/net/sctp/socket.c | |||
@@ -476,7 +476,7 @@ static int sctp_bindx_add(struct sock *sk, struct sockaddr *addrs, int addrcnt) | |||
476 | /* The list may contain either IPv4 or IPv6 address; | 476 | /* The list may contain either IPv4 or IPv6 address; |
477 | * determine the address length for walking thru the list. | 477 | * determine the address length for walking thru the list. |
478 | */ | 478 | */ |
479 | sa_addr = (struct sockaddr *)addr_buf; | 479 | sa_addr = addr_buf; |
480 | af = sctp_get_af_specific(sa_addr->sa_family); | 480 | af = sctp_get_af_specific(sa_addr->sa_family); |
481 | if (!af) { | 481 | if (!af) { |
482 | retval = -EINVAL; | 482 | retval = -EINVAL; |
@@ -555,7 +555,7 @@ static int sctp_send_asconf_add_ip(struct sock *sk, | |||
555 | */ | 555 | */ |
556 | addr_buf = addrs; | 556 | addr_buf = addrs; |
557 | for (i = 0; i < addrcnt; i++) { | 557 | for (i = 0; i < addrcnt; i++) { |
558 | addr = (union sctp_addr *)addr_buf; | 558 | addr = addr_buf; |
559 | af = sctp_get_af_specific(addr->v4.sin_family); | 559 | af = sctp_get_af_specific(addr->v4.sin_family); |
560 | if (!af) { | 560 | if (!af) { |
561 | retval = -EINVAL; | 561 | retval = -EINVAL; |
@@ -583,22 +583,35 @@ static int sctp_send_asconf_add_ip(struct sock *sk, | |||
583 | goto out; | 583 | goto out; |
584 | } | 584 | } |
585 | 585 | ||
586 | retval = sctp_send_asconf(asoc, chunk); | ||
587 | if (retval) | ||
588 | goto out; | ||
589 | |||
590 | /* Add the new addresses to the bind address list with | 586 | /* Add the new addresses to the bind address list with |
591 | * use_as_src set to 0. | 587 | * use_as_src set to 0. |
592 | */ | 588 | */ |
593 | addr_buf = addrs; | 589 | addr_buf = addrs; |
594 | for (i = 0; i < addrcnt; i++) { | 590 | for (i = 0; i < addrcnt; i++) { |
595 | addr = (union sctp_addr *)addr_buf; | 591 | addr = addr_buf; |
596 | af = sctp_get_af_specific(addr->v4.sin_family); | 592 | af = sctp_get_af_specific(addr->v4.sin_family); |
597 | memcpy(&saveaddr, addr, af->sockaddr_len); | 593 | memcpy(&saveaddr, addr, af->sockaddr_len); |
598 | retval = sctp_add_bind_addr(bp, &saveaddr, | 594 | retval = sctp_add_bind_addr(bp, &saveaddr, |
599 | SCTP_ADDR_NEW, GFP_ATOMIC); | 595 | SCTP_ADDR_NEW, GFP_ATOMIC); |
600 | addr_buf += af->sockaddr_len; | 596 | addr_buf += af->sockaddr_len; |
601 | } | 597 | } |
598 | if (asoc->src_out_of_asoc_ok) { | ||
599 | struct sctp_transport *trans; | ||
600 | |||
601 | list_for_each_entry(trans, | ||
602 | &asoc->peer.transport_addr_list, transports) { | ||
603 | /* Clear the source and route cache */ | ||
604 | dst_release(trans->dst); | ||
605 | trans->cwnd = min(4*asoc->pathmtu, max_t(__u32, | ||
606 | 2*asoc->pathmtu, 4380)); | ||
607 | trans->ssthresh = asoc->peer.i.a_rwnd; | ||
608 | trans->rto = asoc->rto_initial; | ||
609 | trans->rtt = trans->srtt = trans->rttvar = 0; | ||
610 | sctp_transport_route(trans, NULL, | ||
611 | sctp_sk(asoc->base.sk)); | ||
612 | } | ||
613 | } | ||
614 | retval = sctp_send_asconf(asoc, chunk); | ||
602 | } | 615 | } |
603 | 616 | ||
604 | out: | 617 | out: |
@@ -646,7 +659,7 @@ static int sctp_bindx_rem(struct sock *sk, struct sockaddr *addrs, int addrcnt) | |||
646 | goto err_bindx_rem; | 659 | goto err_bindx_rem; |
647 | } | 660 | } |
648 | 661 | ||
649 | sa_addr = (union sctp_addr *)addr_buf; | 662 | sa_addr = addr_buf; |
650 | af = sctp_get_af_specific(sa_addr->sa.sa_family); | 663 | af = sctp_get_af_specific(sa_addr->sa.sa_family); |
651 | if (!af) { | 664 | if (!af) { |
652 | retval = -EINVAL; | 665 | retval = -EINVAL; |
@@ -715,7 +728,9 @@ static int sctp_send_asconf_del_ip(struct sock *sk, | |||
715 | struct sctp_sockaddr_entry *saddr; | 728 | struct sctp_sockaddr_entry *saddr; |
716 | int i; | 729 | int i; |
717 | int retval = 0; | 730 | int retval = 0; |
731 | int stored = 0; | ||
718 | 732 | ||
733 | chunk = NULL; | ||
719 | if (!sctp_addip_enable) | 734 | if (!sctp_addip_enable) |
720 | return retval; | 735 | return retval; |
721 | 736 | ||
@@ -743,7 +758,7 @@ static int sctp_send_asconf_del_ip(struct sock *sk, | |||
743 | */ | 758 | */ |
744 | addr_buf = addrs; | 759 | addr_buf = addrs; |
745 | for (i = 0; i < addrcnt; i++) { | 760 | for (i = 0; i < addrcnt; i++) { |
746 | laddr = (union sctp_addr *)addr_buf; | 761 | laddr = addr_buf; |
747 | af = sctp_get_af_specific(laddr->v4.sin_family); | 762 | af = sctp_get_af_specific(laddr->v4.sin_family); |
748 | if (!af) { | 763 | if (!af) { |
749 | retval = -EINVAL; | 764 | retval = -EINVAL; |
@@ -766,8 +781,37 @@ static int sctp_send_asconf_del_ip(struct sock *sk, | |||
766 | bp = &asoc->base.bind_addr; | 781 | bp = &asoc->base.bind_addr; |
767 | laddr = sctp_find_unmatch_addr(bp, (union sctp_addr *)addrs, | 782 | laddr = sctp_find_unmatch_addr(bp, (union sctp_addr *)addrs, |
768 | addrcnt, sp); | 783 | addrcnt, sp); |
769 | if (!laddr) | 784 | if ((laddr == NULL) && (addrcnt == 1)) { |
770 | continue; | 785 | if (asoc->asconf_addr_del_pending) |
786 | continue; | ||
787 | asoc->asconf_addr_del_pending = | ||
788 | kzalloc(sizeof(union sctp_addr), GFP_ATOMIC); | ||
789 | if (asoc->asconf_addr_del_pending == NULL) { | ||
790 | retval = -ENOMEM; | ||
791 | goto out; | ||
792 | } | ||
793 | asoc->asconf_addr_del_pending->sa.sa_family = | ||
794 | addrs->sa_family; | ||
795 | asoc->asconf_addr_del_pending->v4.sin_port = | ||
796 | htons(bp->port); | ||
797 | if (addrs->sa_family == AF_INET) { | ||
798 | struct sockaddr_in *sin; | ||
799 | |||
800 | sin = (struct sockaddr_in *)addrs; | ||
801 | asoc->asconf_addr_del_pending->v4.sin_addr.s_addr = sin->sin_addr.s_addr; | ||
802 | } else if (addrs->sa_family == AF_INET6) { | ||
803 | struct sockaddr_in6 *sin6; | ||
804 | |||
805 | sin6 = (struct sockaddr_in6 *)addrs; | ||
806 | ipv6_addr_copy(&asoc->asconf_addr_del_pending->v6.sin6_addr, &sin6->sin6_addr); | ||
807 | } | ||
808 | SCTP_DEBUG_PRINTK_IPADDR("send_asconf_del_ip: keep the last address asoc: %p ", | ||
809 | " at %p\n", asoc, asoc->asconf_addr_del_pending, | ||
810 | asoc->asconf_addr_del_pending); | ||
811 | asoc->src_out_of_asoc_ok = 1; | ||
812 | stored = 1; | ||
813 | goto skip_mkasconf; | ||
814 | } | ||
771 | 815 | ||
772 | /* We do not need RCU protection throughout this loop | 816 | /* We do not need RCU protection throughout this loop |
773 | * because this is done under a socket lock from the | 817 | * because this is done under a socket lock from the |
@@ -780,12 +824,13 @@ static int sctp_send_asconf_del_ip(struct sock *sk, | |||
780 | goto out; | 824 | goto out; |
781 | } | 825 | } |
782 | 826 | ||
827 | skip_mkasconf: | ||
783 | /* Reset use_as_src flag for the addresses in the bind address | 828 | /* Reset use_as_src flag for the addresses in the bind address |
784 | * list that are to be deleted. | 829 | * list that are to be deleted. |
785 | */ | 830 | */ |
786 | addr_buf = addrs; | 831 | addr_buf = addrs; |
787 | for (i = 0; i < addrcnt; i++) { | 832 | for (i = 0; i < addrcnt; i++) { |
788 | laddr = (union sctp_addr *)addr_buf; | 833 | laddr = addr_buf; |
789 | af = sctp_get_af_specific(laddr->v4.sin_family); | 834 | af = sctp_get_af_specific(laddr->v4.sin_family); |
790 | list_for_each_entry(saddr, &bp->address_list, list) { | 835 | list_for_each_entry(saddr, &bp->address_list, list) { |
791 | if (sctp_cmp_addr_exact(&saddr->a, laddr)) | 836 | if (sctp_cmp_addr_exact(&saddr->a, laddr)) |
@@ -805,12 +850,37 @@ static int sctp_send_asconf_del_ip(struct sock *sk, | |||
805 | sctp_sk(asoc->base.sk)); | 850 | sctp_sk(asoc->base.sk)); |
806 | } | 851 | } |
807 | 852 | ||
853 | if (stored) | ||
854 | /* We don't need to transmit ASCONF */ | ||
855 | continue; | ||
808 | retval = sctp_send_asconf(asoc, chunk); | 856 | retval = sctp_send_asconf(asoc, chunk); |
809 | } | 857 | } |
810 | out: | 858 | out: |
811 | return retval; | 859 | return retval; |
812 | } | 860 | } |
813 | 861 | ||
862 | /* set addr events to assocs in the endpoint. ep and addr_wq must be locked */ | ||
863 | int sctp_asconf_mgmt(struct sctp_sock *sp, struct sctp_sockaddr_entry *addrw) | ||
864 | { | ||
865 | struct sock *sk = sctp_opt2sk(sp); | ||
866 | union sctp_addr *addr; | ||
867 | struct sctp_af *af; | ||
868 | |||
869 | /* It is safe to write port space in caller. */ | ||
870 | addr = &addrw->a; | ||
871 | addr->v4.sin_port = htons(sp->ep->base.bind_addr.port); | ||
872 | af = sctp_get_af_specific(addr->sa.sa_family); | ||
873 | if (!af) | ||
874 | return -EINVAL; | ||
875 | if (sctp_verify_addr(sk, addr, af->sockaddr_len)) | ||
876 | return -EINVAL; | ||
877 | |||
878 | if (addrw->state == SCTP_ADDR_NEW) | ||
879 | return sctp_send_asconf_add_ip(sk, (struct sockaddr *)addr, 1); | ||
880 | else | ||
881 | return sctp_send_asconf_del_ip(sk, (struct sockaddr *)addr, 1); | ||
882 | } | ||
883 | |||
814 | /* Helper for tunneling sctp_bindx() requests through sctp_setsockopt() | 884 | /* Helper for tunneling sctp_bindx() requests through sctp_setsockopt() |
815 | * | 885 | * |
816 | * API 8.1 | 886 | * API 8.1 |
@@ -927,7 +997,7 @@ SCTP_STATIC int sctp_setsockopt_bindx(struct sock* sk, | |||
927 | return -EINVAL; | 997 | return -EINVAL; |
928 | } | 998 | } |
929 | 999 | ||
930 | sa_addr = (struct sockaddr *)addr_buf; | 1000 | sa_addr = addr_buf; |
931 | af = sctp_get_af_specific(sa_addr->sa_family); | 1001 | af = sctp_get_af_specific(sa_addr->sa_family); |
932 | 1002 | ||
933 | /* If the address family is not supported or if this address | 1003 | /* If the address family is not supported or if this address |
@@ -1018,7 +1088,7 @@ static int __sctp_connect(struct sock* sk, | |||
1018 | goto out_free; | 1088 | goto out_free; |
1019 | } | 1089 | } |
1020 | 1090 | ||
1021 | sa_addr = (union sctp_addr *)addr_buf; | 1091 | sa_addr = addr_buf; |
1022 | af = sctp_get_af_specific(sa_addr->sa.sa_family); | 1092 | af = sctp_get_af_specific(sa_addr->sa.sa_family); |
1023 | 1093 | ||
1024 | /* If the address family is not supported or if this address | 1094 | /* If the address family is not supported or if this address |
@@ -2129,8 +2199,6 @@ static int sctp_setsockopt_autoclose(struct sock *sk, char __user *optval, | |||
2129 | return -EINVAL; | 2199 | return -EINVAL; |
2130 | if (copy_from_user(&sp->autoclose, optval, optlen)) | 2200 | if (copy_from_user(&sp->autoclose, optval, optlen)) |
2131 | return -EFAULT; | 2201 | return -EFAULT; |
2132 | /* make sure it won't exceed MAX_SCHEDULE_TIMEOUT */ | ||
2133 | sp->autoclose = min_t(long, sp->autoclose, MAX_SCHEDULE_TIMEOUT / HZ); | ||
2134 | 2202 | ||
2135 | return 0; | 2203 | return 0; |
2136 | } | 2204 | } |
@@ -3213,11 +3281,11 @@ static int sctp_setsockopt_auth_chunk(struct sock *sk, | |||
3213 | return -EFAULT; | 3281 | return -EFAULT; |
3214 | 3282 | ||
3215 | switch (val.sauth_chunk) { | 3283 | switch (val.sauth_chunk) { |
3216 | case SCTP_CID_INIT: | 3284 | case SCTP_CID_INIT: |
3217 | case SCTP_CID_INIT_ACK: | 3285 | case SCTP_CID_INIT_ACK: |
3218 | case SCTP_CID_SHUTDOWN_COMPLETE: | 3286 | case SCTP_CID_SHUTDOWN_COMPLETE: |
3219 | case SCTP_CID_AUTH: | 3287 | case SCTP_CID_AUTH: |
3220 | return -EINVAL; | 3288 | return -EINVAL; |
3221 | } | 3289 | } |
3222 | 3290 | ||
3223 | /* add this chunk id to the endpoint */ | 3291 | /* add this chunk id to the endpoint */ |
@@ -3360,6 +3428,46 @@ static int sctp_setsockopt_del_key(struct sock *sk, | |||
3360 | 3428 | ||
3361 | } | 3429 | } |
3362 | 3430 | ||
3431 | /* | ||
3432 | * 8.1.23 SCTP_AUTO_ASCONF | ||
3433 | * | ||
3434 | * This option will enable or disable the use of the automatic generation of | ||
3435 | * ASCONF chunks to add and delete addresses to an existing association. Note | ||
3436 | * that this option has two caveats namely: a) it only affects sockets that | ||
3437 | * are bound to all addresses available to the SCTP stack, and b) the system | ||
3438 | * administrator may have an overriding control that turns the ASCONF feature | ||
3439 | * off no matter what setting the socket option may have. | ||
3440 | * This option expects an integer boolean flag, where a non-zero value turns on | ||
3441 | * the option, and a zero value turns off the option. | ||
3442 | * Note. In this implementation, socket operation overrides default parameter | ||
3443 | * being set by sysctl as well as FreeBSD implementation | ||
3444 | */ | ||
3445 | static int sctp_setsockopt_auto_asconf(struct sock *sk, char __user *optval, | ||
3446 | unsigned int optlen) | ||
3447 | { | ||
3448 | int val; | ||
3449 | struct sctp_sock *sp = sctp_sk(sk); | ||
3450 | |||
3451 | if (optlen < sizeof(int)) | ||
3452 | return -EINVAL; | ||
3453 | if (get_user(val, (int __user *)optval)) | ||
3454 | return -EFAULT; | ||
3455 | if (!sctp_is_ep_boundall(sk) && val) | ||
3456 | return -EINVAL; | ||
3457 | if ((val && sp->do_auto_asconf) || (!val && !sp->do_auto_asconf)) | ||
3458 | return 0; | ||
3459 | |||
3460 | if (val == 0 && sp->do_auto_asconf) { | ||
3461 | list_del(&sp->auto_asconf_list); | ||
3462 | sp->do_auto_asconf = 0; | ||
3463 | } else if (val && !sp->do_auto_asconf) { | ||
3464 | list_add_tail(&sp->auto_asconf_list, | ||
3465 | &sctp_auto_asconf_splist); | ||
3466 | sp->do_auto_asconf = 1; | ||
3467 | } | ||
3468 | return 0; | ||
3469 | } | ||
3470 | |||
3363 | 3471 | ||
3364 | /* API 6.2 setsockopt(), getsockopt() | 3472 | /* API 6.2 setsockopt(), getsockopt() |
3365 | * | 3473 | * |
@@ -3507,6 +3615,9 @@ SCTP_STATIC int sctp_setsockopt(struct sock *sk, int level, int optname, | |||
3507 | case SCTP_AUTH_DELETE_KEY: | 3615 | case SCTP_AUTH_DELETE_KEY: |
3508 | retval = sctp_setsockopt_del_key(sk, optval, optlen); | 3616 | retval = sctp_setsockopt_del_key(sk, optval, optlen); |
3509 | break; | 3617 | break; |
3618 | case SCTP_AUTO_ASCONF: | ||
3619 | retval = sctp_setsockopt_auto_asconf(sk, optval, optlen); | ||
3620 | break; | ||
3510 | default: | 3621 | default: |
3511 | retval = -ENOPROTOOPT; | 3622 | retval = -ENOPROTOOPT; |
3512 | break; | 3623 | break; |
@@ -3789,6 +3900,12 @@ SCTP_STATIC int sctp_init_sock(struct sock *sk) | |||
3789 | local_bh_disable(); | 3900 | local_bh_disable(); |
3790 | percpu_counter_inc(&sctp_sockets_allocated); | 3901 | percpu_counter_inc(&sctp_sockets_allocated); |
3791 | sock_prot_inuse_add(sock_net(sk), sk->sk_prot, 1); | 3902 | sock_prot_inuse_add(sock_net(sk), sk->sk_prot, 1); |
3903 | if (sctp_default_auto_asconf) { | ||
3904 | list_add_tail(&sp->auto_asconf_list, | ||
3905 | &sctp_auto_asconf_splist); | ||
3906 | sp->do_auto_asconf = 1; | ||
3907 | } else | ||
3908 | sp->do_auto_asconf = 0; | ||
3792 | local_bh_enable(); | 3909 | local_bh_enable(); |
3793 | 3910 | ||
3794 | return 0; | 3911 | return 0; |
@@ -3797,13 +3914,17 @@ SCTP_STATIC int sctp_init_sock(struct sock *sk) | |||
3797 | /* Cleanup any SCTP per socket resources. */ | 3914 | /* Cleanup any SCTP per socket resources. */ |
3798 | SCTP_STATIC void sctp_destroy_sock(struct sock *sk) | 3915 | SCTP_STATIC void sctp_destroy_sock(struct sock *sk) |
3799 | { | 3916 | { |
3800 | struct sctp_endpoint *ep; | 3917 | struct sctp_sock *sp; |
3801 | 3918 | ||
3802 | SCTP_DEBUG_PRINTK("sctp_destroy_sock(sk: %p)\n", sk); | 3919 | SCTP_DEBUG_PRINTK("sctp_destroy_sock(sk: %p)\n", sk); |
3803 | 3920 | ||
3804 | /* Release our hold on the endpoint. */ | 3921 | /* Release our hold on the endpoint. */ |
3805 | ep = sctp_sk(sk)->ep; | 3922 | sp = sctp_sk(sk); |
3806 | sctp_endpoint_free(ep); | 3923 | if (sp->do_auto_asconf) { |
3924 | sp->do_auto_asconf = 0; | ||
3925 | list_del(&sp->auto_asconf_list); | ||
3926 | } | ||
3927 | sctp_endpoint_free(sp->ep); | ||
3807 | local_bh_disable(); | 3928 | local_bh_disable(); |
3808 | percpu_counter_dec(&sctp_sockets_allocated); | 3929 | percpu_counter_dec(&sctp_sockets_allocated); |
3809 | sock_prot_inuse_add(sock_net(sk), sk->sk_prot, -1); | 3930 | sock_prot_inuse_add(sock_net(sk), sk->sk_prot, -1); |
@@ -5303,6 +5424,28 @@ static int sctp_getsockopt_assoc_number(struct sock *sk, int len, | |||
5303 | } | 5424 | } |
5304 | 5425 | ||
5305 | /* | 5426 | /* |
5427 | * 8.1.23 SCTP_AUTO_ASCONF | ||
5428 | * See the corresponding setsockopt entry as description | ||
5429 | */ | ||
5430 | static int sctp_getsockopt_auto_asconf(struct sock *sk, int len, | ||
5431 | char __user *optval, int __user *optlen) | ||
5432 | { | ||
5433 | int val = 0; | ||
5434 | |||
5435 | if (len < sizeof(int)) | ||
5436 | return -EINVAL; | ||
5437 | |||
5438 | len = sizeof(int); | ||
5439 | if (sctp_sk(sk)->do_auto_asconf && sctp_is_ep_boundall(sk)) | ||
5440 | val = 1; | ||
5441 | if (put_user(len, optlen)) | ||
5442 | return -EFAULT; | ||
5443 | if (copy_to_user(optval, &val, len)) | ||
5444 | return -EFAULT; | ||
5445 | return 0; | ||
5446 | } | ||
5447 | |||
5448 | /* | ||
5306 | * 8.2.6. Get the Current Identifiers of Associations | 5449 | * 8.2.6. Get the Current Identifiers of Associations |
5307 | * (SCTP_GET_ASSOC_ID_LIST) | 5450 | * (SCTP_GET_ASSOC_ID_LIST) |
5308 | * | 5451 | * |
@@ -5486,6 +5629,9 @@ SCTP_STATIC int sctp_getsockopt(struct sock *sk, int level, int optname, | |||
5486 | case SCTP_GET_ASSOC_ID_LIST: | 5629 | case SCTP_GET_ASSOC_ID_LIST: |
5487 | retval = sctp_getsockopt_assoc_ids(sk, len, optval, optlen); | 5630 | retval = sctp_getsockopt_assoc_ids(sk, len, optval, optlen); |
5488 | break; | 5631 | break; |
5632 | case SCTP_AUTO_ASCONF: | ||
5633 | retval = sctp_getsockopt_auto_asconf(sk, len, optval, optlen); | ||
5634 | break; | ||
5489 | default: | 5635 | default: |
5490 | retval = -ENOPROTOOPT; | 5636 | retval = -ENOPROTOOPT; |
5491 | break; | 5637 | break; |
@@ -6538,6 +6684,7 @@ static void sctp_sock_migrate(struct sock *oldsk, struct sock *newsk, | |||
6538 | struct sk_buff *skb, *tmp; | 6684 | struct sk_buff *skb, *tmp; |
6539 | struct sctp_ulpevent *event; | 6685 | struct sctp_ulpevent *event; |
6540 | struct sctp_bind_hashbucket *head; | 6686 | struct sctp_bind_hashbucket *head; |
6687 | struct list_head tmplist; | ||
6541 | 6688 | ||
6542 | /* Migrate socket buffer sizes and all the socket level options to the | 6689 | /* Migrate socket buffer sizes and all the socket level options to the |
6543 | * new socket. | 6690 | * new socket. |
@@ -6545,7 +6692,12 @@ static void sctp_sock_migrate(struct sock *oldsk, struct sock *newsk, | |||
6545 | newsk->sk_sndbuf = oldsk->sk_sndbuf; | 6692 | newsk->sk_sndbuf = oldsk->sk_sndbuf; |
6546 | newsk->sk_rcvbuf = oldsk->sk_rcvbuf; | 6693 | newsk->sk_rcvbuf = oldsk->sk_rcvbuf; |
6547 | /* Brute force copy old sctp opt. */ | 6694 | /* Brute force copy old sctp opt. */ |
6548 | inet_sk_copy_descendant(newsk, oldsk); | 6695 | if (oldsp->do_auto_asconf) { |
6696 | memcpy(&tmplist, &newsp->auto_asconf_list, sizeof(tmplist)); | ||
6697 | inet_sk_copy_descendant(newsk, oldsk); | ||
6698 | memcpy(&newsp->auto_asconf_list, &tmplist, sizeof(tmplist)); | ||
6699 | } else | ||
6700 | inet_sk_copy_descendant(newsk, oldsk); | ||
6549 | 6701 | ||
6550 | /* Restore the ep value that was overwritten with the above structure | 6702 | /* Restore the ep value that was overwritten with the above structure |
6551 | * copy. | 6703 | * copy. |
diff --git a/net/sctp/sysctl.c b/net/sctp/sysctl.c index 50cb57f0919..60ffbd067ff 100644 --- a/net/sctp/sysctl.c +++ b/net/sctp/sysctl.c | |||
@@ -53,6 +53,10 @@ static int sack_timer_min = 1; | |||
53 | static int sack_timer_max = 500; | 53 | static int sack_timer_max = 500; |
54 | static int addr_scope_max = 3; /* check sctp_scope_policy_t in include/net/sctp/constants.h for max entries */ | 54 | static int addr_scope_max = 3; /* check sctp_scope_policy_t in include/net/sctp/constants.h for max entries */ |
55 | static int rwnd_scale_max = 16; | 55 | static int rwnd_scale_max = 16; |
56 | static unsigned long max_autoclose_min = 0; | ||
57 | static unsigned long max_autoclose_max = | ||
58 | (MAX_SCHEDULE_TIMEOUT / HZ > UINT_MAX) | ||
59 | ? UINT_MAX : MAX_SCHEDULE_TIMEOUT / HZ; | ||
56 | 60 | ||
57 | extern long sysctl_sctp_mem[3]; | 61 | extern long sysctl_sctp_mem[3]; |
58 | extern int sysctl_sctp_rmem[3]; | 62 | extern int sysctl_sctp_rmem[3]; |
@@ -183,6 +187,13 @@ static ctl_table sctp_table[] = { | |||
183 | .proc_handler = proc_dointvec, | 187 | .proc_handler = proc_dointvec, |
184 | }, | 188 | }, |
185 | { | 189 | { |
190 | .procname = "default_auto_asconf", | ||
191 | .data = &sctp_default_auto_asconf, | ||
192 | .maxlen = sizeof(int), | ||
193 | .mode = 0644, | ||
194 | .proc_handler = proc_dointvec, | ||
195 | }, | ||
196 | { | ||
186 | .procname = "prsctp_enable", | 197 | .procname = "prsctp_enable", |
187 | .data = &sctp_prsctp_enable, | 198 | .data = &sctp_prsctp_enable, |
188 | .maxlen = sizeof(int), | 199 | .maxlen = sizeof(int), |
@@ -251,6 +262,15 @@ static ctl_table sctp_table[] = { | |||
251 | .extra1 = &one, | 262 | .extra1 = &one, |
252 | .extra2 = &rwnd_scale_max, | 263 | .extra2 = &rwnd_scale_max, |
253 | }, | 264 | }, |
265 | { | ||
266 | .procname = "max_autoclose", | ||
267 | .data = &sctp_max_autoclose, | ||
268 | .maxlen = sizeof(unsigned long), | ||
269 | .mode = 0644, | ||
270 | .proc_handler = &proc_doulongvec_minmax, | ||
271 | .extra1 = &max_autoclose_min, | ||
272 | .extra2 = &max_autoclose_max, | ||
273 | }, | ||
254 | 274 | ||
255 | { /* sentinel */ } | 275 | { /* sentinel */ } |
256 | }; | 276 | }; |