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