Initial c661x version
[keystone-rtos/ibl.git] / src / driver / eth / net.c
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 = 
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)
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];
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)
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;
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)
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;
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)
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;
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)
281     /* Set the Error Flag; */
282     netmcb.error_flag = 1;
283     return;
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 *))
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     }
363    
364     /* The network module is UP and running.. */ 
365     return 0;
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)
380     if (netmcb.net_device.stop)
381         (*netmcb.net_device.stop)(&netmcb.net_device);
383     return 0;
387 /**
388  *  @b Description
389  *  @n
390  *      If a waiting packet is found it is processed
391  */
392 static void proc_packet (void)
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     }
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)
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;
541     
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;
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)
584     return (net_read_peek (ptr_buf, num_bytes, NET_READ));
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)
607     return (net_read_peek (ptr_buf, num_bytes, NET_PEEK));
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)
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);
638     
639         }
641     } while (dataSize >= 0);
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)
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     }
703         
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;
731     
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;
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)
765     return (stream_level());
767