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.
Fork of mbed-os by
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 13:15:53 by
