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 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 36 #include <msg.h> 37 #include <ss7_inc.h> 38 #include <sysgct.h> 39 #include <pack.h> 40 #include <system.h> 41 42 #include "pcap-septel.h" 43 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_getnonblock(pcap_t *p); 47 static int septel_setnonblock(pcap_t *p, int nonblock); 48 49 /* 50 * Private data for capturing on Septel devices. 51 */ 52 struct pcap_septel { 53 struct pcap_stat stat; 54 } 55 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 63 struct pcap_septel *ps = p->priv; 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. */ 161 ps->stat.ps_recv++; 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 /* 191 * Activate a handle for a live capture from the given Septel device. Always pass a NULL device 192 * The promisc flag is ignored because Septel cards have built-in tracing. 193 * The timeout is also ignored as it is not supported in hardware. 194 * 195 * See also pcap(3). 196 */ 197 static pcap_t *septel_activate(pcap_t* handle) { 198 /* Initialize some components of the pcap structure. */ 199 handle->linktype = DLT_MTP2; 200 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 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 */ 223 handle->getnonblock_op = septel_getnonblock; 224 handle->setnonblock_op = septel_setnonblock; 225 handle->stats_op = septel_stats; 226 227 return 0; 228 } 229 230 pcap_t *septel_create(const char *device, char *ebuf, int *is_ours) { 231 const char *cp; 232 pcap_t *p; 233 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 247 p = pcap_create_common(ebuf, sizeof (struct pcap_septel)); 248 if (p == NULL) 249 return NULL; 250 251 p->activate_op = septel_activate; 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; 261 return p; 262 } 263 264 static int septel_stats(pcap_t *p, struct pcap_stat *ps) { 265 struct pcap_septel *handlep = p->priv; 266 /*handlep->stat.ps_recv = 0;*/ 267 /*handlep->stat.ps_drop = 0;*/ 268 269 *ps = handlep->stat; 270 271 return 0; 272 } 273 274 275 int 276 septel_findalldevs(pcap_if_list_t *devlistp, char *errbuf) 277 { 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; 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 303 if (install_bpf_program(p, fp) < 0) 304 return -1; 305 306 return (0); 307 } 308 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 } 321 322 static int 323 septel_setnonblock(pcap_t *p, int nonblock _U_) 324 { 325 fprintf(p->errbuf, PCAP_ERRBUF_SIZE, "Non-blocking mode not supported on Septel devices"); 326 return (-1); 327 } 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 339 pcap_platform_finddevs(pcap_if_list_t *devlistp, char *errbuf) 340 { 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 } 354 355 /* 356 * Libpcap version string. 357 */ 358 const char * 359 pcap_lib_version(void) 360 { 361 return (PCAP_VERSION_STRING " (Septel-only)"); 362 } 363 #endif 364