open-ameba/RTL00_SDKV35a/component/common/network/netbios/netbios.c

397 lines
12 KiB
C
Raw Normal View History

2016-12-22 13:27:32 +00:00
/**
* @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 <string.h>
#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