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 (IP)                                              */
18 /**                                                                       */
19 /**************************************************************************/
20 /**************************************************************************/
21 
22 #define NX_SOURCE_CODE
23 
24 
25 /* Include necessary system files.  */
26 
27 #include "nx_api.h"
28 #include "nx_ip.h"
29 #include "nx_packet.h"
30 
31 #ifndef NX_DISABLE_IPV4
32 /**************************************************************************/
33 /*                                                                        */
34 /*  FUNCTION                                               RELEASE        */
35 /*                                                                        */
36 /*    _nx_ip_driver_packet_send                           PORTABLE C      */
37 /*                                                           6.1          */
38 /*  AUTHOR                                                                */
39 /*                                                                        */
40 /*    Yuxin Zhou, Microsoft Corporation                                   */
41 /*                                                                        */
42 /*  DESCRIPTION                                                           */
43 /*                                                                        */
44 /*    This function sends an IP packet to the appropriate link driver.    */
45 /*                                                                        */
46 /*  INPUT                                                                 */
47 /*                                                                        */
48 /*    ip_ptr                                Pointer to IP control block   */
49 /*    packet_ptr                            Pointer to packet to send     */
50 /*    destination_ip                        Destination IP address        */
51 /*    fragment                              Don't fragment bit            */
52 /*    next_hop_address                      Next Hop address              */
53 /*                                                                        */
54 /*  OUTPUT                                                                */
55 /*                                                                        */
56 /*    None                                                                */
57 /*                                                                        */
58 /*  CALLS                                                                 */
59 /*                                                                        */
60 /*    (_nx_arp_entry_allocate)              ARP entry allocate service    */
61 /*    (_nx_arp_packet_send)                 Send an ARP packet            */
62 /*    _nx_ip_packet_deferred_receive        Receive loopback packet       */
63 /*    _nx_packet_copy                       Copy packet to input packet   */
64 /*    _nx_packet_transmit_release           Release transmit packet       */
65 /*    (nx_ip_fragment_processing)           Fragment processing           */
66 /*    (ip_link_driver)                      User supplied link driver     */
67 /*    _nx_ip_packet_checksum_compute        Compute checksum              */
68 /*                                                                        */
69 /*  CALLED BY                                                             */
70 /*                                                                        */
71 /*    NetX Source Code                                                    */
72 /*                                                                        */
73 /*  RELEASE HISTORY                                                       */
74 /*                                                                        */
75 /*    DATE              NAME                      DESCRIPTION             */
76 /*                                                                        */
77 /*  05-19-2020     Yuxin Zhou               Initial Version 6.0           */
78 /*  09-30-2020     Yuxin Zhou               Modified comment(s),          */
79 /*                                            resulting in version 6.1    */
80 /*                                                                        */
81 /**************************************************************************/
_nx_ip_driver_packet_send(NX_IP * ip_ptr,NX_PACKET * packet_ptr,ULONG destination_ip,ULONG fragment,ULONG next_hop_address)82 VOID  _nx_ip_driver_packet_send(NX_IP *ip_ptr, NX_PACKET *packet_ptr, ULONG destination_ip, ULONG fragment, ULONG next_hop_address)
83 {
84 
85 TX_INTERRUPT_SAVE_AREA
86 NX_IP_DRIVER driver_request;
87 UINT         index;
88 ULONG        network_mask;
89 ULONG        network;
90 UCHAR        loopback = NX_FALSE;
91 NX_ARP      *arp_ptr;
92 NX_PACKET   *last_packet;
93 NX_PACKET   *remove_packet;
94 NX_PACKET   *packet_copy;
95 UINT         queued_count;
96 
97     /* Add debug information. */
98     NX_PACKET_DEBUG(__FILE__, __LINE__, packet_ptr);
99 
100     /* Initialize the driver request. */
101     driver_request.nx_ip_driver_ptr =                   ip_ptr;
102     driver_request.nx_ip_driver_packet =                packet_ptr;
103     driver_request.nx_ip_driver_interface =             packet_ptr -> nx_packet_address.nx_packet_interface_ptr;
104     driver_request.nx_ip_driver_command =               NX_LINK_PACKET_SEND;
105 
106     /* Determine if physical mapping is needed by the link driver.  */
107     if (packet_ptr -> nx_packet_address.nx_packet_interface_ptr -> nx_interface_address_mapping_needed)
108     {
109 
110         /* Get the network and network mask.*/
111         network_mask = packet_ptr -> nx_packet_address.nx_packet_interface_ptr -> nx_interface_ip_network_mask;
112         network = packet_ptr -> nx_packet_address.nx_packet_interface_ptr -> nx_interface_ip_network;
113 
114         /* Determine if an IP limited or directed broadcast is requested.  */
115         if ((destination_ip == NX_IP_LIMITED_BROADCAST) ||
116             (((destination_ip & network_mask) == network) &&
117              ((destination_ip & ~network_mask) == ~network_mask)))
118         {
119 
120             /* Build the driver request.  */
121             driver_request.nx_ip_driver_command =               NX_LINK_PACKET_BROADCAST;
122             driver_request.nx_ip_driver_physical_address_msw =  0xFFFFUL;
123             driver_request.nx_ip_driver_physical_address_lsw =  0xFFFFFFFFUL;
124         }
125         /* Determine if we have a loopback address.  */
126         else if (destination_ip == packet_ptr -> nx_packet_address.nx_packet_interface_ptr -> nx_interface_ip_address)
127         {
128             loopback = NX_TRUE;
129             driver_request.nx_ip_driver_interface = NX_NULL;
130         }
131         /* Determine if we have a class D multicast address.  */
132         else if ((destination_ip & NX_IP_CLASS_D_MASK) == NX_IP_CLASS_D_TYPE)
133         {
134 
135             /* Yes, we have a class D multicast address.  Derive the physical mapping from
136                the class D address.  */
137 
138             /* Determine if the group address has been joined in this IP instance.  */
139             index =  0;
140             while (index < NX_MAX_MULTICAST_GROUPS)
141             {
142 
143                 /* Determine if the destination address matches the requested address.  */
144                 if (ip_ptr -> nx_ipv4_multicast_entry[index].nx_ipv4_multicast_join_list == destination_ip)
145                 {
146 
147                     /* Yes, break the loop!  */
148                     break;
149                 }
150 
151                 /* Increment the join list index.  */
152                 index++;
153             }
154 
155             /* Determine if the group was joined by this IP instance.  */
156             if (index < NX_MAX_MULTICAST_GROUPS)
157             {
158 
159                 /* Determine if the group has loopback enabled.  */
160                 if (ip_ptr -> nx_ipv4_multicast_entry[index].nx_ipv4_multicast_loopback_enable)
161                 {
162                     loopback = NX_TRUE;
163                 }
164             }
165 
166             /* Build the driver request. Derive the physical mapping from
167                the class D address.  */
168             driver_request.nx_ip_driver_physical_address_msw =  NX_IP_MULTICAST_UPPER;
169             driver_request.nx_ip_driver_physical_address_lsw =  NX_IP_MULTICAST_LOWER | (destination_ip & NX_IP_MULTICAST_MASK);
170         }
171         else
172         {
173 
174             NX_PARAMETER_NOT_USED(fragment);
175             /* Look into the ARP Routing Table to derive the physical address.  */
176 
177             /* If we get here, the packet destination is a unicast address.  */
178             destination_ip = next_hop_address;
179 
180             /* Calculate the hash index for the destination IP address.  */
181             index =  (UINT)((destination_ip + (destination_ip >> 8)) & NX_ARP_TABLE_MASK);
182 
183             /* Determine if there is an entry for this IP address.  */
184             arp_ptr =  ip_ptr -> nx_ip_arp_table[index];
185 
186             /* Loop to look for an ARP match.  */
187             while (arp_ptr)
188             {
189 
190                 /* Determine if this arp entry matches the destination IP address.  */
191                 if (arp_ptr -> nx_arp_ip_address == destination_ip)
192                 {
193 
194                     /* Yes, we found a match.  Get out of the loop!  */
195                     break;
196                 }
197 
198                 /* Move to the next active ARP entry.  */
199                 arp_ptr =  arp_ptr -> nx_arp_active_next;
200 
201                 /* Determine if we are at the end of the ARP list.  */
202                 if (arp_ptr == ip_ptr -> nx_ip_arp_table[index])
203                 {
204                     /* Clear the ARP pointer.  */
205                     arp_ptr =  NX_NULL;
206                     break;
207                 }
208             }
209 
210             /* Determine if we actually found a matching and effective ARP entry.  */
211             if ((arp_ptr) && (arp_ptr -> nx_arp_physical_address_msw | arp_ptr -> nx_arp_physical_address_lsw))
212             {
213 
214                 /* Disable interrupts temporarily.  */
215                 TX_DISABLE
216 
217                 /* Yes, we have a physical mapping.  Copy the physical address into the driver
218                    request structure.  */
219                 driver_request.nx_ip_driver_physical_address_msw =  arp_ptr -> nx_arp_physical_address_msw;
220                 driver_request.nx_ip_driver_physical_address_lsw =  arp_ptr -> nx_arp_physical_address_lsw;
221 
222                 /* Move this ARP entry to the head of the list.  */
223                 ip_ptr -> nx_ip_arp_table[index] =  arp_ptr;
224 
225                 /* Restore interrupts.  */
226                 TX_RESTORE
227             }
228             else
229             {
230 
231                 /* Determine if fragmentation is needed before queue the packet on the ARP waiting queue.  */
232                 if (packet_ptr -> nx_packet_length > packet_ptr -> nx_packet_address.nx_packet_interface_ptr -> nx_interface_ip_mtu_size)
233                 {
234 
235 #ifndef NX_DISABLE_FRAGMENTATION
236                     /* Check the DF bit flag.  */
237                     if ((ip_ptr -> nx_ip_fragment_processing == NX_NULL) || (fragment != NX_FRAGMENT_OKAY))
238 #endif
239                     {
240 
241 #ifndef NX_DISABLE_IP_INFO
242 
243                         /* Increment the IP send packets dropped count.  */
244                         ip_ptr -> nx_ip_send_packets_dropped++;
245 #endif
246                         /* Just release the packet.  */
247                         _nx_packet_transmit_release(packet_ptr);
248 
249                         /* Return... nothing more can be done!  */
250                         return;
251                     }
252                 }
253 
254                 /* Determine if we actually found a matching ARP entry.  */
255                 if (arp_ptr)
256                 {
257 
258                     /* Yes, we have an existing ARP mapping entry.  */
259 
260                     /* Disable interrupts temporarily.  */
261                     TX_DISABLE
262 
263                     /* Ensure the current packet's queue next pointer to NULL.  */
264                     packet_ptr -> nx_packet_queue_next =  NX_NULL;
265 
266                     /* Determine if the queue is empty.  */
267                     if (arp_ptr -> nx_arp_packets_waiting == NX_NULL)
268                     {
269 
270                         /* Yes, we have an empty ARP packet queue.  Simply place the
271                            packet at the head of the list.  */
272                         arp_ptr -> nx_arp_packets_waiting =  packet_ptr;
273 
274                         /* Add debug information. */
275                         NX_PACKET_DEBUG(NX_PACKET_ARP_WAITING_QUEUE, __LINE__, packet_ptr);
276 
277                         /* Restore interrupts.  */
278                         TX_RESTORE
279                     }
280                     else
281                     {
282 
283                         /* Determine how many packets are on the ARP entry's packet
284                            queue and remember the last packet in the queue.  We know
285                            there is at least one on the queue and another that is
286                            going to be queued.  */
287                         last_packet =  arp_ptr -> nx_arp_packets_waiting;
288                         queued_count = 1;
289                         while (last_packet -> nx_packet_queue_next)
290                         {
291 
292                             /* Increment the queued count.  */
293                             queued_count++;
294 
295                             /* Move to the next packet in the queue.  */
296                             last_packet =  last_packet -> nx_packet_queue_next;
297                         }
298 
299                         /* Add debug information. */
300                         NX_PACKET_DEBUG(NX_PACKET_ARP_WAITING_QUEUE, __LINE__, packet_ptr);
301 
302                         /* Place the packet at the end of the list.  */
303                         last_packet -> nx_packet_queue_next =  packet_ptr;
304 
305                         /* Default the remove packet pointer to NULL.  */
306                         remove_packet =  NX_NULL;
307 
308                         /* Determine if the packets queued has exceeded the queue
309                            depth.  */
310                         if (queued_count >= NX_ARP_MAX_QUEUE_DEPTH)
311                         {
312 
313                             /* Save the packet pointer at the head of the list.  */
314                             remove_packet =  arp_ptr -> nx_arp_packets_waiting;
315 
316                             /* Remove the packet from the ARP queue.  */
317                             arp_ptr -> nx_arp_packets_waiting =  remove_packet -> nx_packet_queue_next;
318 
319                             /* Clear the remove packet queue next pointer.  */
320                             remove_packet -> nx_packet_queue_next =  NX_NULL;
321 
322 #ifndef NX_DISABLE_IP_INFO
323 
324                             /* Increment the IP transmit resource error count.  */
325                             ip_ptr -> nx_ip_transmit_resource_errors++;
326 
327                             /* Increment the IP send packets dropped count.  */
328                             ip_ptr -> nx_ip_send_packets_dropped++;
329 #endif
330                         }
331 
332                         /* Restore interrupts.  */
333                         TX_RESTORE
334 
335                         /* Determine if there is a packet to remove.  */
336                         if (remove_packet)
337                         {
338 
339                             /* Yes, the packet queue depth for this ARP entry was exceeded
340                                so release the packet that was removed from the queue.  */
341                             _nx_packet_transmit_release(remove_packet);
342                         }
343                     }
344                 }
345                 else
346                 {
347 
348                     /* No ARP entry was found.  We need to allocate a new ARP entry, populate it, and
349                        initiate an ARP request to get the specific physical mapping.  */
350 
351                     /* Allocate a new ARP entry.  */
352                     if ((!ip_ptr -> nx_ip_arp_allocate) ||
353                         ((ip_ptr -> nx_ip_arp_allocate)(ip_ptr, &(ip_ptr -> nx_ip_arp_table[index]), NX_FALSE)))
354                     {
355 
356                         /* Error, release the protection and the packet.  */
357 
358 #ifndef NX_DISABLE_IP_INFO
359 
360                         /* Increment the IP transmit resource error count.  */
361                         ip_ptr -> nx_ip_transmit_resource_errors++;
362 
363                         /* Increment the IP send packets dropped count.  */
364                         ip_ptr -> nx_ip_send_packets_dropped++;
365 #endif
366 
367                         /* Release the packet.  */
368                         _nx_packet_transmit_release(packet_ptr);
369 
370                         /* Just return!  */
371                         return;
372                     }
373 
374                     /* Otherwise, setup a pointer to the new ARP entry.  */
375                     arp_ptr =  (ip_ptr -> nx_ip_arp_table[index]) -> nx_arp_active_previous;
376 
377                     /* Setup the IP address and clear the physical mapping.  */
378                     arp_ptr -> nx_arp_ip_address =            destination_ip;
379                     arp_ptr -> nx_arp_physical_address_msw =  0;
380                     arp_ptr -> nx_arp_physical_address_lsw =  0;
381                     arp_ptr -> nx_arp_entry_next_update =     NX_ARP_UPDATE_RATE;
382                     arp_ptr -> nx_arp_retries =               0;
383                     arp_ptr -> nx_arp_ip_interface =          packet_ptr -> nx_packet_address.nx_packet_interface_ptr;
384 
385                     /* Ensure the queue next pointer is NULL for the packet before it
386                        is placed on the ARP waiting queue.  */
387                     packet_ptr -> nx_packet_queue_next =  NX_NULL;
388 
389                     /* Add debug information. */
390                     NX_PACKET_DEBUG(NX_PACKET_ARP_WAITING_QUEUE, __LINE__, packet_ptr);
391 
392                     /* Queue the packet for output.  */
393                     arp_ptr -> nx_arp_packets_waiting =  packet_ptr;
394 
395                     /* Call ARP send to send an ARP request.  */
396                     (ip_ptr -> nx_ip_arp_packet_send)(ip_ptr, destination_ip, packet_ptr -> nx_packet_address.nx_packet_interface_ptr);
397                 }
398 
399                 /* Just return!  */
400                 return;
401             }
402         }
403     }
404     else
405     {
406 
407         /* This IP instance does not require any IP-to-physical mapping.  */
408 
409         /* Determine if we have a loopback address.  */
410         if ((((destination_ip >= NX_IP_LOOPBACK_FIRST) &&
411               (destination_ip <= NX_IP_LOOPBACK_LAST))) ||
412             (destination_ip == packet_ptr -> nx_packet_address.nx_packet_interface_ptr -> nx_interface_ip_address))
413         {
414 
415             /* Yes, we have an internal loopback address.  */
416             loopback = NX_TRUE;
417             driver_request.nx_ip_driver_interface = NX_NULL;
418         }
419     }
420 
421     /* Check whether the packet should be loop back. */
422     if (loopback == NX_TRUE)
423     {
424 
425         /* Copy the packet so it can be enqueued properly by the receive
426            processing.  */
427         if (_nx_packet_copy(packet_ptr, &packet_copy, ip_ptr -> nx_ip_default_packet_pool, NX_NO_WAIT) == NX_SUCCESS)
428         {
429 
430 #ifdef NX_ENABLE_INTERFACE_CAPABILITY
431 
432             /* Compute checksum for upper layer protocol. */
433             /*lint --e{644} suppress variable might not be initialized, since "packet_copy" was initialized as long as return value is NX_SUCCESS. */
434             if (packet_copy -> nx_packet_interface_capability_flag)
435             {
436                 _nx_ip_packet_checksum_compute(packet_copy);
437             }
438 #endif /* NX_ENABLE_INTERFACE_CAPABILITY */
439 
440 #ifndef NX_DISABLE_IP_INFO
441 
442             /* Increment the IP packet sent count.  */
443             ip_ptr -> nx_ip_total_packets_sent++;
444 
445             /* Increment the IP bytes sent count.  */
446             ip_ptr -> nx_ip_total_bytes_sent +=  packet_ptr -> nx_packet_length - (ULONG)sizeof(NX_IPV4_HEADER);
447 #endif
448 
449 #ifdef NX_IPSEC_ENABLE
450             /* Clear the ipsec sa pointer.  */
451             packet_copy -> nx_packet_ipsec_sa_ptr = NX_NULL;
452 #endif /* NX_IPSEC_ENABLE  */
453 
454             /* Add debug information. */
455             /*lint --e{644} suppress variable might not be initialized, since "packet_copy" was initialized as long as return value is NX_SUCCESS. */
456             NX_PACKET_DEBUG(__FILE__, __LINE__, packet_copy);
457 
458             /* Send the packet to this IP's receive processing like it came in from the
459                driver.  */
460             _nx_ip_packet_deferred_receive(ip_ptr, packet_copy);
461         }
462 #ifndef NX_DISABLE_IP_INFO
463         else
464         {
465 
466             /* Increment the IP send packets dropped count.  */
467             ip_ptr -> nx_ip_send_packets_dropped++;
468 
469             /* Increment the IP transmit resource error count.  */
470             ip_ptr -> nx_ip_transmit_resource_errors++;
471         }
472 #endif
473     }
474 
475     /* Check whether the packet should be sent through driver. */
476     if (driver_request.nx_ip_driver_interface)
477     {
478 
479         /* Determine if fragmentation is needed.  */
480         if (packet_ptr -> nx_packet_length > packet_ptr -> nx_packet_address.nx_packet_interface_ptr -> nx_interface_ip_mtu_size)
481         {
482 
483 #ifndef NX_DISABLE_FRAGMENTATION
484             /* Check the DF bit flag.  */
485             if ((ip_ptr -> nx_ip_fragment_processing) && (fragment != NX_DONT_FRAGMENT))
486             {
487 
488                 /* Fragmentation is needed, call the IP fragment processing routine.  */
489                 (ip_ptr -> nx_ip_fragment_processing)(&driver_request);
490             }
491             else
492 #endif /* NX_DISABLE_FRAGMENTATION */
493             {
494 
495 #ifndef NX_DISABLE_IP_INFO
496 
497                 /* Increment the IP send packets dropped count.  */
498                 ip_ptr -> nx_ip_send_packets_dropped++;
499 #endif
500                 /* Just release the packet.  */
501                 _nx_packet_transmit_release(packet_ptr);
502             }
503 
504             /* In either case, this packet send is complete, just return.  */
505             return;
506         }
507 
508 #ifndef NX_DISABLE_IP_INFO
509 
510         /* Increment the IP packet sent count.  */
511         ip_ptr -> nx_ip_total_packets_sent++;
512 
513         /* Increment the IP bytes sent count.  */
514         ip_ptr -> nx_ip_total_bytes_sent +=  packet_ptr -> nx_packet_length - (ULONG)sizeof(NX_IPV4_HEADER);
515 #endif
516 
517         /* If trace is enabled, insert this event into the trace buffer.  */
518         NX_TRACE_IN_LINE_INSERT(NX_TRACE_INTERNAL_IO_DRIVER_PACKET_SEND, ip_ptr, packet_ptr, packet_ptr -> nx_packet_length, 0, NX_TRACE_INTERNAL_EVENTS, 0, 0);
519 
520         /* Add debug information. */
521         NX_PACKET_DEBUG(__FILE__, __LINE__, packet_ptr);
522 
523         /* Driver entry must not be NULL. */
524         NX_ASSERT(packet_ptr -> nx_packet_address.nx_packet_interface_ptr -> nx_interface_link_driver_entry != NX_NULL);
525 
526         /* Broadcast packet.  */
527         (packet_ptr -> nx_packet_address.nx_packet_interface_ptr -> nx_interface_link_driver_entry)(&driver_request);
528     }
529     else
530     {
531 
532         /* Release the transmit packet.  */
533         _nx_packet_transmit_release(packet_ptr);
534     }
535 }
536 #endif /* !NX_DISABLE_IPV4  */
537 
538