This patch adds sockopt SCTP_EVENT described in rfc6525#section-6.2. With this sockopt users can subscribe to an event from a specified asoc.
Unified · Split
| @@ -129,6 +129,7 @@ typedef __s32 sctp_assoc_t; · 128 unmodified lines | ||
| 129 | 129 | #define SCTP_STREAM_SCHEDULER_VALUE 124 |
| 130 | 130 | #define SCTP_INTERLEAVING_SUPPORTED 125 |
| 131 | 131 | #define SCTP_SENDMSG_CONNECT 126 |
| 132 | +#define SCTP_EVENT 127 | |
| 132 | 133 | |
| 133 | 134 | /* PR-SCTP policies */ |
| 134 | 135 | #define SCTP_PR_SCTP_NONE 0x0000 |
| @@ -1154,6 +1155,12 @@ struct sctp_add_streams { · 1019 unmodified lines | ||
| 1154 | 1155 | uint16_t sas_outstrms; |
| 1155 | 1156 | }; |
| 1156 | 1157 | |
| 1158 | +struct sctp_event { | |
| 1159 | + sctp_assoc_t se_assoc_id; | |
| 1160 | + uint16_t se_type; | |
| 1161 | + uint8_t se_on; | |
| 1162 | +}; | |
| 1163 | + | |
| 1157 | 1164 | /* SCTP Stream schedulers */ |
| 1158 | 1165 | enum sctp_sched_type { |
| 1159 | 1166 | SCTP_SS_FCFS, |
| @@ -4288,6 +4288,57 @@ static int sctp_setsockopt_reuse_port(struct sock *sk, char __user *optval, · 4287 unmodified lines | ||
| 4288 | 4288 | return 0; |
| 4289 | 4289 | } |
| 4290 | 4290 | |
| 4291 | +static int sctp_setsockopt_event(struct sock *sk, char __user *optval, | |
| 4292 | + unsigned int optlen) | |
| 4293 | +{ | |
| 4294 | + struct sctp_association *asoc; | |
| 4295 | + struct sctp_ulpevent *event; | |
| 4296 | + struct sctp_event param; | |
| 4297 | + int retval = 0; | |
| 4298 | + | |
| 4299 | + if (optlen < sizeof(param)) { | |
| 4300 | + retval = -EINVAL; | |
| 4301 | + goto out; | |
| 4302 | + } | |
| 4303 | + | |
| 4304 | + optlen = sizeof(param); | |
| 4305 | + if (copy_from_user(¶m, optval, optlen)) { | |
| 4306 | + retval = -EFAULT; | |
| 4307 | + goto out; | |
| 4308 | + } | |
| 4309 | + | |
| 4310 | + if (param.se_type < SCTP_SN_TYPE_BASE || | |
| 4311 | + param.se_type > SCTP_SN_TYPE_MAX) { | |
| 4312 | + retval = -EINVAL; | |
| 4313 | + goto out; | |
| 4314 | + } | |
| 4315 | + | |
| 4316 | + asoc = sctp_id2assoc(sk, param.se_assoc_id); | |
| 4317 | + if (!asoc) { | |
| 4318 | + sctp_ulpevent_type_set(&sctp_sk(sk)->subscribe, | |
| 4319 | + param.se_type, param.se_on); | |
| 4320 | + goto out; | |
| 4321 | + } | |
| 4322 | + | |
| 4323 | + sctp_ulpevent_type_set(&asoc->subscribe, param.se_type, param.se_on); | |
| 4324 | + | |
| 4325 | + if (param.se_type == SCTP_SENDER_DRY_EVENT && param.se_on) { | |
| 4326 | + if (sctp_outq_is_empty(&asoc->outqueue)) { | |
| 4327 | + event = sctp_ulpevent_make_sender_dry_event(asoc, | |
| 4328 | + GFP_USER | __GFP_NOWARN); | |
| 4329 | + if (!event) { | |
| 4330 | + retval = -ENOMEM; | |
| 4331 | + goto out; | |
| 4332 | + } | |
| 4333 | + | |
| 4334 | + asoc->stream.si->enqueue_event(&asoc->ulpq, event); | |
| 4335 | + } | |
| 4336 | + } | |
| 4337 | + | |
| 4338 | +out: | |
| 4339 | + return retval; | |
| 4340 | +} | |
| 4341 | + | |
| 4291 | 4342 | /* API 6.2 setsockopt(), getsockopt() |
| 4292 | 4343 | * |
| 4293 | 4344 | * Applications use setsockopt() and getsockopt() to set or retrieve |
| @@ -4485,6 +4536,9 @@ static int sctp_setsockopt(struct sock *sk, int level, int optname, · 191 unmodified lines | ||
| 4485 | 4536 | case SCTP_REUSE_PORT: |
| 4486 | 4537 | retval = sctp_setsockopt_reuse_port(sk, optval, optlen); |
| 4487 | 4538 | break; |
| 4539 | + case SCTP_EVENT: | |
| 4540 | + retval = sctp_setsockopt_event(sk, optval, optlen); | |
| 4541 | + break; | |
| 4488 | 4542 | default: |
| 4489 | 4543 | retval = -ENOPROTOOPT; |
| 4490 | 4544 | break; |
| @@ -7430,6 +7484,37 @@ static int sctp_getsockopt_reuse_port(struct sock *sk, int len, · 2939 unmodified lines | ||
| 7430 | 7484 | return 0; |
| 7431 | 7485 | } |
| 7432 | 7486 | |
| 7487 | +static int sctp_getsockopt_event(struct sock *sk, int len, char __user *optval, | |
| 7488 | + int __user *optlen) | |
| 7489 | +{ | |
| 7490 | + struct sctp_association *asoc; | |
| 7491 | + struct sctp_event param; | |
| 7492 | + __u16 subscribe; | |
| 7493 | + | |
| 7494 | + if (len < sizeof(param)) | |
| 7495 | + return -EINVAL; | |
| 7496 | + | |
| 7497 | + len = sizeof(param); | |
| 7498 | + if (copy_from_user(¶m, optval, len)) | |
| 7499 | + return -EFAULT; | |
| 7500 | + | |
| 7501 | + if (param.se_type < SCTP_SN_TYPE_BASE || | |
| 7502 | + param.se_type > SCTP_SN_TYPE_MAX) | |
| 7503 | + return -EINVAL; | |
| 7504 | + | |
| 7505 | + asoc = sctp_id2assoc(sk, param.se_assoc_id); | |
| 7506 | + subscribe = asoc ? asoc->subscribe : sctp_sk(sk)->subscribe; | |
| 7507 | + param.se_on = sctp_ulpevent_type_enabled(subscribe, param.se_type); | |
| 7508 | + | |
| 7509 | + if (put_user(len, optlen)) | |
| 7510 | + return -EFAULT; | |
| 7511 | + | |
| 7512 | + if (copy_to_user(optval, ¶m, len)) | |
| 7513 | + return -EFAULT; | |
| 7514 | + | |
| 7515 | + return 0; | |
| 7516 | +} | |
| 7517 | + | |
| 7433 | 7518 | static int sctp_getsockopt(struct sock *sk, int level, int optname, |
| 7434 | 7519 | char __user *optval, int __user *optlen) |
| 7435 | 7520 | { |
| @@ -7628,6 +7713,9 @@ static int sctp_getsockopt(struct sock *sk, int level, int optname, · 192 unmodified lines | ||
| 7628 | 7713 | case SCTP_REUSE_PORT: |
| 7629 | 7714 | retval = sctp_getsockopt_reuse_port(sk, len, optval, optlen); |
| 7630 | 7715 | break; |
| 7716 | + case SCTP_EVENT: | |
| 7717 | + retval = sctp_getsockopt_event(sk, len, optval, optlen); | |
| 7718 | + break; | |
| 7631 | 7719 | default: |
| 7632 | 7720 | retval = -ENOPROTOOPT; |
| 7633 | 7721 | break; |