/** Parse an EXTENDED or EXTENDED2 cell (according to <b>command</b>) from the * <b>payload_length</b> bytes of <b>payload</b> into <b>cell_out</b>. Return * 0 on success, -1 on failure. */ int extended_cell_parse(extended_cell_t *cell_out, const uint8_t command, const uint8_t *payload, size_t payload_len) { tor_assert(cell_out); tor_assert(payload); memset(cell_out, 0, sizeof(*cell_out)); if (payload_len > RELAY_PAYLOAD_SIZE) return -1; switch (command) { case RELAY_COMMAND_EXTENDED: if (payload_len != TAP_ONIONSKIN_REPLY_LEN) return -1; cell_out->cell_type = RELAY_COMMAND_EXTENDED; cell_out->created_cell.cell_type = CELL_CREATED; cell_out->created_cell.handshake_len = TAP_ONIONSKIN_REPLY_LEN; memcpy(cell_out->created_cell.reply, payload, TAP_ONIONSKIN_REPLY_LEN); break; case RELAY_COMMAND_EXTENDED2: { cell_out->cell_type = RELAY_COMMAND_EXTENDED2; cell_out->created_cell.cell_type = CELL_CREATED2; cell_out->created_cell.handshake_len = ntohs(get_uint16(payload)); if (cell_out->created_cell.handshake_len > RELAY_PAYLOAD_SIZE - 2 || cell_out->created_cell.handshake_len > payload_len - 2) return -1; memcpy(cell_out->created_cell.reply, payload+2, cell_out->created_cell.handshake_len); } break; default: return -1; } return check_extended_cell(cell_out); }
/** Format the EXTENDED{,2} cell in <b>cell_in</b>, storing its relay payload * in <b>payload_out</b>, the number of bytes used in *<b>len_out</b>, and the * relay command in *<b>command_out</b>. The <b>payload_out</b> must have * RELAY_PAYLOAD_SIZE bytes available. Return 0 on success, -1 on failure. */ int extended_cell_format(uint8_t *command_out, uint16_t *len_out, uint8_t *payload_out, const extended_cell_t *cell_in) { uint8_t *p; if (check_extended_cell(cell_in) < 0) return -1; p = payload_out; memset(p, 0, RELAY_PAYLOAD_SIZE); switch (cell_in->cell_type) { case RELAY_COMMAND_EXTENDED: { *command_out = RELAY_COMMAND_EXTENDED; *len_out = TAP_ONIONSKIN_REPLY_LEN; memcpy(payload_out, cell_in->created_cell.reply, TAP_ONIONSKIN_REPLY_LEN); } break; case RELAY_COMMAND_EXTENDED2: { *command_out = RELAY_COMMAND_EXTENDED2; *len_out = 2 + cell_in->created_cell.handshake_len; set_uint16(payload_out, htons(cell_in->created_cell.handshake_len)); if (2+cell_in->created_cell.handshake_len > RELAY_PAYLOAD_SIZE) return -1; memcpy(payload_out+2, cell_in->created_cell.reply, cell_in->created_cell.handshake_len); } break; default: return -1; } return 0; }