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