The Android Open Source Project | 478ab6c | 2009-03-03 19:30:05 -0800 | [diff] [blame] | 1 | /* |
| 2 | * pcap-septel.c: Packet capture interface for Intel/Septel card. |
| 3 | * |
| 4 | * The functionality of this code attempts to mimic that of pcap-linux as much |
| 5 | * as possible. This code is compiled in several different ways depending on |
| 6 | * whether SEPTEL_ONLY and HAVE_SEPTEL_API are defined. If HAVE_SEPTEL_API is |
| 7 | * not defined it should not get compiled in, otherwise if SEPTEL_ONLY is |
| 8 | * defined then the 'septel_' function calls are renamed to 'pcap_' |
| 9 | * equivalents. If SEPTEL_ONLY is not defined then nothing is altered - the |
| 10 | * septel_ functions will be called as required from their |
| 11 | * pcap-linux/equivalents. |
| 12 | * |
| 13 | * Authors: Gilbert HOYEK (gil_hoyek@hotmail.com), Elias M. KHOURY |
| 14 | * (+961 3 485243) |
| 15 | */ |
| 16 | |
The Android Open Source Project | 478ab6c | 2009-03-03 19:30:05 -0800 | [diff] [blame] | 17 | #ifdef HAVE_CONFIG_H |
Haibo Huang | 165065a | 2018-07-23 17:26:52 -0700 | [diff] [blame] | 18 | #include <config.h> |
The Android Open Source Project | 478ab6c | 2009-03-03 19:30:05 -0800 | [diff] [blame] | 19 | #endif |
| 20 | |
| 21 | #include <sys/param.h> |
| 22 | |
| 23 | #include <stdlib.h> |
| 24 | #include <string.h> |
| 25 | #include <errno.h> |
| 26 | |
| 27 | #include "pcap-int.h" |
| 28 | |
| 29 | #include <ctype.h> |
| 30 | #include <netinet/in.h> |
| 31 | #include <sys/mman.h> |
| 32 | #include <sys/socket.h> |
| 33 | #include <sys/types.h> |
| 34 | #include <unistd.h> |
| 35 | |
The Android Open Source Project | 478ab6c | 2009-03-03 19:30:05 -0800 | [diff] [blame] | 36 | #include <msg.h> |
| 37 | #include <ss7_inc.h> |
| 38 | #include <sysgct.h> |
| 39 | #include <pack.h> |
| 40 | #include <system.h> |
The Android Open Source Project | 478ab6c | 2009-03-03 19:30:05 -0800 | [diff] [blame] | 41 | |
The Android Open Source Project | 478ab6c | 2009-03-03 19:30:05 -0800 | [diff] [blame] | 42 | #include "pcap-septel.h" |
| 43 | |
The Android Open Source Project | 478ab6c | 2009-03-03 19:30:05 -0800 | [diff] [blame] | 44 | static int septel_setfilter(pcap_t *p, struct bpf_program *fp); |
| 45 | static int septel_stats(pcap_t *p, struct pcap_stat *ps); |
Haibo Huang | 165065a | 2018-07-23 17:26:52 -0700 | [diff] [blame] | 46 | static int septel_getnonblock(pcap_t *p); |
| 47 | static int septel_setnonblock(pcap_t *p, int nonblock); |
The Android Open Source Project | 478ab6c | 2009-03-03 19:30:05 -0800 | [diff] [blame] | 48 | |
JP Abgrall | 511eca3 | 2014-02-12 13:46:45 -0800 | [diff] [blame] | 49 | /* |
| 50 | * Private data for capturing on Septel devices. |
| 51 | */ |
| 52 | struct pcap_septel { |
| 53 | struct pcap_stat stat; |
The Android Open Source Project | 478ab6c | 2009-03-03 19:30:05 -0800 | [diff] [blame] | 54 | } |
| 55 | |
The Android Open Source Project | 478ab6c | 2009-03-03 19:30:05 -0800 | [diff] [blame] | 56 | /* |
| 57 | * Read at most max_packets from the capture queue and call the callback |
| 58 | * for each of them. Returns the number of packets handled, -1 if an |
| 59 | * error occured, or -2 if we were told to break out of the loop. |
| 60 | */ |
| 61 | static int septel_read(pcap_t *p, int cnt, pcap_handler callback, u_char *user) { |
| 62 | |
JP Abgrall | 511eca3 | 2014-02-12 13:46:45 -0800 | [diff] [blame] | 63 | struct pcap_septel *ps = p->priv; |
The Android Open Source Project | 478ab6c | 2009-03-03 19:30:05 -0800 | [diff] [blame] | 64 | HDR *h; |
| 65 | MSG *m; |
| 66 | int processed = 0 ; |
| 67 | int t = 0 ; |
| 68 | |
| 69 | /* identifier for the message queue of the module(upe) from which we are capturing |
| 70 | * packets.These IDs are defined in system.txt . By default it is set to 0x2d |
| 71 | * so change it to 0xdd for technical reason and therefore the module id for upe becomes: |
| 72 | * LOCAL 0xdd * upe - Example user part task */ |
| 73 | unsigned int id = 0xdd; |
| 74 | |
| 75 | /* process the packets */ |
| 76 | do { |
| 77 | |
| 78 | unsigned short packet_len = 0; |
| 79 | int caplen = 0; |
| 80 | int counter = 0; |
| 81 | struct pcap_pkthdr pcap_header; |
| 82 | u_char *dp ; |
| 83 | |
| 84 | /* |
| 85 | * Has "pcap_breakloop()" been called? |
| 86 | */ |
| 87 | loop: |
| 88 | if (p->break_loop) { |
| 89 | /* |
| 90 | * Yes - clear the flag that indicates that |
| 91 | * it has, and return -2 to indicate that |
| 92 | * we were told to break out of the loop. |
| 93 | */ |
| 94 | p->break_loop = 0; |
| 95 | return -2; |
| 96 | } |
| 97 | |
| 98 | /*repeat until a packet is read |
| 99 | *a NULL message means : |
| 100 | * when no packet is in queue or all packets in queue already read */ |
| 101 | do { |
| 102 | /* receive packet in non-blocking mode |
| 103 | * GCT_grab is defined in the septel library software */ |
| 104 | h = GCT_grab(id); |
| 105 | |
| 106 | m = (MSG*)h; |
| 107 | /* a couter is added here to avoid an infinite loop |
| 108 | * that will cause our capture program GUI to freeze while waiting |
| 109 | * for a packet*/ |
| 110 | counter++ ; |
| 111 | |
| 112 | } |
| 113 | while ((m == NULL)&& (counter< 100)) ; |
| 114 | |
| 115 | if (m != NULL) { |
| 116 | |
| 117 | t = h->type ; |
| 118 | |
| 119 | /* catch only messages with type = 0xcf00 or 0x8f01 corrsponding to ss7 messages*/ |
| 120 | /* XXX = why not use API_MSG_TX_REQ for 0xcf00 and API_MSG_RX_IND |
| 121 | * for 0x8f01? */ |
| 122 | if ((t != 0xcf00) && (t != 0x8f01)) { |
| 123 | relm(h); |
| 124 | goto loop ; |
| 125 | } |
| 126 | |
| 127 | /* XXX - is API_MSG_RX_IND for an MTP2 or MTP3 message? */ |
| 128 | dp = get_param(m);/* get pointer to MSG parameter area (m->param) */ |
| 129 | packet_len = m->len; |
| 130 | caplen = p->snapshot ; |
| 131 | |
| 132 | |
| 133 | if (caplen > packet_len) { |
| 134 | |
| 135 | caplen = packet_len; |
| 136 | } |
| 137 | /* Run the packet filter if there is one. */ |
| 138 | if ((p->fcode.bf_insns == NULL) || bpf_filter(p->fcode.bf_insns, dp, packet_len, caplen)) { |
| 139 | |
| 140 | |
| 141 | /* get a time stamp , consisting of : |
| 142 | * |
| 143 | * pcap_header.ts.tv_sec: |
| 144 | * ---------------------- |
| 145 | * a UNIX format time-in-seconds when he packet was captured, |
| 146 | * i.e. the number of seconds since Epoch time (January 1,1970, 00:00:00 GMT) |
| 147 | * |
| 148 | * pcap_header.ts.tv_usec : |
| 149 | * ------------------------ |
| 150 | * the number of microseconds since that second |
| 151 | * when the packet was captured |
| 152 | */ |
| 153 | |
| 154 | (void)gettimeofday(&pcap_header.ts, NULL); |
| 155 | |
| 156 | /* Fill in our own header data */ |
| 157 | pcap_header.caplen = caplen; |
| 158 | pcap_header.len = packet_len; |
| 159 | |
| 160 | /* Count the packet. */ |
JP Abgrall | 511eca3 | 2014-02-12 13:46:45 -0800 | [diff] [blame] | 161 | ps->stat.ps_recv++; |
The Android Open Source Project | 478ab6c | 2009-03-03 19:30:05 -0800 | [diff] [blame] | 162 | |
| 163 | /* Call the user supplied callback function */ |
| 164 | callback(user, &pcap_header, dp); |
| 165 | |
| 166 | processed++ ; |
| 167 | |
| 168 | } |
| 169 | /* after being processed the packet must be |
| 170 | *released in order to receive another one */ |
| 171 | relm(h); |
| 172 | }else |
| 173 | processed++; |
| 174 | |
| 175 | } |
| 176 | while (processed < cnt) ; |
| 177 | |
| 178 | return processed ; |
| 179 | } |
| 180 | |
| 181 | |
| 182 | static int |
| 183 | septel_inject(pcap_t *handle, const void *buf _U_, size_t size _U_) |
| 184 | { |
| 185 | strlcpy(handle->errbuf, "Sending packets isn't supported on Septel cards", |
| 186 | PCAP_ERRBUF_SIZE); |
| 187 | return (-1); |
| 188 | } |
| 189 | |
| 190 | /* |
JP Abgrall | 511eca3 | 2014-02-12 13:46:45 -0800 | [diff] [blame] | 191 | * Activate a handle for a live capture from the given Septel device. Always pass a NULL device |
The Android Open Source Project | 478ab6c | 2009-03-03 19:30:05 -0800 | [diff] [blame] | 192 | * The promisc flag is ignored because Septel cards have built-in tracing. |
JP Abgrall | 511eca3 | 2014-02-12 13:46:45 -0800 | [diff] [blame] | 193 | * The timeout is also ignored as it is not supported in hardware. |
The Android Open Source Project | 478ab6c | 2009-03-03 19:30:05 -0800 | [diff] [blame] | 194 | * |
| 195 | * See also pcap(3). |
| 196 | */ |
JP Abgrall | 511eca3 | 2014-02-12 13:46:45 -0800 | [diff] [blame] | 197 | static pcap_t *septel_activate(pcap_t* handle) { |
Elliott Hughes | d8845d7 | 2015-10-19 18:07:04 -0700 | [diff] [blame] | 198 | /* Initialize some components of the pcap structure. */ |
The Android Open Source Project | 478ab6c | 2009-03-03 19:30:05 -0800 | [diff] [blame] | 199 | handle->linktype = DLT_MTP2; |
Elliott Hughes | d8845d7 | 2015-10-19 18:07:04 -0700 | [diff] [blame] | 200 | |
Haibo Huang | 165065a | 2018-07-23 17:26:52 -0700 | [diff] [blame] | 201 | /* |
| 202 | * Turn a negative snapshot value (invalid), a snapshot value of |
| 203 | * 0 (unspecified), or a value bigger than the normal maximum |
| 204 | * value, into the maximum allowed value. |
| 205 | * |
| 206 | * If some application really *needs* a bigger snapshot |
| 207 | * length, we should just increase MAXIMUM_SNAPLEN. |
| 208 | */ |
| 209 | if (handle->snapshot <= 0 || handle->snapshot > MAXIMUM_SNAPLEN) |
| 210 | handle->snapshot = MAXIMUM_SNAPLEN; |
| 211 | |
The Android Open Source Project | 478ab6c | 2009-03-03 19:30:05 -0800 | [diff] [blame] | 212 | handle->bufsize = 0; |
| 213 | |
| 214 | /* |
| 215 | * "select()" and "poll()" don't work on Septel queues |
| 216 | */ |
| 217 | handle->selectable_fd = -1; |
| 218 | |
| 219 | handle->read_op = septel_read; |
| 220 | handle->inject_op = septel_inject; |
| 221 | handle->setfilter_op = septel_setfilter; |
| 222 | handle->set_datalink_op = NULL; /* can't change data link type */ |
Haibo Huang | 165065a | 2018-07-23 17:26:52 -0700 | [diff] [blame] | 223 | handle->getnonblock_op = septel_getnonblock; |
The Android Open Source Project | 478ab6c | 2009-03-03 19:30:05 -0800 | [diff] [blame] | 224 | handle->setnonblock_op = septel_setnonblock; |
| 225 | handle->stats_op = septel_stats; |
The Android Open Source Project | 478ab6c | 2009-03-03 19:30:05 -0800 | [diff] [blame] | 226 | |
JP Abgrall | 511eca3 | 2014-02-12 13:46:45 -0800 | [diff] [blame] | 227 | return 0; |
| 228 | } |
The Android Open Source Project | 478ab6c | 2009-03-03 19:30:05 -0800 | [diff] [blame] | 229 | |
JP Abgrall | 511eca3 | 2014-02-12 13:46:45 -0800 | [diff] [blame] | 230 | pcap_t *septel_create(const char *device, char *ebuf, int *is_ours) { |
| 231 | const char *cp; |
| 232 | pcap_t *p; |
The Android Open Source Project | 478ab6c | 2009-03-03 19:30:05 -0800 | [diff] [blame] | 233 | |
JP Abgrall | 511eca3 | 2014-02-12 13:46:45 -0800 | [diff] [blame] | 234 | /* Does this look like the Septel device? */ |
| 235 | cp = strrchr(device, '/'); |
| 236 | if (cp == NULL) |
| 237 | cp = device; |
| 238 | if (strcmp(cp, "septel") != 0) { |
| 239 | /* Nope, it's not "septel" */ |
| 240 | *is_ours = 0; |
| 241 | return NULL; |
| 242 | } |
| 243 | |
| 244 | /* OK, it's probably ours. */ |
| 245 | *is_ours = 1; |
| 246 | |
Elliott Hughes | 965a4b5 | 2017-05-15 10:37:39 -0700 | [diff] [blame] | 247 | p = pcap_create_common(ebuf, sizeof (struct pcap_septel)); |
JP Abgrall | 511eca3 | 2014-02-12 13:46:45 -0800 | [diff] [blame] | 248 | if (p == NULL) |
| 249 | return NULL; |
| 250 | |
| 251 | p->activate_op = septel_activate; |
Haibo Huang | 165065a | 2018-07-23 17:26:52 -0700 | [diff] [blame] | 252 | /* |
| 253 | * Set these up front, so that, even if our client tries |
| 254 | * to set non-blocking mode before we're activated, or |
| 255 | * query the state of non-blocking mode, they get an error, |
| 256 | * rather than having the non-blocking mode option set |
| 257 | * for use later. |
| 258 | */ |
| 259 | p->getnonblock_op = septel_getnonblock; |
| 260 | p->setnonblock_op = septel_setnonblock; |
JP Abgrall | 511eca3 | 2014-02-12 13:46:45 -0800 | [diff] [blame] | 261 | return p; |
The Android Open Source Project | 478ab6c | 2009-03-03 19:30:05 -0800 | [diff] [blame] | 262 | } |
| 263 | |
| 264 | static int septel_stats(pcap_t *p, struct pcap_stat *ps) { |
JP Abgrall | 511eca3 | 2014-02-12 13:46:45 -0800 | [diff] [blame] | 265 | struct pcap_septel *handlep = p->priv; |
| 266 | /*handlep->stat.ps_recv = 0;*/ |
| 267 | /*handlep->stat.ps_drop = 0;*/ |
Elliott Hughes | d8845d7 | 2015-10-19 18:07:04 -0700 | [diff] [blame] | 268 | |
JP Abgrall | 511eca3 | 2014-02-12 13:46:45 -0800 | [diff] [blame] | 269 | *ps = handlep->stat; |
Elliott Hughes | d8845d7 | 2015-10-19 18:07:04 -0700 | [diff] [blame] | 270 | |
The Android Open Source Project | 478ab6c | 2009-03-03 19:30:05 -0800 | [diff] [blame] | 271 | return 0; |
| 272 | } |
| 273 | |
| 274 | |
| 275 | int |
Haibo Huang | 165065a | 2018-07-23 17:26:52 -0700 | [diff] [blame] | 276 | septel_findalldevs(pcap_if_list_t *devlistp, char *errbuf) |
The Android Open Source Project | 478ab6c | 2009-03-03 19:30:05 -0800 | [diff] [blame] | 277 | { |
Haibo Huang | 165065a | 2018-07-23 17:26:52 -0700 | [diff] [blame] | 278 | /* |
| 279 | * XXX - do the notions of "up", "running", or "connected" apply here? |
| 280 | */ |
| 281 | if (add_dev(devlistp,"septel",0,"Intel/Septel device",errbuf) == NULL) |
| 282 | return -1; |
| 283 | return 0; |
The Android Open Source Project | 478ab6c | 2009-03-03 19:30:05 -0800 | [diff] [blame] | 284 | } |
| 285 | |
| 286 | |
| 287 | /* |
| 288 | * Installs the given bpf filter program in the given pcap structure. There is |
| 289 | * no attempt to store the filter in kernel memory as that is not supported |
| 290 | * with Septel cards. |
| 291 | */ |
| 292 | static int septel_setfilter(pcap_t *p, struct bpf_program *fp) { |
| 293 | if (!p) |
| 294 | return -1; |
| 295 | if (!fp) { |
| 296 | strncpy(p->errbuf, "setfilter: No filter specified", |
| 297 | sizeof(p->errbuf)); |
| 298 | return -1; |
| 299 | } |
| 300 | |
| 301 | /* Make our private copy of the filter */ |
| 302 | |
Haibo Huang | 165065a | 2018-07-23 17:26:52 -0700 | [diff] [blame] | 303 | if (install_bpf_program(p, fp) < 0) |
The Android Open Source Project | 478ab6c | 2009-03-03 19:30:05 -0800 | [diff] [blame] | 304 | return -1; |
The Android Open Source Project | 478ab6c | 2009-03-03 19:30:05 -0800 | [diff] [blame] | 305 | |
The Android Open Source Project | 478ab6c | 2009-03-03 19:30:05 -0800 | [diff] [blame] | 306 | return (0); |
| 307 | } |
| 308 | |
Haibo Huang | 165065a | 2018-07-23 17:26:52 -0700 | [diff] [blame] | 309 | /* |
| 310 | * We don't support non-blocking mode. I'm not sure what we'd |
| 311 | * do to support it and, given that we don't support select()/ |
| 312 | * poll()/epoll_wait()/kevent() etc., it probably doesn't |
| 313 | * matter. |
| 314 | */ |
| 315 | static int |
| 316 | septel_getnonblock(pcap_t *p) |
| 317 | { |
| 318 | fprintf(p->errbuf, PCAP_ERRBUF_SIZE, "Non-blocking mode not supported on Septel devices"); |
| 319 | return (-1); |
| 320 | } |
The Android Open Source Project | 478ab6c | 2009-03-03 19:30:05 -0800 | [diff] [blame] | 321 | |
| 322 | static int |
Haibo Huang | 165065a | 2018-07-23 17:26:52 -0700 | [diff] [blame] | 323 | septel_setnonblock(pcap_t *p, int nonblock _U_) |
The Android Open Source Project | 478ab6c | 2009-03-03 19:30:05 -0800 | [diff] [blame] | 324 | { |
Haibo Huang | 165065a | 2018-07-23 17:26:52 -0700 | [diff] [blame] | 325 | fprintf(p->errbuf, PCAP_ERRBUF_SIZE, "Non-blocking mode not supported on Septel devices"); |
JP Abgrall | 511eca3 | 2014-02-12 13:46:45 -0800 | [diff] [blame] | 326 | return (-1); |
The Android Open Source Project | 478ab6c | 2009-03-03 19:30:05 -0800 | [diff] [blame] | 327 | } |
Elliott Hughes | 965a4b5 | 2017-05-15 10:37:39 -0700 | [diff] [blame] | 328 | |
| 329 | #ifdef SEPTEL_ONLY |
| 330 | /* |
| 331 | * This libpcap build supports only Septel cards, not regular network |
| 332 | * interfaces. |
| 333 | */ |
| 334 | |
| 335 | /* |
| 336 | * There are no regular interfaces, just Septel interfaces. |
| 337 | */ |
| 338 | int |
Haibo Huang | 165065a | 2018-07-23 17:26:52 -0700 | [diff] [blame] | 339 | pcap_platform_finddevs(pcap_if_list_t *devlistp, char *errbuf) |
Elliott Hughes | 965a4b5 | 2017-05-15 10:37:39 -0700 | [diff] [blame] | 340 | { |
Elliott Hughes | 965a4b5 | 2017-05-15 10:37:39 -0700 | [diff] [blame] | 341 | return (0); |
| 342 | } |
| 343 | |
| 344 | /* |
| 345 | * Attempts to open a regular interface fail. |
| 346 | */ |
| 347 | pcap_t * |
| 348 | pcap_create_interface(const char *device, char *errbuf) |
| 349 | { |
| 350 | pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, |
| 351 | "This version of libpcap only supports Septel cards"); |
| 352 | return (NULL); |
| 353 | } |
Haibo Huang | 165065a | 2018-07-23 17:26:52 -0700 | [diff] [blame] | 354 | |
| 355 | /* |
| 356 | * Libpcap version string. |
| 357 | */ |
| 358 | const char * |
| 359 | pcap_lib_version(void) |
| 360 | { |
| 361 | return (PCAP_VERSION_STRING " (Septel-only)"); |
| 362 | } |
Elliott Hughes | 965a4b5 | 2017-05-15 10:37:39 -0700 | [diff] [blame] | 363 | #endif |