2 * Copyright 2006-2010, Haiku, Inc. All Rights Reserved.
3 * Distributed under the terms of the MIT License.
6 * Axel Dörfler, axeld@pinc-software.de
16 #include <sys/socket.h>
17 #include <sys/sockio.h>
20 #include <net/if_dl.h>
21 #include <net/if_types.h>
30 * Private data for capturing on Haiku sockets.
33 struct pcap_stat stat;
34 char *device; /* device name */
39 prepare_request(struct ifreq& request, const char* name)
41 if (strlen(name) >= IF_NAMESIZE)
44 strcpy(request.ifr_name, name);
50 pcap_read_haiku(pcap_t* handle, int maxPackets _U_, pcap_handler callback,
53 // Receive a single packet
55 u_char* buffer = (u_char*)handle->buffer + handle->offset;
56 struct sockaddr_dl from;
57 ssize_t bytesReceived;
59 if (handle->break_loop) {
60 // Clear the break loop flag, and return -2 to indicate our
62 handle->break_loop = 0;
66 socklen_t fromLength = sizeof(from);
67 bytesReceived = recvfrom(handle->fd, buffer, handle->bufsize, MSG_TRUNC,
68 (struct sockaddr*)&from, &fromLength);
69 } while (bytesReceived < 0 && errno == B_INTERRUPTED);
71 if (bytesReceived < 0) {
72 if (errno == B_WOULD_BLOCK) {
73 // there is no packet for us
77 snprintf(handle->errbuf, sizeof(handle->errbuf),
78 "recvfrom: %s", strerror(errno));
82 int32 captureLength = bytesReceived;
83 if (captureLength > handle->snapshot)
84 captureLength = handle->snapshot;
86 // run the packet filter
87 if (handle->fcode.bf_insns) {
88 if (pcap_filter(handle->fcode.bf_insns, buffer, bytesReceived,
89 captureLength) == 0) {
90 // packet got rejected
95 // fill in pcap_header
97 header.caplen = captureLength;
98 header.len = bytesReceived;
99 header.ts.tv_usec = system_time() % 1000000;
100 header.ts.tv_sec = system_time() / 1000000;
101 // TODO: get timing from packet!!!
103 /* Call the user supplied callback function */
104 callback(userdata, &header, buffer);
110 pcap_inject_haiku(pcap_t *handle, const void *buffer, int size)
112 // we don't support injecting packets yet
113 // TODO: use the AF_LINK protocol (we need another socket for this) to
114 // inject the packets
115 strlcpy(handle->errbuf, "Sending packets isn't supported yet",
122 pcap_stats_haiku(pcap_t *handle, struct pcap_stat *stats)
124 struct pcap_haiku* handlep = (struct pcap_haiku*)handle->priv;
126 int socket = ::socket(AF_INET, SOCK_DGRAM, 0);
130 prepare_request(request, handlep->device);
131 if (ioctl(socket, SIOCGIFSTATS, &request, sizeof(struct ifreq)) < 0) {
132 snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "pcap_stats: %s",
139 handlep->stat.ps_recv += request.ifr_stats.receive.packets;
140 handlep->stat.ps_drop += request.ifr_stats.receive.dropped;
141 *stats = handlep->stat;
147 pcap_activate_haiku(pcap_t *handle)
149 struct pcap_haiku* handlep = (struct pcap_haiku*)handle->priv;
151 const char* device = handle->opt.device;
153 handle->read_op = pcap_read_haiku;
154 handle->setfilter_op = install_bpf_program; /* no kernel filtering */
155 handle->inject_op = pcap_inject_haiku;
156 handle->stats_op = pcap_stats_haiku;
158 // use default hooks where possible
159 handle->getnonblock_op = pcap_getnonblock_fd;
160 handle->setnonblock_op = pcap_setnonblock_fd;
163 * Turn a negative snapshot value (invalid), a snapshot value of
164 * 0 (unspecified), or a value bigger than the normal maximum
165 * value, into the maximum allowed value.
167 * If some application really *needs* a bigger snapshot
168 * length, we should just increase MAXIMUM_SNAPLEN.
170 if (handle->snapshot <= 0 || handle->snapshot > MAXIMUM_SNAPLEN)
171 handle->snapshot = MAXIMUM_SNAPLEN;
173 handlep->device = strdup(device);
174 if (handlep->device == NULL) {
175 pcap_fmt_errmsg_for_errno(handle->errbuf, PCAP_ERRBUF_SIZE,
180 handle->bufsize = 65536;
181 // TODO: should be determined by interface MTU
183 // allocate buffer for monitoring the device
184 handle->buffer = (u_char*)malloc(handle->bufsize);
185 if (handle->buffer == NULL) {
186 pcap_fmt_errmsg_for_errno(handle->errbuf, PCAP_ERRBUF_SIZE,
187 errno, "buffer malloc");
192 handle->linktype = DLT_EN10MB;
193 // TODO: check interface type!
199 // #pragma mark - pcap API
203 pcap_create_interface(const char *device, char *errorBuffer)
205 // TODO: handle promiscuous mode!
207 // we need a socket to talk to the networking stack
208 int socket = ::socket(AF_INET, SOCK_DGRAM, 0);
210 snprintf(errorBuffer, PCAP_ERRBUF_SIZE,
211 "The networking stack doesn't seem to be available.\n");
215 struct ifreq request;
216 if (!prepare_request(request, device)) {
217 snprintf(errorBuffer, PCAP_ERRBUF_SIZE,
218 "Interface name \"%s\" is too long.", device);
223 // check if the interface exist
224 if (ioctl(socket, SIOCGIFINDEX, &request, sizeof(request)) < 0) {
225 snprintf(errorBuffer, PCAP_ERRBUF_SIZE,
226 "Interface \"%s\" does not exist.\n", device);
232 // no longer needed after this point
234 // get link level interface for this interface
236 socket = ::socket(AF_LINK, SOCK_DGRAM, 0);
238 snprintf(errorBuffer, PCAP_ERRBUF_SIZE, "No link level: %s\n",
244 if (ioctl(socket, SIOCSPACKETCAP, &request, sizeof(struct ifreq)) < 0) {
245 snprintf(errorBuffer, PCAP_ERRBUF_SIZE, "Cannot start monitoring: %s\n",
251 struct wrapper_struct { pcap_t __common; struct pcap_haiku __private; };
252 pcap_t* handle = pcap_create_common(errorBuffer,
253 sizeof (struct wrapper_struct),
254 offsetof (struct wrapper_struct, __private));
256 if (handle == NULL) {
257 snprintf(errorBuffer, PCAP_ERRBUF_SIZE, "malloc: %s", strerror(errno));
262 handle->selectable_fd = socket;
265 handle->activate_op = pcap_activate_haiku;
271 can_be_bound(const char *name _U_)
277 get_if_flags(const char *name, bpf_u_int32 *flags, char *errbuf)
280 if (*flags & PCAP_IF_LOOPBACK) {
282 * Loopback devices aren't wireless, and "connected"/
283 * "disconnected" doesn't apply to them.
285 *flags |= PCAP_IF_CONNECTION_STATUS_NOT_APPLICABLE;
292 pcap_platform_finddevs(pcap_if_list_t* _allDevices, char* errorBuffer)
294 return pcap_findalldevs_interfaces(_allDevices, errorBuffer, can_be_bound,
299 * Libpcap version string.
301 extern "C" const char *
302 pcap_lib_version(void)
304 return (PCAP_VERSION_STRING);