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( 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;
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( 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 while( readdir(dp, filename) )
232 if(filename[0] == '.') continue;
240 * \brief Dump an interface
242 void DumpInterface(const char *Name)
246 char path[sizeof(IPSTACK_ROOT)+1+FILENAME_MAX+1] = IPSTACK_ROOT"/";
250 fd = open(path, OPENFLAG_READ);
252 fprintf(stderr, "Bad interface name '%s' (%s does not exist)\t", Name, path);
256 type = ioctl(fd, 4, NULL);
263 printf("%s:\t", Name);
265 int call_num = ioctl(fd, 3, "get_device");
266 int len = ioctl(fd, call_num, NULL);
267 char *buf = malloc(len+1);
268 ioctl(fd, call_num, buf);
269 printf("'%s'\n", buf);
273 // Get the address type
276 case 0: // Disabled/Unset
277 printf("DISABLED\n");
284 ioctl(fd, 5, ip); // Get IP Address
285 subnet = ioctl(fd, 7, NULL); // Get Subnet Bits
286 printf("%i.%i.%i.%i/%i\n", ip[0], ip[1], ip[2], ip[3], subnet);
294 ioctl(fd, 5, ip); // Get IP Address
295 subnet = ioctl(fd, 7, NULL); // Get Subnet Bits
296 printf("%x:%x:%x:%x:%x:%x:%x:%x/%i\n",
297 ntohs(ip[0]), ntohs(ip[1]), ntohs(ip[2]), ntohs(ip[3]),
298 ntohs(ip[4]), ntohs(ip[5]), ntohs(ip[6]), ntohs(ip[7]),
303 printf("UNKNOWN (%i)\n", type);
312 * \brief Dump a route
314 void DumpRoute(const char *Name)
318 char path[sizeof(IPSTACK_ROOT)+8+FILENAME_MAX+1] = IPSTACK_ROOT"/routes/";
322 fd = open(path, OPENFLAG_READ);
324 printf("%s:\tUnable to open ('%s')\n", Name, path);
328 type = ioctl(fd, 4, NULL);
335 printf("%s:\t", Name);
337 int call_num = ioctl(fd, 3, "get_interface");
338 int len = ioctl(fd, call_num, NULL);
339 char *buf = malloc(len+1);
340 ioctl(fd, call_num, buf);
341 printf("'%s'\t", buf);
345 // Get the address type
348 case 0: // Disabled/Unset
349 printf("DISABLED\n");
353 uint8_t net[4], addr[4];
356 ioctl(fd, ioctl(fd, 3, "get_network"), net); // Get Network
357 ioctl(fd, ioctl(fd, 3, "get_nexthop"), addr); // Get Gateway/NextHop
358 subnet = ioctl(fd, ioctl(fd, 3, "getset_subnetbits"), NULL); // Get Subnet Bits
359 metric = ioctl(fd, ioctl(fd, 3, "getset_metric"), NULL); // Get Subnet Bits
360 printf("\tNetwork: %s/%i\n", Net_PrintAddress(4, net), subnet);
361 printf("\tGateway: %s\n", Net_PrintAddress(4, addr));
362 printf("\tMetric: %i\n", metric);
367 uint16_t net[8], addr[8];
370 ioctl(fd, ioctl(fd, 3, "get_network"), net); // Get Network
371 ioctl(fd, ioctl(fd, 3, "get_nexthop"), addr); // Get Gateway/NextHop
372 subnet = ioctl(fd, ioctl(fd, 3, "getset_subnetbits"), NULL); // Get Subnet Bits
373 metric = ioctl(fd, ioctl(fd, 3, "getset_metric"), NULL); // Get Subnet Bits
374 printf("\tNetwork: %s/%i\n", Net_PrintAddress(6, net), subnet);
375 printf("\tGateway: %s\n", Net_PrintAddress(6, addr));
376 printf("\tMetric: %i\n", metric);
380 printf("UNKNOWN (%i)\n", type);
389 * \brief Create a new interface using the passed device
390 * \param Device Network device to bind to
392 int AddInterface(const char *Device)
396 dp = open(IPSTACK_ROOT, OPENFLAG_READ);
397 ret = ioctl(dp, 4, (void*)Device);
401 fprintf(stderr, "Unable to add '%s' as a network interface\n", Device);
405 printf("-- Added '"IPSTACK_ROOT"/%i' using device %s\n", ret, Device);
410 void AddRoute(const char *Interface, int AddressType, void *Dest, int MaskBits, int Metric, void *NextHop)
414 char tmp[sizeof(IPSTACK_ROOT"/routes/") + 5]; // enough for 4 digits
415 char *ifaceToFree = NULL;
417 // Get interface name
422 "BUG: AddRoute(Interface=NULL,...,NextHop=NULL)\n"
423 "Only one should be NULL\n"
428 // Query for the interface name
429 Interface = ifaceToFree = Net_GetInterface(AddressType, NextHop);
431 // Check address type (if the interface was passed)
432 // - If we got the interface name, then it should be correct
435 char ifacePath[sizeof(IPSTACK_ROOT"/")+strlen(Interface)+1];
438 strcpy(ifacePath, IPSTACK_ROOT"/");
439 strcat(ifacePath, Interface);
440 fd = open(ifacePath, 0);
442 fprintf(stderr, "Error: Interface '%s' does not exist\n", Interface);
445 // Get and check type
446 num = ioctl(fd, ioctl(fd, 3, "getset_type"), NULL);
447 if( num != AddressType ) {
448 fprintf(stderr, "Error: Passed type does not match interface type (%i != %i)\n",
457 fd = open(IPSTACK_ROOT"/routes", 0);
458 num = ioctl(fd, ioctl(fd, 3, "add_route"), (char*)Interface);
462 sprintf(tmp, IPSTACK_ROOT"/routes/%i", num);
465 ioctl(fd, ioctl(fd, 3, "set_network"), Dest);
467 ioctl(fd, ioctl(fd, 3, "set_nexthop"), NextHop);
468 ioctl(fd, ioctl(fd, 3, "getset_subnetbits"), &MaskBits);
469 ioctl(fd, ioctl(fd, 3, "getset_metric"), &Metric);
473 // Check if the interface name was allocated by us
479 * \note Debugging HACK!
480 * \brief Autoconfigure the specified device to 10.0.2.55/8 using
481 * 10.0.2.1 as the gateway.
483 int DoAutoConfig(const char *Device)
486 char path[sizeof(IPSTACK_ROOT)+1+4+1]; // /0000
487 uint8_t addr[4] = {10,0,2,55};
488 uint8_t gw[4] = {10,0,2,2};
491 tmp = AddInterface(Device);
492 if( tmp < 0 ) return tmp;
494 sprintf(path, IPSTACK_ROOT"/%i", tmp);
496 fd = open(path, OPENFLAG_READ);
498 fprintf(stderr, "Unable to open '%s'\n", path);
503 tmp = ioctl(fd, ioctl(fd, 3, "getset_type"), &tmp);
505 fprintf(stderr, "Error in setting address type (got %i, expected 4)\n", tmp);
509 ioctl(fd, ioctl(fd, 3, "set_address"), addr);
511 ioctl(fd, ioctl(fd, 3, "getset_subnet"), &subnet);
515 uint8_t net[4] = {0,0,0,0};
516 AddRoute(path + sizeof(IPSTACK_ROOT), 4, addr, subnet, DEFAULT_METRIC, net); // This interface
517 AddRoute(path + sizeof(IPSTACK_ROOT), 4, net, 0, DEFAULT_METRIC, gw); // Gateway
522 printf("Set address to %i.%i.%i.%i/%i (GW: %i.%i.%i.%i)\n",
523 addr[0], addr[1], addr[2], addr[3],
525 gw[0], gw[1], gw[2], gw[3]);
531 * \brief Set the address on an interface from a textual IP address
533 int SetAddress(int IFNum, const char *Address)
537 char path[sizeof(IPSTACK_ROOT)+1+5+1]; // ip000
541 type = ParseIPAddress(Address, addr, &subnet);
543 fprintf(stderr, "'%s' cannot be parsed as an IP address\n", Address);
548 sprintf(path, IPSTACK_ROOT"/%i", IFNum);
549 fd = open(path, OPENFLAG_READ);
551 fprintf(stderr, "Unable to open '%s'\n", path);
556 tmp = ioctl(fd, ioctl(fd, 3, "getset_type"), &tmp);
558 fprintf(stderr, "Error in setting address type (got %i, expected %i)\n", tmp, type);
563 ioctl(fd, ioctl(fd, 3, "set_address"), addr);
566 ioctl(fd, ioctl(fd, 3, "getset_subnet"), &subnet);
571 //DumpInterface( path+sizeof(IPSTACK_ROOT)+1 );
577 * \brief Parse an IP Address
578 * \return 0 for unknown, 4 for IPv4 and 6 for IPv6
580 int ParseIPAddress(const char *Address, uint8_t *Dest, int *SubnetBits)
582 const char *p = Address;
585 while(*p && *p >= '0' && *p <= '9') p ++;
593 for( j = 0; Address[i] && j < 4; j ++ )
596 for( ; '0' <= Address[i] && Address[i] <= '9'; i++ )
598 val = val*10 + Address[i] - '0';
601 //printf("val > 255 (%i)\n", val);
606 if(Address[i] == '.')
610 //printf("4 parts expected, %i found\n", j);
614 if(Address[i] == '/') {
617 while('0' <= Address[i] && Address[i] <= '9') {
619 val += Address[i] - '0';
623 printf("Notice: Subnet size >32 (%i)\n", val);
625 if(SubnetBits) *SubnetBits = val;
627 if(Address[i] != '\0') {
628 //printf("EOS != '\\0', '%c'\n", Address[i]);
635 if(*p == ':' || ('a' <= *p && *p <= 'f') || ('A' <= *p && *p <= 'F'))
639 int val, split = -1, end;
640 uint16_t hi[8], low[8];
642 for( j = 0; Address[i] && j < 8; j ++ )
644 if(Address[i] == '/')
647 if(Address[i] == ':') {
649 printf("Two '::'s\n");
658 for( k = 0; Address[i] && Address[i] != ':' && Address[i] != '/'; i++, k++ )
661 if('0' <= Address[i] && Address[i] <= '9')
662 val += Address[i] - '0';
663 else if('A' <= Address[i] && Address[i] <= 'F')
664 val += Address[i] - 'A' + 10;
665 else if('a' <= Address[i] && Address[i] <= 'f')
666 val += Address[i] - 'a' + 10;
668 printf("%c unexpected\n", Address[i]);
674 printf("val (0x%x) > 0xFFFF\n", val);
683 if( Address[i] == ':' ) {
690 if(Address[i] == '/') {
692 while('0' <= Address[i] && Address[i] <= '9') {
694 val += Address[i] - '0';
698 printf("Notice: Subnet size >128 (%i)\n", val);
700 if(SubnetBits) *SubnetBits = val;
703 for( j = 0; j < split; j ++ )
705 //printf("%04x:", hi[j]);
706 Dest[j*2] = hi[j]>>8;
707 Dest[j*2+1] = hi[j]&0xFF;
709 for( ; j < 8 - (end - split); j++ )
711 //printf("0000:", hi[j]);
715 for( k = 0; j < 8; j ++, k++)
717 //printf("%04x:", low[k]);
718 Dest[j*2] = low[k]>>8;
719 Dest[j*2+1] = low[k]&0xFF;