Magellan Linux

Annotation of /trunk/mkinitrd-magellan/klibc/usr/kinit/ipconfig/bootp_proto.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1122 - (hide annotations) (download)
Wed Aug 18 21:11:40 2010 UTC (13 years, 9 months ago) by niro
File MIME type: text/plain
File size: 4996 byte(s)
-updated to klibc-1.5.19
1 niro 532 /*
2     * BOOTP packet protocol handling.
3     */
4     #include <sys/types.h>
5     #include <sys/uio.h>
6     #include <stdio.h>
7     #include <stdlib.h>
8     #include <string.h>
9     #include <time.h>
10     #include <unistd.h>
11     #include <netinet/in.h>
12    
13     #include "ipconfig.h"
14     #include "netdev.h"
15     #include "bootp_packet.h"
16     #include "bootp_proto.h"
17     #include "packet.h"
18    
19     static uint8_t bootp_options[312] = {
20     [ 0] = 99, 130, 83, 99,/* RFC1048 magic cookie */
21     [ 4] = 1, 4, /* 4- 9 subnet mask */
22     [ 10] = 3, 4, /* 10- 15 default gateway */
23     [ 16] = 5, 8, /* 16- 25 nameserver */
24     [ 26] = 12, 32, /* 26- 59 host name */
25     [ 60] = 40, 32, /* 60- 95 nis domain name */
26     [ 96] = 17, 40, /* 96-137 boot path */
27     [138] = 57, 2, 1, 150, /* 138-141 extension buffer */
28     [142] = 255, /* end of list */
29     };
30    
31     /*
32     * Send a plain bootp request packet with options
33     */
34     int bootp_send_request(struct netdev *dev)
35     {
36     struct bootp_hdr bootp;
37     struct iovec iov[] = {
38     /* [0] = ip + udp headers */
39     [1] = {&bootp, sizeof(bootp)},
40     [2] = {bootp_options, 312}
41     };
42    
43     memset(&bootp, 0, sizeof(struct bootp_hdr));
44    
45     bootp.op = BOOTP_REQUEST, bootp.htype = dev->hwtype;
46     bootp.hlen = dev->hwlen;
47     bootp.xid = dev->bootp.xid;
48     bootp.ciaddr = dev->ip_addr;
49     bootp.secs = htons(time(NULL) - dev->open_time);
50     memcpy(bootp.chaddr, dev->hwaddr, 16);
51    
52 niro 1122 dprintf("-> bootp xid 0x%08x secs 0x%08x ",
53     bootp.xid, ntohs(bootp.secs));
54 niro 532
55     return packet_send(dev, iov, 2);
56     }
57    
58     /*
59     * Parse a bootp reply packet
60     */
61     int bootp_parse(struct netdev *dev, struct bootp_hdr *hdr,
62     uint8_t *exts, int extlen)
63     {
64     dev->bootp.gateway = hdr->giaddr;
65     dev->ip_addr = hdr->yiaddr;
66     dev->ip_server = hdr->siaddr;
67     dev->ip_netmask = INADDR_ANY;
68     dev->ip_broadcast = INADDR_ANY;
69     dev->ip_gateway = hdr->giaddr;
70     dev->ip_nameserver[0] = INADDR_ANY;
71     dev->ip_nameserver[1] = INADDR_ANY;
72     dev->hostname[0] = '\0';
73     dev->nisdomainname[0] = '\0';
74     dev->bootpath[0] = '\0';
75     memcpy(&dev->filename, &hdr->boot_file, FNLEN);
76    
77     if (extlen >= 4 && exts[0] == 99 && exts[1] == 130 &&
78     exts[2] == 83 && exts[3] == 99) {
79     uint8_t *ext;
80    
81     for (ext = exts + 4; ext - exts < extlen;) {
82     int len;
83     uint8_t opt = *ext++;
84    
85     if (opt == 0)
86     continue;
87     else if (opt == 255)
88     break;
89    
90     len = *ext++;
91    
92     switch (opt) {
93     case 1: /* subnet mask */
94     if (len == 4)
95     memcpy(&dev->ip_netmask, ext, 4);
96     break;
97     case 3: /* default gateway */
98     if (len >= 4)
99     memcpy(&dev->ip_gateway, ext, 4);
100     break;
101     case 6: /* DNS server */
102     if (len >= 4)
103     memcpy(&dev->ip_nameserver, ext,
104     len >= 8 ? 8 : 4);
105     break;
106     case 12: /* host name */
107     if (len > sizeof(dev->hostname) - 1)
108     len = sizeof(dev->hostname) - 1;
109     memcpy(&dev->hostname, ext, len);
110     dev->hostname[len] = '\0';
111     break;
112     case 15: /* domain name */
113     if (len > sizeof(dev->dnsdomainname) - 1)
114     len = sizeof(dev->dnsdomainname) - 1;
115     memcpy(&dev->dnsdomainname, ext, len);
116     dev->dnsdomainname[len] = '\0';
117     break;
118     case 17: /* root path */
119     if (len > sizeof(dev->bootpath) - 1)
120     len = sizeof(dev->bootpath) - 1;
121     memcpy(&dev->bootpath, ext, len);
122     dev->bootpath[len] = '\0';
123     break;
124     case 26: /* interface MTU */
125     if (len == 2)
126     dev->mtu = (ext[0] << 8) + ext[1];
127     break;
128     case 28: /* broadcast addr */
129     if (len == 4)
130     memcpy(&dev->ip_broadcast, ext, 4);
131     break;
132     case 40: /* NIS domain name */
133     if (len > sizeof(dev->nisdomainname) - 1)
134     len = sizeof(dev->nisdomainname) - 1;
135     memcpy(&dev->nisdomainname, ext, len);
136     dev->nisdomainname[len] = '\0';
137     break;
138 niro 815 case 54: /* server identifier */
139 niro 532 if (len == 4 && !dev->ip_server)
140     memcpy(&dev->ip_server, ext, 4);
141     break;
142     }
143    
144     ext += len;
145     }
146     }
147    
148     /*
149     * Got packet.
150     */
151     return 1;
152     }
153    
154     /*
155     * Receive a bootp reply and parse packet
156 niro 1122 * Returns:
157     *-1 = Error in packet_recv, try again later
158     * 0 = Unexpected packet, discarded
159     * 1 = Correctly received and parsed packet
160 niro 532 */
161     int bootp_recv_reply(struct netdev *dev)
162     {
163     struct bootp_hdr bootp;
164     uint8_t bootp_options[312];
165     struct iovec iov[] = {
166     /* [0] = ip + udp headers */
167     [1] = {&bootp, sizeof(struct bootp_hdr)},
168     [2] = {bootp_options, 312}
169     };
170     int ret;
171    
172     ret = packet_recv(iov, 3);
173     if (ret <= 0)
174 niro 1122 return -1;
175 niro 532
176     if (ret < sizeof(struct bootp_hdr) ||
177     bootp.op != BOOTP_REPLY || /* RFC951 7.5 */
178     bootp.xid != dev->bootp.xid ||
179     memcmp(bootp.chaddr, dev->hwaddr, 16))
180     return 0;
181    
182     ret -= sizeof(struct bootp_hdr);
183    
184     return bootp_parse(dev, &bootp, bootp_options, ret);
185     }
186    
187     /*
188     * Initialise interface for bootp.
189     */
190     int bootp_init_if(struct netdev *dev)
191     {
192     short flags;
193    
194     /*
195     * Get the device flags
196     */
197     if (netdev_getflags(dev, &flags))
198     return -1;
199    
200     /*
201     * We can't do DHCP nor BOOTP if this device
202     * doesn't support broadcast.
203     */
204     if (dev->mtu < 364 || (flags & IFF_BROADCAST) == 0) {
205     dev->caps &= ~(CAP_BOOTP | CAP_DHCP);
206     return 0;
207     }
208    
209     /*
210     * Get a random XID
211     */
212     dev->bootp.xid = (uint32_t) lrand48();
213     dev->open_time = time(NULL);
214    
215     return 0;
216     }