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 | 140 | #define SCTP_ECN_SUPPORTED 130 |
| 141 | 141 | #define SCTP_EXPOSE_POTENTIALLY_FAILED_STATE 131 |
| 142 | 142 | #define SCTP_EXPOSE_PF_STATE SCTP_EXPOSE_POTENTIALLY_FAILED_STATE |
| 143 | +#define SCTP_REMOTE_UDP_ENCAPS_PORT 132 | |
| 143 | 144 | |
| 144 | 145 | /* PR-SCTP policies */ |
| 145 | 146 | #define SCTP_PR_SCTP_NONE 0x0000 |
| @@ -1197,6 +1198,12 @@ struct sctp_event { · 1051 unmodified lines | ||
| 1197 | 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 | 1207 | /* SCTP Stream schedulers */ |
| 1201 | 1208 | enum sctp_sched_type { |
| 1202 | 1209 | SCTP_SS_FCFS, |
| @@ -4417,6 +4417,55 @@ out: · 4416 unmodified lines | ||
| 4417 | 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 | 4469 | /* API 6.2 setsockopt(), getsockopt() |
| 4421 | 4470 | * |
| 4422 | 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 | 4685 | case SCTP_EXPOSE_POTENTIALLY_FAILED_STATE: |
| 4637 | 4686 | retval = sctp_setsockopt_pf_expose(sk, kopt, optlen); |
| 4638 | 4687 | break; |
| 4688 | + case SCTP_REMOTE_UDP_ENCAPS_PORT: | |
| 4689 | + retval = sctp_setsockopt_encap_port(sk, kopt, optlen); | |
| 4690 | + break; | |
| 4639 | 4691 | default: |
| 4640 | 4692 | retval = -ENOPROTOOPT; |
| 4641 | 4693 | break; |
| @@ -7791,6 +7843,65 @@ out: · 3149 unmodified lines | ||
| 7791 | 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 | 7905 | static int sctp_getsockopt(struct sock *sk, int level, int optname, |
| 7795 | 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 | 8122 | case SCTP_EXPOSE_POTENTIALLY_FAILED_STATE: |
| 8012 | 8123 | retval = sctp_getsockopt_pf_expose(sk, len, optval, optlen); |
| 8013 | 8124 | break; |
| 8125 | + case SCTP_REMOTE_UDP_ENCAPS_PORT: | |
| 8126 | + retval = sctp_getsockopt_encap_port(sk, len, optval, optlen); | |
| 8127 | + break; | |
| 8014 | 8128 | default: |
| 8015 | 8129 | retval = -ENOPROTOOPT; |
| 8016 | 8130 | break; |