libpcap  1.10.1
About: libpcap is a packet filter library used by tools like tcpdump.
  Fossies Dox: libpcap-1.10.1.tar.gz  ("unofficial" and yet experimental doxygen-generated source code documentation)  

pcap-haiku.cpp
Go to the documentation of this file.
1 /*
2  * Copyright 2006-2010, Haiku, Inc. All Rights Reserved.
3  * Distributed under the terms of the MIT License.
4  *
5  * Authors:
6  * Axel Dörfler, axeld@pinc-software.de
7  * James Woodcock
8  */
9 
10 
11 #include "config.h"
12 #include "pcap-int.h"
13 
14 #include <OS.h>
15 
16 #include <sys/socket.h>
17 #include <sys/sockio.h>
18 
19 #include <net/if.h>
20 #include <net/if_dl.h>
21 #include <net/if_types.h>
22 
23 #include <errno.h>
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <string.h>
27 
28 
29 /*
30  * Private data for capturing on Haiku sockets.
31  */
32 struct pcap_haiku {
33  struct pcap_stat stat;
34  char *device; /* device name */
35 };
36 
37 
38 bool
39 prepare_request(struct ifreq& request, const char* name)
40 {
41  if (strlen(name) >= IF_NAMESIZE)
42  return false;
43 
44  strcpy(request.ifr_name, name);
45  return true;
46 }
47 
48 
49 static int
50 pcap_read_haiku(pcap_t* handle, int maxPackets, pcap_handler callback,
51  u_char* userdata)
52 {
53  // Receive a single packet
54 
55  struct pcap_haiku* handlep = (struct pcap_haiku*)handle->priv;
56  u_char* buffer = (u_char*)handle->buffer + handle->offset;
57  struct sockaddr_dl from;
58  ssize_t bytesReceived;
59  do {
60  if (handle->break_loop) {
61  // Clear the break loop flag, and return -2 to indicate our
62  // reasoning
63  handle->break_loop = 0;
64  return -2;
65  }
66 
67  socklen_t fromLength = sizeof(from);
68  bytesReceived = recvfrom(handle->fd, buffer, handle->bufsize, MSG_TRUNC,
69  (struct sockaddr*)&from, &fromLength);
70  } while (bytesReceived < 0 && errno == B_INTERRUPTED);
71 
72  if (bytesReceived < 0) {
73  if (errno == B_WOULD_BLOCK) {
74  // there is no packet for us
75  return 0;
76  }
77 
78  snprintf(handle->errbuf, sizeof(handle->errbuf),
79  "recvfrom: %s", strerror(errno));
80  return -1;
81  }
82 
83  int32 captureLength = bytesReceived;
84  if (captureLength > handle->snapshot)
85  captureLength = handle->snapshot;
86 
87  // run the packet filter
88  if (handle->fcode.bf_insns) {
89  if (pcap_filter(handle->fcode.bf_insns, buffer, bytesReceived,
90  captureLength) == 0) {
91  // packet got rejected
92  return 0;
93  }
94  }
95 
96  // fill in pcap_header
97  pcap_pkthdr header;
98  header.caplen = captureLength;
99  header.len = bytesReceived;
100  header.ts.tv_usec = system_time() % 1000000;
101  header.ts.tv_sec = system_time() / 1000000;
102  // TODO: get timing from packet!!!
103 
104  /* Call the user supplied callback function */
105  callback(userdata, &header, buffer);
106  return 1;
107 }
108 
109 
110 static int
111 pcap_inject_haiku(pcap_t *handle, const void *buffer, int size)
112 {
113  // we don't support injecting packets yet
114  // TODO: use the AF_LINK protocol (we need another socket for this) to
115  // inject the packets
116  strlcpy(handle->errbuf, "Sending packets isn't supported yet",
118  return -1;
119 }
120 
121 
122 static int
123 pcap_stats_haiku(pcap_t *handle, struct pcap_stat *stats)
124 {
125  struct pcap_haiku* handlep = (struct pcap_haiku*)handle->priv;
126  ifreq request;
127  int socket = ::socket(AF_INET, SOCK_DGRAM, 0);
128  if (socket < 0) {
129  return -1;
130  }
131  prepare_request(request, handlep->device);
132  if (ioctl(socket, SIOCGIFSTATS, &request, sizeof(struct ifreq)) < 0) {
133  snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "pcap_stats: %s",
134  strerror(errno));
135  close(socket);
136  return -1;
137  }
138 
139  close(socket);
140  handlep->stat.ps_recv += request.ifr_stats.receive.packets;
141  handlep->stat.ps_drop += request.ifr_stats.receive.dropped;
142  *stats = handlep->stat;
143  return 0;
144 }
145 
146 
147 static int
149 {
150  struct pcap_haiku* handlep = (struct pcap_haiku*)handle->priv;
151 
152  const char* device = handle->opt.device;
153 
154  handle->read_op = pcap_read_haiku;
155  handle->setfilter_op = install_bpf_program; /* no kernel filtering */
156  handle->inject_op = pcap_inject_haiku;
157  handle->stats_op = pcap_stats_haiku;
158 
159  // use default hooks where possible
162 
163  handlep->device = strdup(device);
164  if (handlep->device == NULL) {
166  errno, "strdup");
167  return PCAP_ERROR;
168  }
169 
170  handle->bufsize = 65536;
171  // TODO: should be determined by interface MTU
172 
173  // allocate buffer for monitoring the device
174  handle->buffer = (u_char*)malloc(handle->bufsize);
175  if (handle->buffer == NULL) {
177  errno, "buffer malloc");
178  return PCAP_ERROR;
179  }
180 
181  handle->offset = 0;
182  handle->linktype = DLT_EN10MB;
183  // TODO: check interface type!
184 
185  return 0;
186 }
187 
188 
189 // #pragma mark - pcap API
190 
191 
192 extern "C" pcap_t *
193 pcap_create_interface(const char *device, char *errorBuffer)
194 {
195  // TODO: handle promiscuous mode!
196 
197  // we need a socket to talk to the networking stack
198  int socket = ::socket(AF_INET, SOCK_DGRAM, 0);
199  if (socket < 0) {
200  snprintf(errorBuffer, PCAP_ERRBUF_SIZE,
201  "The networking stack doesn't seem to be available.\n");
202  return NULL;
203  }
204 
205  struct ifreq request;
206  if (!prepare_request(request, device)) {
207  snprintf(errorBuffer, PCAP_ERRBUF_SIZE,
208  "Interface name \"%s\" is too long.", device);
209  close(socket);
210  return NULL;
211  }
212 
213  // check if the interface exist
214  if (ioctl(socket, SIOCGIFINDEX, &request, sizeof(request)) < 0) {
215  snprintf(errorBuffer, PCAP_ERRBUF_SIZE,
216  "Interface \"%s\" does not exist.\n", device);
217  close(socket);
218  return NULL;
219  }
220 
221  close(socket);
222  // no longer needed after this point
223 
224  // get link level interface for this interface
225 
226  socket = ::socket(AF_LINK, SOCK_DGRAM, 0);
227  if (socket < 0) {
228  snprintf(errorBuffer, PCAP_ERRBUF_SIZE, "No link level: %s\n",
229  strerror(errno));
230  return NULL;
231  }
232 
233  // start monitoring
234  if (ioctl(socket, SIOCSPACKETCAP, &request, sizeof(struct ifreq)) < 0) {
235  snprintf(errorBuffer, PCAP_ERRBUF_SIZE, "Cannot start monitoring: %s\n",
236  strerror(errno));
237  close(socket);
238  return NULL;
239  }
240 
241  pcap_t* handle = PCAP_CREATE_COMMON(errorBuffer, struct pcap_haiku);
242  if (handle == NULL) {
243  snprintf(errorBuffer, PCAP_ERRBUF_SIZE, "malloc: %s", strerror(errno));
244  close(socket);
245  return NULL;
246  }
247 
248  handle->selectable_fd = socket;
249  handle->fd = socket;
250 
252 
253  return handle;
254 }
255 
256 static int
257 can_be_bound(const char *name)
258 {
259  return 1;
260 }
261 
262 static int
263 get_if_flags(const char *name, bpf_u_int32 *flags, char *errbuf)
264 {
265  /* TODO */
266  if (*flags & PCAP_IF_LOOPBACK) {
267  /*
268  * Loopback devices aren't wireless, and "connected"/
269  * "disconnected" doesn't apply to them.
270  */
272  return (0);
273  }
274  return (0);
275 }
276 
277 extern "C" int
278 pcap_platform_finddevs(pcap_if_list_t* _allDevices, char* errorBuffer)
279 {
280  return pcap_findalldevs_interfaces(_allDevices, errorBuffer, can_be_bound,
281  get_if_flags);
282 }
u_int bpf_u_int32
Definition: bpf.h:98
u_int pcap_filter(const struct bpf_insn *pc, const u_char *p, u_int wirelen, u_int buflen)
Definition: bpf_filter.c:391
#define DLT_EN10MB
Definition: dlt.h:63
int pcap_findalldevs_interfaces(pcap_if_list_t *devlistp, char *errbuf, int(*check_usable)(const char *), get_if_flags_func get_flags_func)
Definition: fad-getad.c:146
void pcap_fmt_errmsg_for_errno(char *errbuf, size_t errbuflen, int errnum, const char *fmt,...)
Definition: fmtutils.c:269
int install_bpf_program(pcap_t *p, struct bpf_program *fp)
Definition: optimize.c:2939
int snprintf(char *, size_t, const char *,...)
char * strerror(int)
int recvfrom(int, char *, u_int, int, struct sockaddr *, int *)
int ioctl(int, int, caddr_t)
int socket(int, int, int)
int close(int)
int errno
static int pcap_stats_haiku(pcap_t *handle, struct pcap_stat *stats)
Definition: pcap-haiku.cpp:123
static int pcap_read_haiku(pcap_t *handle, int maxPackets, pcap_handler callback, u_char *userdata)
Definition: pcap-haiku.cpp:50
static int get_if_flags(const char *name, bpf_u_int32 *flags, char *errbuf)
Definition: pcap-haiku.cpp:263
static int pcap_inject_haiku(pcap_t *handle, const void *buffer, int size)
Definition: pcap-haiku.cpp:111
pcap_t * pcap_create_interface(const char *device, char *errorBuffer)
Definition: pcap-haiku.cpp:193
static int pcap_activate_haiku(pcap_t *handle)
Definition: pcap-haiku.cpp:148
int pcap_platform_finddevs(pcap_if_list_t *_allDevices, char *errorBuffer)
Definition: pcap-haiku.cpp:278
static int can_be_bound(const char *name)
Definition: pcap-haiku.cpp:257
bool prepare_request(struct ifreq &request, const char *name)
Definition: pcap-haiku.cpp:39
int pcap_getnonblock_fd(pcap_t *)
Definition: pcap.c:3537
int pcap_setnonblock_fd(pcap_t *p, int)
Definition: pcap.c:3583
#define PCAP_CREATE_COMMON(ebuf, type)
Definition: pcap-int.h:474
int socklen_t
Definition: pcap-linux.c:168
#define PCAP_IF_CONNECTION_STATUS_NOT_APPLICABLE
Definition: pcap.h:317
#define PCAP_IF_LOOPBACK
Definition: pcap.h:309
void(* pcap_handler)(u_char *, const struct pcap_pkthdr *, const u_char *)
Definition: pcap.h:330
#define PCAP_ERRBUF_SIZE
Definition: pcap.h:152
#define PCAP_ERROR
Definition: pcap.h:339
#define IF_NAMESIZE
int int32
struct bpf_insn * bf_insns
Definition: bpf.h:119
char * device
Definition: pcap-haiku.cpp:34
struct pcap_stat stat
Definition: pcap-haiku.cpp:33
char * device
Definition: pcap-int.h:146
bpf_u_int32 caplen
Definition: pcap.h:247
struct timeval ts
Definition: pcap.h:246
bpf_u_int32 len
Definition: pcap.h:248
u_int ps_drop
Definition: pcap.h:256
u_int ps_recv
Definition: pcap.h:255
Definition: pcap-int.h:200
stats_op_t stats_op
Definition: pcap-int.h:320
activate_op_t activate_op
Definition: pcap-int.h:311
setnonblock_op_t setnonblock_op
Definition: pcap-int.h:319
setfilter_op_t setfilter_op
Definition: pcap-int.h:315
sig_atomic_t break_loop
Definition: pcap-int.h:225
u_int bufsize
Definition: pcap-int.h:220
void * priv
Definition: pcap-int.h:227
getnonblock_op_t getnonblock_op
Definition: pcap-int.h:318
int offset
Definition: pcap-int.h:250
read_op_t read_op
Definition: pcap-int.h:204
void * buffer
Definition: pcap-int.h:221
int snapshot
Definition: pcap-int.h:247
inject_op_t inject_op
Definition: pcap-int.h:313
struct bpf_program fcode
Definition: pcap-int.h:293
char errbuf[256+1]
Definition: pcap-int.h:295
int linktype
Definition: pcap-int.h:248
int selectable_fd
Definition: pcap-int.h:274
int fd
Definition: pcap-int.h:214
struct pcap_opt opt
Definition: pcap-int.h:254