blob: a9a3498f33e219081ff5fa7ac70981f2f088961a [file] [log] [blame]
developer02e65912023-08-17 16:33:10 +08001/* iotoken.c
2 *
3 * IOToken API implementation for the EIP-197 Server with ICE only
4 *
5 */
6
7/*****************************************************************************
8* Copyright (c) 2016-2022 by Rambus, Inc. and/or its subsidiaries.
9*
10* This program is free software: you can redistribute it and/or modify
11* it under the terms of the GNU General Public License as published by
12* the Free Software Foundation, either version 2 of the License, or
13* any later version.
14*
15* This program is distributed in the hope that it will be useful,
16* but WITHOUT ANY WARRANTY; without even the implied warranty of
17* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18* GNU General Public License for more details.
19*
20* You should have received a copy of the GNU General Public License
21* along with this program. If not, see <http://www.gnu.org/licenses/>.
22*****************************************************************************/
23
24/*----------------------------------------------------------------------------
25 * This module implements (provides) the following interface(s):
26 */
27
28// Extended IOToken API
29#include "iotoken_ext.h"
30
31
32/*----------------------------------------------------------------------------
33 * This module uses (requires) the following interface(s):
34 */
35
36// Default configuration
37#include "c_iotoken.h" // IOTOKEN_STRICT_ARGS
38
39// Driver Framework Basic Definitions API
40#include "basic_defs.h" // IDENTIFIER_NOT_USED, bool, uint32_t
41
42// Firmware packet flow codes
43#include "firmware_eip207_api_cmd.h"
44
45// ZEROINIT
46#include "clib.h"
47
48#include "log.h"
49
50// Packet buffer access
51#include "adapter_pec_pktbuf.h"
52
53/*----------------------------------------------------------------------------
54 * Definitions and macros
55 */
56
57#define IOTOKEN_ARGUMENT_ERROR -1
58#define IOTOKEN_INTERNAL_ERROR -2
59
60#ifdef IOTOKEN_STRICT_ARGS
61#define IOTOKEN_CHECK_POINTER(_p) \
62 if (NULL == (_p)) \
63 return IOTOKEN_ARGUMENT_ERROR;
64#define IOTOKEN_CHECK_INT_INRANGE(_i, _min, _max) \
65 if ((_i) < (_min) || (_i) > (_max)) \
66 return IOTOKEN_ARGUMENT_ERROR;
67#define IOTOKEN_CHECK_INT_ATLEAST(_i, _min) \
68 if ((_i) < (_min)) \
69 return IOTOKEN_ARGUMENT_ERROR;
70#define IOTOKEN_CHECK_INT_ATMOST(_i, _max) \
71 if ((_i) > (_max)) \
72 return IOTOKEN_ARGUMENT_ERROR;
73#else
74/* IOTOKEN_STRICT_ARGS undefined */
75#define IOTOKEN_CHECK_POINTER(_p)
76#define IOTOKEN_CHECK_INT_INRANGE(_i, _min, _max)
77#define IOTOKEN_CHECK_INT_ATLEAST(_i, _min)
78#define IOTOKEN_CHECK_INT_ATMOST(_i, _max)
79#endif /*end of IOTOKEN_STRICT_ARGS */
80
81// Input Token words offsets
82#define IOTOKEN_HDR_IN_WORD_OFFS 0
83#define IOTOKEN_APP_ID_IN_WORD_OFFS 1
84#define IOTOKEN_SA_ADDR_LO_IN_WORD_OFFS 2
85#define IOTOKEN_SA_ADDR_HI_IN_WORD_OFFS 3
86#define IOTOKEN_HW_SERVICES_IN_WORD_OFFS 4
87#define IOTOKEN_NH_OFFSET_IN_WORD_OFFS 5
88#define IOTOKEN_BP_DATA_IN_WORD_OFFS 6
89
90// Output Token words offsets
91#define IOTOKEN_HDR_OUT_WORD_OFFS 0
92#define IOTOKEN_BP_LEN_OUT_WORD_OFFS 1
93#define IOTOKEN_APP_ID_OUT_WORD_OFFS 2
94#define IOTOKEN_PAD_NH_OUT_WORD_OFFS 3
95#define IOTOKEN_SA_ADDR_LO_OUT_WORD_OFFS 4
96#define IOTOKEN_SA_ADDR_HI_OUT_WORD_OFFS 5
97#define IOTOKEN_NPH_CTX_OUT_WORD_OFFS 6
98#define IOTOKEN_PREV_NH_OFFS_OUT_WORD_OFFS 7
99#define IOTOKEN_BP_DATA_OUT_WORD_OFFS 8
100
101#define IOTOKEN_MARK 0xEC00
102
103
104/*----------------------------------------------------------------------------
105 * Local variables
106 */
107
108
109/*----------------------------------------------------------------------------
110 * IOToken_InWordCount_Get
111 */
112unsigned int
113IOToken_InWordCount_Get(void)
114{
115 return IOTOKEN_IN_WORD_COUNT - 4 + IOTOKEN_BYPASS_WORD_COUNT;
116}
117
118
119/*----------------------------------------------------------------------------
120 * IOToken_OutWordCount_Get
121 */
122unsigned int
123IOToken_OutWordCount_Get(void)
124{
125 return IOTOKEN_OUT_WORD_COUNT - 4 + IOTOKEN_BYPASS_WORD_COUNT;
126}
127
128
129/*----------------------------------------------------------------------------
130 * IOToken_Create
131 */
132int
133IOToken_Create(
134 const IOToken_Input_Dscr_t * const Dscr_p,
135 uint32_t * Data_p)
136{
137 IOToken_Input_Dscr_Ext_t * DscrExt_p;
138#if IOTOKEN_BYPASS_WORD_COUNT > 0
139 unsigned int bypass_gap = 0;
140#endif
141 unsigned int i;
142
143 IOTOKEN_CHECK_POINTER(Dscr_p);
144 IOTOKEN_CHECK_POINTER(Dscr_p->Ext_p);
145 IOTOKEN_CHECK_POINTER(Data_p);
146
147 DscrExt_p = (IOToken_Input_Dscr_Ext_t *)Dscr_p->Ext_p;
148
149 // Input Token word: EIP-96 Token Header Word
150 {
151 i = IOTOKEN_HDR_IN_WORD_OFFS;
152
153 // Set initialization value in the Token Header Word excluding packet
154 // size field
155 Data_p[i] = Dscr_p->TknHdrWordInit & ~MASK_16_BITS;
156
157 // Input packet size
158 Data_p[i] |= Dscr_p->InPacket_ByteCount & MASK_16_BITS;
159
160 if (DscrExt_p->HW_Services == IOTOKEN_CMD_PKT_LAC)
161 {
162 // Options, ARC4 pre-fetch
163 if (DscrExt_p->fARC4Prefetch)
164 Data_p[i] |= BIT_16;
165
166 Data_p[i] |= BIT_17; // Set token header format to EIP-(1)97
167
168 Data_p[i] |= BIT_18; // Only 64-bit Context (SA) pointer is supported
169
170 // Enable Context Reuse auto detect if no new SA
171 if (Dscr_p->Options.fReuseSA)
172 Data_p[i] |= BIT_21;
173 }
174 // Mask size for inbound ESP
175 if (DscrExt_p->SequenceMaskBitCount != 0)
176 {
177 switch(DscrExt_p->SequenceMaskBitCount)
178 {
179 case 64:
180 Data_p[i] |= 0x00200000;
181 break;
182 case 128:
183 Data_p[i] |= 0x00400000;
184 break;
185 case 256:
186 Data_p[i] |= 0x00600000;
187 break;
188 case 512:
189 Data_p[i] |= 0x00800000;
190 break;
191 }
192 }
193 // Extended options for LIP
194 if (DscrExt_p->fEncLastDest)
195 Data_p[i] |= BIT_25;
196 // Extended options for in-line DTLS packet flow
197 {
198 if (DscrExt_p->Options.fCAPWAP)
199 Data_p[i] |= BIT_26;
200
201 if (DscrExt_p->Options.fInbound)
202 Data_p[i] |= BIT_27;
203
204 Data_p[i] |= DscrExt_p->Options.ContentType << 28;
205 }
206
207 Data_p[i] |= IOTOKEN_FLOW_TYPE << 30; // Implemented flow type
208 }
209
210 // Input Token word: Application ID
211 {
212 i = IOTOKEN_APP_ID_IN_WORD_OFFS;
213 Data_p[i] = (Dscr_p->AppID & MASK_7_BITS) << 9;
214 Data_p[i] |= (DscrExt_p->AAD_ByteCount & MASK_8_BITS);
215 if (DscrExt_p->fInline)
216 Data_p[i] |= (32 + IOTOKEN_BYPASS_WORD_COUNT*4) << 16;
217 }
218
219 // Input Token word: Context (SA) low 32 bits physical address
220 {
221 i = IOTOKEN_SA_ADDR_LO_IN_WORD_OFFS;
222 Data_p[i] = Dscr_p->SA_PhysAddr.Lo;
223 }
224
225 // Input Token word: Context (SA) high 32 bits physical address
226 {
227 i = IOTOKEN_SA_ADDR_HI_IN_WORD_OFFS;
228 //if (DscrExt_p->Options.f64bitSA) // Only 64-bit SA address supported
229 Data_p[i] = Dscr_p->SA_PhysAddr.Hi;
230 }
231
232 // Input Token word: HW services, e,g, packet flow selection
233 {
234 i = IOTOKEN_HW_SERVICES_IN_WORD_OFFS;
235 Data_p[i] = ((DscrExt_p->HW_Services & MASK_8_BITS) << 24) |
236 (DscrExt_p->UserDef & MASK_16_BITS);
237 if (DscrExt_p->fStripPadding != IOTOKEN_PADDING_DEFAULT_ON)
238 Data_p[i] |= BIT_22;
239 if (DscrExt_p->fAllowPadding != IOTOKEN_PADDING_DEFAULT_ON)
240 Data_p[i] |= BIT_23;
241 }
242
243 // Input Token word: Offset and Next Header
244 {
245 i = IOTOKEN_NH_OFFSET_IN_WORD_OFFS;
246 Data_p[i] = (DscrExt_p->Offset_ByteCount & MASK_8_BITS) << 8;
247 Data_p[i] |= (DscrExt_p->NextHeader & MASK_8_BITS) << 16;
248 if (DscrExt_p->fFL)
249 Data_p[i] |= BIT_24;
250 if (DscrExt_p->fIPv4Chksum)
251 Data_p[i] |= BIT_25;
252 if (DscrExt_p->fL4Chksum)
253 Data_p[i] |= BIT_26;
254 if (DscrExt_p->fParseEther)
255 Data_p[i] |= BIT_27;
256 if (DscrExt_p->fKeepOuter)
257 Data_p[i] |= BIT_28;
258
259 }
260
261 if (DscrExt_p->fInline)
262 {
263 Data_p[IOTOKEN_BP_DATA_IN_WORD_OFFS]=0;
264 Data_p[IOTOKEN_BP_DATA_IN_WORD_OFFS+1]=0;
265#if IOTOKEN_BYPASS_WORD_COUNT > 0
266 bypass_gap = 2;
267#endif
268 }
269
270#if IOTOKEN_BYPASS_WORD_COUNT > 0
271 // Input Token word: Bypass Data
272 {
273 unsigned int j;
274
275 if (DscrExt_p->BypassData_p)
276 {
277 for (j = 0; j < IOTOKEN_BYPASS_WORD_COUNT; j++)
278 Data_p[j+IOTOKEN_BP_DATA_IN_WORD_OFFS + bypass_gap] = DscrExt_p->BypassData_p[j];
279 }
280 else
281 {
282 for (j = 0; j < IOTOKEN_BYPASS_WORD_COUNT; j++)
283 Data_p[j+IOTOKEN_BP_DATA_IN_WORD_OFFS + bypass_gap] = 0xf0f0f0f0;
284 }
285 i += bypass_gap + j;
286 }
287#endif
288
289 if (i >= IOTOKEN_IN_WORD_COUNT_IL)
290 return IOTOKEN_INTERNAL_ERROR;
291 else
292 return i+1;
293}
294
295
296/*----------------------------------------------------------------------------
297 * IOToken_Fixup
298 */
299int
300IOToken_Fixup(
301 uint32_t * const Data_p,
302 const DMABuf_Handle_t PacketHandle)
303{
304 uint32_t AppendFlags;
305 if (Data_p == NULL)
306 return 0;
307
308 AppendFlags = Data_p[IOTOKEN_BP_LEN_OUT_WORD_OFFS] & (BIT_31|BIT_30|BIT_29);
309 if (AppendFlags != 0)
310 {
311 uint8_t AppendData[12];
312 uint8_t *Append_p;
313 unsigned int Offset;
314 unsigned int PrevNH_Offset;
315 unsigned int UpdateOffset;
316 unsigned int AppendLen = 0;
317 if ((AppendFlags & BIT_31) != 0)
318 AppendLen+=4;
319 if ((AppendFlags & BIT_30) != 0)
320 AppendLen+=4;
321 if ((AppendFlags & BIT_29) != 0)
322 AppendLen+=4;
323 UpdateOffset = Data_p[IOTOKEN_HDR_OUT_WORD_OFFS] & MASK_17_BITS;
324 UpdateOffset = 4*((UpdateOffset + 3)/4); // Align to word boundary.
325 Offset = Data_p[IOTOKEN_PAD_NH_OUT_WORD_OFFS] >> 16 & MASK_8_BITS;
326 // Get first byte of header
327 Append_p = Adapter_PEC_PktData_Get(PacketHandle, AppendData, UpdateOffset, AppendLen);
328 if (AppendFlags == (BIT_31|BIT_30))
329 { // IPv6 header update, NH plus length
330 PrevNH_Offset = Data_p[IOTOKEN_PREV_NH_OFFS_OUT_WORD_OFFS] & MASK_16_BITS;
331 Adapter_PEC_PktByte_Put(PacketHandle, PrevNH_Offset, Append_p[4]);
332 Adapter_PEC_PktByte_Put(PacketHandle, Offset + 4, Append_p[0]);
333 Adapter_PEC_PktByte_Put(PacketHandle, Offset + 5, Append_p[1]);
334 LOG_INFO("IOToken_Fixup: IPv6 inbound transport\n");
335 }
336 else if (AppendFlags == BIT_29)
337 { // IPv4 checksum only update
338 Adapter_PEC_PktByte_Put(PacketHandle, Offset + 10, Append_p[0]);
339 Adapter_PEC_PktByte_Put(PacketHandle, Offset + 11, Append_p[1]);
340 LOG_INFO("IOToken_Fixup: IPv4 inbound tunnel\n");
341 }
342 else if (AppendFlags == (BIT_31|BIT_30|BIT_29))
343 { // IPv4 header update, proto + length + checksum.
344 Adapter_PEC_PktByte_Put(PacketHandle, Offset + 2, Append_p[0]);
345 Adapter_PEC_PktByte_Put(PacketHandle, Offset + 3, Append_p[1]);
346 Adapter_PEC_PktByte_Put(PacketHandle, Offset + 9, Append_p[5]);
347 Adapter_PEC_PktByte_Put(PacketHandle, Offset + 10, Append_p[8]);
348 Adapter_PEC_PktByte_Put(PacketHandle, Offset + 11, Append_p[9]);
349 LOG_INFO("IOToken_Fixup: IPv4 inbound transport\n");
350 }
351 else
352 {
353 LOG_CRIT("IOToken_Fixup: Unexpected flags combination 0x%08x\n",
354 AppendFlags);
355 return -1;
356 }
357 }
358 return 0;
359}
360
361/*----------------------------------------------------------------------------
362 * IOToken_SAAddr_Update
363 */
364int
365IOToken_SAAddr_Update(
366 const IOToken_PhysAddr_t * const SA_PhysAddr_p,
367 uint32_t * InTokenData_p)
368{
369 IOTOKEN_CHECK_POINTER(SA_PhysAddr_p);
370 IOTOKEN_CHECK_POINTER(InTokenData_p);
371
372 // Input Token word: Context (SA) low 32 bits physical address
373 InTokenData_p[IOTOKEN_SA_ADDR_LO_IN_WORD_OFFS] = SA_PhysAddr_p->Lo;
374
375 // Input Token word: Context (SA) high 32 bits physical address
376 InTokenData_p[IOTOKEN_SA_ADDR_HI_IN_WORD_OFFS] = SA_PhysAddr_p->Hi;
377
378 return 2; // updated 32-bit token words
379}
380
381
382/*----------------------------------------------------------------------------
383 * IOToken_SAReuse_Update
384 */
385int
386IOToken_SAReuse_Update(
387 const bool fReuseSA,
388 uint32_t * InTokenData_p)
389{
390 IOTOKEN_CHECK_POINTER(InTokenData_p);
391
392 // Enable Context Reuse auto detect if no new SA
393 if (fReuseSA)
394 InTokenData_p[IOTOKEN_HDR_IN_WORD_OFFS] |= BIT_21;
395 else
396 InTokenData_p[IOTOKEN_HDR_IN_WORD_OFFS] &= ~BIT_21;
397
398 return 1;
399}
400
401
402/*----------------------------------------------------------------------------
403 * IOToken_Mark_Set
404 */
405int
406IOToken_Mark_Set(
407 uint32_t * InTokenData_p)
408{
409 IOTOKEN_CHECK_POINTER(InTokenData_p);
410
411 InTokenData_p[IOTOKEN_APP_ID_IN_WORD_OFFS] &= ~(MASK_7_BITS << 9);
412 InTokenData_p[IOTOKEN_APP_ID_IN_WORD_OFFS] |= IOTOKEN_MARK;
413
414 return 1;
415}
416
417
418/*----------------------------------------------------------------------------
419 * IOToken_Mark_Offset_Get
420 */
421int
422IOToken_OutMarkOffset_Get(void)
423{
424 return IOTOKEN_APP_ID_OUT_WORD_OFFS;
425}
426
427
428/*----------------------------------------------------------------------------
429 * IOToken_Mark_Check
430 */
431int
432IOToken_Mark_Check(
433 uint32_t * OutTokenData_p)
434{
435 uint32_t Mark;
436
437 IOTOKEN_CHECK_POINTER(OutTokenData_p);
438
439 Mark = OutTokenData_p[IOTOKEN_APP_ID_OUT_WORD_OFFS] & IOTOKEN_MARK;
440
441 if (Mark == IOTOKEN_MARK)
442 return 0;
443 else
444 return 1;
445}
446
447
448/*----------------------------------------------------------------------------
449 * IOToken_Parse
450 */
451int
452IOToken_Parse(
453 const uint32_t * Data_p,
454 IOToken_Output_Dscr_t * const Dscr_p)
455{
456 unsigned int i, j = 0;
457 IOToken_Output_Dscr_Ext_t * Ext_p;
458
459 IOTOKEN_CHECK_POINTER(Data_p);
460 IOTOKEN_CHECK_POINTER(Dscr_p);
461
462 Ext_p = (IOToken_Output_Dscr_Ext_t *)Dscr_p->Ext_p;
463
464 // Output Token word: EIP-96 Output Token Header Word
465 {
466 i = IOTOKEN_HDR_OUT_WORD_OFFS;
467 Dscr_p->OutPacket_ByteCount = Data_p[i] & MASK_17_BITS;
468 Dscr_p->ErrorCode = Data_p[i] >> 17 & MASK_15_BITS;
469 }
470
471 // Output Token word: EIP-96 Output Token Bypass Data Length Word
472 {
473 i = IOTOKEN_BP_LEN_OUT_WORD_OFFS;
474 Dscr_p->BypassData_ByteCount = Data_p[i] & MASK_4_BITS;
475 Dscr_p->fHashAppended = (Data_p[i] & BIT_21) != 0;
476
477 Dscr_p->Hash_ByteCount = Data_p[i] >> 22 & MASK_6_BITS;
478
479 Dscr_p->fBytesAppended = (Data_p[i] & BIT_28) != 0;
480 Dscr_p->fChecksumAppended = (Data_p[i] & BIT_29) != 0;
481 Dscr_p->fNextHeaderAppended = (Data_p[i] & BIT_30) != 0;
482 Dscr_p->fLengthAppended = (Data_p[i] & BIT_31) != 0;
483 }
484
485 // Output Token word: EIP-96 Output Token Application ID Word
486 {
487 i = IOTOKEN_APP_ID_OUT_WORD_OFFS;
488 Dscr_p->AppID = Data_p[i] >> 9 & MASK_7_BITS;
489 }
490
491 // Output Token word: Pad Length and Next Header
492 {
493 i = IOTOKEN_PAD_NH_OUT_WORD_OFFS;
494 Dscr_p->NextHeader = Data_p[i] & MASK_8_BITS;
495 Dscr_p->Pad_ByteCount = Data_p[i] >> 8 & MASK_8_BITS;
496 }
497
498 // Parse Output Token descriptor extension if requested
499 if (Ext_p)
500 {
501 // Output Token word: ToS/TC, DF, Firmware errors
502 {
503 j = IOTOKEN_BP_LEN_OUT_WORD_OFFS;
504 Ext_p->TOS_TC = Data_p[j] >> 5 & MASK_8_BITS;
505
506 Ext_p->fDF = (Data_p[j] & BIT_13) != 0;
507
508 Ext_p->CfyErrors = Data_p[j] >> 16 & MASK_5_BITS;
509 }
510
511#ifdef IOTOKEN_EXTENDED_ERRORS_ENABLE
512 if ((Data_p[IOTOKEN_HDR_OUT_WORD_OFFS] & BIT_31) != 0)
513 {
514 Ext_p->ExtErrors = (Data_p[IOTOKEN_HDR_OUT_WORD_OFFS] >> 17) & MASK_8_BITS;
515 }
516 else
517#endif
518 {
519 Ext_p->ExtErrors = 0;
520 }
521
522 // Output Token word: IP Length Delta and Offset
523 {
524 j = IOTOKEN_PAD_NH_OUT_WORD_OFFS;
525 Ext_p->Offset_ByteCount = Data_p[j] >> 16 & MASK_8_BITS;
526 Ext_p->IPDelta_ByteCount = Data_p[j] >> 24 & MASK_8_BITS;
527 }
528
529 // Output Token word: SA physical address low/high words
530 {
531 j = IOTOKEN_SA_ADDR_LO_OUT_WORD_OFFS;
532 Ext_p->SA_PhysAddr.Lo = Data_p[j];
533
534 j = IOTOKEN_SA_ADDR_HI_OUT_WORD_OFFS;
535 Ext_p->SA_PhysAddr.Hi = Data_p[j];
536 }
537
538 // Output Token word: Application header processing context
539 {
540 j = IOTOKEN_NPH_CTX_OUT_WORD_OFFS;
541 Ext_p->NPH_Context = Data_p[j];
542 }
543
544 // Output Token word: Previous Next Header Offset
545 {
546 j = IOTOKEN_PREV_NH_OFFS_OUT_WORD_OFFS;
547 Ext_p->NextHeaderOffset = Data_p[j] & MASK_16_BITS;
548 Ext_p->fInIPv6 = ((Data_p[j] & BIT_16) != 0);
549 Ext_p->fFromEther = ((Data_p[j] & BIT_17) != 0);
550 Ext_p->fOutIPv6 = ((Data_p[j] & BIT_22) != 0);
551 Ext_p->fInbTunnel = ((Data_p[j] & BIT_23) != 0);
552 }
553
554#if IOTOKEN_BYPASS_WORD_COUNT > 0
555 // Output Token word: Bypass Data
556 {
557 unsigned int k = 0;
558 if (Ext_p->BypassData_p)
559 {
560 for (k = 0; k < IOTOKEN_BYPASS_WORD_COUNT; k++)
561 Ext_p->BypassData_p[k] =
562 Data_p[k+IOTOKEN_BP_DATA_OUT_WORD_OFFS];
563 }
564 j += k;
565 }
566#endif
567 }
568
569 // Output Token word: Reserved word not used
570 // i = IOTOKEN_RSVD_OUT_WORD_OFFS;
571
572 return MAX(i, j);
573}
574
575
576/*----------------------------------------------------------------------------
577 * IOToken_PacketLegth_Get
578 */
579int
580IOToken_PacketLegth_Get(
581 const uint32_t * Data_p,
582 unsigned int * Pkt_ByteCount_p)
583{
584 IOTOKEN_CHECK_POINTER(Data_p);
585 IOTOKEN_CHECK_POINTER(Pkt_ByteCount_p);
586
587 *Pkt_ByteCount_p = Data_p[IOTOKEN_HDR_OUT_WORD_OFFS] & MASK_17_BITS;
588
589 return 1;
590}
591
592
593/*----------------------------------------------------------------------------
594 * IOToken_BypassLegth_Get
595 */
596int
597IOToken_BypassLegth_Get(
598 const uint32_t * Data_p,
599 unsigned int * BD_ByteCount_p)
600{
601 IOTOKEN_CHECK_POINTER(Data_p);
602 IOTOKEN_CHECK_POINTER(BD_ByteCount_p);
603
604 *BD_ByteCount_p = Data_p[IOTOKEN_BP_LEN_OUT_WORD_OFFS] & MASK_4_BITS;
605
606 return 1;
607}
608
609
610/*----------------------------------------------------------------------------
611 * IOToken_ErrorCode_Get
612 */
613int
614IOToken_ErrorCode_Get(
615 const uint32_t * Data_p,
616 unsigned int * ErrorCode_p)
617{
618 IOTOKEN_CHECK_POINTER(Data_p);
619 IOTOKEN_CHECK_POINTER(ErrorCode_p);
620
621 *ErrorCode_p = (Data_p[IOTOKEN_HDR_OUT_WORD_OFFS] >> 17) & MASK_15_BITS;
622#ifdef IOTOKEN_EXTENDED_ERRORS_ENABLE
623 if ((Data_p[IOTOKEN_HDR_OUT_WORD_OFFS] & BIT_31) != 0)
624 {
625 *ErrorCode_p &= ~0x40ff; // Remove the detailed error code and related bits.
626 }
627#endif
628
629 return 1;
630}
631
632
633/* end of file iotoken.c */