1 /**
2 * @file net.c
3 *
4 * @brief
5 * The file implements the NET Boot Module.
6 *
7 * \par
8 * NOTE:
9 * (C) Copyright 2008, Texas Instruments, Inc.
10 *
11 * \par
12 */
13 #include "types.h"
14 #include "iblloc.h"
15 #include "net.h"
16 #include "netif.h"
17 #include "timer.h"
18 #include "stream.h"
19 #include <string.h>
20 #include "net_osal.h"
23 /**********************************************************************
24 *************************** Local Functions **************************
25 **********************************************************************/
26 static Int32 net_open (void* ptr_driver, void (*asyncComplete)(void *));
27 static Int32 net_close(void);
28 static Int32 net_read (Uint8* ptr_buf, Uint32 num_bytes);
29 static Int32 net_peek (Uint8* ptr_buf, Uint32 num_bytes);
30 static Int32 net_seek (Int32 loc, Int32 from);
31 static Int32 net_query (void);
33 /**********************************************************************
34 *************************** GLOBAL Variables *************************
35 **********************************************************************/
37 /**
38 * @defgroup net_op
39 *
40 * @ingroup net_op
41 * @{
42 *
43 * @brief
44 * Internal definition to distinguish a read from a peek
45 *
46 */
48 /**
49 * @def NET_READ
50 */
51 #define NET_READ 400 /**< Read from the net device */
53 /**
54 * @def NET_PEEK
55 */
56 #define NET_PEEK 420 /**< Peek from the net device */
58 /* @} */
61 /**
62 * @brief This is the NETWORK Master control block which keeps track
63 * of all the Network boot module related information.
64 */
65 NET_MCB netmcb;
67 /**
68 * @brief This keeps track of the network statistics.
69 */
70 NET_STATS net_stats;
72 /**
73 * @brief This is the global Network Boot Module function table which
74 * implements the Boot Module Interface with the kernel.
75 */
76 BOOT_MODULE_FXN_TABLE net_boot_module =
77 {
78 net_open, /* Open API */
79 net_close, /* Close API */
80 net_read, /* Read API */
81 NULL, /* Write API (NULL: This is not interactive) */
82 net_peek, /* Peek API */
83 net_seek, /* Seek API */
84 net_query /* Query API */
85 };
87 /**********************************************************************
88 **************************** NET Functions ***************************
89 **********************************************************************/
91 /**
92 * @b Description
93 * @n
94 * The function is used to allocate a packet for transmission. This
95 * is called by the higher layer protocols when a packet needs to
96 * be transmitted. The function ensures there is sufficient space
97 * allocated at the beginning of the packet for the Ethernet header.
98 * Since the pointer returned by this API is used to store L3/L4 headers
99 * it always returns a 4 byte aligned buffer data pointer.
100 *
101 * @param[in] packet_len
102 * Length of the packet being transmitted.
103 *
104 * @retval
105 * Success - Pointer to the L3 header.
106 * @retval
107 * Error - NULL
108 */
109 Uint8* net_alloc_tx_packet(Int32 packet_len)
110 {
111 /* Sanity Check: Ensure the packet being allocated does not exceed the
112 * max buffer size that we have. */
113 if (packet_len > NET_MAX_MTU)
114 return NULL;
116 /* Sanity Check: Ensure that the packet is available for use. */
117 if (netmcb.txuse == 1)
118 return NULL;
120 /* Mark the packet as being in use. */
121 netmcb.txuse = 1;
123 /* Reset the contents of the packet */
124 netMemset ((void *)&netmcb.tx_packet[0], 0, sizeof(netmcb.tx_packet));
126 /* Reserve some space at the head of the packet for the Ethernet headers. */
127 return &netmcb.tx_packet[16];
128 }
130 /**
131 * @b Description
132 * @n
133 * The function is called to free up a previously allocated transmit
134 * packet.
135 *
136 * @param[in] ptr
137 * Pointer to the packet being cleaned.
138 *
139 * @retval
140 * Not Applicable.
141 */
142 void net_free_tx_packet (Uint8* ptr)
143 {
144 /* Sanity Checks: Ensure that the packet being cleaned is the same as the one
145 * which was allocated. */
146 if (ptr != &netmcb.tx_packet[16])
147 mprintf ("ERROR: NET Free Transmit packet detected corruption\n");
149 /* Sanity Checks: Ensure that there is no double free. */
150 if (netmcb.txuse == 0)
151 mprintf ("ERROR: NET Free Transmit packet detected double free\n");
153 /* Mark the transmit packet as free and available. */
154 netmcb.txuse = 0;
155 return;
156 }
158 /**
159 * @b Description
160 * @n
161 * The function is used to append an Ethernet header on the packet.
162 * The source MAC Address in the packet is always the one which was
163 * registered by the driver. Higher layer protocol authors need to
164 * use the 'net_alloc_tx_packet' API to get a transmit buffer.
165 *
166 * @param[in] ptr_l3_hdr
167 * This is the pointer to the layer3 header.
168 * @param[in] dst_mac
169 * The destination MAC address
170 * @param[in] protocol
171 * The layer3 protocol version (passed in host order)
172 *
173 * @retval
174 * Success - Pointer to the start of the Ethernet header i.e. L2.
175 * @retval
176 * Error - NULL
177 */
178 ETHHDR* net_create_eth_header (Uint8* ptr_l3_hdr, Uint8* dst_mac, Uint16 protocol)
179 {
180 Int32 rsvd_space;
182 /* Compute the reserved space. */
183 rsvd_space = (Int32)ptr_l3_hdr - (Int32)&netmcb.tx_packet[0];
185 /* Ensure there is sufficient space to add the header. We dont want memory corruption
186 * to occur here. */
187 if ((rsvd_space < 0) || (rsvd_space > NET_MAX_MTU) || (rsvd_space < ETHHDR_SIZE))
188 return NULL;
190 /* Convert the protocol to network order. */
191 protocol = ntohs(protocol);
193 /* Start adding the Ethernet header.
194 * Move back the data pointer to account for the protocol. */
195 ptr_l3_hdr = ptr_l3_hdr - 2;
196 netMemcpy ((void *)ptr_l3_hdr, (void *)&protocol, sizeof(Uint16));
198 /* Move back the data pointer to account for the source MAC. */
199 ptr_l3_hdr = ptr_l3_hdr - 6;
200 netMemcpy ((void *)ptr_l3_hdr, (void *)&netmcb.net_device.mac_address[0], 6);
202 /* Move back the data pointer to account for the destination MAC. */
203 ptr_l3_hdr = ptr_l3_hdr - 6;
204 netMemcpy ((void *)ptr_l3_hdr, (void *)dst_mac, 6);
206 /* Return the pointer to the start of the Ethernet header. */
207 return (ETHHDR *)ptr_l3_hdr;
208 }
210 /**
211 * @b Description
212 * @n
213 * The function is used to send a packet to the driver.
214 *
215 * @param[in] ptr_l2_hdr
216 * This is the pointer to the L2 header of the packet to be transmitted.
217 * All the headers need to be populated by the time comes to this API.
218 * @param[in] length
219 * Length of the packet being transmitted. This include the L2 header
220 * information.
221 *
222 * @retval
223 * Not Applicable.
224 */
225 void net_send_packet (ETHHDR* ptr_l2_hdr, Uint16 length)
226 {
227 /* Sanity Check: This is called after the LAYER3 and ETHER headers
228 * have been appended to the packet. Here we ensure that the layer3 header
229 * is aligned on the 4 byte boundary. */
230 if ( (((Uint32)ptr_l2_hdr+ETHHDR_SIZE) % 4) != 0)
231 mprintf ("ERROR: Misaligned Layer3 packet transmitted 0x%p.\n", ptr_l2_hdr);
233 /* Increment the stats. */
234 net_stats.num_pkt_txed++;
236 /* Pass the packet to the platform API for transmission. */
237 netmcb.net_device.send (&netmcb.net_device, (Uint8 *)ptr_l2_hdr, (Int32)length);
238 return;
239 }
241 /**
242 * @b Description
243 * @n
244 * The function is called from any entity inside the NETWORK Boot Module
245 * to indicate that there has been a FATAL error and that the boot module
246 * processing needs to be aborted.
247 *
248 * @retval
249 * Not Applicable.
250 */
251 void net_set_error (void)
252 {
253 /* Set the Error Flag; */
254 netmcb.error_flag = 1;
255 return;
256 }
258 /**
259 * @b Description
260 * @n
261 * The function opens the BLF NET Module. The function initializes
262 * the various internal components of the NET module and also
263 * initializes the peripheral driver controller
264 *
265 * @param[in] ptr_driver
266 * This is the pointer to the driver block which was passed to
267 * the BLF through the BOOT Mode descriptor. For the NET boot
268 * module this points to the NET_DRV_DEVICE object.
269 *
270 * @retval
271 * Success - 0
272 * @retval
273 * Error - <0
274 */
275 static Int32 net_open (void* ptr_driver, void (*asyncComplete)(void *))
276 {
277 NET_DRV_DEVICE* ptr_net_driver;
279 /* Get the pointer to the net driver. */
280 ptr_net_driver = (NET_DRV_DEVICE*)ptr_driver;
282 /* Basic Validation: Ensure there is a valid driver block being passed. */
283 if (ptr_net_driver == NULL)
284 return -1;
286 /* Basic Validation: Ensure that all the required API have been provided */
287 if ((ptr_net_driver->start == NULL) || (ptr_net_driver->send == NULL) ||
288 (ptr_net_driver->receive == NULL) || (ptr_net_driver->stop == NULL))
289 {
290 /* Error: Required API was not specified. */
291 return -1;
292 }
294 /* Initialize the NET MCB. */
295 netMemset (&netmcb, 0, sizeof(NET_MCB));
297 /* Initialize the Network Statistics. */
298 netMemset (&net_stats, 0, sizeof(NET_STATS));
300 /* Copy the driver information into the NET MCB */
301 netMemcpy ((void *)&netmcb.net_device, (void *)ptr_net_driver, sizeof(NET_DRV_DEVICE));
303 /* Initialize the ARP Module. */
304 arp_init ();
306 /* Initialize the IP Module. */
307 ip_init ();
309 /* Initialize the UDP Module. */
310 udp_init ();
312 /* Start the networking device */
313 if (netmcb.net_device.start(&netmcb.net_device) < 0)
314 return -1;
316 /* Determine if we need to execute BOOTP or not? */
317 if (netmcb.net_device.ip_address != 0)
318 {
319 /* IP Address was supplied by the device team. There is no need
320 * to execute the BOOTP protocol; manually create the network route also. */
321 ip_add_route (FLG_RT_NETWORK, netmcb.net_device.ip_address, netmcb.net_device.net_mask, 0);
323 /* Optional call back with boot server info */
324 if (asyncComplete != NULL)
325 (*asyncComplete)((void *)&netmcb.net_device);
327 /* Lets download the file from the TFTP Server. */
328 tftp_get_file (netmcb.net_device.server_ip, netmcb.net_device.file_name);
329 }
330 else
331 {
332 /* No IP Address was supplied we need to execute the BOOTP protocol. */
333 bootp_init (asyncComplete);
334 }
336 /* The network module is UP and running.. */
337 return 0;
338 }
340 /**
341 * @b Description
342 * @n
343 * The function closes the BLF NET Module.
344 *
345 * @retval
346 * Success - 0
347 * @retval
348 * Error - <0
349 */
350 static Int32 net_close (void)
351 {
352 return 0;
353 }
356 /**
357 * @b Description
358 * @n
359 * If a waiting packet is found it is processed
360 */
361 static void proc_packet (void)
362 {
363 Uint8* ptr_data_packet;
364 Int32 packet_size;
365 Uint16 protocol;
366 Uint8 dst_mac_address[6];
368 /* Initialize the pointer in the received packet is stored.
369 * This is misaligned on the 2 byte boundary as this will ensure that
370 * the layer3 headers i.e. IPv4 and ARP are aligned correctly. */
371 ptr_data_packet = (Uint8 *)&netmcb.rx_packet[2];
373 /* Check if a packet has been received? */
374 packet_size = netmcb.net_device.receive(&netmcb.net_device, ptr_data_packet);
375 if (packet_size == 0)
376 return;
378 /* Increment the number of packets received. */
379 net_stats.num_pkt_rxed++;
381 /* Extract the destination MAC Address from the received packet. */
382 netMemcpy ((void *)&dst_mac_address[0], (void *)ptr_data_packet, 6);
384 /* Extract the protocol from the received packet. This is at offset 12 from the
385 * start of the packet. We need to skip the destination and source mac address. */
386 protocol = *((Uint16 *)(ptr_data_packet + 12));
387 protocol = ntohs(protocol);
389 /* Process the received data.
390 * Check the destination mac address to determine if the packet is
391 * meant for us or not? We accept only directed UNICAST & BROADCAST
392 * packets */
393 if(((dst_mac_address[0] != 0xFF) || (dst_mac_address[1] != 0xFF) ||
394 (dst_mac_address[2] != 0xFF) || (dst_mac_address[3] != 0xFF) ||
395 (dst_mac_address[4] != 0xFF) || (dst_mac_address[5] != 0xFF)) &&
396 ((dst_mac_address[0] != netmcb.net_device.mac_address[0]) ||
397 (dst_mac_address[1] != netmcb.net_device.mac_address[1]) ||
398 (dst_mac_address[2] != netmcb.net_device.mac_address[2]) ||
399 (dst_mac_address[3] != netmcb.net_device.mac_address[3]) ||
400 (dst_mac_address[4] != netmcb.net_device.mac_address[4]) ||
401 (dst_mac_address[5] != netmcb.net_device.mac_address[5])))
402 {
403 /* Packet is not meant for us; ignore this packet. */
404 net_stats.rx_l2_dropped++;
405 return;
406 }
408 /* Move the pointer to the data packet and skip the ethernet header. */
409 ptr_data_packet = ptr_data_packet + sizeof(ETHHDR);
411 /* Deduct the Ethernet header size from the total number of bytes received. */
412 packet_size = packet_size - sizeof(ETHHDR);
414 /* Sanity Check: We need to ensure that the Layer3 headers are aligned on the
415 * 4 byte boundary at this stage. */
416 if (((Uint32)ptr_data_packet % 4) != 0)
417 mprintf ("ERROR: Misaligned Layer3 packet received 0x%p.\n", ptr_data_packet);
419 /* Demux on the protocol basis and pass it to the upper layer. */
420 switch (protocol)
421 {
422 case ETH_IP:
423 {
424 /* IPv4 Packet. */
425 if (ip_receive ((IPHDR *)ptr_data_packet, packet_size) < 0)
426 net_stats.rx_ip_dropped++;
427 break;
428 }
429 case ETH_ARP:
430 {
431 /* ARP Packet. */
432 if (arp_receive ((ARPHDR *)ptr_data_packet, packet_size) < 0)
433 net_stats.rx_arp_dropped++;
434 break;
435 }
436 default:
437 {
438 /* Unexpected packet. Drop the packet! */
439 net_stats.rx_l2_dropped++;
440 break;
441 }
442 }
444 }
446 /**
447 * @b Description
448 * @n
449 * The function reads/peeks data from the BLF net module.
450 *
451 * @param[in] ptr_buf
452 * This points to the data buffer which needs to be populated
453 * with the received data.
454 *
455 * @param[in] num_bytes
456 * This is the number of bytes of data which need to be read.
457 *
458 * @param[in] op
459 * Determines if a read or peek operation is performed
460 *
461 * @retval
462 * Success - 0
463 * @retval
464 * Error - <0
465 */
466 static Int32 net_read_peek (Uint8* ptr_buf, Uint32 num_bytes, Int32 op)
467 {
468 Int32 num_bytes_read = 0;
469 Int32 total_num_bytes_read = 0;
471 /* Basic Validations: Ensure that the parameters are valid. */
472 if ((ptr_buf == NULL) || (num_bytes == 0))
473 return -1;
475 /* Execute the network scheduler; till there is no error. */
476 while (netmcb.error_flag == 0)
477 {
479 /* If the stream is empty and closed return */
480 if (stream_level() < 0) {
481 if (total_num_bytes_read > 0)
482 return (0);
483 else
484 return (-1);
485 }
488 /* Call the timer scheduler. */
489 timer_run();
491 /* Check if there is data in the STREAM? */
492 if (stream_isempty() == FALSE)
493 {
494 /* STREAM indicates there is some data. Lets read it first. */
495 if (op == NET_READ) {
496 num_bytes_read = stream_read (((ptr_buf + total_num_bytes_read)), num_bytes);
497 netmcb.fileOffset = netmcb.fileOffset + num_bytes_read;
498 } else
499 num_bytes_read = stream_peek (((ptr_buf + total_num_bytes_read)), num_bytes);
501 /* Keep track of the total amount of data read till now. */
502 total_num_bytes_read = total_num_bytes_read + num_bytes_read;
504 /* How much more data do we need to read? */
505 num_bytes = num_bytes - num_bytes_read;
507 /* Check if we have read all the data that was requested? */
508 if (num_bytes == 0)
509 break;
511 /* Control comes here implies that there was more data to be read into
512 * the buffer. We need it to have it available before we can exit the loop.
513 * So lets fall through! */
514 }
515 else
516 {
517 /* STREAM Module is empty. */
518 }
520 /* Check for and process any received packets */
521 proc_packet ();
523 }
525 /* Did we come out because of error or not? */
526 if (netmcb.error_flag == 0)
527 return 0;
529 /* Return error */
530 return -1;
531 }
534 /**
535 * @b Description
536 * @n
537 * The function reads data from the BLF net module.
538 *
539 * @param[in] ptr_buf
540 * This points to the data buffer which needs to be populated
541 * with the received data.
542 *
543 * @param[in] num_bytes
544 * This is the number of bytes of data which need to be read.
545 *
546 * @retval
547 * Success - 0
548 * @retval
549 * Error - <0
550 */
551 static Int32 net_read (Uint8* ptr_buf, Uint32 num_bytes)
552 {
553 return (net_read_peek (ptr_buf, num_bytes, NET_READ));
554 }
557 /**
558 * @b Description
559 * @n
560 * The function peeks data from the BLF net module.
561 *
562 * @param[in] ptr_buf
563 * This points to the data buffer which needs to be populated
564 * with the received data.
565 *
566 * @param[in] num_bytes
567 * This is the number of bytes of data which need to be read.
568 *
569 * @retval
570 * Success - 0
571 * @retval
572 * Error - <0
573 */
574 static Int32 net_peek (Uint8* ptr_buf, Uint32 num_bytes)
575 {
576 return (net_read_peek (ptr_buf, num_bytes, NET_PEEK));
577 }
580 /**
581 * @b Description
582 * Read data until the transfer is done
583 */
584 #define MIN(a,b) ((a) < (b)) ? (a) : (b)
585 void net_complete_transfer (void)
586 {
587 Int32 dataSize;
588 Int32 n;
589 uint8 buf[16];
591 do {
593 dataSize = stream_level();
595 if (dataSize > 0) {
597 while (dataSize > 0) {
599 n = MIN(dataSize, sizeof(buf));
600 net_read (buf, n);
601 dataSize = dataSize - n;
602 }
604 } else if (dataSize == 0) {
606 net_peek (buf, 1);
608 }
610 } while (dataSize >= 0);
612 }
617 /**
618 * @b Description
619 * @n
620 * This function moves the read pointer in the stream.
621 * Because this is a tftp boot, only forward reads
622 * are permitted.
623 *
624 * @param[in] loc
625 * This points to where the stream should be
626 *
627 * @param[in] from
628 * This describes parameter loc.
629 * 0 = from the start of the file
630 * 1 = from the current position
631 * 2 = from the end of the file
632 *
633 * @retval
634 * Success - 0
635 * @retval
636 * Error - <0
637 */
638 static Int32 net_seek (Int32 loc, Int32 from)
639 {
640 Uint32 num_bytes;
641 Int32 num_bytes_read = 0;
642 Int32 total_num_bytes_read = 0;
643 Uint32 desiredPos;
646 /* This driver can only seek forward, and cannot seek from the end of the file */
647 if (from == 0)
648 desiredPos = loc;
649 else if (from == 1)
650 desiredPos = netmcb.fileOffset + loc;
651 else
652 return (-1);
654 /* Check if already in the correct position */
655 if (desiredPos == netmcb.fileOffset)
656 return (0);
658 /* To seek backwords the current tftp transfer is completed,
659 * and then restarted */
660 if (desiredPos < netmcb.fileOffset) {
662 /* Complete the transfer */
663 net_complete_transfer ();
665 /* Reset the current file offset */
666 netmcb.fileOffset = 0;
668 /* Re-request the data file */
669 tftp_get_file (netmcb.net_device.server_ip, netmcb.net_device.file_name);
671 }
674 /* Read data from the file until the file position matches the desired one */
675 num_bytes = desiredPos - netmcb.fileOffset;
678 /* Execute the network scheduler; till there is no error. */
679 while (netmcb.error_flag == 0)
680 {
681 /* Call the timer scheduler. */
682 timer_run();
684 /* Check if there is data in the STREAM? */
685 if (stream_isempty() == FALSE)
686 {
687 /* STREAM indicates there is some data. Lets read it first. */
688 num_bytes_read = stream_read (NULL, num_bytes);
689 netmcb.fileOffset = netmcb.fileOffset + num_bytes_read;
691 /* Keep track of the total amount of data read till now. */
692 total_num_bytes_read = total_num_bytes_read + num_bytes_read;
694 /* How much more data do we need to read? */
695 num_bytes = num_bytes - num_bytes_read;
697 /* Check if we have read all the data that was requested? */
698 if (num_bytes == 0)
699 break;
701 /* Control comes here implies that there was more data to be read into
702 * the buffer. We need it to have it available before we can exit the loop.
703 * So lets fall through! */
704 }
705 else
706 {
707 /* STREAM Module is empty. */
708 }
710 /* Check for and process any received packets */
711 proc_packet ();
713 }
715 /* Did we come out because of error or not? */
716 if (netmcb.error_flag == 0)
717 return 0;
719 /* Return error */
720 return -1;
721 }
723 /**
724 * @b Description
725 * @n
726 * This function returns how many bytes of data
727 * are currently available for immediate read.
728 *
729 * @retval
730 * The number of bytes available
731 */
732 static Int32 net_query (void)
733 {
734 return (stream_level());
735 }