mdns.c

Go to the documentation of this file.
00001 
00002 
00003 
00014 
00015 
00016 
00017 
00018 #define MDNS_C
00019 
00020 
00022 // Includes
00024 
00025 #include "TCPIP.h"
00026 #include "mdns.h"
00027 
00028 
00030 // Local defines
00032 
00033 // Thats the maximum interval for an MDNS resolve. The resolve message is 
00034 // repeated starting with 1 second interval and doubling each time until this
00035 // maximum interval is reached.
00036 #define MAXREPEAT_INTERVAL (TICK_HOUR)
00037 
00038 // The predefined TTLs are used in the DNS entries...
00039 #define DNS_DEFAULT_TTL 120ul   // In seconds...
00040 #define DNS_RR_TTL      4500ul  // In seconds...
00041 
00042 // Some special label identifiers...
00043 #define DNS_ROOT_LABEL          (0xFF)
00044 #define DNS_UNSPECIFIED_LABEL   (0xFF)
00045 
00046 
00047 // Indices for dynamic label list entries.
00048 #define TCP_SERVICE_NAME_IDX    (14)
00049 #define QUERY_SERVICE_NAME_IDX  (15)
00050 #define QUERY_NAME_IDX          (16)
00051 
00052 
00053 // Count of labels and DNS entries stored here (see the lists below).
00054 #define DNS_ENTRIES (sizeof(_asDNSEntries)/sizeof(DNS_ENTRY))
00055 #define DNS_LABELS (sizeof(_asROMLabelList)/sizeof(ROM char *))
00056 
00057 
00058 // This define sets the number of probe entries (from index zero to this
00059 // number). The probe packets include only this entries:
00060 #define DNS_PROBE_ENTRIES   2
00061 
00062 // This define sets the number of goodbye entries (counted from the last
00063 // index downwards).
00064 #define DNS_GOODBYE_ENTRIES 1
00065 
00066 // Needed maximum string length (must be greater than the maximum stored name 
00067 // in the DNS entry table.
00068 #define MAX_DNS_NAME_LEN    100
00069 
00070 
00072 // Local typedefs
00074 
00075 // Internal MDNS states
00076 typedef enum
00077 {
00078     MDNS_STOPPED = 0,
00079     MDNS_WAIT_FOR_PROBING,
00080     MDNS_SECOND_PROBE,
00081     MDNS_THIRD_PROBE,
00082     MDNS_FIRST_ANNOUNCING,
00083     MDNS_SECOND_ANNOUNCING,
00084     MDNS_THIRD_ANNOUNCING,
00085     MDNS_FOURTH_ANNOUNCING,
00086     MDNS_FIFTH_ANNOUNCING,
00087     MDNS_IDLE
00088 } SM_MDNS;
00089 
00090 // Internal MDNS Responder states
00091 typedef enum
00092 {
00093     MDNSR_STOPPED = 0,
00094     MDNSR_SERVICE,
00095     MDNSR_NAME,
00096     MDNSR_RESOLVED
00097 } SM_MDNSR;
00098 
00099 
00100 // Header of the (M)DNS message
00101 typedef struct _DNS_HEADER
00102 {
00103     WORD_VAL TransactionID;
00104     WORD_VAL Flags;
00105     WORD_VAL Questions;
00106     WORD_VAL Answers;
00107     WORD_VAL AuthoritativeRecords;
00108     WORD_VAL AdditionalRecords;
00109 } DNS_HEADER;
00110 
00111 // Structure of one DNS entry.
00112 typedef struct
00113 {
00114     BYTE        u8FirstLabelIdx;
00115     WORD_VAL    u16Type;
00116     DWORD_VAL   u32TTL;
00117     WORD_VAL    u16DataLength;
00118     void *      pData;
00119     BYTE        u8DNSFirstLabelIdx;
00120     BYTE        u8NumberOfAddRRs;
00121     ROM char *  pAddRRList;
00122     BOOL        bUnique;
00123 } DNS_ENTRY;
00124 
00125 // Single chain link structure for DNS names (pointer to the higher DNS tree
00126 // hierarchy) which are located in flash.
00127 typedef struct
00128 {
00129     ROM char *  pLabel; // Pointer to a DNS label (maximum 63 bytes) as string.
00130     BYTE        u8PrevIndex;    // 0xFF if root
00131 } DNS_ROMLABEL;
00132 
00133 
00134 // Simple structure for DNS names located in RAM (dynamic labels).
00135 typedef struct
00136 {
00137     char *  pLabel;
00138 } DNS_RAMLABEL;
00139 
00140 // With this structure an DNS query (consisting of DNS name and type qualifier)
00141 // is described. The structure is therefore used for sending queries.
00142 typedef struct
00143 {
00144     BYTE        u8FirstLabelIdx;
00145     WORD_VAL    u16Type;
00146 } DNS_QUERY;
00147 
00148 // This structures describes the architeture of an DNS service record.
00149 typedef struct
00150 {
00151     WORD_VAL    u16Priority;
00152     WORD_VAL    u16Weight;
00153     WORD_VAL    u16Port;
00154 } SRV_ENTRY;
00155 
00156 // Control fields for processing received queries and answers.
00157 typedef struct
00158 {
00159     BYTE bAnswer : 1;
00160     BYTE bUCAnswer : 1;
00161     BYTE bAdditional : 1;
00162 } DNS_CONTROL;
00163 
00164 
00166 // Local Variables
00168 
00169 // Internal MDNS state machine
00170 static SM_MDNS _eSM_MDNS = MDNS_STOPPED;
00171 static UDP_SOCKET _sMDNSMCSocket = INVALID_UDP_SOCKET;
00172 static DWORD _u32MdnsTimer;
00173 
00174 
00176 // Variables for resolving services and names 
00177 
00178 static BYTE _au8QuerySrvName[17];
00179 static SRV_ENTRY _sQuerySrv;
00180 static BYTE _au8QueryName[64];
00181 static BYTE _au8QueryIP[4];
00182 static DWORD _u32RetryTimer;
00183 static DWORD _u32IntervalTime;
00184 static SM_MDNSR _eSMResolver = MDNSR_STOPPED;
00185 
00186 
00187 
00189 // Lists for ROM and RAM DNS label storage
00190 
00191 // The list stores all known labels and forms a DNS tree due the single chain
00192 // link mechanism. ROM Labels which consits of a single byte equal or greater
00193 // '0x80' are pointer to the dynamic label list (_asRAMLabelList). In case the
00194 // processing function looks up such a value, it can simple substract '0x80' to
00195 // get the index for _asRAMLabelList.
00196 ROM DNS_ROMLABEL _asROMLabelList[] =
00197 {
00198 // 0
00199     {HOSTNAME, 1},
00200 // 1
00201     {(ROM BYTE *) "local", DNS_ROOT_LABEL},
00202 // 2
00203     {(ROM BYTE *) "_http", 3},
00204 // 3
00205     {(ROM BYTE *) "_tcp", 1},
00206 // 4
00207     {(ROM BYTE *) "in-addr", 5},
00208 // 5
00209     {(ROM BYTE *) "arpa", DNS_ROOT_LABEL},
00210 // 6
00211     {(ROM BYTE *) "_services", 7},
00212 // 7
00213     {(ROM BYTE *) "_dns-sd", 8},
00214 // 8
00215     {(ROM BYTE *) "_udp", 1},
00216 // 9
00217     {(ROM BYTE *) "\x80", 4},
00218 // 10
00219     {(ROM BYTE *) "\x81", 9},
00220 // 11
00221     {(ROM BYTE *) "\x82", 10},
00222 // 12
00223     {(ROM BYTE *) "\x83", 11},
00224 // 13
00225     {HOSTNAME, 2},
00226 // 14 (TCP_QUERY_SERVICE_IDX) -> _pQuerySrv
00227     {(ROM BYTE *) "\x84", 3},
00228 // 15 (QUERY_SERVICE_NAME_IDX) -> _pQueryName
00229     {(ROM BYTE *) "\x85", 14},
00230 // 16 (QUERY_NAME_IDX) -> _pQueryName
00231     {(ROM BYTE *) "\x85", 1},
00232 };
00233 
00234 
00235 
00236 // Buffer for the (dynamic) IP label:
00237 static BYTE _u8IPbuf[16];
00238 
00239 
00240 // This list stores all dynamic labels. This labels are located in RAM, the
00241 // pointers to this locations are stored here. Due the ROM label mechanism
00242 // this list is part of the ROM label list (see documenation of 
00243 // _asROMLabelList).
00244 ROM DNS_RAMLABEL _asRAMLabelList[] =
00245 {
00246     _u8IPbuf,
00247     &_u8IPbuf[4],
00248     &_u8IPbuf[8],
00249     &_u8IPbuf[12],
00250     _au8QuerySrvName,
00251     _au8QueryName,
00252 };
00253 
00254 
00256 // DNS entry table
00257 // Each entry is a unique key value entry. The key consists of name and type.
00258 
00259 // This a simple placeholder for a DNS name with zero length. Zero length label
00260 // must store at least the zero for the root.
00261 static BYTE _u8ZeroLength = 0;
00262 
00263 // This service entry for the eWicht HTTP service is used by the DNS entry 
00264 // table.
00265 static SRV_ENTRY _sHttpService = {0,0,0x5000};  // htons(80)=0x5000
00266 
00267 
00268 ROM DNS_ENTRY _asDNSEntries[] = 
00269 { 
00270     // hostname.local. A -> Local IP Address
00271     {0, DNS_TYPE_A, DNS_DEFAULT_TTL, 4, (void *) &sIPConfig.MyIPAddr, 
00272         DNS_UNSPECIFIED_LABEL, 0, 0, TRUE},
00273 
00274     // hostname._http._tcp.local. SRV -> hostname.local.
00275     {13, DNS_TYPE_SRV, DNS_DEFAULT_TTL, sizeof(SRV_ENTRY), &_sHttpService,
00276         0, 1, (ROM BYTE *) "\x000", TRUE},
00277 
00278     // ipaddr.in-addr.arpa. PTR -> hostname.local.
00279     {12, DNS_TYPE_PTR, DNS_DEFAULT_TTL, 0, 0, 0, 0, 0, TRUE},
00280 
00281     // _services._dns-sd._udp.local. PTR -> PTR
00282     {6, DNS_TYPE_PTR, DNS_RR_TTL, 0, 0, 2, 0, 0, FALSE},
00283 
00284     // hostname._http._tcp.local. TXT -> hostname.local.
00285     {13, DNS_TYPE_TXT, DNS_RR_TTL, 1, (void *) &_u8ZeroLength, 
00286         DNS_UNSPECIFIED_LABEL, 1, (ROM BYTE *) "\x000", TRUE},
00287 
00288     // _http._tcp.local. PTR -> hostname._http._tcp.local.
00289     {2, DNS_TYPE_PTR, DNS_RR_TTL, 0, 0, 
00290         13, 3, (ROM BYTE *) "\x000\x001\x004", FALSE}
00291 };
00292 
00293 
00294 
00296 // Control structures and variables for processing and sending frames.
00297 
00298 static WORD_VAL _au16SendEntries[DNS_LABELS];
00299 static DNS_CONTROL _sControl[DNS_ENTRIES];
00300 static BYTE _u8UniqueEntries;
00301 
00302 
00303 
00305 // Local function prototypes
00307 
00308 static void _PutQuery(BOOL bProbe, BOOL bQU, DNS_QUERY * pQuery);
00309 static BOOL _PrepareMulticast(BYTE nQueries, BYTE nAnswers, 
00310                                          BYTE nAuthoritives, BYTE nAdditional);
00311 static void _SendRRList(BYTE nEntries, ROM DNS_ENTRY * pRRList, BOOL bGoodbye);
00312 static void _PutDNSName(BYTE u8StartIndex);
00313 static BYTE _u8GetDNSNameLength(BYTE u8LabelIndex);
00314 static void _GetQueryData(WORD_VAL * psType, WORD_VAL * psClass);
00315 static void _QueryLookUp(void);
00316 static void _AnswerLookUp(BOOL bQuery);
00317 BYTE _u8GetRRData(WORD_VAL * pType, WORD_VAL * pClass);
00318 BYTE _u8GetStartLabelFromFrame(void);
00319 void _CheckForQueryResponse(WORD_VAL u16Type, WORD_VAL * pu16Length, 
00320                                                             BYTE u8Startlabel);
00321 
00323 // Implementation
00325 
00330 BOOL bInitMDNSResponder(void)
00331 {
00332     BYTE i = 0;
00333     NODE_INFO nodeInfo;
00334 
00335     // Prepare multicast address data for the frame.
00336     nodeInfo.MACAddr.v[0]= 0x01;
00337     nodeInfo.MACAddr.v[1]= 0x00;
00338     nodeInfo.MACAddr.v[2]= 0x5e;
00339     nodeInfo.MACAddr.v[3]= 0x00;
00340     nodeInfo.MACAddr.v[4]= 0x00;
00341     nodeInfo.MACAddr.v[5]= 0xfb;
00342     nodeInfo.IPAddr.v[0] = 224;
00343     nodeInfo.IPAddr.v[1] = 0;
00344     nodeInfo.IPAddr.v[2] = 0;
00345     nodeInfo.IPAddr.v[3] = 251;
00346 
00347     _eSM_MDNS = MDNS_STOPPED;
00348 
00349     _sMDNSMCSocket = UDPOpen(MDNS_PORT, &nodeInfo, MDNS_PORT);
00350 
00351     if(_sMDNSMCSocket == INVALID_UDP_SOCKET)
00352         return FALSE;
00353 
00354     // Determine the count of unique DNS entries (no PTR records!)
00355     _u8UniqueEntries = 0;
00356     for (i=0; i < DNS_ENTRIES; i++)
00357     {
00358         if ((_asDNSEntries[i].u16Type.Val != DNS_TYPE_PTR)&&
00359             (_asDNSEntries[i].bUnique==TRUE))
00360                 _u8UniqueEntries++;
00361     }
00362     
00363     return TRUE;
00364 }
00365 
00368 
00369 void StartMDNSResponder(void)
00370 {
00371     BYTE i = 0;
00372 
00373     MDNSStopResolving();
00374 
00375     // Prepare the IP labels!
00376     for (i=0;i<4;i++)
00377         sprintf(&_u8IPbuf[i<<2], "%u", sIPConfig.MyIPAddr.v[i]);
00378 
00379     // Start probing the DNS entries like described in the Multicast DNS 
00380     // internet draft chapter 9.1.
00381 
00382     _u32MdnsTimer = TickGet() + (rand() % ((DWORD)(TICKS_PER_SECOND >> 2)));
00383     _eSM_MDNS = MDNS_WAIT_FOR_PROBING;
00384 
00385 /*
00386     From mDNS draft:
00387     When ready to send its mDNS probe packet(s) the host should first
00388     wait for a short random delay time, uniformly distributed in the
00389     range 0-250ms. This random delay is to guard against the case where a
00390     group of devices are powered on simultaneously, or a group of devices
00391     are connected to an Ethernet hub which is then powered on, or some
00392     other external event happens that might cause a group of hosts to all
00393     send synchronized probes.
00394 */
00395 }
00396 
00399 
00400 void StopMDNSResponder(void)
00401 {
00402     // Stop any pending queries...
00403     MDNSStopResolving();
00404 
00405     if (_eSM_MDNS > MDNS_THIRD_PROBE)
00406     {
00407         // As seen in the Bonjour traces, we only send entries in the goodbye
00408         // packet which are shared entries which point to unique entries. 
00409         _PrepareMulticast(0, DNS_GOODBYE_ENTRIES, 0, 0);
00410         _SendRRList(DNS_GOODBYE_ENTRIES, 
00411                 &_asDNSEntries[DNS_ENTRIES-DNS_GOODBYE_ENTRIES], 
00412                 TRUE);
00413         UDPFlush();
00414     }
00415     
00416     _eSM_MDNS = MDNS_STOPPED;
00417 }
00418 
00421 
00422 MDNS_STATE eGetMDNSState(void)
00423 {
00424     if (_eSM_MDNS == MDNS_STOPPED)
00425         return MDNS_HAS_STOPPED;
00426     else if (_eSM_MDNS > MDNS_FIRST_ANNOUNCING)
00427         return MDNS_IS_RUNNING;
00428     else
00429         return MDNS_IS_STARTING_UP;
00430 }
00431 
00434 
00435 void MDNSResponder()
00436 {
00437     BOOL bSendUnicast = TRUE;
00438     BYTE i=0;
00439 
00440     switch(_eSM_MDNS)
00441     {
00442     case MDNS_STOPPED:
00443         break;
00444 
00445     case MDNS_THIRD_PROBE:
00446         bSendUnicast = FALSE;
00447     case MDNS_SECOND_PROBE:
00448     case MDNS_WAIT_FOR_PROBING:
00449         if (TickGet() > _u32MdnsTimer)
00450         {
00451             /*
00452             From mDNS internet draft:
00453             250ms after the first query the host should send a second, then
00454             250ms after that a third. If, by 250ms after the third probe, no
00455             conflicting Multicast DNS responses have been received, the host may
00456             move to the next step, announcing. (Note that this is the one
00457             exception from the normal rule that there should be at least one
00458             second between repetitions of the same question, and the interval
00459             between subsequent repetitions should double.)
00460             */
00461 
00462             // Send a probe packet...
00463             _PrepareMulticast(DNS_PROBE_ENTRIES, 0, _u8UniqueEntries, 0);
00464 
00465             for(i=0; i < DNS_PROBE_ENTRIES; i++)
00466             {
00467                 DNS_QUERY query;
00468                 query.u8FirstLabelIdx = _asDNSEntries[i].u8FirstLabelIdx;
00469                 query.u16Type = _asDNSEntries[i].u16Type;
00470                 _PutQuery(TRUE, bSendUnicast, &query);
00471             }
00472         
00473             // Transfer the unique entries a authoritive nameserver...
00474             for (i=0; i < DNS_ENTRIES; i++)
00475             {
00476                 if((_asDNSEntries[i].bUnique==TRUE)&&
00477                    (_asDNSEntries[i].u16Type.Val != DNS_TYPE_PTR))
00478                 {
00479                     _SendRRList(1, &_asDNSEntries[i], FALSE);
00480                 }
00481             }
00482             UDPFlush();
00483 
00484             _u32MdnsTimer += (DWORD)(TICKS_PER_SECOND >> 2);
00485             _eSM_MDNS++;
00486         }
00487         break;
00488 
00489     case MDNS_FIRST_ANNOUNCING:
00490     case MDNS_SECOND_ANNOUNCING:
00491     case MDNS_THIRD_ANNOUNCING:
00492     case MDNS_FOURTH_ANNOUNCING:
00493     case MDNS_FIFTH_ANNOUNCING:
00494         if (TickGet() > _u32MdnsTimer)
00495         {
00496             /* From mDNS internet draft:
00497             The Multicast DNS Responder MUST send at least two gratuitous
00498             responses, one second apart. A Responder MAY send up to eight
00499             gratuitous Responses, provided that the interval between gratuitous
00500             responses doubles with every response sent. */
00501 
00502             // Send an announce packet...
00503             _PrepareMulticast(0, DNS_ENTRIES, 0, 0);
00504             _SendRRList(DNS_ENTRIES, _asDNSEntries, FALSE);
00505             UDPFlush();
00506 
00507             _u32MdnsTimer += (TICKS_PER_SECOND)*
00508                                          (1<<(_eSM_MDNS-(MDNS_FIRST_ANNOUNCING)));
00509             _eSM_MDNS++;
00510         }
00511         break;
00512     }
00513 
00514     if((_eSM_MDNS > MDNS_FIRST_ANNOUNCING)&&
00515        ((_eSMResolver == MDNSR_SERVICE) || (_eSMResolver == MDNSR_NAME)))
00516     {
00517         if (TickGet() > _u32RetryTimer)
00518         {
00519             if (_u32IntervalTime<MAXREPEAT_INTERVAL)
00520                 _u32IntervalTime = _u32IntervalTime << 1;
00521 
00522             _u32RetryTimer += _u32IntervalTime;
00523             if (_eSMResolver == MDNSR_SERVICE)
00524                 MDNSResolveService(0, 0);           
00525             else
00526                 MDNSResolveName(0);
00527         }
00528     }
00529 }
00530 
00533 
00534 void MDNSProcessFrame(NODE_INFO *remoteNode, IP_ADDR *localIP)
00535 {
00536     DNS_HEADER head;
00537     BYTE i;
00538 
00539     // Multicast-IP 224.0.0.251 regardless of source IP OR
00540     // same subnet of local IP and source IP
00541     if ((localIP->Val != 0xFB0000E0ul) &&
00542         ((remoteNode->IPAddr.Val & sIPConfig.MyMask.Val) !=
00543          (sIPConfig.MyIPAddr.Val & sIPConfig.MyMask.Val)))
00544     {
00545         return;
00546     }
00547 
00548 
00549     // The following function call should always return TRUE!!!
00550     if (!UDPIsGetReady(_sMDNSMCSocket))
00551         return;
00552 
00553     // Received a frame to process. Prepare status fields:
00554     memset(_sControl, 0, sizeof(_sControl));
00555 
00556 
00557     // ToDo: Add unicast support here!
00558     // It is recommended feature of the mDNS internet draft (chapter 6) to 
00559     // answer as a unicast frame on unicast queries. It is not mandatory!
00560     // All informations are available here to generate a unicast answer easily.
00561 
00562 
00563 
00564 
00565     // Retrieve the DNS header and de-big-endian it
00566 
00567     // MDNS ignores the Query ID field (except for generating legacy responses)
00568     UDPGet(&head.TransactionID.v[1]);
00569     UDPGet(&head.TransactionID.v[0]);
00570 
00571     UDPGet(&head.Flags.v[1]);
00572     UDPGet(&head.Flags.v[0]);
00573 
00574     UDPGet(&head.Questions.v[1]);
00575     UDPGet(&head.Questions.v[0]);
00576     UDPGet(&head.Answers.v[1]);
00577     UDPGet(&head.Answers.v[0]);
00578     UDPGet(&head.AuthoritativeRecords.v[1]);
00579     UDPGet(&head.AuthoritativeRecords.v[0]);
00580     UDPGet(&head.AdditionalRecords.v[1]);
00581     UDPGet(&head.AdditionalRecords.v[0]);
00582 
00583 
00584     if (head.Flags.Val == 0)
00585     {
00586         // Standard query received. Maybe we can response it?
00587         BYTE j, answers = 0, additional = 0;
00588 
00589         // The responder only processes frames after probing is successfull.
00590         if (_eSM_MDNS < MDNS_SECOND_ANNOUNCING)
00591             goto MDNSProcessEnd;
00592 
00593         // We only reply to requests with at least one query.
00594         if (head.Questions.Val == 0)
00595             goto MDNSProcessEnd;
00596 
00597         while(head.Questions.Val--)
00598         {
00599             // Check all questions for known answers!
00600             _QueryLookUp();
00601         }
00602 
00603         while(head.Answers.Val--)
00604         {
00605             // Check all answers for known answers!
00606             _AnswerLookUp(TRUE);
00607         }
00608 
00609         // count the valid answers...
00610         for(i = 0; i < DNS_ENTRIES; i++)
00611         {
00612             if (_sControl[i].bAnswer == TRUE)
00613             {
00614                 answers++;
00615                 
00616                 // Mark the additional records!
00617                 // (see dns-sd internet draft chapter 13)
00618                 for(j = 0; j < _asDNSEntries[i].u8NumberOfAddRRs; j++)
00619                 {
00620                     BYTE add = _asDNSEntries[i].pAddRRList[j];
00621                     if (_sControl[add].bAnswer == FALSE)
00622                         _sControl[add].bAdditional = TRUE;
00623                 }
00624             }
00625         }
00626 
00627         // count the valid additional fields...
00628         for(i = 0; i < DNS_ENTRIES; i++)
00629         {
00630             if (_sControl[i].bAdditional == TRUE)
00631                 additional++;
00632         }
00633 
00634         if (answers)
00635         {
00636             // Send an answer packet...
00637             _PrepareMulticast(0, answers, 0, additional);
00638 
00639             for(i = 0; i < DNS_ENTRIES; i++)
00640             {
00641                 if (_sControl[i].bAnswer == TRUE)
00642                     _SendRRList(1, &_asDNSEntries[i], FALSE);
00643             }
00644             
00645             if (additional)
00646             {
00647                 for(i = 0; i < DNS_ENTRIES; i++)
00648                 {
00649                     if (_sControl[i].bAdditional == TRUE)
00650                         _SendRRList(1, &_asDNSEntries[i], FALSE);
00651                 }
00652             }
00653 
00654             UDPFlush();
00655         }
00656     }
00657     else if (head.Flags.Val & 0x8000)
00658     {
00659         // Response received. 
00660 
00661         // 1.1 Compare all answers (TYPE and NAME) with our local DNS entry
00662         // list. If the found matches include unique entries, there is a 
00663         // conflict on the network! The service will be stopped.
00664 
00665         // 1.2 If a DNS query is pending, save the matching answer to a 
00666         // answer list.
00667 
00668         while(head.Answers.Val--)
00669             _AnswerLookUp(FALSE);
00670 
00671         while(head.AuthoritativeRecords.Val--)
00672             _AnswerLookUp(FALSE);
00673 
00674         while(head.AdditionalRecords.Val--)
00675             _AnswerLookUp(FALSE);
00676 
00677         // Look for found answers which are ambiguous!
00678         for(i = 0; i < DNS_ENTRIES; i++)
00679         {
00680             if (_sControl[i].bAnswer == TRUE)
00681                 break;
00682         }
00683 
00684         // Ambiguity is very bad and leads to a stopped MDNS service!
00685         if (i != DNS_ENTRIES)
00686             StopMDNSResponder();
00687         
00688     }
00689 
00690 MDNSProcessEnd:
00691     UDPDiscard();
00692 }
00693 
00696 
00697 BOOL bMDNSNameIsResolved(IP_ADDR * pIP)
00698 {
00699     if (_eSMResolver != MDNSR_RESOLVED)
00700         return FALSE;
00701     memcpy(pIP,(void *)_au8QueryIP, 4);
00702     return TRUE; 
00703 }
00704 
00707 
00708 BOOL bMDNSServiceIsResolved(IP_ADDR * pIP, WORD_VAL * pu16Port)
00709 {
00710     if (bMDNSNameIsResolved(pIP) == TRUE)
00711     {
00712         *pu16Port = _sQuerySrv.u16Port;
00713         return TRUE;
00714     }
00715     return FALSE;
00716 }
00717 
00720 
00721 void MDNSStopResolving(void)
00722 {
00723     _eSMResolver = MDNSR_STOPPED;
00724 }
00725 
00728 
00729 void MDNSResolveName(char * pName)
00730 {
00731     DNS_QUERY query;
00732 
00733     // Copy the name to query in dynamic query field.
00734     if (pName)
00735     {
00736         // Initial query!
00737         strcpy(_au8QueryName, pName);
00738         _u32RetryTimer = TickGet() + TICKS_PER_SECOND;
00739         _u32IntervalTime = TICKS_PER_SECOND;
00740     }
00741 
00742     query.u16Type.Val = DNS_TYPE_A;
00743     query.u8FirstLabelIdx = QUERY_NAME_IDX;
00744 
00745     _PrepareMulticast(1, 0, 0, 0);
00746     _PutQuery(FALSE, FALSE, &query);
00747 
00748     UDPFlush();
00749 
00750     _eSMResolver = MDNSR_NAME;
00751 }
00752 
00755 
00756 void MDNSResolveService(char * pName, ROM char * pServiceName)
00757 {
00758     DNS_QUERY query;
00759 
00760     // Copy the name and the service to query in dynamic query field.
00761     if (pName)
00762     {
00763         // Initial query
00764         strcpypgm2ram(_au8QuerySrvName, pServiceName);
00765         strcpy(_au8QueryName, pName);
00766         _u32RetryTimer = TickGet() + TICKS_PER_SECOND;
00767         _u32IntervalTime = TICKS_PER_SECOND;
00768     }
00769 
00770     query.u16Type.Val = DNS_TYPE_SRV;
00771     query.u8FirstLabelIdx = QUERY_SERVICE_NAME_IDX;
00772 
00773     _PrepareMulticast(1, 0, 0, 0);
00774     _PutQuery(FALSE, FALSE, &query);
00775 
00776     UDPFlush();
00777 
00778     _eSMResolver = MDNSR_SERVICE;
00779 }
00780 
00783 
00784 static BYTE _u8GetDNSNameLength(BYTE u8LabelIndex)
00785 {
00786     BYTE i=0;
00787 
00788     while(u8LabelIndex != DNS_ROOT_LABEL)
00789     {
00790         ROM BYTE * pRomLabel = _asROMLabelList[u8LabelIndex].pLabel;
00791 
00792         if (_au16SendEntries[u8LabelIndex].Val)
00793         {
00794             // Message compression field.
00795             i+=2;
00796             return i;
00797         }
00798 
00799         // Add one length byte for the length field
00800         i++;
00801         if (*pRomLabel & 0x80)
00802         {
00803             // Pointer to a RAM-Label.
00804             BYTE ramidx = (*pRomLabel) & 0x7F;
00805             BYTE * pRamLabel = _asRAMLabelList[ramidx].pLabel;
00806             
00807             // Put the length...
00808             i += strlen(pRamLabel);
00809         }
00810         else
00811             i += strlenpgm(pRomLabel);
00812     
00813         u8LabelIndex = _asROMLabelList[u8LabelIndex].u8PrevIndex;   
00814     }
00815 
00816     // Add the root label length indicator.
00817     return i++;
00818 }
00819 
00822 
00823 static void _PutDNSName(BYTE u8LabelIndex)
00824 {
00825     while(u8LabelIndex != DNS_ROOT_LABEL)
00826     {
00827         ROM BYTE * pRomLabel = _asROMLabelList[u8LabelIndex].pLabel;
00828         
00829         if (_au16SendEntries[u8LabelIndex].Val)
00830         {
00831             // DNS name already sent via UDP (Do message compression).
00832             UDPPut(0xc0 | (_au16SendEntries[u8LabelIndex].v[1]));
00833             
00834             // Insert the position.
00835             UDPPut(_au16SendEntries[u8LabelIndex].v[0]);
00836             return;
00837         }
00838         else
00839         {
00840             // Save the offset for message compression:
00841             _au16SendEntries[u8LabelIndex].Val = UDPGetPutOffset();
00842 
00843             if (*pRomLabel & 0x80)
00844             {
00845                 // Pointer to a RAM-Label.
00846                 BYTE ramidx = (*pRomLabel) & 0x7F;
00847                 BYTE * pRamLabel = _asRAMLabelList[ramidx].pLabel;
00848                 
00849                 // Put the length...
00850                 UDPPut(strlen(pRamLabel));
00851     
00852                 UDPPutString(pRamLabel);
00853             }
00854             else
00855             {
00856                 // Pointer to a ROM-Label.
00857     
00858                 // Put the length...
00859                 UDPPut(strlenpgm(pRomLabel));
00860     
00861                 UDPPutROMString(pRomLabel);
00862             }
00863         
00864             u8LabelIndex = _asROMLabelList[u8LabelIndex].u8PrevIndex;
00865         }
00866     }
00867     
00868     // Put the string terminator character
00869     UDPPut(0x00);
00870 }
00871 
00874 
00875 static void _GetQueryData(WORD_VAL * psType, WORD_VAL * psClass)
00876 {
00877     // Get the type from the received packet
00878     UDPGet(&psType->v[1]);  
00879     UDPGet(&psType->v[0]);
00880 
00881     // Get the class from the received packet
00882     UDPGet(&psClass->v[1]); 
00883     UDPGet(&psClass->v[0]); 
00884 }
00885 
00888 
00889 static void _AnswerLookUp(BOOL bQuery)
00890 {
00891     BYTE startlabel=0, i=0;
00892     WORD j=0;
00893     WORD_VAL type=0, class=0;
00894     WORD_VAL length, locallength;
00895     DWORD_VAL ttl = 0;
00896     BOOL bKeyMatch = FALSE;
00897     BOOL bEntryMatch = FALSE;
00898 
00899     // 1) Get the start label from the frame...
00900     startlabel = _u8GetRRData(&type, &class);   
00901 
00902     
00903     // 2) Read out the rest of the answer section...
00904     UDPGet(&ttl.v[3]);
00905     UDPGet(&ttl.v[2]);
00906     UDPGet(&ttl.v[1]);
00907     UDPGet(&ttl.v[0]);
00908 
00909     UDPGet(&length.v[1]);
00910     UDPGet(&length.v[0]);
00911 
00912 
00913     // 3) Unknown DNS name: Stop the processing.
00914     if (startlabel == DNS_UNSPECIFIED_LABEL)
00915     {
00916         // read out the payload and throw it away
00917         UDPGetArray(NULL, length.Val);
00918         return;
00919     }
00920 
00921 
00922     // 4) Get the DNS entry for the found name/type key.
00923     for(i=0; i < DNS_ENTRIES; i++)
00924     {
00925         if ((_asDNSEntries[i].u8FirstLabelIdx == startlabel)&&
00926             (_asDNSEntries[i].u16Type.Val == type.Val))
00927         {
00928             bKeyMatch = TRUE;
00929             locallength.Val = 
00930                       _u8GetDNSNameLength(_asDNSEntries[i].u8DNSFirstLabelIdx);
00931 
00932             if(length.Val != _asDNSEntries[i].u16DataLength.Val+locallength.Val)
00933                 break;
00934 
00935             // Check the payload for equality!
00936             for (j=0; j<_asDNSEntries[i].u16DataLength.Val; j++)
00937             {
00938                 BYTE tmp = 0;
00939                 UDPGet(&tmp);
00940                 length.Val--;
00941                 if (tmp!=((BYTE *)(_asDNSEntries[i].pData))[j])
00942                     break;
00943             }
00944             
00945             if (j!=_asDNSEntries[i].u16DataLength.Val)
00946                 break;
00947 
00948             if ((_asDNSEntries[i].u8DNSFirstLabelIdx!=DNS_UNSPECIFIED_LABEL)&&
00949                 (_u8GetStartLabelFromFrame() !=
00950                                           _asDNSEntries[i].u8DNSFirstLabelIdx))
00951             {
00952                 // _u8GetStartLabelFromFrame() reads out the hole name:
00953                 // No payload is left?! Check this out!
00954                 length.Val = 0;
00955                 break;
00956             }
00957 
00958             // Like described in mDNS internet draft (chapter 7.1 Known Answer
00959             // Suppression): Check the TTL of an received possible answer. If
00960             // the entry is to old, send a new answer.
00961             if ((_asDNSEntries[i].u32TTL.Val >> 1)<ttl.Val)
00962             {
00963                 // Thats our answer. Surpress it in a answer packet!
00964                 _sControl[i].bAnswer = FALSE;
00965             }
00966 
00967             bEntryMatch = TRUE;
00968             break;
00969         }
00970     }
00971     
00972     // Look, if it is a answer for a running query...
00973     if ((bQuery==FALSE)&&(bKeyMatch==FALSE))
00974         _CheckForQueryResponse(type, &length, startlabel);
00975 
00976     
00977     // read out the rest of the answer RR.
00978     if (length.Val)
00979         UDPGetArray(NULL,length.Val);
00980 
00981     // Check the uniqueness of the found DNS entry!
00982     if ((bQuery==FALSE)&&(bKeyMatch==TRUE)&&(_asDNSEntries[i].bUnique==TRUE))
00983     {
00984         // Thats a ambiguous DNS entry! Mark it for the calling function.
00985         _sControl[i].bAnswer = TRUE;
00986     }
00987     return;
00988 }
00989 
00992 
00993 static void _QueryLookUp(void)
00994 {
00995     BYTE labellen = 0;
00996     BYTE namelen = 0;
00997     BYTE startlabel = 0, j = 0;
00998     WORD_VAL type = 0, class = 0;
00999 
01000     // 1) Get the start label from the frame.
01001     startlabel = _u8GetRRData(&type, &class);   
01002     if (startlabel == DNS_UNSPECIFIED_LABEL)
01003         return;
01004 
01005 
01006     // 2) Get the DNS entry for the found label row
01007     for(j=0; j < DNS_ENTRIES; j++)
01008     {
01009         if ((_asDNSEntries[j].u8FirstLabelIdx == startlabel)&&
01010             ((_asDNSEntries[j].u16Type.Val == type.Val) ||
01011              (type.Val == DNS_TYPE_ANY)))
01012         {
01013             // We know the answer!
01014             _sControl[j].bAnswer = TRUE;
01015 
01016             // Is a unicast reponse requested?
01017             if (class.v[1] & 0x80)
01018                 _sControl[j].bUCAnswer = TRUE;
01019         }
01020     }
01021 
01022     return;
01023 }
01024 
01027 
01028 BYTE _u8GetRRData(WORD_VAL * pType, WORD_VAL * pClass)
01029 {
01030     BYTE label = _u8GetStartLabelFromFrame();
01031     _GetQueryData(pType, pClass);
01032 
01033     // Check the class (only internet class is supported)
01034     if ((pClass->Val & 0x7FFF) != 0x0001)
01035         return DNS_UNSPECIFIED_LABEL;
01036 
01037     return label;
01038 }
01039 
01042 
01043 void _CheckForQueryResponse(WORD_VAL u16Type, WORD_VAL * pu16Length, 
01044                                                              BYTE u8Startlabel)
01045 {
01046     if ((u16Type.Val==DNS_TYPE_SRV)&&
01047         (_eSMResolver == MDNSR_SERVICE)&&
01048         (u8Startlabel == QUERY_SERVICE_NAME_IDX))
01049     {
01050         // Service query is running and is resolved.
01051         BYTE labellen;
01052 
01053         // Name query is running and is resolved.
01054         UDPGet(&_sQuerySrv.u16Priority.v[1]);
01055         UDPGet(&_sQuerySrv.u16Priority.v[0]);
01056         UDPGet(&_sQuerySrv.u16Weight.v[1]);
01057         UDPGet(&_sQuerySrv.u16Weight.v[0]);
01058         UDPGet(&_sQuerySrv.u16Port.v[1]);
01059         UDPGet(&_sQuerySrv.u16Port.v[0]);
01060 
01061         pu16Length->Val = pu16Length->Val - sizeof(SRV_ENTRY);
01062 
01063         UDPGet(&labellen);
01064         if (labellen & 0xc0)
01065         {
01067             /*
01068             WORD_VAL pos;
01069             pos.v[1] = labellen & 0x3F;
01070             UDPGet(&pos.v[0]);
01071             labellen++;
01072             */
01073         }
01074         else
01075             UDPGetArray(_au8QueryName, labellen);
01076 
01077         _au8QueryName[labellen] = 0;    // Terminate the string.
01078         pu16Length->Val-= labellen+1;   // Correct the length field.
01079 
01080         // Start resolving the found name...
01081         _u32RetryTimer = TickGet() + TICKS_PER_SECOND;
01082         _u32IntervalTime = TICKS_PER_SECOND;
01083         _eSMResolver = MDNSR_NAME;
01084         strlwr(_au8QueryName);  
01085     }
01086     else if ((u16Type.Val==DNS_TYPE_A)&&
01087         (_eSMResolver == MDNSR_NAME)&&
01088         (u8Startlabel == QUERY_NAME_IDX))
01089     {
01090         // Name query is running and is resolved.
01091         UDPGetArray(_au8QueryIP, 4);
01092         pu16Length->Val = 0;
01093         _eSMResolver = MDNSR_RESOLVED;
01094     }
01095 }
01096 
01099 
01100 BYTE _u8GetStartLabelFromFrame(void)
01101 {
01102     BOOL bFound = FALSE;
01103     BOOL bNoSpaceLeft = FALSE;
01104     BYTE labellen = 0, namelen = 0, labelcount = 0, i, j;
01105     BYTE name[MAX_DNS_NAME_LEN];
01106     WORD_VAL udppos = u16MACGetCurrentReadPtrPos();
01107 
01108     memset(name, 0, MAX_DNS_NAME_LEN);
01109 
01110     // 1) Fetch complete DNS name (until pointer or root) from UDP frame.
01111     while(1)
01112     {
01113         labellen = MACGet();        // Get the length field
01114 
01115         if (labellen & 0xc0)
01116         {
01117             // Message compression label
01118             WORD_VAL address;
01119             address.v[1] = labellen & 0x3F;
01120             address.v[0] = MACGet();
01121 
01122             // Seek to the label position
01123             MACSetReadPtrInRx(sizeof(IP_HEADER)+sizeof(UDP_HEADER)+address.Val);
01124             continue;
01125         }
01126         
01127         if (labellen == 0)
01128             // root
01129             break;
01130 
01131 
01132         // Is space left for more names?
01133         if ((namelen+labellen) > MAX_DNS_NAME_LEN)
01134         {
01135             // No space left...
01136             bNoSpaceLeft = TRUE;
01137             break;
01138         }
01139 
01140         name[namelen++] = labellen;
01141 
01142         MACGetArray(&name[namelen], labellen);
01143 
01144         // DNS does not distinguish between lower and upper:    
01145         strlwr(&name[namelen]); 
01146 
01147         namelen += labellen;
01148     }
01149 
01150     // 3) Reseek 
01151     MACSetCurrentReadPtrPos(udppos);
01152     
01153 
01154     //  4) Read out the name from the UDP frame
01155     while(UDPGet(&labellen) == TRUE)
01156     {
01157         if (labellen & 0xc0)
01158         {
01159             BYTE dummy;
01160             UDPGet(&dummy);
01161             break;
01162         }
01163         else if (labellen == 0)
01164             break;
01165 
01166         UDPGetArray(NULL, labellen);
01167     }
01168 
01169     if (bNoSpaceLeft == TRUE)
01170         return DNS_UNSPECIFIED_LABEL;
01171 
01172 
01173     // 5) Compare the local labels with the DNS labels (starting at the leafs).
01174     for(i=0; i<DNS_LABELS; i++)
01175     {
01176         BYTE index = i; // Startindex
01177         namelen = 0;
01178 
01179         while(1)
01180         {
01181             ROM BYTE * pRomLabel;
01182 
01183             labellen = name[namelen++];
01184             if (labellen == 0)
01185             {
01186                 // Root
01187                 if (index == DNS_ROOT_LABEL)
01188                     bFound = TRUE;
01189 
01190                 break;
01191             }
01192 
01193             pRomLabel = _asROMLabelList[index].pLabel;
01194             if (*pRomLabel & 0x80)
01195             {
01196                 // RAM-Label
01197                 BYTE ramidx = (*pRomLabel) & 0x7F;
01198                 BYTE * pRamLabel = _asRAMLabelList[ramidx].pLabel;
01199                 
01200                 if (memcmp((void*)&name[namelen],(void*) pRamLabel, labellen)!=0)
01201                     break;
01202             }
01203             else
01204             {
01205                 // ROM-Label
01206                 if (memcmppgm2ram(&name[namelen], pRomLabel, labellen)!=0)
01207                     break;
01208             }
01209             
01210             index = _asROMLabelList[index].u8PrevIndex;
01211             namelen += labellen;
01212         };
01213 
01214         // DNS name already found?
01215         if(bFound == TRUE)
01216             break;
01217     }
01218 
01219 
01220 
01221     // Go back, if we have not found anything.
01222     if (bFound == FALSE)
01223         return DNS_UNSPECIFIED_LABEL;
01224 
01225     return i;
01226 }
01227 
01230 
01231 static BOOL _PrepareMulticast(BYTE nQueries, BYTE nAnswers, 
01232                                           BYTE nAuthoritives, BYTE nAdditional)
01233 {
01234     if(!UDPIsPutReady(_sMDNSMCSocket))
01235         return FALSE;
01236 
01237     // Reset the message compression fields...
01238     memset(_au16SendEntries, 0, sizeof(_au16SendEntries));
01239 
01240     UDPPut(0x00);   // Transaction ID is always zero in multicasts.
01241     UDPPut(0x00);
01242 
01243 
01244     /*
01245     Taken from Internet draft:
01246     AA (Authoritative Answer) Bit
01247 
01248     In query messages, the Authoritative Answer bit MUST be zero on
01249     transmission, and MUST be ignored on reception.
01250     
01251     In response messages for Multicast Domains, the Authoritative Answer
01252     bit MUST be set to one (not setting this bit implies there's some
01253     other place where "better" information may be found) and MUST be
01254     ignored on reception.
01255     */
01256 
01257     if (nQueries)
01258         UDPPut(0x00);       // Standard query without recursion
01259     else
01260         UDPPut(0x84);       // Response
01261     UDPPut(0x00);   
01262 
01263     UDPPut(0x00);
01264     UDPPut(nQueries);       // questions
01265     
01266     UDPPut(0x00);
01267     UDPPut(nAnswers);       // answers
01268 
01269     UDPPut(0x00);
01270     UDPPut(nAuthoritives);      // Name server resource records.
01271     UDPPut(0x00);
01272     UDPPut(nAdditional);        // Additional records
01273 
01274     return TRUE;
01275 }
01276 
01279 
01280 static void _SendRRList(BYTE nEntries, ROM DNS_ENTRY * pRRList, BOOL bGoodbye)
01281 {
01282     BYTE i = 0;
01283  
01284     for(; i < nEntries; i++)
01285     {
01286         WORD_VAL len = 0;
01287 
01288         _PutDNSName(pRRList[i].u8FirstLabelIdx);
01289 
01290         // Transfer type...
01291         UDPPut(pRRList[i].u16Type.v[1]);
01292         UDPPut(pRRList[i].u16Type.v[0]);
01293 
01294         // Transfer class (Internet)
01295         UDPPut(pRRList[i].bUnique<<7);  
01296         UDPPut(0x01);
01297 
01298         // Transfer TTL (zero if goodbye)
01299         if (bGoodbye == FALSE)
01300         {
01301             UDPPut(pRRList[i].u32TTL.v[3]); 
01302             UDPPut(pRRList[i].u32TTL.v[2]);
01303             UDPPut(pRRList[i].u32TTL.v[1]);
01304             UDPPut(pRRList[i].u32TTL.v[0]);
01305         }
01306         else
01307         {
01308             UDPPut(0);  
01309             UDPPut(0);
01310             UDPPut(0);
01311             UDPPut(0);
01312         }
01313 
01314         // Transfer data length (first add RAM and ROM payload)
01315         len.Val = pRRList[i].u16DataLength.Val +
01316                         _u8GetDNSNameLength(pRRList[i].u8DNSFirstLabelIdx);
01317         UDPPut(len.v[1]);
01318         UDPPut(len.v[0]);       
01319 
01320         // Transfer the RAM payload if available...
01321         if (pRRList[i].u16DataLength.Val)
01322             UDPPutArray(pRRList[i].pData, pRRList[i].u16DataLength.Val);
01323 
01324         // Transfer the DNS payload if available...
01325         if (pRRList[i].u8DNSFirstLabelIdx != DNS_ROOT_LABEL)
01326             _PutDNSName(pRRList[i].u8DNSFirstLabelIdx);
01327     }
01328 }
01329 
01330 
01333 
01334 static void _PutQuery(BOOL bProbe, BOOL bQU, DNS_QUERY * pQuery)
01335 {
01336     BYTE i = 0;
01337     _PutDNSName(pQuery->u8FirstLabelIdx);
01338 
01339     // Type...
01340     if (bProbe==TRUE)
01341     {
01342         UDPPut(DNS_TYPE_ANY>>8);
01343         UDPPut(DNS_TYPE_ANY);
01344     }
01345     else
01346     {
01347         UDPPut(pQuery->u16Type.v[1]);
01348         UDPPut(pQuery->u16Type.v[0]);
01349     }
01350 
01351     // Class...
01352     /*
01353     Taken from Internet draft:
01354     Repurposing of top bit of qclass in Question Section
01355     
01356     In the Question Section of a Multicast DNS Query, the top bit of the
01357     qclass field is used to indicate that unicast responses are preferred
01358     for this particular question.   
01359     */
01360 
01361     UDPPut(bQU<<7); // Force unicast reponse, if requested.     
01362     UDPPut(0x01);   // Class: IN (Internet)
01363 }

Generated on Sun Nov 27 20:02:38 2011 for eWicht by  doxygen 1.5.5