Magellan Linux

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 532 - (hide annotations) (download)
Sat Sep 1 22:45:15 2007 UTC (16 years, 9 months ago) by niro
File MIME type: text/plain
File size: 4737 byte(s)
-import if magellan mkinitrd; it is a fork of redhats mkinitrd-5.0.8 with all magellan patches and features; deprecates magellan-src/mkinitrd

1 niro 532 /*
2     * DHCP RFC 2131 and 2132
3     */
4     #include <sys/types.h>
5     #include <sys/uio.h>
6     #include <netinet/in.h>
7     #include <stdio.h>
8     #include <string.h>
9     #include <time.h>
10    
11     #include "ipconfig.h"
12     #include "netdev.h"
13     #include "bootp_packet.h"
14     #include "bootp_proto.h"
15     #include "dhcp_proto.h"
16     #include "packet.h"
17    
18     static uint8_t dhcp_params[] = {
19     1, /* subnet mask */
20     3, /* default gateway */
21     6, /* DNS server */
22     12, /* host name */
23     15, /* domain name */
24     17, /* root path */
25     26, /* interface mtu */
26     28, /* broadcast addr */
27     40, /* NIS domain name (why?) */
28     };
29    
30     static uint8_t dhcp_discover_hdr[] = {
31     99, 130, 83, 99, /* bootp cookie */
32     53, 1, DHCPDISCOVER, /* dhcp message type */
33     55, sizeof(dhcp_params), /* parameter list */
34     };
35    
36     static uint8_t dhcp_request_hdr[] = {
37     99, 130, 83, 99, /* boot cookie */
38     53, 1, DHCPREQUEST, /* dhcp message type */
39     #define SERVER_IP_OFF 9
40     54, 4, 0, 0, 0, 0, /* server IP */
41     #define REQ_IP_OFF 15
42     50, 4, 0, 0, 0, 0, /* requested IP address */
43     55, sizeof(dhcp_params), /* parameter list */
44     };
45    
46     static uint8_t dhcp_end[] = {
47     255,
48     };
49    
50     /* Both iovecs below have to have the same structure, since dhcp_send()
51     pokes at the internals */
52     #define DHCP_IOV_LEN 6
53    
54     static struct iovec dhcp_discover_iov[] = {
55     /* [0] = ip + udp header */
56     /* [1] = bootp header */
57     [2] = {dhcp_discover_hdr, sizeof(dhcp_discover_hdr)},
58     [3] = {dhcp_params, sizeof(dhcp_params)},
59     /* [4] = DHCP vendor class */
60     [5] = {dhcp_end, sizeof(dhcp_end)}
61     };
62    
63     static struct iovec dhcp_request_iov[] = {
64     /* [0] = ip + udp header */
65     /* [1] = bootp header */
66     [2] = {dhcp_request_hdr, sizeof(dhcp_request_hdr)},
67     [3] = {dhcp_params, sizeof(dhcp_params)},
68     /* [4] = DHCP vendor class */
69     [5] = {dhcp_end, sizeof(dhcp_end)}
70     };
71    
72     /*
73     * Parse a DHCP response packet
74     */
75     static int
76     dhcp_parse(struct netdev *dev, struct bootp_hdr *hdr, uint8_t * exts, int extlen)
77     {
78     uint8_t type = 0;
79     uint32_t serverid = INADDR_NONE;
80     int ret = 0;
81    
82     if (extlen >= 4 && exts[0] == 99 && exts[1] == 130 &&
83     exts[2] == 83 && exts[3] == 99) {
84     uint8_t *ext;
85    
86     for (ext = exts + 4; ext - exts < extlen;) {
87     uint8_t len, *opt = ext++;
88     if (*opt == 0)
89     continue;
90    
91     len = *ext++;
92    
93     ext += len;
94    
95     if (*opt == 53)
96     type = opt[2];
97     if (*opt == 54)
98     memcpy(&serverid, opt + 2, 4);
99     }
100     }
101    
102     switch (type) {
103     case DHCPOFFER:
104     ret = bootp_parse(dev, hdr, exts, extlen);
105     if (ret == 1 && serverid != INADDR_NONE)
106     dev->serverid = serverid;
107     DEBUG(("\n dhcp offer\n"));
108     break;
109    
110     case DHCPACK:
111     ret = bootp_parse(dev, hdr, exts, extlen);
112     DEBUG(("\n dhcp ack\n"));
113     break;
114    
115     case DHCPNAK:
116     ret = 2;
117     DEBUG(("\n dhcp nak\n"));
118     break;
119     }
120     return ret;
121     }
122    
123     /*
124     * Receive and parse a DHCP packet
125     */
126     static int dhcp_recv(struct netdev *dev)
127     {
128     struct bootp_hdr bootp;
129     uint8_t dhcp_options[1500];
130     struct iovec iov[] = {
131     /* [0] = ip + udp header */
132     [1] = {&bootp, sizeof(struct bootp_hdr)},
133     [2] = {dhcp_options, sizeof(dhcp_options)}
134     };
135     int ret;
136    
137     ret = packet_recv(iov, 3);
138     if (ret <= 0)
139     return ret;
140    
141     DEBUG(("\n dhcp xid %08x ", dev->bootp.xid));
142    
143     if (ret < sizeof(struct bootp_hdr) || bootp.op != BOOTP_REPLY || /* RFC951 7.5 */
144     bootp.xid != dev->bootp.xid ||
145     memcmp(bootp.chaddr, dev->hwaddr, 16))
146     return 0;
147    
148     ret -= sizeof(struct bootp_hdr);
149    
150     return dhcp_parse(dev, &bootp, dhcp_options, ret);
151     }
152    
153     static int dhcp_send(struct netdev *dev, struct iovec *vec)
154     {
155     struct bootp_hdr bootp;
156    
157     memset(&bootp, 0, sizeof(struct bootp_hdr));
158    
159     bootp.op = BOOTP_REQUEST;
160     bootp.htype = dev->hwtype;
161     bootp.hlen = dev->hwlen;
162     bootp.xid = dev->bootp.xid;
163     bootp.ciaddr = dev->ip_addr;
164     bootp.giaddr = dev->bootp.gateway;
165     bootp.secs = htons(time(NULL) - dev->open_time);
166     memcpy(bootp.chaddr, dev->hwaddr, 16);
167    
168     vec[1].iov_base = &bootp;
169     vec[1].iov_len = sizeof(struct bootp_hdr);
170    
171     vec[4].iov_base = vendor_class_identifier;
172     vec[4].iov_len = vendor_class_identifier_len;
173    
174     DEBUG(("xid %08x secs %d ", bootp.xid, ntohs(bootp.secs)));
175    
176     return packet_send(dev, vec, DHCP_IOV_LEN);
177     }
178    
179     /*
180     * Send a DHCP discover packet
181     */
182     int dhcp_send_discover(struct netdev *dev)
183     {
184     dev->ip_addr = INADDR_ANY;
185     dev->ip_gateway = INADDR_ANY;
186    
187     DEBUG(("-> dhcp discover "));
188    
189     return dhcp_send(dev, dhcp_discover_iov);
190     }
191    
192     /*
193     * Receive a DHCP offer packet
194     */
195     int dhcp_recv_offer(struct netdev *dev)
196     {
197     return dhcp_recv(dev);
198     }
199    
200     /*
201     * Send a DHCP request packet
202     */
203     int dhcp_send_request(struct netdev *dev)
204     {
205     memcpy(&dhcp_request_hdr[SERVER_IP_OFF], &dev->serverid, 4);
206     memcpy(&dhcp_request_hdr[REQ_IP_OFF], &dev->ip_addr, 4);
207    
208     DEBUG(("-> dhcp request "));
209    
210     return dhcp_send(dev, dhcp_request_iov);
211     }
212    
213     /*
214     * Receive a DHCP ack packet
215     */
216     int dhcp_recv_ack(struct netdev *dev)
217     {
218     return dhcp_recv(dev);
219     }