IPStack / ifconfig - Routing changes
[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 #include <net.h>
10
11 // === CONSTANTS ===
12 #define FILENAME_MAX    255
13 #define IPSTACK_ROOT    "/Devices/ip"
14 #define DEFAULT_METRIC  30
15
16 // TODO: Move this to a header
17 #define ntohs(v)        (((v&0xFF)<<8)|((v>>8)&0xFF))
18
19 // === PROTOTYPES ===
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);
30
31 // === CODE ===
32 /**
33  * \brief Program entrypoint
34  */
35 int main(int argc, char *argv[])
36 {
37          int    ret;
38         
39         // No args, dump interfaces
40         if(argc == 1) {
41                 DumpInterfaces();
42                 return 0;
43         }
44         
45         // Routes
46         if( strcmp(argv[1], "route") == 0 )
47         {
48                 // Add new route
49                 if( strcmp(argv[2], "add") == 0 )
50                 {
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;
56                          int    metric = DEFAULT_METRIC;
57                         // Usage:
58                         // ifconfig route add <host>[/<prefix>] <interface> [<metric>]
59                         // ifconfig route add <host>[/<prefix>] <next hop> [<metric>]
60                         if( argc - 3  < 2 ) {
61                                 fprintf(stderr, "ERROR: '%s route add' takes at least two arguments, %i passed\n",
62                                         argv[0], argc-3);
63                                 PrintUsage(argv[0]);
64                                 return -1;
65                         }
66                         
67                         if( argc - 3 > 3 ) {
68                                 fprintf(stderr, "ERROR: '%s route add' takes at most three arguments, %i passed\n",
69                                         argv[0], argc-3);
70                                 PrintUsage(argv[0]);
71                                 return -1;
72                         }
73                         
74                         // Destination IP
75                         addrType = ParseIPAddress(argv[3], dest, &subnetBits);
76                         if( subnetBits == -1 ) {
77                                 subnetBits = Net_GetAddressSize(addrType)*8;
78                         }
79                         // Interface Name / Next Hop
80                         if( (nextHopType = ParseIPAddress(argv[4], nextHop, &nextHopBits)) == 0 )
81                         {
82                                 // Interface name
83                                 ifaceName = argv[4];
84                         }
85                         else
86                         {
87                                 // Next Hop
88                                 // - Check if it's the same type as the network/destination
89                                 if( nextHopType != addrType ) {
90                                         fprintf(stderr, "ERROR: Address type mismatch\n");
91                                         return -1;
92                                 }
93                                 // - Make sure there's no mask
94                                 if( nextHopBits != -1 ) {
95                                         fprintf(stderr, "Error: Next hop cannot be masked\n");
96                                         return -1;
97                                 }
98                         }
99                         
100                         // Metric
101                         if( argc - 3 >= 3 )
102                         {
103                                 metric = atoi(argv[5]);
104                                 if( metric == 0 && argv[5][0] != '0' ) {
105                                         fprintf(stderr, "ERROR: Metric should be a number\n");
106                                         return -1;
107                                 }
108                         }
109                         
110                         // Make the route!
111                         AddRoute(ifaceName, addrType, dest, subnetBits, metric, nextHop);
112                         
113                         return 0;
114                 }
115                 // Delete a route
116                 else if( strcmp(argv[2], "del") == 0 )
117                 {
118                         // Usage:
119                         // ifconfig route del <routenum>
120                         // ifconfig route del <host>[/<prefix>]
121                 }
122                 else
123                 {
124                         // List routes
125                         DumpRoutes();
126                 }
127                 return 0;
128         }
129         // Add a new interface
130         else if( strcmp(argv[1], "add") == 0 )
131         {
132                 if( argc < 4 ) {
133                         fprintf(stderr, "ERROR: '%s add' requires two arguments, %i passed\n", argv[0], argc-2);
134                         PrintUsage(argv[0]);
135                         return -1;
136                 }
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] );
141                 return ret;
142         }
143         // Delete an interface
144         else if( strcmp(argv[1], "del") == 0 )
145         {
146                 if( argc < 3 ) {
147                         fprintf(stderr, "ERROR: '%s del' requires an argument\n", argv[0]);
148                         PrintUsage(argv[0]);
149                         return -1;
150                 }
151                 // TODO:
152         }
153         // Autoconfigure an interface
154         // NOTE: Debugging hack (see the function for more details)
155         else if( strcmp(argv[1], "autoconf") == 0 )
156         {
157                 DoAutoConfig(argv[2]);
158                 return 0;
159         }
160         else if( strcmp(argv[1], "help") == 0 || strcmp(argv[1], "--help") == 0 )
161         {
162                 PrintUsage(argv[0]);
163                 return 0;
164         }
165         
166         // Dump a named interface
167         DumpInterface(argv[1]);
168         
169         return 0;
170 }
171
172 /**
173  * \brief Print usage instructions
174  */
175 void PrintUsage(const char *ProgName)
176 {
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");
199 }
200
201 /**
202  * \brief Dump all interfaces
203  */
204 void DumpInterfaces(void)
205 {
206          int    dp;
207         char    filename[FILENAME_MAX+1];
208         
209         dp = open(IPSTACK_ROOT, OPENFLAG_READ);
210         
211         while( readdir(dp, filename) )
212         {
213                 if(filename[0] == '.')  continue;
214                 DumpInterface(filename);
215         }
216         
217         close(dp);
218 }
219
220 /**
221  * \brief Dump all interfaces
222  */
223 void DumpRoutes(void)
224 {
225          int    dp;
226         char    filename[FILENAME_MAX+1];
227         
228         dp = open(IPSTACK_ROOT"/routes", OPENFLAG_READ);
229         
230         while( readdir(dp, filename) )
231         {
232                 if(filename[0] == '.')  continue;
233                 DumpRoute(filename);
234         }
235         
236         close(dp);
237 }
238
239 /**
240  * \brief Dump an interface
241  */
242 void DumpInterface(const char *Name)
243 {
244          int    fd;
245          int    type;
246         char    path[sizeof(IPSTACK_ROOT)+1+FILENAME_MAX+1] = IPSTACK_ROOT"/";
247         
248         strcat(path, Name);
249         
250         fd = open(path, OPENFLAG_READ);
251         if(fd == -1) {
252                 fprintf(stderr, "Bad interface name '%s' (%s does not exist)\t", Name, path);
253                 return ;
254         }
255         
256         type = ioctl(fd, 4, NULL);
257         
258         // Ignore -1 values
259         if( type == -1 ) {
260                 return ;
261         }
262         
263         printf("%s:\t", Name);
264         {
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);
270                 free(buf);
271         }
272         printf("\t");
273         // Get the address type
274         switch(type)
275         {
276         case 0: // Disabled/Unset
277                 printf("DISABLED\n");
278                 break;
279         case 4: // IPv4
280                 {
281                 uint8_t ip[4];
282                  int    subnet;
283                 printf("IPv4\t");
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);
287                 }
288                 break;
289         case 6: // IPv6
290                 {
291                 uint16_t        ip[8];
292                  int    subnet;
293                 printf("IPv6\t");
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]),
299                         subnet);
300                 }
301                 break;
302         default:        // Unknow
303                 printf("UNKNOWN (%i)\n", type);
304                 break;
305         }
306                         
307         close(fd);
308 }
309
310
311 /**
312  * \brief Dump a route
313  */
314 void DumpRoute(const char *Name)
315 {
316          int    fd;
317          int    type;
318         char    path[sizeof(IPSTACK_ROOT)+8+FILENAME_MAX+1] = IPSTACK_ROOT"/routes/";
319         
320         strcat(path, Name);
321         
322         fd = open(path, OPENFLAG_READ);
323         if(fd == -1) {
324                 printf("%s:\tUnable to open ('%s')\n", Name, path);
325                 return ;
326         }
327         
328         type = ioctl(fd, 4, NULL);
329         
330         // Ignore -1 values
331         if( type == -1 ) {
332                 return ;
333         }
334         
335         printf("%s:\t", Name);
336         {
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);
342                 free(buf);
343         }
344         
345         // Get the address type
346         switch(type)
347         {
348         case 0: // Disabled/Unset
349                 printf("DISABLED\n");
350                 break;
351         case 4: // IPv4
352                 {
353                 uint8_t net[4], addr[4];
354                  int    subnet, metric;
355                 printf("IPv4\n");
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);
363                 }
364                 break;
365         case 6: // IPv6
366                 {
367                 uint16_t        net[8], addr[8];
368                  int    subnet, metric;
369                 printf("IPv6\n");
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);
377                 }
378                 break;
379         default:        // Unknow
380                 printf("UNKNOWN (%i)\n", type);
381                 break;
382         }
383         printf("\n");
384                         
385         close(fd);
386 }
387
388 /**
389  * \brief Create a new interface using the passed device
390  * \param Device        Network device to bind to
391  */
392 int AddInterface(const char *Device)
393 {
394          int    dp, ret;
395         
396         dp = open(IPSTACK_ROOT, OPENFLAG_READ);
397         ret = ioctl(dp, 4, (void*)Device);
398         close(dp);
399         
400         if( ret < 0 ) {
401                 fprintf(stderr, "Unable to add '%s' as a network interface\n", Device);
402                 return -1;
403         }
404         
405         printf("-- Added '"IPSTACK_ROOT"/%i' using device %s\n", ret, Device);
406         
407         return ret;
408 }
409
410 void AddRoute(const char *Interface, int AddressType, void *Dest, int MaskBits, int Metric, void *NextHop)
411 {
412          int    fd;
413          int    num;
414         char    tmp[sizeof(IPSTACK_ROOT"/routes/") + 5];        // enough for 4 digits
415         char    *ifaceToFree = NULL;
416         
417         // Get interface name
418         if( !Interface )
419         {
420                 if( !NextHop ) {
421                         fprintf(stderr,
422                                 "BUG: AddRoute(Interface=NULL,...,NextHop=NULL)\n"
423                                 "Only one should be NULL\n"
424                                 );
425                         return ;
426                 }
427                 
428                 // Query for the interface name
429                 Interface = ifaceToFree = Net_GetInterface(AddressType, NextHop);
430         }
431         // Check address type (if the interface was passed)
432         // - If we got the interface name, then it should be correct
433         else
434         {
435                 char    ifacePath[sizeof(IPSTACK_ROOT"/")+strlen(Interface)+1];
436                 
437                 // Open interface
438                 strcpy(ifacePath, IPSTACK_ROOT"/");
439                 strcat(ifacePath, Interface);
440                 fd = open(ifacePath, 0);
441                 if( fd == -1 ) {
442                         fprintf(stderr, "Error: Interface '%s' does not exist\n", Interface);
443                         return ;
444                 }
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",
449                                 AddressType, num);
450                         return ;
451                 }
452                 
453                 close(fd);
454         }
455         
456         // Create route
457         fd = open(IPSTACK_ROOT"/routes", 0);
458         num = ioctl(fd, ioctl(fd, 3, "add_route"), (char*)Interface);
459         close(fd);
460         
461         // Open route
462         sprintf(tmp, IPSTACK_ROOT"/routes/%i", num);
463         fd = open(tmp, 0);
464         
465         ioctl(fd, ioctl(fd, 3, "set_network"), Dest);
466         if( NextHop )
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);
470         
471         close(fd);
472         
473         // Check if the interface name was allocated by us
474         if( ifaceToFree )
475                 free(ifaceToFree);
476 }
477
478 /**
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.
482  */
483 int DoAutoConfig(const char *Device)
484 {
485          int    tmp, fd;
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};
489          int    subnet = 24;
490         
491         tmp = AddInterface(Device);
492         if( tmp < 0 )   return tmp;
493         
494         sprintf(path, IPSTACK_ROOT"/%i", tmp);
495         
496         fd = open(path, OPENFLAG_READ);
497         if( fd == -1 ) {
498                 fprintf(stderr, "Unable to open '%s'\n", path);
499                 return -1;
500         }
501         
502         tmp = 4;        // IPv4
503         tmp = ioctl(fd, ioctl(fd, 3, "getset_type"), &tmp);
504         if( tmp != 4 ) {
505                 fprintf(stderr, "Error in setting address type (got %i, expected 4)\n", tmp);
506                 return -1;
507         }
508         // Set Address
509         ioctl(fd, ioctl(fd, 3, "set_address"), addr);
510         // Set Subnet
511         ioctl(fd, ioctl(fd, 3, "getset_subnet"), &subnet);
512         
513         // Set routes
514         {
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
518         }
519         
520         close(fd);
521         
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],
524                 subnet,
525                 gw[0], gw[1], gw[2], gw[3]);
526         
527         return 0;
528 }
529
530 /**
531  * \brief Set the address on an interface from a textual IP address
532  */
533 int     SetAddress(int IFNum, const char *Address)
534 {
535         uint8_t addr[16];
536          int    type;
537         char    path[sizeof(IPSTACK_ROOT)+1+5+1];       // ip000
538          int    tmp, fd, subnet;
539         
540         // Parse IP Address
541         type = ParseIPAddress(Address, addr, &subnet);
542         if(type == 0) {
543                 fprintf(stderr, "'%s' cannot be parsed as an IP address\n", Address);
544                 return -1;
545         }
546         
547         // Open file
548         sprintf(path, IPSTACK_ROOT"/%i", IFNum);
549         fd = open(path, OPENFLAG_READ);
550         if( fd == -1 ) {
551                 fprintf(stderr, "Unable to open '%s'\n", path);
552                 return -1;
553         }
554         
555         tmp = type;
556         tmp = ioctl(fd, ioctl(fd, 3, "getset_type"), &tmp);
557         if( tmp != type ) {
558                 fprintf(stderr, "Error in setting address type (got %i, expected %i)\n", tmp, type);
559                 close(fd);
560                 return -1;
561         }
562         // Set Address
563         ioctl(fd, ioctl(fd, 3, "set_address"), addr);
564         
565         // Set Subnet
566         ioctl(fd, ioctl(fd, 3, "getset_subnet"), &subnet);
567         
568         close(fd);
569         
570         // Dump!
571         //DumpInterface( path+sizeof(IPSTACK_ROOT)+1 );
572         
573         return 0;
574 }
575
576 /**
577  * \brief Parse an IP Address
578  * \return 0 for unknown, 4 for IPv4 and 6 for IPv6
579  */
580 int ParseIPAddress(const char *Address, uint8_t *Dest, int *SubnetBits)
581 {
582         const char      *p = Address;
583         
584         // Check first block
585         while(*p && *p >= '0' && *p <= '9')     p ++;
586         
587         // IPv4?
588         if(*p == '.')
589         {
590                  int    i = 0, j;
591                  int    val;
592                 
593                 for( j = 0; Address[i] && j < 4; j ++ )
594                 {
595                         val = 0;
596                         for( ; '0' <= Address[i] && Address[i] <= '9'; i++ )
597                         {
598                                 val = val*10 + Address[i] - '0';
599                         }
600                         if(val > 255) {
601                                 //printf("val > 255 (%i)\n", val);
602                                 return 0;
603                         }
604                         Dest[j] = val;
605                         
606                         if(Address[i] == '.')
607                                 i ++;
608                 }
609                 if( j != 4 ) {
610                         //printf("4 parts expected, %i found\n", j);
611                         return 0;
612                 }
613                 // Parse subnet size
614                 if(Address[i] == '/') {
615                         val = 0;
616                         i ++;
617                         while('0' <= Address[i] && Address[i] <= '9') {
618                                 val *= 10;
619                                 val += Address[i] - '0';
620                                 i ++;
621                         }
622                         if(val > 32) {
623                                 printf("Notice: Subnet size >32 (%i)\n", val);
624                         }
625                         if(SubnetBits)  *SubnetBits = val;
626                 }
627                 if(Address[i] != '\0') {
628                         //printf("EOS != '\\0', '%c'\n", Address[i]);
629                         return 0;
630                 }
631                 return 4;
632         }
633         
634         // IPv6
635         if(*p == ':' || ('a' <= *p && *p <= 'f') || ('A' <= *p && *p <= 'F'))
636         {
637                  int    i = 0;
638                  int    j, k;
639                  int    val, split = -1, end;
640                 uint16_t        hi[8], low[8];
641                 
642                 for( j = 0; Address[i] && j < 8; j ++ )
643                 {
644                         if(Address[i] == '/')
645                                 break;
646                         
647                         if(Address[i] == ':') {
648                                 if(split != -1) {
649                                         printf("Two '::'s\n");
650                                         return 0;
651                                 }
652                                 split = j;
653                                 i ++;
654                                 continue;
655                         }
656                         
657                         val = 0;
658                         for( k = 0; Address[i] && Address[i] != ':' && Address[i] != '/'; i++, k++ )
659                         {
660                                 val *= 16;
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;
667                                 else {
668                                         printf("%c unexpected\n", Address[i]);
669                                         return 0;
670                                 }
671                         }
672                         
673                         if(val > 0xFFFF) {
674                                 printf("val (0x%x) > 0xFFFF\n", val);
675                                 return 0;
676                         }
677                         
678                         if(split == -1)
679                                 hi[j] = val;
680                         else
681                                 low[j-split] = val;
682                         
683                         if( Address[i] == ':' ) {
684                                 i ++;
685                         }
686                 }
687                 end = j;
688                 
689                 // Parse subnet size
690                 if(Address[i] == '/') {
691                         val = 0;
692                         while('0' <= Address[i] && Address[i] <= '9') {
693                                 val *= 10;
694                                 val += Address[i] - '0';
695                                 i ++;
696                         }
697                         if(val > 128) {
698                                 printf("Notice: Subnet size >128 (%i)\n", val);
699                         }
700                         if(SubnetBits)  *SubnetBits = val;
701                 }
702                 
703                 for( j = 0; j < split; j ++ )
704                 {
705                         //printf("%04x:", hi[j]);
706                         Dest[j*2] = hi[j]>>8;
707                         Dest[j*2+1] = hi[j]&0xFF;
708                 }
709                 for( ; j < 8 - (end - split); j++ )
710                 {
711                         //printf("0000:", hi[j]);
712                         Dest[j*2] = 0;
713                         Dest[j*2+1] = 0;
714                 }
715                 for( k = 0; j < 8; j ++, k++)
716                 {
717                         //printf("%04x:", low[k]);
718                         Dest[j*2] = low[k]>>8;
719                         Dest[j*2+1] = low[k]&0xFF;
720                 }
721                 return 6;
722         }
723         // Unknown type
724         return 0;
725 }

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