Blame view

net/dns.c 4.8 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
   * 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>
9fb625ce0   Simon Glass   env: Move env_set...
27
  #include <env.h>
1a32bf418   Robin Getz   Add DNS support
28
  #include <net.h>
6dc809f40   Bernhard Kaindl   net/dns.c: Fix en...
29
  #include <asm/unaligned.h>
1a32bf418   Robin Getz   Add DNS support
30
31
  
  #include "dns.h"
786eac5f9   Joe Hershberger   net: cosmetic: Cl...
32
33
  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
34

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

786eac5f9   Joe Hershberger   net: cosmetic: Cl...
37
  static void dns_send(void)
1a32bf418   Robin Getz   Add DNS support
38
39
40
41
42
43
44
  {
  	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...
45
  	name = net_dns_resolve;
1203fccee   Joe Hershberger   net: cosmetic: Cl...
46
47
  	pkt = (uchar *)(net_tx_packet + net_eth_hdr_size() + IP_UDP_HDR_SIZE);
  	p = pkt;
1a32bf418   Robin Getz   Add DNS support
48
49
  
  	/* Prepare DNS packet header */
786eac5f9   Joe Hershberger   net: cosmetic: Cl...
50
  	header           = (struct header *)pkt;
1a32bf418   Robin Getz   Add DNS support
51
52
53
54
55
56
57
58
59
  	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...
60
  	p = (uchar *)&header->data;	/* For encoding host name into packet */
1a32bf418   Robin Getz   Add DNS support
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
88
  
  	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...
89
  	dns_our_port = random_port();
1a32bf418   Robin Getz   Add DNS support
90

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

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

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

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