source: azure_iot_hub_f767zi/trunk/asp_baseplatform/lwip/lwip-2.1.2/src/apps/netbiosns/netbiosns.c@ 457

Last change on this file since 457 was 457, checked in by coas-nagasima, 4 years ago

ファイルを追加

  • Property svn:eol-style set to native
  • Property svn:mime-type set to text/x-csrc;charset=UTF-8
File size: 18.2 KB
Line 
1 /**
2 * @file
3 * NetBIOS name service responder
4 */
5
6/**
7 * @defgroup netbiosns NETBIOS responder
8 * @ingroup apps
9 *
10 * This is an example implementation of a NetBIOS name server.
11 * It responds to name queries for a configurable name.
12 * Name resolving is not supported.
13 *
14 * Note that the device doesn't broadcast it's own name so can't
15 * detect duplicate names!
16 */
17
18/*
19 * Redistribution and use in source and binary forms, with or without modification,
20 * are permitted provided that the following conditions are met:
21 *
22 * 1. Redistributions of source code must retain the above copyright notice,
23 * this list of conditions and the following disclaimer.
24 * 2. Redistributions in binary form must reproduce the above copyright notice,
25 * this list of conditions and the following disclaimer in the documentation
26 * and/or other materials provided with the distribution.
27 * 3. The name of the author may not be used to endorse or promote products
28 * derived from this software without specific prior written permission.
29 *
30 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
31 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
32 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
33 * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
34 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
35 * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
36 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
37 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
38 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
39 * OF SUCH DAMAGE.
40 *
41 * This file is part of the lwIP TCP/IP stack.
42 *
43 * Modifications by Ray Abram to respond to NetBIOS name requests when Incoming name = *
44 * - based on code from "https://github.com/esp8266/Arduino/commit/1f7989b31d26d7df9776a08f36d685eae7ac8f99"
45 * - with permission to relicense to BSD from original author:
46 * http://www.xpablo.cz/?p=751#more-751
47 */
48
49#include "lwip/apps/netbiosns.h"
50
51#if LWIP_IPV4 && LWIP_UDP /* don't build if not configured for use in lwipopts.h */
52
53#include "lwip/def.h"
54#include "lwip/udp.h"
55#include "lwip/ip.h"
56#include "lwip/netif.h"
57#include "lwip/prot/iana.h"
58
59#include <string.h>
60
61/** size of a NetBIOS name */
62#define NETBIOS_NAME_LEN 16
63
64/** The Time-To-Live for NetBIOS name responds (in seconds)
65 * Default is 300000 seconds (3 days, 11 hours, 20 minutes) */
66#define NETBIOS_NAME_TTL 300000u
67
68/** NetBIOS header flags */
69#define NETB_HFLAG_RESPONSE 0x8000U
70#define NETB_HFLAG_OPCODE 0x7800U
71#define NETB_HFLAG_OPCODE_NAME_QUERY 0x0000U
72#define NETB_HFLAG_AUTHORATIVE 0x0400U
73#define NETB_HFLAG_TRUNCATED 0x0200U
74#define NETB_HFLAG_RECURS_DESIRED 0x0100U
75#define NETB_HFLAG_RECURS_AVAILABLE 0x0080U
76#define NETB_HFLAG_BROADCAST 0x0010U
77#define NETB_HFLAG_REPLYCODE 0x0008U
78#define NETB_HFLAG_REPLYCODE_NOERROR 0x0000U
79
80/* NetBIOS question types */
81#define NETB_QTYPE_NB 0x0020U
82#define NETB_QTYPE_NBSTAT 0x0021U
83
84/** NetBIOS name flags */
85#define NETB_NFLAG_UNIQUE 0x8000U
86#define NETB_NFLAG_NODETYPE 0x6000U
87#define NETB_NFLAG_NODETYPE_HNODE 0x6000U
88#define NETB_NFLAG_NODETYPE_MNODE 0x4000U
89#define NETB_NFLAG_NODETYPE_PNODE 0x2000U
90#define NETB_NFLAG_NODETYPE_BNODE 0x0000U
91
92#define NETB_NFLAG_NAME_IN_CONFLICT 0x0800U /* 1=Yes, 0=No */
93#define NETB_NFLAG_NAME_IS_ACTIVE 0x0400U /* 1=Yes, 0=No */
94#define NETB_NFLAG_NAME_IS_PERMANENT 0x0200U /* 1=Yes (Name is Permanent Node Name), 0=No */
95
96/** NetBIOS message header */
97#ifdef PACK_STRUCT_USE_INCLUDES
98# include "arch/bpstruct.h"
99#endif
100PACK_STRUCT_BEGIN
101struct netbios_hdr {
102 PACK_STRUCT_FIELD(u16_t trans_id);
103 PACK_STRUCT_FIELD(u16_t flags);
104 PACK_STRUCT_FIELD(u16_t questions);
105 PACK_STRUCT_FIELD(u16_t answerRRs);
106 PACK_STRUCT_FIELD(u16_t authorityRRs);
107 PACK_STRUCT_FIELD(u16_t additionalRRs);
108} PACK_STRUCT_STRUCT;
109PACK_STRUCT_END
110#ifdef PACK_STRUCT_USE_INCLUDES
111# include "arch/epstruct.h"
112#endif
113
114/** NetBIOS message question part */
115#ifdef PACK_STRUCT_USE_INCLUDES
116# include "arch/bpstruct.h"
117#endif
118PACK_STRUCT_BEGIN
119struct netbios_question_hdr {
120 PACK_STRUCT_FLD_8(u8_t nametype);
121 PACK_STRUCT_FLD_8(u8_t encname[(NETBIOS_NAME_LEN * 2) + 1]);
122 PACK_STRUCT_FIELD(u16_t type);
123 PACK_STRUCT_FIELD(u16_t cls);
124} PACK_STRUCT_STRUCT;
125PACK_STRUCT_END
126#ifdef PACK_STRUCT_USE_INCLUDES
127# include "arch/epstruct.h"
128#endif
129
130/** NetBIOS message name part */
131#ifdef PACK_STRUCT_USE_INCLUDES
132# include "arch/bpstruct.h"
133#endif
134PACK_STRUCT_BEGIN
135struct netbios_name_hdr {
136 PACK_STRUCT_FLD_8(u8_t nametype);
137 PACK_STRUCT_FLD_8(u8_t encname[(NETBIOS_NAME_LEN * 2) + 1]);
138 PACK_STRUCT_FIELD(u16_t type);
139 PACK_STRUCT_FIELD(u16_t cls);
140 PACK_STRUCT_FIELD(u32_t ttl);
141 PACK_STRUCT_FIELD(u16_t datalen);
142 PACK_STRUCT_FIELD(u16_t flags);
143 PACK_STRUCT_FLD_S(ip4_addr_p_t addr);
144} PACK_STRUCT_STRUCT;
145PACK_STRUCT_END
146#ifdef PACK_STRUCT_USE_INCLUDES
147# include "arch/epstruct.h"
148#endif
149
150/** NetBIOS message */
151#ifdef PACK_STRUCT_USE_INCLUDES
152# include "arch/bpstruct.h"
153#endif
154PACK_STRUCT_BEGIN
155struct netbios_resp {
156 struct netbios_hdr resp_hdr;
157 struct netbios_name_hdr resp_name;
158} PACK_STRUCT_STRUCT;
159PACK_STRUCT_END
160#ifdef PACK_STRUCT_USE_INCLUDES
161# include "arch/epstruct.h"
162#endif
163
164/** The NBNS Structure Responds to a Name Query */
165#ifdef PACK_STRUCT_USE_INCLUDES
166# include "arch/bpstruct.h"
167#endif
168PACK_STRUCT_BEGIN
169struct netbios_answer {
170 struct netbios_hdr answer_hdr;
171 /** the length of the next string */
172 PACK_STRUCT_FIELD(u8_t name_size);
173 /** WARNING!!! this item may be of a different length (we use this struct for transmission) */
174 PACK_STRUCT_FLD_8(u8_t query_name[(NETBIOS_NAME_LEN * 2) + 1]);
175 PACK_STRUCT_FIELD(u16_t packet_type);
176 PACK_STRUCT_FIELD(u16_t cls);
177 PACK_STRUCT_FIELD(u32_t ttl);
178 PACK_STRUCT_FIELD(u16_t data_length);
179#define OFFSETOF_STRUCT_NETBIOS_ANSWER_NUMBER_OF_NAMES 56
180 /** number of names */
181 PACK_STRUCT_FLD_8(u8_t number_of_names);
182 /** node name */
183 PACK_STRUCT_FLD_8(u8_t answer_name[NETBIOS_NAME_LEN]);
184 /** node flags */
185 PACK_STRUCT_FIELD(u16_t answer_name_flags);
186 /** Unit ID */
187 PACK_STRUCT_FLD_8(u8_t unit_id[6]);
188 /** Jumpers */
189 PACK_STRUCT_FLD_8(u8_t jumpers);
190 /** Test result */
191 PACK_STRUCT_FLD_8(u8_t test_result);
192 /** Version number */
193 PACK_STRUCT_FIELD(u16_t version_number);
194 /** Period of statistics */
195 PACK_STRUCT_FIELD(u16_t period_of_statistics);
196 /** Statistics */
197 PACK_STRUCT_FIELD(u16_t number_of_crcs);
198 /** Statistics */
199 PACK_STRUCT_FIELD(u16_t number_of_alignment_errors);
200 /** Statistics */
201 PACK_STRUCT_FIELD(u16_t number_of_collisions);
202 /** Statistics */
203 PACK_STRUCT_FIELD(u16_t number_of_send_aborts);
204 /** Statistics */
205 PACK_STRUCT_FIELD(u32_t number_of_good_sends);
206 /** Statistics */
207 PACK_STRUCT_FIELD(u32_t number_of_good_receives);
208 /** Statistics */
209 PACK_STRUCT_FIELD(u16_t number_of_retransmits);
210 /** Statistics */
211 PACK_STRUCT_FIELD(u16_t number_of_no_resource_condition);
212 /** Statistics */
213 PACK_STRUCT_FIELD(u16_t number_of_free_command_blocks);
214 /** Statistics */
215 PACK_STRUCT_FIELD(u16_t total_number_of_command_blocks);
216 /** Statistics */
217 PACK_STRUCT_FIELD(u16_t max_total_number_of_command_blocks);
218 /** Statistics */
219 PACK_STRUCT_FIELD(u16_t number_of_pending_sessions);
220 /** Statistics */
221 PACK_STRUCT_FIELD(u16_t max_number_of_pending_sessions);
222 /** Statistics */
223 PACK_STRUCT_FIELD(u16_t max_total_sessions_possible);
224 /** Statistics */
225 PACK_STRUCT_FIELD(u16_t session_data_packet_size);
226} PACK_STRUCT_STRUCT;
227PACK_STRUCT_END
228#ifdef PACK_STRUCT_USE_INCLUDES
229# include "arch/epstruct.h"
230#endif
231
232#ifdef NETBIOS_LWIP_NAME
233#define NETBIOS_LOCAL_NAME NETBIOS_LWIP_NAME
234#else
235static char netbiosns_local_name[NETBIOS_NAME_LEN];
236#define NETBIOS_LOCAL_NAME netbiosns_local_name
237#endif
238
239static struct udp_pcb *netbiosns_pcb;
240
241/** Decode a NetBIOS name (from packet to string) */
242static int
243netbiosns_name_decode(char *name_enc, char *name_dec, int name_dec_len)
244{
245 char *pname;
246 char cname;
247 char cnbname;
248 int idx = 0;
249
250 LWIP_UNUSED_ARG(name_dec_len);
251
252 /* Start decoding netbios name. */
253 pname = name_enc;
254 for (;;) {
255 /* Every two characters of the first level-encoded name
256 * turn into one character in the decoded name. */
257 cname = *pname;
258 if (cname == '\0') {
259 break; /* no more characters */
260 }
261 if (cname == '.') {
262 break; /* scope ID follows */
263 }
264 if (!lwip_isupper(cname)) {
265 /* Not legal. */
266 return -1;
267 }
268 cname -= 'A';
269 cnbname = cname << 4;
270 pname++;
271
272 cname = *pname;
273 if (!lwip_isupper(cname)) {
274 /* Not legal. */
275 return -1;
276 }
277 cname -= 'A';
278 cnbname |= cname;
279 pname++;
280
281 /* Do we have room to store the character? */
282 if (idx < NETBIOS_NAME_LEN) {
283 /* Yes - store the character. */
284 name_dec[idx++] = (cnbname != ' ' ? cnbname : '\0');
285 }
286 }
287
288 return 0;
289}
290
291#if 0 /* function currently unused */
292/** Encode a NetBIOS name (from string to packet) - currently unused because
293 we don't ask for names. */
294static int
295netbiosns_name_encode(char *name_enc, char *name_dec, int name_dec_len)
296{
297 char *pname;
298 char cname;
299 unsigned char ucname;
300 int idx = 0;
301
302 /* Start encoding netbios name. */
303 pname = name_enc;
304
305 for (;;) {
306 /* Every two characters of the first level-encoded name
307 * turn into one character in the decoded name. */
308 cname = *pname;
309 if (cname == '\0') {
310 break; /* no more characters */
311 }
312 if (cname == '.') {
313 break; /* scope ID follows */
314 }
315 if ((cname < 'A' || cname > 'Z') && (cname < '0' || cname > '9')) {
316 /* Not legal. */
317 return -1;
318 }
319
320 /* Do we have room to store the character? */
321 if (idx >= name_dec_len) {
322 return -1;
323 }
324
325 /* Yes - store the character. */
326 ucname = cname;
327 name_dec[idx++] = ('A' + ((ucname >> 4) & 0x0F));
328 name_dec[idx++] = ('A' + ( ucname & 0x0F));
329 pname++;
330 }
331
332 /* Fill with "space" coding */
333 for (; idx < name_dec_len - 1;) {
334 name_dec[idx++] = 'C';
335 name_dec[idx++] = 'A';
336 }
337
338 /* Terminate string */
339 name_dec[idx] = '\0';
340
341 return 0;
342}
343#endif /* 0 */
344
345/** NetBIOS Name service recv callback */
346static void
347netbiosns_recv(void *arg, struct udp_pcb *upcb, struct pbuf *p, const ip_addr_t *addr, u16_t port)
348{
349 LWIP_UNUSED_ARG(arg);
350
351 /* if packet is valid */
352 if (p != NULL) {
353 char netbios_name[NETBIOS_NAME_LEN + 1];
354 struct netbios_hdr *netbios_hdr = (struct netbios_hdr *)p->payload;
355 struct netbios_question_hdr *netbios_question_hdr = (struct netbios_question_hdr *)(netbios_hdr + 1);
356
357 /* is the packet long enough (we need the header in one piece) */
358 if (p->len < (sizeof(struct netbios_hdr) + sizeof(struct netbios_question_hdr))) {
359 /* packet too short */
360 pbuf_free(p);
361 return;
362 }
363 /* we only answer if we got a default interface */
364 if (netif_default != NULL) {
365 /* @todo: do we need to check answerRRs/authorityRRs/additionalRRs? */
366 /* if the packet is a NetBIOS name query question */
367 if (((netbios_hdr->flags & PP_NTOHS(NETB_HFLAG_OPCODE)) == PP_NTOHS(NETB_HFLAG_OPCODE_NAME_QUERY)) &&
368 ((netbios_hdr->flags & PP_NTOHS(NETB_HFLAG_RESPONSE)) == 0) &&
369 (netbios_hdr->questions == PP_NTOHS(1))) {
370 /* decode the NetBIOS name */
371 netbiosns_name_decode((char *)(netbios_question_hdr->encname), netbios_name, sizeof(netbios_name));
372 /* check the request type */
373 if (netbios_question_hdr->type == PP_HTONS(NETB_QTYPE_NB)) {
374 /* if the packet is for us */
375 if (lwip_strnicmp(netbios_name, NETBIOS_LOCAL_NAME, sizeof(NETBIOS_LOCAL_NAME)) == 0) {
376 struct pbuf *q;
377 struct netbios_resp *resp;
378
379 q = pbuf_alloc(PBUF_TRANSPORT, sizeof(struct netbios_resp), PBUF_RAM);
380 if (q != NULL) {
381 resp = (struct netbios_resp *)q->payload;
382
383 /* prepare NetBIOS header response */
384 resp->resp_hdr.trans_id = netbios_hdr->trans_id;
385 resp->resp_hdr.flags = PP_HTONS(NETB_HFLAG_RESPONSE |
386 NETB_HFLAG_OPCODE_NAME_QUERY |
387 NETB_HFLAG_AUTHORATIVE |
388 NETB_HFLAG_RECURS_DESIRED);
389 resp->resp_hdr.questions = 0;
390 resp->resp_hdr.answerRRs = PP_HTONS(1);
391 resp->resp_hdr.authorityRRs = 0;
392 resp->resp_hdr.additionalRRs = 0;
393
394 /* prepare NetBIOS header datas */
395 MEMCPY( resp->resp_name.encname, netbios_question_hdr->encname, sizeof(netbios_question_hdr->encname));
396 resp->resp_name.nametype = netbios_question_hdr->nametype;
397 resp->resp_name.type = netbios_question_hdr->type;
398 resp->resp_name.cls = netbios_question_hdr->cls;
399 {
400 uint32_t tty = PP_HTONL(NETBIOS_NAME_TTL);
401 MEMCPY(&resp->resp_name.ttl, &tty, 4);
402 }
403 resp->resp_name.datalen = PP_HTONS(sizeof(resp->resp_name.flags) + sizeof(resp->resp_name.addr));
404 resp->resp_name.flags = PP_HTONS(NETB_NFLAG_NODETYPE_BNODE);
405 ip4_addr_copy(resp->resp_name.addr, *netif_ip4_addr(netif_default));
406
407 /* send the NetBIOS response */
408 udp_sendto(upcb, q, addr, port);
409
410 /* free the "reference" pbuf */
411 pbuf_free(q);
412 }
413 }
414#if LWIP_NETBIOS_RESPOND_NAME_QUERY
415 } else if (netbios_question_hdr->type == PP_HTONS(NETB_QTYPE_NBSTAT)) {
416 /* if the packet is for us or general query */
417 if (!lwip_strnicmp(netbios_name, NETBIOS_LOCAL_NAME, sizeof(NETBIOS_LOCAL_NAME)) ||
418 !lwip_strnicmp(netbios_name, "*", sizeof(NETBIOS_LOCAL_NAME))) {
419 /* general query - ask for our IP address */
420 struct pbuf *q;
421 struct netbios_answer *resp;
422
423 q = pbuf_alloc(PBUF_TRANSPORT, sizeof(struct netbios_answer), PBUF_RAM);
424 if (q != NULL) {
425 /* buffer to which a response is compiled */
426 resp = (struct netbios_answer *) q->payload;
427
428 /* Init response to zero, especially the statistics fields */
429 memset(resp, 0, sizeof(*resp));
430
431 /* copy the query to the response ID */
432 resp->answer_hdr.trans_id = netbios_hdr->trans_id;
433 /* acknowledgment of termination */
434 resp->answer_hdr.flags = PP_HTONS(NETB_HFLAG_RESPONSE | NETB_HFLAG_OPCODE_NAME_QUERY | NETB_HFLAG_AUTHORATIVE);
435 /* resp->answer_hdr.questions = PP_HTONS(0); done by memset() */
436 /* serial number of the answer */
437 resp->answer_hdr.answerRRs = PP_HTONS(1);
438 /* resp->answer_hdr.authorityRRs = PP_HTONS(0); done by memset() */
439 /* resp->answer_hdr.additionalRRs = PP_HTONS(0); done by memset() */
440 /* we will copy the length of the station name */
441 resp->name_size = netbios_question_hdr->nametype;
442 /* we will copy the queried name */
443 MEMCPY(resp->query_name, netbios_question_hdr->encname, (NETBIOS_NAME_LEN * 2) + 1);
444 /* NBSTAT */
445 resp->packet_type = PP_HTONS(0x21);
446 /* Internet name */
447 resp->cls = PP_HTONS(1);
448 /* resp->ttl = PP_HTONL(0); done by memset() */
449 resp->data_length = PP_HTONS(sizeof(struct netbios_answer) - offsetof(struct netbios_answer, number_of_names));
450 resp->number_of_names = 1;
451
452 /* make windows see us as workstation, not as a server */
453 memset(resp->answer_name, 0x20, NETBIOS_NAME_LEN - 1);
454 /* strlen is checked to be < NETBIOS_NAME_LEN during initialization */
455 MEMCPY(resp->answer_name, NETBIOS_LOCAL_NAME, strlen(NETBIOS_LOCAL_NAME));
456
457 /* b-node, unique, active */
458 resp->answer_name_flags = PP_HTONS(NETB_NFLAG_NAME_IS_ACTIVE);
459
460 /* Set responder netif MAC address */
461 SMEMCPY(resp->unit_id, ip_current_input_netif()->hwaddr, sizeof(resp->unit_id));
462
463 udp_sendto(upcb, q, addr, port);
464 pbuf_free(q);
465 }
466 }
467#endif /* LWIP_NETBIOS_RESPOND_NAME_QUERY */
468 }
469 }
470 }
471 /* free the pbuf */
472 pbuf_free(p);
473 }
474}
475
476/**
477 * @ingroup netbiosns
478 * Init netbios responder
479 */
480void
481netbiosns_init(void)
482{
483 /* LWIP_ASSERT_CORE_LOCKED(); is checked by udp_new() */
484#ifdef NETBIOS_LWIP_NAME
485 LWIP_ASSERT("NetBIOS name is too long!", strlen(NETBIOS_LWIP_NAME) < NETBIOS_NAME_LEN);
486#endif
487
488 netbiosns_pcb = udp_new_ip_type(IPADDR_TYPE_ANY);
489 if (netbiosns_pcb != NULL) {
490 /* we have to be allowed to send broadcast packets! */
491 ip_set_option(netbiosns_pcb, SOF_BROADCAST);
492 udp_bind(netbiosns_pcb, IP_ANY_TYPE, LWIP_IANA_PORT_NETBIOS);
493 udp_recv(netbiosns_pcb, netbiosns_recv, netbiosns_pcb);
494 }
495}
496
497#ifndef NETBIOS_LWIP_NAME
498/**
499 * @ingroup netbiosns
500 * Set netbios name. ATTENTION: the hostname must be less than 15 characters!
501 * the NetBIOS name spec says the name MUST be upper case, so incoming name is forced into uppercase :-)
502 */
503void
504netbiosns_set_name(const char *hostname)
505{
506 size_t i;
507 size_t copy_len = strlen(hostname);
508 LWIP_ASSERT_CORE_LOCKED();
509 LWIP_ASSERT("NetBIOS name is too long!", copy_len < NETBIOS_NAME_LEN);
510 if (copy_len >= NETBIOS_NAME_LEN) {
511 copy_len = NETBIOS_NAME_LEN - 1;
512 }
513
514 /* make name into upper case */
515 for (i = 0; i < copy_len; i++ ) {
516 netbiosns_local_name[i] = (char)lwip_toupper(hostname[i]);
517 }
518 netbiosns_local_name[copy_len] = '\0';
519}
520#endif /* NETBIOS_LWIP_NAME */
521
522/**
523 * @ingroup netbiosns
524 * Stop netbios responder
525 */
526void
527netbiosns_stop(void)
528{
529 LWIP_ASSERT_CORE_LOCKED();
530 if (netbiosns_pcb != NULL) {
531 udp_remove(netbiosns_pcb);
532 netbiosns_pcb = NULL;
533 }
534}
535
536#endif /* LWIP_IPV4 && LWIP_UDP */
Note: See TracBrowser for help on using the repository browser.