1 /**************************************************************************/
2 /*                                                                        */
3 /*       Copyright (c) Microsoft Corporation. All rights reserved.        */
4 /*                                                                        */
5 /*       This software is licensed under the Microsoft Software License   */
6 /*       Terms for Microsoft Azure RTOS. Full text of the license can be  */
7 /*       found in the LICENSE file at https://aka.ms/AzureRTOS_EULA       */
8 /*       and in the root directory of this software.                      */
9 /*                                                                        */
10 /**************************************************************************/
11 
12 
13 /**************************************************************************/
14 /**************************************************************************/
15 /**                                                                       */
16 /** NetX Component                                                        */
17 /**                                                                       */
18 /**   Internet Group Management Protocol (IGMP)                           */
19 /**                                                                       */
20 /**************************************************************************/
21 /**************************************************************************/
22 
23 #define NX_SOURCE_CODE
24 
25 
26 /* Include necessary system files.  */
27 
28 #include "nx_api.h"
29 #include "nx_igmp.h"
30 #include "nx_ipv4.h"
31 #include "nx_packet.h"
32 
33 
34 #ifndef NX_DISABLE_IPV4
35 /**************************************************************************/
36 /*                                                                        */
37 /*  FUNCTION                                               RELEASE        */
38 /*                                                                        */
39 /*    _nx_igmp_interface_report_send                      PORTABLE C      */
40 /*                                                           6.1          */
41 /*  AUTHOR                                                                */
42 /*                                                                        */
43 /*    Yuxin Zhou, Microsoft Corporation                                   */
44 /*                                                                        */
45 /*  DESCRIPTION                                                           */
46 /*                                                                        */
47 /*    This function builds and sends an IGMP report.  If it is a JOIN     */
48 /*    report, the IP nx_igmp_reports_sent statistic is incremented.       */
49 /*                                                                        */
50 /*    Note: An IGMPv1 host does not send a LEAVE message. The caller in   */
51 /*    that case, _nx_igmp_multicast_interface_leave_internal, checks the  */
52 /*    IGMP host version and only calls this function for IGMPv2 hosts.    */
53 /*                                                                        */
54 /*  INPUT                                                                 */
55 /*                                                                        */
56 /*    ip_ptr                                IP instance pointer           */
57 /*    group_address                         Multicast group to join       */
58 /*    interface_index                       Index to the interface        */
59 /*    is_joining                            Indicate if joining or leaving*/
60 /*                                            NX_TRUE = send join report  */
61 /*                                            NX_FALSE = send leave report*/
62 /*                                                                        */
63 /*  OUTPUT                                                                */
64 /*                                                                        */
65 /*    status                                Completion status             */
66 /*                                                                        */
67 /*  CALLS                                                                 */
68 /*                                                                        */
69 /*    _nx_ip_packet_send                    Send packet from the IP layer */
70 /*    _nx_packet_allocate                   Allocate a packet for report  */
71 /*    tx_mutex_get                          Obtain protection mutex       */
72 /*    tx_mutex_put                          Release protection mutex      */
73 /*                                                                        */
74 /*  CALLED BY                                                             */
75 /*                                                                        */
76 /*    nx_igmp_periodic_processing           Performs periodic IGMP tasks  */
77 /*    nx_igmp_multicast_interface_leave_internal                          */
78 /*                                          Processes a LEAVE report for  */
79 /*                                            transmission to all routers */
80 /*                                                                        */
81 /*  RELEASE HISTORY                                                       */
82 /*                                                                        */
83 /*    DATE              NAME                      DESCRIPTION             */
84 /*                                                                        */
85 /*  05-19-2020     Yuxin Zhou               Initial Version 6.0           */
86 /*  09-30-2020     Yuxin Zhou               Modified comment(s),          */
87 /*                                            resulting in version 6.1    */
88 /*                                                                        */
89 /**************************************************************************/
_nx_igmp_interface_report_send(NX_IP * ip_ptr,ULONG group_address,UINT interface_index,UINT is_joining)90 UINT  _nx_igmp_interface_report_send(NX_IP *ip_ptr, ULONG group_address, UINT interface_index, UINT is_joining)
91 {
92 
93 NX_INTERFACE   *nx_interface;
94 UINT            router_alert = 0;
95 UINT            status;
96 ULONG           checksum;
97 ULONG           temp;
98 NX_PACKET      *packet_ptr;
99 NX_IGMP_HEADER *header_ptr;
100 
101 
102 #ifndef NX_DISABLE_IGMPV2
103     if (ip_ptr -> nx_ip_igmp_router_version == NX_IGMP_HOST_VERSION_2)
104     {
105         router_alert = 4;
106     }
107 #endif
108 
109     /* Obtain the IP mutex so we can search the multicast join list.  */
110     tx_mutex_get(&(ip_ptr -> nx_ip_protection), TX_WAIT_FOREVER);
111 
112     nx_interface = &ip_ptr -> nx_ip_interface[interface_index];
113 
114     /* Build an IGMP host response packet and send it!  */
115 
116     /* Allocate a packet to place the IGMP host response message in.  */
117 #ifdef NX_ENABLE_DUAL_PACKET_POOL
118     /* Allocate from auxiliary packet pool first. */
119     status = _nx_packet_allocate(ip_ptr -> nx_ip_auxiliary_packet_pool, &packet_ptr, (ULONG)(NX_IGMP_PACKET + router_alert + NX_IGMP_HEADER_SIZE), TX_NO_WAIT);
120     if ((status != NX_SUCCESS) && (ip_ptr -> nx_ip_auxiliary_packet_pool != ip_ptr -> nx_ip_default_packet_pool))
121 #endif /* NX_ENABLE_DUAL_PACKET_POOL */
122     {
123         status = _nx_packet_allocate(ip_ptr -> nx_ip_default_packet_pool, &packet_ptr, (ULONG)(NX_IGMP_PACKET + router_alert + NX_IGMP_HEADER_SIZE), TX_NO_WAIT);
124     }
125 
126     if (status)
127     {
128 
129         /* Packet allocation failed. Release the mutex and return error status. */
130         tx_mutex_put(&(ip_ptr -> nx_ip_protection));
131 
132         return(status);
133     }
134 
135     /* Add debug information. */
136     NX_PACKET_DEBUG(__FILE__, __LINE__, packet_ptr);
137 
138     /* Prepare an IGMP response and send on the "all hosts" multicast
139        address.  */
140 
141 #ifndef NX_DISABLE_IGMP_INFO
142     /* Increase the IGMP reports sent count.  */
143     if (is_joining == NX_TRUE)
144     {
145         ip_ptr -> nx_ip_igmp_reports_sent++;
146     }
147 
148 #endif
149 
150     /* Calculate the IGMP response message size and store it in the
151        packet header.  */
152     /*lint -e{644} suppress variable might not be initialized, since "packet_ptr" was initialized as long as status is NX_SUCCESS. */
153     packet_ptr -> nx_packet_length =  NX_IGMP_HEADER_SIZE;
154 
155     /* Setup the prepend pointer.  */
156     packet_ptr -> nx_packet_prepend_ptr -= NX_IGMP_HEADER_SIZE;
157 
158     /* Stamp the outgoing interface. */
159     packet_ptr -> nx_packet_address.nx_packet_interface_ptr = nx_interface;
160 
161     /* Build the IGMP host response packet.  */
162 
163     /* Setup the pointer to the message area.  */
164     /*lint -e{927} -e{826} suppress cast of pointer to pointer, since it is necessary  */
165     header_ptr =  (NX_IGMP_HEADER *)packet_ptr -> nx_packet_prepend_ptr;
166 
167 #ifndef NX_DISABLE_IGMPV2
168 
169     /* Build the IGMPv2 response message.  */
170 
171     /* Is the router using IGMPv1? */
172     if (ip_ptr -> nx_ip_igmp_router_version == NX_IGMP_HOST_VERSION_1)
173     {
174 #endif /* NX_DISABLE_IGMPV2 */
175 
176         /* Yes; Set the header fields with the max response time
177            zero and the version/type 0x12. */
178         header_ptr -> nx_igmp_header_word_0 =  (ULONG)(NX_IGMP_VERSION | NX_IGMP_HOST_RESPONSE_TYPE);
179         header_ptr -> nx_igmp_header_word_1 =  group_address;
180 #ifndef NX_DISABLE_IGMPV2
181     }
182     /* The router is running the IGMPv2 (or higher) protocol. */
183     else
184     {
185 
186         /* Indicate if the report is a join or leave report. */
187         if (is_joining)
188         {
189 
190             header_ptr -> nx_igmp_header_word_0 =  (ULONG)(NX_IGMP_HOST_V2_JOIN_TYPE);
191         }
192         else
193         {
194             header_ptr -> nx_igmp_header_word_0 =  (ULONG)(NX_IGMP_HOST_V2_LEAVE_TYPE);
195         }
196 
197         header_ptr -> nx_igmp_header_word_1 =  group_address;
198     }
199 #endif /* NX_DISABLE_IGMPV2 */
200 
201 
202 #ifdef NX_ENABLE_INTERFACE_CAPABILITY
203     if (!(packet_ptr -> nx_packet_address.nx_packet_interface_ptr -> nx_interface_capability_flag & NX_INTERFACE_CAPABILITY_IGMP_TX_CHECKSUM))
204 #endif /* NX_ENABLE_INTERFACE_CAPABILITY  */
205     {
206 
207         /* Calculate the checksum.  */
208         temp =      header_ptr -> nx_igmp_header_word_0;
209         checksum =  (temp >> NX_SHIFT_BY_16);
210         checksum += (temp & NX_LOWER_16_MASK);
211         temp =      header_ptr -> nx_igmp_header_word_1;
212         checksum += (temp >> NX_SHIFT_BY_16);
213         checksum += (temp & NX_LOWER_16_MASK);
214 
215         /* Add in the carry bits into the checksum.  */
216         checksum = (checksum >> NX_SHIFT_BY_16) + (checksum & NX_LOWER_16_MASK);
217 
218         /* Do it again in case previous operation generates an overflow.  */
219         checksum = (checksum >> NX_SHIFT_BY_16) + (checksum & NX_LOWER_16_MASK);
220 
221         /* Place the checksum into the first header word.  */
222         header_ptr -> nx_igmp_header_word_0 =  header_ptr -> nx_igmp_header_word_0 | (~checksum & NX_LOWER_16_MASK);
223     }
224 #ifdef NX_ENABLE_INTERFACE_CAPABILITY
225     else
226     {
227         packet_ptr -> nx_packet_interface_capability_flag |= NX_INTERFACE_CAPABILITY_IGMP_TX_CHECKSUM;
228     }
229 #endif /* NX_ENABLE_INTERFACE_CAPABILITY */
230 
231     /* IGMPv2 packets must be IPv4 packets. */
232     packet_ptr -> nx_packet_ip_version = NX_IP_VERSION_V4;
233 
234     /* If NX_LITTLE_ENDIAN is defined, the headers need to be swapped.  */
235     NX_CHANGE_ULONG_ENDIAN(header_ptr -> nx_igmp_header_word_0);
236     NX_CHANGE_ULONG_ENDIAN(header_ptr -> nx_igmp_header_word_1);
237 
238     /* Send the IGMP response packet out!  */
239     if (is_joining == NX_TRUE)
240     {
241 
242         /* For JOIN reports, set the packet destination to the group address. */
243         _nx_ip_packet_send(ip_ptr, packet_ptr,
244                            group_address,
245                            NX_IP_NORMAL, NX_IGMP_TTL, NX_IP_IGMP, NX_FRAGMENT_OKAY,
246                            group_address);
247     }
248     else
249     {
250 
251         /* For LEAVE reports, set the destination to ALL ROUTERS as per RFC 2236 Section 3 page 4.*/
252         _nx_ip_packet_send(ip_ptr, packet_ptr,
253                            NX_ALL_ROUTERS_ADDRESS,
254                            NX_IP_NORMAL, NX_IGMP_TTL, NX_IP_IGMP, NX_FRAGMENT_OKAY,
255                            NX_ALL_ROUTERS_ADDRESS);
256     }
257 
258     /* Release the protection over the IP instance.  */
259     tx_mutex_put(&(ip_ptr -> nx_ip_protection));
260 
261     return NX_SUCCESS;
262 }
263 #endif /* NX_DISABLE_IPV4 */
264 
265