]> git.karo-electronics.de Git - karo-tx-redboot.git/blob - packages/redboot/v2_0/src/net/dns.c
c6cf392fbe3d29943cd8b44a301f19ed6e0c9881
[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 #endif
77
78 /* So we remember which ports have been used */
79 static int get_port = 7700;
80
81 #define DOMAIN_PORT           53
82
83 /* Some magic to make dns_impl.inl compile under RedBoot */
84 #define sprintf diag_sprintf
85
86 /* DNS server address possibly returned from bootp */
87 struct in_addr __bootp_dns_addr;
88 cyg_bool __bootp_dns_set = false;
89
90 struct sockaddr_in server;
91
92 /* static buffers so we can make do without malloc */
93 static struct hostent _hent;
94 static char* _h_addr_list[2];
95 static struct in_addr _h_addr_list0;
96 static int _hent_alloc = 0;
97
98 #define _STRING_COUNT  2
99 #define _STRING_LENGTH 64
100 static char _strings[_STRING_COUNT][_STRING_LENGTH];
101 static int _strings_alloc = 0;
102
103 /* as in dns.c proper */
104 static short id = 0;              /* ID of the last query */
105 static int s = -1;                /* Socket to the DNS server */
106 static cyg_drv_mutex_t dns_mutex; /* Mutex to stop multiple queries as once */
107 static char * domainname=NULL;    /* Domain name used for queries */
108
109
110 /* Allocate space for string of length (len). Return NULL on
111    failure. */
112 static char*
113 alloc_string(int len)
114 {
115     int i;
116
117     if (len > _STRING_LENGTH)
118         return NULL;
119
120     for (i = 0; i < _STRING_COUNT; i++) {
121         if (_strings_alloc & (1 << i)) continue;
122         _strings_alloc |= (1<<i);
123         return _strings[i];
124     }
125     return NULL;
126 }
127
128 static void
129 free_string(char* s)
130 {
131     int i;
132     for (i = 0; i < _STRING_COUNT; i++) {
133         if (_strings[i] == s) {
134             _strings_alloc &= ~(1<<i);
135             break;
136         }
137     }
138 }
139
140 /* Deallocate the memory taken to hold a hent structure */
141 static void
142 free_hent(struct hostent * hent)
143 {
144     if (hent->h_name) {
145         free_string(hent->h_name);
146     }
147     _hent_alloc = 0;
148 }
149
150 /* Allocate hent structure with room for one in_addr. Returns NULL on
151    failure. */
152 static struct hostent*
153 alloc_hent(void)
154 {
155     struct hostent *hent;
156
157     if (_hent_alloc) return NULL;
158
159     hent = &_hent;
160     memset(hent, 0, sizeof(struct hostent));
161     hent->h_addr_list = _h_addr_list;
162     hent->h_addr_list[0] = (char*)&_h_addr_list0;
163     hent->h_addr_list[1] = NULL;
164     _hent_alloc = 1;
165
166     return hent;
167 }
168
169 static __inline__ void
170 free_stored_hent(void)
171 {
172     free_hent( &_hent );
173 }
174
175 static __inline__ void
176 store_hent(struct hostent *hent)
177 {
178     hent=hent; // avoid warning
179 }
180
181 /* Send the query to the server and read the response back. Return -1
182    if it fails, otherwise put the response back in msg and return the
183    length of the response. */
184 static int 
185 send_recv(char * msg, int len, int msglen)
186 {
187     struct dns_header *dns_hdr;
188     int finished = false;
189     int read = 0;
190
191     dns_hdr = (struct dns_header *) msg;
192
193     do { 
194         int len_togo = len;
195         struct timeval timeout;
196         struct sockaddr_in local_addr, from_addr;
197
198         memset((char *)&local_addr, 0, sizeof(local_addr));
199         local_addr.sin_family = AF_INET;
200         local_addr.sin_addr.s_addr = htonl(INADDR_ANY);
201         local_addr.sin_port = htons(get_port++);
202
203         if (__udp_sendto(msg, len_togo, &server, &local_addr) < 0)
204             return -1;
205
206         memset((char *)&from_addr, 0, sizeof(from_addr));
207
208         timeout.tv_sec = CYGNUM_REDBOOT_NETWORKING_DNS_TIMEOUT;
209         timeout.tv_usec = 0;
210
211         read = __udp_recvfrom(msg, len, &from_addr, &local_addr, &timeout);
212         if (read < 0)
213             return -1;
214
215         /* Reply to an old query. Ignore it */
216         if (ntohs(dns_hdr->id) != (id-1)) {
217             continue;
218         }
219         finished = true;
220     } while (!finished);
221
222     return read;
223 }
224     
225 void
226 set_dns(char* new_ip)
227 {
228     in_addr_t dns_ip;
229
230     memset(&server.sin_addr, 0, sizeof(server.sin_addr));
231     if (!inet_aton(new_ip, &dns_ip)) {
232         diag_printf("Bad DNS server address: %s\n", new_ip);
233     } else {
234         memcpy(&server.sin_addr, &dns_ip, sizeof(dns_ip));
235         /* server config is valid */
236         s = 0;
237     }
238 }
239
240 void
241 show_dns(void)
242 {
243     diag_printf(", DNS server IP: %s", inet_ntoa((in_addr_t *)&server.sin_addr));
244     if (0 == server.sin_addr.s_addr) {
245         s = -1;
246     }
247 }
248
249 /* Initialise the resolver. Open a socket and bind it to the address
250    of the server.  return -1 if something goes wrong, otherwise 0 */
251 int  
252 redboot_dns_res_init(void)
253 {
254     memset((char *)&server, 0, sizeof(server));
255     server.sin_len = sizeof(server);
256     server.sin_family = AF_INET;
257     server.sin_port = htons(DOMAIN_PORT);
258     cyg_drv_mutex_init(&dns_mutex);
259
260     /* If we got a DNS server address from the DHCP/BOOTP, then use that address */
261     if ( __bootp_dns_set ) {
262         memcpy(&server.sin_addr, &__bootp_dns_addr, sizeof(__bootp_dns_addr) );
263         s = 0;
264     }
265     else {
266 #ifdef CYGSEM_REDBOOT_FLASH_CONFIG
267     {
268         ip_addr_t dns_ip;
269
270         flash_get_config("dns_ip", &dns_ip, CONFIG_IP);
271         if (dns_ip[0] == 0 && dns_ip[1] == 0 && dns_ip[2] == 0 && dns_ip[3] == 0)
272             return -1;
273         memcpy(&server.sin_addr, &dns_ip, sizeof(dns_ip));
274         /* server config is valid */
275         s = 0;
276     }
277 #else
278       // Use static configuration
279         set_dns(__Xstr(CYGPKG_REDBOOT_NETWORKING_DNS_IP));
280 #endif
281     }
282
283     return 0;
284 }
285
286 /* Include the DNS client implementation code */
287 #include <cyg/ns/dns/dns_impl.inl>