Example #1
0
/* Create and initialize an SCTP_PEER_ADDR_CHANGE event.
 *
 * Socket Extensions for SCTP - draft-01
 * 5.3.1.2 SCTP_PEER_ADDR_CHANGE
 *
 * When a destination address on a multi-homed peer encounters a change
 * an interface details event is sent.
 */
struct sctp_ulpevent *sctp_ulpevent_make_peer_addr_change(
	const struct sctp_association *asoc,
	const struct sockaddr_storage *aaddr,
	int flags, int state, int error, gfp_t gfp)
{
	struct sctp_ulpevent *event;
	struct sctp_paddr_change  *spc;
	struct sk_buff *skb;

	event = sctp_ulpevent_new(sizeof(struct sctp_paddr_change),
				  MSG_NOTIFICATION, gfp);
	if (!event)
		goto fail;

	skb = sctp_event2skb(event);
	spc = (struct sctp_paddr_change *)
		skb_put(skb, sizeof(struct sctp_paddr_change));

	/* Sockets API Extensions for SCTP
	 * Section 5.3.1.2 SCTP_PEER_ADDR_CHANGE
	 *
	 * spc_type:
	 *
	 *    It should be SCTP_PEER_ADDR_CHANGE.
	 */
	spc->spc_type = SCTP_PEER_ADDR_CHANGE;

	/* Sockets API Extensions for SCTP
	 * Section 5.3.1.2 SCTP_PEER_ADDR_CHANGE
	 *
	 * spc_length: sizeof (__u32)
	 *
	 * This field is the total length of the notification data, including
	 * the notification header.
	 */
	spc->spc_length = sizeof(struct sctp_paddr_change);

	/* Sockets API Extensions for SCTP
	 * Section 5.3.1.2 SCTP_PEER_ADDR_CHANGE
	 *
	 * spc_flags: 16 bits (unsigned integer)
	 * Currently unused.
	 */
	spc->spc_flags = 0;

	/* Sockets API Extensions for SCTP
	 * Section 5.3.1.2 SCTP_PEER_ADDR_CHANGE
	 *
	 * spc_state:  32 bits (signed integer)
	 *
	 * This field holds one of a number of values that communicate the
	 * event that happened to the address.
	 */
	spc->spc_state = state;

	/* Sockets API Extensions for SCTP
	 * Section 5.3.1.2 SCTP_PEER_ADDR_CHANGE
	 *
	 * spc_error:  32 bits (signed integer)
	 *
	 * If the state was reached due to any error condition (e.g.
	 * ADDRESS_UNREACHABLE) any relevant error information is available in
	 * this field.
	 */
	spc->spc_error = error;

	/* Socket Extensions for SCTP
	 * 5.3.1.1 SCTP_ASSOC_CHANGE
	 *
	 * spc_assoc_id: sizeof (sctp_assoc_t)
	 *
	 * The association id field, holds the identifier for the association.
	 * All notifications for a given association have the same association
	 * identifier.  For TCP style socket, this field is ignored.
	 */
	sctp_ulpevent_set_owner(event, asoc);
	spc->spc_assoc_id = sctp_assoc2id(asoc);

	/* Sockets API Extensions for SCTP
	 * Section 5.3.1.2 SCTP_PEER_ADDR_CHANGE
	 *
	 * spc_aaddr: sizeof (struct sockaddr_storage)
	 *
	 * The affected address field, holds the remote peer's address that is
	 * encountering the change of state.
	 */
	memcpy(&spc->spc_aaddr, aaddr, sizeof(struct sockaddr_storage));

	/* Map ipv4 address into v4-mapped-on-v6 address.  */
	sctp_get_pf_specific(asoc->base.sk->sk_family)->addr_v4map(
					sctp_sk(asoc->base.sk),
					(union sctp_addr *)&spc->spc_aaddr);

	return event;

fail:
	return NULL;
}
Example #2
0
/* Create and initialize an SCTP_ASSOC_CHANGE event.
 *
 * 5.3.1.1 SCTP_ASSOC_CHANGE
 *
 * Communication notifications inform the ULP that an SCTP association
 * has either begun or ended. The identifier for a new association is
 * provided by this notification.
 *
 * Note: There is no field checking here.  If a field is unused it will be
 * zero'd out.
 */
