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