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 return 0;
381 }
384 /**
385 * @b Description
386 * @n
387 * If a waiting packet is found it is processed
388 */
389 static void proc_packet (void)
390 {
391 Uint8* ptr_data_packet;
392 Int32 packet_size;
393 Uint16 protocol;
394 Uint8 dst_mac_address[6];
396 /* Initialize the pointer in the received packet is stored.
397 * This is misaligned on the 2 byte boundary as this will ensure that
398 * the layer3 headers i.e. IPv4 and ARP are aligned correctly. */
399 ptr_data_packet = (Uint8 *)&netmcb.rx_packet[2];
401 /* Check if a packet has been received? */
402 packet_size = netmcb.net_device.receive(&netmcb.net_device, ptr_data_packet);
403 if (packet_size == 0)
404 return;
406 /* Increment the number of packets received. */
407 net_stats.num_pkt_rxed++;
409 /* Extract the destination MAC Address from the received packet. */
410 netMemcpy ((void *)&dst_mac_address[0], (void *)ptr_data_packet, 6);
412 /* Extract the protocol from the received packet. This is at offset 12 from the
413 * start of the packet. We need to skip the destination and source mac address. */
414 protocol = *((Uint16 *)(ptr_data_packet + 12));
415 protocol = ntohs(protocol);
417 /* Process the received data.
418 * Check the destination mac address to determine if the packet is
419 * meant for us or not? We accept only directed UNICAST & BROADCAST
420 * packets */
421 if(((dst_mac_address[0] != 0xFF) || (dst_mac_address[1] != 0xFF) ||
422 (dst_mac_address[2] != 0xFF) || (dst_mac_address[3] != 0xFF) ||
423 (dst_mac_address[4] != 0xFF) || (dst_mac_address[5] != 0xFF)) &&
424 ((dst_mac_address[0] != netmcb.net_device.mac_address[0]) ||
425 (dst_mac_address[1] != netmcb.net_device.mac_address[1]) ||
426 (dst_mac_address[2] != netmcb.net_device.mac_address[2]) ||
427 (dst_mac_address[3] != netmcb.net_device.mac_address[3]) ||
428 (dst_mac_address[4] != netmcb.net_device.mac_address[4]) ||
429 (dst_mac_address[5] != netmcb.net_device.mac_address[5])))
430 {
431 /* Packet is not meant for us; ignore this packet. */
432 net_stats.rx_l2_dropped++;
433 return;
434 }
436 /* Move the pointer to the data packet and skip the ethernet header. */
437 ptr_data_packet = ptr_data_packet + sizeof(ETHHDR);
439 /* Deduct the Ethernet header size from the total number of bytes received. */
440 packet_size = packet_size - sizeof(ETHHDR);
442 /* Sanity Check: We need to ensure that the Layer3 headers are aligned on the
443 * 4 byte boundary at this stage. */
444 if (((Uint32)ptr_data_packet % 4) != 0)
445 mprintf ("ERROR: Misaligned Layer3 packet received 0x%p.\n", ptr_data_packet);
447 /* Demux on the protocol basis and pass it to the upper layer. */
448 switch (protocol)
449 {
450 case ETH_IP:
451 {
452 /* IPv4 Packet. */
453 if (ip_receive ((IPHDR *)ptr_data_packet, packet_size) < 0)
454 net_stats.rx_ip_dropped++;
455 break;
456 }
457 case ETH_ARP:
458 {
459 /* ARP Packet. */
460 if (arp_receive ((ARPHDR *)ptr_data_packet, packet_size) < 0)
461 net_stats.rx_arp_dropped++;
462 break;
463 }
464 default:
465 {
466 /* Unexpected packet. Drop the packet! */
467 net_stats.rx_l2_dropped++;
468 break;
469 }
470 }
472 }
474 /**
475 * @b Description
476 * @n
477 * The function reads/peeks data from the BLF net module.
478 *
479 * @param[in] ptr_buf
480 * This points to the data buffer which needs to be populated
481 * with the received data.
482 *
483 * @param[in] num_bytes
484 * This is the number of bytes of data which need to be read.
485 *
486 * @param[in] op
487 * Determines if a read or peek operation is performed
488 *
489 * @retval
490 * Success - 0
491 * @retval
492 * Error - <0
493 */
494 static Int32 net_read_peek (Uint8* ptr_buf, Uint32 num_bytes, Int32 op)
495 {
496 Int32 num_bytes_read = 0;
497 Int32 total_num_bytes_read = 0;
499 /* Basic Validations: Ensure that the parameters are valid. */
500 if ((ptr_buf == NULL) || (num_bytes == 0))
501 return -1;
503 /* Execute the network scheduler; till there is no error. */
504 while (netmcb.error_flag == 0)
505 {
507 /* If the stream is empty and closed return */
508 if (stream_level() < 0) {
509 if (total_num_bytes_read > 0)
510 return (0);
511 else
512 return (-1);
513 }
516 /* Call the timer scheduler. */
517 timer_run();
519 /* Check if there is data in the STREAM? */
520 if (stream_isempty() == FALSE)
521 {
522 /* STREAM indicates there is some data. Lets read it first. */
523 if (op == NET_READ) {
524 num_bytes_read = stream_read (((ptr_buf + total_num_bytes_read)), num_bytes);
525 netmcb.fileOffset = netmcb.fileOffset + num_bytes_read;
526 } else
527 num_bytes_read = stream_peek (((ptr_buf + total_num_bytes_read)), num_bytes);
529 /* Keep track of the total amount of data read till now. */
530 total_num_bytes_read = total_num_bytes_read + num_bytes_read;
532 /* How much more data do we need to read? */
533 num_bytes = num_bytes - num_bytes_read;
535 /* Check if we have read all the data that was requested? */
536 if (num_bytes == 0)
537 break;
539 /* Control comes here implies that there was more data to be read into
540 * the buffer. We need it to have it available before we can exit the loop.
541 * So lets fall through! */
542 }
543 else
544 {
545 /* STREAM Module is empty. */
546 }
548 /* Check for and process any received packets */
549 proc_packet ();
551 }
553 /* Did we come out because of error or not? */
554 if (netmcb.error_flag == 0)
555 return 0;
557 /* Return error */
558 return -1;
559 }
562 /**
563 * @b Description
564 * @n
565 * The function reads data from the BLF net module.
566 *
567 * @param[in] ptr_buf
568 * This points to the data buffer which needs to be populated
569 * with the received data.
570 *
571 * @param[in] num_bytes
572 * This is the number of bytes of data which need to be read.
573 *
574 * @retval
575 * Success - 0
576 * @retval
577 * Error - <0
578 */
579 static Int32 net_read (Uint8* ptr_buf, Uint32 num_bytes)
580 {
581 return (net_read_peek (ptr_buf, num_bytes, NET_READ));
582 }
585 /**
586 * @b Description
587 * @n
588 * The function peeks data from the BLF net module.
589 *
590 * @param[in] ptr_buf
591 * This points to the data buffer which needs to be populated
592 * with the received data.
593 *
594 * @param[in] num_bytes
595 * This is the number of bytes of data which need to be read.
596 *
597 * @retval
598 * Success - 0
599 * @retval
600 * Error - <0
601 */
602 static Int32 net_peek (Uint8* ptr_buf, Uint32 num_bytes)
603 {
604 return (net_read_peek (ptr_buf, num_bytes, NET_PEEK));
605 }
608 /**
609 * @b Description
610 * Read data until the transfer is done
611 */
612 #define MIN(a,b) ((a) < (b)) ? (a) : (b)
613 void net_complete_transfer (void)
614 {
615 Int32 dataSize;
616 Int32 n;
617 uint8 buf[16];
619 do {
621 dataSize = stream_level();
623 if (dataSize > 0) {
625 while (dataSize > 0) {
627 n = MIN(dataSize, sizeof(buf));
628 net_read (buf, n);
629 dataSize = dataSize - n;
630 }
632 } else if (dataSize == 0) {
634 net_peek (buf, 1);
636 }
638 } while (dataSize >= 0);
640 }
645 /**
646 * @b Description
647 * @n
648 * This function moves the read pointer in the stream.
649 * Because this is a tftp boot, only forward reads
650 * are permitted.
651 *
652 * @param[in] loc
653 * This points to where the stream should be
654 *
655 * @param[in] from
656 * This describes parameter loc.
657 * 0 = from the start of the file
658 * 1 = from the current position
659 * 2 = from the end of the file
660 *
661 * @retval
662 * Success - 0
663 * @retval
664 * Error - <0
665 */
666 static Int32 net_seek (Int32 loc, Int32 from)
667 {
668 Uint32 num_bytes;
669 Int32 num_bytes_read = 0;
670 Int32 total_num_bytes_read = 0;
671 Uint32 desiredPos;
674 /* This driver can only seek forward, and cannot seek from the end of the file */
675 if (from == 0)
676 desiredPos = loc;
677 else if (from == 1)
678 desiredPos = netmcb.fileOffset + loc;
679 else
680 return (-1);
682 /* Check if already in the correct position */
683 if (desiredPos == netmcb.fileOffset)
684 return (0);
686 /* To seek backwords the current tftp transfer is completed,
687 * and then restarted */
688 if (desiredPos < netmcb.fileOffset) {
690 /* Complete the transfer */
691 net_complete_transfer ();
693 /* Reset the current file offset */
694 netmcb.fileOffset = 0;
696 /* Re-request the data file */
697 tftp_get_file (netmcb.net_device.server_ip, netmcb.net_device.file_name);
699 }
702 /* Read data from the file until the file position matches the desired one */
703 num_bytes = desiredPos - netmcb.fileOffset;
706 /* Execute the network scheduler; till there is no error. */
707 while (netmcb.error_flag == 0)
708 {
709 /* Call the timer scheduler. */
710 timer_run();
712 /* Check if there is data in the STREAM? */
713 if (stream_isempty() == FALSE)
714 {
715 /* STREAM indicates there is some data. Lets read it first. */
716 num_bytes_read = stream_read (NULL, num_bytes);
717 netmcb.fileOffset = netmcb.fileOffset + num_bytes_read;
719 /* Keep track of the total amount of data read till now. */
720 total_num_bytes_read = total_num_bytes_read + num_bytes_read;
722 /* How much more data do we need to read? */
723 num_bytes = num_bytes - num_bytes_read;
725 /* Check if we have read all the data that was requested? */
726 if (num_bytes == 0)
727 break;
729 /* Control comes here implies that there was more data to be read into
730 * the buffer. We need it to have it available before we can exit the loop.
731 * So lets fall through! */
732 }
733 else
734 {
735 /* STREAM Module is empty. */
736 }
738 /* Check for and process any received packets */
739 proc_packet ();
741 }
743 /* Did we come out because of error or not? */
744 if (netmcb.error_flag == 0)
745 return 0;
747 /* Return error */
748 return -1;
749 }
751 /**
752 * @b Description
753 * @n
754 * This function returns how many bytes of data
755 * are currently available for immediate read.
756 *
757 * @retval
758 * The number of bytes available
759 */
760 static Int32 net_query (void)
761 {
762 return (stream_level());
763 }