STM32F769IDiscovery  1.00
uDANTE Audio Networking with STM32F7 DISCO board
netbiosns.c
Go to the documentation of this file.
1 
13 /*
14  * Redistribution and use in source and binary forms, with or without modification,
15  * are permitted provided that the following conditions are met:
16  *
17  * 1. Redistributions of source code must retain the above copyright notice,
18  * this list of conditions and the following disclaimer.
19  * 2. Redistributions in binary form must reproduce the above copyright notice,
20  * this list of conditions and the following disclaimer in the documentation
21  * and/or other materials provided with the distribution.
22  * 3. The name of the author may not be used to endorse or promote products
23  * derived from this software without specific prior written permission.
24  *
25  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
26  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
27  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
28  * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
29  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
30  * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
31  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
32  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
33  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
34  * OF SUCH DAMAGE.
35  *
36  * This file is part of the lwIP TCP/IP stack.
37  *
38  */
39 
40 #include "lwip/apps/netbiosns.h"
41 
42 #if LWIP_IPV4 && LWIP_UDP /* don't build if not configured for use in lwipopts.h */
43 
44 #include "lwip/udp.h"
45 #include "lwip/netif.h"
46 
47 #include <string.h>
48 
50 #define NETBIOS_PORT 137
51 
53 #define NETBIOS_NAME_LEN 16
54 
57 #define NETBIOS_NAME_TTL 300000u
58 
60 #define NETB_HFLAG_RESPONSE 0x8000U
61 #define NETB_HFLAG_OPCODE 0x7800U
62 #define NETB_HFLAG_OPCODE_NAME_QUERY 0x0000U
63 #define NETB_HFLAG_AUTHORATIVE 0x0400U
64 #define NETB_HFLAG_TRUNCATED 0x0200U
65 #define NETB_HFLAG_RECURS_DESIRED 0x0100U
66 #define NETB_HFLAG_RECURS_AVAILABLE 0x0080U
67 #define NETB_HFLAG_BROADCAST 0x0010U
68 #define NETB_HFLAG_REPLYCODE 0x0008U
69 #define NETB_HFLAG_REPLYCODE_NOERROR 0x0000U
70 
72 #define NETB_NFLAG_UNIQUE 0x8000U
73 #define NETB_NFLAG_NODETYPE 0x6000U
74 #define NETB_NFLAG_NODETYPE_HNODE 0x6000U
75 #define NETB_NFLAG_NODETYPE_MNODE 0x4000U
76 #define NETB_NFLAG_NODETYPE_PNODE 0x2000U
77 #define NETB_NFLAG_NODETYPE_BNODE 0x0000U
78 
80 #ifdef PACK_STRUCT_USE_INCLUDES
81 # include "arch/bpstruct.h"
82 #endif
84 struct netbios_hdr {
85  PACK_STRUCT_FIELD(u16_t trans_id);
86  PACK_STRUCT_FIELD(u16_t flags);
87  PACK_STRUCT_FIELD(u16_t questions);
88  PACK_STRUCT_FIELD(u16_t answerRRs);
89  PACK_STRUCT_FIELD(u16_t authorityRRs);
90  PACK_STRUCT_FIELD(u16_t additionalRRs);
93 #ifdef PACK_STRUCT_USE_INCLUDES
94 # include "arch/epstruct.h"
95 #endif
96 
98 #ifdef PACK_STRUCT_USE_INCLUDES
99 # include "arch/bpstruct.h"
100 #endif
102 struct netbios_name_hdr {
103  PACK_STRUCT_FLD_8(u8_t nametype);
104  PACK_STRUCT_FLD_8(u8_t encname[(NETBIOS_NAME_LEN*2)+1]);
105  PACK_STRUCT_FIELD(u16_t type);
108  PACK_STRUCT_FIELD(u16_t datalen);
109  PACK_STRUCT_FIELD(u16_t flags);
110  PACK_STRUCT_FLD_S(ip4_addr_p_t addr);
113 #ifdef PACK_STRUCT_USE_INCLUDES
114 # include "arch/epstruct.h"
115 #endif
116 
118 #ifdef PACK_STRUCT_USE_INCLUDES
119 # include "arch/bpstruct.h"
120 #endif
122 struct netbios_resp
123 {
124  struct netbios_hdr resp_hdr;
125  struct netbios_name_hdr resp_name;
128 #ifdef PACK_STRUCT_USE_INCLUDES
129 # include "arch/epstruct.h"
130 #endif
131 
132 #ifdef NETBIOS_LWIP_NAME
133 #define NETBIOS_LOCAL_NAME NETBIOS_LWIP_NAME
134 #else
135 static char netbiosns_local_name[NETBIOS_NAME_LEN];
136 #define NETBIOS_LOCAL_NAME netbiosns_local_name
137 #endif
138 
139 struct udp_pcb *netbiosns_pcb;
140 
142 static int
143 netbiosns_name_decode(char *name_enc, char *name_dec, int name_dec_len)
144 {
145  char *pname;
146  char cname;
147  char cnbname;
148  int idx = 0;
149 
150  LWIP_UNUSED_ARG(name_dec_len);
151 
152  /* Start decoding netbios name. */
153  pname = name_enc;
154  for (;;) {
155  /* Every two characters of the first level-encoded name
156  * turn into one character in the decoded name. */
157  cname = *pname;
158  if (cname == '\0')
159  break; /* no more characters */
160  if (cname == '.')
161  break; /* scope ID follows */
162  if (cname < 'A' || cname > 'Z') {
163  /* Not legal. */
164  return -1;
165  }
166  cname -= 'A';
167  cnbname = cname << 4;
168  pname++;
169 
170  cname = *pname;
171  if (cname == '\0' || cname == '.') {
172  /* No more characters in the name - but we're in
173  * the middle of a pair. Not legal. */
174  return -1;
175  }
176  if (cname < 'A' || cname > 'Z') {
177  /* Not legal. */
178  return -1;
179  }
180  cname -= 'A';
181  cnbname |= cname;
182  pname++;
183 
184  /* Do we have room to store the character? */
185  if (idx < NETBIOS_NAME_LEN) {
186  /* Yes - store the character. */
187  name_dec[idx++] = (cnbname!=' '?cnbname:'\0');
188  }
189  }
190 
191  return 0;
192 }
193 
194 #if 0 /* function currently unused */
195 
197 static int
198 netbiosns_name_encode(char *name_enc, char *name_dec, int name_dec_len)
199 {
200  char *pname;
201  char cname;
202  unsigned char ucname;
203  int idx = 0;
204 
205  /* Start encoding netbios name. */
206  pname = name_enc;
207 
208  for (;;) {
209  /* Every two characters of the first level-encoded name
210  * turn into one character in the decoded name. */
211  cname = *pname;
212  if (cname == '\0')
213  break; /* no more characters */
214  if (cname == '.')
215  break; /* scope ID follows */
216  if ((cname < 'A' || cname > 'Z') && (cname < '0' || cname > '9')) {
217  /* Not legal. */
218  return -1;
219  }
220 
221  /* Do we have room to store the character? */
222  if (idx >= name_dec_len) {
223  return -1;
224  }
225 
226  /* Yes - store the character. */
227  ucname = cname;
228  name_dec[idx++] = ('A'+((ucname>>4) & 0x0F));
229  name_dec[idx++] = ('A'+( ucname & 0x0F));
230  pname++;
231  }
232 
233  /* Fill with "space" coding */
234  for (;idx < name_dec_len - 1;) {
235  name_dec[idx++] = 'C';
236  name_dec[idx++] = 'A';
237  }
238 
239  /* Terminate string */
240  name_dec[idx] = '\0';
241 
242  return 0;
243 }
244 #endif /* 0 */
245 
247 static void
248 netbiosns_recv(void *arg, struct udp_pcb *upcb, struct pbuf *p, const ip_addr_t *addr, u16_t port)
249 {
250  LWIP_UNUSED_ARG(arg);
251 
252  /* if packet is valid */
253  if (p != NULL) {
254  char netbios_name[NETBIOS_NAME_LEN+1];
255  struct netbios_hdr* netbios_hdr = (struct netbios_hdr*)p->payload;
256  struct netbios_name_hdr* netbios_name_hdr = (struct netbios_name_hdr*)(netbios_hdr+1);
257 
258  /* we only answer if we got a default interface */
259  if (netif_default != NULL) {
260  /* @todo: do we need to check answerRRs/authorityRRs/additionalRRs? */
261  /* if the packet is a NetBIOS name query question */
262  if (((netbios_hdr->flags & PP_NTOHS(NETB_HFLAG_OPCODE)) == PP_NTOHS(NETB_HFLAG_OPCODE_NAME_QUERY)) &&
263  ((netbios_hdr->flags & PP_NTOHS(NETB_HFLAG_RESPONSE)) == 0) &&
264  (netbios_hdr->questions == PP_NTOHS(1))) {
265  /* decode the NetBIOS name */
266  netbiosns_name_decode((char*)(netbios_name_hdr->encname), netbios_name, sizeof(netbios_name));
267  /* if the packet is for us */
268  if (NETBIOS_STRCMP(netbios_name, NETBIOS_LOCAL_NAME) == 0) {
269  struct pbuf *q;
270  struct netbios_resp *resp;
271 
272  q = pbuf_alloc(PBUF_TRANSPORT, sizeof(struct netbios_resp), PBUF_RAM);
273  if (q != NULL) {
274  resp = (struct netbios_resp*)q->payload;
275 
276  /* prepare NetBIOS header response */
277  resp->resp_hdr.trans_id = netbios_hdr->trans_id;
278  resp->resp_hdr.flags = PP_HTONS(NETB_HFLAG_RESPONSE |
279  NETB_HFLAG_OPCODE_NAME_QUERY |
280  NETB_HFLAG_AUTHORATIVE |
281  NETB_HFLAG_RECURS_DESIRED);
282  resp->resp_hdr.questions = 0;
283  resp->resp_hdr.answerRRs = PP_HTONS(1);
284  resp->resp_hdr.authorityRRs = 0;
285  resp->resp_hdr.additionalRRs = 0;
286 
287  /* prepare NetBIOS header datas */
288  MEMCPY( resp->resp_name.encname, netbios_name_hdr->encname, sizeof(netbios_name_hdr->encname));
289  resp->resp_name.nametype = netbios_name_hdr->nametype;
290  resp->resp_name.type = netbios_name_hdr->type;
291  resp->resp_name.cls = netbios_name_hdr->cls;
292  resp->resp_name.ttl = PP_HTONL(NETBIOS_NAME_TTL);
293  resp->resp_name.datalen = PP_HTONS(sizeof(resp->resp_name.flags)+sizeof(resp->resp_name.addr));
294  resp->resp_name.flags = PP_HTONS(NETB_NFLAG_NODETYPE_BNODE);
295  ip4_addr_copy(resp->resp_name.addr, *netif_ip4_addr(netif_default));
296 
297  /* send the NetBIOS response */
298  udp_sendto(upcb, q, addr, port);
299 
300  /* free the "reference" pbuf */
301  pbuf_free(q);
302  }
303  }
304  }
305  }
306  /* free the pbuf */
307  pbuf_free(p);
308  }
309 }
310 
311 void
312 netbiosns_init(void)
313 {
314 #ifdef NETBIOS_LWIP_NAME
315  LWIP_ASSERT("NetBIOS name is too long!", strlen(NETBIOS_LWIP_NAME) < NETBIOS_NAME_LEN);
316 #endif
317 
318  netbiosns_pcb = udp_new();
319  if (netbiosns_pcb != NULL) {
320  /* we have to be allowed to send broadcast packets! */
321  netbiosns_pcb->so_options |= SOF_BROADCAST;
322  udp_bind(netbiosns_pcb, IP_ADDR_ANY, NETBIOS_PORT);
323  udp_recv(netbiosns_pcb, netbiosns_recv, netbiosns_pcb);
324  }
325 }
326 
327 #ifndef NETBIOS_LWIP_NAME
328 /* ATTENTION: the hostname must be <= 15 characters! */
329 void
330 netbiosns_set_name(const char* hostname)
331 {
332  size_t copy_len = strlen(hostname);
333  LWIP_ASSERT("NetBIOS name is too long!", copy_len < NETBIOS_NAME_LEN);
334  if(copy_len >= NETBIOS_NAME_LEN) {
335  copy_len = NETBIOS_NAME_LEN - 1;
336  }
337  memcpy(netbiosns_local_name, hostname, copy_len + 1);
338 }
339 #endif
340 
341 void
342 netbiosns_stop(void)
343 {
344  if (netbiosns_pcb != NULL) {
345  udp_remove(netbiosns_pcb);
346  netbiosns_pcb = NULL;
347  }
348 }
349 
350 #endif /* LWIP_IPV4 && LWIP_UDP */
#define PP_HTONL(x)
Definition: def.h:99
#define PACK_STRUCT_STRUCT
Definition: arch.h:68
struct netif * netif_default
Definition: netif.c:85
uint32_t idx
Definition: lcd_log.c:247
#define PACK_STRUCT_FLD_8(x)
Definition: arch.h:78
void netbiosns_init(void)
#define MEMCPY(dst, src, len)
Definition: opt.h:84
#define PACK_STRUCT_FIELD(x)
Definition: arch.h:72
struct pbuf * pbuf_alloc(pbuf_layer layer, u16_t length, pbuf_type type)
Definition: pbuf.c:199
Definition: pbuf.h:77
#define NULL
Definition: usbd_def.h:53
u8_t pbuf_free(struct pbuf *p)
Definition: pbuf.c:652
#define PP_HTONS(x)
Definition: def.h:97
unsigned long u32_t
Definition: cc.h:42
Definition: pbuf.h:108
#define LWIP_ASSERT(message, assertion)
Definition: debug.h:70
void netbiosns_stop(void)
#define NETBIOS_STRCMP(str1, str2)
#define PACK_STRUCT_FLD_S(x)
Definition: arch.h:84
#define PACK_STRUCT_BEGIN
Definition: arch.h:60
#define SOF_BROADCAST
Definition: ip.h:120
#define PP_NTOHS(x)
Definition: def.h:98
void netbiosns_set_name(const char *hostname)
unsigned char u8_t
Definition: cc.h:38
ip6_addr_t ip_addr_t
Definition: ip_addr.h:194
#define PACK_STRUCT_END
Definition: arch.h:64
#define LWIP_UNUSED_ARG(x)
Definition: arch.h:89
unsigned short u16_t
Definition: cc.h:40
void * payload
Definition: pbuf.h:113