ad071db7f755fa86a3f6f48819a44a766839ef24
[tpg/acess2.git] / Usermode / Applications / dhcpclient_src / main.c
1 /*
2  */
3 #include <unistd.h>
4 #include <stdint.h>
5 #include <stdio.h>
6 #include <string.h>
7 #include <net.h>
8
9 // --- Translation functions ---
10 static inline uint32_t htonl(uint32_t v)
11 {
12         return    (((v >> 24) & 0xFF) <<  0)
13                 | (((v >> 16) & 0xFF) <<  8)
14                 | (((v >>  8) & 0xFF) << 16)
15                 | (((v >>  0) & 0xFF) << 24);
16 }
17 static inline uint16_t htons(uint16_t v)
18 {
19         return    (((v >> 8) & 0xFF) <<  0)
20                 | (((v >> 0) & 0xFF) <<  8);
21 }
22 #define htonb(v)        v
23 #define ntohl(v)        htonl(v)
24
25 // === CONSTANTS ===
26 enum eStates
27 {
28         STATE_PREINIT,
29         STATE_DISCOVER_SENT,
30         STATE_REQUEST_SENT,
31         STATE_COMPLETE
32 };
33
34 // === STRUCTURES ===
35 #define DHCP_MAGIC      0x63825363
36 struct sDHCP_Message
37 {
38         uint8_t op;
39         uint8_t htype;  // 1 = Ethernet
40         uint8_t hlen;   // 6 bytes for MAC
41         uint8_t hops;   // Hop counting
42         uint32_t        xid;
43         uint16_t        secs;
44         uint16_t        flags;
45         uint32_t        ciaddr;
46         uint32_t        yiaddr;
47         uint32_t        siaddr;
48         uint32_t        giaddr;
49         uint8_t chaddr[16];
50         uint8_t sname[64];
51         uint8_t file[128];
52         uint32_t        dhcp_magic;     // 0x63 0x82 0x53 0x63
53         uint8_t options[];
54 };
55
56 typedef struct sInterface
57 {
58         const char      *Adapter;
59          int    State;
60          int    Num;
61          int    SocketFD;
62          int    IfaceFD;
63 } tInterface;
64
65 // === PROTOTYPES ===
66 int     main(int argc, char *argv[]);
67 int     Start_Interface(tInterface *Iface);
68 void    Send_DHCPDISCOVER(tInterface *Iface);
69 void    Send_DHCPREQUEST(tInterface *Iface, void *OfferBuffer, int TypeOffset);
70 void    Handle_Packet(tInterface *Iface);
71 void    SetAddress(tInterface *Iface, void *Addr, void *Mask, void *Router);
72
73 // === CODE ===
74 int main(int argc, char *argv[])
75 {
76         tInterface      iface;
77
78         if( argc != 2 ) {
79                 fprintf(stderr, "Usage: %s <interface>\n", argv[0]);
80                 return -1;
81         }       
82
83         iface.State = STATE_PREINIT;
84         iface.Adapter = argv[1];
85
86         if( Start_Interface(&iface) < 0 ) {
87                 return -1;
88         }
89         
90         // Send request
91         Send_DHCPDISCOVER(&iface);
92
93         for( ;; ) 
94         {
95                  int    maxfd;
96                 fd_set  fds;
97         
98                 maxfd = 0;
99                 FD_ZERO(&fds);
100                 FD_SET(iface.SocketFD, &fds);   if(maxfd < iface.SocketFD) maxfd = iface.SocketFD;
101                 if( select(maxfd+1, &fds, NULL, NULL, NULL) < 0 )
102                 {
103                         // TODO: Check error result
104                         return -1;
105                 }
106
107                 _SysDebug("select returned");   
108         
109                 if( FD_ISSET(iface.SocketFD, &fds) )
110                 {
111                         // TODO: Catch response
112                         Handle_Packet( &iface );
113                         
114                 }
115         }
116         return 0;
117 }
118
119 // RETURN: Client FD
120 int Start_Interface(tInterface *Iface)
121 {
122          int    fd, tmp;
123         char    path[] = "/Devices/ip/XXXXX/udpc";
124         char    addr[4] = {0,0,0,0};
125         
126         // TODO: Check that the adapter is not in use
127         
128         // Initialise an interface, with a dummy IP address (zero)
129         fd = open("/Devices/ip", 0);
130         if( fd == -1 ) {
131                 fprintf(stderr, "ERROR: Unable to open '/Devices/ip'\n"); 
132                 return -1;
133         }
134         Iface->Num = ioctl(fd, 4, (void*)Iface->Adapter);       // Create interface
135         if( Iface->Num == -1 ) {
136                 fprintf(stderr, "ERROR: Unable to create new interface\n");
137                 return -1;
138         }
139         close(fd);
140         
141         // Open new interface
142         snprintf(path, sizeof(path), "/Devices/ip/%i", Iface->Num);
143         Iface->IfaceFD = fd = open(path, 0);
144         if( fd == -1 ) {
145                 fprintf(stderr, "ERROR: Unable to open '%s'\n", path); 
146                 return -1;
147         }
148         tmp = 4; ioctl(fd, 4, &tmp);    // Set to IPv4
149         ioctl(fd, 6, addr);     // Set address to 0.0.0.0
150         tmp = 0; ioctl(fd, 7, &tmp);    // Set subnet mask to 0
151
152         // Open UDP Client
153         snprintf(path, sizeof(path), "/Devices/ip/%i/udp", Iface->Num);
154         Iface->SocketFD = fd = open(path, O_RDWR);
155         if( fd == -1 ) {
156                 fprintf(stderr, "ERROR: Unable to open '%s'\n", path); 
157                 return -1;
158         }
159         tmp = 68; ioctl(fd, 4, &tmp);   // Local port
160         tmp = 67; ioctl(fd, 5, &tmp);   // Remote port
161         tmp = 0;        ioctl(fd, 7, &tmp);     // Remote addr mask - we don't care where the reply comes from
162         addr[0] = addr[1] = addr[2] = addr[3] = 255;    // 255.255.255.255
163         ioctl(fd, 8, addr);     // Remote address
164         
165         return fd;
166 }
167
168 void Send_DHCPDISCOVER(tInterface *Iface)
169 {
170         uint32_t        transaction_id;
171         struct sDHCP_Message    *msg;
172         char    data[8 + sizeof(struct sDHCP_Message) + 3 + 1];
173         msg = (void*)data + 8;
174         
175         transaction_id = rand();
176
177         msg->op    = htonb(1);  // BOOTREQUEST
178         msg->htype = htonb(1);  // 10mb Ethernet
179         msg->hlen  = htonb(6);  // 6 byte MAC
180         msg->hops  = htonb(0);  // Hop count so far
181         msg->xid   = htonl(transaction_id);     // Transaction ID
182         msg->secs  = htons(0);  // secs - No time has elapsed
183         msg->flags = htons(0);  // flags - TODO: Check if broadcast bit need be set
184         msg->ciaddr = htonl(0); // ciaddr - Zero, as we don't have one yet
185         msg->yiaddr = htonl(0); // yiaddr - Zero?
186         msg->siaddr = htonl(0); // siaddr - Zero? maybe -1
187         msg->giaddr = htonl(0); // giaddr - Zero?
188         // Request MAC address from network adapter
189         {
190                 int fd = open(Iface->Adapter, 0);
191                 // TODO: Check if open() failed
192                 ioctl(fd, 4, msg->chaddr);
193                 // TODO: Check if ioctl() failed
194                 close(fd);
195         }
196         memset(msg->sname, 0, sizeof(msg->sname));      // Nuke the rest
197         memset(msg->file, 0, sizeof(msg->file));        // Nuke the rest
198         msg->dhcp_magic = htonl(DHCP_MAGIC);
199
200         int i = 0;
201         msg->options[i++] =  53;        // DHCP Message Type
202         msg->options[i++] =   1;
203         msg->options[i++] =   1;        // - DHCPDISCOVER
204         msg->options[i++] = 255;        // End of list
205         
206
207         data[0] = 67;   data[1] = 0;    // Port
208         data[2] = 4;    data[3] = 0;    // AddrType
209         data[4] = 255;  data[5] = 255;  data[6] = 255;  data[7] = 255;
210
211         write(Iface->SocketFD, data, sizeof(data));
212         Iface->State = STATE_DISCOVER_SENT;
213 }
214
215 void Send_DHCPREQUEST(tInterface *Iface, void *OfferPacket, int TypeOffset)
216 {
217         struct sDHCP_Message    *msg;
218         msg = (void*) ((char*)OfferPacket) + 8;
219
220         // Reuses old data :)
221         msg->op = 1;
222         msg->options[TypeOffset+2] = 3; // DHCPREQUEST
223         msg->options[TypeOffset+3] = 255;
224         
225         write(Iface->SocketFD, OfferPacket, 8 + sizeof(*msg) + TypeOffset + 4);
226         Iface->State = STATE_REQUEST_SENT;
227 }
228
229 void Handle_Packet(tInterface *Iface)
230 {
231         char    data[8+576];
232         struct sDHCP_Message    *msg = (void*)(data + 8);
233          int    len, i;
234         
235          int    dhcp_msg_type = 0, dhcp_msg_type_ofs;
236         void    *router = NULL;
237         void    *subnet_mask = NULL;
238         
239         _SysDebug("Doing read on %i", Iface->SocketFD);
240         len = read(Iface->SocketFD, data, sizeof(data));
241         _SysDebug("len = %i", len);
242
243         _SysDebug("*msg = {");
244         _SysDebug("  .op = %i", msg->op);
245         _SysDebug("  .htype = %i", msg->htype);
246         _SysDebug("  .ciaddr = 0x%x", ntohl(msg->ciaddr));
247         _SysDebug("  .yiaddr = 0x%x", ntohl(msg->yiaddr));
248         _SysDebug("}");
249         if( msg->op != 2 ) {
250                 // Not a response
251                 _SysDebug("Not a response message");
252                 return ;
253         }
254
255         if( htonl(msg->dhcp_magic) != DHCP_MAGIC ) {
256                 _SysDebug("DHCP magic doesn't match (got 0x%x, expected 0x%x)",
257                         htonl(msg->dhcp_magic), DHCP_MAGIC);
258                 return ;
259         }       
260
261         i = 0;
262         while( i < len - sizeof(*msg) - 8 && msg->options[i] != 255 )
263         {
264                 if( msg->options[i] == 0 ) {
265                         i ++;
266                         continue ;
267                 }
268                 _SysDebug("Option %i, %i bytes long", msg->options[i], msg->options[i+1]);
269                 switch(msg->options[i])
270                 {
271                 case 1:
272                         subnet_mask = &msg->options[i+2];
273                         break;
274                 case 3:
275                         router = &msg->options[i+2];
276                         break;
277                 case 53:
278                         dhcp_msg_type_ofs = i;
279                         dhcp_msg_type = msg->options[i+2];
280                         break;
281                 }
282                 i += msg->options[i+1]+2;
283         }
284         
285         _SysDebug("dhcp_msg_type = %i", dhcp_msg_type);
286
287         switch( dhcp_msg_type )
288         {
289         case 1: // DHCPDISCOVER - wut?
290                 break;
291         case 2: // DHCPOFFER
292                 // Send out request for this address
293                 if( Iface->State != STATE_DISCOVER_SENT )       return ;
294                 Send_DHCPREQUEST(Iface, data, dhcp_msg_type_ofs);
295                 break;
296         case 3: // DHCPREQUEST - wut?
297                 break;
298         case 4: // DHCPDECLINE - ?
299                 break;
300         case 5: // DHCPACK
301                 // TODO: Apply address
302                 SetAddress(Iface, &msg->yiaddr, subnet_mask, router);
303                 exit( 0 );
304                 break;
305         }
306 }
307
308 void SetAddress(tInterface *Iface, void *Addr, void *Mask, void *Router)
309 {
310          int    mask_bits = 0;  
311
312         // Translate the mask
313         if( Mask )
314         {
315                 uint8_t *mask = Mask;
316                  int    i;
317                 _SysDebug("Mask %i.%i.%i.%i", mask[0], mask[1], mask[2], mask[3]);
318                 for( i = 0; i < 4 && mask[i] == 0xFF; i ++ ) ;
319                 mask_bits = i*8;
320                 if( i == 4 )
321                 {
322                         // Wut? /32?
323                 }
324                 else
325                 {
326                         switch(mask[i])
327                         {
328                         case 0x00:      mask_bits += 0; break;
329                         case 0x80:      mask_bits += 1; break;
330                         case 0xC0:      mask_bits += 2; break;
331                         case 0xE0:      mask_bits += 3; break;
332                         case 0xF0:      mask_bits += 4; break;
333                         case 0xF8:      mask_bits += 5; break;
334                         case 0xFC:      mask_bits += 6; break;
335                         case 0xFE:      mask_bits += 7; break;
336                         default:
337                                 // Bad mask!
338                                 break;
339                         }
340                 }
341         }
342         
343         {
344                 uint8_t *addr = Addr;
345                 _SysDebug("Addr %i.%i.%i.%i/%i", addr[0], addr[1], addr[2], addr[3], mask_bits);
346
347                 printf("Assigned %i.%i.%i.%i/%i to IF#%i (%s)\n",
348                         addr[0], addr[1], addr[2], addr[3], mask_bits,
349                         Iface->Num, Iface->Adapter
350                         );
351         }
352
353         ioctl(Iface->IfaceFD, 6, Addr);
354         ioctl(Iface->IfaceFD, 7, &mask_bits);
355
356         if( Router );
357         {
358                 uint8_t *addr = Router;
359                 _SysDebug("Router %i.%i.%i.%i", addr[0], addr[1], addr[2], addr[3]);
360 //              ioctl(Iface->IfaceFD, 8, addr);
361                 // TODO: Default route
362         }
363 }
364

UCC git Repository :: git.ucc.asn.au