struct sctp_ulpevent  *sctp_ulpevent_make_assoc_change(
	const struct sctp_association *asoc,
	__u16 flags, __u16 state, __u16 error, __u16 outbound,
	__u16 inbound, struct sctp_chunk *chunk, gfp_t gfp)
{
	struct sctp_ulpevent *event;
	struct sctp_assoc_change *sac;
	struct sk_buff *skb;

	/* If the lower layer passed in the chunk, it will be
	 * an ABORT, so we need to include it in the sac_info.
	 */
	if (chunk) {
		/* Copy the chunk data to a new skb and reserve enough
		 * head room to use as notification.
		 */
		skb = skb_copy_expand(chunk->skb,
				      sizeof(struct sctp_assoc_change), 0, gfp);

		if (!skb)
			goto fail;

		/* Embed the event fields inside the cloned skb.  */
		event = sctp_skb2event(skb);
		sctp_ulpevent_init(event, MSG_NOTIFICATION, skb->truesize);

		/* Include the notification structure */
		sac = (struct sctp_assoc_change *)
			skb_push(skb, sizeof(struct sctp_assoc_change));

		/* Trim the buffer to the right length.  */
		skb_trim(skb, sizeof(struct sctp_assoc_change) +
			 ntohs(chunk->chunk_hdr->length) -
			 sizeof(sctp_chunkhdr_t));
	} else {
		event = sctp_ulpevent_new(sizeof(struct sctp_assoc_change),
				  MSG_NOTIFICATION, gfp);
		if (!event)
			goto fail;

		skb = sctp_event2skb(event);
		sac = (struct sctp_assoc_change *) skb_put(skb,
					sizeof(struct sctp_assoc_change));
	}

	/* Socket Extensions for SCTP
	 * 5.3.1.1 SCTP_ASSOC_CHANGE
	 *
	 * sac_type:
	 * It should be SCTP_ASSOC_CHANGE.
	 */
	sac->sac_type = SCTP_ASSOC_CHANGE;

	/* Socket Extensions for SCTP
	 * 5.3.1.1 SCTP_ASSOC_CHANGE
	 *
	 * sac_state: 32 bits (signed integer)
	 * This field holds one of a number of values that communicate the
	 * event that happened to the association.
	 */
	sac->sac_state = state;

	/* Socket Extensions for SCTP
	 * 5.3.1.1 SCTP_ASSOC_CHANGE
	 *
	 * sac_flags: 16 bits (unsigned integer)
	 * Currently unused.
	 */
	sac->sac_flags = 0;

	/* Socket Extensions for SCTP
	 * 5.3.1.1 SCTP_ASSOC_CHANGE
	 *
	 * sac_length: sizeof (__u32)
	 * This field is the total length of the notification data, including
	 * the notification header.
	 */
	sac->sac_length = skb->len;

	/* Socket Extensions for SCTP
	 * 5.3.1.1 SCTP_ASSOC_CHANGE
	 *
	 * sac_error:  32 bits (signed integer)
	 *
	 * If the state was reached due to a error condition (e.g.
	 * COMMUNICATION_LOST) any relevant error information is available in
	 * this field. This corresponds to the protocol error codes defined in
	 * [SCTP].
	 */
	sac->sac_error = error;

	/* Socket Extensions for SCTP
	 * 5.3.1.1 SCTP_ASSOC_CHANGE
	 *
	 * sac_outbound_streams:  16 bits (unsigned integer)
	 * sac_inbound_streams:  16 bits (unsigned integer)
	 *
	 * The maximum number of streams allowed in each direction are
	 * available in sac_outbound_streams and sac_inbound streams.
	 */
	sac->sac_outbound_streams = outbound;
	sac->sac_inbound_streams = inbound;

	/* Socket Extensions for SCTP
	 * 5.3.1.1 SCTP_ASSOC_CHANGE
	 *
	 * sac_assoc_id: sizeof (sctp_assoc_t)
	 *
	 * The association id field, holds the identifier for the association.
	 * All notifications for a given association have the same association
	 * identifier.  For TCP style socket, this field is ignored.
	 */
	sctp_ulpevent_set_owner(event, asoc);
	sac->sac_assoc_id = sctp_assoc2id(asoc);

	return event;

fail:
	return NULL;
}
Example #3
0
/* Create and initialize a SCTP_SEND_FAILED notification.
 *
 * Socket Extensions for SCTP - draft-01
 * 5.3.1.4 SCTP_SEND_FAILED
 */
