diff options
Diffstat (limited to 'net/sctp/socket.c')
-rw-r--r-- | net/sctp/socket.c | 48 |
1 files changed, 44 insertions, 4 deletions
diff --git a/net/sctp/socket.c b/net/sctp/socket.c index 5fb3a8c9792e..0f01e5d8a24f 100644 --- a/net/sctp/socket.c +++ b/net/sctp/socket.c | |||
@@ -1100,6 +1100,15 @@ static int __sctp_connect(struct sock* sk, | |||
1100 | goto out_free; | 1100 | goto out_free; |
1101 | } | 1101 | } |
1102 | 1102 | ||
1103 | /* In case the user of sctp_connectx() wants an association | ||
1104 | * id back, assign one now. | ||
1105 | */ | ||
1106 | if (assoc_id) { | ||
1107 | err = sctp_assoc_set_id(asoc, GFP_KERNEL); | ||
1108 | if (err < 0) | ||
1109 | goto out_free; | ||
1110 | } | ||
1111 | |||
1103 | err = sctp_primitive_ASSOCIATE(asoc, NULL); | 1112 | err = sctp_primitive_ASSOCIATE(asoc, NULL); |
1104 | if (err < 0) { | 1113 | if (err < 0) { |
1105 | goto out_free; | 1114 | goto out_free; |
@@ -1120,7 +1129,7 @@ static int __sctp_connect(struct sock* sk, | |||
1120 | timeo = sock_sndtimeo(sk, f_flags & O_NONBLOCK); | 1129 | timeo = sock_sndtimeo(sk, f_flags & O_NONBLOCK); |
1121 | 1130 | ||
1122 | err = sctp_wait_for_connect(asoc, &timeo); | 1131 | err = sctp_wait_for_connect(asoc, &timeo); |
1123 | if (!err && assoc_id) | 1132 | if ((err == 0 || err == -EINPROGRESS) && assoc_id) |
1124 | *assoc_id = asoc->assoc_id; | 1133 | *assoc_id = asoc->assoc_id; |
1125 | 1134 | ||
1126 | /* Don't free association on exit. */ | 1135 | /* Don't free association on exit. */ |
@@ -1264,6 +1273,34 @@ SCTP_STATIC int sctp_setsockopt_connectx(struct sock* sk, | |||
1264 | return assoc_id; | 1273 | return assoc_id; |
1265 | } | 1274 | } |
1266 | 1275 | ||
1276 | /* | ||
1277 | * New (hopefully final) interface for the API. The option buffer is used | ||
1278 | * both for the returned association id and the addresses. | ||
1279 | */ | ||
1280 | SCTP_STATIC int sctp_getsockopt_connectx3(struct sock* sk, int len, | ||
1281 | char __user *optval, | ||
1282 | int __user *optlen) | ||
1283 | { | ||
1284 | sctp_assoc_t assoc_id = 0; | ||
1285 | int err = 0; | ||
1286 | |||
1287 | if (len < sizeof(assoc_id)) | ||
1288 | return -EINVAL; | ||
1289 | |||
1290 | err = __sctp_setsockopt_connectx(sk, | ||
1291 | (struct sockaddr __user *)(optval + sizeof(assoc_id)), | ||
1292 | len - sizeof(assoc_id), &assoc_id); | ||
1293 | |||
1294 | if (err == 0 || err == -EINPROGRESS) { | ||
1295 | if (copy_to_user(optval, &assoc_id, sizeof(assoc_id))) | ||
1296 | return -EFAULT; | ||
1297 | if (put_user(sizeof(assoc_id), optlen)) | ||
1298 | return -EFAULT; | ||
1299 | } | ||
1300 | |||
1301 | return err; | ||
1302 | } | ||
1303 | |||
1267 | /* API 3.1.4 close() - UDP Style Syntax | 1304 | /* API 3.1.4 close() - UDP Style Syntax |
1268 | * Applications use close() to perform graceful shutdown (as described in | 1305 | * Applications use close() to perform graceful shutdown (as described in |
1269 | * Section 10.1 of [SCTP]) on ALL the associations currently represented | 1306 | * Section 10.1 of [SCTP]) on ALL the associations currently represented |
@@ -1844,7 +1881,7 @@ static int sctp_skb_pull(struct sk_buff *skb, int len) | |||
1844 | len -= skb_len; | 1881 | len -= skb_len; |
1845 | __skb_pull(skb, skb_len); | 1882 | __skb_pull(skb, skb_len); |
1846 | 1883 | ||
1847 | for (list = skb_shinfo(skb)->frag_list; list; list = list->next) { | 1884 | skb_walk_frags(skb, list) { |
1848 | rlen = sctp_skb_pull(list, len); | 1885 | rlen = sctp_skb_pull(list, len); |
1849 | skb->len -= (len-rlen); | 1886 | skb->len -= (len-rlen); |
1850 | skb->data_len -= (len-rlen); | 1887 | skb->data_len -= (len-rlen); |
@@ -5578,6 +5615,9 @@ SCTP_STATIC int sctp_getsockopt(struct sock *sk, int level, int optname, | |||
5578 | retval = sctp_getsockopt_local_addrs(sk, len, optval, | 5615 | retval = sctp_getsockopt_local_addrs(sk, len, optval, |
5579 | optlen); | 5616 | optlen); |
5580 | break; | 5617 | break; |
5618 | case SCTP_SOCKOPT_CONNECTX3: | ||
5619 | retval = sctp_getsockopt_connectx3(sk, len, optval, optlen); | ||
5620 | break; | ||
5581 | case SCTP_DEFAULT_SEND_PARAM: | 5621 | case SCTP_DEFAULT_SEND_PARAM: |
5582 | retval = sctp_getsockopt_default_send_param(sk, len, | 5622 | retval = sctp_getsockopt_default_send_param(sk, len, |
5583 | optval, optlen); | 5623 | optval, optlen); |
@@ -6620,7 +6660,7 @@ static void sctp_sock_rfree_frag(struct sk_buff *skb) | |||
6620 | goto done; | 6660 | goto done; |
6621 | 6661 | ||
6622 | /* Don't forget the fragments. */ | 6662 | /* Don't forget the fragments. */ |
6623 | for (frag = skb_shinfo(skb)->frag_list; frag; frag = frag->next) | 6663 | skb_walk_frags(skb, frag) |
6624 | sctp_sock_rfree_frag(frag); | 6664 | sctp_sock_rfree_frag(frag); |
6625 | 6665 | ||
6626 | done: | 6666 | done: |
@@ -6635,7 +6675,7 @@ static void sctp_skb_set_owner_r_frag(struct sk_buff *skb, struct sock *sk) | |||
6635 | goto done; | 6675 | goto done; |
6636 | 6676 | ||
6637 | /* Don't forget the fragments. */ | 6677 | /* Don't forget the fragments. */ |
6638 | for (frag = skb_shinfo(skb)->frag_list; frag; frag = frag->next) | 6678 | skb_walk_frags(skb, frag) |
6639 | sctp_skb_set_owner_r_frag(frag, sk); | 6679 | sctp_skb_set_owner_r_frag(frag, sk); |
6640 | 6680 | ||
6641 | done: | 6681 | done: |