[4696] | 1 | /** @file WARP_ip_udp.h |
---|
| 2 | * @brief WARP IP/UDP Library |
---|
| 3 | * |
---|
| 4 | * @copyright Copyright 2015, Mango Communications. All rights reserved. |
---|
| 5 | * Distributed under the WARP license (http://warpproject.org/license) |
---|
| 6 | * |
---|
| 7 | * @author Chris Hunter (chunter [at] mangocomm.com) |
---|
| 8 | * @author Patrick Murphy (murphpo [at] mangocomm.com) |
---|
| 9 | * @author Erik Welsh (welsh [at] mangocomm.com) |
---|
| 10 | */ |
---|
| 11 | |
---|
| 12 | // How to use: |
---|
| 13 | // |
---|
| 14 | // To use the WARP IP/UDP Library, code should include the following files: |
---|
| 15 | // |
---|
| 16 | // #include "WARP_ip_udp.h" |
---|
| 17 | // #include "WARP_ip_udp_device.h" |
---|
| 18 | // |
---|
| 19 | // These files define the public API for the library. |
---|
| 20 | // |
---|
| 21 | // |
---|
| 22 | // Ethernet resources: |
---|
| 23 | // |
---|
| 24 | // - http://en.wikipedia.org/wiki/Ethernet_frame |
---|
| 25 | // - http://en.wikipedia.org/wiki/EtherType |
---|
| 26 | // - http://en.wikipedia.org/wiki/IPv4 |
---|
| 27 | // - http://en.wikipedia.org/wiki/User_Datagram_Protocol |
---|
| 28 | // - http://en.wikipedia.org/wiki/Jumbo_frame |
---|
| 29 | // - http://en.wikipedia.org/wiki/Address_Resolution_Protocol |
---|
| 30 | // - http://en.wikipedia.org/wiki/Internet_Control_Message_Protocol |
---|
| 31 | // - http://en.wikipedia.org/wiki/Network_socket |
---|
| 32 | // |
---|
| 33 | // The WARP IP/UDP library supports jumbo and non-jumbo Ethernet frames carrying IP/UDP traffic. This library |
---|
| 34 | // does not support TCP traffic, but does support ARP and IMCP to allow usage with standard host OSes (Window, OSX, |
---|
| 35 | // Linux). It also implements a partial socket API to manage connections to hosts. |
---|
| 36 | // |
---|
| 37 | // NOTE: The CRC/FCS checksum for an Ethernet frame will be computed by the Ethernet hardware module. |
---|
| 38 | // NOTE: Currently, the WARP IP/UDP Library only supports IPv4 |
---|
| 39 | // |
---|
| 40 | // |
---|
| 41 | // Design Considerations: |
---|
| 42 | // |
---|
| 43 | // Due to processing alignment constraints, WARP nodes require most data to be at least word aligned (ie 32 bit |
---|
| 44 | // aligned). However, a standard UDP/IP Ethernet Header is 42 bytes (ie. 14 bytes for the Ethernet header; |
---|
| 45 | // 20 bytes for IP header; 8 bytes for the UDP header) which is not 32 bit aligned. Therefore, one issue that |
---|
| 46 | // the library has to deal with is what to do with the two bytes to align the data. In previous versions of the |
---|
| 47 | // library, the two bytes were considered part of the WARPLab / WARPNet transport header. This was fine because |
---|
| 48 | // the library would always have contiguous data for Ethernet packets. In this version of the library, to |
---|
| 49 | // reduce processing overhead for large data transfers, we are using the scatter gather capabilities of the AXI DMA. |
---|
| 50 | // Therefore, it becomes necessary to consider the padding as part of the UDP/IP Ethernet Header since that will |
---|
| 51 | // align the pieces of data correctly. |
---|
| 52 | // |
---|
| 53 | // Previously, when transmitting data, the WARPLab / WARPNet transports would copy the data from the given memory, |
---|
| 54 | // such as DDR, into the Ethernet send buffer, usually via the CDMA, before using the AXI DMA to copy the data |
---|
| 55 | // to the Ethernet controller to be sent out over the wire. This double copy of data is not really necessary |
---|
| 56 | // given the AXI DMA has scatter gather capabilities. However, the WARPxilnet driver required the double copy |
---|
| 57 | // because it had to support multiple Ethernet interface peripherals (ie AXI FIFO, TEMAC, etc). Given the WARP |
---|
| 58 | // IP/UDP Library only supports AXI DMA, there is no longer a need to enforce the double copy. However, this requires |
---|
| 59 | // that the library align each piece of data for the Ethernet packet to make sure that there are not alignment |
---|
| 60 | // processing issues in the rest of the software framework. |
---|
| 61 | // |
---|
| 62 | // Therefore, for transmitting data, the library will generally split the Ethernet packet into two or three |
---|
| 63 | // segments: |
---|
| 64 | // 1) WARP IP/UDP Header (includes Ethernet, IP, and UDP headers along with a 2 byte delimiter) - 44 bytes |
---|
| 65 | // 2) WARPNet Header(s) (includes WARPNet Transport, Command / Response, and other headers) - (12 to 32 bytes) |
---|
| 66 | // 3) Packet Data (could be contiguous or non-contiguous with the WARPNet Header(s)) |
---|
| 67 | // |
---|
| 68 | // with each segment starting on a 32-bit aligned value. |
---|
| 69 | // |
---|
| 70 | // However, when receiving data, we will always have to perform a double copy due to limitations with the Xilinx |
---|
| 71 | // IP. The AXI DMA requires that all of the buffer space for the Ethernet packet be specified a priori. This |
---|
| 72 | // means that unless the library processes the AXI stream directly through a dedicated peripheral, it is |
---|
| 73 | // impossible to decode the packet such that the library could direct the data to its final resting place with |
---|
| 74 | // only a single copy unless some restrictions are introduced to communication between the host and the WARP node |
---|
| 75 | // that are not suitable for a reference design. |
---|
| 76 | // |
---|
| 77 | // |
---|
| 78 | // |
---|
| 79 | // Naming Conventions: |
---|
| 80 | // |
---|
| 81 | // In general, the library tries to be as explicit as possible when naming variables. There is a tradeoff between |
---|
| 82 | // name length and specificity so the library tries to balance those competing forces. One area that needs some |
---|
| 83 | // greater clarification is the use of "length" vs "size". In general, the library will use the term "length" to |
---|
| 84 | // indicate the number of contiguous items (ie how long an array or structure is), while the term "size" refers to |
---|
| 85 | // the number of allocated items (ie the space of an array or structure). For example, in the warp_ip_udp_buffer: |
---|
| 86 | // |
---|
| 87 | // - "max_size" refers to the number of bytes allocated by the library for the buffer (ie if you access |
---|
| 88 | // data[max_size], you will have overflowed the buffer since C arrays are zero indexed). |
---|
| 89 | // - "size" refers to the number of bytes populated in the buffer (ie the size of the data in buffer) |
---|
| 90 | // - "length" refers to the number of remaining bytes from the offset (ie the length of the remaining bytes in the |
---|
| 91 | // buffer). This value should be adjusted as a buffer is processed and the offset changes |
---|
| 92 | // |
---|
| 93 | // Hopefully, this does not cause too much confusion. |
---|
| 94 | // |
---|
| 95 | // |
---|
| 96 | // |
---|
| 97 | // Structure: |
---|
| 98 | // |
---|
| 99 | // In general, the library tries to follow standard socket programming conventions. The WARP node acts like a |
---|
| 100 | // socket server listening on the multiple sockets. For example, in WARPLab, the node will listen on a unicast socket |
---|
| 101 | // for direct node messages and a broadcast socket for triggers and other broadcast messages (ie the server looks for |
---|
| 102 | // messages on two different ports). The WARP IP/UDP Library supports two use cases: |
---|
| 103 | // |
---|
| 104 | // 1) The node is acting as a server receiving and responding to commands from a client (this includes responses |
---|
| 105 | // that may contain multiple Ethernet frames) |
---|
| 106 | // |
---|
| 107 | // 2) The node is asynchronously sending data to a destination address. |
---|
| 108 | // |
---|
| 109 | // The second use case is considered a slight extension to the first use case in that the data send asynchronously |
---|
| 110 | // are not commands that require responses (ie the library does not support a socket client model, where it sends |
---|
| 111 | // commands and expects responses from a server). This simplified use model and some hardware limitations results |
---|
| 112 | // in some situations where the library has to deviate from standard socket conventions. |
---|
| 113 | // |
---|
| 114 | // In a standard OS environment, there is enough memory and buffering, that the OS is able to keep packets around |
---|
| 115 | // long enough to support the polling of multiple sockets in series (see socket recv / recvfrom which only checks a |
---|
| 116 | // single port to see if it has data). However, to support WARP based reference designs, the WARP IP/UDP Library must |
---|
| 117 | // limit its memory / compute footprint so that as many resources as possible are available to the reference design. Also, |
---|
| 118 | // given that most WARP reference designs look for messages on multiple ports, the library needs to shift the focus |
---|
| 119 | // of how messages are received. Therefore, the library receive processing is built around a given Ethernet device |
---|
| 120 | // (ie, the physical Ethernet peripheral, for example Eth A or Eth B on the WARP v3 hardware) vs a given socket. When |
---|
| 121 | // the library executes a socket_recvfrom_eth() call, this will first check that there is a Ethernet frame on the given |
---|
| 122 | // Ethernet device, and then as part of the packet processing determine what socket the packet is associated with. This |
---|
| 123 | // allows the library to more efficiently process packets destined to multiple sockets. |
---|
| 124 | // |
---|
| 125 | // One of the consequences of this Ethernet device centric processing is that the concept of binding sockets is a |
---|
| 126 | // bit different. In a standard OS environment, sockets are able to simplify programming in multihomed hosts (ie, hosts |
---|
| 127 | // that have more than one network interface and address) through the use of the constant INADDR_ANY for the IP address. |
---|
| 128 | // When receiving, a socket bound to this address receives packets from all interfaces. When sending, a socket bound with |
---|
| 129 | // INADDR_ANY binds to the default IP address, which is that of the lowest-numbered interface. However, to reduce the |
---|
| 130 | // potential for confusion, the WARP IP/UDP Library requires explicit binding of sockets to an Ethernet device. This means |
---|
| 131 | // that the INADDR_ANY functionality is not supported and the application would need to create an individual socket for |
---|
| 132 | // each Ethernet device. |
---|
| 133 | // |
---|
| 134 | // However, on the send path, we can follow standard socket programming. Since the socket is bound to an Ethernet |
---|
| 135 | // device, when sending data on that socket, it will be sent to the associated Ethernet device. This is why there is |
---|
| 136 | // not a socket_sendto_eth() function, only socket_sendto(). This allows the library to reduce the number of arguments |
---|
| 137 | // that must be passed around since only the socket index is required for the library to know how to send the packet. |
---|
| 138 | // |
---|
| 139 | // |
---|
| 140 | // |
---|
| 141 | // Extensions: |
---|
| 142 | // |
---|
| 143 | // Given the current structure of the WARP IP/UDP Library, it would be straightforward to abstract away the Ethernet |
---|
| 144 | // device centric nature of the receive processing chain from the WARP applications. In the current polling framework, |
---|
| 145 | // this would add processing overhead since it would require checking both Ethernet devices on any given poll. If |
---|
| 146 | // Ethernet processing was moved from a polling framework to an interrupt based framework, this would be a logical |
---|
| 147 | // extension to implement since it would no longer require the additional overhead. |
---|
| 148 | // |
---|
| 149 | // Additionally, it would be straightforward to move the framework from a polling based to an interrupt based |
---|
| 150 | // framework. The easiest way to implement this would be to create a global queue of packets to be processed |
---|
| 151 | // that would be fed by the ISRs. For example, you could have an ISR similar to this to feed packet into a global |
---|
| 152 | // processing queue: |
---|
| 153 | // |
---|
| 154 | // void transport_isr_eth_A() { |
---|
| 155 | // int recv_bytes = 0; |
---|
| 156 | // int socket_index; |
---|
| 157 | // warp_ip_udp_buffer * recv_buffer = transport_alloc_transport_buffer(); |
---|
| 158 | // sockaddr * from = transport_alloc_sockaddr(); |
---|
| 159 | // |
---|
| 160 | // // Check the socket to see if there is data |
---|
| 161 | // recv_bytes = socket_recvfrom_eth(ETH_A_MAC, &socket_index, from, recv_buffer); |
---|
| 162 | // |
---|
| 163 | // // If we have received data, then we need to process it |
---|
| 164 | // if (recv_bytes > 0) { |
---|
| 165 | // // Add the packet to the global queue to be processed |
---|
| 166 | // transport_add_packet(socket_index, from, recv_buffer); |
---|
| 167 | // } |
---|
| 168 | // } |
---|
| 169 | // |
---|
| 170 | // Then in the main processing loop, you can poll a function like this to process a packet: |
---|
| 171 | // |
---|
| 172 | // void transport_process_packets() { |
---|
| 173 | // int socket_index; |
---|
| 174 | // warp_transport_packet * recv_packet; |
---|
| 175 | // |
---|
| 176 | // // Check that there is a packet in the global queue |
---|
| 177 | // if (transport_has_packet()) { |
---|
| 178 | // |
---|
| 179 | // // Allocate a send buffer from the transport driver |
---|
| 180 | // send_buffer = socket_alloc_send_buffer(); |
---|
| 181 | // |
---|
| 182 | // // Get data from the global packet queue |
---|
| 183 | // recv_packet = tranport_get_packet(); |
---|
| 184 | // |
---|
| 185 | // // Process the received packet |
---|
| 186 | // transport_receive(recv_packet->socket_index, recv_packet->from, recv_packet->buffer, send_buffer); |
---|
| 187 | // |
---|
| 188 | // // Need to communicate to the transport driver that the buffers can now be reused |
---|
| 189 | // socket_free_rcvd_buffer(socket_index, recv_buffer); |
---|
| 190 | // socket_free_send_buffer(send_buffer); |
---|
| 191 | // transport_free_packet(recv_packet); |
---|
| 192 | // } |
---|
| 193 | // } |
---|
| 194 | // |
---|
| 195 | // where a warp_transport_packet would be defined as: |
---|
| 196 | // |
---|
| 197 | // typedef struct { |
---|
| 198 | // int socket_index; |
---|
| 199 | // struct sockaddr * from; |
---|
| 200 | // warp_ip_udp_buffer * buffer; |
---|
| 201 | // } warp_transport_packet; |
---|
| 202 | // |
---|
| 203 | // |
---|
| 204 | // The thing to remember is that you should not perform the processing of the packet by the WARP application |
---|
| 205 | // within the ISR. One other challenge is to make sure that there is enough buffering within the library |
---|
| 206 | // and global data structures so that no packets are lost. Currently, the library uses static memory allocation |
---|
| 207 | // based on the BSP configuration, but using a larger memory space, like DDR, and moving to a dynamic allocation |
---|
| 208 | // scheme could help with this. |
---|
| 209 | // |
---|
| 210 | // Additionally, it would not be difficult to add the INADDR_ANY functionality as part of these extensions |
---|
| 211 | // to the library. This would require modification to the udp_process_packet() function to apply the port |
---|
| 212 | // check to sockets both for the current Ethernet device as well as sockets for INADDR_ANY. However, it would |
---|
| 213 | // require the application to understand which Ethernet device packets were going to be sent on since that would |
---|
| 214 | // move from an explicitly defined value to an implicitly defined value in the case where a socket had an IP |
---|
| 215 | // address of INADDR_ANY. |
---|
| 216 | // |
---|
| 217 | // |
---|
| 218 | // |
---|
| 219 | // |
---|
| 220 | |
---|
| 221 | |
---|
| 222 | /***************************** Include Files *********************************/ |
---|
| 223 | |
---|
| 224 | // Xilinx / Standard library includes |
---|
| 225 | #include <xil_types.h> |
---|
| 226 | |
---|
| 227 | |
---|
| 228 | /*************************** Constant Definitions ****************************/ |
---|
| 229 | #ifndef WARP_IP_UDP_H_ |
---|
| 230 | #define WARP_IP_UDP_H_ |
---|
| 231 | |
---|
| 232 | |
---|
| 233 | // ********************************************************************** |
---|
| 234 | // WARP IP/UDP Library Version Information |
---|
| 235 | // |
---|
| 236 | |
---|
| 237 | // Version info (vMAJOR_MINOR_REV) |
---|
| 238 | // MAJOR and MINOR are both u8, while REV is char |
---|
| 239 | // |
---|
| 240 | #define WARP_IP_UDP_VER_MAJOR 1 |
---|
| 241 | #define WARP_IP_UDP_VER_MINOR 0 |
---|
| 242 | #define WARP_IP_UDP_VER_REV a |
---|
| 243 | |
---|
| 244 | |
---|
| 245 | |
---|
| 246 | // ********************************************************************** |
---|
| 247 | // WARP IP/UDP Library Common Defines |
---|
| 248 | // |
---|
| 249 | |
---|
| 250 | #define WARP_IP_UDP_DELIM 0xFFFF // Value of transport delimiter |
---|
| 251 | #define WARP_IP_UDP_DELIM_LEN 2 // Length of transport delimiter (ie padding) (in bytes) |
---|
| 252 | |
---|
| 253 | #define WARP_IP_UDP_SUCCESS 0 // Return value for library success |
---|
| 254 | #define WARP_IP_UDP_FAILURE -1 // Return value for library failure |
---|
| 255 | |
---|
| 256 | // Ethernet device defines |
---|
| 257 | #define WARP_IP_UDP_INVALID_ETH_DEVICE 0xFFFF // Invalid Ethernet device number |
---|
| 258 | #define WARP_IP_UDP_ALL_ETH_DEVICES 0xFFFFFFFF // All Ethernet devices |
---|
| 259 | |
---|
| 260 | |
---|
| 261 | // ********************************************************************** |
---|
| 262 | // WARP IP/UDP Library Ethernet Defines |
---|
| 263 | // |
---|
| 264 | |
---|
| 265 | #define ETH_MAC_ADDR_LEN 6 // Length of Ethernet MAC address (in bytes) |
---|
| 266 | #define ETH_HEADER_LEN 14 // Length of Ethernet Header (in bytes) |
---|
| 267 | |
---|
| 268 | #define ETH_MIN_FRAME_LEN 60 // Length of minimum Ethernet frame (in bytes) |
---|
| 269 | #define ETH_MAX_FRAME_LEN 9014 // Length of maximum Ethernet frame (in bytes) |
---|
| 270 | // - Support for jumbo frames |
---|
| 271 | |
---|
| 272 | #define ETHERTYPE_IP_V4 0x0800 // EtherType: IPv4 packet |
---|
| 273 | #define ETHERTYPE_ARP 0x0806 // EtherType: ARP packet |
---|
| 274 | |
---|
| 275 | |
---|
| 276 | // ********************************************************************** |
---|
| 277 | // WARP IP/UDP Library IP Defines |
---|
| 278 | // |
---|
| 279 | |
---|
| 280 | #define IP_VERSION_4 4 // IP version 4 |
---|
| 281 | #define IP_ADDR_LEN 4 // Length of IP address (in bytes) |
---|
| 282 | |
---|
| 283 | // NOTE: For all transmitted IP packets, IHL == 5 (ie the library always uses the minimum IP header length) |
---|
| 284 | #define IP_HEADER_LEN 5 // Length of IP header (in 32-bit words) |
---|
| 285 | #define IP_HEADER_LEN_BYTES 20 // Length of IP header (in bytes) (ie 5 words * 4 bytes / word) |
---|
| 286 | |
---|
| 287 | // The WARP IP/UDP Library is best effort |
---|
| 288 | // See http://en.wikipedia.org/wiki/Differentiated_services |
---|
| 289 | // |
---|
| 290 | #define IP_DSCP_CS0 0 // IP Precedence: Best Effort |
---|
| 291 | |
---|
| 292 | // The WARP IP/UDP Library is not ECN capable |
---|
| 293 | // See http://en.wikipedia.org/wiki/Explicit_Congestion_Notification |
---|
| 294 | // |
---|
| 295 | #define IP_ECN_NON_ECT 0 // Non ECN-Capable Transport |
---|
| 296 | |
---|
| 297 | // Fragmentation |
---|
| 298 | // |
---|
| 299 | #define IP_NO_FRAGMENTATION 0 // No fragmentation |
---|
| 300 | #define IP_DF_FRAGMENT 0x4000 // "Don't Fragment" bit |
---|
| 301 | |
---|
| 302 | // Default TTL |
---|
| 303 | // See http://en.wikipedia.org/wiki/Time_to_live |
---|
| 304 | #define IP_DEFAULT_TTL 0x40 // Default TTL is 64 per recommendation |
---|
| 305 | |
---|
| 306 | // Supported IP protocols |
---|
| 307 | // See http://en.wikipedia.org/wiki/List_of_IP_protocol_numbers |
---|
| 308 | // |
---|
| 309 | #define IP_PROTOCOL_IMCP 0x01 // Internet Control Message Protocol (IMCP) |
---|
| 310 | #define IP_PROTOCOL_UDP 0x11 // User Datagram Protocol (UDP) |
---|
| 311 | |
---|
| 312 | |
---|
| 313 | // ********************************************************************** |
---|
| 314 | // WARP IP/UDP Library UDP Defines |
---|
| 315 | // |
---|
| 316 | |
---|
| 317 | #define UDP_HEADER_LEN 8 // Length of UDP header (in bytes) |
---|
| 318 | |
---|
| 319 | #define UDP_NO_CHECKSUM 0x0000 // Value if no checksum is generated by the transmitter |
---|
| 320 | |
---|
| 321 | |
---|
| 322 | // ********************************************************************** |
---|
| 323 | // WARP IP/UDP Library ARP Defines |
---|
| 324 | // |
---|
| 325 | |
---|
| 326 | #define ARP_IPV4_PACKET_LEN 28 // Length of IPv4 ARP packet (in bytes) |
---|
| 327 | |
---|
| 328 | // ARP Hardware Types |
---|
| 329 | #define ARP_HTYPE_ETH 0x0001 // Hardware Type: Ethernet (big endian) |
---|
| 330 | |
---|
| 331 | // ARP Operation |
---|
| 332 | #define ARP_REQUEST 0x0001 // ARP Request |
---|
| 333 | #define ARP_REPLY 0x0002 // ARP Reply |
---|
| 334 | |
---|
| 335 | |
---|
| 336 | // ********************************************************************** |
---|
| 337 | // WARP IP/UDP Library IMCP Defines |
---|
| 338 | // |
---|
| 339 | |
---|
| 340 | #define IMCP_HEADER_LEN 8 // Length of IMCP header (in bytes) |
---|
| 341 | |
---|
| 342 | #define ICMP_ECHO_REQUEST_TYPE 0x0008 // Echo Request (Ping) |
---|
| 343 | #define ICMP_ECHO_REPLY_TYPE 0x0000 // Echo Reply (Ping) |
---|
| 344 | #define ICMP_ECHO_CODE 0x0000 // Echo Request / Reply code |
---|
| 345 | |
---|
| 346 | |
---|
| 347 | // ********************************************************************** |
---|
| 348 | // WARP IP/UDP Library Socket Defines |
---|
| 349 | // |
---|
| 350 | |
---|
| 351 | // Socket Types |
---|
| 352 | #define SOCK_STREAM 1 // Socket stream (connection) (tcp) |
---|
| 353 | #define SOCK_DGRAM 2 // Socket datagram (connectionless) (udp) |
---|
| 354 | |
---|
| 355 | // Address Families |
---|
| 356 | #define AF_UNIX 1 // Local to host (pipes, portals) |
---|
| 357 | #define AF_INET 2 // Inter-network: UDP, TCP, etc. |
---|
| 358 | |
---|
| 359 | // WARP IP/UDP Library socket defines |
---|
| 360 | #define SOCKET_INVALID_SOCKET -1 // Socket is invalid |
---|
| 361 | |
---|
| 362 | |
---|
| 363 | // ********************************************************************** |
---|
| 364 | // WARP IP/UDP Library Header Defines |
---|
| 365 | // |
---|
| 366 | #define WARP_IP_UDP_HEADER_LEN (ETH_HEADER_LEN + IP_HEADER_LEN_BYTES + UDP_HEADER_LEN + WARP_IP_UDP_DELIM_LEN) |
---|
| 367 | |
---|
| 368 | |
---|
| 369 | |
---|
| 370 | /***************************** Macro Definitions *****************************/ |
---|
| 371 | |
---|
| 372 | // ********************************************************************** |
---|
| 373 | // WARP IP/UDP Library Ethernet Macros |
---|
| 374 | // |
---|
| 375 | |
---|
| 376 | // Convert Ethernet device number to WARP convention (ie ETH A or ETH B) |
---|
| 377 | #define warp_conv_eth_dev_num(x) (char)(((int)'A') + x) |
---|
| 378 | |
---|
| 379 | |
---|
| 380 | |
---|
| 381 | /*********************** Global Structure Definitions ************************/ |
---|
| 382 | |
---|
| 383 | // ********************************************************************** |
---|
| 384 | // WARP IP/UDP Library Common Structures |
---|
| 385 | // |
---|
| 386 | |
---|
| 387 | // WARP IP/UDP buffer |
---|
| 388 | // Describes a buffer of data with maximum length of 2^32 bytes |
---|
| 389 | // |
---|
| 390 | typedef struct { |
---|
| 391 | u32 state; // State of the buffer |
---|
| 392 | u32 max_size; // Maximum size of the buffer (in bytes) (ie number of bytes allocated; immutable) |
---|
| 393 | u32 size; // Size of the buffer data (in bytes) (ie total number of data bytes populated in the buffer) |
---|
| 394 | u8 * data; // Pointer to the buffer data |
---|
| 395 | u8 * offset; // Pointer to offset within the buffer data |
---|
| 396 | u32 length; // Length of remaining data in the buffer from the offset (ie length = (data + size) - offset) |
---|
| 397 | void * descriptor; // A pointer to a buffer descriptor (optional) |
---|
| 398 | } warp_ip_udp_buffer; |
---|
| 399 | |
---|
| 400 | |
---|
| 401 | // ********************************************************************** |
---|
| 402 | // WARP IP/UDP Library Ethernet Structures |
---|
| 403 | // |
---|
| 404 | |
---|
| 405 | typedef struct { |
---|
| 406 | u8 dest_mac_addr[ETH_MAC_ADDR_LEN]; // Destination MAC address |
---|
| 407 | u8 src_mac_addr[ETH_MAC_ADDR_LEN]; // Source MAC address |
---|
| 408 | u16 ethertype; // EtherType |
---|
| 409 | } ethernet_header; |
---|
| 410 | |
---|
| 411 | |
---|
| 412 | // ********************************************************************** |
---|
| 413 | // WARP IP/UDP Library IP Structures |
---|
| 414 | // |
---|
| 415 | |
---|
| 416 | typedef struct { |
---|
| 417 | u8 version_ihl; // [7:4] Version; [3:0] Internet Header Length |
---|
| 418 | u8 dscp_ecn; // [7:2] Differentiated Services Code Point; [1:0] Explicit Congestion Notification |
---|
| 419 | u16 total_length; // Total Length (includes header and data - in bytes) |
---|
| 420 | u16 identification; // Identification |
---|
| 421 | u16 fragment_offset; // [15:14] Flags; [13:0] Fragment offset |
---|
| 422 | u8 ttl; // Time To Live |
---|
| 423 | u8 protocol; // Protocol |
---|
| 424 | u16 header_checksum; // IP header checksum |
---|
| 425 | u32 src_ip_addr; // Source IP address (big endian) |
---|
| 426 | u32 dest_ip_addr; // Destination IP address (big endian) |
---|
| 427 | } ipv4_header; |
---|
| 428 | |
---|
| 429 | |
---|
| 430 | // ********************************************************************** |
---|
| 431 | // WARP IP/UDP Library UDP Structures |
---|
| 432 | // |
---|
| 433 | |
---|
| 434 | // udp header structure |
---|
| 435 | typedef struct { |
---|
| 436 | u16 src_port; // Source port number |
---|
| 437 | u16 dest_port; // Destination port number |
---|
| 438 | u16 length; // Length of UDP header and UDP data (in bytes) |
---|
| 439 | u16 checksum; // Checksum |
---|
| 440 | } udp_header; |
---|
| 441 | |
---|
| 442 | |
---|
| 443 | // ********************************************************************** |
---|
| 444 | // WARP IP/UDP Library ARP Structures |
---|
| 445 | // - NOTE: The WARP IP/UDP Library only support IPv4 ARP |
---|
| 446 | // |
---|
| 447 | |
---|
| 448 | typedef struct { |
---|
| 449 | u16 htype; // Hardware Type |
---|
| 450 | u16 ptype; // Protocol Type |
---|
| 451 | u8 hlen; // Length of Hardware address |
---|
| 452 | u8 plen; // Length of Protocol address |
---|
| 453 | u16 oper; // Operation |
---|
| 454 | u8 sender_haddr[ETH_MAC_ADDR_LEN]; // Sender hardware address |
---|
| 455 | u8 sender_paddr[IP_ADDR_LEN]; // Sender protocol address |
---|
| 456 | u8 target_haddr[ETH_MAC_ADDR_LEN]; // Target hardware address |
---|
| 457 | u8 target_paddr[IP_ADDR_LEN]; // Target protocol address |
---|
| 458 | } arp_ipv4_packet; |
---|
| 459 | |
---|
| 460 | |
---|
| 461 | // ********************************************************************** |
---|
| 462 | // WARP IP/UDP Library IMCP Structures |
---|
| 463 | // NOTE: The WARP IP/UDP Library only support Echo Reply |
---|
| 464 | // http://en.wikipedia.org/wiki/Ping_(networking_utility) |
---|
| 465 | // |
---|
| 466 | |
---|
| 467 | typedef struct { |
---|
| 468 | u8 type; // IMCP Type |
---|
| 469 | u8 code; // IMCP subtype |
---|
| 470 | u16 checksum; // Header checksum (only IMCP part of packet) |
---|
| 471 | u32 rest; // Rest of Header (4 bytes that vary based on IMCP type and code) |
---|
| 472 | } imcp_header; |
---|
| 473 | |
---|
| 474 | |
---|
| 475 | typedef struct { |
---|
| 476 | u8 type; // IMCP Type |
---|
| 477 | u8 code; // IMCP subtype |
---|
| 478 | u16 checksum; // Header checksum (only IMCP part of packet) |
---|
| 479 | u16 identifier; // Ping identifier |
---|
| 480 | u16 seq_num; // Ping sequence number |
---|
| 481 | } imcp_echo_header; |
---|
| 482 | |
---|
| 483 | |
---|
| 484 | // ********************************************************************** |
---|
| 485 | // WARP IP/UDP Library Combined Data Structures |
---|
| 486 | // |
---|
| 487 | |
---|
| 488 | // WARP IP/UDP Library header |
---|
| 489 | // Describes the header of a standard UDP/IP Ethernet packet, aligned to 32 bits |
---|
| 490 | // |
---|
| 491 | typedef struct __attribute__((__packed__)) { |
---|
| 492 | ethernet_header eth_hdr; |
---|
| 493 | ipv4_header ip_hdr; |
---|
| 494 | udp_header udp_hdr; |
---|
| 495 | u16 delimiter; |
---|
| 496 | } warp_ip_udp_header; |
---|
| 497 | |
---|
| 498 | |
---|
| 499 | |
---|
| 500 | // ********************************************************************** |
---|
| 501 | // WARP IP/UDP Library Socket Structures |
---|
| 502 | // |
---|
| 503 | |
---|
| 504 | // NOTE: To ease processing, each UDP socket should keep track of the WARP IP/UDP Library header |
---|
| 505 | // used for the socket. This header will be transmitted as part of each packet to the |
---|
| 506 | // socket (if indicated). |
---|
| 507 | // |
---|
| 508 | // NOTE: To ease processing, instead of maintaining a struct sockaddr_in within the socket, |
---|
| 509 | // the library splits out the necessary structure fields. This may need to be modified |
---|
| 510 | // in the future if the library needs to support more than UDP sockets. |
---|
| 511 | // |
---|
| 512 | // NOTE: Given the library only supports AF_INET SOCK_DGRAM sockets, the socket does not need to |
---|
| 513 | // keep track of the socket domain or family. However, the socket has the sin_family field |
---|
| 514 | // to maintain 32-bit data alignment within the structure. |
---|
| 515 | // |
---|
| 516 | typedef struct { |
---|
| 517 | u32 index; // Index of the socket |
---|
| 518 | u32 state; // State of the socket |
---|
| 519 | u32 eth_dev_num; // Ethernet device associated with the sockets |
---|
| 520 | |
---|
| 521 | // Necessary fields of struct sockaddr_in |
---|
| 522 | u16 sin_family; // Family of the socket (only used for data alignment) |
---|
| 523 | u16 sin_port; // Port of the socket |
---|
| 524 | u32 sin_addr; // IP address of the socket |
---|
| 525 | |
---|
| 526 | warp_ip_udp_header * hdr; // WARP IP/UDP Library header associated with the socket |
---|
| 527 | } warp_ip_udp_socket; |
---|
| 528 | |
---|
| 529 | |
---|
| 530 | // ********************************************************************** |
---|
| 531 | // Standard Socket Structures |
---|
| 532 | // NOTE: These structures use standard socket naming conventions for compatibility. |
---|
| 533 | // |
---|
| 534 | |
---|
| 535 | // Internet (IP) address structure |
---|
| 536 | struct in_addr { |
---|
| 537 | u32 s_addr; |
---|
| 538 | }; |
---|
| 539 | |
---|
| 540 | // Socket address structure |
---|
| 541 | struct sockaddr { |
---|
| 542 | u16 sa_family; |
---|
| 543 | u8 sa_data[14]; |
---|
| 544 | }; |
---|
| 545 | |
---|
| 546 | // Internet (IP) socket address structure |
---|
| 547 | struct sockaddr_in { |
---|
| 548 | u16 sin_family; |
---|
| 549 | u16 sin_port; |
---|
| 550 | struct in_addr sin_addr; |
---|
| 551 | u8 sin_zero[8]; // Padding to fill out to 16 bytes |
---|
| 552 | }; |
---|
| 553 | |
---|
| 554 | |
---|
| 555 | |
---|
| 556 | /*************************** Function Prototypes *****************************/ |
---|
| 557 | |
---|
| 558 | // WARP IP/UDP Library functions |
---|
| 559 | int warp_ip_udp_init(); |
---|
| 560 | |
---|
| 561 | // Ethernet Device functions |
---|
| 562 | int eth_init(u32 eth_dev_num, u8 * hw_addr, u8 * ip_addr, u32 verbose); |
---|
| 563 | int eth_start_device(u32 eth_dev_num); |
---|
| 564 | |
---|
[5127] | 565 | void eth_set_interrupt_enable_callback(void(*callback)()); |
---|
| 566 | void eth_set_interrupt_disable_callback(void(*callback)()); |
---|
| 567 | |
---|
[4696] | 568 | int eth_set_ip_addr(u32 eth_dev_num, u8 * ip_addr); |
---|
| 569 | int eth_get_ip_addr(u32 eth_dev_num, u8 * ip_addr); |
---|
| 570 | |
---|
| 571 | int eth_set_hw_addr(u32 eth_dev_num, u8 * hw_addr); |
---|
| 572 | int eth_get_hw_addr(u32 eth_dev_num, u8 * hw_addr); |
---|
| 573 | |
---|
| 574 | int eth_not_in_memory_range(u32 eth_dev_num, u32 hi_addr, u32 lo_addr); |
---|
| 575 | int eth_set_operating_speed(u32 eth_dev_num, u32 speed); |
---|
| 576 | int eth_read_phy_reg(u32 eth_dev_num, u32 phy_addr, u32 reg_addr, u16 * reg_value); |
---|
| 577 | int eth_write_phy_reg(u32 eth_dev_num, u32 phy_addr, u32 reg_addr, u16 reg_value); |
---|
| 578 | |
---|
| 579 | int eth_get_num_tx_descriptors(); |
---|
| 580 | |
---|
| 581 | // IP functions |
---|
| 582 | void ipv4_update_header(ipv4_header * header, u32 dest_ip_addr, u16 ip_length, u8 protocol); |
---|
| 583 | |
---|
| 584 | // ARP functions |
---|
| 585 | void arp_send_request(u32 eth_dev_num, u8 * target_haddr, u8 * target_paddr); |
---|
| 586 | void arp_send_announcement(u32 eth_dev_num); |
---|
| 587 | |
---|
| 588 | int arp_update_cache(u32 eth_dev_num, u8 * hw_addr, u8 * ip_addr); |
---|
| 589 | int arp_get_hw_addr(u32 eth_dev_num, u8 * hw_addr, u8 * ip_addr); |
---|
| 590 | |
---|
| 591 | // Socket functions |
---|
| 592 | int socket_socket(int domain, int type, int protocol); |
---|
| 593 | int socket_bind_eth(int socket_index, u32 eth_dev_num, u16 port); |
---|
| 594 | int socket_sendto(int socket_index, struct sockaddr * to, warp_ip_udp_buffer ** buffers, u32 num_buffers); |
---|
| 595 | int socket_sendto_raw(int socket_index, warp_ip_udp_buffer ** buffers, u32 num_buffers); |
---|
| 596 | int socket_recvfrom_eth(u32 eth_dev_num, int * socket_index, struct sockaddr * from, warp_ip_udp_buffer * buffer); |
---|
| 597 | void socket_close(int socket_index); |
---|
| 598 | |
---|
| 599 | u32 socket_get_eth_dev_num(int socket_index); |
---|
| 600 | warp_ip_udp_header * socket_get_warp_ip_udp_header(int socket_index); |
---|
| 601 | |
---|
| 602 | warp_ip_udp_buffer * socket_alloc_send_buffer(); |
---|
| 603 | void socket_free_send_buffer(warp_ip_udp_buffer * buffer); |
---|
| 604 | |
---|
| 605 | void socket_free_recv_buffer(int socket_index, warp_ip_udp_buffer * buffer); |
---|
| 606 | |
---|
| 607 | #endif // WARP_IP_UDP_H_ |
---|