struct sctp_ulpevent *sctp_ulpevent_make_send_failed(
    const struct sctp_association *asoc, struct sctp_chunk *chunk,
    __u16 flags, __u32 error, gfp_t gfp)
{
    struct sctp_ulpevent *event;
    struct sctp_send_failed *ssf;
    struct sk_buff *skb;

    /* Pull off any padding. */
    int len = ntohs(chunk->chunk_hdr->length);

    /* Make skb with more room so we can prepend notification.  */
    skb = skb_copy_expand(chunk->skb,
                          sizeof(struct sctp_send_failed), /* headroom */
                          0,                               /* tailroom */
                          gfp);
    if (!skb)
        goto fail;

    /* Pull off the common chunk header and DATA header.  */
    skb_pull(skb, sizeof(struct sctp_data_chunk));
    len -= sizeof(struct sctp_data_chunk);

    /* Embed the event fields inside the cloned skb.  */
    event = sctp_skb2event(skb);
    sctp_ulpevent_init(event, MSG_NOTIFICATION, skb->truesize);

    ssf = (struct sctp_send_failed *)
          skb_push(skb, sizeof(struct sctp_send_failed));

    /* Socket Extensions for SCTP
     * 5.3.1.4 SCTP_SEND_FAILED
     *
     * ssf_type:
     * It should be SCTP_SEND_FAILED.
     */
    ssf->ssf_type = SCTP_SEND_FAILED;

    /* Socket Extensions for SCTP
     * 5.3.1.4 SCTP_SEND_FAILED
     *
     * ssf_flags: 16 bits (unsigned integer)
     * The flag value will take one of the following values
     *
     * SCTP_DATA_UNSENT - Indicates that the data was never put on
     *                    the wire.
     *
     * SCTP_DATA_SENT   - Indicates that the data was put on the wire.
     *                    Note that this does not necessarily mean that the
     *                    data was (or was not) successfully delivered.
     */
    ssf->ssf_flags = flags;

    /* Socket Extensions for SCTP
     * 5.3.1.4 SCTP_SEND_FAILED
     *
     * ssf_length: sizeof (__u32)
     * This field is the total length of the notification data, including
     * the notification header.
     */
    ssf->ssf_length = sizeof(struct sctp_send_failed) + len;
    skb_trim(skb, ssf->ssf_length);

    /* Socket Extensions for SCTP
     * 5.3.1.4 SCTP_SEND_FAILED
     *
     * ssf_error: 16 bits (unsigned integer)
     * This value represents the reason why the send failed, and if set,
     * will be a SCTP protocol error code as defined in [SCTP] section
     * 3.3.10.
     */
    ssf->ssf_error = error;

    /* Socket Extensions for SCTP
     * 5.3.1.4 SCTP_SEND_FAILED
     *
     * ssf_info: sizeof (struct sctp_sndrcvinfo)
     * The original send information associated with the undelivered
     * message.
     */
    memcpy(&ssf->ssf_info, &chunk->sinfo, sizeof(struct sctp_sndrcvinfo));

    /* Per TSVWG discussion with Randy. Allow the application to
     * reassemble a fragmented message.
     */
    ssf->ssf_info.sinfo_flags = chunk->chunk_hdr->flags;

    /* Socket Extensions for SCTP
     * 5.3.1.4 SCTP_SEND_FAILED
     *
     * ssf_assoc_id: sizeof (sctp_assoc_t)
     * The association id field, sf_assoc_id, holds the identifier for the
     * association.  All notifications for a given association have the
     * same association identifier.  For TCP style socket, this field is
     * ignored.
     */
    sctp_ulpevent_set_owner(event, asoc);
    ssf->ssf_assoc_id = sctp_assoc2id(asoc);
    return event;

fail:
    return NULL;
}
Example #4
0
/* Copy out the sndrcvinfo into a msghdr.  */
void sctp_ulpevent_read_sndrcvinfo(const struct sctp_ulpevent *event,
                                   struct msghdr *msghdr)
{
    struct sctp_sndrcvinfo sinfo;

