forked from xuos/xiuos
				
			
		
			
				
	
	
		
			534 lines
		
	
	
		
			18 KiB
		
	
	
	
		
			C
		
	
	
	
			
		
		
	
	
			534 lines
		
	
	
		
			18 KiB
		
	
	
	
		
			C
		
	
	
	
|   /**
 | |
|  * @file
 | |
|  * NetBIOS name service responder
 | |
|  */
 | |
| 
 | |
| /**
 | |
|  * @defgroup netbiosns NETBIOS responder
 | |
|  * @ingroup apps
 | |
|  *
 | |
|  * This is an example implementation of a NetBIOS name server.
 | |
|  * It responds to name queries for a configurable name.
 | |
|  * Name resolving is not supported.
 | |
|  *
 | |
|  * Note that the device doesn't broadcast it's own name so can't
 | |
|  * detect duplicate names!
 | |
|  */
 | |
| 
 | |
| /*
 | |
|  * Redistribution and use in source and binary forms, with or without modification,
 | |
|  * are permitted provided that the following conditions are met:
 | |
|  *
 | |
|  * 1. Redistributions of source code must retain the above copyright notice,
 | |
|  *    this list of conditions and the following disclaimer.
 | |
|  * 2. Redistributions in binary form must reproduce the above copyright notice,
 | |
|  *    this list of conditions and the following disclaimer in the documentation
 | |
|  *    and/or other materials provided with the distribution.
 | |
|  * 3. The name of the author may not be used to endorse or promote products
 | |
|  *    derived from this software without specific prior written permission.
 | |
|  *
 | |
|  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
 | |
|  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
 | |
|  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
 | |
|  * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 | |
|  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
 | |
|  * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 | |
|  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 | |
|  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
 | |
|  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
 | |
|  * OF SUCH DAMAGE.
 | |
|  *
 | |
|  * This file is part of the lwIP TCP/IP stack.
 | |
|  *
 | |
|  * Modifications by Ray Abram to respond to NetBIOS name requests when Incoming name = *
 | |
|  * - based on code from "https://github.com/esp8266/Arduino/commit/1f7989b31d26d7df9776a08f36d685eae7ac8f99"
 | |
|  * - with permission to relicense to BSD from original author:
 | |
|  *   http://www.xpablo.cz/?p=751#more-751
 | |
|  */
 | |
| 
 | |
| #include "lwip/apps/netbiosns.h"
 | |
| 
 | |
| #if LWIP_IPV4 && LWIP_UDP  /* don't build if not configured for use in lwipopts.h */
 | |
| 
 | |
| #include "lwip/def.h"
 | |
| #include "lwip/udp.h"
 | |
| #include "lwip/ip.h"
 | |
| #include "lwip/netif.h"
 | |
| #include "lwip/prot/iana.h"
 | |
| 
 | |
| #include <string.h>
 | |
| 
 | |
| /** size of a NetBIOS name */
 | |
| #define NETBIOS_NAME_LEN 16
 | |
| 
 | |
| /** The Time-To-Live for NetBIOS name responds (in seconds)
 | |
|  * Default is 300000 seconds (3 days, 11 hours, 20 minutes) */
 | |
| #define NETBIOS_NAME_TTL 300000u
 | |
| 
 | |
| /** NetBIOS header flags */
 | |
| #define NETB_HFLAG_RESPONSE           0x8000U
 | |
| #define NETB_HFLAG_OPCODE             0x7800U
 | |
| #define NETB_HFLAG_OPCODE_NAME_QUERY  0x0000U
 | |
| #define NETB_HFLAG_AUTHORATIVE        0x0400U
 | |
| #define NETB_HFLAG_TRUNCATED          0x0200U
 | |
| #define NETB_HFLAG_RECURS_DESIRED     0x0100U
 | |
| #define NETB_HFLAG_RECURS_AVAILABLE   0x0080U
 | |
| #define NETB_HFLAG_BROADCAST          0x0010U
 | |
| #define NETB_HFLAG_REPLYCODE          0x0008U
 | |
| #define NETB_HFLAG_REPLYCODE_NOERROR  0x0000U
 | |
| 
 | |
| /* NetBIOS question types */
 | |
| #define NETB_QTYPE_NB                 0x0020U
 | |
