Blob: pcap.c
Blob id: 2596a498ebcfab03b7e70b6e7427574cc52dd4b1
Size: 4.0 KB
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 | // SPDX-License-Identifier: LGPL-2.1-or-later /* * * BlueZ - Bluetooth protocol stack for Linux * * Copyright (C) 2012-2014 Intel Corporation. All rights reserved. * * */ #ifdef HAVE_CONFIG_H #include <config.h> #endif #define _GNU_SOURCE #include <fcntl.h> #include <unistd.h> #include <stdlib.h> #include "src/shared/util.h" #include "src/shared/pcap.h" struct pcap_hdr { uint32_t magic_number; /* magic number */ uint16_t version_major; /* major version number */ uint16_t version_minor; /* minor version number */ int32_t thiszone; /* GMT to local correction */ uint32_t sigfigs; /* accuracy of timestamps */ uint32_t snaplen; /* max length of captured packets, in octets */ uint32_t network; /* data link type */ } __attribute__ ((packed)); #define PCAP_HDR_SIZE (sizeof(struct pcap_hdr)) struct pcap_pkt { uint32_t ts_sec; /* timestamp seconds */ uint32_t ts_usec; /* timestamp microseconds */ uint32_t incl_len; /* number of octets of packet saved in file */ uint32_t orig_len; /* actual length of packet */ } __attribute__ ((packed)); #define PCAP_PKT_SIZE (sizeof(struct pcap_pkt)) struct pcap_ppi { uint8_t version; /* version, currently 0 */ uint8_t flags; /* flags */ uint16_t len; /* length of entire message */ uint32_t dlt; /* data link type */ } __attribute__ ((packed)); #define PCAP_PPI_SIZE (sizeof(struct pcap_ppi)) struct pcap { int ref_count; int fd; uint32_t type; uint32_t snaplen; }; struct pcap *pcap_open(const char *path) { struct pcap *pcap; struct pcap_hdr hdr; ssize_t len; pcap = calloc(1, sizeof(*pcap)); if (!pcap) return NULL; pcap->fd = open(path, O_RDONLY | O_CLOEXEC); if (pcap->fd < 0) { free(pcap); return NULL; } len = read(pcap->fd, &hdr, PCAP_HDR_SIZE); if (len < 0 || len != PCAP_HDR_SIZE) goto failed; if (hdr.magic_number != 0xa1b2c3d4) goto failed; if (hdr.version_major != 2 || hdr.version_minor != 4) goto failed; pcap->snaplen = hdr.snaplen; pcap->type = hdr.network; return pcap_ref(pcap); failed: close(pcap->fd); free(pcap); return NULL; } struct pcap *pcap_ref(struct pcap *pcap) { if (!pcap) return NULL; __sync_fetch_and_add(&pcap->ref_count, 1); return pcap; } void pcap_unref(struct pcap *pcap) { if (!pcap) return; if (__sync_sub_and_fetch(&pcap->ref_count, 1)) return; if (pcap->fd >= 0) close(pcap->fd); free(pcap); } uint32_t pcap_get_type(struct pcap *pcap) { if (!pcap) return PCAP_TYPE_INVALID; return pcap->type; } uint32_t pcap_get_snaplen(struct pcap *pcap) { if (!pcap) return 0; return pcap->snaplen; } bool pcap_read(struct pcap *pcap, struct timeval *tv, void *data, uint32_t size, uint32_t *len) { struct pcap_pkt pkt; uint32_t toread; ssize_t bytes_read; if (!pcap) return false; bytes_read = read(pcap->fd, &pkt, PCAP_PKT_SIZE); if (bytes_read != PCAP_PKT_SIZE) return false; if (pkt.incl_len > size) toread = size; else toread = pkt.incl_len; bytes_read = read(pcap->fd, data, toread); if (bytes_read < 0) return false; if (tv) { tv->tv_sec = pkt.ts_sec; tv->tv_usec = pkt.ts_usec; } if (len) *len = toread; return true; } bool pcap_read_ppi(struct pcap *pcap, struct timeval *tv, uint32_t *type, void *data, uint32_t size, uint32_t *offset, uint32_t *len) { struct pcap_pkt pkt; struct pcap_ppi ppi; uint16_t pph_len; uint32_t toread; ssize_t bytes_read; if (!pcap) return false; bytes_read = read(pcap->fd, &pkt, PCAP_PKT_SIZE); if (bytes_read != PCAP_PKT_SIZE) return false; if (pkt.incl_len > size) toread = size; else toread = pkt.incl_len; bytes_read = read(pcap->fd, &ppi, PCAP_PPI_SIZE); if (bytes_read != PCAP_PPI_SIZE) return false; if (ppi.flags) return false; pph_len = le16_to_cpu(ppi.len); if (pph_len < PCAP_PPI_SIZE) return false; bytes_read = read(pcap->fd, data, toread - PCAP_PPI_SIZE); if (bytes_read < 0) return false; if (tv) { tv->tv_sec = pkt.ts_sec; tv->tv_usec = pkt.ts_usec; } if (type) *type = le32_to_cpu(ppi.dlt); if (offset) *offset = pph_len - PCAP_PPI_SIZE; if (len) *len = toread - pph_len; return true; } |