Blame view

net/dns.c 4.79 KB
1a32bf418   Robin Getz   Add DNS support
1
2
3
4
5
6
7
  /*
   * DNS support driver
   *
   * Copyright (c) 2008 Pieter Voorthuijsen <pieter.voorthuijsen@prodrive.nl>
   * Copyright (c) 2009 Robin Getz <rgetz@blackfin.uclinux.org>
   *
   * This is a simple DNS implementation for U-Boot. It will use the first IP
049a95a77   Joe Hershberger   net: cosmetic: Ch...
8
   * in the DNS response as net_server_ip. This can then be used for any other
1a32bf418   Robin Getz   Add DNS support
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
   * network related activities.
   *
   * The packet handling is partly based on TADNS, original copyrights
   * follow below.
   *
   */
  
  /*
   * Copyright (c) 2004-2005 Sergey Lyubka <valenok@gmail.com>
   *
   * "THE BEER-WARE LICENSE" (Revision 42):
   * Sergey Lyubka wrote this file.  As long as you retain this notice you
   * can do whatever you want with this stuff. If we meet some day, and you think
   * this stuff is worth it, you can buy me a beer in return.
   */
  
  #include <common.h>
  #include <command.h>
  #include <net.h>
6dc809f40   Bernhard Kaindl   net/dns.c: Fix en...
28
  #include <asm/unaligned.h>
1a32bf418   Robin Getz   Add DNS support
29
30
  
  #include "dns.h"
786eac5f9   Joe Hershberger   net: cosmetic: Cl...
31
32
  char *net_dns_resolve;	/* The host to resolve  */
  char *net_dns_env_var;	/* The envvar to store the answer in */
1a32bf418   Robin Getz   Add DNS support
33

786eac5f9   Joe Hershberger   net: cosmetic: Cl...
34
  static int dns_our_port;
1a32bf418   Robin Getz   Add DNS support
35

786eac5f9   Joe Hershberger   net: cosmetic: Cl...
36
  static void dns_send(void)
