aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/net/sctp/sctp.h1
-rw-r--r--net/sctp/socket.c24
2 files changed, 10 insertions, 15 deletions
diff --git a/include/net/sctp/sctp.h b/include/net/sctp/sctp.h
index d3685615a8b0..6ee44b24864a 100644
--- a/include/net/sctp/sctp.h
+++ b/include/net/sctp/sctp.h
@@ -413,6 +413,7 @@ static inline sctp_assoc_t sctp_assoc2id(const struct sctp_association *asoc)
413/* Look up the association by its id. */ 413/* Look up the association by its id. */
414struct sctp_association *sctp_id2assoc(struct sock *sk, sctp_assoc_t id); 414struct sctp_association *sctp_id2assoc(struct sock *sk, sctp_assoc_t id);
415 415
416int sctp_do_peeloff(struct sock *sk, sctp_assoc_t id, struct socket **sockp);
416 417
417/* A macro to walk a list of skbs. */ 418/* A macro to walk a list of skbs. */
418#define sctp_skb_for_each(pos, head, tmp) \ 419#define sctp_skb_for_each(pos, head, tmp) \
diff --git a/net/sctp/socket.c b/net/sctp/socket.c
index 408ebd0e7330..06b42b7f5a02 100644
--- a/net/sctp/socket.c
+++ b/net/sctp/socket.c
@@ -4170,14 +4170,16 @@ static int sctp_getsockopt_autoclose(struct sock *sk, int len, char __user *optv
4170} 4170}
4171 4171
4172/* Helper routine to branch off an association to a new socket. */ 4172/* Helper routine to branch off an association to a new socket. */
4173SCTP_STATIC int sctp_do_peeloff(struct sctp_association *asoc, 4173int sctp_do_peeloff(struct sock *sk, sctp_assoc_t id, struct socket **sockp)
4174 struct socket **sockp)
4175{ 4174{
4176 struct sock *sk = asoc->base.sk; 4175 struct sctp_association *asoc = sctp_id2assoc(sk, id);
4177 struct socket *sock; 4176 struct socket *sock;
4178 struct sctp_af *af; 4177 struct sctp_af *af;
4179 int err = 0; 4178 int err = 0;
4180 4179
4180 if (!asoc)
4181 return -EINVAL;
4182
4181 /* An association cannot be branched off from an already peeled-off 4183 /* An association cannot be branched off from an already peeled-off
4182 * socket, nor is this supported for tcp style sockets. 4184 * socket, nor is this supported for tcp style sockets.
4183 */ 4185 */
@@ -4206,13 +4208,13 @@ SCTP_STATIC int sctp_do_peeloff(struct sctp_association *asoc,
4206 4208
4207 return err; 4209 return err;
4208} 4210}
4211EXPORT_SYMBOL(sctp_do_peeloff);
4209 4212
4210static int sctp_getsockopt_peeloff(struct sock *sk, int len, char __user *optval, int __user *optlen) 4213static int sctp_getsockopt_peeloff(struct sock *sk, int len, char __user *optval, int __user *optlen)
4211{ 4214{
4212 sctp_peeloff_arg_t peeloff; 4215 sctp_peeloff_arg_t peeloff;
4213 struct socket *newsock; 4216 struct socket *newsock;
4214 int retval = 0; 4217 int retval = 0;
4215 struct sctp_association *asoc;
4216 4218
4217 if (len < sizeof(sctp_peeloff_arg_t)) 4219 if (len < sizeof(sctp_peeloff_arg_t))
4218 return -EINVAL; 4220 return -EINVAL;
@@ -4220,15 +4222,7 @@ static int sctp_getsockopt_peeloff(struct sock *sk, int len, char __user *optval
4220 if (copy_from_user(&peeloff, optval, len)) 4222 if (copy_from_user(&peeloff, optval, len))
4221 return -EFAULT; 4223 return -EFAULT;
4222 4224
4223 asoc = sctp_id2assoc(sk, peeloff.associd); 4225 retval = sctp_do_peeloff(sk, peeloff.associd, &newsock);
4224 if (!asoc) {
4225 retval = -EINVAL;
4226 goto out;
4227 }
4228
4229 SCTP_DEBUG_PRINTK("%s: sk: %p asoc: %p\n", __func__, sk, asoc);
4230
4231 retval = sctp_do_peeloff(asoc, &newsock);
4232 if (retval < 0) 4226 if (retval < 0)
4233 goto out; 4227 goto out;
4234 4228
@@ -4239,8 +4233,8 @@ static int sctp_getsockopt_peeloff(struct sock *sk, int len, char __user *optval
4239 goto out; 4233 goto out;
4240 } 4234 }
4241 4235
4242 SCTP_DEBUG_PRINTK("%s: sk: %p asoc: %p newsk: %p sd: %d\n", 4236 SCTP_DEBUG_PRINTK("%s: sk: %p newsk: %p sd: %d\n",
4243 __func__, sk, asoc, newsock->sk, retval); 4237 __func__, sk, newsock->sk, retval);
4244 4238
4245 /* Return the fd mapped to the new socket. */ 4239 /* Return the fd mapped to the new socket. */
4246 peeloff.sd = retval; 4240 peeloff.sd = retval;