| #define NETB_QTYPE_NBSTAT             0x0021U
 | |
| 
 | |
| /** NetBIOS name flags */
 | |
| #define NETB_NFLAG_UNIQUE             0x8000U
 | |
| #define NETB_NFLAG_NODETYPE           0x6000U
 | |
| #define NETB_NFLAG_NODETYPE_HNODE     0x6000U
 | |
| #define NETB_NFLAG_NODETYPE_MNODE     0x4000U
 | |
| #define NETB_NFLAG_NODETYPE_PNODE     0x2000U
 | |
| #define NETB_NFLAG_NODETYPE_BNODE     0x0000U
 | |
| 
 | |
| #define NETB_NFLAG_NAME_IN_CONFLICT   0x0800U /* 1=Yes, 0=No */
 | |
| #define NETB_NFLAG_NAME_IS_ACTIVE     0x0400U /* 1=Yes, 0=No */
 | |
| #define NETB_NFLAG_NAME_IS_PERMANENT  0x0200U /* 1=Yes (Name is Permanent Node Name), 0=No */
 | |
| 
 | |
| /** NetBIOS message header */
 | |
| #ifdef PACK_STRUCT_USE_INCLUDES
 | |
| #  include "arch/bpstruct.h"
 | |
| #endif
 | |
| PACK_STRUCT_BEGIN
 | |
| struct netbios_hdr {
 | |
|   PACK_STRUCT_FIELD(u16_t trans_id);
 | |
|   PACK_STRUCT_FIELD(u16_t flags);
 | |
|   PACK_STRUCT_FIELD(u16_t questions);
 | |
|   PACK_STRUCT_FIELD(u16_t answerRRs);
 | |
|   PACK_STRUCT_FIELD(u16_t authorityRRs);
 | |
|   PACK_STRUCT_FIELD(u16_t additionalRRs);
 | |
| } PACK_STRUCT_STRUCT;
 | |
| PACK_STRUCT_END
 | |
| #ifdef PACK_STRUCT_USE_INCLUDES
 | |
| #  include "arch/epstruct.h"
 | |
| #endif
 | |
| 
 | |
| /** NetBIOS message question part */
 | |
| #ifdef PACK_STRUCT_USE_INCLUDES
 | |
| #  include "arch/bpstruct.h"
 | |
| #endif
 | |
| PACK_STRUCT_BEGIN
 | |
| struct netbios_question_hdr {
 | |
|   PACK_STRUCT_FLD_8(u8_t  nametype);
 | |
|   PACK_STRUCT_FLD_8(u8_t  encname[(NETBIOS_NAME_LEN * 2) + 1]);
 | |
|   PACK_STRUCT_FIELD(u16_t type);
 | |
|   PACK_STRUCT_FIELD(u16_t cls);
 | |
| } PACK_STRUCT_STRUCT;
 | |
| PACK_STRUCT_END
 | |
| #ifdef PACK_STRUCT_USE_INCLUDES
 | |
| #  include "arch/epstruct.h"
 | |
| #endif
 | |
| 
 | |
| /** NetBIOS message name part */
 | |
| #ifdef PACK_STRUCT_USE_INCLUDES
 | |
| #  include "arch/bpstruct.h"
 | |
| #endif
 | |
| PACK_STRUCT_BEGIN
 | |
| struct netbios_name_hdr {
 | |
|   PACK_STRUCT_FLD_8(u8_t  nametype);
 | |
|   PACK_STRUCT_FLD_8(u8_t  encname[(NETBIOS_NAME_LEN * 2) + 1]);
 | |
|   PACK_STRUCT_FIELD(u16_t type);
 | |
|   PACK_STRUCT_FIELD(u16_t cls);
 | |
|   PACK_STRUCT_FIELD(u32_t ttl);
 | |
|   PACK_STRUCT_FIELD(u16_t datalen);
 | |
|   PACK_STRUCT_FIELD(u16_t flags);
 | |
|   PACK_STRUCT_FLD_S(ip4_addr_p_t addr);
 | |
| } PACK_STRUCT_STRUCT;
 | |
| PACK_STRUCT_END
 | |
| #ifdef PACK_STRUCT_USE_INCLUDES
 | |
| #  include "arch/epstruct.h"
 | |
