Multiple IPStack Related changes (and other bugfixes)
[tpg/acess2.git] / Usermode / Applications / ifconfig_src / main.c
1 /*
2  * Acess2 IFCONFIG command
3  */
4 #include <stdlib.h>
5 #include <stdio.h>
6 #include <stdint.h>
7 #include <string.h>
8 #include <acess/sys.h>
9
10 // === CONSTANTS ===
11 #define FILENAME_MAX    255
12 #define IPSTACK_ROOT    "/Devices/ip"
13
14 // TODO: Move this to a header
15 #define ntohs(v)        (((v&0xFF)<<8)|((v>>8)&0xFF))
16
17 // === PROTOTYPES ===
18 void    PrintUsage(const char *ProgName);
19 void    DumpInterfaces(void);
20 void    DumpInterface(const char *Name);
21  int    AddInterface(const char *Device);
22  int    DoAutoConfig(const char *Device);
23  int    SetAddress(int IFNum, const char *Address);
24  int    ParseIPAddres(const char *Address, uint8_t *Dest, int *SubnetBits);
25
26 // === CODE ===
27 /**
28  * \brief Program entrypoint
29  */
30 int main(int argc, char *argv[])
31 {
32          int    ret;
33         // No args, dump interfaces
34         if(argc == 1) {
35                 DumpInterfaces();
36                 return 0;
37         }
38         
39         // Add a new interface
40         if( strcmp(argv[1], "add") == 0 ) {
41                 if( argc < 4 ) {
42                         fprintf(stderr, "ERROR: '%s add' requires two arguments, %i passed\n", argv[0], argc-2);
43                         PrintUsage(argv[0]);
44                         return -1;
45                 }
46                 // TODO: Also set the IP address as the usage says it does
47                 ret = AddInterface( argv[2] );
48                 if(ret < 0)     return ret;
49                 ret = SetAddress( ret, argv[3] );
50                 return ret;
51         }
52         
53         // Delete an interface
54         if( strcmp(argv[1], "del") == 0 ) {
55                 if( argc < 3 ) {
56                         fprintf(stderr, "ERROR: '%s del' requires an argument\n", argv[0]);
57                         PrintUsage(argv[0]);
58                         return -1;
59                 }
60                 // TODO:
61         }
62         
63         // Autoconfigure an interface
64         // NOTE: Debugging hack (see the function for more details)
65         if( strcmp(argv[1], "autoconf") == 0 ) {
66                 DoAutoConfig(argv[2]);
67                 return 0;
68         }
69         
70         // Print usage instructions
71         PrintUsage(argv[0]);
72         
73         return 0;
74 }
75
76 /**
77  * \brief Print usage instructions
78  */
79 void PrintUsage(const char *ProgName)
80 {
81         fprintf(stderr, "Usage:\n");
82         fprintf(stderr, "    %s add <device> <ip>/<prefix>\n", ProgName);
83         fprintf(stderr, "        Add a new interface listening on <device> with the specified\n");
84         fprintf(stderr, "        address.\n");
85         fprintf(stderr, "    %s del <interface>\n", ProgName);
86         fprintf(stderr, "    %s set <interface> <option> <value>\n", ProgName);
87         fprintf(stderr, "        Set an option on an interface, a list of valid options follows\n");
88         fprintf(stderr, "        gw      IPv4 default gateway\n");
89         fprintf(stderr, "    %s [<interface>]\n", ProgName);
90         fprintf(stderr, "        Print the current interfaces (or only <interface> if passed)\n");
91         fprintf(stderr, "\n");
92         fprintf(stderr, "A note on Acess's IP Stack:\n");
93         fprintf(stderr, "    Each interface corresponds to only one IP address (either IPv4\n");
94         fprintf(stderr, "    or IPv6). A network device can have multiple interfaces bound\n");
95         fprintf(stderr, "    to it, allowing multiple addresses for one network connection\n");
96         fprintf(stderr, "\n");
97 }
98
99 /**
100  * \brief Dump all interfaces
101  */
102 void DumpInterfaces(void)
103 {
104          int    dp;
105         char    filename[FILENAME_MAX+1];
106         
107         dp = open(IPSTACK_ROOT, OPENFLAG_READ);
108         
109         while( readdir(dp, filename) )
110         {
111                 if(filename[0] == '.')  continue;
112                 DumpInterface(filename);
113         }
114         
115         close(dp);
116 }
117
118 /**
119  * \brief Dump an interface
120  */
121 void DumpInterface(const char *Name)
122 {
123          int    fd;
124          int    type;
125         char    path[sizeof(IPSTACK_ROOT)+1+FILENAME_MAX+1] = IPSTACK_ROOT"/";
126         
127         strcat(path, Name);
128         
129         fd = open(path, OPENFLAG_READ);
130         if(fd == -1) {
131                 printf("%s:\tUnable to open ('%s')\n", Name, path);
132                 return ;
133         }
134         
135         type = ioctl(fd, 4, NULL);
136         
137         // Ignore -1 values
138         if( type == -1 ) {
139                 return ;
140         }
141         
142         printf("%s:\t", Name);
143         {
144                  int    call_num = ioctl(fd, 3, "get_device");
145                  int    len = ioctl(fd, call_num, NULL);
146                 char    *buf = malloc(len+1);
147                 ioctl(fd, call_num, buf);
148                 printf("'%s'\t", buf);
149                 free(buf);
150         }
151         // Get the address type
152         switch(type)
153         {
154         case 0: // Disabled/Unset
155                 printf("DISABLED\n");
156                 break;
157         case 4: // IPv4
158                 {
159                 uint8_t ip[4];
160                  int    subnet;
161                 printf("IPv4\n");
162                 ioctl(fd, 5, ip);       // Get IP Address
163                 subnet = ioctl(fd, 7, NULL);    // Get Subnet Bits
164                 printf("\tAddress: %i.%i.%i.%i/%i\n", ip[0], ip[1], ip[2], ip[3], subnet);
165                 ioctl(fd, 8, ip);       // Get Gateway
166                 printf("\tGateway: %i.%i.%i.%i\n", ip[0], ip[1], ip[2], ip[3]);
167                 }
168                 break;
169         case 6: // IPv6
170                 {
171                 uint16_t        ip[8];
172                  int    subnet;
173                 printf("IPv6\n");
174                 ioctl(fd, 5, ip);       // Get IP Address
175                 subnet = ioctl(fd, 7, NULL);    // Get Subnet Bits
176                 printf("\t%x:%x:%x:%x:%x:%x:%x:%x/%i\n",
177                         ntohs(ip[0]), ntohs(ip[1]), ntohs(ip[2]), ntohs(ip[3]),
178                         ntohs(ip[4]), ntohs(ip[5]), ntohs(ip[6]), ntohs(ip[7]),
179                         subnet);
180                 }
181                 break;
182         default:        // Unknow
183                 printf("UNKNOWN (%i)\n", type);
184                 break;
185         }
186         printf("\n");
187                         
188         close(fd);
189 }
190
191 /**
192  * \brief Create a new interface using the passed device
193  * \param Device        Network device to bind to
194  */
195 int AddInterface(const char *Device)
196 {
197          int    dp, ret;
198         
199         dp = open(IPSTACK_ROOT, OPENFLAG_READ);
200         ret = ioctl(dp, 4, (void*)Device);
201         close(dp);
202         
203         if( ret < 0 ) {
204                 fprintf(stderr, "Unable to add '%s' as a network interface\n", Device);
205                 return -1;
206         }
207         
208         printf("-- Added '"IPSTACK_ROOT"/%i' using device %s\n", ret, Device);
209         
210         return ret;
211 }
212
213 void AddRoute(const char *Interface, void *Dest, int MaskBits, void *NextHop)
214 {
215          int    fd;
216          int    num;
217         char    tmp[sizeof(IPSTACK_ROOT"/routes/") + 5];        // enough for 4 digits
218         
219         // Create route
220         fd = open(IPSTACK_ROOT"/routes", 0);
221         num = ioctl(fd, ioctl(fd, 3, "add_route"), (char*)Interface);
222         close(fd);
223         
224         // Open route
225         sprintf(tmp, IPSTACK_ROOT"/routes/%i", num);
226         fd = open(tmp, 0);
227         
228         ioctl(fd, ioctl(fd, 3, "set_network"), Dest);
229         ioctl(fd, ioctl(fd, 3, "set_nexthop"), NextHop);
230         ioctl(fd, ioctl(fd, 3, "getset_subnetbits"), &MaskBits);
231         
232         close(fd);
233         
234 }
235
236 /**
237  * \note Debugging HACK!
238  * \brief Autoconfigure the specified device to 10.0.2.55/8 using
239  *        10.0.2.1 as the gateway.
240  */
241 int DoAutoConfig(const char *Device)
242 {
243          int    tmp, fd;
244         char    path[sizeof(IPSTACK_ROOT)+5+1]; // ip000
245         uint8_t addr[4] = {10,0,2,55};
246         uint8_t gw[4] = {10,0,2,1};
247          int    subnet = 8;
248         
249         tmp = AddInterface(Device);
250         if( tmp < 0 )   return tmp;
251         
252         sprintf(path, IPSTACK_ROOT"/%i", tmp);
253         
254         fd = open(path, OPENFLAG_READ);
255         if( fd == -1 ) {
256                 fprintf(stderr, "Unable to open '%s'\n", path);
257                 return -1;
258         }
259         
260         tmp = 4;        // IPv4
261         tmp = ioctl(fd, ioctl(fd, 3, "getset_type"), &tmp);
262         if( tmp != 4 ) {
263                 fprintf(stderr, "Error in setting address type (got %i, expected 4)\n", tmp);
264                 return -1;
265         }
266         // Set Address
267         ioctl(fd, ioctl(fd, 3, "set_address"), addr);
268         // Set Subnet
269         ioctl(fd, ioctl(fd, 3, "getset_subnet"), &subnet);
270         // Set Gateway
271         ioctl(fd, ioctl(fd, 3, "set_gateway"), gw);
272         
273         close(fd);
274         
275         printf("Set address to %i.%i.%i.%i/%i (GW: %i.%i.%i.%i)\n",
276                 addr[0], addr[1], addr[2], addr[3],
277                 subnet,
278                 gw[0], gw[1], gw[2], gw[3]);
279         
280         return 0;
281 }
282
283 /**
284  * \brief Set the address on an interface from a textual IP address
285  */
286 int     SetAddress(int IFNum, const char *Address)
287 {
288         uint8_t addr[16];
289          int    type;
290         char    path[sizeof(IPSTACK_ROOT)+1+5+1];       // ip000
291          int    tmp, fd, subnet;
292         
293         // Parse IP Address
294         type = ParseIPAddres(Address, addr, &subnet);
295         if(type == 0) {
296                 fprintf(stderr, "'%s' cannot be parsed as an IP address\n", Address);
297                 return -1;
298         }
299         
300         // Open file
301         sprintf(path, IPSTACK_ROOT"/%i", IFNum);
302         fd = open(path, OPENFLAG_READ);
303         if( fd == -1 ) {
304                 fprintf(stderr, "Unable to open '%s'\n", path);
305                 return -1;
306         }
307         
308         tmp = type;
309         tmp = ioctl(fd, ioctl(fd, 3, "getset_type"), &tmp);
310         if( tmp != type ) {
311                 fprintf(stderr, "Error in setting address type (got %i, expected %i)\n", tmp, type);
312                 close(fd);
313                 return -1;
314         }
315         // Set Address
316         ioctl(fd, ioctl(fd, 3, "set_address"), addr);
317         
318         // Set Subnet
319         ioctl(fd, ioctl(fd, 3, "getset_subnet"), &subnet);
320         
321         close(fd);
322         
323         // Dump!
324         //DumpInterface( path+sizeof(IPSTACK_ROOT)+1 );
325         
326         return 0;
327 }
328
329 /**
330  * \brief Parse an IP Address
331  * \return 0 for unknown, 4 for IPv4 and 6 for IPv6
332  */
333 int ParseIPAddres(const char *Address, uint8_t *Dest, int *SubnetBits)
334 {
335         const char      *p = Address;
336         
337         // Check first block
338         while(*p && *p >= '0' && *p <= '9')     p ++;
339         
340         // IPv4?
341         if(*p == '.')
342         {
343                  int    i = 0, j;
344                  int    val;
345                 
346                 for( j = 0; Address[i] && j < 4; j ++ )
347                 {
348                         val = 0;
349                         for( ; '0' <= Address[i] && Address[i] <= '9'; i++ )
350                         {
351                                 val = val*10 + Address[i] - '0';
352                         }
353                         if(val > 255) {
354                                 //printf("val > 255 (%i)\n", val);
355                                 return 0;
356                         }
357                         Dest[j] = val;
358                         
359                         if(Address[i] == '.')
360                                 i ++;
361                 }
362                 if( j != 4 ) {
363                         //printf("4 parts expected, %i found\n", j);
364                         return 0;
365                 }
366                 // Parse subnet size
367                 if(Address[i] == '/') {
368                         val = 0;
369                         i ++;
370                         while('0' <= Address[i] && Address[i] <= '9') {
371                                 val *= 10;
372                                 val += Address[i] - '0';
373                                 i ++;
374                         }
375                         if(val > 32) {
376                                 printf("Notice: Subnet size >32 (%i)\n", val);
377                         }
378                         *SubnetBits = val;
379                 }
380                 if(Address[i] != '\0') {
381                         //printf("EOS != '\\0', '%c'\n", Address[i]);
382                         return 0;
383                 }
384                 return 4;
385         }
386         
387         // IPv6
388         if(*p == ':' || ('a' <= *p && *p <= 'f') || ('A' <= *p && *p <= 'F'))
389         {
390                  int    i = 0;
391                  int    j, k;
392                  int    val, split = -1, end;
393                 uint16_t        hi[8], low[8];
394                 
395                 for( j = 0; Address[i] && j < 8; j ++ )
396                 {
397                         if(Address[i] == '/')
398                                 break;
399                         
400                         if(Address[i] == ':') {
401                                 if(split != -1) {
402                                         printf("Two '::'s\n");
403                                         return 0;
404                                 }
405                                 split = j;
406                                 i ++;
407                                 continue;
408                         }
409                         
410                         val = 0;
411                         for( k = 0; Address[i] && Address[i] != ':' && Address[i] != '/'; i++, k++ )
412                         {
413                                 val *= 16;
414                                 if('0' <= Address[i] && Address[i] <= '9')
415                                         val += Address[i] - '0';
416                                 else if('A' <= Address[i] && Address[i] <= 'F')
417                                         val += Address[i] - 'A' + 10;
418                                 else if('a' <= Address[i] && Address[i] <= 'f')
419                                         val += Address[i] - 'a' + 10;
420                                 else {
421                                         printf("%c unexpected\n", Address[i]);
422                                         return 0;
423                                 }
424                         }
425                         
426                         if(val > 0xFFFF) {
427                                 printf("val (0x%x) > 0xFFFF\n", val);
428                                 return 0;
429                         }
430                         
431                         if(split == -1)
432                                 hi[j] = val;
433                         else
434                                 low[j-split] = val;
435                         
436                         if( Address[i] == ':' ) {
437                                 i ++;
438                         }
439                 }
440                 end = j;
441                 
442                 // Parse subnet size
443                 if(Address[i] == '/') {
444                         val = 0;
445                         while('0' <= Address[i] && Address[i] <= '9') {
446                                 val *= 10;
447                                 val += Address[i] - '0';
448                                 i ++;
449                         }
450                         if(val > 128) {
451                                 printf("Notice: Subnet size >128 (%i)\n", val);
452                         }
453                         *SubnetBits = val;
454                 }
455                 
456                 for( j = 0; j < split; j ++ )
457                 {
458                         //printf("%04x:", hi[j]);
459                         Dest[j*2] = hi[j]>>8;
460                         Dest[j*2+1] = hi[j]&0xFF;
461                 }
462                 for( ; j < 8 - (end - split); j++ )
463                 {
464                         //printf("0000:", hi[j]);
465                         Dest[j*2] = 0;
466                         Dest[j*2+1] = 0;
467                 }
468                 for( k = 0; j < 8; j ++, k++)
469                 {
470                         //printf("%04x:", low[k]);
471                         Dest[j*2] = low[k]>>8;
472                         Dest[j*2+1] = low[k]&0xFF;
473                 }
474                 return 6;
475         }
476         // Unknown type
477         return 0;
478 }

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