    if (sctp_ulpevent_is_notification(event))
        return;

    /* Sockets API Extensions for SCTP
     * Section 5.2.2 SCTP Header Information Structure (SCTP_SNDRCV)
     *
     * sinfo_stream: 16 bits (unsigned integer)
     *
     * For recvmsg() the SCTP stack places the message's stream number in
     * this value.
    */
    sinfo.sinfo_stream = event->stream;
    /* sinfo_ssn: 16 bits (unsigned integer)
     *
     * For recvmsg() this value contains the stream sequence number that
     * the remote endpoint placed in the DATA chunk.  For fragmented
     * messages this is the same number for all deliveries of the message
     * (if more than one recvmsg() is needed to read the message).
     */
    sinfo.sinfo_ssn = event->ssn;
    /* sinfo_ppid: 32 bits (unsigned integer)
     *
     * In recvmsg() this value is
     * the same information that was passed by the upper layer in the peer
     * application.  Please note that byte order issues are NOT accounted
     * for and this information is passed opaquely by the SCTP stack from
     * one end to the other.
     */
    sinfo.sinfo_ppid = event->ppid;
    /* sinfo_flags: 16 bits (unsigned integer)
     *
     * This field may contain any of the following flags and is composed of
     * a bitwise OR of these values.
     *
     * recvmsg() flags:
     *
     * SCTP_UNORDERED - This flag is present when the message was sent
     *                 non-ordered.
     */
    sinfo.sinfo_flags = event->flags;
    /* sinfo_tsn: 32 bit (unsigned integer)
     *
     * For the receiving side, this field holds a TSN that was
     * assigned to one of the SCTP Data Chunks.
     */
    sinfo.sinfo_tsn = event->tsn;
    /* sinfo_cumtsn: 32 bit (unsigned integer)
     *
     * This field will hold the current cumulative TSN as
     * known by the underlying SCTP layer.  Note this field is
     * ignored when sending and only valid for a receive
     * operation when sinfo_flags are set to SCTP_UNORDERED.
     */
    sinfo.sinfo_cumtsn = event->cumtsn;
    /* sinfo_assoc_id: sizeof (sctp_assoc_t)
     *
     * The association handle field, sinfo_assoc_id, holds the identifier
     * for the association announced in the COMMUNICATION_UP notification.
     * All notifications for a given association have the same identifier.
     * Ignored for one-to-one style sockets.
     */
    sinfo.sinfo_assoc_id = sctp_assoc2id(event->asoc);

    /* context value that is set via SCTP_CONTEXT socket option. */
    sinfo.sinfo_context = event->asoc->default_rcv_context;

    /* These fields are not used while receiving. */
    sinfo.sinfo_timetolive = 0;

