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