1a32bf418   Robin Getz   Add DNS support
37
38
39
40
41
42
43
  {
  	struct header *header;
  	int n, name_len;
  	uchar *p, *pkt;
  	const char *s;
  	const char *name;
  	enum dns_query_type qtype = DNS_A_RECORD;
786eac5f9   Joe Hershberger   net: cosmetic: Cl...
44
  	name = net_dns_resolve;
1203fccee   Joe Hershberger   net: cosmetic: Cl...
45
46
  	pkt = (uchar *)(net_tx_packet + net_eth_hdr_size() + IP_UDP_HDR_SIZE);
  	p = pkt;
1a32bf418   Robin Getz   Add DNS support
47
48
  
  	/* Prepare DNS packet header */
786eac5f9   Joe Hershberger   net: cosmetic: Cl...
49
  	header           = (struct header *)pkt;
1a32bf418   Robin Getz   Add DNS support
50
51
52
53
54
55
56
57
58
  	header->tid      = 1;
  	header->flags    = htons(0x100);	/* standard query */
  	header->nqueries = htons(1);		/* Just one query */
  	header->nanswers = 0;
  	header->nauth    = 0;
  	header->nother   = 0;
  
  	/* Encode DNS name */
  	name_len = strlen(name);
786eac5f9   Joe Hershberger   net: cosmetic: Cl...
59
  	p = (uchar *)&header->data;	/* For encoding host name into packet */
1a32bf418   Robin Getz   Add DNS support
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
  
  	do {
  		s = strchr(name, '.');
  		if (!s)
  			s = name + name_len;
  
  		n = s - name;			/* Chunk length */
  		*p++ = n;			/* Copy length  */
  		memcpy(p, name, n);		/* Copy chunk   */
  		p += n;
  
  		if (*s == '.')
  			n++;
  
  		name += n;
  		name_len -= n;
  	} while (*s != '\0');
  
  	*p++ = 0;			/* Mark end of host name */
  	*p++ = 0;			/* Some servers require double null */
  	*p++ = (unsigned char) qtype;	/* Query Type */
  
  	*p++ = 0;
  	*p++ = 1;				/* Class: inet, 0x0001 */
  
  	n = p - pkt;				/* Total packet length */
  	debug("Packet size %d
  ", n);
786eac5f9   Joe Hershberger   net: cosmetic: Cl...
88
  	dns_our_port = random_port();
1a32bf418   Robin Getz   Add DNS support
89

1203fccee   Joe Hershberger   net: cosmetic: Cl...
90
  	net_send_udp_packet(net_server_ethaddr, net_dns_server,
786eac5f9   Joe Hershberger   net: cosmetic: Cl...
91
  			    DNS_SERVICE_PORT, dns_our_port, n);
1a32bf418   Robin Getz   Add DNS support
92
93
94
  	debug("DNS packet sent
  ");
  }
786eac5f9   Joe Hershberger   net: cosmetic: Cl...
95
  static void dns_timeout_handler(void)
1a32bf418   Robin Getz   Add DNS support
96
97
98
  {
  	puts("Timeout
  ");
22f6e99d5   Joe Hershberger   net: Refactor to ...
99
  	net_set_state(NETLOOP_FAIL);
1a32bf418   Robin Getz   Add DNS support
100
  }
049a95a77   Joe Hershberger   net: cosmetic: Ch...
101
102
  static void dns_handler(uchar *pkt, unsigned dest, struct in_addr sip,
  			unsigned src, unsigned len)
1a32bf418   Robin Getz   Add DNS support
103
104
105
106
107
  {
  	struct header *header;
  	const unsigned char *p, *e, *s;
  	u16 type, i;
  	int found, stop, dlen;
786eac5f9   Joe Hershberger   net: cosmetic: Cl...
108
  	char ip_str[22];
049a95a77   Joe Hershberger   net: cosmetic: Ch...
109
  	struct in_addr ip_addr;
1a32bf418   Robin Getz   Add DNS support
110
111
112
113
  
  
  	debug("%s
  ", __func__);
786eac5f9   Joe Hershberger   net: cosmetic: Cl...
114
  	if (dest != dns_our_port)
1a32bf418   Robin Getz   Add DNS support
115
116
117
118
119
  		return;
  
  	for (i = 0; i < len; i += 4)
  		debug("0x%p - 0x%.2x  0x%.2x  0x%.2x  0x%.2x
  ",
786eac5f9   Joe Hershberger   net: cosmetic: Cl...
120
  		      pkt+i, pkt[i], pkt[i+1], pkt[i+2], pkt[i+3]);
1a32bf418   Robin Getz   Add DNS support
121

6dc809f40   Bernhard Kaindl   net/dns.c: Fix en...
122
  	/* We sent one query. We want to have a single answer: */
786eac5f9   Joe Hershberger   net: cosmetic: Cl...
123
  	header = (struct header *)pkt;
1a32bf418   Robin Getz   Add DNS support
124
125
126
127
128
  	if (ntohs(header->nqueries) != 1)
  		return;
  
  	/* Received 0 answers */
  	if (header->nanswers == 0) {
6dc809f40   Bernhard Kaindl   net/dns.c: Fix en...
129
130
  		puts("DNS: host not found
  ");
22f6e99d5   Joe Hershberger   net: Refactor to ...
131
  		net_set_state(NETLOOP_SUCCESS);
1a32bf418   Robin Getz   Add DNS support
132
133
134
135
136
137
138
139
140
141
  		return;
  	}
  
  	/* Skip host name */
  	s = &header->data[0];
  	e = pkt + len;
  	for (p = s; p < e && *p != '\0'; p++)
  		continue;
  
  	/* We sent query class 1, query type 1 */
6dc809f40   Bernhard Kaindl   net/dns.c: Fix en...
142
143
144
  	if (&p[5] > e || get_unaligned_be16(p+1) != DNS_A_RECORD) {
  		puts("DNS: response was not an A record
  ");
22f6e99d5   Joe Hershberger   net: Refactor to ...
145
  		net_set_state(NETLOOP_SUCCESS);
1a32bf418   Robin Getz   Add DNS support
146
147
148
149
150
151
152
153
  		return;
  	}
  
  	/* Go to the first answer section */
  	p += 5;
  
  	/* Loop through the answers, we want A type answer */
  	for (found = stop = 0; !stop && &p[12] < e; ) {
1a32bf418   Robin Getz   Add DNS support
154
155
156
157
158
159
160
161
  		/* Skip possible name in CNAME answer */
  		if (*p != 0xc0) {
  			while (*p && &p[12] < e)
  				p++;
  			p--;
  		}
  		debug("Name (Offset in header): %d
  ", p[1]);
6dc809f40   Bernhard Kaindl   net/dns.c: Fix en...
162
  		type = get_unaligned_be16(p+2);
1a32bf418   Robin Getz   Add DNS support
163
164
165
166
167
168
  		debug("type = %d
  ", type);
  		if (type == DNS_CNAME_RECORD) {
  			/* CNAME answer. shift to the next section */
  			debug("Found canonical name
  ");
6dc809f40   Bernhard Kaindl   net/dns.c: Fix en...
169
  			dlen = get_unaligned_be16(p+10);
1a32bf418   Robin Getz   Add DNS support
170
171
172
173
174
175
  			debug("dlen = %d
  ", dlen);
  			p += 12 + dlen;
  		} else if (type == DNS_A_RECORD) {
  			debug("Found A-record
  ");
786eac5f9   Joe Hershberger   net: cosmetic: Cl...
176
177
  			found = 1;
  			stop = 1;
1a32bf418   Robin Getz   Add DNS support
178
179
180
181
182
183
184
185
  		} else {
  			debug("Unknown type
  ");
  			stop = 1;
  		}
  	}
  
  	if (found && &p[12] < e) {
6dc809f40   Bernhard Kaindl   net/dns.c: Fix en...
186
  		dlen = get_unaligned_be16(p+10);
1a32bf418   Robin Getz   Add DNS support
187
  		p += 12;
049a95a77   Joe Hershberger   net: cosmetic: Ch...
188
  		memcpy(&ip_addr, p, 4);
1a32bf418   Robin Getz   Add DNS support
189
190
  
  		if (p + dlen <= e) {
786eac5f9   Joe Hershberger   net: cosmetic: Cl...
191
192
193
194
  			ip_to_string(ip_addr, ip_str);
  			printf("%s
  ", ip_str);
  			if (net_dns_env_var)
382bee57f   Simon Glass   env: Rename seten...
195
  				env_set(net_dns_env_var, ip_str);
786eac5f9   Joe Hershberger   net: cosmetic: Cl...
196
  		} else {
1a32bf418   Robin Getz   Add DNS support
197
198
  			puts("server responded with invalid IP number
  ");
786eac5f9   Joe Hershberger   net: cosmetic: Cl...
199
  		}
1a32bf418   Robin Getz   Add DNS support
200
  	}
22f6e99d5   Joe Hershberger   net: Refactor to ...
201
  	net_set_state(NETLOOP_SUCCESS);
1a32bf418   Robin Getz   Add DNS support
202
  }
786eac5f9   Joe Hershberger   net: cosmetic: Cl...
203
  void dns_start(void)
1a32bf418   Robin Getz   Add DNS support
204
205
206
  {
  	debug("%s
  ", __func__);
bc0571fc1   Joe Hershberger   net: cosmetic: Fi...
207
  	net_set_timeout_handler(DNS_TIMEOUT, dns_timeout_handler);
049a95a77   Joe Hershberger   net: cosmetic: Ch...
208
  	net_set_udp_handler(dns_handler);
1a32bf418   Robin Getz   Add DNS support
209

f395e75e2   Gerhard Sittig   net: dns: fix for...
210
  	/* Clear a previous MAC address, the server IP might have changed. */
0adb5b761   Joe Hershberger   net: cosmetic: Na...
211
  	memset(net_server_ethaddr, 0, sizeof(net_server_ethaddr));
f395e75e2   Gerhard Sittig   net: dns: fix for...
212

786eac5f9   Joe Hershberger   net: cosmetic: Cl...
213
  	dns_send();
1a32bf418   Robin Getz   Add DNS support
214
  }