    put_cmsg(msghdr, IPPROTO_SCTP, SCTP_SNDRCV,
             sizeof(struct sctp_sndrcvinfo), (void *)&sinfo);
}
Example #5
0
/* Create and initialize an SCTP_REMOTE_ERROR notification.
 *
 * Note: This assumes that the chunk->skb->data already points to the
 * operation error payload.
 *
 * Socket Extensions for SCTP - draft-01
 * 5.3.1.3 SCTP_REMOTE_ERROR
 *
 * A remote peer may send an Operational Error message to its peer.
 * This message indicates a variety of error conditions on an
 * association. The entire error TLV as it appears on the wire is
 * included in a SCTP_REMOTE_ERROR event.  Please refer to the SCTP
 * specification [SCTP] and any extensions for a list of possible
 * error formats.
 */
struct sctp_ulpevent *sctp_ulpevent_make_remote_error(
    const struct sctp_association *asoc, struct sctp_chunk *chunk,
    __u16 flags, gfp_t gfp)
{
    struct sctp_ulpevent *event;
    struct sctp_remote_error *sre;
    struct sk_buff *skb;
    sctp_errhdr_t *ch;
    __be16 cause;
    int elen;

    ch = (sctp_errhdr_t *)(chunk->skb->data);
    cause = ch->cause;
    elen = WORD_ROUND(ntohs(ch->length)) - sizeof(sctp_errhdr_t);

    /* Pull off the ERROR header.  */
    skb_pull(chunk->skb, sizeof(sctp_errhdr_t));

    /* Copy the skb to a new skb with room for us to prepend
     * notification with.
     */
    skb = skb_copy_expand(chunk->skb, sizeof(struct sctp_remote_error),
                          0, gfp);

    /* Pull off the rest of the cause TLV from the chunk.  */
    skb_pull(chunk->skb, elen);
    if (!skb)
        goto fail;

    /* Embed the event fields inside the cloned skb.  */
    event = sctp_skb2event(skb);
    sctp_ulpevent_init(event, MSG_NOTIFICATION, skb->truesize);

    sre = (struct sctp_remote_error *)
          skb_push(skb, sizeof(struct sctp_remote_error));

    /* Trim the buffer to the right length.  */
    skb_trim(skb, sizeof(struct sctp_remote_error) + elen);

    /* Socket Extensions for SCTP
     * 5.3.1.3 SCTP_REMOTE_ERROR
     *
     * sre_type:
     *   It should be SCTP_REMOTE_ERROR.
     */
    sre->sre_type = SCTP_REMOTE_ERROR;

    /*
     * Socket Extensions for SCTP
     * 5.3.1.3 SCTP_REMOTE_ERROR
     *
     * sre_flags: 16 bits (unsigned integer)
     *   Currently unused.
     */
    sre->sre_flags = 0;

    /* Socket Extensions for SCTP
     * 5.3.1.3 SCTP_REMOTE_ERROR
     *
     * sre_length: sizeof (__u32)
     *
     * This field is the total length of the notification data,
     * including the notification header.
     */
    sre->sre_length = skb->len;

    /* Socket Extensions for SCTP
     * 5.3.1.3 SCTP_REMOTE_ERROR
     *
     * sre_error: 16 bits (unsigned integer)
     * This value represents one of the Operational Error causes defined in
     * the SCTP specification, in network byte order.
     */
    sre->sre_error = cause;

    /* Socket Extensions for SCTP
     * 5.3.1.3 SCTP_REMOTE_ERROR
     *
     * sre_assoc_id: sizeof (sctp_assoc_t)
     *
     * The association id field, holds the identifier for the association.
     * All notifications for a given association have the same association
     * identifier.  For TCP style socket, this field is ignored.
     */
    sctp_ulpevent_set_owner(event, asoc);
    sre->sre_assoc_id = sctp_assoc2id(asoc);

    return event;

fail:
    return NULL;
}