Line data Source code
1 : #ifndef HEADER_fd_src_util_net_fd_udp_h 2 : #define HEADER_fd_src_util_net_fd_udp_h 3 : 4 : #include "fd_ip4.h" /* UDP is tightly tied to IP regardless of standard intent due to pseudo header layer violating BS */ 5 : 6 : /* FIXME: UDP CRASH COURSE HERE */ 7 : 8 : union fd_udp_hdr { 9 : struct { 10 : ushort net_sport; /* src port, net order */ 11 : ushort net_dport; /* dst port, net order */ 12 : ushort net_len; /* datagram length, from first byte of this header to last byte of the udp payload */ 13 : ushort check; /* UDP checksum ("invariant" order), from first byte of pseudo header prepended before this header to last 14 : byte of udp payload with zero padding to even length inclusive. In IP4, 0 indicates no checksum. */ 15 : }; 16 : uint u[2]; 17 : }; 18 : 19 : typedef union fd_udp_hdr fd_udp_hdr_t; 20 : 21 : /* FIXME: CONSIDER A PRETTY PRINTER FOR A FD_UDP_HDR? */ 22 : 23 : FD_PROTOTYPES_BEGIN 24 : 25 : /* fd_ip4_udp_check is used for udp check field computation and 26 : validation. If the dgram has no checksum (check==0), this returns 27 : the value to use for check. If the dgram has a checksum (check!=0), 28 : this returns 0 if the message has a valid checksum or non-zero if 29 : not. ip4_saddr and ip4_daddr are the ip4 source and destination 30 : addresses to use for the udp pseudo header. udp is a non-NULL 31 : pointer to the first byte of a memory region containing the udp 32 : header and dgram is a non-NULL pointer to the first byte of a memory 33 : region containing a datagram of size: 34 : 35 : dgram_sz = fd_ushort_bswap(udp->net_len) - sizeof(fd_udp_hdr_t) 36 : 37 : bytes. This assumes it is safe to read up to 3 bytes past the end of 38 : dgram (technically it will read the fd_align_up(dgram_sz,4UL) bytes 39 : dgram). The contents of the tail read region are irrelevant. 40 : 41 : This is neither a particularly fast calculation (reasonably fast 42 : O(dgram_sz)) nor a particularly robust and it can inhibit cut-through 43 : usage. So in general it is best to avoid UDP checksums, usually by 44 : exploiting their optionality in IP4 (note that the Ethernet CRC is 45 : reasonably strong and still provides protection). 46 : 47 : As such, this is mostly here for the rare application that needs to 48 : manually compute / validate UDP checksums (e.g. overhead doesn't 49 : matter or when the hardware sending/receiving the packet doesn't do 50 : various checksum offload computations and UDP checksums are 51 : required). 52 : 53 : WARNING! With strict aliasing optimizations enabled and having this 54 : inline, the caller might need to type pun the dgram value passed to 55 : this (e.g. fd_type_pun_const(my_dgram)), wrap their dgram structure 56 : in a union like seen above for the udp_hdr_t or play various games 57 : with the may_alias attribute. fd_type_pun_const is the quickest way 58 : to handle this but can inhibit various optimizations. Wrapping in a 59 : union type is the fastest and most conformant way to handle this. 60 : The compiler is pretty good at catching when this is necessary and 61 : warning about it but be careful here. FIXME: CONSIDER NOT INLINING 62 : THIS? */ 63 : 64 : FD_FN_PURE static inline ushort 65 : fd_ip4_udp_check( uint ip4_saddr, 66 : uint ip4_daddr, 67 : fd_udp_hdr_t const * udp, 68 0 : void const * dgram ) { /* Assumed safe to tail read up to 3 bytes past end of msg */ 69 0 : ushort net_len = udp->net_len; /* In net order */ 70 0 : uint rem = (uint)fd_ushort_bswap( net_len ) - (uint)sizeof(fd_udp_hdr_t); 71 0 : 72 0 : /* Sum the pseudo header and UDP header words */ 73 0 : uint const * u = udp->u; 74 0 : ulong ul = ((((ulong)FD_IP4_HDR_PROTOCOL_UDP)<<8) | (((ulong)net_len)<<16)) 75 0 : + ((ulong)ip4_saddr) 76 0 : + ((ulong)ip4_daddr) 77 0 : + ((ulong)u[0]) 78 0 : + ((ulong)u[1]); 79 0 : 80 0 : /* Sum the dgram words (reads up to 4 past end of msg) */ 81 0 : u = (uint const *)dgram; /* See warning above */ 82 0 : for( ; rem>3U; rem-=4U, u++ ) ul += (ulong)u[0]; 83 0 : ul += (ulong)( u[0] & ((1U<<(8U*rem))-1U) ); 84 0 : 85 0 : /* Reduce the sum to a 16-bit one's complement sum */ 86 0 : ul = ( ul>>32 ) + 87 0 : ((ul>>16) & 0xffffUL) + 88 0 : ( ul & 0xffffUL); 89 0 : ul = ( ul>>16 ) + 90 0 : ( ul & 0xffffUL); 91 0 : ul += ( ul>>16 ); 92 0 : 93 0 : /* And complement it */ 94 0 : return (ushort)~ul; 95 0 : } 96 : 97 : /* fd_udp_hdr_bswap reverses the endianness of all fields in the UDP 98 : header. */ 99 : 100 : static inline void 101 37643694 : fd_udp_hdr_bswap( fd_udp_hdr_t * hdr ) { 102 37643694 : hdr->net_sport = (ushort)fd_ushort_bswap( hdr->net_sport ); 103 37643694 : hdr->net_dport = (ushort)fd_ushort_bswap( hdr->net_dport ); 104 37643694 : hdr->net_len = (ushort)fd_ushort_bswap( hdr->net_len ); 105 37643694 : hdr->check = (ushort)fd_ushort_bswap( hdr->check ); 106 37643694 : } 107 : 108 : FD_PROTOTYPES_END 109 : 110 : #endif /* HEADER_fd_src_util_net_fd_udp_h */