📄 sm_make_chunk.c
字号:
if (!retval) goto nodata; /* Cast away the 'const', as this is just telling the chunk * what transport it belongs to. */ retval->transport = (struct sctp_transport *) transport; retval->subh.hbs_hdr = sctp_addto_chunk(retval, paylen, payload);nodata: return retval;}struct sctp_chunk *sctp_make_heartbeat_ack(const struct sctp_association *asoc, const struct sctp_chunk *chunk, const void *payload, const size_t paylen){ struct sctp_chunk *retval; retval = sctp_make_chunk(asoc, SCTP_CID_HEARTBEAT_ACK, 0, paylen); if (!retval) goto nodata; retval->subh.hbs_hdr = sctp_addto_chunk(retval, paylen, payload); /* RFC 2960 6.4 Multi-homed SCTP Endpoints * * An endpoint SHOULD transmit reply chunks (e.g., SACK, * HEARTBEAT ACK, * etc.) to the same destination transport * address from which it * received the DATA or control chunk * to which it is replying. * * [HBACK back to where the HEARTBEAT came from.] */ if (chunk) retval->transport = chunk->transport;nodata: return retval;}/* Create an Operation Error chunk with the specified space reserved. * This routine can be used for containing multiple causes in the chunk. */struct sctp_chunk *sctp_make_op_error_space( const struct sctp_association *asoc, const struct sctp_chunk *chunk, size_t size){ struct sctp_chunk *retval; retval = sctp_make_chunk(asoc, SCTP_CID_ERROR, 0, sizeof(sctp_errhdr_t) + size); if (!retval) goto nodata; /* RFC 2960 6.4 Multi-homed SCTP Endpoints * * An endpoint SHOULD transmit reply chunks (e.g., SACK, * HEARTBEAT ACK, etc.) to the same destination transport * address from which it received the DATA or control chunk * to which it is replying. * */ if (chunk) retval->transport = chunk->transport;nodata: return retval;}/* Create an Operation Error chunk. */struct sctp_chunk *sctp_make_op_error(const struct sctp_association *asoc, const struct sctp_chunk *chunk, __u16 cause_code, const void *payload, size_t paylen){ struct sctp_chunk *retval; retval = sctp_make_op_error_space(asoc, chunk, paylen); if (!retval) goto nodata; sctp_init_cause(retval, cause_code, payload, paylen);nodata: return retval;}/******************************************************************** * 2nd Level Abstractions ********************************************************************//* Turn an skb into a chunk. * FIXME: Eventually move the structure directly inside the skb->cb[]. */struct sctp_chunk *sctp_chunkify(struct sk_buff *skb, const struct sctp_association *asoc, struct sock *sk){ struct sctp_chunk *retval; retval = kmem_cache_alloc(sctp_chunk_cachep, SLAB_ATOMIC); if (!retval) goto nodata; memset(retval, 0, sizeof(struct sctp_chunk)); if (!sk) { SCTP_DEBUG_PRINTK("chunkifying skb %p w/o an sk\n", skb); } retval->skb = skb; retval->asoc = (struct sctp_association *)asoc; retval->resent = 0; retval->has_tsn = 0; retval->has_ssn = 0; retval->rtt_in_progress = 0; retval->sent_at = 0; retval->singleton = 1; retval->end_of_packet = 0; retval->ecn_ce_done = 0; retval->pdiscard = 0; /* sctpimpguide-05.txt Section 2.8.2 * M1) Each time a new DATA chunk is transmitted * set the 'TSN.Missing.Report' count for that TSN to 0. The * 'TSN.Missing.Report' count will be used to determine missing chunks * and when to fast retransmit. */ retval->tsn_missing_report = 0; retval->tsn_gap_acked = 0; retval->fast_retransmit = 0; /* If this is a fragmented message, track all fragments * of the message (for SEND_FAILED). */ retval->msg = NULL; /* Polish the bead hole. */ INIT_LIST_HEAD(&retval->transmitted_list); INIT_LIST_HEAD(&retval->frag_list); SCTP_DBG_OBJCNT_INC(chunk); atomic_set(&retval->refcnt, 1);nodata: return retval;}/* Set chunk->source and dest based on the IP header in chunk->skb. */void sctp_init_addrs(struct sctp_chunk *chunk, union sctp_addr *src, union sctp_addr *dest){ memcpy(&chunk->source, src, sizeof(union sctp_addr)); memcpy(&chunk->dest, dest, sizeof(union sctp_addr));}/* Extract the source address from a chunk. */const union sctp_addr *sctp_source(const struct sctp_chunk *chunk){ /* If we have a known transport, use that. */ if (chunk->transport) { return &chunk->transport->ipaddr; } else { /* Otherwise, extract it from the IP header. */ return &chunk->source; }}/* Create a new chunk, setting the type and flags headers from the * arguments, reserving enough space for a 'paylen' byte payload. */struct sctp_chunk *sctp_make_chunk(const struct sctp_association *asoc, __u8 type, __u8 flags, int paylen){ struct sctp_chunk *retval; sctp_chunkhdr_t *chunk_hdr; struct sk_buff *skb; struct sock *sk; /* No need to allocate LL here, as this is only a chunk. */ skb = alloc_skb(WORD_ROUND(sizeof(sctp_chunkhdr_t) + paylen), GFP_ATOMIC); if (!skb) goto nodata; /* Make room for the chunk header. */ chunk_hdr = (sctp_chunkhdr_t *)skb_put(skb, sizeof(sctp_chunkhdr_t)); chunk_hdr->type = type; chunk_hdr->flags = flags; chunk_hdr->length = htons(sizeof(sctp_chunkhdr_t)); sk = asoc ? asoc->base.sk : NULL; retval = sctp_chunkify(skb, asoc, sk); if (!retval) { kfree_skb(skb); goto nodata; } retval->chunk_hdr = chunk_hdr; retval->chunk_end = ((__u8 *)chunk_hdr) + sizeof(struct sctp_chunkhdr); /* Set the skb to the belonging sock for accounting. */ skb->sk = sk; return retval;nodata: return NULL;}/* Release the memory occupied by a chunk. */static void sctp_chunk_destroy(struct sctp_chunk *chunk){ /* Free the chunk skb data and the SCTP_chunk stub itself. */ dev_kfree_skb(chunk->skb); SCTP_DBG_OBJCNT_DEC(chunk); kmem_cache_free(sctp_chunk_cachep, chunk);}/* Possibly, free the chunk. */void sctp_chunk_free(struct sctp_chunk *chunk){ /* Make sure that we are not on any list. */ skb_unlink((struct sk_buff *) chunk); list_del_init(&chunk->transmitted_list); /* Release our reference on the message tracker. */ if (chunk->msg) sctp_datamsg_put(chunk->msg); sctp_chunk_put(chunk);}/* Grab a reference to the chunk. */void sctp_chunk_hold(struct sctp_chunk *ch){ atomic_inc(&ch->refcnt);}/* Release a reference to the chunk. */void sctp_chunk_put(struct sctp_chunk *ch){ if (atomic_dec_and_test(&ch->refcnt)) sctp_chunk_destroy(ch);}/* Append bytes to the end of a chunk. Will panic if chunk is not big * enough. */void *sctp_addto_chunk(struct sctp_chunk *chunk, int len, const void *data){ void *target; void *padding; int chunklen = ntohs(chunk->chunk_hdr->length); int padlen = chunklen % 4; padding = skb_put(chunk->skb, padlen); target = skb_put(chunk->skb, len); memset(padding, 0, padlen); memcpy(target, data, len); /* Adjust the chunk length field. */ chunk->chunk_hdr->length = htons(chunklen + padlen + len); chunk->chunk_end = chunk->skb->tail; return target;}/* Append bytes from user space to the end of a chunk. Will panic if * chunk is not big enough. * Returns a kernel err value. */int sctp_user_addto_chunk(struct sctp_chunk *chunk, int off, int len, struct iovec *data){ __u8 *target; int err = 0; /* Make room in chunk for data. */ target = skb_put(chunk->skb, len); /* Copy data (whole iovec) into chunk */ if ((err = memcpy_fromiovecend(target, data, off, len))) goto out; /* Adjust the chunk length field. */ chunk->chunk_hdr->length = htons(ntohs(chunk->chunk_hdr->length) + len); chunk->chunk_end = chunk->skb->tail;out: return err;}/* Helper function to assign a TSN if needed. This assumes that both * the data_hdr and association have already been assigned. */void sctp_chunk_assign_ssn(struct sctp_chunk *chunk){ __u16 ssn; __u16 sid; if (chunk->has_ssn) return; /* This is the last possible instant to assign a SSN. */ if (chunk->chunk_hdr->flags & SCTP_DATA_UNORDERED) { ssn = 0; } else { sid = htons(chunk->subh.data_hdr->stream); if (chunk->chunk_hdr->flags & SCTP_DATA_LAST_FRAG) ssn = sctp_ssn_next(&chunk->asoc->ssnmap->out, sid); else ssn = sctp_ssn_peek(&chunk->asoc->ssnmap->out, sid); ssn = htons(ssn); } chunk->subh.data_hdr->ssn = ssn; chunk->has_ssn = 1;}/* Helper function to assign a TSN if needed. This assumes that both * the data_hdr and association have already been assigned. */void sctp_chunk_assign_tsn(struct sctp_chunk *chunk){ if (!chunk->has_tsn) { /* This is the last possible instant to * assign a TSN. */ chunk->subh.data_hdr->tsn = htonl(sctp_association_get_next_tsn(chunk->asoc)); chunk->has_tsn = 1; }}/* Create a CLOSED association to use with an incoming packet. */struct sctp_association *sctp_make_temp_asoc(const struct sctp_endpoint *ep, struct sctp_chunk *chunk, int gfp){ struct sctp_association *asoc; struct sk_buff *skb; sctp_scope_t scope; struct sctp_af *af; /* Create the bare association. */ scope = sctp_scope(sctp_source(chunk)); asoc = sctp_association_new(ep, ep->base.sk, scope, gfp); if (!asoc) goto nodata; asoc->temp = 1; skb = chunk->skb; /* Create an entry for the source address of the packet. */ af = sctp_get_af_specific(ipver2af(skb->nh.iph->version)); if (unlikely(!af)) goto fail; af->from_skb(&asoc->c.peer_addr, skb, 1);nodata: return asoc;fail: sctp_association_free(asoc); return NULL;}/* Build a cookie representing asoc. * This INCLUDES the param header needed to put the cookie in the INIT ACK. */sctp_cookie_param_t *sctp_pack_cookie(const struct sctp_endpoint *ep, const struct sctp_association *asoc, const struct sctp_chunk *init_chunk, int *cookie_len, const __u8 *raw_addrs, int addrs_len){ sctp_cookie_param_t *retval; struct sctp_signed_cookie *cookie; struct scatterlist sg; int headersize, bodysize; unsigned int keylen; char *key; headersize = sizeof(sctp_paramhdr_t) + SCTP_SECRET_SIZE; bodysize = sizeof(struct sctp_cookie) + ntohs(init_chunk->chunk_hdr->length) + addrs_len; /* Pad out the cookie to a multiple to make the signature * functions simpler to write. */ if (bodysize % SCTP_COOKIE_MULTIPLE) bodysize += SCTP_COOKIE_MULTIPLE - (bodysize % SCTP_COOKIE_MULTIPLE); *cookie_len = headersize + bodysize; retval = (sctp_cookie_param_t *)kmalloc(*cookie_len, GFP_ATOMIC); if (!retval) { *cookie_len = 0; goto nodata; } /* Clear this memory since we are sending this data structure * out on the network. */ memset(retval, 0x00, *cookie_len); cookie = (struct sctp_signed_cookie *) retval->body; /* Set up the parameter header. */ retval->p.type = SCTP_PARAM_STATE_COOKIE; retval->p.length = htons(*cookie_len); /* Copy the cookie part of the association itself. */ cookie->c = asoc->c; /* Save the raw address list length in the cookie. */ cookie->c.raw_addr_list_len = addrs_len; /* Remember PR-SCTP capability. */ cookie->c.prsctp_capable = asoc->peer.prsctp_capable; /* Set an expiration time for the cookie. */ do_gettimeofday(&cookie->c.expiration); TIMEVAL_ADD(asoc->cookie_life, cookie->c.expiration); /* Copy the peer's init packet. */ memcpy(&cookie->c.peer_init[0], init_chunk->chunk_hdr, ntohs(init_chunk->chunk_hdr->length)); /* Copy the raw local address list of the association. */ memcpy((__u8 *)&cookie->c.peer_init[0] + ntohs(init_chunk->chunk_hdr->length), raw_addrs, addrs_len); if (sctp_sk(ep->base.sk)->hmac) { /* Sign the message. */ sg.page = virt_to_page(&cookie->c);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -