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 routes\n", ProgName);
187 fprintf(stderr, " Print the routing tables\n");
188 fprintf(stderr, " %s routes add <host>[/<prefix>] [<nexthop> OR <iface>] [<metric>]\n", ProgName);
189 fprintf(stderr, " Add a new route\n");
190 fprintf(stderr, " %s routes del <host>[/<prefix>]\n", ProgName);
191 fprintf(stderr, " %s routes 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("ID\tType\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);
330 type = ioctl(fd, 4, NULL);
338 printf("%s\t", Name);
340 // Get the address type
343 case 0: // Disabled/Unset
344 printf("DISABLED\n");
348 uint8_t net[4], addr[4];
351 ioctl(fd, ioctl(fd, 3, "get_network"), net); // Get Network
352 ioctl(fd, ioctl(fd, 3, "get_nexthop"), addr); // Get Gateway/NextHop
353 subnet = ioctl(fd, ioctl(fd, 3, "getset_subnetbits"), NULL); // Get Subnet Bits
354 metric = ioctl(fd, ioctl(fd, 3, "getset_metric"), NULL); // Get Subnet Bits
355 printf("%s/%i\t", Net_PrintAddress(4, net), subnet);
356 printf("%s \t", Net_PrintAddress(4, addr));
357 printf("%i\t", metric);
362 uint16_t net[8], addr[8];
365 ioctl(fd, ioctl(fd, 3, "get_network"), net); // Get Network
366 ioctl(fd, ioctl(fd, 3, "get_nexthop"), addr); // Get Gateway/NextHop
367 subnet = ioctl(fd, ioctl(fd, 3, "getset_subnetbits"), NULL); // Get Subnet Bits
368 metric = ioctl(fd, ioctl(fd, 3, "getset_metric"), NULL); // Get Subnet Bits
369 printf("%s/%i\t", Net_PrintAddress(6, net), subnet);
370 printf("%s\t", Net_PrintAddress(6, addr));
371 printf("%i\t", metric);
375 printf("UNKNOWN (%i)\n", type);
381 int call_num = ioctl(fd, 3, "get_interface");
382 int len = ioctl(fd, call_num, NULL);
383 char *buf = malloc(len+1);
384 ioctl(fd, call_num, buf);
385 printf("'%s'\t", buf);
395 * \brief Create a new interface using the passed device
396 * \param Device Network device to bind to
398 int AddInterface(const char *Device)
402 dp = open(IPSTACK_ROOT, OPENFLAG_READ);
403 ret = ioctl(dp, 4, (void*)Device);
407 fprintf(stderr, "Unable to add '%s' as a network interface\n", Device);
411 printf("-- Added '"IPSTACK_ROOT"/%i' using device %s\n", ret, Device);
416 void AddRoute(const char *Interface, int AddressType, void *Dest, int MaskBits, int Metric, void *NextHop)
420 char tmp[sizeof(IPSTACK_ROOT"/routes/") + 5]; // enough for 4 digits
421 char *ifaceToFree = NULL;
423 // Get interface name
428 "BUG: AddRoute(Interface=NULL,...,NextHop=NULL)\n"
429 "Only one should be NULL\n"
434 // Query for the interface name
435 Interface = ifaceToFree = Net_GetInterface(AddressType, NextHop);
437 // Check address type (if the interface was passed)
438 // - If we got the interface name, then it should be correct
441 char ifacePath[sizeof(IPSTACK_ROOT"/")+strlen(Interface)+1];
444 strcpy(ifacePath, IPSTACK_ROOT"/");
445 strcat(ifacePath, Interface);
446 fd = open(ifacePath, 0);
448 fprintf(stderr, "Error: Interface '%s' does not exist\n", Interface);
451 // Get and check type
452 num = ioctl(fd, ioctl(fd, 3, "getset_type"), NULL);
453 if( num != AddressType ) {
454 fprintf(stderr, "Error: Passed type does not match interface type (%i != %i)\n",
463 fd = open(IPSTACK_ROOT"/routes", 0);
464 num = ioctl(fd, ioctl(fd, 3, "add_route"), (char*)Interface);
468 sprintf(tmp, IPSTACK_ROOT"/routes/%i", num);
471 ioctl(fd, ioctl(fd, 3, "set_network"), Dest);
473 ioctl(fd, ioctl(fd, 3, "set_nexthop"), NextHop);
474 ioctl(fd, ioctl(fd, 3, "getset_subnetbits"), &MaskBits);
475 ioctl(fd, ioctl(fd, 3, "getset_metric"), &Metric);
479 // Check if the interface name was allocated by us
485 * \note Debugging HACK!
486 * \brief Autoconfigure the specified device to 10.0.2.55/8 using
487 * 10.0.2.1 as the gateway.
489 int DoAutoConfig(const char *Device)
492 char path[sizeof(IPSTACK_ROOT)+1+4+1]; // /0000
493 uint8_t addr[4] = {10,0,2,55};
494 uint8_t gw[4] = {10,0,2,2};
497 tmp = AddInterface(Device);
498 if( tmp < 0 ) return tmp;
500 sprintf(path, IPSTACK_ROOT"/%i", tmp);
502 fd = open(path, OPENFLAG_READ);
504 fprintf(stderr, "Unable to open '%s'\n", path);
509 tmp = ioctl(fd, ioctl(fd, 3, "getset_type"), &tmp);
511 fprintf(stderr, "Error in setting address type (got %i, expected 4)\n", tmp);
515 ioctl(fd, ioctl(fd, 3, "set_address"), addr);
517 ioctl(fd, ioctl(fd, 3, "getset_subnet"), &subnet);
521 uint8_t net[4] = {0,0,0,0};
522 AddRoute(path + sizeof(IPSTACK_ROOT), 4, addr, subnet, DEFAULT_METRIC, net); // This interface
523 AddRoute(path + sizeof(IPSTACK_ROOT), 4, net, 0, DEFAULT_METRIC, gw); // Gateway
528 printf("Set address to %i.%i.%i.%i/%i (GW: %i.%i.%i.%i)\n",
529 addr[0], addr[1], addr[2], addr[3],
531 gw[0], gw[1], gw[2], gw[3]);
537 * \brief Set the address on an interface from a textual IP address
539 int SetAddress(int IFNum, const char *Address)
543 char path[sizeof(IPSTACK_ROOT)+1+5+1]; // ip000
547 type = ParseIPAddress(Address, addr, &subnet);
549 fprintf(stderr, "'%s' cannot be parsed as an IP address\n", Address);
554 sprintf(path, IPSTACK_ROOT"/%i", IFNum);
555 fd = open(path, OPENFLAG_READ);
557 fprintf(stderr, "Unable to open '%s'\n", path);
562 tmp = ioctl(fd, ioctl(fd, 3, "getset_type"), &tmp);
564 fprintf(stderr, "Error in setting address type (got %i, expected %i)\n", tmp, type);
569 ioctl(fd, ioctl(fd, 3, "set_address"), addr);
572 ioctl(fd, ioctl(fd, 3, "getset_subnet"), &subnet);
577 //DumpInterface( path+sizeof(IPSTACK_ROOT)+1 );
583 * \brief Parse an IP Address
584 * \return 0 for unknown, 4 for IPv4 and 6 for IPv6
586 int ParseIPAddress(const char *Address, uint8_t *Dest, int *SubnetBits)
588 const char *p = Address;
591 while(*p && *p >= '0' && *p <= '9') p ++;
599 for( j = 0; Address[i] && j < 4; j ++ )
602 for( ; '0' <= Address[i] && Address[i] <= '9'; i++ )
604 val = val*10 + Address[i] - '0';
607 //printf("val > 255 (%i)\n", val);
612 if(Address[i] == '.')
616 //printf("4 parts expected, %i found\n", j);
620 if(Address[i] == '/') {
623 while('0' <= Address[i] && Address[i] <= '9') {
625 val += Address[i] - '0';
629 printf("Notice: Subnet size >32 (%i)\n", val);
631 if(SubnetBits) *SubnetBits = val;
633 if(Address[i] != '\0') {
634 //printf("EOS != '\\0', '%c'\n", Address[i]);
641 if(*p == ':' || ('a' <= *p && *p <= 'f') || ('A' <= *p && *p <= 'F'))
645 int val, split = -1, end;
646 uint16_t hi[8], low[8];
648 for( j = 0; Address[i] && j < 8; j ++ )
650 if(Address[i] == '/')
653 if(Address[i] == ':') {
655 printf("Two '::'s\n");
664 for( k = 0; Address[i] && Address[i] != ':' && Address[i] != '/'; i++, k++ )
667 if('0' <= Address[i] && Address[i] <= '9')
668 val += Address[i] - '0';
669 else if('A' <= Address[i] && Address[i] <= 'F')
670 val += Address[i] - 'A' + 10;
671 else if('a' <= Address[i] && Address[i] <= 'f')
672 val += Address[i] - 'a' + 10;
674 printf("%c unexpected\n", Address[i]);
680 printf("val (0x%x) > 0xFFFF\n", val);
689 if( Address[i] == ':' ) {
696 if(Address[i] == '/') {
698 while('0' <= Address[i] && Address[i] <= '9') {
700 val += Address[i] - '0';
704 printf("Notice: Subnet size >128 (%i)\n", val);
706 if(SubnetBits) *SubnetBits = val;
709 for( j = 0; j < split; j ++ )
711 //printf("%04x:", hi[j]);
712 Dest[j*2] = hi[j]>>8;
713 Dest[j*2+1] = hi[j]&0xFF;
715 for( ; j < 8 - (end - split); j++ )
717 //printf("0000:", hi[j]);
721 for( k = 0; j < 8; j ++, k++)
723 //printf("%04x:", low[k]);
724 Dest[j*2] = low[k]>>8;
725 Dest[j*2+1] = low[k]&0xFF;