Webserver+3d print

Dependents:   Nucleo

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers nbns_common.c Source File

nbns_common.c

Go to the documentation of this file.
00001 /**
00002  * @file nbns_common.c
00003  * @brief Functions common to NBNS client and NBNS responder
00004  *
00005  * @section License
00006  *
00007  * Copyright (C) 2010-2017 Oryx Embedded SARL. All rights reserved.
00008  *
00009  * This file is part of CycloneTCP Open.
00010  *
00011  * This program is free software; you can redistribute it and/or
00012  * modify it under the terms of the GNU General Public License
00013  * as published by the Free Software Foundation; either version 2
00014  * of the License, or (at your option) any later version.
00015  *
00016  * This program is distributed in the hope that it will be useful,
00017  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00018  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00019  * GNU General Public License for more details.
00020  *
00021  * You should have received a copy of the GNU General Public License
00022  * along with this program; if not, write to the Free Software Foundation,
00023  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
00024  *
00025  * @author Oryx Embedded SARL (www.oryx-embedded.com)
00026  * @version 1.7.6
00027  **/
00028 
00029 //Switch to the appropriate trace level
00030 #define TRACE_LEVEL NBNS_TRACE_LEVEL
00031 
00032 //Dependencies
00033 #include <stdlib.h>
00034 #include <string.h>
00035 #include <ctype.h>
00036 #include "core/net.h"
00037 #include "netbios/nbns_client.h"
00038 #include "netbios/nbns_responder.h"
00039 #include "netbios/nbns_common.h"
00040 #include "dns/dns_debug.h"
00041 #include "debug.h"
00042 
00043 //Check TCP/IP stack configuration
00044 #if (NBNS_CLIENT_SUPPORT == ENABLED || NBNS_RESPONDER_SUPPORT == ENABLED)
00045 #if (IPV4_SUPPORT == ENABLED)
00046 
00047 
00048 /**
00049  * @brief NBNS related initialization
00050  * @param[in] interface Underlying network interface
00051  * @return Error code
00052  **/
00053 
00054 error_t nbnsInit(NetInterface *interface)
00055 {
00056    error_t error;
00057 
00058    //Callback function to be called when a NBNS message is received
00059    error = udpAttachRxCallback(interface, NBNS_PORT, nbnsProcessMessage, NULL);
00060    //Any error to report?
00061    if(error)
00062       return error;
00063 
00064    //Successful initialization
00065    return NO_ERROR;
00066 }
00067 
00068 
00069 /**
00070  * @brief Process incoming NBNS message
00071  * @param[in] interface Underlying network interface
00072  * @param[in] pseudoHeader UDP pseudo header
00073  * @param[in] udpHeader UDP header
00074  * @param[in] buffer Multi-part buffer containing the incoming NBNS message
00075  * @param[in] offset Offset to the first byte of the NBNS message
00076  * @param[in] params Callback function parameter (not used)
00077  **/
00078 
00079 void nbnsProcessMessage(NetInterface *interface, const IpPseudoHeader *pseudoHeader,
00080    const UdpHeader *udpHeader, const NetBuffer *buffer, size_t offset, void *params)
00081 {
00082    size_t length;
00083    NbnsHeader *message;
00084 
00085    //Make sure the NBNS message was received from an IPv4 peer
00086    if(pseudoHeader->length != sizeof(Ipv4PseudoHeader))
00087       return;
00088 
00089    //Retrieve the length of the NBNS message
00090    length = netBufferGetLength(buffer) - offset;
00091 
00092    //Ensure the NBNS message is valid
00093    if(length < sizeof(NbnsHeader))
00094       return;
00095    if(length > DNS_MESSAGE_MAX_SIZE)
00096       return;
00097 
00098    //Point to the NBNS message header
00099    message = netBufferAt(buffer, offset);
00100    //Sanity check
00101    if(message == NULL)
00102       return;
00103 
00104    //Debug message
00105    TRACE_INFO("NBNS message received (%" PRIuSIZE " bytes)...\r\n", length);
00106    //Dump message
00107    dnsDumpMessage((DnsHeader *) message, length);
00108 
00109    //NBNS messages received with an opcode other than zero must be silently ignored
00110    if(message->opcode != DNS_OPCODE_QUERY)
00111       return;
00112    //NBNS messages received with non-zero response codes must be silently ignored
00113    if(message->rcode != DNS_RCODE_NO_ERROR)
00114       return;
00115 
00116    //NBNS query received?
00117    if(!message->qr)
00118    {
00119 #if (NBNS_RESPONDER_SUPPORT == ENABLED)
00120       //Process incoming NBNS query message
00121       nbnsProcessQuery(interface, &pseudoHeader->ipv4Data,
00122          udpHeader, message, length);
00123 #endif
00124    }
00125    //NBNS response received?
00126    else
00127    {
00128 #if (NBNS_CLIENT_SUPPORT == ENABLED)
00129       //Process incoming NBNS response message
00130       nbnsProcessResponse(interface, &pseudoHeader->ipv4Data,
00131          udpHeader, message, length);
00132 #endif
00133    }
00134 }
00135 
00136 
00137 /**
00138  * @brief Encode a NetBIOS name
00139  * @param[in] src Pointer to the name to encode
00140  * @param[out] dest Pointer to the encoded NetBIOS name
00141  * @return Length of the encoded NetBIOS name
00142  **/
00143 
00144 size_t nbnsEncodeName(const char_t *src, uint8_t *dest)
00145 {
00146    size_t i;
00147    size_t j;
00148    char_t c;
00149 
00150    //Point to first byte of the output buffer
00151    j = 0;
00152 
00153    //NetBIOS names are 32-byte long
00154    dest[j++] = 32;
00155 
00156    //Parse input name
00157    for(i = 0; i < 15 && src[i] != '\0'; i++)
00158    {
00159       //Convert current character to uppercase
00160       c = toupper((uint8_t) src[i]);
00161 
00162       //Encode character
00163       dest[j++] = NBNS_ENCODE_H(c);
00164       dest[j++] = NBNS_ENCODE_L(c);
00165    }
00166 
00167    //Pad NetBIOS name with space characters
00168    for(; i < 15; i++)
00169    {
00170       //Encoded space character
00171       dest[j++] = NBNS_ENCODE_H(' ');
00172       dest[j++] = NBNS_ENCODE_L(' ');
00173    }
00174 
00175    //The 16th character is the NetBIOS suffix
00176    dest[j++] = NBNS_ENCODE_H(0);
00177    dest[j++] = NBNS_ENCODE_L(0);
00178 
00179    //Terminate the NetBIOS name with a zero length count
00180    dest[j++] = 0;
00181 
00182    //Return the length of the encoded NetBIOS name
00183    return j;
00184 }
00185 
00186 
00187 /**
00188  * @brief Decode a NetBIOS name
00189  * @param[in] message Pointer to the NBNS message
00190  * @param[in] length Length of the NBNS message
00191  * @param[in] pos Offset of the name to decode
00192  * @param[out] dest Pointer to the decoded name (optional)
00193  * @return The position of the resource record that immediately follows the NetBIOS name
00194  **/
00195 
00196 size_t nbnsParseName(const NbnsHeader *message,
00197    size_t length, size_t pos, char_t *dest)
00198 {
00199    size_t i;
00200    size_t n;
00201    char_t c;
00202 
00203    //Cast the input NBNS message to byte array
00204    uint8_t *src = (uint8_t *) message;
00205 
00206    //Malformed NBNS message?
00207    if((pos + 34) >= length)
00208       return 0;
00209 
00210    //Retrieve the length of the first label
00211    n = src[pos++];
00212 
00213    //NetBIOS names must be 32-byte long
00214    if(n != 32)
00215       return 0;
00216 
00217    //Parse the NetBIOS name
00218    for(i = 0; i < 15; i++)
00219    {
00220       //Make sure the characters of the sequence are valid
00221       if(src[pos] < 'A' || src[pos] > 'P')
00222          return 0;
00223       if(src[pos + 1] < 'A' || src[pos + 1] > 'P')
00224          return 0;
00225 
00226       //Combine nibbles to restore the original ASCII character
00227       c = ((src[pos] - 'A') << 4) | (src[pos + 1] - 'A');
00228 
00229       //Padding character found?
00230       if(c == ' ')
00231          break;
00232 
00233       //Save current ASCII character
00234       if(dest != NULL)
00235          *(dest++) = c;
00236 
00237       //Advance data pointer
00238       pos += 2;
00239    }
00240 
00241    //Skip padding characters
00242    for(; i < 16; i++)
00243    {
00244       //Make sure the nibbles are valid
00245       if(src[pos] < 'A' || src[pos] > 'P')
00246          return 0;
00247       if(src[pos + 1] < 'A' || src[pos + 1] > 'P')
00248          return 0;
00249 
00250       //Advance data pointer
00251       pos += 2;
00252    }
00253 
00254    //Retrieve the length of the next label
00255    n = src[pos++];
00256 
00257    //NetBIOS names are terminated with a zero length count
00258    if(n != 0)
00259       return 0;
00260 
00261    //Properly terminate the string
00262    if(dest != NULL)
00263       *(dest++) = '\0';
00264 
00265    //Return the position of the resource record that
00266    //is immediately following the NetBIOS name
00267    return pos;
00268 }
00269 
00270 
00271 /**
00272  * @brief Compare NetBIOS names
00273  * @param[in] message Pointer to the NBNS message
00274  * @param[in] length Length of the NBNS message
00275  * @param[in] pos Offset of the encoded domain name
00276  * @param[in] name NULL-terminated string that holds a domain name
00277  * @return TRUE if the NetBIOS names match, else FALSE
00278  **/
00279 
00280 bool_t nbnsCompareName(const NbnsHeader *message,
00281    size_t length, size_t pos, const char_t *name)
00282 {
00283    size_t i;
00284    size_t n;
00285    char_t c;
00286 
00287    //Cast the input NBNS message to byte array
00288    uint8_t *src = (uint8_t *) message;
00289 
00290    //Malformed NBNS message?
00291    if((pos + 34) >= length)
00292       return FALSE;
00293 
00294    //Retrieve the length of the first label
00295    n = src[pos++];
00296 
00297    //NetBIOS names must be 32-byte long
00298    if(n != 32)
00299       return FALSE;
00300 
00301    //Parse the NetBIOS name
00302    for(i = 0; i < 15; i++)
00303    {
00304       //Make sure the characters of the sequence are valid
00305       if(src[pos] < 'A' || src[pos] > 'P')
00306          return FALSE;
00307       if(src[pos + 1] < 'A' || src[pos + 1] > 'P')
00308          return FALSE;
00309 
00310       //Combine nibbles to restore the original ASCII character
00311       c = ((src[pos] - 'A') << 4) | (src[pos + 1] - 'A');
00312 
00313       //Padding character found?
00314       if(c == ' ' && *name == '\0')
00315          break;
00316 
00317       //Perform case insensitive comparison
00318       if(toupper((uint8_t) c) != toupper((uint8_t) *name))
00319          return FALSE;
00320 
00321       //Advance data pointer
00322       pos += 2;
00323       name++;
00324    }
00325 
00326    //Skip padding characters
00327    for(; i < 16; i++)
00328    {
00329       //Make sure the nibbles are valid
00330       if(src[pos] < 'A' || src[pos] > 'P')
00331          return FALSE;
00332       if(src[pos + 1] < 'A' || src[pos + 1] > 'P')
00333          return FALSE;
00334 
00335       //Advance data pointer
00336       pos += 2;
00337    }
00338 
00339    //Retrieve the length of the next label
00340    n = src[pos];
00341 
00342    //NetBIOS names are terminated with a zero length count
00343    if(n != 0)
00344       return FALSE;
00345 
00346    //The NetBIOS names match
00347    return TRUE;
00348 }
00349 
00350 #endif
00351 #endif
00352