This patch is to implement: rfc6951#section-6.1: Get or Set the Remote UDP Encapsulation Port Number with the param of the struct: struct sctp_udpencaps { sctp_assoc_t sue_assoc_id; struct sockaddr_storage sue_address; uint16_t sue_port; }; the encap_port of sock, assoc or transport can be changed by users, which also means it allows the different transports of the same asoc to have different encap_port value. v1->v2: - no change. v2->v3: - fix the endian warning when setting values between encap_port and sue_port.
Unified · Split
| @@ -140,6 +140,7 @@ typedef __s32 sctp_assoc_t; · 139 unmodified lines | |||
| 140 | #define SCTP_ECN_SUPPORTED 130 | 140 | #define SCTP_ECN_SUPPORTED 130 |
| 141 | #define SCTP_EXPOSE_POTENTIALLY_FAILED_STATE 131 | 141 | #define SCTP_EXPOSE_POTENTIALLY_FAILED_STATE 131 |
| 142 | #define SCTP_EXPOSE_PF_STATE SCTP_EXPOSE_POTENTIALLY_FAILED_STATE | 142 | #define SCTP_EXPOSE_PF_STATE SCTP_EXPOSE_POTENTIALLY_FAILED_STATE |
| 143 | #define SCTP_REMOTE_UDP_ENCAPS_PORT 132 | ||
| 143 | 144 | ||
| 144 | /* PR-SCTP policies */ | 145 | /* PR-SCTP policies */ |
| 145 | #define SCTP_PR_SCTP_NONE 0x0000 | 146 | #define SCTP_PR_SCTP_NONE 0x0000 |
| @@ -1197,6 +1198,12 @@ struct sctp_event { · 1051 unmodified lines | |||
| 1197 | uint8_t se_on; | 1198 | uint8_t se_on; |
| 1198 | }; | 1199 | }; |
| 1199 | 1200 | ||
| 1201 | struct sctp_udpencaps { | ||
| 1202 | sctp_assoc_t sue_assoc_id; | ||
| 1203 | struct sockaddr_storage sue_address; | ||
| 1204 | uint16_t sue_port; | ||
| 1205 | }; | ||
| 1206 | |||
| 1200 | /* SCTP Stream schedulers */ | 1207 | /* SCTP Stream schedulers */ |
| 1201 | enum sctp_sched_type { | 1208 | enum sctp_sched_type { |
| 1202 | SCTP_SS_FCFS, | 1209 | SCTP_SS_FCFS, |
| @@ -4417,6 +4417,55 @@ out: · 4416 unmodified lines | |||
| 4417 | return retval; | 4417 | return retval; |
| 4418 | } | 4418 | } |
| 4419 | 4419 | ||
| 4420 | static int sctp_setsockopt_encap_port(struct sock *sk, | ||
| 4421 | struct sctp_udpencaps *encap, | ||
| 4422 | unsigned int optlen) | ||
| 4423 | { | ||
| 4424 | struct sctp_association *asoc; | ||
| 4425 | struct sctp_transport *t; | ||
| 4426 | __be16 encap_port; | ||
| 4427 | |||
| 4428 | if (optlen != sizeof(*encap)) | ||
| 4429 | return -EINVAL; | ||
| 4430 | |||
| 4431 | /* If an address other than INADDR_ANY is specified, and | ||
| 4432 | * no transport is found, then the request is invalid. | ||
| 4433 | */ | ||
| 4434 | encap_port = (__force __be16)encap->sue_port; | ||
| 4435 | if (!sctp_is_any(sk, (union sctp_addr *)&encap->sue_address)) { | ||
| 4436 | t = sctp_addr_id2transport(sk, &encap->sue_address, | ||
| 4437 | encap->sue_assoc_id); | ||
| 4438 | if (!t) | ||
| 4439 | return -EINVAL; | ||
| 4440 | |||
| 4441 | t->encap_port = encap_port; | ||
| 4442 | return 0; | ||
| 4443 | } | ||
| 4444 | |||
| 4445 | /* Get association, if assoc_id != SCTP_FUTURE_ASSOC and the | ||
| 4446 | * socket is a one to many style socket, and an association | ||
| 4447 | * was not found, then the id was invalid. | ||
| 4448 | */ | ||
| 4449 | asoc = sctp_id2assoc(sk, encap->sue_assoc_id); | ||
| 4450 | if (!asoc && encap->sue_assoc_id != SCTP_FUTURE_ASSOC && | ||
| 4451 | sctp_style(sk, UDP)) | ||
| 4452 | return -EINVAL; | ||
| 4453 | |||
| 4454 | /* If changes are for association, also apply encap_port to | ||
| 4455 | * each transport. | ||
| 4456 | */ | ||
| 4457 | if (asoc) { | ||
| 4458 | list_for_each_entry(t, &asoc->peer.transport_addr_list, | ||
| 4459 | transports) | ||
| 4460 | t->encap_port = encap_port; | ||
| 4461 | |||
| 4462 | return 0; | ||
| 4463 | } | ||
| 4464 | |||
| 4465 | sctp_sk(sk)->encap_port = encap_port; | ||
| 4466 | return 0; | ||
| 4467 | } | ||
| 4468 | |||
| 4420 | /* API 6.2 setsockopt(), getsockopt() | 4469 | /* API 6.2 setsockopt(), getsockopt() |
| 4421 | * | 4470 | * |
| 4422 | * Applications use setsockopt() and getsockopt() to set or retrieve | 4471 | * Applications use setsockopt() and getsockopt() to set or retrieve |
| @@ -4636,6 +4685,9 @@ static int sctp_setsockopt(struct sock *sk, int level, int optname, · 213 unmodified lines | |||
| 4636 | case SCTP_EXPOSE_POTENTIALLY_FAILED_STATE: | 4685 | case SCTP_EXPOSE_POTENTIALLY_FAILED_STATE: |
| 4637 | retval = sctp_setsockopt_pf_expose(sk, kopt, optlen); | 4686 | retval = sctp_setsockopt_pf_expose(sk, kopt, optlen); |
| 4638 | break; | 4687 | break; |
| 4688 | case SCTP_REMOTE_UDP_ENCAPS_PORT: | ||
| 4689 | retval = sctp_setsockopt_encap_port(sk, kopt, optlen); | ||
| 4690 | break; | ||
| 4639 | default: | 4691 | default: |
| 4640 | retval = -ENOPROTOOPT; | 4692 | retval = -ENOPROTOOPT; |
| 4641 | break; | 4693 | break; |
| @@ -7791,6 +7843,65 @@ out: · 3149 unmodified lines | |||
| 7791 | return retval; | 7843 | return retval; |
| 7792 | } | 7844 | } |
| 7793 | 7845 | ||
| 7846 | static int sctp_getsockopt_encap_port(struct sock *sk, int len, | ||
| 7847 | char __user *optval, int __user *optlen) | ||
| 7848 | { | ||
| 7849 | struct sctp_association *asoc; | ||
| 7850 | struct sctp_udpencaps encap; | ||
| 7851 | struct sctp_transport *t; | ||
| 7852 | __be16 encap_port; | ||
| 7853 | |||
| 7854 | if (len < sizeof(encap)) | ||
| 7855 | return -EINVAL; | ||
| 7856 | |||
| 7857 | len = sizeof(encap); | ||
| 7858 | if (copy_from_user(&encap, optval, len)) | ||
| 7859 | return -EFAULT; | ||
| 7860 | |||
| 7861 | /* If an address other than INADDR_ANY is specified, and | ||
| 7862 | * no transport is found, then the request is invalid. | ||
| 7863 | */ | ||
| 7864 | if (!sctp_is_any(sk, (union sctp_addr *)&encap.sue_address)) { | ||
| 7865 | t = sctp_addr_id2transport(sk, &encap.sue_address, | ||
| 7866 | encap.sue_assoc_id); | ||
| 7867 | if (!t) { | ||
| 7868 | pr_debug("%s: failed no transport\n", __func__); | ||
| 7869 | return -EINVAL; | ||
| 7870 | } | ||
| 7871 | |||
| 7872 | encap_port = t->encap_port; | ||
| 7873 | goto out; | ||
| 7874 | } | ||
| 7875 | |||
| 7876 | /* Get association, if assoc_id != SCTP_FUTURE_ASSOC and the | ||
| 7877 | * socket is a one to many style socket, and an association | ||
| 7878 | * was not found, then the id was invalid. | ||
| 7879 | */ | ||
| 7880 | asoc = sctp_id2assoc(sk, encap.sue_assoc_id); | ||
| 7881 | if (!asoc && encap.sue_assoc_id != SCTP_FUTURE_ASSOC && | ||
| 7882 | sctp_style(sk, UDP)) { | ||
| 7883 | pr_debug("%s: failed no association\n", __func__); | ||
| 7884 | return -EINVAL; | ||
| 7885 | } | ||
| 7886 | |||
| 7887 | if (asoc) { | ||
| 7888 | encap_port = asoc->encap_port; | ||
| 7889 | goto out; | ||
| 7890 | } | ||
| 7891 | |||
| 7892 | encap_port = sctp_sk(sk)->encap_port; | ||
| 7893 | |||
| 7894 | out: | ||
| 7895 | encap.sue_port = (__force uint16_t)encap_port; | ||
| 7896 | if (copy_to_user(optval, &encap, len)) | ||
| 7897 | return -EFAULT; | ||
| 7898 | |||
| 7899 | if (put_user(len, optlen)) | ||
| 7900 | return -EFAULT; | ||
| 7901 | |||
| 7902 | return 0; | ||
| 7903 | } | ||
| 7904 | |||
| 7794 | static int sctp_getsockopt(struct sock *sk, int level, int optname, | 7905 | static int sctp_getsockopt(struct sock *sk, int level, int optname, |
| 7795 | char __user *optval, int __user *optlen) | 7906 | char __user *optval, int __user *optlen) |
| 7796 | { | 7907 | { |
| @@ -8011,6 +8122,9 @@ static int sctp_getsockopt(struct sock *sk, int level, int optname, · 214 unmodified lines | |||
| 8011 | case SCTP_EXPOSE_POTENTIALLY_FAILED_STATE: | 8122 | case SCTP_EXPOSE_POTENTIALLY_FAILED_STATE: |
| 8012 | retval = sctp_getsockopt_pf_expose(sk, len, optval, optlen); | 8123 | retval = sctp_getsockopt_pf_expose(sk, len, optval, optlen); |
| 8013 | break; | 8124 | break; |
| 8125 | case SCTP_REMOTE_UDP_ENCAPS_PORT: | ||
| 8126 | retval = sctp_getsockopt_encap_port(sk, len, optval, optlen); | ||
| 8127 | break; | ||
| 8014 | default: | 8128 | default: |
| 8015 | retval = -ENOPROTOOPT; | 8129 | retval = -ENOPROTOOPT; |
| 8016 | break; | 8130 | break; |