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 |
| 18 | #include "config.h" |
| 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); |
| 46 | static int septel_setnonblock(pcap_t *p, int nonblock, char *errbuf); |
| 47 | |
JP Abgrall | 511eca3 | 2014-02-12 13:46:45 -0800 | [diff] [blame] | 48 | /* |
| 49 | * Private data for capturing on Septel devices. |
| 50 | */ |
| 51 | struct pcap_septel { |
| 52 | struct pcap_stat stat; |
The Android Open Source Project | 478ab6c | 2009-03-03 19:30:05 -0800 | [diff] [blame] | 53 | } |
| 54 | |
The Android Open Source Project | 478ab6c | 2009-03-03 19:30:05 -0800 | [diff] [blame] | 55 | /* |
| 56 | * Read at most max_packets from the capture queue and call the callback |
| 57 | * for each of them. Returns the number of packets handled, -1 if an |
| 58 | * error occured, or -2 if we were told to break out of the loop. |
| 59 | */ |
| 60 | static int septel_read(pcap_t *p, int cnt, pcap_handler callback, u_char *user) { |
| 61 | |
JP Abgrall | 511eca3 | 2014-02-12 13:46:45 -0800 | [diff] [blame] | 62 | struct pcap_septel *ps = p->priv; |
The Android Open Source Project | 478ab6c | 2009-03-03 19:30:05 -0800 | [diff] [blame] | 63 | HDR *h; |
| 64 | MSG *m; |
| 65 | int processed = 0 ; |
| 66 | int t = 0 ; |
| 67 | |
| 68 | /* identifier for the message queue of the module(upe) from which we are capturing |
| 69 | * packets.These IDs are defined in system.txt . By default it is set to 0x2d |
| 70 | * so change it to 0xdd for technical reason and therefore the module id for upe becomes: |
| 71 | * LOCAL 0xdd * upe - Example user part task */ |
| 72 | unsigned int id = 0xdd; |
| 73 | |
| 74 | /* process the packets */ |
| 75 | do { |
| 76 | |
| 77 | unsigned short packet_len = 0; |
| 78 | int caplen = 0; |
| 79 | int counter = 0; |
| 80 | struct pcap_pkthdr pcap_header; |
| 81 | u_char *dp ; |
| 82 | |
| 83 | /* |
| 84 | * Has "pcap_breakloop()" been called? |
| 85 | */ |
| 86 | loop: |
| 87 | if (p->break_loop) { |
| 88 | /* |
| 89 | * Yes - clear the flag that indicates that |
| 90 | * it has, and return -2 to indicate that |
| 91 | * we were told to break out of the loop. |
| 92 | */ |
| 93 | p->break_loop = 0; |
| 94 | return -2; |
| 95 | } |
| 96 | |
| 97 | /*repeat until a packet is read |
| 98 | *a NULL message means : |
| 99 | * when no packet is in queue or all packets in queue already read */ |
| 100 | do { |
| 101 | /* receive packet in non-blocking mode |
| 102 | * GCT_grab is defined in the septel library software */ |
| 103 | h = GCT_grab(id); |
| 104 | |
| 105 | m = (MSG*)h; |
| 106 | /* a couter is added here to avoid an infinite loop |
| 107 | * that will cause our capture program GUI to freeze while waiting |
| 108 | * for a packet*/ |
| 109 | counter++ ; |
| 110 | |
| 111 | } |
| 112 | while ((m == NULL)&& (counter< 100)) ; |
| 113 | |
| 114 | if (m != NULL) { |
| 115 | |
| 116 | t = h->type ; |
| 117 | |
| 118 | /* catch only messages with type = 0xcf00 or 0x8f01 corrsponding to ss7 messages*/ |
| 119 | /* XXX = why not use API_MSG_TX_REQ for 0xcf00 and API_MSG_RX_IND |
| 120 | * for 0x8f01? */ |
| 121 | if ((t != 0xcf00) && (t != 0x8f01)) { |
| 122 | relm(h); |
| 123 | goto loop ; |
| 124 | } |
| 125 | |
| 126 | /* XXX - is API_MSG_RX_IND for an MTP2 or MTP3 message? */ |
| 127 | dp = get_param(m);/* get pointer to MSG parameter area (m->param) */ |
| 128 | packet_len = m->len; |
| 129 | caplen = p->snapshot ; |
| 130 | |
| 131 | |
| 132 | if (caplen > packet_len) { |
| 133 | |
| 134 | caplen = packet_len; |
| 135 | } |
| 136 | /* Run the packet filter if there is one. */ |
| 137 | if ((p->fcode.bf_insns == NULL) || bpf_filter(p->fcode.bf_insns, dp, packet_len, caplen)) { |
| 138 | |
| 139 | |
| 140 | /* get a time stamp , consisting of : |
| 141 | * |
| 142 | * pcap_header.ts.tv_sec: |
| 143 | * ---------------------- |
| 144 | * a UNIX format time-in-seconds when he packet was captured, |
| 145 | * i.e. the number of seconds since Epoch time (January 1,1970, 00:00:00 GMT) |
| 146 | * |
| 147 | * pcap_header.ts.tv_usec : |
| 148 | * ------------------------ |
| 149 | * the number of microseconds since that second |
| 150 | * when the packet was captured |
| 151 | */ |
| 152 | |
| 153 | (void)gettimeofday(&pcap_header.ts, NULL); |
| 154 | |
| 155 | /* Fill in our own header data */ |
| 156 | pcap_header.caplen = caplen; |
| 157 | pcap_header.len = packet_len; |
| 158 | |
| 159 | /* Count the packet. */ |
JP Abgrall | 511eca3 | 2014-02-12 13:46:45 -0800 | [diff] [blame] | 160 | ps->stat.ps_recv++; |
The Android Open Source Project | 478ab6c | 2009-03-03 19:30:05 -0800 | [diff] [blame] | 161 | |
| 162 | /* Call the user supplied callback function */ |
| 163 | callback(user, &pcap_header, dp); |
| 164 | |
| 165 | processed++ ; |
| 166 | |
| 167 | } |
| 168 | /* after being processed the packet must be |
| 169 | *released in order to receive another one */ |
| 170 | relm(h); |
| 171 | }else |
| 172 | processed++; |
| 173 | |
| 174 | } |
| 175 | while (processed < cnt) ; |
| 176 | |
| 177 | return processed ; |
| 178 | } |
| 179 | |
| 180 | |
| 181 | static int |
| 182 | septel_inject(pcap_t *handle, const void *buf _U_, size_t size _U_) |
| 183 | { |
| 184 | strlcpy(handle->errbuf, "Sending packets isn't supported on Septel cards", |
| 185 | PCAP_ERRBUF_SIZE); |
| 186 | return (-1); |
| 187 | } |
| 188 | |
| 189 | /* |
JP Abgrall | 511eca3 | 2014-02-12 13:46:45 -0800 | [diff] [blame] | 190 | * 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] | 191 | * The promisc flag is ignored because Septel cards have built-in tracing. |
JP Abgrall | 511eca3 | 2014-02-12 13:46:45 -0800 | [diff] [blame] | 192 | * 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] | 193 | * |
| 194 | * See also pcap(3). |
| 195 | */ |
JP Abgrall | 511eca3 | 2014-02-12 13:46:45 -0800 | [diff] [blame] | 196 | static pcap_t *septel_activate(pcap_t* handle) { |
Elliott Hughes | d8845d7 | 2015-10-19 18:07:04 -0700 | [diff] [blame^] | 197 | /* Initialize some components of the pcap structure. */ |
The Android Open Source Project | 478ab6c | 2009-03-03 19:30:05 -0800 | [diff] [blame] | 198 | handle->linktype = DLT_MTP2; |
Elliott Hughes | d8845d7 | 2015-10-19 18:07:04 -0700 | [diff] [blame^] | 199 | |
The Android Open Source Project | 478ab6c | 2009-03-03 19:30:05 -0800 | [diff] [blame] | 200 | handle->bufsize = 0; |
| 201 | |
| 202 | /* |
| 203 | * "select()" and "poll()" don't work on Septel queues |
| 204 | */ |
| 205 | handle->selectable_fd = -1; |
| 206 | |
| 207 | handle->read_op = septel_read; |
| 208 | handle->inject_op = septel_inject; |
| 209 | handle->setfilter_op = septel_setfilter; |
| 210 | handle->set_datalink_op = NULL; /* can't change data link type */ |
| 211 | handle->getnonblock_op = pcap_getnonblock_fd; |
| 212 | handle->setnonblock_op = septel_setnonblock; |
| 213 | handle->stats_op = septel_stats; |
The Android Open Source Project | 478ab6c | 2009-03-03 19:30:05 -0800 | [diff] [blame] | 214 | |
JP Abgrall | 511eca3 | 2014-02-12 13:46:45 -0800 | [diff] [blame] | 215 | return 0; |
| 216 | } |
The Android Open Source Project | 478ab6c | 2009-03-03 19:30:05 -0800 | [diff] [blame] | 217 | |
JP Abgrall | 511eca3 | 2014-02-12 13:46:45 -0800 | [diff] [blame] | 218 | pcap_t *septel_create(const char *device, char *ebuf, int *is_ours) { |
| 219 | const char *cp; |
| 220 | pcap_t *p; |
The Android Open Source Project | 478ab6c | 2009-03-03 19:30:05 -0800 | [diff] [blame] | 221 | |
JP Abgrall | 511eca3 | 2014-02-12 13:46:45 -0800 | [diff] [blame] | 222 | /* Does this look like the Septel device? */ |
| 223 | cp = strrchr(device, '/'); |
| 224 | if (cp == NULL) |
| 225 | cp = device; |
| 226 | if (strcmp(cp, "septel") != 0) { |
| 227 | /* Nope, it's not "septel" */ |
| 228 | *is_ours = 0; |
| 229 | return NULL; |
| 230 | } |
| 231 | |
| 232 | /* OK, it's probably ours. */ |
| 233 | *is_ours = 1; |
| 234 | |
| 235 | p = pcap_create_common(device, ebuf, sizeof (struct pcap_septel)); |
| 236 | if (p == NULL) |
| 237 | return NULL; |
| 238 | |
| 239 | p->activate_op = septel_activate; |
| 240 | return p; |
The Android Open Source Project | 478ab6c | 2009-03-03 19:30:05 -0800 | [diff] [blame] | 241 | } |
| 242 | |
| 243 | static int septel_stats(pcap_t *p, struct pcap_stat *ps) { |
JP Abgrall | 511eca3 | 2014-02-12 13:46:45 -0800 | [diff] [blame] | 244 | struct pcap_septel *handlep = p->priv; |
| 245 | /*handlep->stat.ps_recv = 0;*/ |
| 246 | /*handlep->stat.ps_drop = 0;*/ |
Elliott Hughes | d8845d7 | 2015-10-19 18:07:04 -0700 | [diff] [blame^] | 247 | |
JP Abgrall | 511eca3 | 2014-02-12 13:46:45 -0800 | [diff] [blame] | 248 | *ps = handlep->stat; |
Elliott Hughes | d8845d7 | 2015-10-19 18:07:04 -0700 | [diff] [blame^] | 249 | |
The Android Open Source Project | 478ab6c | 2009-03-03 19:30:05 -0800 | [diff] [blame] | 250 | return 0; |
| 251 | } |
| 252 | |
| 253 | |
| 254 | int |
JP Abgrall | 511eca3 | 2014-02-12 13:46:45 -0800 | [diff] [blame] | 255 | septel_findalldevs(pcap_if_t **devlistp, char *errbuf) |
The Android Open Source Project | 478ab6c | 2009-03-03 19:30:05 -0800 | [diff] [blame] | 256 | { |
Elliott Hughes | d8845d7 | 2015-10-19 18:07:04 -0700 | [diff] [blame^] | 257 | return (pcap_add_if(devlistp,"septel",0, |
| 258 | "Intel/Septel device",errbuf)); |
The Android Open Source Project | 478ab6c | 2009-03-03 19:30:05 -0800 | [diff] [blame] | 259 | } |
| 260 | |
| 261 | |
| 262 | /* |
| 263 | * Installs the given bpf filter program in the given pcap structure. There is |
| 264 | * no attempt to store the filter in kernel memory as that is not supported |
| 265 | * with Septel cards. |
| 266 | */ |
| 267 | static int septel_setfilter(pcap_t *p, struct bpf_program *fp) { |
| 268 | if (!p) |
| 269 | return -1; |
| 270 | if (!fp) { |
| 271 | strncpy(p->errbuf, "setfilter: No filter specified", |
| 272 | sizeof(p->errbuf)); |
| 273 | return -1; |
| 274 | } |
| 275 | |
| 276 | /* Make our private copy of the filter */ |
| 277 | |
| 278 | if (install_bpf_program(p, fp) < 0) { |
| 279 | snprintf(p->errbuf, sizeof(p->errbuf), |
| 280 | "malloc: %s", pcap_strerror(errno)); |
| 281 | return -1; |
| 282 | } |
| 283 | |
The Android Open Source Project | 478ab6c | 2009-03-03 19:30:05 -0800 | [diff] [blame] | 284 | return (0); |
| 285 | } |
| 286 | |
| 287 | |
| 288 | static int |
| 289 | septel_setnonblock(pcap_t *p, int nonblock, char *errbuf) |
| 290 | { |
JP Abgrall | 511eca3 | 2014-02-12 13:46:45 -0800 | [diff] [blame] | 291 | fprintf(errbuf, PCAP_ERRBUF_SIZE, "Non-blocking mode not supported on Septel devices"); |
| 292 | return (-1); |
The Android Open Source Project | 478ab6c | 2009-03-03 19:30:05 -0800 | [diff] [blame] | 293 | } |