| #endif
 | |
| 
 | |
| /** NetBIOS message */
 | |
| #ifdef PACK_STRUCT_USE_INCLUDES
 | |
| #  include "arch/bpstruct.h"
 | |
| #endif
 | |
| PACK_STRUCT_BEGIN
 | |
| struct netbios_resp {
 | |
|   struct netbios_hdr      resp_hdr;
 | |
|   struct netbios_name_hdr resp_name;
 | |
| } PACK_STRUCT_STRUCT;
 | |
| PACK_STRUCT_END
 | |
| #ifdef PACK_STRUCT_USE_INCLUDES
 | |
| #  include "arch/epstruct.h"
 | |
| #endif
 | |
| 
 | |
| /** The NBNS Structure Responds to a Name Query */
 | |
| #ifdef PACK_STRUCT_USE_INCLUDES
 | |
| #  include "arch/bpstruct.h"
 | |
| #endif
 | |
| PACK_STRUCT_BEGIN
 | |
| struct netbios_answer {
 | |
|   struct netbios_hdr      answer_hdr;
 | |
|   /** the length of the next string */
 | |
|   PACK_STRUCT_FIELD(u8_t  name_size);
 | |
|   /** WARNING!!! this item may be of a different length (we use this struct for transmission) */
 | |
|   PACK_STRUCT_FLD_8(u8_t  query_name[(NETBIOS_NAME_LEN * 2) + 1]);
 | |
|   PACK_STRUCT_FIELD(u16_t packet_type);
 | |
|   PACK_STRUCT_FIELD(u16_t cls);
 | |
|   PACK_STRUCT_FIELD(u32_t ttl);
 | |
|   PACK_STRUCT_FIELD(u16_t data_length);
 | |
| #define OFFSETOF_STRUCT_NETBIOS_ANSWER_NUMBER_OF_NAMES 56
 | |
|   /** number of names */
 | |
|   PACK_STRUCT_FLD_8(u8_t  number_of_names);
 | |
|   /** node name */
 | |
|   PACK_STRUCT_FLD_8(u8_t  answer_name[NETBIOS_NAME_LEN]);
 | |
|   /** node flags */
 | |
|   PACK_STRUCT_FIELD(u16_t answer_name_flags);
 | |
|   /** Unit ID */
 | |
|   PACK_STRUCT_FLD_8(u8_t  unit_id[6]);
 | |
|   /** Jumpers */
 | |
|   PACK_STRUCT_FLD_8(u8_t  jumpers);
 | |
|   /** Test result */
 | |
|   PACK_STRUCT_FLD_8(u8_t  test_result);
 | |
|   /** Version number */
 | |
|   PACK_STRUCT_FIELD(u16_t version_number);
 | |
|   /** Period of statistics */
 | |
|   PACK_STRUCT_FIELD(u16_t period_of_statistics);
 | |
|   /** Statistics */
 | |
|   PACK_STRUCT_FIELD(u16_t number_of_crcs);
 | |
|   /** Statistics */
 | |
|   PACK_STRUCT_FIELD(u16_t number_of_alignment_errors);
 | |
|   /** Statistics */
 | |
|   PACK_STRUCT_FIELD(u16_t number_of_collisions);
 | |
|   /** Statistics */
 | |
|   PACK_STRUCT_FIELD(u16_t number_of_send_aborts);
 | |
|   /** Statistics */
 | |
|   PACK_STRUCT_FIELD(u32_t number_of_good_sends);
 | |
|   /** Statistics */
 | |
|   PACK_STRUCT_FIELD(u32_t number_of_good_receives);
 | |
|   /** Statistics */
 | |
|   PACK_STRUCT_FIELD(u16_t number_of_retransmits);
 | |
|   /** Statistics */
 | |
|   PACK_STRUCT_FIELD(u16_t number_of_no_resource_condition);
 | |
|   /** Statistics */
 | |
|   PACK_STRUCT_FIELD(u16_t number_of_free_command_blocks);
 | |
|   /** Statistics */
 | |
|   PACK_STRUCT_FIELD(u16_t total_number_of_command_blocks);
 | |
|   /** Statistics */
 | |
|   PACK_STRUCT_FIELD(u16_t max_total_number_of_command_blocks);
 | |
|   /** Statistics */
 | |
|   PACK_STRUCT_FIELD(u16_t number_of_pending_sessions);
 | |
|   /** Statistics */
 | |
|   PACK_STRUCT_FIELD(u16_t max_number_of_pending_sessions);
 | |
|   /** Statistics */
 | |
|   PACK_STRUCT_FIELD(u16_t max_total_sessions_possible);
 | |
|   /** Statistics */
 | |
|   PACK_STRUCT_FIELD(u16_t session_data_packet_size);
 | |
| } PACK_STRUCT_STRUCT;
 | |
