diff options
Diffstat (limited to 'net/sctp/socket.c')
| -rw-r--r-- | net/sctp/socket.c | 184 |
1 files changed, 140 insertions, 44 deletions
diff --git a/net/sctp/socket.c b/net/sctp/socket.c index fd6c36e0415c..cda5d5aab53c 100644 --- a/net/sctp/socket.c +++ b/net/sctp/socket.c @@ -81,13 +81,13 @@ /* Forward declarations for internal helper functions. */ static int sctp_writeable(struct sock *sk); -static inline int sctp_wspace(sctp_association_t *asoc); +static inline int sctp_wspace(struct sctp_association *asoc); static inline void sctp_set_owner_w(sctp_chunk_t *chunk); static void sctp_wfree(struct sk_buff *skb); -static int sctp_wait_for_sndbuf(sctp_association_t *asoc, long *timeo_p, +static int sctp_wait_for_sndbuf(struct sctp_association *, long *timeo_p, int msg_len); static int sctp_wait_for_packet(struct sock * sk, int *err, long *timeo_p); -static int sctp_wait_for_connect(sctp_association_t *asoc, long *timeo_p); +static int sctp_wait_for_connect(struct sctp_association *, long *timeo_p); static inline int sctp_verify_addr(struct sock *, union sctp_addr *, int); static int sctp_bindx_add(struct sock *, struct sockaddr_storage *, int); static int sctp_bindx_rem(struct sock *, struct sockaddr_storage *, int); @@ -158,7 +158,7 @@ static struct sctp_af *sctp_sockaddr_af(struct sctp_opt *opt, /* Bind a local address either to an endpoint or to an association. */ SCTP_STATIC int sctp_do_bind(struct sock *sk, union sctp_addr *addr, int len) { - sctp_opt_t *sp = sctp_sk(sk); + struct sctp_opt *sp = sctp_sk(sk); sctp_endpoint_t *ep = sp->ep; sctp_bind_addr_t *bp = &ep->base.bind_addr; struct sctp_af *af; @@ -454,7 +454,7 @@ err_bindx_add: */ int sctp_bindx_rem(struct sock *sk, struct sockaddr_storage *addrs, int addrcnt) { - sctp_opt_t *sp = sctp_sk(sk); + struct sctp_opt *sp = sctp_sk(sk); sctp_endpoint_t *ep = sp->ep; int cnt; sctp_bind_addr_t *bp = &ep->base.bind_addr; @@ -662,6 +662,7 @@ SCTP_STATIC void sctp_close(struct sock *sk, long timeout) /* Clean up any skbs sitting on the receive queue. */ skb_queue_purge(&sk->receive_queue); + skb_queue_purge(&sctp_sk(sk)->pd_lobby); /* This will run the backlog queue. */ sctp_release_sock(sk); @@ -714,7 +715,7 @@ SCTP_STATIC int sctp_msghdr_parse(const struct msghdr *, sctp_cmsgs_t *); SCTP_STATIC int sctp_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, int msg_len) { - sctp_opt_t *sp; + struct sctp_opt *sp; sctp_endpoint_t *ep; sctp_association_t *new_asoc=NULL, *asoc=NULL; struct sctp_transport *transport; @@ -939,6 +940,19 @@ SCTP_STATIC int sctp_sendmsg(struct kiocb *iocb, struct sock *sk, /* ASSERT: we have a valid association at this point. */ SCTP_DEBUG_PRINTK("We have a valid association.\n"); + if (!sinfo) { + /* If the user didn't specify SNDRCVINFO, make up one with + * some defaults. + */ + default_sinfo.sinfo_stream = asoc->defaults.stream; + default_sinfo.sinfo_flags = asoc->defaults.flags; + default_sinfo.sinfo_ppid = asoc->defaults.ppid; + default_sinfo.sinfo_context = asoc->defaults.context; + default_sinfo.sinfo_timetolive = asoc->defaults.timetolive; + default_sinfo.sinfo_assoc_id = sctp_assoc2id(asoc); + sinfo = &default_sinfo; + } + /* API 7.1.7, the sndbuf size per association bounds the * maximum size of data that can be sent in a single send call. */ @@ -963,13 +977,6 @@ SCTP_STATIC int sctp_sendmsg(struct kiocb *iocb, struct sock *sk, err = -EINVAL; goto out_free; } - } else { - /* If the user didn't specify SNDRCVINFO, make up one with - * some defaults. - */ - default_sinfo.sinfo_stream = asoc->defaults.stream; - default_sinfo.sinfo_ppid = asoc->defaults.ppid; - sinfo = &default_sinfo; } timeo = sock_sndtimeo(sk, msg->msg_flags & MSG_DONTWAIT); @@ -979,21 +986,6 @@ SCTP_STATIC int sctp_sendmsg(struct kiocb *iocb, struct sock *sk, goto out_free; } -#if 0 - /* FIXME: This looks wrong so I'll comment out. - * We should be able to use this same technique for - * primary address override! --jgrimm - */ - /* If the user gave us an address, copy it in. */ - if (msg->msg_name) { - chunk->transport = sctp_assoc_lookup_paddr(asoc, &to); - if (!chunk->transport) { - err = -EINVAL; - goto out_free; - } - } -#endif /* 0 */ - /* Break the message into multiple chunks of maximum size. */ skb_queue_head_init(&chunks); err = sctp_datachunks_from_user(asoc, sinfo, msg, msg_len, &chunks); @@ -1013,6 +1005,23 @@ SCTP_STATIC int sctp_sendmsg(struct kiocb *iocb, struct sock *sk, /* Do accounting for the write space. */ sctp_set_owner_w(chunk); + + /* This flag, in the UDP model, requests the SCTP stack to + * override the primary destination address with the + * address found with the sendto/sendmsg call. + */ + if (sinfo_flags & MSG_ADDR_OVER) { + if (!msg->msg_name) { + err = -EINVAL; + goto out_free; + } + chunk->transport = sctp_assoc_lookup_paddr(asoc, &to); + if (!chunk->transport) { + err = -EINVAL; + goto out_free; + } + } + /* Send it to the lower layers. */ sctp_primitive_SEND(asoc, chunk); SCTP_DEBUG_PRINTK("We sent primitively.\n"); @@ -1110,8 +1119,8 @@ static struct sk_buff *sctp_skb_recv_datagram(struct sock *, int, int, int *); SCTP_STATIC int sctp_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, int len, int noblock, int flags, int *addr_len) { - sctp_ulpevent_t *event = NULL; - sctp_opt_t *sp = sctp_sk(sk); + struct sctp_ulpevent *event = NULL; + struct sctp_opt *sp = sctp_sk(sk); struct sk_buff *skb; int copied; int err = 0; @@ -1143,7 +1152,7 @@ SCTP_STATIC int sctp_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr err = skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied); - event = (sctp_ulpevent_t *) skb->cb; + event = sctp_skb2event(skb); if (err) goto out_free; @@ -1170,7 +1179,6 @@ SCTP_STATIC int sctp_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr /* If skb's length exceeds the user's buffer, update the skb and * push it back to the receive_queue so that the next call to * recvmsg() will return the remaining data. Don't set MSG_EOR. - * Otherwise, set MSG_EOR indicating the end of a message. */ if (skb_len > copied) { msg->msg_flags &= ~MSG_EOR; @@ -1178,6 +1186,7 @@ SCTP_STATIC int sctp_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr goto out_free; sctp_skb_pull(skb, copied); skb_queue_head(&sk->receive_queue, skb); + /* When only partial message is copied to the user, increase * rwnd by that amount. If all the data in the skb is read, * rwnd is updated when the skb's destructor is called via @@ -1185,9 +1194,11 @@ SCTP_STATIC int sctp_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr */ sctp_assoc_rwnd_increase(event->asoc, copied); goto out; - } else { - msg->msg_flags |= MSG_EOR; - } + } else if ((event->msg_flags & MSG_NOTIFICATION) || + (event->msg_flags & MSG_EOR)) + msg->msg_flags |= MSG_EOR; + else + msg->msg_flags &= ~MSG_EOR; out_free: sctp_ulpevent_free(event); /* Free the skb. */ @@ -1225,7 +1236,7 @@ static inline int sctp_setsockopt_set_events(struct sock *sk, char *optval, static inline int sctp_setsockopt_autoclose(struct sock *sk, char *optval, int optlen) { - sctp_opt_t *sp = sctp_sk(sk); + struct sctp_opt *sp = sctp_sk(sk); /* Applicable to UDP-style socket only */ if (SCTP_SOCKET_TCP == sp->type) @@ -1310,6 +1321,44 @@ static inline int sctp_setsockopt_initmsg(struct sock *sk, char *optval, return 0; } +/* + * + * 7.1.15 Set default send parameters (SET_DEFAULT_SEND_PARAM) + * + * Applications that wish to use the sendto() system call may wish to + * specify a default set of parameters that would normally be supplied + * through the inclusion of ancillary data. This socket option allows + * such an application to set the default sctp_sndrcvinfo structure. + * The application that wishes to use this socket option simply passes + * in to this call the sctp_sndrcvinfo structure defined in Section + * 5.2.2) The input parameters accepted by this call include + * sinfo_stream, sinfo_flags, sinfo_ppid, sinfo_context, + * sinfo_timetolive. The user must provide the sinfo_assoc_id field in + * to this call if the caller is using the UDP model. + */ +static inline int sctp_setsockopt_set_default_send_param(struct sock *sk, + char *optval, int optlen) +{ + struct sctp_sndrcvinfo info; + sctp_association_t *asoc; + + if (optlen != sizeof(struct sctp_sndrcvinfo)) + return -EINVAL; + if (copy_from_user(&info, optval, optlen)) + return -EFAULT; + + asoc = sctp_id2assoc(sk, info.sinfo_assoc_id); + if (!asoc) + return -EINVAL; + + asoc->defaults.stream = info.sinfo_stream; + asoc->defaults.flags = info.sinfo_flags; + asoc->defaults.ppid = info.sinfo_ppid; + asoc->defaults.context = info.sinfo_context; + asoc->defaults.timetolive = info.sinfo_timetolive; + return 0; +} + /* API 6.2 setsockopt(), getsockopt() * * Applications use setsockopt() and getsockopt() to set or retrieve @@ -1401,6 +1450,11 @@ SCTP_STATIC int sctp_setsockopt(struct sock *sk, int level, int optname, retval = sctp_setsockopt_initmsg(sk, optval, optlen); break; + case SCTP_SET_DEFAULT_SEND_PARAM: + retval = sctp_setsockopt_set_default_send_param(sk, + optval, optlen); + break; + default: retval = -ENOPROTOOPT; break; @@ -1432,7 +1486,7 @@ out_nounlock: SCTP_STATIC int sctp_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len) { - sctp_opt_t *sp; + struct sctp_opt *sp; sctp_endpoint_t *ep; sctp_association_t *asoc; struct sctp_transport *transport; @@ -1554,7 +1608,7 @@ SCTP_STATIC int sctp_init_sock(struct sock *sk) { sctp_endpoint_t *ep; sctp_protocol_t *proto; - sctp_opt_t *sp; + struct sctp_opt *sp; SCTP_DEBUG_PRINTK("sctp_init_sock(sk: %p)\n", sk); @@ -1583,7 +1637,7 @@ SCTP_STATIC int sctp_init_sock(struct sock *sk) /* Initialize default RTO related parameters. These parameters can * be modified for with the SCTP_RTOINFO socket option. - * FIXME: This are not used yet. + * FIXME: These are not used yet. */ sp->rtoinfo.srto_initial = proto->rto_initial; sp->rtoinfo.srto_max = proto->rto_max; @@ -1620,6 +1674,11 @@ SCTP_STATIC int sctp_init_sock(struct sock *sk) */ sp->autoclose = 0; sp->pf = sctp_get_pf_specific(sk->family); + + /* Control variables for partial data delivery. */ + sp->pd_mode = 0; + skb_queue_head_init(&sp->pd_lobby); + /* Create a per socket endpoint structure. Even if we * change the data structure relationships, this may still * be useful for storing pre-connect address information. @@ -1774,10 +1833,10 @@ SCTP_STATIC int sctp_do_peeloff(sctp_association_t *assoc, struct socket **newso struct sock *newsk; struct socket *tmpsock; sctp_endpoint_t *newep; - sctp_opt_t *oldsp = sctp_sk(oldsk); - sctp_opt_t *newsp; + struct sctp_opt *oldsp = sctp_sk(oldsk); + struct sctp_opt *newsp; struct sk_buff *skb, *tmp; - sctp_ulpevent_t *event; + struct sctp_ulpevent *event; int err = 0; /* An association cannot be branched off from an already peeled-off @@ -1811,13 +1870,50 @@ SCTP_STATIC int sctp_do_peeloff(sctp_association_t *assoc, struct socket **newso * peeled off association to the new socket's receive queue. */ sctp_skb_for_each(skb, &oldsk->receive_queue, tmp) { - event = (sctp_ulpevent_t *)skb->cb; + event = sctp_skb2event(skb); if (event->asoc == assoc) { __skb_unlink(skb, skb->list); __skb_queue_tail(&newsk->receive_queue, skb); } } + /* Clean up an messages pending delivery due to partial + * delivery. Three cases: + * 1) No partial deliver; no work. + * 2) Peeling off partial delivery; keep pd_lobby in new pd_lobby. + * 3) Peeling off non-partial delivery; move pd_lobby to recieve_queue. + */ + skb_queue_head_init(&newsp->pd_lobby); + sctp_sk(newsk)->pd_mode = assoc->ulpq.pd_mode;; + + if (sctp_sk(oldsk)->pd_mode) { + struct sk_buff_head *queue; + + /* Decide which queue to move pd_lobby skbs to. */ + if (assoc->ulpq.pd_mode) { + queue = &newsp->pd_lobby; + } else + queue = &newsk->receive_queue; + + /* Walk through the pd_lobby, looking for skbs that + * need moved to the new socket. + */ + sctp_skb_for_each(skb, &oldsp->pd_lobby, tmp) { + event = sctp_skb2event(skb); + if (event->asoc == assoc) { + __skb_unlink(skb, skb->list); + __skb_queue_tail(queue, skb); + } + } + + /* Clear up any skbs waiting for the partial + * delivery to finish. + */ + if (assoc->ulpq.pd_mode) + sctp_clear_pd(oldsk); + + } + /* Set the type of socket to indicate that it is peeled off from the * original socket. */ @@ -2389,7 +2485,7 @@ static int sctp_get_port(struct sock *sk, unsigned short snum) */ SCTP_STATIC int sctp_seqpacket_listen(struct sock *sk, int backlog) { - sctp_opt_t *sp = sctp_sk(sk); + struct sctp_opt *sp = sctp_sk(sk); sctp_endpoint_t *ep = sp->ep; /* Only UDP style sockets that are not peeled off are allowed to |
