2 * Acess2 IFCONFIG command
12 #define FILENAME_MAX 255
13 #define IPSTACK_ROOT "/Devices/ip"
14 #define DEFAULT_METRIC 30
16 // TODO: Move this to a header
17 #define ntohs(v) (((v&0xFF)<<8)|((v>>8)&0xFF))
20 void PrintUsage(const char *ProgName);
21 void DumpInterfaces(void);
22 void DumpRoutes(void);
23 void DumpInterface(const char *Name);
24 void DumpRoute(const char *Name);
25 int AddInterface(const char *Device);
26 void AddRoute(const char *Interface, int AddressType, void *Dest, int MaskBits, int Metric, void *NextHop);
27 int DoAutoConfig(const char *Device);
28 int SetAddress(int IFNum, const char *Address);
29 int ParseIPAddress(const char *Address, uint8_t *Dest, int *SubnetBits);
33 * \brief Program entrypoint
35 int main(int argc, char *argv[])
39 // No args, dump interfaces
46 if( strcmp(argv[1], "route") == 0 )
49 if( argc > 2 && strcmp(argv[2], "add") == 0 )
51 uint8_t dest[16] = {0};
52 uint8_t nextHop[16] = {0};
53 int addrType, subnetBits = -1;
54 int nextHopType, nextHopBits=-1;
55 char *ifaceName = NULL;
56 int metric = DEFAULT_METRIC;
58 // ifconfig route add <host>[/<prefix>] <interface> [<metric>]
59 // ifconfig route add <host>[/<prefix>] <next hop> [<metric>]
61 fprintf(stderr, "ERROR: '%s route add' takes at least two arguments, %i passed\n",
68 fprintf(stderr, "ERROR: '%s route add' takes at most three arguments, %i passed\n",
75 addrType = ParseIPAddress(argv[3], dest, &subnetBits);
76 if( subnetBits == -1 ) {
77 subnetBits = Net_GetAddressSize(addrType)*8;
79 // Interface Name / Next Hop
80 if( (nextHopType = ParseIPAddress(argv[4], nextHop, &nextHopBits)) == 0 )
88 // - Check if it's the same type as the network/destination
89 if( nextHopType != addrType ) {
90 fprintf(stderr, "ERROR: Address type mismatch\n");
93 // - Make sure there's no mask
94 if( nextHopBits != -1 ) {
95 fprintf(stderr, "Error: Next hop cannot be masked\n");
103 metric = atoi(argv[5]);
104 if( metric == 0 && argv[5][0] != '0' ) {
105 fprintf(stderr, "ERROR: Metric should be a number\n");
111 AddRoute(ifaceName, addrType, dest, subnetBits, metric, nextHop);
116 else if( argc > 2 && strcmp(argv[2], "del") == 0 )
119 // ifconfig route del <routenum>
120 // ifconfig route del <host>[/<prefix>]
129 // Add a new interface
130 else if( strcmp(argv[1], "add") == 0 )
133 fprintf(stderr, "ERROR: '%s add' requires two arguments, %i passed\n", argv[0], argc-2);
137 // TODO: Also set the IP address as the usage says it does
138 ret = AddInterface( argv[2] );
139 if(ret < 0) return ret;
140 ret = SetAddress( ret, argv[3] );
143 // Delete an interface
144 else if( strcmp(argv[1], "del") == 0 )
147 fprintf(stderr, "ERROR: '%s del' requires an argument\n", argv[0]);
153 // Autoconfigure an interface
154 // NOTE: Debugging hack (see the function for more details)
155 else if( strcmp(argv[1], "autoconf") == 0 )
157 DoAutoConfig(argv[2]);
160 else if( strcmp(argv[1], "help") == 0 || strcmp(argv[1], "--help") == 0 )
166 // Dump a named interface
167 DumpInterface(argv[1]);
173 * \brief Print usage instructions
175 void PrintUsage(const char *ProgName)
177 fprintf(stderr, "Usage:\n");
178 fprintf(stderr, " %s add <device> <ip>/<prefix>\n", ProgName);
179 fprintf(stderr, " Add a new interface listening on <device> with the specified\n");
180 fprintf(stderr, " address.\n");
181 fprintf(stderr, " %s del <interface>\n", ProgName);
182 fprintf(stderr, " Delete an interface\n");
183 fprintf(stderr, " %s [<interface>]\n", ProgName);
184 fprintf(stderr, " Print the current interfaces (or only <interface> if passed)\n");
185 fprintf(stderr, "\n");
186 fprintf(stderr, " %s route\n", ProgName);
187 fprintf(stderr, " Print the routing tables\n");
188 fprintf(stderr, " %s route add <host>[/<prefix>] [<nexthop> OR <iface>] [<metric>]\n", ProgName);
189 fprintf(stderr, " Add a new route\n");
190 fprintf(stderr, " %s route del <host>[/<prefix>]\n", ProgName);
191 fprintf(stderr, " %s route del <routenum>\n", ProgName);
192 fprintf(stderr, " Add a new route\n");
193 fprintf(stderr, "\n");
194 fprintf(stderr, "A note on Acess's IP Stack:\n");
195 fprintf(stderr, " Each interface corresponds to only one IP address (either IPv4\n");
196 fprintf(stderr, " or IPv6). A network device can have multiple interfaces bound\n");
197 fprintf(stderr, " to it, allowing multiple addresses for one network connection\n");
198 fprintf(stderr, "\n");
202 * \brief Dump all interfaces
204 void DumpInterfaces(void)
207 char filename[FILENAME_MAX+1];
209 dp = open(IPSTACK_ROOT, OPENFLAG_READ);
211 while( readdir(dp, filename) )
213 if(filename[0] == '.') continue;
214 DumpInterface(filename);
221 * \brief Dump all interfaces
223 void DumpRoutes(void)
226 char filename[FILENAME_MAX+1];
228 dp = open(IPSTACK_ROOT"/routes", OPENFLAG_READ);
230 printf("Type\tNetwork \tGateway \tMetric\tIFace\n");
232 while( readdir(dp, filename) )
234 if(filename[0] == '.') continue;
242 * \brief Dump an interface
244 void DumpInterface(const char *Name)
248 char path[sizeof(IPSTACK_ROOT)+1+FILENAME_MAX+1] = IPSTACK_ROOT"/";
252 fd = open(path, OPENFLAG_READ);
254 fprintf(stderr, "Bad interface name '%s' (%s does not exist)\t", Name, path);
258 type = ioctl(fd, 4, NULL);
265 printf("%s:\t", Name);
267 int call_num = ioctl(fd, 3, "get_device");
268 int len = ioctl(fd, call_num, NULL);
269 char *buf = malloc(len+1);
270 ioctl(fd, call_num, buf);
271 printf("'%s'\n", buf);
275 // Get the address type
278 case 0: // Disabled/Unset
279 printf("DISABLED\n");
286 ioctl(fd, 5, ip); // Get IP Address
287 subnet = ioctl(fd, 7, NULL); // Get Subnet Bits
288 printf("%i.%i.%i.%i/%i\n", ip[0], ip[1], ip[2], ip[3], subnet);
296 ioctl(fd, 5, ip); // Get IP Address
297 subnet = ioctl(fd, 7, NULL); // Get Subnet Bits
298 printf("%x:%x:%x:%x:%x:%x:%x:%x/%i\n",
299 ntohs(ip[0]), ntohs(ip[1]), ntohs(ip[2]), ntohs(ip[3]),
300 ntohs(ip[4]), ntohs(ip[5]), ntohs(ip[6]), ntohs(ip[7]),
305 printf("UNKNOWN (%i)\n", type);
314 * \brief Dump a route
316 void DumpRoute(const char *Name)
320 char path[sizeof(IPSTACK_ROOT)+8+FILENAME_MAX+1] = IPSTACK_ROOT"/routes/";
324 fd = open(path, OPENFLAG_READ);
326 printf("%s:\tUnable to open ('%s')\n", Name, path);
334 int len = Net_GetAddressSize(type);
335 uint8_t net[len], gw[len];
337 for( i = 0; i < len; i ++ ) {
338 char tmp[5] = "0x00";
339 tmp[2] = Name[ofs++];
340 tmp[3] = Name[ofs++];
344 subnet = atoi(Name+ofs);
346 metric = atoi(Name+ofs);
347 ioctl(fd, ioctl(fd, 3, "get_nexthop"), gw); // Get Gateway/NextHop
349 // Get the address type
352 case 0: // Disabled/Unset
353 printf("DISABLED\n");
362 printf("UNKNOWN (%i)\n", type);
365 printf("%s/%i\t", Net_PrintAddress(type, net), subnet);
366 printf("%s \t", Net_PrintAddress(type, gw));
367 printf("%i\t", metric);
371 int call_num = ioctl(fd, 3, "get_interface");
372 int len = ioctl(fd, call_num, NULL);
373 char *buf = malloc(len+1);
374 ioctl(fd, call_num, buf);
375 printf("'%s'\t", buf);
385 * \brief Create a new interface using the passed device
386 * \param Device Network device to bind to
388 int AddInterface(const char *Device)
392 dp = open(IPSTACK_ROOT, OPENFLAG_READ);
393 ret = ioctl(dp, 4, (void*)Device);
397 fprintf(stderr, "Unable to add '%s' as a network interface\n", Device);
401 printf("-- Added '"IPSTACK_ROOT"/%i' using device %s\n", ret, Device);
406 void AddRoute(const char *Interface, int AddressType, void *Dest, int MaskBits, int Metric, void *NextHop)
410 char *ifaceToFree = NULL;
412 // Get interface name
417 "BUG: AddRoute(Interface=NULL,...,NextHop=NULL)\n"
418 "Only one should be NULL\n"
423 // Query for the interface name
424 Interface = ifaceToFree = Net_GetInterface(AddressType, NextHop);
426 // Check address type (if the interface was passed)
427 // - If we got the interface name, then it should be correct
430 char ifacePath[sizeof(IPSTACK_ROOT"/")+strlen(Interface)+1];
433 strcpy(ifacePath, IPSTACK_ROOT"/");
434 strcat(ifacePath, Interface);
435 fd = open(ifacePath, 0);
437 fprintf(stderr, "Error: Interface '%s' does not exist\n", Interface);
440 // Get and check type
441 num = ioctl(fd, ioctl(fd, 3, "getset_type"), NULL);
442 if( num != AddressType ) {
443 fprintf(stderr, "Error: Passed type does not match interface type (%i != %i)\n",
452 int addrsize = Net_GetAddressSize(AddressType);
453 int len = snprintf(NULL, 0, "/Devices/ip/routes/%i::%i:%i", AddressType, MaskBits, Metric) + addrsize*2;
457 ofs = sprintf(path, "/Devices/ip/routes/%i:", AddressType);
458 for( i = 0; i < addrsize; i ++ )
459 sprintf(path+ofs+i*2, "%02x", ((uint8_t*)Dest)[i]);
461 sprintf(path+ofs, ":%i:%i", MaskBits, Metric);
467 fprintf(stderr, "Unable to create route '%s', already exists\n", path);
470 fd = open(path, OPENFLAG_CREATE, 0);
472 fprintf(stderr, "Unable to create '%s'\n", path);
477 ioctl(fd, ioctl(fd, 3, "set_nexthop"), NextHop);
478 ioctl(fd, ioctl(fd, 3, "set_interface"), (void*)Interface);
482 // Check if the interface name was allocated by us
488 * \note Debugging HACK!
489 * \brief Autoconfigure the specified device to 10.0.2.55/24 using
490 * 10.0.2.2 as the gateway.
492 int DoAutoConfig(const char *Device)
495 char path[sizeof(IPSTACK_ROOT)+1+4+1]; // /0000
496 uint8_t addr[4] = {10,0,2,55};
497 uint8_t gw[4] = {10,0,2,2};
500 tmp = AddInterface(Device);
501 if( tmp < 0 ) return tmp;
503 sprintf(path, IPSTACK_ROOT"/%i", tmp);
505 fd = open(path, OPENFLAG_READ);
507 fprintf(stderr, "Unable to open '%s'\n", path);
512 tmp = ioctl(fd, ioctl(fd, 3, "getset_type"), &tmp);
514 fprintf(stderr, "Error in setting address type (got %i, expected 4)\n", tmp);
518 ioctl(fd, ioctl(fd, 3, "set_address"), addr);
520 ioctl(fd, ioctl(fd, 3, "getset_subnet"), &subnet);
524 uint8_t net[4] = {0,0,0,0};
525 AddRoute(path + sizeof(IPSTACK_ROOT), 4, addr, subnet, DEFAULT_METRIC, net); // This interface
526 AddRoute(path + sizeof(IPSTACK_ROOT), 4, net, 0, DEFAULT_METRIC, gw); // Gateway
531 printf("Set address to %i.%i.%i.%i/%i (GW: %i.%i.%i.%i)\n",
532 addr[0], addr[1], addr[2], addr[3],
534 gw[0], gw[1], gw[2], gw[3]);
540 * \brief Set the address on an interface from a textual IP address
542 int SetAddress(int IFNum, const char *Address)
546 char path[sizeof(IPSTACK_ROOT)+1+5+1]; // ip000
550 type = ParseIPAddress(Address, addr, &subnet);
552 fprintf(stderr, "'%s' cannot be parsed as an IP address\n", Address);
557 sprintf(path, IPSTACK_ROOT"/%i", IFNum);
558 fd = open(path, OPENFLAG_READ);
560 fprintf(stderr, "Unable to open '%s'\n", path);
565 tmp = ioctl(fd, ioctl(fd, 3, "getset_type"), &tmp);
567 fprintf(stderr, "Error in setting address type (got %i, expected %i)\n", tmp, type);
572 ioctl(fd, ioctl(fd, 3, "set_address"), addr);
575 ioctl(fd, ioctl(fd, 3, "getset_subnet"), &subnet);
580 //DumpInterface( path+sizeof(IPSTACK_ROOT)+1 );
586 * \brief Parse an IP Address
587 * \return 0 for unknown, 4 for IPv4 and 6 for IPv6
589 int ParseIPAddress(const char *Address, uint8_t *Dest, int *SubnetBits)
591 const char *p = Address;
594 while(*p && *p >= '0' && *p <= '9') p ++;
602 for( j = 0; Address[i] && j < 4; j ++ )
605 for( ; '0' <= Address[i] && Address[i] <= '9'; i++ )
607 val = val*10 + Address[i] - '0';
610 //printf("val > 255 (%i)\n", val);
615 if(Address[i] == '.')
619 //printf("4 parts expected, %i found\n", j);
623 if(Address[i] == '/') {
626 while('0' <= Address[i] && Address[i] <= '9') {
628 val += Address[i] - '0';
632 printf("Notice: Subnet size >32 (%i)\n", val);
634 if(SubnetBits) *SubnetBits = val;
636 if(Address[i] != '\0') {
637 //printf("EOS != '\\0', '%c'\n", Address[i]);
644 if(*p == ':' || ('a' <= *p && *p <= 'f') || ('A' <= *p && *p <= 'F'))
648 int val, split = -1, end;
649 uint16_t hi[8], low[8];
651 for( j = 0; Address[i] && j < 8; j ++ )
653 if(Address[i] == '/')
656 if(Address[i] == ':') {
658 printf("Two '::'s\n");
667 for( k = 0; Address[i] && Address[i] != ':' && Address[i] != '/'; i++, k++ )
670 if('0' <= Address[i] && Address[i] <= '9')
671 val += Address[i] - '0';
672 else if('A' <= Address[i] && Address[i] <= 'F')
673 val += Address[i] - 'A' + 10;
674 else if('a' <= Address[i] && Address[i] <= 'f')
675 val += Address[i] - 'a' + 10;
677 printf("%c unexpected\n", Address[i]);
683 printf("val (0x%x) > 0xFFFF\n", val);
692 if( Address[i] == ':' ) {
699 if(Address[i] == '/') {
701 while('0' <= Address[i] && Address[i] <= '9') {
703 val += Address[i] - '0';
707 printf("Notice: Subnet size >128 (%i)\n", val);
709 if(SubnetBits) *SubnetBits = val;
712 for( j = 0; j < split; j ++ )
714 //printf("%04x:", hi[j]);
715 Dest[j*2] = hi[j]>>8;
716 Dest[j*2+1] = hi[j]&0xFF;
718 for( ; j < 8 - (end - split); j++ )
720 //printf("0000:", hi[j]);
724 for( k = 0; j < 8; j ++, k++)
726 //printf("%04x:", low[k]);
727 Dest[j*2] = low[k]>>8;
728 Dest[j*2+1] = low[k]&0xFF;