📄 sm_make_chunk.c
字号:
sg.offset = (unsigned long)(&cookie->c) % PAGE_SIZE; sg.length = bodysize; keylen = SCTP_SECRET_SIZE; key = (char *)ep->secret_key[ep->current_key]; sctp_crypto_hmac(sctp_sk(ep->base.sk)->hmac, key, &keylen, &sg, 1, cookie->signature); }nodata: return retval;}/* Unpack the cookie from COOKIE ECHO chunk, recreating the association. */struct sctp_association *sctp_unpack_cookie( const struct sctp_endpoint *ep, const struct sctp_association *asoc, struct sctp_chunk *chunk, int gfp, int *error, struct sctp_chunk **errp){ struct sctp_association *retval = NULL; struct sctp_signed_cookie *cookie; struct sctp_cookie *bear_cookie; int headersize, bodysize, fixed_size; __u8 digest[SCTP_SIGNATURE_SIZE]; struct scatterlist sg; unsigned int keylen, len; char *key; sctp_scope_t scope; struct sk_buff *skb = chunk->skb; headersize = sizeof(sctp_chunkhdr_t) + SCTP_SECRET_SIZE; bodysize = ntohs(chunk->chunk_hdr->length) - headersize; fixed_size = headersize + sizeof(struct sctp_cookie); /* Verify that the chunk looks like it even has a cookie. * There must be enough room for our cookie and our peer's * INIT chunk. */ len = ntohs(chunk->chunk_hdr->length); if (len < fixed_size + sizeof(struct sctp_chunkhdr)) goto malformed; /* Verify that the cookie has been padded out. */ if (bodysize % SCTP_COOKIE_MULTIPLE) goto malformed; /* Process the cookie. */ cookie = chunk->subh.cookie_hdr; bear_cookie = &cookie->c; if (!sctp_sk(ep->base.sk)->hmac) goto no_hmac; /* Check the signature. */ keylen = SCTP_SECRET_SIZE; sg.page = virt_to_page(bear_cookie); sg.offset = (unsigned long)(bear_cookie) % PAGE_SIZE; sg.length = bodysize; key = (char *)ep->secret_key[ep->current_key]; memset(digest, 0x00, sizeof(digest)); sctp_crypto_hmac(sctp_sk(ep->base.sk)->hmac, key, &keylen, &sg, 1, digest); if (memcmp(digest, cookie->signature, SCTP_SIGNATURE_SIZE)) { /* Try the previous key. */ key = (char *)ep->secret_key[ep->last_key]; memset(digest, 0x00, sizeof(digest)); sctp_crypto_hmac(sctp_sk(ep->base.sk)->hmac, key, &keylen, &sg, 1, digest); if (memcmp(digest, cookie->signature, SCTP_SIGNATURE_SIZE)) { /* Yikes! Still bad signature! */ *error = -SCTP_IERROR_BAD_SIG; goto fail; } }no_hmac: /* Check to see if the cookie is stale. If there is already * an association, there is no need to check cookie's expiration * for init collision case of lost COOKIE ACK. */ if (!asoc && tv_lt(bear_cookie->expiration, skb->stamp)) { __u16 len; /* * Section 3.3.10.3 Stale Cookie Error (3) * * Cause of error * --------------- * Stale Cookie Error: Indicates the receipt of a valid State * Cookie that has expired. */ len = ntohs(chunk->chunk_hdr->length); *errp = sctp_make_op_error_space(asoc, chunk, len); if (*errp) { suseconds_t usecs = (skb->stamp.tv_sec - bear_cookie->expiration.tv_sec) * 1000000L + skb->stamp.tv_usec - bear_cookie->expiration.tv_usec; usecs = htonl(usecs); sctp_init_cause(*errp, SCTP_ERROR_STALE_COOKIE, &usecs, sizeof(usecs)); *error = -SCTP_IERROR_STALE_COOKIE; } else *error = -SCTP_IERROR_NOMEM; goto fail; } /* Make a new base association. */ scope = sctp_scope(sctp_source(chunk)); retval = sctp_association_new(ep, ep->base.sk, scope, gfp); if (!retval) { *error = -SCTP_IERROR_NOMEM; goto fail; } /* Set up our peer's port number. */ retval->peer.port = ntohs(chunk->sctp_hdr->source); /* Populate the association from the cookie. */ memcpy(&retval->c, bear_cookie, sizeof(*bear_cookie)); if (sctp_assoc_set_bind_addr_from_cookie(retval, bear_cookie, GFP_ATOMIC) < 0) { *error = -SCTP_IERROR_NOMEM; goto fail; } /* Also, add the destination address. */ if (list_empty(&retval->base.bind_addr.address_list)) { sctp_add_bind_addr(&retval->base.bind_addr, &chunk->dest, GFP_ATOMIC); } retval->next_tsn = retval->c.initial_tsn; retval->ctsn_ack_point = retval->next_tsn - 1; retval->addip_serial = retval->c.initial_tsn; retval->adv_peer_ack_point = retval->ctsn_ack_point; retval->peer.prsctp_capable = retval->c.prsctp_capable; /* The INIT stuff will be done by the side effects. */ return retval;fail: if (retval) sctp_association_free(retval); return NULL;malformed: /* Yikes! The packet is either corrupt or deliberately * malformed. */ *error = -SCTP_IERROR_MALFORMED; goto fail;}/******************************************************************** * 3rd Level Abstractions ********************************************************************/struct __sctp_missing { __u32 num_missing; __u16 type;} __attribute__((packed));/* * Report a missing mandatory parameter. */static int sctp_process_missing_param(const struct sctp_association *asoc, sctp_param_t paramtype, struct sctp_chunk *chunk, struct sctp_chunk **errp){ struct __sctp_missing report; __u16 len; len = WORD_ROUND(sizeof(report)); /* Make an ERROR chunk, preparing enough room for * returning multiple unknown parameters. */ if (!*errp) *errp = sctp_make_op_error_space(asoc, chunk, len); if (*errp) { report.num_missing = htonl(1); report.type = paramtype; sctp_init_cause(*errp, SCTP_ERROR_INV_PARAM, &report, sizeof(report)); } /* Stop processing this chunk. */ return 0;}/* Report an Invalid Mandatory Parameter. */static int sctp_process_inv_mandatory(const struct sctp_association *asoc, struct sctp_chunk *chunk, struct sctp_chunk **errp){ /* Invalid Mandatory Parameter Error has no payload. */ if (!*errp) *errp = sctp_make_op_error_space(asoc, chunk, 0); if (*errp) sctp_init_cause(*errp, SCTP_ERROR_INV_PARAM, NULL, 0); /* Stop processing this chunk. */ return 0;}/* Do not attempt to handle the HOST_NAME parm. However, do * send back an indicator to the peer. */static int sctp_process_hn_param(const struct sctp_association *asoc, union sctp_params param, struct sctp_chunk *chunk, struct sctp_chunk **errp){ __u16 len = ntohs(param.p->length); /* Make an ERROR chunk. */ if (!*errp) *errp = sctp_make_op_error_space(asoc, chunk, len); if (*errp) sctp_init_cause(*errp, SCTP_ERROR_DNS_FAILED, param.v, len); /* Stop processing this chunk. */ return 0;}/* RFC 3.2.1 & the Implementers Guide 2.2. * * The Parameter Types are encoded such that the * highest-order two bits specify the action that must be * taken if the processing endpoint does not recognize the * Parameter Type. * * 00 - Stop processing this SCTP chunk and discard it, * do not process any further chunks within it. * * 01 - Stop processing this SCTP chunk and discard it, * do not process any further chunks within it, and report * the unrecognized parameter in an 'Unrecognized * Parameter Type' (in either an ERROR or in the INIT ACK). * * 10 - Skip this parameter and continue processing. * * 11 - Skip this parameter and continue processing but * report the unrecognized parameter in an * 'Unrecognized Parameter Type' (in either an ERROR or in * the INIT ACK). * * Return value: * 0 - discard the chunk * 1 - continue with the chunk */static int sctp_process_unk_param(const struct sctp_association *asoc, union sctp_params param, struct sctp_chunk *chunk, struct sctp_chunk **errp){ int retval = 1; switch (param.p->type & SCTP_PARAM_ACTION_MASK) { case SCTP_PARAM_ACTION_DISCARD: retval = 0; break; case SCTP_PARAM_ACTION_DISCARD_ERR: retval = 0; /* Make an ERROR chunk, preparing enough room for * returning multiple unknown parameters. */ if (NULL == *errp) *errp = sctp_make_op_error_space(asoc, chunk, ntohs(chunk->chunk_hdr->length)); if (*errp) sctp_init_cause(*errp, SCTP_ERROR_UNKNOWN_PARAM, param.v, WORD_ROUND(ntohs(param.p->length))); break; case SCTP_PARAM_ACTION_SKIP: break; case SCTP_PARAM_ACTION_SKIP_ERR: /* Make an ERROR chunk, preparing enough room for * returning multiple unknown parameters. */ if (NULL == *errp) *errp = sctp_make_op_error_space(asoc, chunk, ntohs(chunk->chunk_hdr->length)); if (*errp) { sctp_init_cause(*errp, SCTP_ERROR_UNKNOWN_PARAM, param.v, WORD_ROUND(ntohs(param.p->length))); } else { /* If there is no memory for generating the ERROR * report as specified, an ABORT will be triggered * to the peer and the association won't be * established. */ retval = 0; } break; default: break; } return retval;}/* Find unrecognized parameters in the chunk. * Return values: * 0 - discard the chunk * 1 - continue with the chunk */static int sctp_verify_param(const struct sctp_association *asoc, union sctp_params param, sctp_cid_t cid, struct sctp_chunk *chunk, struct sctp_chunk **err_chunk){ int retval = 1; /* FIXME - This routine is not looking at each parameter per the * chunk type, i.e., unrecognized parameters should be further * identified based on the chunk id. */ switch (param.p->type) { case SCTP_PARAM_IPV4_ADDRESS: case SCTP_PARAM_IPV6_ADDRESS: case SCTP_PARAM_COOKIE_PRESERVATIVE: case SCTP_PARAM_SUPPORTED_ADDRESS_TYPES: case SCTP_PARAM_STATE_COOKIE: case SCTP_PARAM_HEARTBEAT_INFO: case SCTP_PARAM_UNRECOGNIZED_PARAMETERS: case SCTP_PARAM_ECN_CAPABLE: break; case SCTP_PARAM_HOST_NAME_ADDRESS: /* Tell the peer, we won't support this param. */ return sctp_process_hn_param(asoc, param, chunk, err_chunk); case SCTP_PARAM_FWD_TSN_SUPPORT: if (sctp_prsctp_enable) break; /* Fall Through */ default: SCTP_DEBUG_PRINTK("Unrecognized param: %d for chunk %d.\n", ntohs(param.p->type), cid); return sctp_process_unk_param(asoc, param, chunk, err_chunk); break; } return retval;}/* Verify the INIT packet before we process it. */int sctp_verify_init(const struct sctp_association *asoc, sctp_cid_t cid, sctp_init_chunk_t *peer_init, struct sctp_chunk *chunk, struct sctp_chunk **errp){ union sctp_params param; int has_cookie = 0; /* Verify stream values are non-zero. */ if ((0 == peer_init->init_hdr.num_outbound_streams) || (0 == peer_init->init_hdr.num_inbound_streams)) { sctp_process_inv_mandatory(asoc, chunk, errp); return 0; } /* Check for missing mandatory parameters. */ sctp_walk_params(param, peer_init, init_hdr.params) { if (SCTP_PARAM_STATE_COOKIE == param.p->type) has_cookie = 1; } /* for (loop through all parameters) */ /* The only missing mandatory param possible today is * the state cookie for an INIT-ACK chunk. */ if ((SCTP_CID_INIT_ACK == cid) && !has_cookie) { sctp_process_missing_param(asoc, SCTP_PARAM_STATE_COOKIE, chunk, errp); return 0; } /* Find unrecognized parameters. */ sctp_walk_params(param, peer_init, init_hdr.params) { if (!sctp_verify_param(asoc, param, cid, chunk, errp)) { if (SCTP_PARAM_HOST_NAME_ADDRESS == param.p->type) return 0; else return 1; } } /* for (loop through all parameters) */ return 1;}/* Unpack the parameters in an INIT packet into an association. * Returns 0 on failure, else success. * FIXME: This is an association method. */int sctp_process_init(struct sctp_association *asoc, sctp_cid_t cid, const union sctp_addr *peer_addr, sctp_init_chunk_t *peer_init, int gfp){ union sctp_params param; struct sctp_transport *transport; struct list_head *pos, *temp; char *cookie; /* We must include the address that the INIT packet came from. * This is the only address that matters for an INIT packet. * When processing a COOKIE ECHO, we retrieve the from address * of the INIT from the cookie. */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -