Занимался этим очень давно, деталей не помню уже. Основная задача была поднять mdns + autoip. netbios прикрутил к проекту за полдня, столько же поигрался с ним в корпоративной сети. Рабочая машины находилась в домене, устройство находилось вне домена (не знаю насколько это критично с сетевой точки зрения) и пинговалось по имени ("BRIDGE-TEST") без проблем.
Код "портирован" для uIP, компилер ИАР, netbios_name_decoding() удалена для уменьшения размера кода
//#include "lwip/opt.h"
//#include "lwip/udp.h"
//#include "lwip/netif.h"
#include <string.h>
#include "Trace/dbg_cfg.h"
#define DBG_SCOPE NETBIOS_DBG
#include "Trace/dbg.h"
#include "uip.h"
#if UIP_UDP /* don't build if not configured for use in lwipopts.h */
#include "netbios.h"
#define PP_NTOHS HTONS
#define PP_HTONS HTONS
//#define PP_HTONL HTONS
/** 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!
*/
/** 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 : "" : "")
*/
#ifndef NETBIOS_LWIP_NAME
#define NETBIOS_LWIP_NAME "BRIDGE-TEST"
#endif
/** 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) strcmp(str1, str2)
#endif
/** 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 300000
/** NetBIOS header flags */
#define NETB_HFLAG_RESPONSE 0x8000
#define NETB_HFLAG_OPCODE 0x7800
#define NETB_HFLAG_OPCODE_NAME_QUERY 0x0000
#define NETB_HFLAG_AUTHORATIVE 0x0400
#define NETB_HFLAG_TRUNCATED 0x0200
#define NETB_HFLAG_RECURS_DESIRED 0x0100
#define NETB_HFLAG_RECURS_AVAILABLE 0x0080
#define NETB_HFLAG_BROADCAST 0x0010
#define NETB_HFLAG_REPLYCODE 0x0008
#define NETB_HFLAG_REPLYCODE_NOERROR 0x0000
/** NetBIOS name flags */
#define NETB_NFLAG_UNIQUE 0x8000
#define NETB_NFLAG_NODETYPE 0x6000
#define NETB_NFLAG_NODETYPE_HNODE 0x6000
#define NETB_NFLAG_NODETYPE_MNODE 0x4000
#define NETB_NFLAG_NODETYPE_PNODE 0x2000
#define NETB_NFLAG_NODETYPE_BNODE 0x0000
/** NetBIOS message header */
#pragma pack(1)
struct netbios_hdr
{
u16_t trans_id;
u16_t flags;
u16_t questions;
u16_t answerRRs;
u16_t authorityRRs;
u16_t additionalRRs;
};
#pragma pack()
/** NetBIOS message name part */
#pragma pack(1)
struct netbios_name_hdr
{
u8_t nametype;
u8_t encname[(NETBIOS_NAME_LEN*2)+1];
u16_t type;
u16_t cls;
u32_t ttl;
u16_t datalen;
u16_t flags;
// ip_addr_p_t
uip_ipaddr_t addr;
// u8_t addr[4];
};
#pragma pack()
/** NetBIOS message */
#pragma pack(1)
struct netbios_resp
{
struct netbios_hdr resp_hdr;
struct netbios_name_hdr resp_name;
};
#pragma pack()
/** NetBIOS Name service recv callback */
//static
void netbios_recv()//(void *arg, struct udp_pcb *upcb, struct pbuf *p, /*ip_addr_t*/ uip_ipaddr_t *addr, u16_t port)
{
/* if packet is valid */
char netbios_name[NETBIOS_NAME_LEN+1];
// struct netbios_hdr* netbios_hdr = (struct netbios_hdr*)p->payload;
// struct dhcp_msg *m = (struct dhcp_msg *)uip_appdata;
struct netbios_hdr* netbios_hdr = (struct netbios_hdr*)uip_appdata;
struct netbios_name_hdr* netbios_name_hdr = (struct netbios_name_hdr*)(netbios_hdr+1);
/* 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)))
{
DBG_PRINTF(("netbios_recv:: NetBIOS name query question\n"));
/* decode the NetBIOS name */
netbios_name_decoding((char*)(netbios_name_hdr->encname), netbios_name);
DBG_PRINTF(("netbios_recv:: netbios_name_decoding = %s\n", netbios_name));
/* if the packet is for us */
if (NETBIOS_STRCMP(netbios_name, NETBIOS_LWIP_NAME) == 0)
{
struct netbios_resp *resp;
DBG_PRINTF(("netbios_recv:: netbios_name is OK\n"));
// q = pbuf_alloc(PBUF_TRANSPORT, sizeof(struct netbios_resp), PBUF_RAM);
// if (q != NULL)
// {
//resp = (struct netbios_resp*)q->payload;
resp = (struct netbios_resp*)uip_appdata;
/* 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
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 = 0xE0930400; //0x00.04.93.E0 = 300,000 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);
// ip_addr_copy(resp->resp_name.addr, netif_default->ip_addr);
// uip_ipaddr_copy(resp->resp_name.addr,uip_hostaddr);
resp->resp_name.addr[0] = uip_hostaddr[0];
resp->resp_name.addr[1] = uip_hostaddr[1];
// resp->resp_name.addr[0] = (u8_t)(uip_hostaddr[0]&0xFF);
// resp->resp_name.addr[1] = (u8_t)((uip_hostaddr[0]>>8)&0xFF);
// resp->resp_name.addr[2] = (u8_t)(uip_hostaddr[1]&0xFF);
// resp->resp_name.addr[3] = (u8_t)((uip_hostaddr[1]>>8)&0xFF);
uip_send(uip_appdata, sizeof(struct netbios_resp));
/* send the NetBIOS response */
// udp_sendto(upcb, q, addr, port);
/* free the "reference" pbuf */
// pbuf_free(q);
}
}
}
void netbios_init(void)
{
// struct udp_pcb *pcb;
// LWIP_ASSERT("NetBIOS name is too long!", strlen(NETBIOS_LWIP_NAME) < NETBIOS_NAME_LEN);
// 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);
// }
struct uip_udp_conn *conn;
uip_ipaddr_t zeroes_addr = {0x0000,0x0000};
conn = uip_udp_new(&zeroes_addr, 0);
DBG_PRINTF(("udp_listen NETBIOS_PORT\n"));
if(conn != NULL)
{
uip_udp_bind(conn, HTONS(NETBIOS_PORT));
}
}
void netbios_appcall(void)
{
// if(uip_aborted()) { }
// if(uip_timedout()) { }
// if(uip_closed()) { }
// if(uip_connected()){ }
// if(uip_newdata())
// {
DBG_PRINTF(("netbios_appcall >>>>>>>>>>>>>>>>>>>>>>>>>>\n"));
if (uip_conn->lport == NETBIOS_PORT)
{
DBG_PRINTF(("netbios_appcall:: uip_conn->lport == NETBIOS_PORT\n"));
netbios_recv();//(uip_conn);
}
// }
// if(uip_rexmit()) { }
// if(uip_acked()) { }
// if(uip_poll()) { }
}
#endif //#if UIP_UDP