GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usbx_host_classes/src/ux_host_class_cdc_ecm_mac_address_get.c Lines: 80 80 100.0 %
Date: 2024-12-12 17:16:36 Branches: 38 38 100.0 %

Line Branch Exec Source
1
/***************************************************************************
2
 * Copyright (c) 2024 Microsoft Corporation
3
 *
4
 * This program and the accompanying materials are made available under the
5
 * terms of the MIT License which is available at
6
 * https://opensource.org/licenses/MIT.
7
 *
8
 * SPDX-License-Identifier: MIT
9
 **************************************************************************/
10
11
12
/**************************************************************************/
13
/**************************************************************************/
14
/**                                                                       */
15
/** USBX Component                                                        */
16
/**                                                                       */
17
/**   CDC ECM Class                                                       */
18
/**                                                                       */
19
/**************************************************************************/
20
/**************************************************************************/
21
22
23
/* Include necessary system files.  */
24
25
#define UX_SOURCE_CODE
26
27
#include "ux_api.h"
28
#include "ux_host_class_cdc_ecm.h"
29
#include "ux_host_stack.h"
30
31
32
/**************************************************************************/
33
/*                                                                        */
34
/*  FUNCTION                                               RELEASE        */
35
/*                                                                        */
36
/*    _ux_host_class_cdc_ecm_mac_address_get              PORTABLE C      */
37
/*                                                           6.2.0        */
38
/*  AUTHOR                                                                */
39
/*                                                                        */
40
/*    Chaoqiong Xiao, Microsoft Corporation                               */
41
/*                                                                        */
42
/*  DESCRIPTION                                                           */
43
/*                                                                        */
44
/*    This function calls the USBX stack to retrieve the MAC address from */
45
/*    the configuration descriptor.                                       */
46
/*                                                                        */
47
/*  INPUT                                                                 */
48
/*                                                                        */
49
/*    cdc_ecm                                Pointer to cdc_ecm class     */
50
/*                                                                        */
51
/*  OUTPUT                                                                */
52
/*                                                                        */
53
/*    Completion Status                                                   */
54
/*                                                                        */
55
/*  CALLS                                                                 */
56
/*                                                                        */
57
/*    _ux_host_stack_transfer_request        Transfer request             */
58
/*    _ux_utility_memory_allocate            Allocate memory              */
59
/*    _ux_utility_memory_free                Free memory                  */
60
/*    _ux_utility_descriptor_parse           Parse descriptors            */
61
/*                                                                        */
62
/*  CALLED BY                                                             */
63
/*                                                                        */
64
/*    _ux_host_class_cdc_ecm_activate            CDC ECM class activate   */
65
/*                                                                        */
66
/*  RELEASE HISTORY                                                       */
67
/*                                                                        */
68
/*    DATE              NAME                      DESCRIPTION             */
69
/*                                                                        */
70
/*  05-19-2020     Chaoqiong Xiao           Initial Version 6.0           */
71
/*  09-30-2020     Chaoqiong Xiao           Modified comment(s),          */
72
/*                                            resulting in version 6.1    */
73
/*  07-29-2022     Chaoqiong Xiao           Modified comment(s),          */
74
/*                                            checked MAC string length,  */
75
/*                                            resulting in version 6.1.12 */
76
/*  10-31-2022     Chaoqiong Xiao           Modified comment(s),          */
77
/*                                            checked descriptor length,  */
78
/*                                            resulting in version 6.2.0  */
79
/*                                                                        */
80
/**************************************************************************/
81
78
UINT  _ux_host_class_cdc_ecm_mac_address_get(UX_HOST_CLASS_CDC_ECM *cdc_ecm)
82
{
83
84
UINT                                        status;
85
UX_ENDPOINT                                 *control_endpoint;
86
UX_TRANSFER                                 *transfer_request;
87
UX_CONFIGURATION_DESCRIPTOR                 configuration_descriptor;
88
UCHAR                                       *descriptor;
89
78
UCHAR                                       *start_descriptor = UX_NULL;
90
ULONG                                       configuration_index;
91
ULONG                                       total_configuration_length;
92
UINT                                        descriptor_length;
93
UINT                                        descriptor_type;
94
UINT                                        descriptor_subtype;
95
UX_HOST_CLASS_ECM_INTERFACE_DESCRIPTOR      ecm_interface_descriptor;
96
UCHAR                                       *mac_address_string;
97
ULONG                                       string_index;
98
ULONG                                       string_length;
99
UCHAR                                       element_content;
100
UCHAR                                       element_hexa_upper;
101
UCHAR                                       element_hexa_lower;
102
103
    /* We now need to retrieve the MAC address of the node which is embedded in the ECM descriptor.
104
       We will parse the entire configuration descriptor of the device and look for the ECM Ethernet Networking Functional Descriptor.  */
105
78
    configuration_index = (ULONG)cdc_ecm -> ux_host_class_cdc_ecm_interface_data -> ux_interface_configuration -> ux_configuration_descriptor.bConfigurationValue -1;
106
107
    /* We need to get the default control endpoint transfer request pointer.  */
108
78
    control_endpoint =  &cdc_ecm -> ux_host_class_cdc_ecm_device -> ux_device_control_endpoint;
109
78
    transfer_request =  &control_endpoint -> ux_endpoint_transfer_request;
110
111
    /* Need to allocate memory for the descriptor. Since we do not know the size of the
112
       descriptor, we first read the first bytes.  */
113
78
    descriptor =  _ux_utility_memory_allocate(UX_SAFE_ALIGN, UX_CACHE_SAFE_MEMORY, UX_CONFIGURATION_DESCRIPTOR_LENGTH);
114
78
    if (descriptor == UX_NULL)
115
1
        return(UX_MEMORY_INSUFFICIENT);
116
117
    /* Memorize the descriptor start address.  */
118
77
    start_descriptor =  descriptor;
119
120
    /* Create a transfer request for the GET_DESCRIPTOR request.  */
121
77
    transfer_request -> ux_transfer_request_data_pointer =      descriptor;
122
77
    transfer_request -> ux_transfer_request_requested_length =  UX_CONFIGURATION_DESCRIPTOR_LENGTH;
123
77
    transfer_request -> ux_transfer_request_function =          UX_GET_DESCRIPTOR;
124
77
    transfer_request -> ux_transfer_request_type =              UX_REQUEST_IN | UX_REQUEST_TYPE_STANDARD | UX_REQUEST_TARGET_DEVICE;
125
77
    transfer_request -> ux_transfer_request_value =             (UX_CONFIGURATION_DESCRIPTOR_ITEM << 8) | configuration_index;
126
77
    transfer_request -> ux_transfer_request_index =             0;
127
128
    /* Send request to HCD layer.  */
129
77
    status =  _ux_host_stack_transfer_request(transfer_request);
130
131
    /* Check for correct transfer and entire descriptor returned.  */
132

77
    if ((status == UX_SUCCESS) && (transfer_request -> ux_transfer_request_actual_length == UX_CONFIGURATION_DESCRIPTOR_LENGTH))
133
    {
134
135
        /* Parse the descriptor so that we can read the total length.  */
136
73
        _ux_utility_descriptor_parse(descriptor, _ux_system_configuration_descriptor_structure,
137
                                                                UX_CONFIGURATION_DESCRIPTOR_ENTRIES, (UCHAR *) &configuration_descriptor);
138
139
        /* We don't need this descriptor now.  */
140
73
        _ux_utility_memory_free(descriptor);
141
142
        /* Reallocate the memory necessary for the reading the entire descriptor.  */
143
73
        total_configuration_length =  configuration_descriptor.wTotalLength;
144
73
        descriptor =  _ux_utility_memory_allocate(UX_SAFE_ALIGN, UX_CACHE_SAFE_MEMORY, total_configuration_length);
145
73
        if (descriptor == UX_NULL)
146
1
            return(UX_MEMORY_INSUFFICIENT);
147
148
        /* Save this descriptor address.  */
149
72
        start_descriptor =  descriptor;
150
151
        /* Read the descriptor again with the correct length this time.  */
152
72
        transfer_request -> ux_transfer_request_requested_length =  total_configuration_length;
153
154
        /* Since the address of the descriptor may have changed, reprogram it.  */
155
72
        transfer_request -> ux_transfer_request_data_pointer =  descriptor;
156
157
        /* Send request to HCD layer.  */
158
72
        status =  _ux_host_stack_transfer_request(transfer_request);
159
160
        /* Check for correct transfer and entire descriptor returned.  */
161

72
        if ((status == UX_SUCCESS) && (transfer_request -> ux_transfer_request_actual_length == configuration_descriptor.wTotalLength))
162
        {
163
164
            /* The ECM descriptor is embedded within the configuration descriptor. We parse the
165
               entire descriptor to locate the ECM functional descriptor portion.  */
166
354
            while (total_configuration_length)
167
            {
168
169
                /* Gather the length and type of the descriptor.   */
170
351
                descriptor_length  =  *descriptor;
171
351
                descriptor_type    =  *(descriptor + 1);
172
351
                descriptor_subtype =  *(descriptor + 2);
173
174
                /* Descriptor length validation.  */
175

351
                if (descriptor_length < 3 || descriptor_length > total_configuration_length)
176
                {
177
178
                    /* Error trap.  */
179
2
                    _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_CLASS, UX_DESCRIPTOR_CORRUPTED);
180
181
                    /* Free descriptor memory.  */
182
2
                    _ux_utility_memory_free(start_descriptor);
183
184
                    /* Return error.  */
185
2
                    return(UX_DESCRIPTOR_CORRUPTED);
186
                }
187
188
                /* Check the type for an interface descriptor and the subtype for a ECM functional descriptor.  */
189

349
                if ((descriptor_type == UX_HOST_CLASS_CDC_ECM_CS_INTERFACE) && (descriptor_subtype == UX_HOST_CLASS_CDC_ECM_FUNCTIONAL_DESCRIPTOR))
190
                {
191
192
                    /* Parse the interface descriptor and make it machine independent.  */
193
63
                    _ux_utility_descriptor_parse(descriptor,
194
                                _ux_system_ecm_interface_descriptor_structure,
195
                                UX_HOST_CLASS_CDC_ECM_INTERFACE_DESCRIPTOR_ENTRIES,
196
                                (UCHAR *) &ecm_interface_descriptor);
197
198
199
                    /* Release the memory.  */
200
63
                    _ux_utility_memory_free(start_descriptor);
201
202
                    /* We now have the ECM functional descriptor in memory. We can retrieve the index of the iMACAddress
203
                       which we need for NetX.  */
204
205
                    /* Allocate memory for the MAC address.  */
206
63
                    mac_address_string =  _ux_utility_memory_allocate(UX_SAFE_ALIGN, UX_CACHE_SAFE_MEMORY, UX_HOST_CLASS_CDC_ECM_MAC_ADDRESS_STRING_LENGTH);
207
208
                    /* Check memory allocation.  */
209
63
                    if (mac_address_string == UX_NULL)
210
1
                        return(UX_MEMORY_INSUFFICIENT);
211
212
                    /* Create a transfer request for the GET_DESCRIPTOR request.  */
213
62
                    transfer_request -> ux_transfer_request_data_pointer =      mac_address_string;
214
62
                    transfer_request -> ux_transfer_request_requested_length =  UX_HOST_CLASS_CDC_ECM_MAC_ADDRESS_STRING_LENGTH;
215
62
                    transfer_request -> ux_transfer_request_function =          UX_GET_DESCRIPTOR;
216
62
                    transfer_request -> ux_transfer_request_type =              UX_REQUEST_IN | UX_REQUEST_TYPE_STANDARD | UX_REQUEST_TARGET_DEVICE;
217
62
                    transfer_request -> ux_transfer_request_value =             (UX_STRING_DESCRIPTOR_ITEM << 8) | ecm_interface_descriptor.iMACAddress;
218
62
                    transfer_request -> ux_transfer_request_index =             0x0409;
219
220
                    /* Send request to HCD layer.  */
221
62
                    status =  _ux_host_stack_transfer_request(transfer_request);
222
223
                    /* Check for correct transfer. */
224
62
                    if (status == UX_SUCCESS)
225
                    {
226
227
                        /* Translate from Unicode to string. Length is in the first byte followed type.
228
                           We must take away 2 from it and divide by 2 to find the right ascii length. */
229
61
                        string_length = (ULONG) *mac_address_string;
230
231
                        /* Check the length of the MAC address Unicode string
232
                           (length or 1B + type of 1B + string or 12*2B).  */
233
61
                        if (string_length != 26)
234
                        {
235
236
                            /* Error trap. */
237
3
                            _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_CLASS, UX_DESCRIPTOR_CORRUPTED);
238
239
                            /* Return error.  */
240
3
                            status =  UX_DESCRIPTOR_CORRUPTED;
241
                        }
242
                        else
243
                        {
244
245
                            /* No error in length, decode the string.  */
246
58
                            string_length -=2;
247
58
                            string_length = string_length / 2;
248
249
                            /* Now we have a string of 12 hex ASCII digits to be translated into 6 hex digit bytes.
250
                               and copy into the node ID.  */
251
406
                            for (string_index = 0; string_index < string_length; string_index++)
252
                            {
253
254
                                /* Get the upper element from the ASCII string.  */
255
348
                                element_content = *(mac_address_string + (string_index * 2) + 2);
256
257
                                /* We have a valid element content.  Turn it into a hex decimal value.  Note
258
                                   that only hex digits are allowed.  */
259
348
                                if (element_content <= '9')
260
261
                                    /* We have a digit.  */
262
286
                                    element_hexa_upper = (UCHAR)(element_content - '0');
263
264
                                else
265
                                {
266
                                    /* We have a 'A' to 'F' or 'a' to 'f' value.  */
267
62
                                    if (element_content >= 'a')
268
269
                                        /* We have a 'a' to 'f' char.  */
270
4
                                        element_hexa_upper = (UCHAR)(element_content - 'a' + 10);
271
272
                                    else
273
274
                                        /* We have a 'A' to 'F' char.  */
275
58
                                        element_hexa_upper = (UCHAR)(element_content - 'A' + 10);
276
277
                                }
278
279
                                /* Get the lower element from the ASCII string.  */
280
348
                                element_content = *(mac_address_string + ((string_index + 1) * 2) + 2);
281
282
                                /* We have a valid element content.  Turn it into a hexa decimal value.  Note
283
                                   that only hex digits are allowed.  */
284
348
                                if (element_content <= '9')
285
286
                                    /* We have a digit.  */
287
284
                                    element_hexa_lower = (UCHAR)(element_content - '0');
288
289
                                else
290
                                {
291
                                    /* We have a 'A' to 'F' or 'a' to 'f' value.  */
292
64
                                    if (element_content >= 'a')
293
294
                                        /* We have a 'a' to 'f' char.  */
295
4
                                        element_hexa_lower = (UCHAR)(element_content - 'a' + 10);
296
297
                                    else
298
299
                                        /* We have a 'A' to 'F' char.  */
300
60
                                        element_hexa_lower = (UCHAR)(element_content - 'A' + 10);
301
302
                                }
303
304
                                /* Assemble the byte from the 2 nibbles and store it into the node_id. */
305
348
                                *(cdc_ecm -> ux_host_class_cdc_ecm_node_id + string_index / 2) = (UCHAR)(element_hexa_upper << 4 | element_hexa_lower);
306
307
                                /* Skip the lower nibble. */
308
348
                                string_index ++;
309
310
                            }
311
312
                            /* Operation was successful ! */
313
58
                            status = UX_SUCCESS;
314
                        }
315
                    }
316
                    else
317
                    {
318
319
                        /* We have a bad MAC address string.  Do not proceed.  */
320
1
                        status = UX_ERROR;
321
                    }
322
323
                    /* Free the MAC address string.  */
324
62
                    _ux_utility_memory_free(mac_address_string);
325
326
                    /* Return completion status.  */
327
62
                    return(status);
328
                }
329
                else
330
                {
331
332
                    /* Jump to the next descriptor if we have not reached the end.  */
333
286
                    descriptor +=  descriptor_length;
334
335
                    /* And adjust the length left to parse in the descriptor.  */
336
286
                    total_configuration_length -=  descriptor_length;
337
                }
338
            }
339
        }
340
    }
341
342
    /* Error trap. */
343
11
    _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_CLASS, UX_DESCRIPTOR_CORRUPTED);
344
345
    /* If trace is enabled, insert this event into the trace buffer.  */
346
    UX_TRACE_IN_LINE_INSERT(UX_TRACE_ERROR, UX_DESCRIPTOR_CORRUPTED, &configuration_descriptor, 0, 0, UX_TRACE_ERRORS, 0, 0)
347
348
    /* Release the memory.  */
349
11
    _ux_utility_memory_free(start_descriptor);
350
351
    /* Return an error.  */
352
11
    return(UX_DESCRIPTOR_CORRUPTED);
353
354
}