Skip to content

Commit c99614c

Browse files
Add AsyncUDP and simple NetBIOS name lookup server (earlephilhower#2234)
Thanks to @me-no-dev's code. Lets Windows look up the PicoW by name using NBNS and needs much less memory and code than mDNS. AsyncUDP ported from the old ESP8266 version, only minimal changes. Will probably only be valid in IPv4 environments and may not match current ESP32 AsyncUDP interfaces.
1 parent 352d363 commit c99614c

File tree

9 files changed

+239
-2
lines changed

9 files changed

+239
-2
lines changed

.github/workflows/pull-request.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ jobs:
2525
uses: codespell-project/actions-codespell@master
2626
with:
2727
skip: ./ArduinoCore-API,./libraries/ESP8266SdFat,./libraries/Adafruit_TinyUSB_Arduino,./libraries/LittleFS/lib,./tools/pyserial,./pico-sdk,./.github,./docs/i2s.rst,./cores/rp2040/api,./libraries/FreeRTOS,./tools/libbearssl/bearssl,./include,./libraries/WiFi/examples/BearSSL_Server,./ota/uzlib,./libraries/http-parser/lib,./libraries/WebServer/examples/HelloServerBearSSL/HelloServerBearSSL.ino,./libraries/HTTPUpdateServer/examples/SecureBearSSLUpdater/SecureBearSSLUpdater.ino,./.git,./libraries/FatFS/lib/fatfs,./libraries/FatFS/src/diskio.h,./libraries/FatFS/src/ff.cpp,./libraries/FatFS/src/ffconf.h,./libraries/FatFS/src/ffsystem.cpp,./libraries/FatFS/src/ff.h,./libraries/lwIP_WINC1500/src/driver,./libraries/lwIP_WINC1500/src/common,./libraries/lwIP_WINC1500/src/bus_wrapper,./libraries/lwIP_WINC1500/src/spi_flash
28-
ignore_words_list: ser,dout,shiftIn
28+
ignore_words_list: ser,dout,shiftIn,acount
2929

3030
# Consistent style
3131
astyle:

.gitmodules

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,3 +40,6 @@
4040
[submodule "libraries/FatFS/lib/SPIFTL"]
4141
path = libraries/FatFS/lib/SPIFTL
4242
url = https://github.com/earlephilhower/SPIFTL.git
43+
[submodule "libraries/AsyncUDP"]
44+
path = libraries/AsyncUDP
45+
url = https://github.com/earlephilhower/AsyncUDP.git

libraries/AsyncUDP

Submodule AsyncUDP added at dd32bfa
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
// Modified from the ESP32-NetBIOS example
2+
3+
#include <WiFi.h>
4+
#include <NetBIOS.h>
5+
6+
#ifndef STASSID
7+
#define STASSID "your-ssid"
8+
#define STAPSK "your-password"
9+
#endif
10+
11+
const char* ssid = STASSID;
12+
const char* password = STAPSK;
13+
14+
void setup() {
15+
Serial.begin(115200);
16+
17+
// Connect to WiFi network
18+
WiFi.mode(WIFI_STA);
19+
WiFi.begin(ssid, password);
20+
Serial.println("");
21+
22+
// Wait for connection
23+
while (WiFi.status() != WL_CONNECTED) {
24+
delay(500);
25+
Serial.print(".");
26+
}
27+
Serial.println("");
28+
Serial.print("Connected to ");
29+
Serial.println(ssid);
30+
Serial.print("IP address: ");
31+
Serial.println(WiFi.localIP());
32+
33+
// Windows (and other OSes using WINS/NetBIOS resolution should now be able to find the device by name)
34+
NBNS.begin("PicoW");
35+
}
36+
37+
void loop() {}

libraries/NetBIOS/keywords.txt

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
#######################################
2+
# Syntax Coloring Map For ESPNBNS
3+
#######################################
4+
5+
#######################################
6+
# Datatypes (KEYWORD1)
7+
#######################################
8+
9+
NetBIOS KEYWORD1
10+
11+
#######################################
12+
# Methods and Functions (KEYWORD2)
13+
#######################################
14+
15+
begin KEYWORD2
16+
17+
#######################################
18+
# Instances (KEYWORD2)
19+
#######################################
20+
21+
NBNS KEYWORD2
22+
23+
#######################################
24+
# Constants (LITERAL1)
25+
#######################################

libraries/NetBIOS/library.properties

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
name=NetBIOS
2+
version=2.0.0
3+
author=Pablo@xpablo.cz
4+
maintainer=Earle F. Philhower, III <earlephilhower@yahoo.com>
5+
sentence=Enables NBNS (NetBIOS) name resolution.
6+
paragraph=With this library you can connect to your ESP from Windows using a short name
7+
category=Communication
8+
url=http://www.xpablo.cz/?p=751#more-751
9+
architectures=rp2040

libraries/NetBIOS/src/NetBIOS.cpp

Lines changed: 141 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,141 @@
1+
#include "NetBIOS.h"
2+
#include <functional>
3+
#include <lwip/netif.h>
4+
5+
#define NBNS_PORT 137
6+
#define NBNS_MAX_HOSTNAME_LEN 32
7+
8+
typedef struct {
9+
uint16_t id;
10+
uint8_t flags1;
11+
uint8_t flags2;
12+
uint16_t qcount;
13+
uint16_t acount;
14+
uint16_t nscount;
15+
uint16_t adcount;
16+
uint8_t name_len;
17+
char name[NBNS_MAX_HOSTNAME_LEN + 1];
18+
uint16_t type;
19+
uint16_t clas;
20+
} __attribute__((packed)) nbns_question_t;
21+
22+
typedef struct {
23+
uint16_t id;
24+
uint8_t flags1;
25+
uint8_t flags2;
26+
uint16_t qcount;
27+
uint16_t acount;
28+
uint16_t nscount;
29+
uint16_t adcount;
30+
uint8_t name_len;
31+
char name[NBNS_MAX_HOSTNAME_LEN + 1];
32+
uint16_t type;
33+
uint16_t clas;
34+
uint32_t ttl;
35+
uint16_t data_len;
36+
uint16_t flags;
37+
uint32_t addr;
38+
} __attribute__((packed)) nbns_answer_t;
39+
40+
static void _getnbname(const char *nbname, char *name, uint8_t maxlen) {
41+
uint8_t b;
42+
uint8_t c = 0;
43+
44+
while ((*nbname) && (c < maxlen)) {
45+
b = (*nbname++ - 'A') << 4;
46+
c++;
47+
if (*nbname) {
48+
b |= *nbname++ - 'A';
49+
c++;
50+
}
51+
if (!b || b == ' ') {
52+
break;
53+
}
54+
*name++ = b;
55+
}
56+
*name = 0;
57+
}
58+
59+
static void append_16(void *dst, uint16_t value) {
60+
uint8_t *d = (uint8_t *)dst;
61+
*d++ = (value >> 8) & 0xFF;
62+
*d++ = value & 0xFF;
63+
}
64+
65+
static void append_32(void *dst, uint32_t value) {
66+
uint8_t *d = (uint8_t *)dst;
67+
*d++ = (value >> 24) & 0xFF;
68+
*d++ = (value >> 16) & 0xFF;
69+
*d++ = (value >> 8) & 0xFF;
70+
*d++ = value & 0xFF;
71+
}
72+
73+
void NetBIOS::_onPacket(AsyncUDPPacket &packet) {
74+
if (packet.length() >= sizeof(nbns_question_t)) {
75+
nbns_question_t *question = (nbns_question_t *)packet.data();
76+
if (0 == (question->flags1 & 0x80)) {
77+
char name[NBNS_MAX_HOSTNAME_LEN + 1];
78+
_getnbname(&question->name[0], (char *)&name, question->name_len);
79+
if (_name.equals(name)) {
80+
nbns_answer_t nbnsa;
81+
nbnsa.id = question->id;
82+
nbnsa.flags1 = 0x85;
83+
nbnsa.flags2 = 0;
84+
append_16((void *)&nbnsa.qcount, 0);
85+
append_16((void *)&nbnsa.acount, 1);
86+
append_16((void *)&nbnsa.nscount, 0);
87+
append_16((void *)&nbnsa.adcount, 0);
88+
nbnsa.name_len = question->name_len;
89+
memcpy(&nbnsa.name[0], &question->name[0], question->name_len + 1);
90+
append_16((void *)&nbnsa.type, 0x20);
91+
append_16((void *)&nbnsa.clas, 1);
92+
append_32((void *)&nbnsa.ttl, 300000);
93+
append_16((void *)&nbnsa.data_len, 6);
94+
append_16((void *)&nbnsa.flags, 0);
95+
nbnsa.addr = packet.localIP(); // Wrong, but better than nothing
96+
// Iterate over all netifs, see if the incoming address matches one of the netmaskes networks
97+
// TODO - is there an easier way of seeing whicn netif produced a packet?
98+
for (auto netif = netif_list; netif; netif = netif->next) {
99+
auto maskedip = ip4_addr_get_u32(netif_ip4_addr(netif)) & ip4_addr_get_u32(netif_ip4_netmask(netif));
100+
auto maskedin = ((uint32_t)packet.localIP()) & ip4_addr_get_u32(netif_ip4_netmask(netif));
101+
if (maskedip == maskedin) {
102+
nbnsa.addr = ip4_addr_get_u32(netif_ip4_addr(netif));
103+
break;
104+
}
105+
}
106+
_udp.writeTo((uint8_t *)&nbnsa, sizeof(nbnsa), packet.remoteIP(), NBNS_PORT);
107+
}
108+
}
109+
}
110+
}
111+
112+
NetBIOS::NetBIOS() {}
113+
114+
NetBIOS::~NetBIOS() {
115+
end();
116+
}
117+
118+
bool NetBIOS::begin(const char *name) {
119+
_name = name;
120+
_name.toUpperCase();
121+
122+
if (_udp.connected()) {
123+
return true;
124+
}
125+
126+
_udp.onPacket(
127+
[](void *arg, AsyncUDPPacket & packet) {
128+
((NetBIOS *)(arg))->_onPacket(packet);
129+
},
130+
this
131+
);
132+
return _udp.listen(NBNS_PORT);
133+
}
134+
135+
void NetBIOS::end() {
136+
if (_udp.connected()) {
137+
_udp.close();
138+
}
139+
}
140+
141+
NetBIOS NBNS;

libraries/NetBIOS/src/NetBIOS.h

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
//
2+
3+
#pragma once
4+
5+
#include <Arduino.h>
6+
#include <AsyncUDP.h>
7+
8+
class NetBIOS {
9+
protected:
10+
AsyncUDP _udp;
11+
String _name;
12+
void _onPacket(AsyncUDPPacket &packet);
13+
14+
public:
15+
NetBIOS();
16+
~NetBIOS();
17+
bool begin(const char *name);
18+
void end();
19+
};
20+
21+
extern NetBIOS NBNS;

tests/restyle.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ for dir in ./cores/rp2040 ./libraries/EEPROM ./libraries/I2S ./libraries/SingleF
1616
./libraries/lwIP_w5500 ./libraries/lwIP_w5100 ./libraries/lwIP_enc28j60 \
1717
./libraries/SPISlave ./libraries/lwIP_ESPHost ./libraries/FatFS\
1818
./libraries/FatFSUSB ./libraries/BluetoothAudio ./libraries/BluetoothHCI \
19-
./libraries/BluetoothHIDMaster; do
19+
./libraries/BluetoothHIDMaster ./libraries/NetBIOS; do
2020
find $dir -type f \( -name "*.c" -o -name "*.h" -o -name "*.cpp" \) -a \! -path '*api*' -exec astyle --suffix=none --options=./tests/astyle_core.conf \{\} \;
2121
find $dir -type f -name "*.ino" -exec astyle --suffix=none --options=./tests/astyle_examples.conf \{\} \;
2222
done

0 commit comments

Comments
 (0)