Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Dependents: mbed-TFT-example-NCS36510 mbed-Accelerometer-example-NCS36510 mbed-Accelerometer-example-NCS36510
lwip_netbiosns.c
00001 /** 00002 * @file 00003 * NetBIOS name service responder 00004 */ 00005 00006 /** 00007 * @defgroup netbiosns NETBIOS responder 00008 * @ingroup apps 00009 * 00010 * This is an example implementation of a NetBIOS name server. 00011 * It responds to name queries for a configurable name. 00012 * Name resolving is not supported. 00013 * 00014 * Note that the device doesn't broadcast it's own name so can't 00015 * detect duplicate names! 00016 */ 00017 00018 /* 00019 * Redistribution and use in source and binary forms, with or without modification, 00020 * are permitted provided that the following conditions are met: 00021 * 00022 * 1. Redistributions of source code must retain the above copyright notice, 00023 * this list of conditions and the following disclaimer. 00024 * 2. Redistributions in binary form must reproduce the above copyright notice, 00025 * this list of conditions and the following disclaimer in the documentation 00026 * and/or other materials provided with the distribution. 00027 * 3. The name of the author may not be used to endorse or promote products 00028 * derived from this software without specific prior written permission. 00029 * 00030 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED 00031 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 00032 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT 00033 * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 00034 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT 00035 * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 00036 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 00037 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 00038 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY 00039 * OF SUCH DAMAGE. 00040 * 00041 * This file is part of the lwIP TCP/IP stack. 00042 * 00043 */ 00044 00045 #include "lwip/apps/netbiosns.h" 00046 00047 #if LWIP_IPV4 && LWIP_UDP /* don't build if not configured for use in lwipopts.h */ 00048 00049 #include "lwip/udp.h" 00050 #include "lwip/netif.h" 00051 00052 #include <string.h> 00053 00054 /** default port number for "NetBIOS Name service */ 00055 #define NETBIOS_PORT 137 00056 00057 /** size of a NetBIOS name */ 00058 #define NETBIOS_NAME_LEN 16 00059 00060 /** The Time-To-Live for NetBIOS name responds (in seconds) 00061 * Default is 300000 seconds (3 days, 11 hours, 20 minutes) */ 00062 #define NETBIOS_NAME_TTL 300000u 00063 00064 /** NetBIOS header flags */ 00065 #define NETB_HFLAG_RESPONSE 0x8000U 00066 #define NETB_HFLAG_OPCODE 0x7800U 00067 #define NETB_HFLAG_OPCODE_NAME_QUERY 0x0000U 00068 #define NETB_HFLAG_AUTHORATIVE 0x0400U 00069 #define NETB_HFLAG_TRUNCATED 0x0200U 00070 #define NETB_HFLAG_RECURS_DESIRED 0x0100U 00071 #define NETB_HFLAG_RECURS_AVAILABLE 0x0080U 00072 #define NETB_HFLAG_BROADCAST 0x0010U 00073 #define NETB_HFLAG_REPLYCODE 0x0008U 00074 #define NETB_HFLAG_REPLYCODE_NOERROR 0x0000U 00075 00076 /** NetBIOS name flags */ 00077 #define NETB_NFLAG_UNIQUE 0x8000U 00078 #define NETB_NFLAG_NODETYPE 0x6000U 00079 #define NETB_NFLAG_NODETYPE_HNODE 0x6000U 00080 #define NETB_NFLAG_NODETYPE_MNODE 0x4000U 00081 #define NETB_NFLAG_NODETYPE_PNODE 0x2000U 00082 #define NETB_NFLAG_NODETYPE_BNODE 0x0000U 00083 00084 /** NetBIOS message header */ 00085 #ifdef PACK_STRUCT_USE_INCLUDES 00086 # include "arch/bpstruct.h" 00087 #endif 00088 PACK_STRUCT_BEGIN 00089 struct netbios_hdr { 00090 PACK_STRUCT_FIELD(u16_t trans_id); 00091 PACK_STRUCT_FIELD(u16_t flags); 00092 PACK_STRUCT_FIELD(u16_t questions); 00093 PACK_STRUCT_FIELD(u16_t answerRRs); 00094 PACK_STRUCT_FIELD(u16_t authorityRRs); 00095 PACK_STRUCT_FIELD(u16_t additionalRRs); 00096 } PACK_STRUCT_STRUCT; 00097 PACK_STRUCT_END 00098 #ifdef PACK_STRUCT_USE_INCLUDES 00099 # include "arch/epstruct.h" 00100 #endif 00101 00102 /** NetBIOS message name part */ 00103 #ifdef PACK_STRUCT_USE_INCLUDES 00104 # include "arch/bpstruct.h" 00105 #endif 00106 PACK_STRUCT_BEGIN 00107 struct netbios_name_hdr { 00108 PACK_STRUCT_FLD_8(u8_t nametype); 00109 PACK_STRUCT_FLD_8(u8_t encname[(NETBIOS_NAME_LEN*2)+1]); 00110 PACK_STRUCT_FIELD(u16_t type); 00111 PACK_STRUCT_FIELD(u16_t cls); 00112 PACK_STRUCT_FIELD(u32_t ttl); 00113 PACK_STRUCT_FIELD(u16_t datalen); 00114 PACK_STRUCT_FIELD(u16_t flags); 00115 PACK_STRUCT_FLD_S(ip4_addr_p_t addr); 00116 } PACK_STRUCT_STRUCT; 00117 PACK_STRUCT_END 00118 #ifdef PACK_STRUCT_USE_INCLUDES 00119 # include "arch/epstruct.h" 00120 #endif 00121 00122 /** NetBIOS message */ 00123 #ifdef PACK_STRUCT_USE_INCLUDES 00124 # include "arch/bpstruct.h" 00125 #endif 00126 PACK_STRUCT_BEGIN 00127 struct netbios_resp 00128 { 00129 struct netbios_hdr resp_hdr; 00130 struct netbios_name_hdr resp_name; 00131 } PACK_STRUCT_STRUCT; 00132 PACK_STRUCT_END 00133 #ifdef PACK_STRUCT_USE_INCLUDES 00134 # include "arch/epstruct.h" 00135 #endif 00136 00137 #ifdef NETBIOS_LWIP_NAME 00138 #define NETBIOS_LOCAL_NAME NETBIOS_LWIP_NAME 00139 #else 00140 static char netbiosns_local_name[NETBIOS_NAME_LEN]; 00141 #define NETBIOS_LOCAL_NAME netbiosns_local_name 00142 #endif 00143 00144 struct udp_pcb *netbiosns_pcb; 00145 00146 /** Decode a NetBIOS name (from packet to string) */ 00147 static int 00148 netbiosns_name_decode(char *name_enc, char *name_dec, int name_dec_len) 00149 { 00150 char *pname; 00151 char cname; 00152 char cnbname; 00153 int idx = 0; 00154 00155 LWIP_UNUSED_ARG(name_dec_len); 00156 00157 /* Start decoding netbios name. */ 00158 pname = name_enc; 00159 for (;;) { 00160 /* Every two characters of the first level-encoded name 00161 * turn into one character in the decoded name. */ 00162 cname = *pname; 00163 if (cname == '\0') 00164 break; /* no more characters */ 00165 if (cname == '.') 00166 break; /* scope ID follows */ 00167 if (cname < 'A' || cname > 'Z') { 00168 /* Not legal. */ 00169 return -1; 00170 } 00171 cname -= 'A'; 00172 cnbname = cname << 4; 00173 pname++; 00174 00175 cname = *pname; 00176 if (cname == '\0' || cname == '.') { 00177 /* No more characters in the name - but we're in 00178 * the middle of a pair. Not legal. */ 00179 return -1; 00180 } 00181 if (cname < 'A' || cname > 'Z') { 00182 /* Not legal. */ 00183 return -1; 00184 } 00185 cname -= 'A'; 00186 cnbname |= cname; 00187 pname++; 00188 00189 /* Do we have room to store the character? */ 00190 if (idx < NETBIOS_NAME_LEN) { 00191 /* Yes - store the character. */ 00192 name_dec[idx++] = (cnbname!=' '?cnbname:'\0'); 00193 } 00194 } 00195 00196 return 0; 00197 } 00198 00199 #if 0 /* function currently unused */ 00200 /** Encode a NetBIOS name (from string to packet) - currently unused because 00201 we don't ask for names. */ 00202 static int 00203 netbiosns_name_encode(char *name_enc, char *name_dec, int name_dec_len) 00204 { 00205 char *pname; 00206 char cname; 00207 unsigned char ucname; 00208 int idx = 0; 00209 00210 /* Start encoding netbios name. */ 00211 pname = name_enc; 00212 00213 for (;;) { 00214 /* Every two characters of the first level-encoded name 00215 * turn into one character in the decoded name. */ 00216 cname = *pname; 00217 if (cname == '\0') 00218 break; /* no more characters */ 00219 if (cname == '.') 00220 break; /* scope ID follows */ 00221 if ((cname < 'A' || cname > 'Z') && (cname < '0' || cname > '9')) { 00222 /* Not legal. */ 00223 return -1; 00224 } 00225 00226 /* Do we have room to store the character? */ 00227 if (idx >= name_dec_len) { 00228 return -1; 00229 } 00230 00231 /* Yes - store the character. */ 00232 ucname = cname; 00233 name_dec[idx++] = ('A'+((ucname>>4) & 0x0F)); 00234 name_dec[idx++] = ('A'+( ucname & 0x0F)); 00235 pname++; 00236 } 00237 00238 /* Fill with "space" coding */ 00239 for (;idx < name_dec_len - 1;) { 00240 name_dec[idx++] = 'C'; 00241 name_dec[idx++] = 'A'; 00242 } 00243 00244 /* Terminate string */ 00245 name_dec[idx] = '\0'; 00246 00247 return 0; 00248 } 00249 #endif /* 0 */ 00250 00251 /** NetBIOS Name service recv callback */ 00252 static void 00253 netbiosns_recv(void *arg, struct udp_pcb *upcb, struct pbuf *p, const ip_addr_t *addr, u16_t port) 00254 { 00255 LWIP_UNUSED_ARG(arg); 00256 00257 /* if packet is valid */ 00258 if (p != NULL) { 00259 char netbios_name[NETBIOS_NAME_LEN+1]; 00260 struct netbios_hdr* netbios_hdr = (struct netbios_hdr*)p->payload; 00261 struct netbios_name_hdr* netbios_name_hdr = (struct netbios_name_hdr*)(netbios_hdr+1); 00262 00263 /* we only answer if we got a default interface */ 00264 if (netif_default != NULL) { 00265 /* @todo: do we need to check answerRRs/authorityRRs/additionalRRs? */ 00266 /* if the packet is a NetBIOS name query question */ 00267 if (((netbios_hdr->flags & PP_NTOHS(NETB_HFLAG_OPCODE)) == PP_NTOHS(NETB_HFLAG_OPCODE_NAME_QUERY)) && 00268 ((netbios_hdr->flags & PP_NTOHS(NETB_HFLAG_RESPONSE)) == 0) && 00269 (netbios_hdr->questions == PP_NTOHS(1))) { 00270 /* decode the NetBIOS name */ 00271 netbiosns_name_decode((char*)(netbios_name_hdr->encname), netbios_name, sizeof(netbios_name)); 00272 /* if the packet is for us */ 00273 if (NETBIOS_STRCMP(netbios_name, NETBIOS_LOCAL_NAME) == 0) { 00274 struct pbuf *q; 00275 struct netbios_resp *resp; 00276 00277 q = pbuf_alloc(PBUF_TRANSPORT, sizeof(struct netbios_resp), PBUF_RAM); 00278 if (q != NULL) { 00279 resp = (struct netbios_resp*)q->payload; 00280 00281 /* prepare NetBIOS header response */ 00282 resp->resp_hdr.trans_id = netbios_hdr->trans_id; 00283 resp->resp_hdr.flags = PP_HTONS(NETB_HFLAG_RESPONSE | 00284 NETB_HFLAG_OPCODE_NAME_QUERY | 00285 NETB_HFLAG_AUTHORATIVE | 00286 NETB_HFLAG_RECURS_DESIRED); 00287 resp->resp_hdr.questions = 0; 00288 resp->resp_hdr.answerRRs = PP_HTONS(1); 00289 resp->resp_hdr.authorityRRs = 0; 00290 resp->resp_hdr.additionalRRs = 0; 00291 00292 /* prepare NetBIOS header datas */ 00293 MEMCPY( resp->resp_name.encname, netbios_name_hdr->encname, sizeof(netbios_name_hdr->encname)); 00294 resp->resp_name.nametype = netbios_name_hdr->nametype; 00295 resp->resp_name.type = netbios_name_hdr->type; 00296 resp->resp_name.cls = netbios_name_hdr->cls; 00297 resp->resp_name.ttl = PP_HTONL(NETBIOS_NAME_TTL); 00298 resp->resp_name.datalen = PP_HTONS(sizeof(resp->resp_name.flags)+sizeof(resp->resp_name.addr)); 00299 resp->resp_name.flags = PP_HTONS(NETB_NFLAG_NODETYPE_BNODE); 00300 ip4_addr_copy(resp->resp_name.addr, *netif_ip4_addr(netif_default)); 00301 00302 /* send the NetBIOS response */ 00303 udp_sendto(upcb, q, addr, port); 00304 00305 /* free the "reference" pbuf */ 00306 pbuf_free(q); 00307 } 00308 } 00309 } 00310 } 00311 /* free the pbuf */ 00312 pbuf_free(p); 00313 } 00314 } 00315 00316 /** 00317 * @ingroup netbiosns 00318 * Init netbios responder 00319 */ 00320 void 00321 netbiosns_init(void) 00322 { 00323 #ifdef NETBIOS_LWIP_NAME 00324 LWIP_ASSERT("NetBIOS name is too long!", strlen(NETBIOS_LWIP_NAME) < NETBIOS_NAME_LEN); 00325 #endif 00326 00327 netbiosns_pcb = udp_new_ip_type(IPADDR_TYPE_ANY); 00328 if (netbiosns_pcb != NULL) { 00329 /* we have to be allowed to send broadcast packets! */ 00330 netbiosns_pcb->so_options |= SOF_BROADCAST; 00331 udp_bind(netbiosns_pcb, IP_ANY_TYPE, NETBIOS_PORT); 00332 udp_recv(netbiosns_pcb, netbiosns_recv, netbiosns_pcb); 00333 } 00334 } 00335 00336 #ifndef NETBIOS_LWIP_NAME 00337 /** 00338 * @ingroup netbiosns 00339 * Set netbios name. ATTENTION: the hostname must be less than 15 characters! 00340 */ 00341 void 00342 netbiosns_set_name(const char* hostname) 00343 { 00344 size_t copy_len = strlen(hostname); 00345 LWIP_ASSERT("NetBIOS name is too long!", copy_len < NETBIOS_NAME_LEN); 00346 if (copy_len >= NETBIOS_NAME_LEN) { 00347 copy_len = NETBIOS_NAME_LEN - 1; 00348 } 00349 memcpy(netbiosns_local_name, hostname, copy_len + 1); 00350 } 00351 #endif 00352 00353 /** 00354 * @ingroup netbiosns 00355 * Stop netbios responder 00356 */ 00357 void 00358 netbiosns_stop(void) 00359 { 00360 if (netbiosns_pcb != NULL) { 00361 udp_remove(netbiosns_pcb); 00362 netbiosns_pcb = NULL; 00363 } 00364 } 00365 00366 #endif /* LWIP_IPV4 && LWIP_UDP */
Generated on Tue Jul 12 2022 11:02:42 by
