]> CyberLeo.Net >> Repos - FreeBSD/releng/10.0.git/blob - contrib/libpcap/pcap-sita.c
- Copy stable/10 (r259064) to releng/10.0 as part of the
[FreeBSD/releng/10.0.git] / contrib / libpcap / pcap-sita.c
1 /*
2  *  pcap-sita.c: Packet capture interface additions for SITA ACN devices
3  *
4  *  Copyright (c) 2007 Fulko Hew, SITA INC Canada, Inc <fulko.hew@sita.aero>
5  *
6  *  License: BSD
7  *
8  *  Redistribution and use in source and binary forms, with or without
9  *  modification, are permitted provided that the following conditions
10  *  are met:
11  *
12  *  1. Redistributions of source code must retain the above copyright
13  *     notice, this list of conditions and the following disclaimer.
14  *  2. Redistributions in binary form must reproduce the above copyright
15  *     notice, this list of conditions and the following disclaimer in
16  *     the documentation and/or other materials provided with the
17  *     distribution.
18  *  3. The names of the authors may not be used to endorse or promote
19  *     products derived from this software without specific prior
20  *     written permission.
21  *
22  *  THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
23  *  IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
24  *  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
25  */
26
27  /* $Id: pcap-sita.c */
28
29 #ifdef HAVE_CONFIG_H
30 #include "config.h"
31 #endif
32
33 #include <stdio.h>
34 #include <string.h>
35 #include <stdlib.h>
36 #include <unistd.h>
37 #include <fcntl.h>
38 #include <errno.h>
39 #include <sys/time.h>
40 #include <sys/socket.h>
41 #include <netinet/in.h>
42 #include <arpa/inet.h>
43 #include "pcap-int.h"
44
45 #include "pcap-sita.h"
46
47         /* non-configureable manifests follow */
48
49 #define IOP_SNIFFER_PORT        49152                   /* TCP port on the IOP used for 'distributed pcap' usage */
50 #define MAX_LINE_SIZE           255                             /* max size of a buffer/line in /etc/hosts we allow */
51 #define MAX_CHASSIS                     8                               /* number of chassis in an ACN site */
52 #define MAX_GEOSLOT                     8                               /* max number of access units in an ACN site */
53
54 #define FIND                    0
55 #define LIVE                    1
56
57 typedef struct iface {
58         struct iface    *next;                                  /* a pointer to the next interface */
59         char                    *name;                                  /* this interface's name on Wireshark */
60         char                    *IOPname;                               /* this interface's name on an IOP */
61         uint32_t                iftype;                                 /* the type of interface (DLT values) */
62 } iface_t;
63
64 typedef struct unit {
65         char                            *ip;                            /* this unit's IP address (as extracted from /etc/hosts) */
66         int                                     fd;                                     /* the connection to this unit (if it exists) */
67         int                                     find_fd;                        /* a big kludge to avoid my programming limitations since I could have this unit open for findalldevs purposes */
68         int                                     first_time;                     /* 0 = just opened via acn_open_live(),  ie. the first time, NZ = nth time */
69         struct sockaddr_in      *serv_addr;                     /* the address control block for comms to this unit */
70         int                                     chassis;
71         int                                     geoslot;
72         iface_t                         *iface;                         /* a pointer to a linked list of interface structures */
73         char                            *imsg;                          /* a pointer to an inbound message */
74         int                                     len;                            /* the current size of the inbound message */
75 } unit_t;
76
77 static char                     *errorString;
78 static unit_t           units[MAX_CHASSIS+1][MAX_GEOSLOT+1];    /* we use indexes of 1 through 8, but we reserve/waste index 0 */
79 static fd_set           readfds;                                                                /* a place to store the file descriptors for the connections to the IOPs */
80 static fd_set           working_set;
81 static int                      max_fs;
82 static char                     static_buf[32];
83
84 pcap_if_t                       *acn_if_list;                                                   /* pcap's list of available interfaces */
85
86 static void dump_interface_list(void) {
87         pcap_if_t               *iff;
88         pcap_addr_t             *addr;
89         int                             longest_name_len = 0;
90         char                    *n, *d, *f;
91         int                             if_number = 0;
92
93         iff = acn_if_list;
94         while (iff) {
95                 if (iff->name && (strlen(iff->name) > longest_name_len)) longest_name_len = strlen(iff->name);
96                 iff = iff->next;
97         }
98         iff = acn_if_list;
99         printf("Interface List:\n");
100         while (iff) {
101                 n = (iff->name)                                                 ? iff->name                     : "";
102                 d = (iff->description)                                  ? iff->description      : "";
103                 f = (iff->flags == PCAP_IF_LOOPBACK)    ? "L"                           : "";
104                 printf("%3d: %*s %s '%s'\n", if_number++, longest_name_len, n, f, d);
105                 addr = iff->addresses;
106                 while (addr) {
107                         printf("%*s ", (5 + longest_name_len), "");             /* add some indentation */
108                         printf("%15s  ", (addr->addr)           ? inet_ntoa(((struct sockaddr_in *)addr->addr)->sin_addr)               : "");
109                         printf("%15s  ", (addr->netmask)        ? inet_ntoa(((struct sockaddr_in *)addr->netmask)->sin_addr)    : "");
110                         printf("%15s  ", (addr->broadaddr)      ? inet_ntoa(((struct sockaddr_in *)addr->broadaddr)->sin_addr)  : "");
111                         printf("%15s  ", (addr->dstaddr)        ? inet_ntoa(((struct sockaddr_in *)addr->dstaddr)->sin_addr)    : "");
112                         printf("\n");
113                         addr = addr->next;
114                 }
115                 iff = iff->next;
116         }
117 }
118
119 static void dump(unsigned char *ptr, int i, int indent) {
120         fprintf(stderr, "%*s", indent, " ");
121         for (; i > 0; i--) {
122                 fprintf(stderr, "%2.2x ", *ptr++);
123         }
124         fprintf(stderr, "\n");
125 }
126
127 static void dump_interface_list_p(void) {
128         pcap_if_t               *iff;
129         pcap_addr_t             *addr;
130         int                             if_number = 0;
131
132         iff = acn_if_list;
133         printf("Interface Pointer @ %p is %p:\n", &acn_if_list, iff);
134         while (iff) {
135                 printf("%3d: %p %p next: %p\n", if_number++, iff->name, iff->description, iff->next);
136                 dump((unsigned char *)iff, sizeof(pcap_if_t), 5);
137                 addr = iff->addresses;
138                 while (addr) {
139                         printf("          %p %p %p %p, next: %p\n", addr->addr, addr->netmask, addr->broadaddr, addr->dstaddr, addr->next);
140                         dump((unsigned char *)addr, sizeof(pcap_addr_t), 10);
141                         addr = addr->next;
142                 }
143                 iff = iff->next;
144         }
145 }
146
147 static void dump_unit_table(void) {
148         int             chassis, geoslot;
149         iface_t *p;
150
151         printf("%c:%c %s %s\n", 'C', 'S', "fd", "IP Address");
152         for (chassis = 0; chassis <= MAX_CHASSIS; chassis++) {
153                 for (geoslot = 0; geoslot <= MAX_GEOSLOT; geoslot++) {
154                         if (units[chassis][geoslot].ip != NULL)
155                                 printf("%d:%d %2d %s\n", chassis, geoslot, units[chassis][geoslot].fd, units[chassis][geoslot].ip);
156                         p = units[chassis][geoslot].iface;
157                         while (p) {
158                                 char *n = (p->name)                     ? p->name                       : "";
159                                 char *i = (p->IOPname)          ? p->IOPname            : "";
160                                 p = p->next;
161                                 printf("   %12s    -> %12s\n", i, n);
162                         }
163                 }
164         }
165 }
166
167 static int find_unit_by_fd(int fd, int *chassis, int *geoslot, unit_t **unit_ptr) {
168         int             c, s;
169
170         for (c = 0; c <= MAX_CHASSIS; c++) {
171                 for (s = 0; s <= MAX_GEOSLOT; s++) {
172                         if (units[c][s].fd == fd || units[c][s].find_fd == fd) {
173                                 if (chassis)    *chassis = c;
174                                 if (geoslot)    *geoslot = s;
175                                 if (unit_ptr)   *unit_ptr = &units[c][s];
176                                 return 1;
177                         }
178                 }
179         }
180         return 0;
181 }
182
183 static int read_client_nbytes(int fd, int count, unsigned char *buf) {
184         unit_t                  *u;
185         int                             chassis, geoslot;
186         int                             len;
187
188         find_unit_by_fd(fd, &chassis, &geoslot, &u);
189         while (count) {
190                 if ((len = recv(fd, buf, count, 0)) <= 0)       return -1;      /* read in whatever data was sent to us */
191                 count -= len;   
192                 buf += len;
193         }                                                                                                                       /* till we have everything we are looking for */
194         return 0;
195 }
196
197 static void empty_unit_iface(unit_t *u) {
198         iface_t *p, *cur;
199
200         cur = u->iface;
201         while (cur) {                                                                                   /* loop over all the interface entries */
202                 if (cur->name)                  free(cur->name);                        /* throwing away the contents if they exist */
203                 if (cur->IOPname)               free(cur->IOPname);
204                 p = cur->next;
205                 free(cur);                                                                                      /* then throw away the structure itself */
206                 cur = p;
207         }
208         u->iface = 0;                                                                                   /* and finally remember that there are no remaining structure */
209 }
210
211 static void empty_unit(int chassis, int geoslot) {
212         unit_t  *u = &units[chassis][geoslot];
213
214         empty_unit_iface(u);
215         if (u->imsg) {                                                                                  /* then if an inbound message buffer exists */
216                 u->imsg = (char *)realloc(u->imsg, 1);                          /* and re-allocate the old large buffer into a new small one */
217                 if (u->imsg == NULL) {  /* oops, realloc call failed */
218                         fprintf(stderr, "Warning...call to realloc() failed, value of errno is %d\n", errno);
219                 
220         }
221 }
222
223 static void empty_unit_table(void) {
224         int             chassis, geoslot;
225
226         for (chassis = 0; chassis <= MAX_CHASSIS; chassis++) {
227                 for (geoslot = 0; geoslot <= MAX_GEOSLOT; geoslot++) {
228                         if (units[chassis][geoslot].ip != NULL) {
229                                 free(units[chassis][geoslot].ip);                       /* get rid of the malloc'ed space that holds the IP address */
230                                 units[chassis][geoslot].ip = 0;                         /* then set the pointer to NULL */
231                         }
232                         empty_unit(chassis, geoslot);
233                 }
234         }
235 }
236
237 static char *find_nth_interface_name(int n) {
238         int             chassis, geoslot;
239         iface_t *p;
240         char    *last_name = 0;
241
242         if (n < 0) n = 0;                                                                                               /* ensure we are working with a valid number */
243         for (chassis = 0; chassis <= MAX_CHASSIS; chassis++) {                  /* scan the table... */
244                 for (geoslot = 0; geoslot <= MAX_GEOSLOT; geoslot++) {
245                         if (units[chassis][geoslot].ip != NULL) {
246                                 p = units[chassis][geoslot].iface;
247                                 while (p) {                                                                                     /* and all interfaces... */
248                                         if (p->IOPname) last_name = p->name;                    /* remembering the last name found */
249                                         if (n-- == 0) return last_name;                                 /* and if we hit the instance requested */
250                                         p = p->next;
251                                 }
252                         }
253                 }
254         }
255                                                                                         /* if we couldn't fine the selected entry */
256         if (last_name)  return last_name;               /* ... but we did have at least one entry... return the last entry found */
257         return "";                                                              /* ... but if there wasn't any entry... return an empty string instead */
258 }
259
260 int acn_parse_hosts_file(char *errbuf) {                                /* returns: -1 = error, 0 = OK */
261         FILE    *fp;
262         char    buf[MAX_LINE_SIZE];
263         char    *ptr, *ptr2;
264         int             pos;
265         int             chassis, geoslot;
266         unit_t  *u;
267
268         empty_unit_table();
269         if ((fp = fopen("/etc/hosts", "r")) == NULL) {                                                                          /* try to open the hosts file and if it fails */
270                 snprintf(errbuf, PCAP_ERRBUF_SIZE, "Cannot open '/etc/hosts' for reading.");    /* return the nohostsfile error response */
271                 return -1;
272         }
273         while (fgets(buf, MAX_LINE_SIZE-1, fp)) {                       /* while looping over the file */
274
275                 pos = strcspn(buf, "#\n\r");                                    /* find the first comment character or EOL */
276                 *(buf + pos) = '\0';                                                    /* and clobber it and anything that follows it */
277
278                 pos = strspn(buf, " \t");                                               /* then find the first non-white space */
279                 if (pos == strlen(buf))                                                 /* if there is nothing but white space on the line */
280                         continue;                                                                       /* ignore that empty line */
281                 ptr = buf + pos;                                                                /* and skip over any of that leading whitespace */
282
283                 if ((ptr2 = strstr(ptr, "_I_")) == NULL)                /* skip any lines that don't have names that look like they belong to IOPs */
284                         continue;
285                 if (*(ptr2 + 4) != '_')                                                 /* and skip other lines that have names that don't look like ACN components */
286                         continue;
287                 *(ptr + strcspn(ptr, " \t")) = '\0';                    /* null terminate the IP address so its a standalone string */
288
289                 chassis = *(ptr2 + 3) - '0';                                    /* extract the chassis number */
290                 geoslot = *(ptr2 + 5) - '0';                                    /* and geo-slot number */
291                 if (chassis < 1 || chassis > MAX_CHASSIS ||
292                         geoslot < 1 || geoslot > MAX_GEOSLOT) {         /* if the chassis and/or slot numbers appear to be bad... */
293                         snprintf(errbuf, PCAP_ERRBUF_SIZE, "Invalid ACN name in '/etc/hosts'.");        /* warn the user */
294                         continue;                                                                                                                                       /* and ignore the entry */
295                 }
296                 if ((ptr2 = (char *)malloc(strlen(ptr) + 1)) == NULL) {
297                         snprintf(errbuf, PCAP_ERRBUF_SIZE, "malloc: %s", pcap_strerror(errno));
298                         continue;
299                 }
300                 strcpy(ptr2, ptr);                                                              /* copy the IP address into our malloc'ed memory */
301                 u = &units[chassis][geoslot];
302                 u->ip = ptr2;                                                                   /* and remember the whole shebang */
303                 u->chassis = chassis;
304                 u->geoslot = geoslot;
305         }
306         fclose(fp);
307         if (*errbuf)    return -1;
308         else                    return 0;
309 }
310
311 static int open_with_IOP(unit_t  *u, int flag) {
312         int                                     sockfd;
313         char                            *ip;
314
315         if (u->serv_addr == NULL) {
316                 u->serv_addr = malloc(sizeof(struct sockaddr_in));
317
318                 /* since we called malloc(), lets check to see if we actually got the memory    */
319                 if (u->serv_addr == NULL) {     /* oops, we didn't get the memory requested     */
320                         fprintf(stderr, "malloc() request for u->serv_addr failed, value of errno is: %d\n", errno);
321                         return 0;
322                 }
323
324         }
325         ip = u->ip;
326         /* bzero() is deprecated, replaced with memset()        */
327         memset((char *)u->serv_addr, 0, sizeof(struct sockaddr_in));
328         u->serv_addr->sin_family                = AF_INET;
329         u->serv_addr->sin_addr.s_addr   = inet_addr(ip);
330         u->serv_addr->sin_port                  = htons(IOP_SNIFFER_PORT);
331
332         if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
333                 fprintf(stderr, "pcap can't open a socket for connecting to IOP at %s\n", ip);
334                 return 0;
335         }
336         if (connect(sockfd, (struct sockaddr *)u->serv_addr, sizeof(struct sockaddr_in)) < 0) {
337                 fprintf(stderr, "pcap can't connect to IOP at %s\n", ip);
338                 return 0;
339         }
340         if (flag == LIVE)       u->fd = sockfd;
341         else                            u->find_fd = sockfd;
342         u->first_time = 0;
343         return sockfd;                  /* return the non-zero file descriptor as a 'success' indicator */
344 }
345
346 static void close_with_IOP(int chassis, int geoslot, int flag) {
347         int             *id;
348
349         if (flag == LIVE)       id = &units[chassis][geoslot].fd;
350         else                            id = &units[chassis][geoslot].find_fd;
351
352         if (*id) {                                                                              /* this was the last time, so... if we are connected... */
353                 close(*id);                                                                     /* disconnect us */
354                 *id = 0;                                                                        /* and forget that the descriptor exists because we are not open */
355         }
356 }
357
358 static void pcap_cleanup_acn(pcap_t *handle) {
359         int             chassis, geoslot;
360         unit_t  *u;
361
362         if (find_unit_by_fd(handle->fd, &chassis, &geoslot, &u) == 0)
363                 return;
364         close_with_IOP(chassis, geoslot, LIVE);
365         if (u)
366                 u->first_time = 0;
367         pcap_cleanup_live_common(handle);
368 }
369
370 static void send_to_fd(int fd, int len, unsigned char *str) {
371         int             nwritten;
372         int             chassis, geoslot;
373
374         while (len > 0) {
375                 if ((nwritten = write(fd, str, len)) <= 0) {
376                         find_unit_by_fd(fd, &chassis, &geoslot, NULL);
377                         if (units[chassis][geoslot].fd == fd)                   close_with_IOP(chassis, geoslot, LIVE);
378                         else if (units[chassis][geoslot].find_fd == fd) close_with_IOP(chassis, geoslot, FIND);
379                         empty_unit(chassis, geoslot);
380                         return;
381                 }
382                 len -= nwritten;
383                 str += nwritten;
384         }
385 }
386
387 static void acn_freealldevs(void) {
388
389         pcap_if_t       *iff, *next_iff;
390         pcap_addr_t     *addr, *next_addr;
391
392         for (iff = acn_if_list; iff != NULL; iff = next_iff) {
393                 next_iff = iff->next;
394                 for (addr = iff->addresses; addr != NULL; addr = next_addr) {
395                         next_addr = addr->next;
396                         if (addr->addr)                 free(addr->addr);
397                         if (addr->netmask)              free(addr->netmask);
398                         if (addr->broadaddr)    free(addr->broadaddr);
399                         if (addr->dstaddr)              free(addr->dstaddr);
400                         free(addr);
401                 }
402                 if (iff->name)                  free(iff->name);
403                 if (iff->description)   free(iff->description);
404                 free(iff);
405         }
406 }
407
408 static char *nonUnified_port_num(unit_t *u, int IOPportnum) {
409
410         sprintf(static_buf, "%d_%d", u->chassis, u->geoslot);
411         return static_buf;
412 }
413
414 static char *unified_port_num(unit_t *u, int IOPportnum) {
415         int                     portnum;
416
417         portnum = ((u->chassis - 1) * 64) + ((u->geoslot - 1) * 8) + IOPportnum + 1;
418         sprintf(static_buf, "%d", portnum);
419         return static_buf;
420 }
421
422 static char *translate_IOP_to_pcap_name(unit_t *u, char *IOPname, bpf_u_int32 iftype) {
423         iface_t         *iface_ptr, *iface;
424         char            *name;
425         char            buf[32];
426         char            *proto;
427         char            *port;
428         int                     IOPportnum = 0;
429
430         iface = malloc(sizeof(iface_t));                /* get memory for a structure */
431         if (iface == NULL) {    /* oops, we didn't get the memory requested     */
432                 fprintf(stderr, "Error...couldn't allocate memory for interface structure...value of errno is: %d\n", errno);
433                 return NULL;
434         }
435         memset((char *)iface, 0, sizeof(iface_t));      /* bzero is deprecated(), replaced with memset() */
436
437         iface->iftype = iftype;                                 /* remember the interface type of this interface */
438
439         name = malloc(strlen(IOPname) + 1);             /* get memory for the IOP's name */
440         if (name == NULL) {    /* oops, we didn't get the memory requested     */
441                 fprintf(stderr, "Error...couldn't allocate memory for IOPname...value of errno is: %d\n", errno);
442                 return NULL;
443         }
444
445         strcpy(name, IOPname);                                  /* and copy it in */
446         iface->IOPname = name;                                  /* and stick it into the structure */
447
448         if (strncmp(IOPname, "lo", 2) == 0) {
449                 IOPportnum = atoi(&IOPname[2]);
450                 switch (iftype) {
451                         case DLT_EN10MB:        proto = "lo";           port = nonUnified_port_num(u, IOPportnum);      break;
452                         default:                        proto = "???";          port = unified_port_num(u, IOPportnum);         break;
453                 }
454         } else if (strncmp(IOPname, "eth", 3) == 0) {
455                 IOPportnum = atoi(&IOPname[3]);
456                 switch (iftype) {
457                         case DLT_EN10MB:        proto = "eth";          port = nonUnified_port_num(u, IOPportnum);      break;
458                         default:                        proto = "???";          port = unified_port_num(u, IOPportnum);         break;
459                 }
460         } else if (strncmp(IOPname, "wan", 3) == 0) {
461                 IOPportnum = atoi(&IOPname[3]);
462                 switch (iftype) {
463                         case DLT_SITA:          proto = "wan";          port = unified_port_num(u, IOPportnum);         break;
464                         default:                        proto = "???";          port = unified_port_num(u, IOPportnum);         break;
465                 }
466         }
467
468         sprintf(buf, "%s_%s", proto, port);             /* compose the user's name for that IOP port name */
469         name = malloc(strlen(buf) + 1);                 /* get memory for that name */
470         if (name == NULL) {    /* oops, we didn't get the memory requested     */
471                 fprintf(stderr, "Error...couldn't allocate memory for IOP port name...value of errno is: %d\n", errno);
472                 return NULL;
473         }
474
475         strcpy(name, buf);                                              /* and copy it in */
476         iface->name = name;                                             /* and stick it into the structure */
477
478         if (u->iface == 0) {                                    /* if this is the first name */
479                 u->iface = iface;                                       /* stick this entry at the head of the list */
480         } else {
481                 iface_ptr = u->iface;
482                 while (iface_ptr->next) {                       /* othewise scan the list */
483                         iface_ptr = iface_ptr->next;    /* till we're at the last entry */
484                 }
485                 iface_ptr->next = iface;                        /* then tack this entry on the end of the list */
486         }
487         return iface->name;
488 }
489
490 static int if_sort(char *s1, char *s2) {
491         char    *s1_p2, *s2_p2;
492         char    str1[MAX_LINE_SIZE], str2[MAX_LINE_SIZE];
493         int             s1_p1_len, s2_p1_len;
494         int             retval;
495
496         if ((s1_p2 = strchr(s1, '_'))) {        /* if an underscore is found... */
497                 s1_p1_len = s1_p2 - s1;                 /* the prefix length is the difference in pointers */
498                 s1_p2++;                                                /* the suffix actually starts _after_ the underscore */
499         } else {                                                        /* otherwise... */
500                 s1_p1_len = strlen(s1);                 /* the prefix length is the length of the string itself */
501                 s1_p2 = 0;                                              /* and there is no suffix */
502         }
503         if ((s2_p2 = strchr(s2, '_'))) {        /* now do the same for the second string */
504                 s2_p1_len = s2_p2 - s2;
505                 s2_p2++;
506         } else {
507                 s2_p1_len = strlen(s2);
508                 s2_p2 = 0;
509         }
510         strncpy(str1, s1, (s1_p1_len > sizeof(str1)) ? s1_p1_len : sizeof(str1));   *(str1 + s1_p1_len) = 0;
511         strncpy(str2, s2, (s2_p1_len > sizeof(str2)) ? s2_p1_len : sizeof(str2));   *(str2 + s2_p1_len) = 0;
512         retval = strcmp(str1, str2);
513         if (retval != 0) return retval;         /* if they are not identical, then we can quit now and return the indication */
514         return strcmp(s1_p2, s2_p2);            /* otherwise we return the result of comparing the 2nd half of the string */
515 }
516
517 static void sort_if_table(void) {
518         pcap_if_t       *p1, *p2, *prev, *temp;
519         int                     has_swapped;
520
521         if (!acn_if_list) return;                               /* nothing to do if the list is empty */
522
523         while (1) {
524                 p1 = acn_if_list;                                       /* start at the head of the list */
525                 prev = 0;
526                 has_swapped = 0;
527                 while ((p2 = p1->next)) {
528                         if (if_sort(p1->name, p2->name) > 0) {
529                                 if (prev) {                                     /* we are swapping things that are _not_ at the head of the list */
530                                         temp = p2->next;
531                                         prev->next = p2;
532                                         p2->next = p1;
533                                         p1->next = temp;
534                                 } else {                                        /* special treatment if we are swapping with the head of the list */
535                                         temp = p2->next;
536                                         acn_if_list= p2;
537                                         p2->next = p1;
538                                         p1->next = temp;
539                                 }
540                                 p1 = p2;
541                                 prev = p1;
542                                 has_swapped = 1;
543                         }
544                         prev = p1;
545                         p1 = p1->next;
546                 }
547                 if (has_swapped == 0)
548                         return;
549         }       
550         return;
551 }
552         
553 static int process_client_data (char *errbuf) {                                                         /* returns: -1 = error, 0 = OK */
554         int                                     chassis, geoslot;
555         unit_t                          *u;
556         pcap_if_t                       *iff, *prev_iff;
557         pcap_addr_t                     *addr, *prev_addr;
558         char                            *ptr;
559         int                                     address_count;
560         struct sockaddr_in      *s;
561         char                            *newname;
562         bpf_u_int32                             interfaceType;
563         unsigned char           flags;
564
565         prev_iff = 0;
566         for (chassis = 0; chassis <= MAX_CHASSIS; chassis++) {
567                 for (geoslot = 0; geoslot <= MAX_GEOSLOT; geoslot++) {                          /* now loop over all the devices */
568                         u = &units[chassis][geoslot];
569                         empty_unit_iface(u);
570                         ptr = u->imsg;                                                                                                  /* point to the start of the msg for this IOP */
571                         while (ptr < (u->imsg + u->len)) {
572                                 if ((iff = malloc(sizeof(pcap_if_t))) == NULL) {
573                                         snprintf(errbuf, PCAP_ERRBUF_SIZE, "malloc: %s", pcap_strerror(errno));
574                                         return -1;
575                                 }
576                                 memset((char *)iff, 0, sizeof(pcap_if_t)); /* bzero() is deprecated, replaced with memset() */
577                                 if (acn_if_list == 0)   acn_if_list = iff;                                      /* remember the head of the list */
578                                 if (prev_iff)                   prev_iff->next = iff;                           /* insert a forward link */
579
580                                 if (*ptr) {                                                                                                     /* if there is a count for the name */
581                                         if ((iff->name = malloc(*ptr + 1)) == NULL) {                   /* get that amount of space */
582                                                 snprintf(errbuf, PCAP_ERRBUF_SIZE, "malloc: %s", pcap_strerror(errno));
583                                                 return -1;
584                                         }
585                                         memcpy(iff->name, (ptr + 1), *ptr);                                             /* copy the name into the malloc'ed space */
586                                         *(iff->name + *ptr) = 0;                                                                /* and null terminate the string */
587                                         ptr += *ptr;                                                                                    /* now move the pointer forwards by the length of the count plus the length of the string */
588                                 }
589                                 ptr++;
590
591                                 if (*ptr) {                                                                                                     /* if there is a count for the description */
592                                         if ((iff->description = malloc(*ptr + 1)) == NULL) {    /* get that amount of space */
593                                                 snprintf(errbuf, PCAP_ERRBUF_SIZE, "malloc: %s", pcap_strerror(errno));
594                                                 return -1;
595                                         }
596                                         memcpy(iff->description, (ptr + 1), *ptr);                              /* copy the name into the malloc'ed space */
597                                         *(iff->description + *ptr) = 0;                                                 /* and null terminate the string */
598                                         ptr += *ptr;                                                                                    /* now move the pointer forwards by the length of the count plus the length of the string */
599                                 }
600                                 ptr++;
601
602                                 interfaceType = ntohl(*(bpf_u_int32 *)ptr);
603                                 ptr += 4;                                                                                                       /* skip over the interface type */
604
605                                 flags = *ptr++;
606                                 if (flags) iff->flags = PCAP_IF_LOOPBACK;                                       /* if this is a loopback style interface, lets mark it as such */
607
608                                 address_count = *ptr++;
609
610                                 prev_addr = 0;
611                                 while (address_count--) {
612                                         if ((addr = malloc(sizeof(pcap_addr_t))) == NULL) {
613                                                 snprintf(errbuf, PCAP_ERRBUF_SIZE, "malloc: %s", pcap_strerror(errno));
614                                                 return -1;
615                                         }
616 +                                       memset((char *)addr, 0, sizeof(pcap_addr_t)); /* bzero() is deprecated, replaced with memset() */
617                                         if (iff->addresses == 0) iff->addresses = addr;
618                                         if (prev_addr) prev_addr->next = addr;                                                  /* insert a forward link */
619                                         if (*ptr) {                                                                                                             /* if there is a count for the address */
620                                                 if ((s = malloc(sizeof(struct sockaddr_in))) == NULL) {         /* get that amount of space */
621                                                         snprintf(errbuf, PCAP_ERRBUF_SIZE, "malloc: %s", pcap_strerror(errno));
622                                                         return -1;
623                                                 }
624                                                 memset((char *)s, 0, sizeof(struct sockaddr_in)); /* bzero() is deprecated, replaced with memset() */
625                                                 addr->addr = (struct sockaddr *)s;
626                                                 s->sin_family           = AF_INET;
627                                                 s->sin_addr.s_addr      = *(bpf_u_int32 *)(ptr + 1);                    /* copy the address in */
628                                                 ptr += *ptr;                                                                            /* now move the pointer forwards according to the specified length of the address */
629                                         }
630                                         ptr++;                                                                                                  /* then forwards one more for the 'length of the address' field */
631                                         if (*ptr) {                                                                                             /* process any netmask */
632                                                 if ((s = malloc(sizeof(struct sockaddr_in))) == NULL) {
633                                                         snprintf(errbuf, PCAP_ERRBUF_SIZE, "malloc: %s", pcap_strerror(errno));
634                                                         return -1;
635                                                 }
636                                                 /* bzero() is deprecated, replaced with memset() */
637                                                 memset((char *)s, 0, sizeof(struct sockaddr_in));
638
639                                                 addr->netmask = (struct sockaddr *)s;
640                                                 s->sin_family           = AF_INET;
641                                                 s->sin_addr.s_addr      = *(bpf_u_int32*)(ptr + 1);
642                                                 ptr += *ptr;
643                                         }
644                                         ptr++;
645                                         if (*ptr) {                                                                                             /* process any broadcast address */
646                                                 if ((s = malloc(sizeof(struct sockaddr_in))) == NULL) {
647                                                         snprintf(errbuf, PCAP_ERRBUF_SIZE, "malloc: %s", pcap_strerror(errno));
648                                                         return -1;
649                                                 }
650                                                 /* bzero() is deprecated, replaced with memset() */
651                                                 memset((char *)s, 0, sizeof(struct sockaddr_in));
652
653                                                 addr->broadaddr = (struct sockaddr *)s;
654                                                 s->sin_family           = AF_INET;
655                                                 s->sin_addr.s_addr      = *(bpf_u_int32*)(ptr + 1);
656                                                 ptr += *ptr;
657                                         }
658                                         ptr++;
659                                         if (*ptr) {                                                                                             /* process any destination address */
660                                                 if ((s = malloc(sizeof(struct sockaddr_in))) == NULL) {
661                                                         snprintf(errbuf, PCAP_ERRBUF_SIZE, "malloc: %s", pcap_strerror(errno));
662                                                         return -1;
663                                                 }
664                                                 /* bzero() is deprecated, replaced with memset() */
665                                                 memset((char *)s, 0, sizeof(struct sockaddr_in));
666
667                                                 addr->dstaddr = (struct sockaddr *)s;
668                                                 s->sin_family           = AF_INET;
669                                                 s->sin_addr.s_addr      = *(bpf_u_int32*)(ptr + 1);
670                                                 ptr += *ptr;
671                                         }
672                                         ptr++;
673                                         prev_addr = addr;
674                                 }
675                                 prev_iff = iff;
676
677                                 newname = translate_IOP_to_pcap_name(u, iff->name, interfaceType);              /* add a translation entry and get a point to the mangled name */
678                                 if ((iff->name = realloc(iff->name, strlen(newname) + 1)) == NULL) {    /* we now re-write the name stored in the interface list */
679                                         snprintf(errbuf, PCAP_ERRBUF_SIZE, "realloc: %s", pcap_strerror(errno));
680                                         return -1;
681                                 }
682                                 strcpy(iff->name, newname);                                                                                             /* to this new name */
683                         }
684                 }
685         }
686         return 0;
687 }
688
689 static int read_client_data (int fd) {
690         unsigned char   buf[256];
691         int                             chassis, geoslot;
692         unit_t                  *u;
693         int                             len;
694
695         find_unit_by_fd(fd, &chassis, &geoslot, &u);
696
697         if ((len = recv(fd, buf, sizeof(buf), 0)) <= 0) return 0;       /* read in whatever data was sent to us */
698
699         if ((u->imsg = realloc(u->imsg, (u->len + len))) == NULL)       /* extend the buffer for the new data */
700                 return 0;
701         memcpy((u->imsg + u->len), buf, len);                                           /* append the new data */
702         u->len += len;
703         return 1;
704 }
705
706 static void wait_for_all_answers(void) {
707         int             retval;
708         struct  timeval tv;
709         int             fd;
710         int             chassis, geoslot;
711
712         tv.tv_sec = 2;
713         tv.tv_usec = 0;
714
715         while (1) {
716                 int flag = 0;
717                 for (fd = 0; fd <= max_fs; fd++) {                                                              /* scan the list of descriptors we may be listening to */
718                         if (FD_ISSET(fd, &readfds)) flag = 1;                                           /* and see if there are any still set */
719                 }
720                 if (flag == 0) return;                                                                                  /* we are done, when they are all gone */
721
722                 memcpy(&working_set, &readfds, sizeof(readfds));                                /* otherwise, we still have to listen for more stuff, till we timeout */
723                 retval = select(max_fs + 1, &working_set, NULL, NULL, &tv);
724                 if (retval == -1) {                                                                                             /* an error occured !!!!! */
725                         return;
726                 } else if (retval == 0) {                                                                               /* timeout occured, so process what we've got sofar and return */
727                         printf("timeout\n");
728                         return;
729                 } else {
730                         for (fd = 0; fd <= max_fs; fd++) {                                                      /* scan the list of things to do, and do them */
731                                 if (FD_ISSET(fd, &working_set)) {
732                                         if (read_client_data(fd) == 0) {                                        /* if the socket has closed */
733                                                 FD_CLR(fd, &readfds);                                                   /* and descriptors we listen to for errors */
734                                                 find_unit_by_fd(fd, &chassis, &geoslot, NULL);
735                                                 close_with_IOP(chassis, geoslot, FIND);                 /* and close out connection to him */
736                                         }
737                                 }
738                         }
739                 }
740         }
741 }
742
743 static char *get_error_response(int fd, char *errbuf) {         /* return a pointer on error, NULL on no error */
744         char    byte;
745         int             len = 0;
746
747         while (1) {
748                 recv(fd, &byte, 1, 0);                                                  /* read another byte in */
749                 if (errbuf && (len++ < PCAP_ERRBUF_SIZE)) {             /* and if there is still room in the buffer */
750                         *errbuf++ = byte;                                                       /* stick it in */
751                         *errbuf = '\0';                                                         /* ensure the string is null terminated just in case we might exceed the buffer's size */
752                 }
753                 if (byte == '\0') {
754                         if (len > 1)    { return errbuf;        }
755                         else                    { return NULL;          }
756                 }
757         }
758 }
759
760 int acn_findalldevs(char *errbuf) {                                                             /* returns: -1 = error, 0 = OK */
761         int             chassis, geoslot;
762         unit_t  *u;
763
764         FD_ZERO(&readfds);
765         max_fs = 0;
766         for (chassis = 0; chassis <= MAX_CHASSIS; chassis++) {
767                 for (geoslot = 0; geoslot <= MAX_GEOSLOT; geoslot++) {
768                         u = &units[chassis][geoslot];
769                         if (u->ip && (open_with_IOP(u, FIND))) {                        /* connect to the remote IOP */
770                                 send_to_fd(u->find_fd, 1, (unsigned char *)"\0");
771                                 if (get_error_response(u->find_fd, errbuf))
772                                         close_with_IOP(chassis, geoslot, FIND);
773                                 else {
774                                         if (u->find_fd > max_fs)
775                                                 max_fs = u->find_fd;                                                            /* remember the highest number currently in use */
776                                         FD_SET(u->find_fd, &readfds);                                           /* we are going to want to read this guy's response to */
777                                         u->len = 0;
778                                         send_to_fd(u->find_fd, 1, (unsigned char *)"Q");                /* this interface query request */
779                                 }
780                         }
781                 }
782         }
783         wait_for_all_answers();
784         if (process_client_data(errbuf))
785                 return -1;
786         sort_if_table();
787         return 0;
788 }
789
790 static int pcap_stats_acn(pcap_t *handle, struct pcap_stat *ps) {
791         unsigned char   buf[12];
792
793         send_to_fd(handle->fd, 1, (unsigned char *)"S");                                                /* send the get_stats command to the IOP */
794
795         if (read_client_nbytes(handle->fd, sizeof(buf), buf) == -1) return -1;  /* try reading the required bytes */
796
797         ps->ps_recv             = ntohl(*(uint32_t *)&buf[0]);                                                  /* break the buffer into its three 32 bit components */
798         ps->ps_drop             = ntohl(*(uint32_t *)&buf[4]);
799         ps->ps_ifdrop   = ntohl(*(uint32_t *)&buf[8]);
800
801         return 0;
802 }
803
804 static int acn_open_live(const char *name, char *errbuf, int *linktype) {               /* returns 0 on error, else returns the file descriptor */
805         int                     chassis, geoslot;
806         unit_t          *u;
807         iface_t         *p;
808         pcap_if_t       *alldevsp;
809
810         pcap_findalldevs_interfaces(&alldevsp, errbuf);
811         for (chassis = 0; chassis <= MAX_CHASSIS; chassis++) {                                                                          /* scan the table... */
812                 for (geoslot = 0; geoslot <= MAX_GEOSLOT; geoslot++) {
813                         u = &units[chassis][geoslot];
814                         if (u->ip != NULL) {
815                                 p = u->iface;
816                                 while (p) {                                                                                                                                             /* and all interfaces... */
817                                         if (p->IOPname && p->name && (strcmp(p->name, name) == 0)) {                            /* and if we found the interface we want... */
818                                                 *linktype = p->iftype;
819                                                 open_with_IOP(u, LIVE);                                                                                                 /* start a connection with that IOP */
820                                                 send_to_fd(u->fd, strlen(p->IOPname)+1, (unsigned char *)p->IOPname);   /* send the IOP's interface name, and a terminating null */
821                                                 if (get_error_response(u->fd, errbuf)) {
822                                                         return -1;
823                                                 }
824                                                 return u->fd;                                                                                                                   /* and return that open descriptor */
825                                         }
826                                         p = p->next;
827                                 }
828                         }
829                 }
830         }
831         return -1;                                                                                                                                                              /* if the interface wasn't found, return an error */
832 }
833
834 static void acn_start_monitor(int fd, int snaplen, int timeout, int promiscuous, int direction) {
835         unsigned char   buf[8];
836         unit_t                  *u;
837
838         //printf("acn_start_monitor()\n");                              // fulko
839         find_unit_by_fd(fd, NULL, NULL, &u);
840         if (u->first_time == 0) {
841                 buf[0]                                  = 'M';
842                 *(uint32_t *)&buf[1]    = htonl(snaplen);
843                 buf[5]                                  = timeout;
844                 buf[6]                                  = promiscuous;
845                 buf[7]                                  = direction;
846         //printf("acn_start_monitor() first time\n");                           // fulko
847                 send_to_fd(fd, 8, buf);                                                         /* send the start monitor command with its parameters to the IOP */
848                 u->first_time = 1;
849         }
850         //printf("acn_start_monitor() complete\n");                             // fulko
851 }
852
853 static int pcap_inject_acn(pcap_t *p, const void *buf _U_, size_t size _U_) {
854         strlcpy(p->errbuf, "Sending packets isn't supported on ACN adapters",
855             PCAP_ERRBUF_SIZE);
856         return (-1);
857 }
858
859 static int pcap_setfilter_acn(pcap_t *handle, struct bpf_program *bpf) {
860         int                             fd = handle->fd;
861         int                             count;
862         struct bpf_insn *p;
863         uint16_t                shortInt;
864         uint32_t                longInt;
865
866         send_to_fd(fd, 1, (unsigned char *)"F");                        /* BPF filter follows command */
867         count = bpf->bf_len;
868         longInt = htonl(count);
869         send_to_fd(fd, 4, (unsigned char *)&longInt);           /* send the instruction sequence count */
870         p = bpf->bf_insns;
871         while (count--) {                                                                       /* followed by the list of instructions */
872                 shortInt = htons(p->code);
873                 longInt = htonl(p->k);
874                 send_to_fd(fd, 2, (unsigned char *)&shortInt);
875                 send_to_fd(fd, 1, (unsigned char *)&p->jt);
876                 send_to_fd(fd, 1, (unsigned char *)&p->jf);
877                 send_to_fd(fd, 4, (unsigned char *)&longInt);
878                 p++;
879         }
880         if (get_error_response(fd, NULL))
881                 return -1;
882         return 0;
883 }
884
885 static int pcap_setdirection_acn(pcap_t *handle, pcap_direction_t d) {
886         snprintf(handle->errbuf, sizeof(handle->errbuf),
887             "Setting direction is not supported on ACN adapters");
888         return -1;
889 }
890
891 static int acn_read_n_bytes_with_timeout(pcap_t *handle, int count) {
892         struct          timeval tv;
893         int                     retval, fd;
894         fd_set          r_fds;
895         fd_set          w_fds;
896         u_char          *bp;
897         int                     len = 0;
898         int                     offset = 0;
899
900         tv.tv_sec = 5;
901         tv.tv_usec = 0;
902
903         fd = handle->fd;
904         FD_ZERO(&r_fds);
905         FD_SET(fd, &r_fds);
906         memcpy(&w_fds, &r_fds, sizeof(r_fds));
907         bp = handle->bp;
908         while (count) {
909                 retval = select(fd + 1, &w_fds, NULL, NULL, &tv);
910                 if (retval == -1) {                                                                                     /* an error occured !!!!! */
911 //                      fprintf(stderr, "error during packet data read\n");
912                         return -1;                                                                                              /* but we need to return a good indication to prevent unneccessary popups */
913                 } else if (retval == 0) {                                                                       /* timeout occured, so process what we've got sofar and return */
914 //                      fprintf(stderr, "timeout during packet data read\n");
915                         return -1;
916                 } else {
917                         if ((len = recv(fd, (bp + offset), count, 0)) <= 0) {
918 //                              fprintf(stderr, "premature exit during packet data rx\n");
919                                 return -1;
920                         }
921                         count -= len;
922                         offset += len;
923                 }
924         }
925         return 0;
926 }
927
928 static int pcap_read_acn(pcap_t *handle, int max_packets, pcap_handler callback, u_char *user) {
929         #define HEADER_SIZE (4 * 4)
930         unsigned char           packet_header[HEADER_SIZE];
931         struct pcap_pkthdr      pcap_header;
932
933         //printf("pcap_read_acn()\n");                  // fulko
934         acn_start_monitor(handle->fd, handle->snapshot, handle->md.timeout, handle->md.clear_promisc, handle->direction);       /* maybe tell him to start monitoring */
935         //printf("pcap_read_acn() after start monitor\n");                      // fulko
936
937         handle->bp = packet_header;
938         if (acn_read_n_bytes_with_timeout(handle, HEADER_SIZE) == -1) return 0;                 /* try to read a packet header in so we can get the sizeof the packet data */
939
940         pcap_header.ts.tv_sec   = ntohl(*(uint32_t *)&packet_header[0]);                                /* tv_sec */
941         pcap_header.ts.tv_usec  = ntohl(*(uint32_t *)&packet_header[4]);                                /* tv_usec */
942         pcap_header.caplen              = ntohl(*(uint32_t *)&packet_header[8]);                                /* caplen */
943         pcap_header.len                 = ntohl(*(uint32_t *)&packet_header[12]);                               /* len */
944
945         handle->bp = handle->buffer + handle->offset;                                                                   /* start off the receive pointer at the right spot */
946         if (acn_read_n_bytes_with_timeout(handle, pcap_header.caplen) == -1) return 0;  /* then try to read in the rest of the data */
947
948         callback(user, &pcap_header, handle->bp);                                                                               /* call the user supplied callback function */
949         return 1;
950 }
951
952 static int pcap_activate_sita(pcap_t *handle) {
953         int             fd;
954
955         if (handle->opt.rfmon) {
956                 /*
957                  * No monitor mode on SITA devices (they're not Wi-Fi
958                  * devices).
959                  */
960                 return PCAP_ERROR_RFMON_NOTSUP;
961         }
962
963         /* Initialize some components of the pcap structure. */
964
965         handle->inject_op = pcap_inject_acn;
966         handle->setfilter_op = pcap_setfilter_acn;
967         handle->setdirection_op = pcap_setdirection_acn;
968         handle->set_datalink_op = NULL; /* can't change data link type */
969         handle->getnonblock_op = pcap_getnonblock_fd;
970         handle->setnonblock_op = pcap_setnonblock_fd;
971         handle->cleanup_op = pcap_cleanup_acn;
972         handle->read_op = pcap_read_acn;
973         handle->stats_op = pcap_stats_acn;
974
975         fd = acn_open_live(handle->opt.source, handle->errbuf,
976             &handle->linktype);
977         if (fd == -1)
978                 return PCAP_ERROR;
979         handle->md.clear_promisc = handle->md.promisc;
980         handle->fd = fd;
981         handle->bufsize = handle->snapshot;
982
983         /* Allocate the buffer */
984
985         handle->buffer   = malloc(handle->bufsize + handle->offset);
986         if (!handle->buffer) {
987                 snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
988                          "malloc: %s", pcap_strerror(errno));
989                 pcap_cleanup_acn(handle);
990                 return PCAP_ERROR;
991         }
992
993         /*
994          * "handle->fd" is a socket, so "select()" and "poll()"
995          * should work on it.
996          */
997         handle->selectable_fd = handle->fd;
998
999         return 0;
1000 }
1001
1002 pcap_t *pcap_create_interface(const char *device, char *ebuf) {
1003         pcap_t *p;
1004
1005         p = pcap_create_common(device, ebuf);
1006         if (p == NULL)
1007                 return (NULL);
1008
1009         p->activate_op = pcap_activate_sita;
1010         return (p);
1011 }