VirtualBox

source: vbox/trunk/include/iprt/net.h@ 106967

Last change on this file since 106967 was 106061, checked in by vboxsync, 2 months ago

Copyright year updates by scm.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 35.5 KB
Line 
1/** @file
2 * IPRT - Network Protocols.
3 */
4
5/*
6 * Copyright (C) 2008-2024 Oracle and/or its affiliates.
7 *
8 * This file is part of VirtualBox base platform packages, as
9 * available from https://www.virtualbox.org.
10 *
11 * This program is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU General Public License
13 * as published by the Free Software Foundation, in version 3 of the
14 * License.
15 *
16 * This program is distributed in the hope that it will be useful, but
17 * WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 * General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, see <https://www.gnu.org/licenses>.
23 *
24 * The contents of this file may alternatively be used under the terms
25 * of the Common Development and Distribution License Version 1.0
26 * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
27 * in the VirtualBox distribution, in which case the provisions of the
28 * CDDL are applicable instead of those of the GPL.
29 *
30 * You may elect to license modified versions of this file under the
31 * terms and conditions of either the GPL or the CDDL or both.
32 *
33 * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
34 */
35
36#ifndef IPRT_INCLUDED_net_h
37#define IPRT_INCLUDED_net_h
38#ifndef RT_WITHOUT_PRAGMA_ONCE
39# pragma once
40#endif
41
42#include <iprt/cdefs.h>
43#include <iprt/types.h>
44#include <iprt/assert.h>
45
46
47RT_C_DECLS_BEGIN
48
49/** @defgroup grp_rt_net RTNet - Network Protocols
50 * @ingroup grp_rt
51 * @{
52 */
53
54/**
55 * Converts an stringified Ethernet MAC address into the RTMAC representation.
56 *
57 * @todo This should be move to some generic part of the runtime.
58 *
59 * @returns VINF_SUCCESS on success, VERR_GETOPT_INVALID_ARGUMENT_FORMAT on
60 * failure.
61 *
62 * @param pszAddr The address string to convert.
63 * @param pMacAddr Where to store the result.
64 */
65RTDECL(int) RTNetStrToMacAddr(const char *pszAddr, PRTMAC pMacAddr);
66
67/**
68 * IPv4 address.
69 */
70typedef RTUINT32U RTNETADDRIPV4;
71AssertCompileSize(RTNETADDRIPV4, 4);
72/** Pointer to a IPv4 address. */
73typedef RTNETADDRIPV4 *PRTNETADDRIPV4;
74/** Pointer to a const IPv4 address. */
75typedef RTNETADDRIPV4 const *PCRTNETADDRIPV4;
76
77/**
78 * Tests if the given string is an IPv4 address.
79 *
80 * @returns boolean.
81 * @param pcszAddr String which may be an IPv4 address.
82 */
83RTDECL(bool) RTNetIsIPv4AddrStr(const char *pcszAddr);
84
85/**
86 * Tests if the given string is a wildcard IPv4 address.
87 *
88 * @returns boolean.
89 * @param pcszAddr String which may be an IPv4 address.
90 */
91RTDECL(bool) RTNetStrIsIPv4AddrAny(const char *pcszAddr);
92
93/**
94 * Parses dotted-decimal IPv4 address into RTNETADDRIPV4 representation.
95 *
96 * @returns VINF_SUCCESS on success, VERR_INVALID_PARAMETER on
97 * failure.
98 *
99 * @param pcszAddr The value to convert.
100 * @param ppszNext Where to store the pointer to the first char
101 * following the address. (Optional)
102 * @param pAddr Where to store the result.
103 */
104RTDECL(int) RTNetStrToIPv4AddrEx(const char *pcszAddr, PRTNETADDRIPV4 pAddr, char **ppszNext);
105
106/**
107 * Parses dotted-decimal IPv4 address into RTNETADDRIPV4 representation.
108 * Leading and trailing whitespace is ignored.
109 *
110 * @returns VINF_SUCCESS on success, VERR_INVALID_PARAMETER on
111 * failure.
112 *
113 * @param pcszAddr The value to convert.
114 * @param pAddr Where to store the result.
115 */
116RTDECL(int) RTNetStrToIPv4Addr(const char *pcszAddr, PRTNETADDRIPV4 pAddr);
117
118/**
119 * Parses dotted-decimal IPv4 CIDR notation into RTNETADDRIPV4
120 * representation and prefix length. Missing prefix specification is
121 * treated as exact address specification (prefix length 32). Leading
122 * and trailing whitespace is ignored.
123 *
124 * @returns VINF_SUCCESS on success, VERR_INVALID_PARAMETER on
125 * failure.
126 *
127 * @param pcszAddr The value to convert.
128 * @param pAddr Where to store the address.
129 * @param piPrefix Where to store the prefix length;
130 */
131RTDECL(int) RTNetStrToIPv4Cidr(const char *pcszAddr, PRTNETADDRIPV4 pAddr, int *piPrefix);
132
133/**
134 * Verifies that RTNETADDRIPV4 is a valid contiguous netmask and
135 * computes its prefix length.
136 *
137 * @returns VINF_SUCCESS on success, VERR_INVALID_PARAMETER on
138 * failure.
139 *
140 * @param pMask The netmask to verify and convert.
141 * @param piPrefix Where to store the prefix length. (Optional)
142 */
143RTDECL(int) RTNetMaskToPrefixIPv4(PCRTNETADDRIPV4 pMask, int *piPrefix);
144
145/**
146 * Computes netmask corresponding to the prefix length.
147 *
148 * @returns VINF_SUCCESS on success, VERR_INVALID_PARAMETER on
149 * failure.
150 *
151 * @param iPrefix The prefix to convert.
152 * @param pMask Where to store the netmask.
153 */
154RTDECL(int) RTNetPrefixToMaskIPv4(int iPrefix, PRTNETADDRIPV4 pMask);
155
156/**
157 * Initializes an IPv4 address from four octets.
158 *
159 * @returns The address (network endian).
160 * @param b3 The 4th and the most significant address octet.
161 * @param b2 The 3rd address octet.
162 * @param b1 The 2nd address octet.
163 * @param b0 The 1st and least significant address octet.
164 */
165DECLINLINE(RTNETADDRIPV4) RTNetIPv4AddrFromU8(uint8_t b3, uint8_t b2, uint8_t b1, uint8_t b0)
166{
167 RTNETADDRIPV4 Ret;
168#ifdef RT_LITTLE_ENDIAN
169 Ret.u = RT_MAKE_U32_FROM_U8( b3, b2, b1, b0);
170#else
171 Ret.u = RT_MAKE_U32_FROM_MSB_U8(b3, b2, b1, b0);
172#endif
173 return Ret;
174}
175
176/**
177 * Initializes an IPv4 address from four octets, host endian version.
178 *
179 * @returns The address (host endian).
180 * @param b3 The 4th and the most significant address octet.
181 * @param b2 The 3rd address octet.
182 * @param b1 The 2nd address octet.
183 * @param b0 The 1st and least significant address octet.
184 */
185DECLINLINE(RTNETADDRIPV4) RTNetIPv4AddrHEFromU8(uint8_t b3, uint8_t b2, uint8_t b1, uint8_t b0)
186{
187 RTNETADDRIPV4 Ret;
188 Ret.u = RT_MAKE_U32_FROM_MSB_U8(b3, b2, b1, b0);
189 return Ret;
190}
191
192#ifdef RTNET_INCL_IN_ADDR
193
194/**
195 * Initializes an struct in_addr from four octets
196 *
197 * @returns The in_addr (network endian).
198 * @param b3 The 4th and the most significant address octet.
199 * @param b2 The 3rd address octet.
200 * @param b1 The 2nd address octet.
201 * @param b0 The 1st and least significant address octet.
202 */
203DECLINLINE(struct in_addr) RTNetInAddrFromU8(uint8_t b3, uint8_t b2, uint8_t b1, uint8_t b0)
204{
205 struct in_addr Ret;
206# ifdef RT_LITTLE_ENDIAN
207 Ret.s_addr = RT_MAKE_U32_FROM_U8( b3, b2, b1, b0);
208# else
209 Ret.s_addr = RT_MAKE_U32_FROM_MSB_U8(b3, b2, b1, b0);
210# endif
211 return Ret;
212}
213
214/**
215 * Converts an IPv4 address to the struct in_addr format.
216 *
217 * @returns Converted address (network endian).
218 * @param pAddr The IPv4 address to convert (network endian).
219 */
220DECLINLINE(struct in_addr) RTNetIPv4AddrToInAddr(PCRTNETADDRIPV4 pAddr)
221{
222 struct in_addr Ret;
223 Ret.s_addr = pAddr->u;
224 return Ret;
225}
226
227# ifdef IPRT_INCLUDED_asm_h /* for ASMByteSwapU32 */
228/**
229 * Converts an IPv4 address to the struct in_addr format, host endian version.
230 *
231 * @returns Converted address (network endian).
232 * @param pAddr The IPv4 address to convert - host endian.
233 */
234DECLINLINE(struct in_addr) RTNetIPv4AddrHEToInAddr(PCRTNETADDRIPV4 pAddr)
235{
236 struct in_addr Ret;
237 Ret.s_addr = RT_H2N_U32(pAddr->u);
238 return Ret;
239}
240# endif
241
242/**
243 * Converts an IPv4 address to the struct in_addr format.
244 *
245 * @returns Converted address (network endian).
246 * @param pInAddr The in_addr to convert (network endian).
247 */
248DECLINLINE(RTNETADDRIPV4) RTNetIPv4AddrFromInAddr(struct in_addr const *pInAddr)
249{
250 RTNETADDRIPV4 Ret;
251 Ret.u = pInAddr->s_addr;
252 return Ret;
253}
254
255# ifdef IPRT_INCLUDED_asm_h /* for ASMByteSwapU32 */
256/**
257 * Converts an IPv4 address to the struct in_addr format, host endian version.
258 *
259 * @returns Converted address (host endian).
260 * @param pInAddr The in_addr to convert (network endian).
261 */
262DECLINLINE(RTNETADDRIPV4) RTNetIPv4AddrHEFromInAddr(struct in_addr const *pInAddr)
263{
264 RTNETADDRIPV4 Ret;
265 Ret.u = RT_N2H_U32(pInAddr->s_addr);
266 return Ret;
267}
268# endif
269
270#endif /* RTNET_INCL_IN_ADDR */
271
272
273/**
274 * IPv6 address.
275 */
276typedef RTUINT128U RTNETADDRIPV6;
277AssertCompileSize(RTNETADDRIPV6, 16);
278/** Pointer to a IPv6 address. */
279typedef RTNETADDRIPV6 *PRTNETADDRIPV6;
280/** Pointer to a const IPv6 address. */
281typedef RTNETADDRIPV6 const *PCRTNETADDRIPV6;
282
283/**
284 * Tests if the given string is a valid IPv6 address.
285 *
286 * @returns @c true if it is, @c false if not.
287 * @param pszAddress String which may be an IPv6 address.
288 */
289RTDECL(bool) RTNetIsIPv6AddrStr(const char *pszAddress);
290
291/**
292 * Tests if the given string is a wildcard IPv6 address.
293 *
294 * @returns @c true if it is, @c false if not.
295 * @param pszAddress String which may be an IPv6 address.
296 */
297RTDECL(bool) RTNetStrIsIPv6AddrAny(const char *pszAddress);
298
299/**
300 * Parses IPv6 address into RTNETADDRIPV6 representation.
301 *
302 * @returns VINF_SUCCESS on success, VERR_INVALID_PARAMETER on
303 * failure.
304 *
305 * @param pcszAddr The value to convert.
306 * @param ppszNext Where to store the pointer to the first char
307 * following the address. (Optional)
308 * @param pAddr Where to store the result.
309 */
310RTDECL(int) RTNetStrToIPv6AddrEx(const char *pcszAddr, PRTNETADDRIPV6 pAddr, char **ppszNext);
311
312/**
313 * Parses IPv6 address into RTNETADDRIPV6 representation.
314 * Leading and trailing whitespace is ignored.
315 *
316 * @returns VINF_SUCCESS on success, VERR_INVALID_PARAMETER on
317 * failure.
318 *
319 * @param pcszAddr The value to convert.
320 * @param ppszZone Where to store the pointer to the first char
321 * of the zone id. NULL is stored if there is
322 * no zone id.
323 * @param pAddr Where to store the result.
324 */
325RTDECL(int) RTNetStrToIPv6Addr(const char *pcszAddr, PRTNETADDRIPV6 pAddr, char **ppszZone);
326
327/**
328 * Verifies that RTNETADDRIPV6 is a valid contiguous netmask and
329 * computes its prefix length.
330 *
331 * @returns VINF_SUCCESS on success, VERR_INVALID_PARAMETER on
332 * failure.
333 *
334 * @param pMask The netmask to verify and convert.
335 * @param piPrefix Where to store the prefix length. (Optional)
336 */
337RTDECL(int) RTNetMaskToPrefixIPv6(PCRTNETADDRIPV6 pMask, int *piPrefix);
338
339/**
340 * Computes netmask corresponding to the prefix length.
341 *
342 * @returns VINF_SUCCESS on success, VERR_INVALID_PARAMETER on
343 * failure.
344 *
345 * @param iPrefix The prefix to convert.
346 * @param pMask Where to store the netmask.
347 */
348RTDECL(int) RTNetPrefixToMaskIPv6(int iPrefix, PRTNETADDRIPV6 pMask);
349
350/**
351 * Parses IPv6 prefix notation into RTNETADDRIPV6 representation and
352 * prefix length. Missing prefix specification is treated as exact
353 * address specification (prefix length 128). Leading and trailing
354 * whitespace is ignored.
355 *
356 * "CIDR" in the name is a misnomer as IPv6 doesn't have network
357 * classes, but is parallel to the IPv4 name (and naming things is
358 * hard).
359 *
360 * @returns VINF_SUCCESS on success, VERR_INVALID_PARAMETER on
361 * failure.
362 *
363 * @param pcszAddr The value to convert.
364 * @param pAddr Where to store the address.
365 * @param piPrefix Where to store the prefix length;
366 */
367RTDECL(int) RTNetStrToIPv6Cidr(const char *pcszAddr, PRTNETADDRIPV6 pAddr, int *piPrefix);
368
369
370/**
371 * IPX address.
372 */
373#pragma pack(1)
374typedef struct RTNETADDRIPX
375{
376 /** The network ID. */
377 uint32_t Network;
378 /** The node ID. (Defaults to the MAC address apparently.) */
379 RTMAC Node;
380} RTNETADDRIPX;
381#pragma pack()
382AssertCompileSize(RTNETADDRIPX, 4+6);
383/** Pointer to an IPX address. */
384typedef RTNETADDRIPX *PRTNETADDRIPX;
385/** Pointer to a const IPX address. */
386typedef RTNETADDRIPX const *PCRTNETADDRIPX;
387
388/**
389 * Network address union.
390 *
391 * @remarks The size of this structure may change in the future.
392 */
393typedef union RTNETADDRU
394{
395 /** 64-bit view. */
396 uint64_t au64[2];
397 /** 32-bit view. */
398 uint32_t au32[4];
399 /** 16-bit view. */
400 uint16_t au16[8];
401 /** 8-bit view. */
402 uint8_t au8[16];
403 /** IPv4 view. */
404 RTNETADDRIPV4 IPv4;
405#ifndef IPv6 /* Work around X11 and RDP defining IPv6 to 1. */
406 /** IPv6 view. */
407 RTNETADDRIPV6 IPv6;
408#endif
409 /** IPX view. */
410 RTNETADDRIPX Ipx;
411 /** MAC address view. */
412 RTMAC Mac;
413} RTNETADDRU;
414AssertCompileSize(RTNETADDRU, 16);
415/** Pointer to an address union. */
416typedef RTNETADDRU *PRTNETADDRU;
417/** Pointer to a const address union. */
418typedef RTNETADDRU const *PCRTNETADDRU;
419
420/**
421 * Network address type.
422 *
423 * @remarks The value assignments may change in the future.
424 */
425typedef enum RTNETADDRTYPE
426{
427 /** The invalid 0 entry. */
428 RTNETADDRTYPE_INVALID = 0,
429 /** IP version 4. */
430 RTNETADDRTYPE_IPV4,
431 /** IP version 6. */
432 RTNETADDRTYPE_IPV6,
433 /** IPX. */
434 RTNETADDRTYPE_IPX,
435 /** MAC address. */
436 RTNETADDRTYPE_MAC,
437 /** The end of the valid values. */
438 RTNETADDRTYPE_END,
439 /** The usual 32-bit hack. */
440 RTNETADDRTYPE_32_BIT_HACK = 0x7fffffff
441} RTNETADDRTYPE;
442/** Pointer to a network address type. */
443typedef RTNETADDRTYPE *PRTNETADDRTYPE;
444/** Pointer to a const network address type. */
445typedef RTNETADDRTYPE const *PCRTNETADDRTYPE;
446
447/**
448 * Network address.
449 *
450 * @remarks The size and type values may change.
451 */
452typedef struct RTNETADDR
453{
454 /** The address union. */
455 RTNETADDRU uAddr;
456 /** Indicates which view of @a u that is valid. */
457 RTNETADDRTYPE enmType;
458 /** The port number for IPv4 and IPv6 addresses. This is set to
459 * RTNETADDR_NA_PORT if not applicable. */
460 uint32_t uPort;
461} RTNETADDR;
462/** Pointer to a network address. */
463typedef RTNETADDR *PRTNETADDR;
464/** Pointer to a const network address. */
465typedef RTNETADDR const *PCRTNETADDR;
466
467/** The not applicable value of RTNETADDR::uPort value use to inid. */
468#define RTNETADDR_PORT_NA UINT32_MAX
469
470/**
471 * Ethernet header.
472 */
473#pragma pack(1)
474typedef struct RTNETETHERHDR
475{
476 RTMAC DstMac;
477 RTMAC SrcMac;
478 /** Ethernet frame type or frame size, depending on the kind of ethernet.
479 * This is big endian on the wire. */
480 uint16_t EtherType;
481} RTNETETHERHDR;
482#pragma pack()
483AssertCompileSize(RTNETETHERHDR, 14);
484/** Pointer to an ethernet header. */
485typedef RTNETETHERHDR *PRTNETETHERHDR;
486/** Pointer to a const ethernet header. */
487typedef RTNETETHERHDR const *PCRTNETETHERHDR;
488
489/** @name EtherType (RTNETETHERHDR::EtherType)
490 * @{ */
491#define RTNET_ETHERTYPE_IPV4 UINT16_C(0x0800)
492#define RTNET_ETHERTYPE_ARP UINT16_C(0x0806)
493#define RTNET_ETHERTYPE_IPV6 UINT16_C(0x86dd)
494#define RTNET_ETHERTYPE_VLAN UINT16_C(0x8100)
495#define RTNET_ETHERTYPE_IPX_1 UINT16_C(0x8037)
496#define RTNET_ETHERTYPE_IPX_2 UINT16_C(0x8137)
497#define RTNET_ETHERTYPE_IPX_3 UINT16_C(0x8138)
498/** @} */
499
500
501/**
502 * IPv4 header.
503 * All is bigendian on the wire.
504 */
505#pragma pack(1)
506typedef struct RTNETIPV4
507{
508#ifdef RT_BIG_ENDIAN
509 unsigned int ip_v : 4;
510 unsigned int ip_hl : 4;
511 unsigned int ip_tos : 8;
512 unsigned int ip_len : 16;
513#else
514 /** 00:0 - Header length given as a 32-bit word count. */
515 unsigned int ip_hl : 4;
516 /** 00:4 - Header version. */
517 unsigned int ip_v : 4;
518 /** 01 - Type of service. */
519 unsigned int ip_tos : 8;
520 /** 02 - Total length (header + data). */
521 unsigned int ip_len : 16;
522#endif
523 /** 04 - Packet idenficiation. */
524 uint16_t ip_id;
525 /** 06 - Offset if fragmented. */
526 uint16_t ip_off;
527 /** 08 - Time to live. */
528 uint8_t ip_ttl;
529 /** 09 - Protocol. */
530 uint8_t ip_p;
531 /** 0a - Header check sum. */
532 uint16_t ip_sum;
533 /** 0c - Source address. */
534 RTNETADDRIPV4 ip_src;
535 /** 10 - Destination address. */
536 RTNETADDRIPV4 ip_dst;
537 /** 14 - Options (optional). */
538 uint32_t ip_options[1];
539} RTNETIPV4;
540#pragma pack()
541AssertCompileSize(RTNETIPV4, 6 * 4);
542/** Pointer to a IPv4 header. */
543typedef RTNETIPV4 *PRTNETIPV4;
544/** Pointer to a const IPv4 header. */
545typedef RTNETIPV4 const *PCRTNETIPV4;
546
547/** The minimum IPv4 header length (in bytes).
548 * Up to and including RTNETIPV4::ip_dst. */
549#define RTNETIPV4_MIN_LEN (20)
550
551
552/** @name IPv4 Protocol Numbers
553 * @{ */
554/** IPv4: ICMP */
555#define RTNETIPV4_PROT_ICMP (1)
556/** IPv4: TCP */
557#define RTNETIPV4_PROT_TCP (6)
558/** IPv4: UDP */
559#define RTNETIPV4_PROT_UDP (17)
560/** @} */
561
562/** @name Common IPv4 Port Assignments
563 * @{
564 */
565/** Boostrap Protocol / DHCP) Server. */
566#define RTNETIPV4_PORT_BOOTPS (67)
567/** Boostrap Protocol / DHCP) Client. */
568#define RTNETIPV4_PORT_BOOTPC (68)
569/** @} */
570
571/** @name IPv4 Flags
572 * @{ */
573/** IPv4: Don't fragment */
574#define RTNETIPV4_FLAGS_DF (0x4000)
575/** IPv4: More fragments */
576#define RTNETIPV4_FLAGS_MF (0x2000)
577/** @} */
578
579RTDECL(uint16_t) RTNetIPv4HdrChecksum(PCRTNETIPV4 pIpHdr);
580RTDECL(bool) RTNetIPv4IsHdrValid(PCRTNETIPV4 pIpHdr, size_t cbHdrMax, size_t cbPktMax, bool fChecksum);
581RTDECL(uint32_t) RTNetIPv4PseudoChecksum(PCRTNETIPV4 pIpHdr);
582RTDECL(uint32_t) RTNetIPv4PseudoChecksumBits(RTNETADDRIPV4 SrcAddr, RTNETADDRIPV4 DstAddr, uint8_t bProtocol, uint16_t cbPkt);
583RTDECL(uint32_t) RTNetIPv4AddDataChecksum(void const *pvData, size_t cbData, uint32_t u32Sum, bool *pfOdd);
584RTDECL(uint16_t) RTNetIPv4FinalizeChecksum(uint32_t u32Sum);
585
586
587/**
588 * IPv6 header.
589 * All is bigendian on the wire.
590 */
591#pragma pack(1)
592typedef struct RTNETIPV6
593{
594 /** Version (4 bits), Traffic Class (8 bits) and Flow Lable (20 bits).
595 * @todo this is probably mislabeled - ip6_flow vs. ip6_vfc, fix later. */
596 uint32_t ip6_vfc;
597 /** 04 - Payload length, including extension headers. */
598 uint16_t ip6_plen;
599 /** 06 - Next header type (RTNETIPV4_PROT_XXX). */
600 uint8_t ip6_nxt;
601 /** 07 - Hop limit. */
602 uint8_t ip6_hlim;
603 /** xx - Source address. */
604 RTNETADDRIPV6 ip6_src;
605 /** xx - Destination address. */
606 RTNETADDRIPV6 ip6_dst;
607} RTNETIPV6;
608#pragma pack()
609AssertCompileSize(RTNETIPV6, 8 + 16 + 16);
610/** Pointer to a IPv6 header. */
611typedef RTNETIPV6 *PRTNETIPV6;
612/** Pointer to a const IPv6 header. */
613typedef RTNETIPV6 const *PCRTNETIPV6;
614
615/** The minimum IPv6 header length (in bytes).
616 * Up to and including RTNETIPV6::ip6_dst. */
617#define RTNETIPV6_MIN_LEN (40)
618#define RTNETIPV6_ICMPV6_ND_WITH_LLA_OPT_MIN_LEN (32)
619
620RTDECL(uint32_t) RTNetIPv6PseudoChecksum(PCRTNETIPV6 pIpHdr);
621RTDECL(uint32_t) RTNetIPv6PseudoChecksumEx(PCRTNETIPV6 pIpHdr, uint8_t bProtocol, uint16_t cbPkt);
622RTDECL(uint32_t) RTNetIPv6PseudoChecksumBits(PCRTNETADDRIPV6 pSrcAddr, PCRTNETADDRIPV6 pDstAddr,
623 uint8_t bProtocol, uint16_t cbPkt);
624
625
626/**
627 * UDP header.
628 */
629#pragma pack(1)
630typedef struct RTNETUDP
631{
632 /** The source port. */
633 uint16_t uh_sport;
634 /** The destination port. */
635 uint16_t uh_dport;
636 /** The length of the UDP header and associated data. */
637 uint16_t uh_ulen;
638 /** The checksum of the pseudo header, the UDP header and the data. */
639 uint16_t uh_sum;
640} RTNETUDP;
641#pragma pack()
642AssertCompileSize(RTNETUDP, 8);
643/** Pointer to an UDP header. */
644typedef RTNETUDP *PRTNETUDP;
645/** Pointer to a const UDP header. */
646typedef RTNETUDP const *PCRTNETUDP;
647
648/** The minimum UDP packet length (in bytes). (RTNETUDP::uh_ulen) */
649#define RTNETUDP_MIN_LEN (8)
650
651RTDECL(uint16_t) RTNetUDPChecksum(uint32_t u32Sum, PCRTNETUDP pUdpHdr);
652RTDECL(uint32_t) RTNetIPv4AddUDPChecksum(PCRTNETUDP pUdpHdr, uint32_t u32Sum);
653RTDECL(uint16_t) RTNetIPv4UDPChecksum(PCRTNETIPV4 pIpHdr, PCRTNETUDP pUdpHdr, void const *pvData);
654RTDECL(bool) RTNetIPv4IsUDPSizeValid(PCRTNETIPV4 pIpHdr, PCRTNETUDP pUdpHdr, size_t cbPktMax);
655RTDECL(bool) RTNetIPv4IsUDPValid(PCRTNETIPV4 pIpHdr, PCRTNETUDP pUdpHdr, void const *pvData, size_t cbPktMax, bool fChecksum);
656
657
658/**
659 * IPv4 BOOTP / DHCP packet.
660 */
661#pragma pack(1)
662typedef struct RTNETBOOTP
663{
664 /** 00 - The packet opcode (RTNETBOOTP_OP_*). */
665 uint8_t bp_op;
666 /** 01 - Hardware address type. Same as RTNETARPHDR::ar_htype. */
667 uint8_t bp_htype;
668 /** 02 - Hardware address length. */
669 uint8_t bp_hlen;
670 /** 03 - Gateway hops. */
671 uint8_t bp_hops;
672 /** 04 - Transaction ID. */
673 uint32_t bp_xid;
674 /** 08 - Seconds since boot started. */
675 uint16_t bp_secs;
676 /** 0a - Unused (BOOTP) / Flags (DHCP) (RTNET_DHCP_FLAGS_*). */
677 uint16_t bp_flags;
678 /** 0c - Client IPv4 address. */
679 RTNETADDRIPV4 bp_ciaddr;
680 /** 10 - Your IPv4 address. */
681 RTNETADDRIPV4 bp_yiaddr;
682 /** 14 - Server IPv4 address. */
683 RTNETADDRIPV4 bp_siaddr;
684 /** 18 - Gateway IPv4 address. */
685 RTNETADDRIPV4 bp_giaddr;
686 /** 1c - Client hardware address. */
687 union
688 {
689 uint8_t au8[16];
690 RTMAC Mac;
691 } bp_chaddr;
692 /** 2c - Server name. */
693 uint8_t bp_sname[64];
694 /** 6c - File name / more DHCP options. */
695 uint8_t bp_file[128];
696 /** ec - Vendor specific area (BOOTP) / Options (DHCP).
697 * @remark This is really 312 bytes in the DHCP version. */
698 union
699 {
700 uint8_t au8[128];
701 struct DHCP
702 {
703 /** ec - The DHCP cookie (RTNET_DHCP_COOKIE). */
704 uint32_t dhcp_cookie;
705 /** f0 - The DHCP options. */
706 uint8_t dhcp_opts[124];
707 } Dhcp;
708 } bp_vend;
709
710} RTNETBOOTP;
711#pragma pack()
712AssertCompileSize(RTNETBOOTP, 0xec + 128);
713/** Pointer to a BOOTP / DHCP packet. */
714typedef RTNETBOOTP *PRTNETBOOTP;
715/** Pointer to a const BOOTP / DHCP packet. */
716typedef RTNETBOOTP const *PCRTNETBOOTP;
717
718/** Minimum BOOTP packet length. For quick validation, no standard thing really. */
719#define RTNETBOOTP_MIN_LEN 0xec
720/** Minimum DHCP packet length. For quick validation, no standard thing really. */
721#define RTNETBOOTP_DHCP_MIN_LEN 0xf1
722
723/** The normal size of the a DHCP packet (i.e. a RTNETBOOTP).
724 * Same as RTNET_DHCP_OPT_SIZE, just expressed differently. */
725#define RTNET_DHCP_NORMAL_SIZE (0xec + 4 + RTNET_DHCP_OPT_SIZE)
726/** The normal size of RTNETBOOTP::bp_vend::Dhcp::dhcp_opts. */
727#define RTNET_DHCP_OPT_SIZE (312 - 4)
728
729/** @name BOOTP packet opcode values
730 * @{ */
731#define RTNETBOOTP_OP_REQUEST 1
732#define RTNETBOOTP_OP_REPLY 2
733/** @} */
734
735/** @name DHCP flags (RTNETBOOTP::bp_flags)
736 * @{ */
737#define RTNET_DHCP_FLAGS_NO_BROADCAST UINT16_C(0x8000) /** @todo check test!!! */
738/** @} */
739
740/** The DHCP cookie (network endian). */
741#define RTNET_DHCP_COOKIE UINT32_C(0x63825363)
742
743/**
744 * An IPv4 DHCP option header.
745 */
746typedef struct RTNETDHCPOPT
747{
748 /** 00 - The DHCP option. */
749 uint8_t dhcp_opt;
750 /** 01 - The data length (excluding this header). */
751 uint8_t dhcp_len;
752 /* 02 - The option data follows here, optional and of variable length. */
753} RTNETDHCPOPT;
754AssertCompileSize(RTNETDHCPOPT, 2);
755/** Pointer to a DHCP option header. */
756typedef RTNETDHCPOPT *PRTNETDHCPOPT;
757/** Pointer to a const DHCP option header. */
758typedef RTNETDHCPOPT const *PCRTNETDHCPOPT;
759
760/** @name DHCP options
761 * @{ */
762/** 1 byte padding, this has no dhcp_len field. */
763#define RTNET_DHCP_OPT_PAD 0
764
765/** The subnet mask. */
766#define RTNET_DHCP_OPT_SUBNET_MASK 1
767/** The time offset. */
768#define RTNET_DHCP_OPT_TIME_OFFSET 2
769/** The routers for the subnet. */
770#define RTNET_DHCP_OPT_ROUTERS 3
771/** Domain Name Server. */
772#define RTNET_DHCP_OPT_DNS 6
773/** Host name. */
774#define RTNET_DHCP_OPT_HOST_NAME 12
775/** Domain name. */
776#define RTNET_DHCP_OPT_DOMAIN_NAME 15
777
778/** The requested address. */
779#define RTNET_DHCP_OPT_REQ_ADDR 50
780/** The lease time in seconds. */
781#define RTNET_DHCP_OPT_LEASE_TIME 51
782/** Option overload.
783 * Indicates that the bp_file and/or bp_sname holds contains DHCP options. */
784#define RTNET_DHCP_OPT_OPTION_OVERLOAD 52
785/** Have a 8-bit message type value as data, see RTNET_DHCP_MT_*. */
786#define RTNET_DHCP_OPT_MSG_TYPE 53
787/** Server ID. */
788#define RTNET_DHCP_OPT_SERVER_ID 54
789/** Parameter request list. */
790#define RTNET_DHCP_OPT_PARAM_REQ_LIST 55
791/** The maximum DHCP message size a client is willing to accept. */
792#define RTNET_DHCP_OPT_MAX_DHCP_MSG_SIZE 57
793/** Client ID. */
794#define RTNET_DHCP_OPT_CLIENT_ID 61
795/** TFTP server name. */
796#define RTNET_DHCP_OPT_TFTP_SERVER_NAME 66
797/** Bootfile name. */
798#define RTNET_DHCP_OPT_BOOTFILE_NAME 67
799
800/** Marks the end of the DHCP options, this has no dhcp_len field. */
801#define RTNET_DHCP_OPT_END 255
802/** @} */
803
804/** @name DHCP Option overload flags (option 52)
805 * @{ */
806#define RTNET_DHCP_OPTION_OVERLOAD_FILE 1
807#define RTNET_DHCP_OPTION_OVERLOAD_SNAME 2
808#define RTNET_DHCP_OPTION_OVERLOAD_MASK 3
809/** @} */
810
811/** @name DHCP Message Types (option 53)
812 * @{ */
813#define RTNET_DHCP_MT_DISCOVER 1
814#define RTNET_DHCP_MT_OFFER 2
815#define RTNET_DHCP_MT_REQUEST 3
816#define RTNET_DHCP_MT_DECLINE 4
817#define RTNET_DHCP_MT_ACK 5
818#define RTNET_DHCP_MT_NAC 6
819#define RTNET_DHCP_MT_RELEASE 7
820#define RTNET_DHCP_MT_INFORM 8
821/** @} */
822
823/** @name DHCP Flags
824 * @{ */
825#define RTNET_DHCP_FLAG_BROADCAST 0x8000
826/** @} */
827
828RTDECL(bool) RTNetIPv4IsDHCPValid(PCRTNETUDP pUdpHdr, PCRTNETBOOTP pDhcp, size_t cbDhcp, uint8_t *pMsgType);
829
830
831/**
832 * IPv4 DHCP packet.
833 * @deprecated Use RTNETBOOTP.
834 */
835#pragma pack(1)
836typedef struct RTNETDHCP
837{
838 /** 00 - The packet opcode. */
839 uint8_t Op;
840 /** Hardware address type. */
841 uint8_t HType;
842 /** Hardware address length. */
843 uint8_t HLen;
844 uint8_t Hops;
845 uint32_t XID;
846 uint16_t Secs;
847 uint16_t Flags;
848 /** Client IPv4 address. */
849 RTNETADDRIPV4 CIAddr;
850 /** Your IPv4 address. */
851 RTNETADDRIPV4 YIAddr;
852 /** Server IPv4 address. */
853 RTNETADDRIPV4 SIAddr;
854 /** Gateway IPv4 address. */
855 RTNETADDRIPV4 GIAddr;
856 /** Client hardware address. */
857 uint8_t CHAddr[16];
858 /** Server name. */
859 uint8_t SName[64];
860 uint8_t File[128];
861 uint8_t abMagic[4];
862 uint8_t DhcpOpt;
863 uint8_t DhcpLen; /* 1 */
864 uint8_t DhcpReq;
865 uint8_t abOptions[57];
866} RTNETDHCP;
867#pragma pack()
868/** @todo AssertCompileSize(RTNETDHCP, ); */
869/** Pointer to a DHCP packet. */
870typedef RTNETDHCP *PRTNETDHCP;
871/** Pointer to a const DHCP packet. */
872typedef RTNETDHCP const *PCRTNETDHCP;
873
874
875/**
876 * TCP packet.
877 */
878#pragma pack(1)
879typedef struct RTNETTCP
880{
881 /** 00 - The source port. */
882 uint16_t th_sport;
883 /** 02 - The destination port. */
884 uint16_t th_dport;
885 /** 04 - The sequence number. */
886 uint32_t th_seq;
887 /** 08 - The acknowledgement number. */
888 uint32_t th_ack;
889#ifdef RT_BIG_ENDIAN
890 unsigned int th_win : 16;
891 unsigned int th_flags : 8;
892 unsigned int th_off : 4;
893 unsigned int th_x2 : 4;
894#else
895 /** 0c:0 - Reserved. */
896 unsigned int th_x2 : 4;
897 /** 0c:4 - The data offset given as a dword count from the start of this header. */
898 unsigned int th_off : 4;
899 /** 0d - flags. */
900 unsigned int th_flags : 8;
901 /** 0e - The window. */
902 unsigned int th_win : 16;
903#endif
904 /** 10 - The checksum of the pseudo header, the TCP header and the data. */
905 uint16_t th_sum;
906 /** 12 - The urgent pointer. */
907 uint16_t th_urp;
908 /* (options follows here and then the data (aka text).) */
909} RTNETTCP;
910#pragma pack()
911AssertCompileSize(RTNETTCP, 20);
912/** Pointer to a TCP packet. */
913typedef RTNETTCP *PRTNETTCP;
914/** Pointer to a const TCP packet. */
915typedef RTNETTCP const *PCRTNETTCP;
916
917/** The minimum TCP header length (in bytes). (RTNETTCP::th_off * 4) */
918#define RTNETTCP_MIN_LEN (20)
919
920/** @name TCP flags (RTNETTCP::th_flags)
921 * @{ */
922#define RTNETTCP_F_FIN 0x01
923#define RTNETTCP_F_SYN 0x02
924#define RTNETTCP_F_RST 0x04
925#define RTNETTCP_F_PSH 0x08
926#define RTNETTCP_F_ACK 0x10
927#define RTNETTCP_F_URG 0x20
928#define RTNETTCP_F_ECE 0x40
929#define RTNETTCP_F_CWR 0x80
930/** @} */
931
932RTDECL(uint16_t) RTNetTCPChecksum(uint32_t u32Sum, PCRTNETTCP pTcpHdr, void const *pvData, size_t cbData);
933RTDECL(uint32_t) RTNetIPv4AddTCPChecksum(PCRTNETTCP pTcpHdr, uint32_t u32Sum);
934RTDECL(uint16_t) RTNetIPv4TCPChecksum(PCRTNETIPV4 pIpHdr, PCRTNETTCP pTcpHdr, void const *pvData);
935RTDECL(bool) RTNetIPv4IsTCPSizeValid(PCRTNETIPV4 pIpHdr, PCRTNETTCP pTcpHdr, size_t cbHdrMax, size_t cbPktMax);
936RTDECL(bool) RTNetIPv4IsTCPValid(PCRTNETIPV4 pIpHdr, PCRTNETTCP pTcpHdr, size_t cbHdrMax, void const *pvData,
937 size_t cbPktMax, bool fChecksum);
938
939
940/**
941 * IPv4 ICMP packet header.
942 */
943#pragma pack(1)
944typedef struct RTNETICMPV4HDR
945{
946 /** 00 - The ICMP message type. */
947 uint8_t icmp_type;
948 /** 01 - Type specific code that further qualifies the message. */
949 uint8_t icmp_code;
950 /** 02 - Checksum of the ICMP message. */
951 uint16_t icmp_cksum;
952} RTNETICMPV4HDR;
953#pragma pack()
954AssertCompileSize(RTNETICMPV4HDR, 4);
955/** Pointer to an ICMP packet header. */
956typedef RTNETICMPV4HDR *PRTNETICMPV4HDR;
957/** Pointer to a const ICMP packet header. */
958typedef RTNETICMPV4HDR const *PCRTNETICMPV4HDR;
959
960/** @name ICMP (v4) message types.
961 * @{ */
962#define RTNETICMPV4_TYPE_ECHO_REPLY 0
963#define RTNETICMPV4_TYPE_ECHO_REQUEST 8
964#define RTNETICMPV4_TYPE_TRACEROUTE 30
965/** @} */
966
967/**
968 * IPv4 ICMP ECHO Reply & Request packet.
969 */
970#pragma pack(1)
971typedef struct RTNETICMPV4ECHO
972{
973 /** 00 - The ICMP header. */
974 RTNETICMPV4HDR Hdr;
975 /** 04 - The identifier to help the requestor match up the reply.
976 * Can be 0. Typically fixed value. */
977 uint16_t icmp_id;
978 /** 06 - The sequence number to help the requestor match up the reply.
979 * Can be 0. Typically incrementing between requests. */
980 uint16_t icmp_seq;
981 /** 08 - Variable length data that is to be returned unmodified in the reply. */
982 uint8_t icmp_data[1];
983} RTNETICMPV4ECHO;
984#pragma pack()
985AssertCompileSize(RTNETICMPV4ECHO, 9);
986/** Pointer to an ICMP ECHO packet. */
987typedef RTNETICMPV4ECHO *PRTNETICMPV4ECHO;
988/** Pointer to a const ICMP ECHO packet. */
989typedef RTNETICMPV4ECHO const *PCRTNETICMPV4ECHO;
990
991/**
992 * IPv4 ICMP TRACEROUTE packet.
993 * This is an reply to an IP packet with the traceroute option set.
994 */
995#pragma pack(1)
996typedef struct RTNETICMPV4TRACEROUTE
997{
998 /** 00 - The ICMP header. */
999 RTNETICMPV4HDR Hdr;
1000 /** 04 - Identifier copied from the traceroute option's ID number. */
1001 uint16_t icmp_id;
1002 /** 06 - Unused. (Possibly an icmp_seq?) */
1003 uint16_t icmp_void;
1004 /** 08 - Outbound hop count. From the IP packet causing this message. */
1005 uint16_t icmp_ohc;
1006 /** 0a - Return hop count. From the IP packet causing this message. */
1007 uint16_t icmp_rhc;
1008 /** 0c - Output link speed, 0 if not known. */
1009 uint32_t icmp_speed;
1010 /** 10 - Output link MTU, 0 if not known. */
1011 uint32_t icmp_mtu;
1012} RTNETICMPV4TRACEROUTE;
1013#pragma pack()
1014AssertCompileSize(RTNETICMPV4TRACEROUTE, 20);
1015/** Pointer to an ICMP TRACEROUTE packet. */
1016typedef RTNETICMPV4TRACEROUTE *PRTNETICMPV4TRACEROUTE;
1017/** Pointer to a const ICMP TRACEROUTE packet. */
1018typedef RTNETICMPV4TRACEROUTE const *PCRTNETICMPV4TRACEROUTE;
1019
1020/** @todo add more ICMPv4 as needed. */
1021
1022/**
1023 * IPv4 ICMP union packet.
1024 */
1025typedef union RTNETICMPV4
1026{
1027 RTNETICMPV4HDR Hdr;
1028 RTNETICMPV4ECHO Echo;
1029 RTNETICMPV4TRACEROUTE Traceroute;
1030} RTNETICMPV4;
1031/** Pointer to an ICMP union packet. */
1032typedef RTNETICMPV4 *PRTNETICMPV4;
1033/** Pointer to a const ICMP union packet. */
1034typedef RTNETICMPV4 const *PCRTNETICMPV4;
1035
1036
1037/**
1038 * IPv6 ICMP packet header.
1039 */
1040#pragma pack(1)
1041typedef struct RTNETICMPV6HDR
1042{
1043 /** 00 - The ICMPv6 message type. */
1044 uint8_t icmp6_type;
1045 /** 01 - Type specific code that further qualifies the message. */
1046 uint8_t icmp6_code;
1047 /** 02 - Checksum of the ICMPv6 message. */
1048 uint16_t icmp6_cksum;
1049} RTNETICMPV6HDR;
1050#pragma pack()
1051AssertCompileSize(RTNETICMPV6HDR, 4);
1052/** Pointer to an ICMPv6 packet header. */
1053typedef RTNETICMPV6HDR *PRTNETICMPV6HDR;
1054/** Pointer to a const ICMP packet header. */
1055typedef RTNETICMPV6HDR const *PCRTNETICMPV6HDR;
1056
1057#define RTNETIPV6_PROT_ICMPV6 (58)
1058
1059/** @name Internet Control Message Protocol version 6 (ICMPv6) message types.
1060 * @{ */
1061#define RTNETIPV6_ICMP_TYPE_RS 133
1062#define RTNETIPV6_ICMP_TYPE_RA 134
1063#define RTNETIPV6_ICMP_TYPE_NS 135
1064#define RTNETIPV6_ICMP_TYPE_NA 136
1065#define RTNETIPV6_ICMP_TYPE_RDR 137
1066/** @} */
1067
1068/** @name Neighbor Discovery option types
1069 * @{ */
1070#define RTNETIPV6_ICMP_ND_SLLA_OPT (1)
1071#define RTNETIPV6_ICMP_ND_TLLA_OPT (2)
1072/** @} */
1073
1074/** ICMPv6 ND Source/Target Link Layer Address option */
1075#pragma pack(1)
1076typedef struct RTNETNDP_LLA_OPT
1077{
1078 uint8_t type;
1079 uint8_t len;
1080 RTMAC lla;
1081} RTNETNDP_LLA_OPT;
1082#pragma pack()
1083
1084AssertCompileSize(RTNETNDP_LLA_OPT, 1+1+6);
1085
1086typedef RTNETNDP_LLA_OPT *PRTNETNDP_LLA_OPT;
1087typedef RTNETNDP_LLA_OPT const *PCRTNETNDP_LLA_OPT;
1088
1089/** ICMPv6 ND Neighbor Sollicitation */
1090#pragma pack(1)
1091typedef struct RTNETNDP
1092{
1093 /** 00 - The ICMPv6 header. */
1094 RTNETICMPV6HDR Hdr;
1095 /** 04 - reserved */
1096 uint32_t reserved;
1097 /** 08 - target address */
1098 RTNETADDRIPV6 target_address;
1099} RTNETNDP;
1100#pragma pack()
1101AssertCompileSize(RTNETNDP, 4+4+16);
1102/** Pointer to a NDP ND packet. */
1103typedef RTNETNDP *PRTNETNDP;
1104/** Pointer to a const NDP NS packet. */
1105typedef RTNETNDP const *PCRTNETNDP;
1106
1107
1108/**
1109 * Ethernet ARP header.
1110 */
1111#pragma pack(1)
1112typedef struct RTNETARPHDR
1113{
1114 /** The hardware type. */
1115 uint16_t ar_htype;
1116 /** The protocol type (ethertype). */
1117 uint16_t ar_ptype;
1118 /** The hardware address length. */
1119 uint8_t ar_hlen;
1120 /** The protocol address length. */
1121 uint8_t ar_plen;
1122 /** The operation. */
1123 uint16_t ar_oper;
1124} RTNETARPHDR;
1125#pragma pack()
1126AssertCompileSize(RTNETARPHDR, 8);
1127/** Pointer to an ethernet ARP header. */
1128typedef RTNETARPHDR *PRTNETARPHDR;
1129/** Pointer to a const ethernet ARP header. */
1130typedef RTNETARPHDR const *PCRTNETARPHDR;
1131
1132/** ARP hardware type - ethernet. */
1133#define RTNET_ARP_ETHER UINT16_C(1)
1134
1135/** @name ARP operations
1136 * @{ */
1137#define RTNET_ARPOP_REQUEST UINT16_C(1) /**< Request hardware address given a protocol address (ARP). */
1138#define RTNET_ARPOP_REPLY UINT16_C(2)
1139#define RTNET_ARPOP_REVREQUEST UINT16_C(3) /**< Request protocol address given a hardware address (RARP). */
1140#define RTNET_ARPOP_REVREPLY UINT16_C(4)
1141#define RTNET_ARPOP_INVREQUEST UINT16_C(8) /**< Inverse ARP. */
1142#define RTNET_ARPOP_INVREPLY UINT16_C(9)
1143/** Check if an ARP operation is a request or not. */
1144#define RTNET_ARPOP_IS_REQUEST(Op) ((Op) & 1)
1145/** Check if an ARP operation is a reply or not. */
1146#define RTNET_ARPOP_IS_REPLY(Op) (!RTNET_ARPOP_IS_REQUEST(Op))
1147/** @} */
1148
1149
1150/**
1151 * Ethernet IPv4 + 6-byte MAC ARP request packet.
1152 */
1153#pragma pack(1)
1154typedef struct RTNETARPIPV4
1155{
1156 /** ARP header. */
1157 RTNETARPHDR Hdr;
1158 /** The sender hardware address. */
1159 RTMAC ar_sha;
1160 /** The sender protocol address. */
1161 RTNETADDRIPV4 ar_spa;
1162 /** The target hardware address. */
1163 RTMAC ar_tha;
1164 /** The target protocol address. */
1165 RTNETADDRIPV4 ar_tpa;
1166} RTNETARPIPV4;
1167#pragma pack()
1168AssertCompileSize(RTNETARPIPV4, 8+6+4+6+4);
1169/** Pointer to an ethernet IPv4+MAC ARP request packet. */
1170typedef RTNETARPIPV4 *PRTNETARPIPV4;
1171/** Pointer to a const ethernet IPv4+MAC ARP request packet. */
1172typedef RTNETARPIPV4 const *PCRTNETARPIPV4;
1173
1174
1175/** @} */
1176
1177RT_C_DECLS_END
1178
1179#endif /* !IPRT_INCLUDED_net_h */
1180
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette