/** * @file * NetBIOS name service sample * https://tools.ietf.org/html/rfc1002 * Modified for RTL871x pvvx */ #if 1 // def USE_NETBIOS /* * 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. * */ #include "rtl8195a/rtl_common.h" #include "rtl8195a.h" #include "lwip/opt.h" #include "netbios/netbios.h" #if LWIP_UDP /* don't build if not configured for use in lwipopts.h */ #include #include "ipv4/lwip/ip.h" #include "lwip/udp.h" #include "lwip/netif.h" #include "lwip_netconf.h" #include "rtl8195a/esp_comp.h" #define NETBIOS_CODE_ATTR #define NETBIOS_DATA_ATTR //extern struct netif xnetif[NET_IF_NUM]; #define NBS_DEF_NAME "rtl871x" /** 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! */ /** Since there's no standard function for case-insensitive string comparision, * we need another define here: * define this to stricmp() for windows or strcasecmp() for linux. * If not defined, comparision is case sensitive and NETBIOS_LWIP_NAME must be * uppercase */ #ifndef NETBIOS_STRCMP #define NETBIOS_STRCMP(str1, str2) os_strcmp(str1, str2) #endif /** default port number for "NetBIOS Name service */ //#define NETBIOS_PORT 137 /** NetBIOS name of LWIP device * This must be uppercase until NETBIOS_STRCMP() is defined to a string * comparision function that is case insensitive. * If you want to use the netif's hostname, use this (with LWIP_NETIF_HOSTNAME): * (ip_current_netif() != NULL ? ip_current_netif()->hostname != NULL ? ip_current_netif()->hostname : "" : "") */ /** size of a NetBIOS name */ //#define NETBIOS_NAME_LEN 16 // in netbios.h char netbios_name[NET_IF_NUM][NETBIOS_NAME_LEN + 1]; // default netifs: 0 - SoftAP, 1 - Station, 2 - Ethernet /** The Time-To-Live for NetBIOS name responds (in seconds) * Default is 300000 seconds (3 days, 11 hours, 20 minutes) */ #define NETBIOS_NAME_TTL 300000 /** 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 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 /** 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 name part */ #ifdef PACK_STRUCT_USE_INCLUDES # include "arch/bpstruct.h" #endif PACK_STRUCT_BEGIN struct netbios_name_hdr { PACK_STRUCT_FIELD(u8_t nametype); PACK_STRUCT_FIELD(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_FIELD(ip_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 /** NetBIOS decoding name */ static int8_t NETBIOS_CODE_ATTR NBNS_decode(char *dst, char *src) { uint8_t i, j; char c; for(i=0, j=0; i<15; i++) { c = (src[j++]-'A')<<4; c |= (src[j++]-'A')<<0; if(c == ' ') { break; } dst[i] = toupper(c); } dst[i] = 0; return (((src[30]-'A')<<4)|(src[31]-'A')); // 0x00 = Workstation } #if 0 /** NetBIOS encoding name */ static void NBNS_encode(char *dst, char *src, uint8_t type) { uint8_t i, j; char c; //encode name for(i=0, j=0; (i<15) && src[i]; i++) { c = toupper(src[i]); dst[j++] = 'A'+((c>>4)&0x0f); dst[j++] = 'A'+((c>>0)&0x0f); } //add spaces for(; i<15; i++) { dst[j++] = 'A'+((' '>>4)&0x0f); dst[j++] = 'A'+((' '>>0)&0x0f); } //set type (0x00 = Workstation) dst[j++] = 'A'+((type>>4)&0x0f); dst[j++] = 'A'+((type>>0)&0x0f); } #endif /** NetBIOS Name service recv callback */ static void NETBIOS_CODE_ATTR netbios_recv(void *arg, struct udp_pcb *upcb, struct pbuf *p, ip_addr_t *addr, u16_t port) { LWIP_UNUSED_ARG(arg); /* if packet is valid */ if (p != NULL && p->len >= sizeof(struct netbios_hdr) + sizeof(struct netbios_name_hdr) - 12) { if (current_netif != NULL && current_netif->num < NET_IF_NUM) { uint32 ip = current_netif->ip_addr.addr; char *curbiosname = netbios_name[current_netif->num]; if (curbiosname[0] != '\0' && ip != NULL /* we only answer if we got a default interface */ && (((ip ^ addr->addr) & current_netif->netmask.addr) == 0)) { // запрет ответа другой подсети #if DEBUGSOO > 3 os_printf("nbns: " IPSTR ",\t'%s'\n", IP2STR(&ip), curbiosname); #endif char netbiosname[NETBIOS_NAME_LEN + 1]; os_memset(netbiosname, 0, sizeof(netbiosname)); struct netbios_hdr* netbios_hdr = (struct netbios_hdr*) p->payload; struct netbios_name_hdr* netbios_name_hdr = (struct netbios_name_hdr*) (netbios_hdr + 1); /* @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)) && (netbios_name_hdr->cls == PP_NTOHS(1)) && (netbios_name_hdr->type == PP_NTOHS(0x20))) { /* decode the NetBIOS name */ int8_t ret = NBNS_decode(netbiosname, (char*) (netbios_name_hdr->encname)); /* if the packet is for us */ #if DEBUGSOO > 2 if (ret == 0) os_printf("nbns: get " IPSTR ", '%s'\n", IP2STR(addr), netbiosname); #endif if (ret == 0 && NETBIOS_STRCMP(curbiosname, netbiosname) == 0) { // netbiosname[0] == '*' #if DEBUGSOO > 1 os_printf("nbns: out " IPSTR ", '%s'\n", IP2STR(&ip), curbiosname); #endif 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_name_hdr->encname, sizeof(netbios_name_hdr->encname)); resp->resp_name.nametype = netbios_name_hdr->nametype; resp->resp_name.type = netbios_name_hdr->type; resp->resp_name.cls = netbios_name_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); resp->resp_name.addr.addr = ip; // netif_default->ip_addr.addr; /* send the NetBIOS response */ udp_sendto(upcb, q, addr, port); /* free the "reference" pbuf */ pbuf_free(q); } } } } } /* free the pbuf */ pbuf_free(p); } } struct udp_pcb * NETBIOS_CODE_ATTR netbios_pcb(void) { struct udp_pcb *pcb; for (pcb = udp_pcbs; pcb != NULL; pcb = pcb->next) { if (pcb->local_port == NETBIOS_PORT) return pcb; } return NULL; } /* default netifs/interfacenum: 0 - SoftAP, 1 - Station, 2 - Ethernet */ bool NETBIOS_CODE_ATTR netbios_set_name(unsigned char interfacenum, char * name) { if (interfacenum >= NET_IF_NUM) return false; int i; uint8 * pnbn = netbios_name[interfacenum]; uint8 * pmane = name; if (name != NULL) { for (i = 0; i < NETBIOS_NAME_LEN; i++) { if (*pmane < ' ') break; else if (*pmane == ' ') *pnbn++ = '_'; else *pnbn++ = toupper(*pmane); pmane++; }; }; *pnbn = '\0'; return true; } bool NETBIOS_CODE_ATTR netbios_off(void) { struct udp_pcb *pcb = netbios_pcb(); if (pcb == NULL) return false; udp_remove(pcb); return true; } void NETBIOS_CODE_ATTR netbios_init(void) { struct udp_pcb *pcb; char buf[] = "a"NBS_DEF_NAME; #if NET_IF_NUM > 0 if (netbios_name[0][0] == 0) { buf[0] = 'a'; // SoftAP netbios_set_name(0, buf); } #endif #if NET_IF_NUM > 1 if (netbios_name[1][0] == 0) { buf[0] = 's'; // Station netbios_set_name(1, buf); } #endif #if NET_IF_NUM > 2 if (netbios_name[2][0] == 0) { buf[0] = 'e'; // Ethernet netbios_set_name(2, buf); } #endif #if NET_IF_NUM > 3 #error "NBNS: Add NETBIOS Name!" #endif if (netbios_pcb() != NULL) return; #if DEBUGSOO > 1 #if NET_IF_NUM > 2 // os_printf("NetBIOS init, name AP: '%s', ST: '%s', Eth: '%s'\n", netbios_name[0], netbios_name[1], netbios_name[2]); os_printf("NetBIOS init, interface 0: '%s', 1: '%s', 2: '%s'\n", netbios_name[0], netbios_name[1], netbios_name[2]); #elif NET_IF_NUM > 1 // os_printf("NetBIOS init, name AP: '%s', ST: '%s'\n", netbios_name[0], netbios_name[1]); os_printf("NetBIOS init, interface 0: '%s', 1: '%s'\n", netbios_name[0], netbios_name[1]); #else os_printf("NetBIOS init\n"); #endif #endif pcb = udp_new(); if (pcb != NULL) { /* we have to be allowed to send broadcast packets! */ pcb->so_options |= SOF_BROADCAST; udp_bind(pcb, IP_ADDR_ANY, NETBIOS_PORT); udp_recv(pcb, netbios_recv, pcb); } } #endif /* LWIP_UDP */ #endif // USE_NETBIOS