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", 117 PCAP_ERRBUF_SIZE); 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 148 pcap_activate_haiku(pcap_t *handle) 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 160 handle->getnonblock_op = pcap_getnonblock_fd; 161 handle->setnonblock_op = pcap_setnonblock_fd; 162 163 handlep->device = strdup(device); 164 if (handlep->device == NULL) { 165 pcap_fmt_errmsg_for_errno(handle->errbuf, PCAP_ERRBUF_SIZE, 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) { 176 pcap_fmt_errmsg_for_errno(handle->errbuf, PCAP_ERRBUF_SIZE, 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 251 handle->activate_op = pcap_activate_haiku; 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 */ 271 *flags |= PCAP_IF_CONNECTION_STATUS_NOT_APPLICABLE; 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 } 283