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 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 *
15 * Redistributions of source code must retain the above copyright
16 * notice, this list of conditions and the following disclaimer.
17 *
18 * Redistributions in binary form must reproduce the above copyright
19 * notice, this list of conditions and the following disclaimer in the
20 * documentation and/or other materials provided with the
21 * distribution.
22 *
23 * Neither the name of Texas Instruments Incorporated nor the names of
24 * its contributors may be used to endorse or promote products derived
25 * from this software without specific prior written permission.
26 *
27 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
28 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
29 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
30 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
31 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
32 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
33 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
34 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
35 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
36 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
37 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
38 *
39 * \par
40 */
41 #include "types.h"
42 #include "iblloc.h"
43 #include "net.h"
44 #include "netif.h"
45 #include "timer.h"
46 #include "stream.h"
47 #include <string.h>
48 #include "net_osal.h"
51 /**********************************************************************
52 *************************** Local Functions **************************
53 **********************************************************************/
54 static Int32 net_open (void* ptr_driver, void (*asyncComplete)(void *));
55 static Int32 net_close(void);
56 static Int32 net_read (Uint8* ptr_buf, Uint32 num_bytes);
57 static Int32 net_peek (Uint8* ptr_buf, Uint32 num_bytes);
58 static Int32 net_seek (Int32 loc, Int32 from);
59 static Int32 net_query (void);
61 /**********************************************************************
62 *************************** GLOBAL Variables *************************
63 **********************************************************************/
65 /**
66 * @defgroup net_op
67 *
68 * @ingroup net_op
69 * @{
70 *
71 * @brief
72 * Internal definition to distinguish a read from a peek
73 *
74 */
76 /**
77 * @def NET_READ
78 */
79 #define NET_READ 400 /**< Read from the net device */
81 /**
82 * @def NET_PEEK
83 */
84 #define NET_PEEK 420 /**< Peek from the net device */
86 /* @} */
89 /**
90 * @brief This is the NETWORK Master control block which keeps track
91 * of all the Network boot module related information.
92 */
93 NET_MCB netmcb;
95 /**
96 * @brief This keeps track of the network statistics.
97 */
98 NET_STATS net_stats;
100 /**
101 * @brief This is the global Network Boot Module function table which
102 * implements the Boot Module Interface with the kernel.
103 */
104 BOOT_MODULE_FXN_TABLE net_boot_module =
105 {
106 net_open, /* Open API */
107 net_close, /* Close API */
108 net_read, /* Read API */
109 NULL, /* Write API (NULL: This is not interactive) */
110 net_peek, /* Peek API */
111 net_seek, /* Seek API */
112 net_query /* Query API */
113 };
115 /**********************************************************************
116 **************************** NET Functions ***************************
117 **********************************************************************/
119 /**
120 * @b Description
121 * @n
122 * The function is used to allocate a packet for transmission. This
123 * is called by the higher layer protocols when a packet needs to
124 * be transmitted. The function ensures there is sufficient space
125 * allocated at the beginning of the packet for the Ethernet header.
126 * Since the pointer returned by this API is used to store L3/L4 headers
127 * it always returns a 4 byte aligned buffer data pointer.
128 *
129 * @param[in] packet_len
130 * Length of the packet being transmitted.
131 *
132 * @retval
133 * Success - Pointer to the L3 header.
134 * @retval
135 * Error - NULL
136 */
137 Uint8* net_alloc_tx_packet(Int32 packet_len)
138 {
139 /* Sanity Check: Ensure the packet being allocated does not exceed the
140 * max buffer size that we have. */
141 if (packet_len > NET_MAX_MTU)
142 return NULL;
144 /* Sanity Check: Ensure that the packet is available for use. */
145 if (netmcb.txuse == 1)
146 return NULL;
148 /* Mark the packet as being in use. */
149 netmcb.txuse = 1;
151 /* Reset the contents of the packet */
152 netMemset ((void *)&netmcb.tx_packet[0], 0, sizeof(netmcb.tx_packet));
154 /* Reserve some space at the head of the packet for the Ethernet headers. */
155 return &netmcb.tx_packet[16];
156 }
158 /**
159 * @b Description
160 * @n
161 * The function is called to free up a previously allocated transmit
162 * packet.
163 *
164 * @param[in] ptr
165 * Pointer to the packet being cleaned.
166 *
167 * @retval
168 * Not Applicable.
169 */
170 void net_free_tx_packet (Uint8* ptr)
171 {
172 /* Sanity Checks: Ensure that the packet being cleaned is the same as the one
173 * which was allocated. */
174 if (ptr != &netmcb.tx_packet[16])
175 mprintf ("ERROR: NET Free Transmit packet detected corruption\n");
177 /* Sanity Checks: Ensure that there is no double free. */
178 if (netmcb.txuse == 0)
179 mprintf ("ERROR: NET Free Transmit packet detected double free\n");
181 /* Mark the transmit packet as free and available. */
182 netmcb.txuse = 0;
183 return;
184 }
186 /**
187 * @b Description
188 * @n
189 * The function is used to append an Ethernet header on the packet.
190 * The source MAC Address in the packet is always the one which was
191 * registered by the driver. Higher layer protocol authors need to
192 * use the 'net_alloc_tx_packet' API to get a transmit buffer.
193 *
194 * @param[in] ptr_l3_hdr
195 * This is the pointer to the layer3 header.
196 * @param[in] dst_mac
197 * The destination MAC address
198 * @param[in] protocol
199 * The layer3 protocol version (passed in host order)
200 *
201 * @retval
202 * Success - Pointer to the start of the Ethernet header i.e. L2.
203 * @retval
204 * Error - NULL
205 */
206 ETHHDR* net_create_eth_header (Uint8* ptr_l3_hdr, Uint8* dst_mac, Uint16 protocol)
207 {
208 Int32 rsvd_space;
210 /* Compute the reserved space. */
211 rsvd_space = (Int32)ptr_l3_hdr - (Int32)&netmcb.tx_packet[0];
213 /* Ensure there is sufficient space to add the header. We dont want memory corruption
214 * to occur here. */
215 if ((rsvd_space < 0) || (rsvd_space > NET_MAX_MTU) || (rsvd_space < ETHHDR_SIZE))
216 return NULL;
218 /* Convert the protocol to network order. */
219 protocol = ntohs(protocol);
221 /* Start adding the Ethernet header.
222 * Move back the data pointer to account for the protocol. */
223 ptr_l3_hdr = ptr_l3_hdr - 2;
224 netMemcpy ((void *)ptr_l3_hdr, (void *)&protocol, sizeof(Uint16));
226 /* Move back the data pointer to account for the source MAC. */
227 ptr_l3_hdr = ptr_l3_hdr - 6;
228 netMemcpy ((void *)ptr_l3_hdr, (void *)&netmcb.net_device.mac_address[0], 6);
230 /* Move back the data pointer to account for the destination MAC. */
231 ptr_l3_hdr = ptr_l3_hdr - 6;
232 netMemcpy ((void *)ptr_l3_hdr, (void *)dst_mac, 6);
234 /* Return the pointer to the start of the Ethernet header. */
235 return (ETHHDR *)ptr_l3_hdr;
236 }
238 /**
239 * @b Description
240 * @n
241 * The function is used to send a packet to the driver.
242 *
243 * @param[in] ptr_l2_hdr
244 * This is the pointer to the L2 header of the packet to be transmitted.
245 * All the headers need to be populated by the time comes to this API.
246 * @param[in] length
247 * Length of the packet being transmitted. This include the L2 header
248 * information.
249 *
250 * @retval
251 * Not Applicable.
252 */
253 void net_send_packet (ETHHDR* ptr_l2_hdr, Uint16 length)
254 {
255 /* Sanity Check: This is called after the LAYER3 and ETHER headers
256 * have been appended to the packet. Here we ensure that the layer3 header
257 * is aligned on the 4 byte boundary. */
258 if ( (((Uint32)ptr_l2_hdr+ETHHDR_SIZE) % 4) != 0)
259 mprintf ("ERROR: Misaligned Layer3 packet transmitted 0x%p.\n", ptr_l2_hdr);
261 /* Increment the stats. */
262 net_stats.num_pkt_txed++;
264 /* Pass the packet to the platform API for transmission. */
265 netmcb.net_device.send (&netmcb.net_device, (Uint8 *)ptr_l2_hdr, (Int32)length);
266 return;
267 }
269 /**
270 * @b Description
271 * @n
272 * The function is called from any entity inside the NETWORK Boot Module
273 * to indicate that there has been a FATAL error and that the boot module
274 * processing needs to be aborted.
275 *
276 * @retval
277 * Not Applicable.
278 */
279 void net_set_error (void)
280 {
281 /* Set the Error Flag; */
282 netmcb.error_flag = 1;
283 return;
284 }
286 /**
287 * @b Description
288 * @n
289 * The function opens the BLF NET Module. The function initializes
290 * the various internal components of the NET module and also
291 * initializes the peripheral driver controller
292 *
293 * @param[in] ptr_driver
294 * This is the pointer to the driver block which was passed to
295 * the BLF through the BOOT Mode descriptor. For the NET boot
296 * module this points to the NET_DRV_DEVICE object.
297 *
298 * @retval
299 * Success - 0
300 * @retval
301 * Error - <0
302 */
303 static Int32 net_open (void* ptr_driver, void (*asyncComplete)(void *))
304 {
305 NET_DRV_DEVICE* ptr_net_driver;
307 /* Get the pointer to the net driver. */
308 ptr_net_driver = (NET_DRV_DEVICE*)ptr_driver;
310 /* Basic Validation: Ensure there is a valid driver block being passed. */
311 if (ptr_net_driver == NULL)
312 return -1;
314 /* Basic Validation: Ensure that all the required API have been provided */
315 if ((ptr_net_driver->start == NULL) || (ptr_net_driver->send == NULL) ||
316 (ptr_net_driver->receive == NULL) || (ptr_net_driver->stop == NULL))
317 {
318 /* Error: Required API was not specified. */
319 return -1;
320 }
322 /* Initialize the NET MCB. */
323 netMemset (&netmcb, 0, sizeof(NET_MCB));
325 /* Initialize the Network Statistics. */
326 netMemset (&net_stats, 0, sizeof(NET_STATS));
328 /* Copy the driver information into the NET MCB */
329 netMemcpy ((void *)&netmcb.net_device, (void *)ptr_net_driver, sizeof(NET_DRV_DEVICE));
331 /* Initialize the ARP Module. */
332 arp_init ();
334 /* Initialize the IP Module. */
335 ip_init ();
337 /* Initialize the UDP Module. */
338 udp_init ();
340 /* Start the networking device */
341 if (netmcb.net_device.start(&netmcb.net_device) < 0)
342 return -1;
344 /* Determine if we need to execute BOOTP or not? */
345 if (netmcb.net_device.ip_address != 0)
346 {
347 /* IP Address was supplied by the device team. There is no need
348 * to execute the BOOTP protocol; manually create the network route also. */
349 ip_add_route (FLG_RT_NETWORK, netmcb.net_device.ip_address, netmcb.net_device.net_mask, 0);
351 /* Optional call back with boot server info */
352 if (asyncComplete != NULL)
353 (*asyncComplete)((void *)&netmcb.net_device);
355 /* Lets download the file from the TFTP Server. */
356 tftp_get_file (netmcb.net_device.server_ip, netmcb.net_device.file_name);
357 }
358 else
359 {
360 /* No IP Address was supplied we need to execute the BOOTP protocol. */
361 bootp_init (asyncComplete);
362 }
364 /* The network module is UP and running.. */
365 return 0;
366 }
368 /**
369 * @b Description
370 * @n
371 * The function closes the BLF NET Module.
372 *
373 * @retval
374 * Success - 0
375 * @retval
376 * Error - <0
377 */
378 static Int32 net_close (void)
379 {
380 if (netmcb.net_device.stop)
381 (*netmcb.net_device.stop)(&netmcb.net_device);
383 return 0;
384 }
387 /**
388 * @b Description
389 * @n
390 * If a waiting packet is found it is processed
391 */
392 static void proc_packet (void)
393 {
394 Uint8* ptr_data_packet;
395 Int32 packet_size;
396 Uint16 protocol;
397 Uint8 dst_mac_address[6];
399 /* Initialize the pointer in the received packet is stored.
400 * This is misaligned on the 2 byte boundary as this will ensure that
401 * the layer3 headers i.e. IPv4 and ARP are aligned correctly. */
402 ptr_data_packet = (Uint8 *)&netmcb.rx_packet[2];
404 /* Check if a packet has been received? */
405 packet_size = netmcb.net_device.receive(&netmcb.net_device, ptr_data_packet);
406 if (packet_size == 0)
407 return;
409 /* Increment the number of packets received. */
410 net_stats.num_pkt_rxed++;
412 /* Extract the destination MAC Address from the received packet. */
413 netMemcpy ((void *)&dst_mac_address[0], (void *)ptr_data_packet, 6);
415 /* Extract the protocol from the received packet. This is at offset 12 from the
416 * start of the packet. We need to skip the destination and source mac address. */
417 protocol = *((Uint16 *)(ptr_data_packet + 12));
418 protocol = ntohs(protocol);
420 /* Process the received data.
421 * Check the destination mac address to determine if the packet is
422 * meant for us or not? We accept only directed UNICAST & BROADCAST
423 * packets */
424 if(((dst_mac_address[0] != 0xFF) || (dst_mac_address[1] != 0xFF) ||
425 (dst_mac_address[2] != 0xFF) || (dst_mac_address[3] != 0xFF) ||
426 (dst_mac_address[4] != 0xFF) || (dst_mac_address[5] != 0xFF)) &&
427 ((dst_mac_address[0] != netmcb.net_device.mac_address[0]) ||
428 (dst_mac_address[1] != netmcb.net_device.mac_address[1]) ||
429 (dst_mac_address[2] != netmcb.net_device.mac_address[2]) ||
430 (dst_mac_address[3] != netmcb.net_device.mac_address[3]) ||
431 (dst_mac_address[4] != netmcb.net_device.mac_address[4]) ||
432 (dst_mac_address[5] != netmcb.net_device.mac_address[5])))
433 {
434 /* Packet is not meant for us; ignore this packet. */
435 net_stats.rx_l2_dropped++;
436 return;
437 }
439 /* Move the pointer to the data packet and skip the ethernet header. */
440 ptr_data_packet = ptr_data_packet + sizeof(ETHHDR);
442 /* Deduct the Ethernet header size from the total number of bytes received. */
443 packet_size = packet_size - sizeof(ETHHDR);
445 /* Sanity Check: We need to ensure that the Layer3 headers are aligned on the
446 * 4 byte boundary at this stage. */
447 if (((Uint32)ptr_data_packet % 4) != 0)
448 mprintf ("ERROR: Misaligned Layer3 packet received 0x%p.\n", ptr_data_packet);
450 /* Demux on the protocol basis and pass it to the upper layer. */
451 switch (protocol)
452 {
453 case ETH_IP:
454 {
455 /* IPv4 Packet. */
456 if (ip_receive ((IPHDR *)ptr_data_packet, packet_size) < 0)
457 net_stats.rx_ip_dropped++;
458 break;
459 }
460 case ETH_ARP:
461 {
462 /* ARP Packet. */
463 if (arp_receive ((ARPHDR *)ptr_data_packet, packet_size) < 0)
464 net_stats.rx_arp_dropped++;
465 break;
466 }
467 default:
468 {
469 /* Unexpected packet. Drop the packet! */
470 net_stats.rx_l2_dropped++;
471 break;
472 }
473 }
475 }
477 /**
478 * @b Description
479 * @n
480 * The function reads/peeks data from the BLF net module.
481 *
482 * @param[in] ptr_buf
483 * This points to the data buffer which needs to be populated
484 * with the received data.
485 *
486 * @param[in] num_bytes
487 * This is the number of bytes of data which need to be read.
488 *
489 * @param[in] op
490 * Determines if a read or peek operation is performed
491 *
492 * @retval
493 * Success - 0
494 * @retval
495 * Error - <0
496 */
497 static Int32 net_read_peek (Uint8* ptr_buf, Uint32 num_bytes, Int32 op)
498 {
499 Int32 num_bytes_read = 0;
500 Int32 total_num_bytes_read = 0;
502 /* Basic Validations: Ensure that the parameters are valid. */
503 if ((ptr_buf == NULL) || (num_bytes == 0))
504 return -1;
506 /* Execute the network scheduler; till there is no error. */
507 while (netmcb.error_flag == 0)
508 {
510 /* If the stream is empty and closed return */
511 if (stream_level() < 0) {
512 if (total_num_bytes_read > 0)
513 return (0);
514 else
515 return (-1);
516 }
519 /* Call the timer scheduler. */
520 timer_run();
522 /* Check if there is data in the STREAM? */
523 if (stream_isempty() == FALSE)
524 {
525 /* STREAM indicates there is some data. Lets read it first. */
526 if (op == NET_READ) {
527 num_bytes_read = stream_read (((ptr_buf + total_num_bytes_read)), num_bytes);
528 netmcb.fileOffset = netmcb.fileOffset + num_bytes_read;
529 } else
530 num_bytes_read = stream_peek (((ptr_buf + total_num_bytes_read)), num_bytes);
532 /* Keep track of the total amount of data read till now. */
533 total_num_bytes_read = total_num_bytes_read + num_bytes_read;
535 /* How much more data do we need to read? */
536 num_bytes = num_bytes - num_bytes_read;
538 /* Check if we have read all the data that was requested? */
539 if (num_bytes == 0)
540 break;
542 /* Control comes here implies that there was more data to be read into
543 * the buffer. We need it to have it available before we can exit the loop.
544 * So lets fall through! */
545 }
546 else
547 {
548 /* STREAM Module is empty. */
549 }
551 /* Check for and process any received packets */
552 proc_packet ();
554 }
556 /* Did we come out because of error or not? */
557 if (netmcb.error_flag == 0)
558 return 0;
560 /* Return error */
561 return -1;
562 }
565 /**
566 * @b Description
567 * @n
568 * The function reads data from the BLF net module.
569 *
570 * @param[in] ptr_buf
571 * This points to the data buffer which needs to be populated
572 * with the received data.
573 *
574 * @param[in] num_bytes
575 * This is the number of bytes of data which need to be read.
576 *
577 * @retval
578 * Success - 0
579 * @retval
580 * Error - <0
581 */
582 static Int32 net_read (Uint8* ptr_buf, Uint32 num_bytes)
583 {
584 return (net_read_peek (ptr_buf, num_bytes, NET_READ));
585 }
588 /**
589 * @b Description
590 * @n
591 * The function peeks data from the BLF net module.
592 *
593 * @param[in] ptr_buf
594 * This points to the data buffer which needs to be populated
595 * with the received data.
596 *
597 * @param[in] num_bytes
598 * This is the number of bytes of data which need to be read.
599 *
600 * @retval
601 * Success - 0
602 * @retval
603 * Error - <0
604 */
605 static Int32 net_peek (Uint8* ptr_buf, Uint32 num_bytes)
606 {
607 return (net_read_peek (ptr_buf, num_bytes, NET_PEEK));
608 }
611 /**
612 * @b Description
613 * Read data until the transfer is done
614 */
615 #define MIN(a,b) ((a) < (b)) ? (a) : (b)
616 void net_complete_transfer (void)
617 {
618 Int32 dataSize;
619 Int32 n;
620 uint8 buf[16];
622 do {
624 dataSize = stream_level();
626 if (dataSize > 0) {
628 while (dataSize > 0) {
630 n = MIN(dataSize, sizeof(buf));
631 net_read (buf, n);
632 dataSize = dataSize - n;
633 }
635 } else if (dataSize == 0) {
637 net_peek (buf, 1);
639 }
641 } while (dataSize >= 0);
643 }
648 /**
649 * @b Description
650 * @n
651 * This function moves the read pointer in the stream.
652 * Because this is a tftp boot, only forward reads
653 * are permitted.
654 *
655 * @param[in] loc
656 * This points to where the stream should be
657 *
658 * @param[in] from
659 * This describes parameter loc.
660 * 0 = from the start of the file
661 * 1 = from the current position
662 * 2 = from the end of the file
663 *
664 * @retval
665 * Success - 0
666 * @retval
667 * Error - <0
668 */
669 static Int32 net_seek (Int32 loc, Int32 from)
670 {
671 Uint32 num_bytes;
672 Int32 num_bytes_read = 0;
673 Int32 total_num_bytes_read = 0;
674 Uint32 desiredPos;
677 /* This driver can only seek forward, and cannot seek from the end of the file */
678 if (from == 0)
679 desiredPos = loc;
680 else if (from == 1)
681 desiredPos = netmcb.fileOffset + loc;
682 else
683 return (-1);
685 /* Check if already in the correct position */
686 if (desiredPos == netmcb.fileOffset)
687 return (0);
689 /* To seek backwords the current tftp transfer is completed,
690 * and then restarted */
691 if (desiredPos < netmcb.fileOffset) {
693 /* Complete the transfer */
694 net_complete_transfer ();
696 /* Reset the current file offset */
697 netmcb.fileOffset = 0;
699 /* Re-request the data file */
700 tftp_get_file (netmcb.net_device.server_ip, netmcb.net_device.file_name);
702 }
705 /* Read data from the file until the file position matches the desired one */
706 num_bytes = desiredPos - netmcb.fileOffset;
709 /* Execute the network scheduler; till there is no error. */
710 while (netmcb.error_flag == 0)
711 {
712 /* Call the timer scheduler. */
713 timer_run();
715 /* Check if there is data in the STREAM? */
716 if (stream_isempty() == FALSE)
717 {
718 /* STREAM indicates there is some data. Lets read it first. */
719 num_bytes_read = stream_read (NULL, num_bytes);
720 netmcb.fileOffset = netmcb.fileOffset + num_bytes_read;
722 /* Keep track of the total amount of data read till now. */
723 total_num_bytes_read = total_num_bytes_read + num_bytes_read;
725 /* How much more data do we need to read? */
726 num_bytes = num_bytes - num_bytes_read;
728 /* Check if we have read all the data that was requested? */
729 if (num_bytes == 0)
730 break;
732 /* Control comes here implies that there was more data to be read into
733 * the buffer. We need it to have it available before we can exit the loop.
734 * So lets fall through! */
735 }
736 else
737 {
738 /* STREAM Module is empty. */
739 }
741 /* Check for and process any received packets */
742 proc_packet ();
744 }
746 /* Did we come out because of error or not? */
747 if (netmcb.error_flag == 0)
748 return 0;
750 /* Return error */
751 return -1;
752 }
754 /**
755 * @b Description
756 * @n
757 * This function returns how many bytes of data
758 * are currently available for immediate read.
759 *
760 * @retval
761 * The number of bytes available
762 */
763 static Int32 net_query (void)
764 {
765 return (stream_level());
766 }