diff options
Diffstat (limited to 'net/sctp/socket.c')
-rw-r--r-- | net/sctp/socket.c | 236 |
1 files changed, 208 insertions, 28 deletions
diff --git a/net/sctp/socket.c b/net/sctp/socket.c index 6766913a53e6..836aa63ee121 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 |
@@ -1384,6 +1454,7 @@ SCTP_STATIC void sctp_close(struct sock *sk, long timeout) | |||
1384 | struct sctp_endpoint *ep; | 1454 | struct sctp_endpoint *ep; |
1385 | struct sctp_association *asoc; | 1455 | struct sctp_association *asoc; |
1386 | struct list_head *pos, *temp; | 1456 | struct list_head *pos, *temp; |
1457 | unsigned int data_was_unread; | ||
1387 | 1458 | ||
1388 | SCTP_DEBUG_PRINTK("sctp_close(sk: 0x%p, timeout:%ld)\n", sk, timeout); | 1459 | SCTP_DEBUG_PRINTK("sctp_close(sk: 0x%p, timeout:%ld)\n", sk, timeout); |
1389 | 1460 | ||
@@ -1393,6 +1464,10 @@ SCTP_STATIC void sctp_close(struct sock *sk, long timeout) | |||
1393 | 1464 | ||
1394 | ep = sctp_sk(sk)->ep; | 1465 | ep = sctp_sk(sk)->ep; |
1395 | 1466 | ||
1467 | /* Clean up any skbs sitting on the receive queue. */ | ||
1468 | data_was_unread = sctp_queue_purge_ulpevents(&sk->sk_receive_queue); | ||
1469 | data_was_unread += sctp_queue_purge_ulpevents(&sctp_sk(sk)->pd_lobby); | ||
1470 | |||
1396 | /* Walk all associations on an endpoint. */ | 1471 | /* Walk all associations on an endpoint. */ |
1397 | list_for_each_safe(pos, temp, &ep->asocs) { | 1472 | list_for_each_safe(pos, temp, &ep->asocs) { |
1398 | asoc = list_entry(pos, struct sctp_association, asocs); | 1473 | asoc = list_entry(pos, struct sctp_association, asocs); |
@@ -1410,7 +1485,9 @@ SCTP_STATIC void sctp_close(struct sock *sk, long timeout) | |||
1410 | } | 1485 | } |
1411 | } | 1486 | } |
1412 | 1487 | ||
1413 | if (sock_flag(sk, SOCK_LINGER) && !sk->sk_lingertime) { | 1488 | if (data_was_unread || !skb_queue_empty(&asoc->ulpq.lobby) || |
1489 | !skb_queue_empty(&asoc->ulpq.reasm) || | ||
1490 | (sock_flag(sk, SOCK_LINGER) && !sk->sk_lingertime)) { | ||
1414 | struct sctp_chunk *chunk; | 1491 | struct sctp_chunk *chunk; |
1415 | 1492 | ||
1416 | chunk = sctp_make_abort_user(asoc, NULL, 0); | 1493 | chunk = sctp_make_abort_user(asoc, NULL, 0); |
@@ -1420,10 +1497,6 @@ SCTP_STATIC void sctp_close(struct sock *sk, long timeout) | |||
1420 | sctp_primitive_SHUTDOWN(asoc, NULL); | 1497 | sctp_primitive_SHUTDOWN(asoc, NULL); |
1421 | } | 1498 | } |
1422 | 1499 | ||
1423 | /* Clean up any skbs sitting on the receive queue. */ | ||
1424 | sctp_queue_purge_ulpevents(&sk->sk_receive_queue); | ||
1425 | sctp_queue_purge_ulpevents(&sctp_sk(sk)->pd_lobby); | ||
1426 | |||
1427 | /* On a TCP-style socket, block for at most linger_time if set. */ | 1500 | /* On a TCP-style socket, block for at most linger_time if set. */ |
1428 | if (sctp_style(sk, TCP) && timeout) | 1501 | if (sctp_style(sk, TCP) && timeout) |
1429 | sctp_wait_for_close(sk, timeout); | 1502 | sctp_wait_for_close(sk, timeout); |
@@ -2073,10 +2146,33 @@ static int sctp_setsockopt_disable_fragments(struct sock *sk, | |||
2073 | static int sctp_setsockopt_events(struct sock *sk, char __user *optval, | 2146 | static int sctp_setsockopt_events(struct sock *sk, char __user *optval, |
2074 | unsigned int optlen) | 2147 | unsigned int optlen) |
2075 | { | 2148 | { |
2149 | struct sctp_association *asoc; | ||
2150 | struct sctp_ulpevent *event; | ||
2151 | |||
2076 | if (optlen > sizeof(struct sctp_event_subscribe)) | 2152 | if (optlen > sizeof(struct sctp_event_subscribe)) |
2077 | return -EINVAL; | 2153 | return -EINVAL; |
2078 | if (copy_from_user(&sctp_sk(sk)->subscribe, optval, optlen)) | 2154 | if (copy_from_user(&sctp_sk(sk)->subscribe, optval, optlen)) |
2079 | return -EFAULT; | 2155 | return -EFAULT; |
2156 | |||
2157 | /* | ||
2158 | * At the time when a user app subscribes to SCTP_SENDER_DRY_EVENT, | ||
2159 | * if there is no data to be sent or retransmit, the stack will | ||
2160 | * immediately send up this notification. | ||
2161 | */ | ||
2162 | if (sctp_ulpevent_type_enabled(SCTP_SENDER_DRY_EVENT, | ||
2163 | &sctp_sk(sk)->subscribe)) { | ||
2164 | asoc = sctp_id2assoc(sk, 0); | ||
2165 | |||
2166 | if (asoc && sctp_outq_is_empty(&asoc->outqueue)) { | ||
2167 | event = sctp_ulpevent_make_sender_dry_event(asoc, | ||
2168 | GFP_ATOMIC); | ||
2169 | if (!event) | ||
2170 | return -ENOMEM; | ||
2171 | |||
2172 | sctp_ulpq_tail_event(&asoc->ulpq, event); | ||
2173 | } | ||
2174 | } | ||
2175 | |||
2080 | return 0; | 2176 | return 0; |
2081 | } | 2177 | } |
2082 | 2178 | ||
@@ -3187,11 +3283,11 @@ static int sctp_setsockopt_auth_chunk(struct sock *sk, | |||
3187 | return -EFAULT; | 3283 | return -EFAULT; |
3188 | 3284 | ||
3189 | switch (val.sauth_chunk) { | 3285 | switch (val.sauth_chunk) { |
3190 | case SCTP_CID_INIT: | 3286 | case SCTP_CID_INIT: |
3191 | case SCTP_CID_INIT_ACK: | 3287 | case SCTP_CID_INIT_ACK: |
3192 | case SCTP_CID_SHUTDOWN_COMPLETE: | 3288 | case SCTP_CID_SHUTDOWN_COMPLETE: |
3193 | case SCTP_CID_AUTH: | 3289 | case SCTP_CID_AUTH: |
3194 | return -EINVAL; | 3290 | return -EINVAL; |
3195 | } | 3291 | } |
3196 | 3292 | ||
3197 | /* add this chunk id to the endpoint */ | 3293 | /* add this chunk id to the endpoint */ |
@@ -3334,6 +3430,46 @@ static int sctp_setsockopt_del_key(struct sock *sk, | |||
3334 | 3430 | ||
3335 | } | 3431 | } |
3336 | 3432 | ||
3433 | /* | ||
3434 | * 8.1.23 SCTP_AUTO_ASCONF | ||
3435 | * | ||
3436 | * This option will enable or disable the use of the automatic generation of | ||
3437 | * ASCONF chunks to add and delete addresses to an existing association. Note | ||
3438 | * that this option has two caveats namely: a) it only affects sockets that | ||
3439 | * are bound to all addresses available to the SCTP stack, and b) the system | ||
3440 | * administrator may have an overriding control that turns the ASCONF feature | ||
3441 | * off no matter what setting the socket option may have. | ||
3442 | * This option expects an integer boolean flag, where a non-zero value turns on | ||
3443 | * the option, and a zero value turns off the option. | ||
3444 | * Note. In this implementation, socket operation overrides default parameter | ||
3445 | * being set by sysctl as well as FreeBSD implementation | ||
3446 | */ | ||
3447 | static int sctp_setsockopt_auto_asconf(struct sock *sk, char __user *optval, | ||
3448 | unsigned int optlen) | ||
3449 | { | ||
3450 | int val; | ||
3451 | struct sctp_sock *sp = sctp_sk(sk); | ||
3452 | |||
3453 | if (optlen < sizeof(int)) | ||
3454 | return -EINVAL; | ||
3455 | if (get_user(val, (int __user *)optval)) | ||
3456 | return -EFAULT; | ||
3457 | if (!sctp_is_ep_boundall(sk) && val) | ||
3458 | return -EINVAL; | ||
3459 | if ((val && sp->do_auto_asconf) || (!val && !sp->do_auto_asconf)) | ||
3460 | return 0; | ||
3461 | |||
3462 | if (val == 0 && sp->do_auto_asconf) { | ||
3463 | list_del(&sp->auto_asconf_list); | ||
3464 | sp->do_auto_asconf = 0; | ||
3465 | } else if (val && !sp->do_auto_asconf) { | ||
3466 | list_add_tail(&sp->auto_asconf_list, | ||
3467 | &sctp_auto_asconf_splist); | ||
3468 | sp->do_auto_asconf = 1; | ||
3469 | } | ||
3470 | return 0; | ||
3471 | } | ||
3472 | |||
3337 | 3473 | ||
3338 | /* API 6.2 setsockopt(), getsockopt() | 3474 | /* API 6.2 setsockopt(), getsockopt() |
3339 | * | 3475 | * |
@@ -3481,6 +3617,9 @@ SCTP_STATIC int sctp_setsockopt(struct sock *sk, int level, int optname, | |||
3481 | case SCTP_AUTH_DELETE_KEY: | 3617 | case SCTP_AUTH_DELETE_KEY: |
3482 | retval = sctp_setsockopt_del_key(sk, optval, optlen); | 3618 | retval = sctp_setsockopt_del_key(sk, optval, optlen); |
3483 | break; | 3619 | break; |
3620 | case SCTP_AUTO_ASCONF: | ||
3621 | retval = sctp_setsockopt_auto_asconf(sk, optval, optlen); | ||
3622 | break; | ||
3484 | default: | 3623 | default: |
3485 | retval = -ENOPROTOOPT; | 3624 | retval = -ENOPROTOOPT; |
3486 | break; | 3625 | break; |
@@ -3763,6 +3902,12 @@ SCTP_STATIC int sctp_init_sock(struct sock *sk) | |||
3763 | local_bh_disable(); | 3902 | local_bh_disable(); |
3764 | percpu_counter_inc(&sctp_sockets_allocated); | 3903 | percpu_counter_inc(&sctp_sockets_allocated); |
3765 | sock_prot_inuse_add(sock_net(sk), sk->sk_prot, 1); | 3904 | sock_prot_inuse_add(sock_net(sk), sk->sk_prot, 1); |
3905 | if (sctp_default_auto_asconf) { | ||
3906 | list_add_tail(&sp->auto_asconf_list, | ||
3907 | &sctp_auto_asconf_splist); | ||
3908 | sp->do_auto_asconf = 1; | ||
3909 | } else | ||
3910 | sp->do_auto_asconf = 0; | ||
3766 | local_bh_enable(); | 3911 | local_bh_enable(); |
3767 | 3912 | ||
3768 | return 0; | 3913 | return 0; |
@@ -3771,13 +3916,17 @@ SCTP_STATIC int sctp_init_sock(struct sock *sk) | |||
3771 | /* Cleanup any SCTP per socket resources. */ | 3916 | /* Cleanup any SCTP per socket resources. */ |
3772 | SCTP_STATIC void sctp_destroy_sock(struct sock *sk) | 3917 | SCTP_STATIC void sctp_destroy_sock(struct sock *sk) |
3773 | { | 3918 | { |
3774 | struct sctp_endpoint *ep; | 3919 | struct sctp_sock *sp; |
3775 | 3920 | ||
3776 | SCTP_DEBUG_PRINTK("sctp_destroy_sock(sk: %p)\n", sk); | 3921 | SCTP_DEBUG_PRINTK("sctp_destroy_sock(sk: %p)\n", sk); |
3777 | 3922 | ||
3778 | /* Release our hold on the endpoint. */ | 3923 | /* Release our hold on the endpoint. */ |
3779 | ep = sctp_sk(sk)->ep; | 3924 | sp = sctp_sk(sk); |
3780 | sctp_endpoint_free(ep); | 3925 | if (sp->do_auto_asconf) { |
3926 | sp->do_auto_asconf = 0; | ||
3927 | list_del(&sp->auto_asconf_list); | ||
3928 | } | ||
3929 | sctp_endpoint_free(sp->ep); | ||
3781 | local_bh_disable(); | 3930 | local_bh_disable(); |
3782 | percpu_counter_dec(&sctp_sockets_allocated); | 3931 | percpu_counter_dec(&sctp_sockets_allocated); |
3783 | sock_prot_inuse_add(sock_net(sk), sk->sk_prot, -1); | 3932 | sock_prot_inuse_add(sock_net(sk), sk->sk_prot, -1); |
@@ -5277,6 +5426,28 @@ static int sctp_getsockopt_assoc_number(struct sock *sk, int len, | |||
5277 | } | 5426 | } |
5278 | 5427 | ||
5279 | /* | 5428 | /* |
5429 | * 8.1.23 SCTP_AUTO_ASCONF | ||
5430 | * See the corresponding setsockopt entry as description | ||
5431 | */ | ||
5432 | static int sctp_getsockopt_auto_asconf(struct sock *sk, int len, | ||
5433 | char __user *optval, int __user *optlen) | ||
5434 | { | ||
5435 | int val = 0; | ||
5436 | |||
5437 | if (len < sizeof(int)) | ||
5438 | return -EINVAL; | ||
5439 | |||
5440 | len = sizeof(int); | ||
5441 | if (sctp_sk(sk)->do_auto_asconf && sctp_is_ep_boundall(sk)) | ||
5442 | val = 1; | ||
5443 | if (put_user(len, optlen)) | ||
5444 | return -EFAULT; | ||
5445 | if (copy_to_user(optval, &val, len)) | ||
5446 | return -EFAULT; | ||
5447 | return 0; | ||
5448 | } | ||
5449 | |||
5450 | /* | ||
5280 | * 8.2.6. Get the Current Identifiers of Associations | 5451 | * 8.2.6. Get the Current Identifiers of Associations |
5281 | * (SCTP_GET_ASSOC_ID_LIST) | 5452 | * (SCTP_GET_ASSOC_ID_LIST) |
5282 | * | 5453 | * |
@@ -5460,6 +5631,9 @@ SCTP_STATIC int sctp_getsockopt(struct sock *sk, int level, int optname, | |||
5460 | case SCTP_GET_ASSOC_ID_LIST: | 5631 | case SCTP_GET_ASSOC_ID_LIST: |
5461 | retval = sctp_getsockopt_assoc_ids(sk, len, optval, optlen); | 5632 | retval = sctp_getsockopt_assoc_ids(sk, len, optval, optlen); |
5462 | break; | 5633 | break; |
5634 | case SCTP_AUTO_ASCONF: | ||
5635 | retval = sctp_getsockopt_auto_asconf(sk, len, optval, optlen); | ||
5636 | break; | ||
5463 | default: | 5637 | default: |
5464 | retval = -ENOPROTOOPT; | 5638 | retval = -ENOPROTOOPT; |
5465 | break; | 5639 | break; |
@@ -6512,6 +6686,7 @@ static void sctp_sock_migrate(struct sock *oldsk, struct sock *newsk, | |||
6512 | struct sk_buff *skb, *tmp; | 6686 | struct sk_buff *skb, *tmp; |
6513 | struct sctp_ulpevent *event; | 6687 | struct sctp_ulpevent *event; |
6514 | struct sctp_bind_hashbucket *head; | 6688 | struct sctp_bind_hashbucket *head; |
6689 | struct list_head tmplist; | ||
6515 | 6690 | ||
6516 | /* Migrate socket buffer sizes and all the socket level options to the | 6691 | /* Migrate socket buffer sizes and all the socket level options to the |
6517 | * new socket. | 6692 | * new socket. |
@@ -6519,7 +6694,12 @@ static void sctp_sock_migrate(struct sock *oldsk, struct sock *newsk, | |||
6519 | newsk->sk_sndbuf = oldsk->sk_sndbuf; | 6694 | newsk->sk_sndbuf = oldsk->sk_sndbuf; |
6520 | newsk->sk_rcvbuf = oldsk->sk_rcvbuf; | 6695 | newsk->sk_rcvbuf = oldsk->sk_rcvbuf; |
6521 | /* Brute force copy old sctp opt. */ | 6696 | /* Brute force copy old sctp opt. */ |
6522 | inet_sk_copy_descendant(newsk, oldsk); | 6697 | if (oldsp->do_auto_asconf) { |
6698 | memcpy(&tmplist, &newsp->auto_asconf_list, sizeof(tmplist)); | ||
6699 | inet_sk_copy_descendant(newsk, oldsk); | ||
6700 | memcpy(&newsp->auto_asconf_list, &tmplist, sizeof(tmplist)); | ||
6701 | } else | ||
6702 | inet_sk_copy_descendant(newsk, oldsk); | ||
6523 | 6703 | ||
6524 | /* Restore the ep value that was overwritten with the above structure | 6704 | /* Restore the ep value that was overwritten with the above structure |
6525 | * copy. | 6705 | * copy. |