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 /** NetX Component                                                        */
16 /**                                                                       */
17 /**   Internet Protocol (IPv6)                                            */
18 /**                                                                       */
19 /**************************************************************************/
20 /**************************************************************************/
21 
22 
23 #define NX_SOURCE_CODE
24 
25 
26 /* Include necessary system files.  */
27 #include "nx_api.h"
28 #include "nx_ipv6.h"
29 
30 /**************************************************************************/
31 /*                                                                        */
32 /*  FUNCTION                                               RELEASE        */
33 /*                                                                        */
34 /*    _nxd_ipv6_multicast_interface_join                  PORTABLE C      */
35 /*                                                           6.1          */
36 /*  AUTHOR                                                                */
37 /*                                                                        */
38 /*    Yuxin Zhou, Microsoft Corporation                                   */
39 /*                                                                        */
40 /*  DESCRIPTION                                                           */
41 /*                                                                        */
42 /*    This service allows an application to join a specific IPv6          */
43 /*    multicast address on a specific physical interface.  The link       */
44 /*    driver is notified to add the multicast address.                    */
45 /*                                                                        */
46 /*  INPUT                                                                 */
47 /*                                                                        */
48 /*    ip_ptr                                IP instance pointer           */
49 /*    group_address                         IPv6 multicast address        */
50 /*    interface_index                       Index to the phyical interface*/
51 /*                                                                        */
52 /*  OUTPUT                                                                */
53 /*                                                                        */
54 /*    status                                Completion status             */
55 /*                                                                        */
56 /*  CALLS                                                                 */
57 /*                                                                        */
58 /*    tx_mutex_get                          Obtain protection mutex       */
59 /*    tx_mutex_put                          Release protection mutex      */
60 /*    memset                                Clear the memory              */
61 /*    (ip_link_driver)                      Device driver entry point     */
62 /*    CHECK_IPV6_ADDRESSES_SAME             IPv6 address compare          */
63 /*    CHECK_UNSPECIFIED_ADDRESS             Check for :: address          */
64 /*                                                                        */
65 /*  CALLED BY                                                             */
66 /*                                                                        */
67 /*    Application                                                         */
68 /*                                                                        */
69 /*  RELEASE HISTORY                                                       */
70 /*                                                                        */
71 /*    DATE              NAME                      DESCRIPTION             */
72 /*                                                                        */
73 /*  05-19-2020     Yuxin Zhou               Initial Version 6.0           */
74 /*  09-30-2020     Yuxin Zhou               Modified comment(s),          */
75 /*                                            resulting in version 6.1    */
76 /*                                                                        */
77 /**************************************************************************/
_nxd_ipv6_multicast_interface_join(NX_IP * ip_ptr,NXD_ADDRESS * group_address,UINT interface_index)78 UINT  _nxd_ipv6_multicast_interface_join(NX_IP *ip_ptr, NXD_ADDRESS *group_address, UINT interface_index)
79 {
80 #if defined(NX_ENABLE_IPV6_MULTICAST) && defined(FEATURE_NX_IPV6)
81 
82 UINT          i;
83 UINT          first_free;
84 NX_IP_DRIVER  driver_request;
85 NX_INTERFACE *nx_interface;
86 
87     /* Obtain the IP mutex so we can search the multicast join list.  */
88     tx_mutex_get(&(ip_ptr -> nx_ip_protection), TX_WAIT_FOREVER);
89 
90     nx_interface = &ip_ptr -> nx_ip_interface[interface_index];
91 
92     /* Search the multicast join list for either the same group request.  */
93     first_free =     NX_MAX_MULTICAST_GROUPS;
94 
95     for (i = 0; i < NX_MAX_MULTICAST_GROUPS; i++)
96     {
97 
98         /* Determine if the specified entry is already in the multicast join list.  */
99         if ((nx_interface == ip_ptr -> nx_ipv6_multicast_entry[i].nx_ip_mld_join_interface_list) &&
100             (CHECK_IPV6_ADDRESSES_SAME(ip_ptr -> nx_ipv6_multicast_entry[i].nx_ip_mld_join_list, group_address -> nxd_ip_address.v6)))
101         {
102 
103             /* Yes, we have found the same entry.  The only thing required in this
104                case is to increment the join count and return.  */
105             ip_ptr -> nx_ipv6_multicast_entry[i].nx_ip_mld_join_count++;
106 
107             /* Release the IP protection.  */
108             tx_mutex_put(&(ip_ptr -> nx_ip_protection));
109 
110             /* Return number of the group.  */
111             return(NX_SUCCESS);
112         }
113 
114         /* Check for an empty entry.  */
115         if (CHECK_UNSPECIFIED_ADDRESS(ip_ptr -> nx_ipv6_multicast_entry[i].nx_ip_mld_join_list) && (first_free == NX_MAX_MULTICAST_GROUPS))
116         {
117 
118             /* Remember the first free entry.  */
119             first_free =  i;
120         }
121     }
122 
123     /* At this point, we have a new entry.   First, check to see if there is an available
124        entry.  */
125     if (first_free == NX_MAX_MULTICAST_GROUPS)
126     {
127 
128         /* Release the protection of the IP instance.  */
129         tx_mutex_put(&(ip_ptr -> nx_ip_protection));
130 
131         /* Return an error code to indicate there are no more group addresses
132            available.  */
133         return(NX_NO_MORE_ENTRIES);
134     }
135 
136     /* Set it up in the IP control structures.  */
137     ip_ptr -> nx_ipv6_multicast_entry[first_free].nx_ip_mld_join_list[0]        =    group_address -> nxd_ip_address.v6[0];
138     ip_ptr -> nx_ipv6_multicast_entry[first_free].nx_ip_mld_join_list[1]        =    group_address -> nxd_ip_address.v6[1];
139     ip_ptr -> nx_ipv6_multicast_entry[first_free].nx_ip_mld_join_list[2]        =    group_address -> nxd_ip_address.v6[2];
140     ip_ptr -> nx_ipv6_multicast_entry[first_free].nx_ip_mld_join_list[3]        =    group_address -> nxd_ip_address.v6[3];
141     ip_ptr -> nx_ipv6_multicast_entry[first_free].nx_ip_mld_join_interface_list =    nx_interface;
142     ip_ptr -> nx_ipv6_multicast_entry[first_free].nx_ip_mld_join_count          =    1;
143 
144     /* Increment the MLD groups joined count.  */
145     ip_ptr -> nx_ipv6_multicast_groups_joined++;
146 
147     /* Register the new multicast group with the underlying driver to
148        ensure that there is room for the new group at the hardware level.  */
149     driver_request.nx_ip_driver_ptr                  =   ip_ptr;
150     driver_request.nx_ip_driver_command              =   NX_LINK_MULTICAST_JOIN;
151     driver_request.nx_ip_driver_physical_address_msw =   0x00003333;
152     driver_request.nx_ip_driver_physical_address_lsw =   group_address -> nxd_ip_address.v6[3];
153     driver_request.nx_ip_driver_interface            =   nx_interface;
154 
155     (nx_interface -> nx_interface_link_driver_entry)(&driver_request);
156 
157     /* Check the return driver status.   */
158     /*lint -e{644} suppress variable might not be initialized, since "nx_ip_driver_status" was initialized in nx_interface_link_driver_entry. */
159     if (driver_request.nx_ip_driver_status != NX_SUCCESS)
160     {
161 
162         /* Release the protection of the IP instance.  */
163         tx_mutex_put(&(ip_ptr -> nx_ip_protection));
164 
165         /* Return an error code to indicate there are no more group addresses
166            available.  */
167         return(NX_OVERFLOW);
168     }
169 
170     /* Release the protection over the IP instance.  */
171     tx_mutex_put(&(ip_ptr -> nx_ip_protection));
172 
173     /* Return SUCCESS.  */
174     return(NX_SUCCESS);
175 
176 #else
177     NX_PARAMETER_NOT_USED(ip_ptr);
178     NX_PARAMETER_NOT_USED(group_address);
179     NX_PARAMETER_NOT_USED(interface_index);
180 
181     return(NX_NOT_SUPPORTED);
182 
183 #endif /* NX_ENABLE_IPV6_MULTICAST && FEATURE_NX_IPV6 */
184 }
185 
186