]> git.karo-electronics.de Git - karo-tx-redboot.git/blob - packages/redboot/v2_0/src/net/dns.c
unified MX27, MX25, MX37 trees
[karo-tx-redboot.git] / packages / redboot / v2_0 / src / net / dns.c
1 //=============================================================================
2 //
3 //      dns.c
4 //
5 //      DNS client code
6 //
7 //=============================================================================
8 //####ECOSGPLCOPYRIGHTBEGIN####
9 // -------------------------------------------
10 // This file is part of eCos, the Embedded Configurable Operating System.
11 // Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
12 // Copyright (C) 2003 Gary Thomas
13 //
14 // eCos is free software; you can redistribute it and/or modify it under
15 // the terms of the GNU General Public License as published by the Free
16 // Software Foundation; either version 2 or (at your option) any later version.
17 //
18 // eCos is distributed in the hope that it will be useful, but WITHOUT ANY
19 // WARRANTY; without even the implied warranty of MERCHANTABILITY or
20 // FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
21 // for more details.
22 //
23 // You should have received a copy of the GNU General Public License along
24 // with eCos; if not, write to the Free Software Foundation, Inc.,
25 // 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
26 //
27 // As a special exception, if other files instantiate templates or use macros
28 // or inline functions from this file, or you compile this file and link it
29 // with other works to produce a work based on this file, this file does not
30 // by itself cause the resulting work to be covered by the GNU General Public
31 // License. However the source code for this file must still be made available
32 // in accordance with section (3) of the GNU General Public License.
33 //
34 // This exception does not invalidate any other reasons why a work based on
35 // this file might be covered by the GNU General Public License.
36 //
37 // Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
38 // at http://sources.redhat.com/ecos/ecos-license/
39 // -------------------------------------------
40 //####ECOSGPLCOPYRIGHTEND####
41 //=============================================================================
42 //#####DESCRIPTIONBEGIN####
43 //
44 // Author(s):   jskov
45 // Contributors:jskov
46 // Date:        2001-09-26
47 // Description: Provides DNS lookup as per RFC 1034/1035.
48 // 
49 // Note:        This is a stripped down clone of dns.c from the CYGPKG_NS_DNS
50 //              package which does not use malloc/free and has been tweaked to
51 //              use UDP via RedBoot's network stack. Also adds commands
52 //              to set the DNS server IP at runtime.
53 //
54 //####DESCRIPTIONEND####
55 //
56 //=============================================================================
57
58 #include <cyg/hal/drv_api.h>
59 #include <cyg/infra/cyg_type.h>
60 #include <cyg/infra/cyg_trac.h>         /* Tracing support */
61
62 #include <net/net.h>
63 #include <redboot.h>
64 /* #include <cyg/ns/dns/dns.h> - it's been moved to redboot.h */
65 #include <cyg/ns/dns/dns_priv.h>
66
67 #ifdef CYGSEM_REDBOOT_FLASH_CONFIG
68 #include <flash_config.h>
69
70 RedBoot_config_option("DNS server IP address",
71                       dns_ip,
72                       ALWAYS_ENABLED, true,
73                       CONFIG_IP,
74                       0
75     );
76
77 RedBoot_config_option("DNS domain name",
78                       dns_domain,
79                       ALWAYS_ENABLED, true,
80                       CONFIG_STRING,
81                       0
82         );
83 #endif
84
85 /* So we remember which ports have been used */
86 static int get_port = 7700;
87
88 #define DOMAIN_PORT           53
89
90 /* Some magic to make dns_impl.inl compile under RedBoot */
91 #define sprintf diag_sprintf
92
93 /* DNS server address possibly returned from bootp */
94 struct in_addr __bootp_dns_addr;
95 cyg_bool __bootp_dns_set = false;
96
97 /* DNS domain name possibly returned from bootp */
98 #ifdef CYGPKG_REDBOOT_NETWORKING_DNS_DHCP_DOMAIN
99 char __bootp_dns_domain[CYGNUM_REDBOOT_NETWORK_DNS_DOMAIN_BUFSIZE];
100 cyg_bool __bootp_dns_domain_set = false;
101 #endif
102
103 struct sockaddr_in server;
104
105 /* static buffers so we can make do without malloc */
106 static struct hostent _hent;
107 static char* _h_addr_list[2];
108 static struct in_addr _h_addr_list0;
109 static int _hent_alloc = 0;
110
111 #define _STRING_COUNT  2
112 #define _STRING_LENGTH 64
113 static char _strings[_STRING_COUNT][_STRING_LENGTH];
114 static int _strings_alloc = 0;
115
116 /* as in dns.c proper */
117 static short id = 0;              /* ID of the last query */
118 static int s = -1;                /* Socket to the DNS server */
119 static cyg_drv_mutex_t dns_mutex; /* Mutex to stop multiple queries as once */
120 static char * domainname=NULL;    /* Domain name used for queries */
121
122
123 /* Allocate space for string of length (len). Return NULL on
124    failure. */
125 static char*
126 alloc_string(int len)
127 {
128     int i;
129
130     if (len > _STRING_LENGTH)
131         return NULL;
132
133     for (i = 0; i < _STRING_COUNT; i++) {
134         if (_strings_alloc & (1 << i)) continue;
135         _strings_alloc |= (1<<i);
136         return _strings[i];
137     }
138     return NULL;
139 }
140
141 static void
142 free_string(char* s)
143 {
144     int i;
145     for (i = 0; i < _STRING_COUNT; i++) {
146         if (_strings[i] == s) {
147             _strings_alloc &= ~(1<<i);
148             break;
149         }
150     }
151 }
152
153 /* Deallocate the memory taken to hold a hent structure */
154 static void
155 free_hent(struct hostent * hent)
156 {
157     if (hent->h_name) {
158         free_string(hent->h_name);
159     }
160     _hent_alloc = 0;
161 }
162
163 /* Allocate hent structure with room for one in_addr. Returns NULL on
164    failure. */
165 static struct hostent*
166 alloc_hent(void)
167 {
168     struct hostent *hent;
169
170     if (_hent_alloc) return NULL;
171
172     hent = &_hent;
173     memset(hent, 0, sizeof(struct hostent));
174     hent->h_addr_list = _h_addr_list;
175     hent->h_addr_list[0] = (char*)&_h_addr_list0;
176     hent->h_addr_list[1] = NULL;
177     _hent_alloc = 1;
178
179     return hent;
180 }
181
182 static __inline__ void
183 free_stored_hent(void)
184 {
185     free_hent( &_hent );
186 }
187
188 static __inline__ void
189 store_hent(struct hostent *hent)
190 {
191     hent=hent; // avoid warning
192 }
193
194 /* Send the query to the server and read the response back. Return -1
195    if it fails, otherwise put the response back in msg and return the
196    length of the response. */
197 static int 
198 send_recv(char * msg, int len, int msglen)
199 {
200     struct dns_header *dns_hdr;
201     int finished = false;
202     int read = 0;
203
204     dns_hdr = (struct dns_header *) msg;
205
206     do { 
207         int len_togo = len;
208         struct timeval timeout;
209         struct sockaddr_in local_addr, from_addr;
210
211         memset((char *)&local_addr, 0, sizeof(local_addr));
212         local_addr.sin_family = AF_INET;
213         local_addr.sin_addr.s_addr = htonl(INADDR_ANY);
214         local_addr.sin_port = htons(get_port++);
215
216         if (__udp_sendto(msg, len_togo, &server, &local_addr) < 0)
217             return -1;
218
219         memset((char *)&from_addr, 0, sizeof(from_addr));
220
221         timeout.tv_sec = CYGNUM_REDBOOT_NETWORKING_DNS_TIMEOUT;
222         timeout.tv_usec = 0;
223
224         read = __udp_recvfrom(msg, len, &from_addr, &local_addr, &timeout);
225         if (read < 0)
226             return -1;
227
228         /* Reply to an old query. Ignore it */
229         if (ntohs(dns_hdr->id) != (id-1)) {
230             continue;
231         }
232         finished = true;
233     } while (!finished);
234
235     return read;
236 }
237     
238 void
239 set_dns(char* new_ip)
240 {
241     in_addr_t dns_ip;
242
243     memset(&server.sin_addr, 0, sizeof(server.sin_addr));
244     if (!inet_aton(new_ip, &dns_ip)) {
245         diag_printf("Bad DNS server address: %s\n", new_ip);
246     } else {
247         memcpy(&server.sin_addr, &dns_ip, sizeof(dns_ip));
248         /* server config is valid */
249         s = 0;
250     }
251 }
252
253 void
254 show_dns(void)
255 {
256     diag_printf("\nDNS server IP: %s, DNS domain name: %s", 
257                 inet_ntoa((in_addr_t *)&server.sin_addr),
258                 domainname);
259     if (0 == server.sin_addr.s_addr) {
260         s = -1;
261     }
262 }
263
264 /* Initialise the resolver. Open a socket and bind it to the address
265    of the server.  return -1 if something goes wrong, otherwise 0 */
266 int  
267 redboot_dns_res_init(void)
268 {
269 #ifdef CYGPKG_REDBOOT_NETWORKING_DNS_FCONFIG_DOMAIN
270   char *dns_domain = NULL;
271 #endif
272     memset((char *)&server, 0, sizeof(server));
273     server.sin_len = sizeof(server);
274     server.sin_family = AF_INET;
275     server.sin_port = htons(DOMAIN_PORT);
276     cyg_drv_mutex_init(&dns_mutex);
277
278     /* Set the default DNS domain first, so that it can be overwritten
279        latter */
280 #ifdef CYGPKG_REDBOOT_NETWORKING_DNS_DEFAULT_DOMAIN
281         setdomainname(__Xstr(CYGPKG_REDBOOT_NETWORKING_DNS_DEFAULT_DOMAIN), 
282                       strlen(__Xstr(CYGPKG_REDBOOT_NETWORKING_DNS_DEFAULT_DOMAIN)));
283 #endif
284         /* Set the domain name from flash so that DHCP can later
285            overwrite it. */
286 #ifdef CYGPKG_REDBOOT_NETWORKING_DNS_FCONFIG_DOMAIN
287         flash_get_config("dns_domain", &dns_domain, CONFIG_STRING);
288         if(dns_domain != NULL && dns_domain[0] != '\0')
289                 setdomainname(dns_domain, strlen(dns_domain));
290 #endif
291
292     /* If we got a DNS server address from the DHCP/BOOTP, then use
293        that address */
294     if ( __bootp_dns_set ) {
295         memcpy(&server.sin_addr, &__bootp_dns_addr, 
296                sizeof(__bootp_dns_addr) );
297     
298 #ifdef CYGPKG_REDBOOT_NETWORKING_DNS_DHCP_DOMAIN        
299         if(__bootp_dns_domain_set) 
300             setdomainname(__bootp_dns_domain, strlen(__bootp_dns_domain));
301 #endif
302         /* server config is valid */
303         s = 0; 
304     }
305     else {
306 #ifdef CYGSEM_REDBOOT_FLASH_CONFIG
307     {
308         ip_addr_t dns_ip;
309
310         flash_get_config("dns_ip", &dns_ip, CONFIG_IP);
311         if (dns_ip[0] == 0 && dns_ip[1] == 0 && 
312             dns_ip[2] == 0 && dns_ip[3] == 0)
313             return -1;
314         memcpy(&server.sin_addr, &dns_ip, sizeof(dns_ip));
315         /* server config is valid */
316         s = 0;
317     }
318 #else
319     // Use static configuration. If CYGPKG_REDBOOT_NETWORKING_DNS_IP
320     // is valid s will set set as a side effect.
321     set_dns(__Xstr(CYGPKG_REDBOOT_NETWORKING_DNS_IP));
322 #endif
323     }
324
325     return 0;
326 }
327
328 /* Include the DNS client implementation code */
329 #include <cyg/ns/dns/dns_impl.inl>