History

sctp: add SCTP_REMOTE_UDP_ENCAPS_PORT sockopt

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.

Xin Long committed 6 years ago

Commit 8dba2961 parent e8a30012 files · +121 −0Browse files

Unified · Split

2 files
  1. include/uapi/linux/sctp.h +7 −0
  2. net/sctp/socket.c +114 −0
include/uapi/linux/sctp.h+7−0
@@ -140,6 +140,7 @@ typedef __s32 sctp_assoc_t; · 139 unmodified lines
140140 #define SCTP_ECN_SUPPORTED 130
141141 #define SCTP_EXPOSE_POTENTIALLY_FAILED_STATE 131
142142 #define SCTP_EXPOSE_PF_STATE SCTP_EXPOSE_POTENTIALLY_FAILED_STATE
143+#define SCTP_REMOTE_UDP_ENCAPS_PORT 132
143144
144145 /* PR-SCTP policies */
145146 #define SCTP_PR_SCTP_NONE 0x0000
@@ -1197,6 +1198,12 @@ struct sctp_event { · 1051 unmodified lines
11971198 uint8_t se_on;
11981199 };
11991200
1201+struct sctp_udpencaps {
1202+ sctp_assoc_t sue_assoc_id;
1203+ struct sockaddr_storage sue_address;
1204+ uint16_t sue_port;
1205+};
1206+
12001207 /* SCTP Stream schedulers */
12011208 enum sctp_sched_type {
12021209 SCTP_SS_FCFS,
net/sctp/socket.c+114−0
@@ -4417,6 +4417,55 @@ out: · 4416 unmodified lines
44174417 return retval;
44184418 }
44194419
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+
44204469 /* API 6.2 setsockopt(), getsockopt()
44214470 *
44224471 * 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
46364685 case SCTP_EXPOSE_POTENTIALLY_FAILED_STATE:
46374686 retval = sctp_setsockopt_pf_expose(sk, kopt, optlen);
46384687 break;
4688+ case SCTP_REMOTE_UDP_ENCAPS_PORT:
4689+ retval = sctp_setsockopt_encap_port(sk, kopt, optlen);
4690+ break;
46394691 default:
46404692 retval = -ENOPROTOOPT;
46414693 break;
@@ -7791,6 +7843,65 @@ out: · 3149 unmodified lines
77917843 return retval;
77927844 }
77937845
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+
77947905 static int sctp_getsockopt(struct sock *sk, int level, int optname,
77957906 char __user *optval, int __user *optlen)
77967907 {
@@ -8011,6 +8122,9 @@ static int sctp_getsockopt(struct sock *sk, int level, int optname, · 214 unmodified lines
80118122 case SCTP_EXPOSE_POTENTIALLY_FAILED_STATE:
80128123 retval = sctp_getsockopt_pf_expose(sk, len, optval, optlen);
80138124 break;
8125+ case SCTP_REMOTE_UDP_ENCAPS_PORT:
8126+ retval = sctp_getsockopt_encap_port(sk, len, optval, optlen);
8127+ break;
80148128 default:
80158129 retval = -ENOPROTOOPT;
80168130 break;