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

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