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 | |
---|
565 | void eth_set_interrupt_enable_callback(void(*callback)()); |
---|
566 | void eth_set_interrupt_disable_callback(void(*callback)()); |
---|
567 | |
---|
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_ |
---|