Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Two protocol fixes #545

Merged
merged 2 commits into from
Apr 20, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 25 additions & 3 deletions src/device/pf_block_reader.c
Original file line number Diff line number Diff line change
Expand Up @@ -244,8 +244,9 @@ static void pf_get_frame_descriptor (
* @param p_info InOut: The parser state.
* @param p_pos InOut: Position in the buffer.
* @param p_ae Out: Destination buffer.
* @return 0 on success, -1 if out of resources.
*/
static void pf_get_iocr_api_entry (
static int pf_get_iocr_api_entry (
pf_get_info_t * p_info,
uint16_t * p_pos,
pf_api_entry_t * p_ae)
Expand All @@ -255,16 +256,25 @@ static void pf_get_iocr_api_entry (
p_ae->api = pf_get_uint32 (p_info, p_pos);

p_ae->nbr_io_data = pf_get_uint16 (p_info, p_pos);
if (p_ae->nbr_io_data > NELEMENTS (p_ae->io_data))
{
return -1;
}
for (ix = 0; ix < p_ae->nbr_io_data; ix++)
{
pf_get_frame_descriptor (p_info, p_pos, &p_ae->io_data[ix]);
}

p_ae->nbr_iocs = pf_get_uint16 (p_info, p_pos);
if (p_ae->nbr_iocs > NELEMENTS (p_ae->iocs))
{
return -1;
}
for (ix = 0; ix < p_ae->nbr_iocs; ix++)
{
pf_get_frame_descriptor (p_info, p_pos, &p_ae->iocs[ix]);
}
return 0;
}

/**
Expand Down Expand Up @@ -383,7 +393,7 @@ void pf_get_ar_param (pf_get_info_t * p_info, uint16_t * p_pos, pf_ar_t * p_ar)
p_ar->ar_param.cm_initiator_station_name[str_len] = '\0';
}

void pf_get_iocr_param (
int pf_get_iocr_param (
pf_get_info_t * p_info,
uint16_t * p_pos,
uint16_t ix,
Expand Down Expand Up @@ -430,10 +440,22 @@ void pf_get_iocr_param (
&p_ar->iocrs[ix].param.iocr_multicast_mac_add);

p_ar->iocrs[ix].param.nbr_apis = pf_get_uint16 (p_info, p_pos);
if (p_ar->iocrs[ix].param.nbr_apis > PNET_MAX_API)
{
return -1;
}
for (iy = 0; iy < p_ar->iocrs[ix].param.nbr_apis; iy++)
{
pf_get_iocr_api_entry (p_info, p_pos, &p_ar->iocrs[ix].param.apis[iy]);
if (
pf_get_iocr_api_entry (
p_info,
p_pos,
&p_ar->iocrs[ix].param.apis[iy]) != 0)
{
return -1;
}
}
return 0;
}

void pf_get_exp_api_module (
Expand Down
3 changes: 2 additions & 1 deletion src/device/pf_block_reader.h
Original file line number Diff line number Diff line change
Expand Up @@ -109,8 +109,9 @@ void pf_get_ar_param (pf_get_info_t * p_info, uint16_t * p_pos, pf_ar_t * p_ar);
* @param p_pos InOut: Position in the buffer.
* @param ix In: The current index into p_ar->iocr[].
* @param p_ar Out: Contains the destination structure.
* @return 0 on success, -1 if out of resources
*/
void pf_get_iocr_param (
int pf_get_iocr_param (
pf_get_info_t * p_info,
uint16_t * p_pos,
uint16_t ix,
Expand Down
117 changes: 95 additions & 22 deletions src/device/pf_cmrpc.c
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,16 @@
#error "PNET_MAX_SESSION_BUFFER_SIZE must be less than or equal to 65535"
#endif

/* Unless negotiated between server and client, a CL-PDU (header (80 bytes) +
* body) should not be larger than MustRecvFragSize (1464 bytes). This means
* that a CL-PDU body should not be larger than 1384 bytes.
* (See DCE 1.1: RPC, p. 578)
*/
#define PF_CMRPC_MUST_RECV_FRAG_SIZE (1464)
#define PF_CMRPC_PDU_HEADER_SIZE (80)
#define PF_CMRPC_MAX_PDU_BODY_SIZE \
(PF_CMRPC_MUST_RECV_FRAG_SIZE - PF_CMRPC_PDU_HEADER_SIZE)

static const pf_uuid_t implicit_ar = {0, 0, 0, {0, 0, 0, 0, 0, 0, 0, 0}};

static const pf_uuid_t uuid_epmap_interface = {
Expand Down Expand Up @@ -1255,16 +1265,47 @@ static int pf_cmrpc_rm_connect_interpret_ind (
}
break;
case PF_BT_IOCR_BLOCK_REQ:
if (p_ar->nbr_iocrs < PNET_MAX_CR)
if (!(p_ar->nbr_iocrs < PNET_MAX_CR))
{
/* Before it is incremented at the end of this block, the
p_ar->nbr_iocrs value is the same as CREP */
LOG_ERROR (
PF_RPC_LOG,
"CMRPC(%d): Too many CR given. Max %u CR per AR supported\n",
__LINE__,
PNET_MAX_CR);
pf_set_error (
&p_sess->rpc_result,
PNET_ERROR_CODE_CONNECT,
PNET_ERROR_DECODE_PNIO,
PNET_ERROR_CODE_1_CMRPC,
PNET_ERROR_CODE_2_CMRPC_WRONG_BLOCK_COUNT);
ret = -1;
}
else if (
pf_get_iocr_param (
&p_sess->get_info,
p_pos,
p_ar->nbr_iocrs,
p_ar);

p_ar) != 0)
{
LOG_ERROR (
PF_RPC_LOG,
"CMRPC(%d): Too many CR resources requested."
" Check that the controller (PLC) does not request more"
" modules or submodules than P-Net has been configured"
" to support.\n",
__LINE__);
pf_set_error (
&p_sess->rpc_result,
PNET_ERROR_CODE_CONNECT,
PNET_ERROR_DECODE_PNIO,
PNET_ERROR_CODE_1_CMRPC,
PNET_ERROR_CODE_2_CMRPC_OUT_OF_PCA_RESOURCES);
ret = -1;
}
else
{
/* Before it is incremented at the end of this block, the
p_ar->nbr_iocrs value is the same as CREP */
LOG_DEBUG (
PF_RPC_LOG,
"CMRPC(%d): Requested send cycle time: %u (in 1/32 of "
Expand Down Expand Up @@ -1329,21 +1370,6 @@ static int pf_cmrpc_rm_connect_interpret_ind (
}
}
}
else
{
LOG_ERROR (
PF_RPC_LOG,
"CMRPC(%d): Too many CR given. Max %u CR per AR supported\n",
__LINE__,
PNET_MAX_CR);
pf_set_error (
&p_sess->rpc_result,
PNET_ERROR_CODE_CONNECT,
PNET_ERROR_DECODE_PNIO,
PNET_ERROR_CODE_1_CMRPC,
PNET_ERROR_CODE_2_CMRPC_WRONG_BLOCK_COUNT);
ret = -1;
}
break;
case PF_BT_EXPECTED_SUBMODULE_BLOCK:
pf_get_exp_api_module (&p_sess->get_info, p_pos, p_ar);
Expand Down Expand Up @@ -4310,7 +4336,16 @@ static int pf_cmrpc_dce_packet (
p_sess->get_info = get_info;
memset (&p_sess->rpc_result, 0, sizeof (p_sess->rpc_result));

if (rpc_req.flags.fragment == false)
if (rpc_req.length_of_body > PF_CMRPC_MAX_PDU_BODY_SIZE)
{
LOG_ERROR (
PF_RPC_LOG,
"CMRPC(%d): RPC fragment too large (%hu bytes)."
" Check the conformance of the controller (PLC).\n",
__LINE__,
rpc_req.length_of_body);
}
else if (rpc_req.flags.fragment == false)
{
/* Incoming message is a request or response contained entirely in one
* frame */
Expand Down Expand Up @@ -4422,7 +4457,45 @@ static int pf_cmrpc_dce_packet (
/* Decide what to do with incoming message */
/* Enter here _even_if_ an error is already detected because we may need
* to generate an error response. */
if (
if (rpc_req.length_of_body > PF_CMRPC_MAX_PDU_BODY_SIZE)
{
/* The specifications do not clearly state what the response should
* be in this case. The current best guess is to send a Reject PDU.
*/

/* Prepare the response */
rpc_res = rpc_req;
rpc_res.packet_type = PF_RPC_PT_REJECT;
rpc_res.flags.last_fragment = false;
rpc_res.flags.fragment = false;
rpc_res.flags.no_fack = true;
rpc_res.flags.maybe = false;
rpc_res.flags.idempotent = true;
rpc_res.flags.broadcast = false;
rpc_res.flags2.cancel_pending = false;
rpc_res.length_of_body = sizeof (uint32_t);
rpc_res.fragment_nmb = 0;
rpc_res.is_big_endian = p_sess->is_big_endian;

pf_put_dce_rpc_header (
&rpc_res,
*p_res_len,
p_res,
&res_pos,
&length_of_body_pos);

pf_put_uint32 (
rpc_res.is_big_endian,
PF_RPC_NCA_PROTO_ERROR,
*p_res_len,
p_res,
&res_pos);

pf_cmrpc_send_once_from_buffer (net, p_sess, p_res, res_pos, "REJECT");

p_sess->kill_session = is_new_session;
}
else if (
(rpc_req.flags.fragment == false) ||
(rpc_req.flags.last_fragment == true))
{
Expand Down
20 changes: 20 additions & 0 deletions src/pf_types.h
Original file line number Diff line number Diff line change
Expand Up @@ -468,6 +468,26 @@ typedef struct pf_rpc_lookup_req
uint16_t udpPort;
} pf_rpc_lookup_req_t;

typedef enum
{
PF_RPC_NCA_RPC_VERSION_MISMATCH = 0x1C000008,
PF_RPC_NCA_UNSPEC_REJECT = 0x1C000009,
PF_RPC_NCA_S_BAD_ACTID = 0x1C00000A,
PF_RPC_NCA_WHO_ARE_YOU_FAILED = 0x1C00000B,
PF_RPC_NCA_MANAGER_NOT_ENTERED = 0x1C00000C,
PF_RPC_NCA_UNSUPPORTED_AUTHN_LEVEL = 0x1C00001D,
PF_RPC_NCA_INVALID_CHECKSUM = 0x1C00001F,
PF_RPC_NCA_INVALID_CRC = 0x1C000020,
PF_RPC_NCA_OP_RNG_ERROR = 0x1C010002,
PF_RPC_NCA_UNK_IF = 0x1C010003,
PF_RPC_NCA_WRONG_BOOT_TIME = 0x1C010006,
PF_RPC_NCA_S_YOU_CRASHED = 0x1C010009,
PF_RPC_NCA_PROTO_ERROR = 0x1C01000B,
PF_RPC_NCA_OUT_ARGS_TOO_BIG = 0x1C010013,
PF_RPC_NCA_SERVER_TOO_BUSY = 0x1C010014,
PF_RPC_NCA_UNSUPPORTED_TYPE = 0x1C010017
} pf_rpc_nca_reject_status_t;

/************************** Block header *************************************/

typedef enum pf_block_type_values
Expand Down