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 _U_, pcap_handler callback, 51 u_char* userdata) 52 { 53 // Receive a single packet 54 55 u_char* buffer = (u_char*)handle->buffer + handle->offset; 56 struct sockaddr_dl from; 57 ssize_t bytesReceived; 58 do { 59 if (handle->break_loop) { 60 // Clear the break loop flag, and return -2 to indicate our 61 // reasoning 62 handle->break_loop = 0; 63 return -2; 64 } 65 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); 70 71 if (bytesReceived < 0) { 72 if (errno == B_WOULD_BLOCK) { 73 // there is no packet for us 74 return 0; 75 } 76 77 snprintf(handle->errbuf, sizeof(handle->errbuf), 78 "recvfrom: %s", strerror(errno)); 79 return -1; 80 } 81 82 int32 captureLength = bytesReceived; 83 if (captureLength > handle->snapshot) 84 captureLength = handle->snapshot; 85 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 91 return 0; 92 } 93 } 94 95 // fill in pcap_header 96 pcap_pkthdr 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!!! 102 103 /* Call the user supplied callback function */ 104 callback(userdata, &header, buffer); 105 return 1; 106 } 107 108 109 static int 110 pcap_inject_haiku(pcap_t *handle, const void *buffer, int size) 111 { 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", 116 PCAP_ERRBUF_SIZE); 117 return -1; 118 } 119 120 121 static int 122 pcap_stats_haiku(pcap_t *handle, struct pcap_stat *stats) 123 { 124 struct pcap_haiku* handlep = (struct pcap_haiku*)handle->priv; 125 ifreq request; 126 int socket = ::socket(AF_INET, SOCK_DGRAM, 0); 127 if (socket < 0) { 128 return -1; 129 } 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", 133 strerror(errno)); 134 close(socket); 135 return -1; 136 } 137 138 close(socket); 139 handlep->stat.ps_recv += request.ifr_stats.receive.packets; 140 handlep->stat.ps_drop += request.ifr_stats.receive.dropped; 141 *stats = handlep->stat; 142 return 0; 143 } 144 145 146 static int 147 pcap_activate_haiku(pcap_t *handle) 148 { 149 struct pcap_haiku* handlep = (struct pcap_haiku*)handle->priv; 150 151 const char* device = handle->opt.device; 152 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; 157 158 // use default hooks where possible 159 handle->getnonblock_op = pcap_getnonblock_fd; 160 handle->setnonblock_op = pcap_setnonblock_fd; 161 162 /* 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. 166 * 167 * If some application really *needs* a bigger snapshot 168 * length, we should just increase MAXIMUM_SNAPLEN. 169 */ 170 if (handle->snapshot <= 0 || handle->snapshot > MAXIMUM_SNAPLEN) 171 handle->snapshot = MAXIMUM_SNAPLEN; 172 173 handlep->device = strdup(device); 174 if (handlep->device == NULL) { 175 pcap_fmt_errmsg_for_errno(handle->errbuf, PCAP_ERRBUF_SIZE, 176 errno, "strdup"); 177 return PCAP_ERROR; 178 } 179 180 handle->bufsize = 65536; 181 // TODO: should be determined by interface MTU 182 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"); 188 return PCAP_ERROR; 189 } 190 191 handle->offset = 0; 192 handle->linktype = DLT_EN10MB; 193 // TODO: check interface type! 194 195 return 0; 196 } 197 198 199 // #pragma mark - pcap API 200 201 202 extern "C" pcap_t * 203 pcap_create_interface(const char *device, char *errorBuffer) 204 { 205 // TODO: handle promiscuous mode! 206 207 // we need a socket to talk to the networking stack 208 int socket = ::socket(AF_INET, SOCK_DGRAM, 0); 209 if (socket < 0) { 210 snprintf(errorBuffer, PCAP_ERRBUF_SIZE, 211 "The networking stack doesn't seem to be available.\n"); 212 return NULL; 213 } 214 215 struct ifreq request; 216 if (!prepare_request(request, device)) { 217 snprintf(errorBuffer, PCAP_ERRBUF_SIZE, 218 "Interface name \"%s\" is too long.", device); 219 close(socket); 220 return NULL; 221 } 222 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); 227 close(socket); 228 return NULL; 229 } 230 231 close(socket); 232 // no longer needed after this point 233 234 // get link level interface for this interface 235 236 socket = ::socket(AF_LINK, SOCK_DGRAM, 0); 237 if (socket < 0) { 238 snprintf(errorBuffer, PCAP_ERRBUF_SIZE, "No link level: %s\n", 239 strerror(errno)); 240 return NULL; 241 } 242 243 // start monitoring 244 if (ioctl(socket, SIOCSPACKETCAP, &request, sizeof(struct ifreq)) < 0) { 245 snprintf(errorBuffer, PCAP_ERRBUF_SIZE, "Cannot start monitoring: %s\n", 246 strerror(errno)); 247 close(socket); 248 return NULL; 249 } 250 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)); 255 256 if (handle == NULL) { 257 snprintf(errorBuffer, PCAP_ERRBUF_SIZE, "malloc: %s", strerror(errno)); 258 close(socket); 259 return NULL; 260 } 261 262 handle->selectable_fd = socket; 263 handle->fd = socket; 264 265 handle->activate_op = pcap_activate_haiku; 266 267 return handle; 268 } 269 270 static int 271 can_be_bound(const char *name _U_) 272 { 273 return 1; 274 } 275 276 static int 277 get_if_flags(const char *name, bpf_u_int32 *flags, char *errbuf) 278 { 279 /* TODO */ 280 if (*flags & PCAP_IF_LOOPBACK) { 281 /* 282 * Loopback devices aren't wireless, and "connected"/ 283 * "disconnected" doesn't apply to them. 284 */ 285 *flags |= PCAP_IF_CONNECTION_STATUS_NOT_APPLICABLE; 286 return (0); 287 } 288 return (0); 289 } 290 291 extern "C" int 292 pcap_platform_finddevs(pcap_if_list_t* _allDevices, char* errorBuffer) 293 { 294 return pcap_findalldevs_interfaces(_allDevices, errorBuffer, can_be_bound, 295 get_if_flags); 296 } 297 298 /* 299 * Libpcap version string. 300 */ 301 extern "C" const char * 302 pcap_lib_version(void) 303 { 304 return (PCAP_VERSION_STRING); 305 } 306