| PACK_STRUCT_END
 | |
| #ifdef PACK_STRUCT_USE_INCLUDES
 | |
| #  include "arch/epstruct.h"
 | |
| #endif
 | |
| 
 | |
| #ifdef NETBIOS_LWIP_NAME
 | |
| #define NETBIOS_LOCAL_NAME NETBIOS_LWIP_NAME
 | |
| #else
 | |
| static char netbiosns_local_name[NETBIOS_NAME_LEN];
 | |
| #define NETBIOS_LOCAL_NAME netbiosns_local_name
 | |
| #endif
 | |
| 
 | |
| static struct udp_pcb *netbiosns_pcb;
 | |
| 
 | |
| /** Decode a NetBIOS name (from packet to string) */
 | |
| static int
 | |
| netbiosns_name_decode(char *name_enc, char *name_dec, int name_dec_len)
 | |
| {
 | |
|   char *pname;
 | |
|   char  cname;
 | |
|   char  cnbname;
 | |
|   int   idx = 0;
 | |
| 
 | |
|   LWIP_UNUSED_ARG(name_dec_len);
 | |
| 
 | |
|   /* Start decoding netbios name. */
 | |
|   pname  = name_enc;
 | |
|   for (;;) {
 | |
|     /* Every two characters of the first level-encoded name
 | |
|      * turn into one character in the decoded name. */
 | |
|     cname = *pname;
 | |
|     if (cname == '\0') {
 | |
|       break;  /* no more characters */
 | |
|     }
 | |
|     if (cname == '.') {
 | |
|       break;  /* scope ID follows */
 | |
|     }
 | |
|     if (!lwip_isupper(cname)) {
 | |
|       /* Not legal. */
 | |
|       return -1;
 | |
|     }
 | |
|     cname -= 'A';
 | |
|     cnbname = cname << 4;
 | |
|     pname++;
 | |
| 
 | |
|     cname = *pname;
 | |
|     if (!lwip_isupper(cname)) {
 | |
|       /* Not legal. */
 | |
|       return -1;
 | |
|     }
 | |
|     cname -= 'A';
 | |
|     cnbname |= cname;
 | |
|     pname++;
 | |
| 
 | |
|     /* Do we have room to store the character? */
 | |
|     if (idx < NETBIOS_NAME_LEN) {
 | |
|       /* Yes - store the character. */
 | |
|       name_dec[idx++] = (cnbname != ' ' ? cnbname : '\0');
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   return 0;
 | |
| }
 | |
| 
 | |
| #if 0 /* function currently unused */
 | |
| /** Encode a NetBIOS name (from string to packet) - currently unused because
 | |
|     we don't ask for names. */
 | |
| static int
 | |
| netbiosns_name_encode(char *name_enc, char *name_dec, int name_dec_len)
 | |
| {
 | |
|   char         *pname;
 | |
|   char          cname;
 | |
|   unsigned char ucname;
 | |
|   int           idx = 0;
 | |
| 
 | |
|   /* Start encoding netbios name. */
 | |
|   pname = name_enc;
 | |
| 
 | |
|   for (;;) {
 | |
|     /* Every two characters of the first level-encoded name
 | |
|      * turn into one character in the decoded name. */
 | |
|     cname = *pname;
 | |
|     if (cname == '\0') {
 | |
|       break;  /* no more characters */
 | |
|     }
 | |
|     if (cname == '.') {
 | |
|       break;  /* scope ID follows */
 | |
|     }
 | |
|     if ((cname < 'A' || cname > 'Z') && (cname < '0' || cname > '9')) {
 | |
|       /* Not legal. */
 | |
|       return -1;
 | |
|     }
 | |
| 
 | |
|     /* Do we have room to store the character? */
 | |
|     if (idx >= name_dec_len) {
 | |
|       return -1;
 | |
|     }
 | |
| 
 | |
|     /* Yes - store the character. */
 | |
|     ucname = cname;
 | |
|     name_dec[idx++] = ('A' + ((ucname >> 4) & 0x0F));
 | |
|     name_dec[idx++] = ('A' + ( ucname     & 0x0F));
 | |
|     pname++;
 | |
|   }
 | |
| 
 | |
|   /* Fill with "space" coding */
 | |
|   for (; idx < name_dec_len - 1;) {
 | |
|     name_dec[idx++] = 'C';
 | |
|     name_dec[idx++] = 'A';
 | |
|   }
 | |
| 
 | |
|   /* Terminate string */
 | |
|   name_dec[idx] = '\0';
 | |
| 
 | |
|   return 0;
 | |
| }
 | |
| #endif /* 0 */
 | |
| 
 | |
| /** NetBIOS Name service recv callback */
 | |
| static void
 | |
| netbiosns_recv(void *arg, struct udp_pcb *upcb, struct pbuf *p, const ip_addr_t *addr, u16_t port)
 | |
| {
 | |
|   LWIP_UNUSED_ARG(arg);
 | |
| 
 | |
|   /* if packet is valid */
 | |
|   if (p != NULL) {
 | |
|     char   netbios_name[NETBIOS_NAME_LEN + 1];
 | |
|     struct netbios_hdr          *netbios_hdr          = (struct netbios_hdr *)p->payload;
 | |
|     struct netbios_question_hdr *netbios_question_hdr = (struct netbios_question_hdr *)(netbios_hdr + 1);
 | |
| 
 | |
|     /* is the packet long enough (we need the header in one piece) */
 | |
|     if (p->len < (sizeof(struct netbios_hdr) + sizeof(struct netbios_question_hdr))) {
 | |
|       /* packet too short */
 | |
|       pbuf_free(p);
 | |
|       return;
 | |
|     }
 | |
|     /* we only answer if we got a default interface */
 | |
|     if (netif_default != NULL) {
 | |
|       /* @todo: do we need to check answerRRs/authorityRRs/additionalRRs? */
 | |
|       /* if the packet is a NetBIOS name query question */
 | |
|       if (((netbios_hdr->flags & PP_NTOHS(NETB_HFLAG_OPCODE)) == PP_NTOHS(NETB_HFLAG_OPCODE_NAME_QUERY)) &&
 | |
|           ((netbios_hdr->flags & PP_NTOHS(NETB_HFLAG_RESPONSE)) == 0) &&
 | |
|           (netbios_hdr->questions == PP_NTOHS(1))) {
 | |
|         /* decode the NetBIOS name */
 | |
|         netbiosns_name_decode((char *)(netbios_question_hdr->encname), netbios_name, sizeof(netbios_name));
 | |
|         /* check the request type */
 | |
|         if (netbios_question_hdr->type == PP_HTONS(NETB_QTYPE_NB)) {
 | |
|           /* if the packet is for us */
 | |
|           if (lwip_strnicmp(netbios_name, NETBIOS_LOCAL_NAME, sizeof(NETBIOS_LOCAL_NAME)) == 0) {
 | |
|             struct pbuf *q;
 | |
|             struct netbios_resp *resp;
 | |
| 
 | |
|             q = pbuf_alloc(PBUF_TRANSPORT, sizeof(struct netbios_resp), PBUF_RAM);
 | |
|             if (q != NULL) {
 | |
|               resp = (struct netbios_resp *)q->payload;
 | |
| 
 | |
|               /* prepare NetBIOS header response */
 | |
|               resp->resp_hdr.trans_id      = netbios_hdr->trans_id;
 | |
|               resp->resp_hdr.flags         = PP_HTONS(NETB_HFLAG_RESPONSE |
 | |
|                                                       NETB_HFLAG_OPCODE_NAME_QUERY |
 | |
|                                                       NETB_HFLAG_AUTHORATIVE |
 | |
|                                                       NETB_HFLAG_RECURS_DESIRED);
 | |
|               resp->resp_hdr.questions     = 0;
 | |
|               resp->resp_hdr.answerRRs     = PP_HTONS(1);
 | |
|               resp->resp_hdr.authorityRRs  = 0;
 | |
|               resp->resp_hdr.additionalRRs = 0;
 | |
| 
 | |
|               /* prepare NetBIOS header datas */
 | |
|               MEMCPY( resp->resp_name.encname, netbios_question_hdr->encname, sizeof(netbios_question_hdr->encname));
 | |
|               resp->resp_name.nametype     = netbios_question_hdr->nametype;
 | |
|               resp->resp_name.type         = netbios_question_hdr->type;
 | |
|               resp->resp_name.cls          = netbios_question_hdr->cls;
 | |
|               resp->resp_name.ttl          = PP_HTONL(NETBIOS_NAME_TTL);
 | |
|               resp->resp_name.datalen      = PP_HTONS(sizeof(resp->resp_name.flags) + sizeof(resp->resp_name.addr));
 | |
|               resp->resp_name.flags        = PP_HTONS(NETB_NFLAG_NODETYPE_BNODE);
 | |
|               ip4_addr_copy(resp->resp_name.addr, *netif_ip4_addr(netif_default));
 | |
| 
 | |
|               /* send the NetBIOS response */
 | |
|               udp_sendto(upcb, q, addr, port);
 | |
| 
 | |
|               /* free the "reference" pbuf */
 | |
|               pbuf_free(q);
 | |
|             }
 | |
|           }
 | |
| #if LWIP_NETBIOS_RESPOND_NAME_QUERY
 | |
|         } else if (netbios_question_hdr->type == PP_HTONS(NETB_QTYPE_NBSTAT)) {
 | |
|           /* if the packet is for us or general query */
 | |
|           if (!lwip_strnicmp(netbios_name, NETBIOS_LOCAL_NAME, sizeof(NETBIOS_LOCAL_NAME)) ||
 | |
|               !lwip_strnicmp(netbios_name, "*", sizeof(NETBIOS_LOCAL_NAME))) {
 | |
|             /* general query - ask for our IP address */
 | |
|             struct pbuf *q;
 | |
|             struct netbios_answer *resp;
 | |
| 
 | |
|             q = pbuf_alloc(PBUF_TRANSPORT, sizeof(struct netbios_answer), PBUF_RAM);
 | |
|             if (q != NULL) {
 | |
|               /* buffer to which a response is compiled */
 | |
|               resp = (struct netbios_answer *) q->payload;
 | |
| 
 | |
|               /* Init response to zero, especially the statistics fields */
 | |
|               memset(resp, 0, sizeof(*resp));
 | |
| 
 | |
|               /* copy the query to the response ID */
 | |
|               resp->answer_hdr.trans_id        = netbios_hdr->trans_id;
 | |
|               /* acknowledgment of termination */
 | |
|               resp->answer_hdr.flags           = PP_HTONS(NETB_HFLAG_RESPONSE | NETB_HFLAG_OPCODE_NAME_QUERY | NETB_HFLAG_AUTHORATIVE);
 | |
|               /* resp->answer_hdr.questions       = PP_HTONS(0); done by memset() */
 | |
|               /* serial number of the answer */
 | |
|               resp->answer_hdr.answerRRs       = PP_HTONS(1);
 | |
|               /* resp->answer_hdr.authorityRRs    = PP_HTONS(0); done by memset() */
 | |
|               /* resp->answer_hdr.additionalRRs   = PP_HTONS(0); done by memset() */
 | |
|               /* we will copy the length of the station name */
 | |
|               resp->name_size                  = netbios_question_hdr->nametype;
 | |
|               /* we will copy the queried name */
 | |
|               MEMCPY(resp->query_name, netbios_question_hdr->encname, (NETBIOS_NAME_LEN * 2) + 1);
 | |
|               /* NBSTAT */
 | |
|               resp->packet_type                = PP_HTONS(0x21);
 | |
|               /* Internet name */
 | |
|               resp->cls                        = PP_HTONS(1);
 | |
|               /* resp->ttl                        = PP_HTONL(0); done by memset() */
 | |
|               resp->data_length                = PP_HTONS(sizeof(struct netbios_answer) - offsetof(struct netbios_answer, number_of_names));
 | |
|               resp->number_of_names            = 1;
 | |
| 
 | |
|               /* make windows see us as workstation, not as a server */
 | |
|               memset(resp->answer_name, 0x20, NETBIOS_NAME_LEN - 1);
 | |
|               /* strlen is checked to be < NETBIOS_NAME_LEN during initialization */
 | |
|               MEMCPY(resp->answer_name, NETBIOS_LOCAL_NAME, strlen(NETBIOS_LOCAL_NAME));
 | |
| 
 | |
|               /* b-node, unique, active */
 | |
|               resp->answer_name_flags          = PP_HTONS(NETB_NFLAG_NAME_IS_ACTIVE);
 | |
| 
 | |
|               /* Set responder netif MAC address */
 | |
|               SMEMCPY(resp->unit_id, ip_current_input_netif()->hwaddr, sizeof(resp->unit_id));
 | |
| 
 | |
|               udp_sendto(upcb, q, addr, port);
 | |
|               pbuf_free(q);
 | |
|             }
 | |
|           }
 | |
| #endif /* LWIP_NETBIOS_RESPOND_NAME_QUERY */
 | |
|         }
 | |
|       }
 | |
|     }
 | |
|     /* free the pbuf */
 | |
|     pbuf_free(p);
 | |
|   }
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * @ingroup netbiosns
 | |
|  * Init netbios responder
 | |
|  */
 | |
| void
 | |
| netbiosns_init(void)
 | |
| {
 | |
|   /* LWIP_ASSERT_CORE_LOCKED(); is checked by udp_new() */
 | |
| #ifdef NETBIOS_LWIP_NAME
 | |
|   LWIP_ASSERT("NetBIOS name is too long!", strlen(NETBIOS_LWIP_NAME) < NETBIOS_NAME_LEN);
 | |
| #endif
 | |
| 
 | |
|   netbiosns_pcb = udp_new_ip_type(IPADDR_TYPE_ANY);
 | |
|   if (netbiosns_pcb != NULL) {
 | |
|     /* we have to be allowed to send broadcast packets! */
 | |
|     ip_set_option(netbiosns_pcb, SOF_BROADCAST);
 | |
|     udp_bind(netbiosns_pcb, IP_ANY_TYPE, LWIP_IANA_PORT_NETBIOS);
 | |
|     udp_recv(netbiosns_pcb, netbiosns_recv, netbiosns_pcb);
 | |
|   }
 | |
| }
 | |
| 
 | |
| #ifndef NETBIOS_LWIP_NAME
 | |
| /**
 | |
|  * @ingroup netbiosns
 | |
|  * Set netbios name. ATTENTION: the hostname must be less than 15 characters!
 | |
|  *                              the NetBIOS name spec says the name MUST be upper case, so incoming name is forced into uppercase :-)
 | |
|  */
 | |
| void
 | |
| netbiosns_set_name(const char *hostname)
 | |
| {
 | |
|   size_t i;
 | |
|   size_t copy_len = strlen(hostname);
 | |
|   LWIP_ASSERT_CORE_LOCKED();
 | |
|   LWIP_ASSERT("NetBIOS name is too long!", copy_len < NETBIOS_NAME_LEN);
 | |
|   if (copy_len >= NETBIOS_NAME_LEN) {
 | |
|     copy_len = NETBIOS_NAME_LEN - 1;
 | |
|   }
 | |
| 
 | |
|   /* make name into upper case */
 | |
|   for (i = 0; i < copy_len; i++ ) {
 | |
|     netbiosns_local_name[i] = (char)lwip_toupper(hostname[i]);
 | |
|   }
 | |
|   netbiosns_local_name[copy_len] = '\0';
 | |
| }
 | |
| #endif /* NETBIOS_LWIP_NAME */
 | |
| 
 | |
| /**
 | |
|  * @ingroup netbiosns
 | |
|  * Stop netbios responder
 | |
|  */
 | |
| void
 | |
| netbiosns_stop(void)
 | |
| {
 | |
|   LWIP_ASSERT_CORE_LOCKED();
 | |
|   if (netbiosns_pcb != NULL) {
 | |
|     udp_remove(netbiosns_pcb);
 | |
|     netbiosns_pcb = NULL;
 | |
|   }
 | |
| }
 | |
| 
 | |
| #endif /* LWIP_IPV4 && LWIP_UDP */
 |