ON Semiconductor / mbed-os

Dependents:   mbed-TFT-example-NCS36510 mbed-Accelerometer-example-NCS36510 mbed-Accelerometer-example-NCS36510

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers lwip_netbiosns.c Source File

lwip_netbiosns.c

Go to the documentation of this file.
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 */