1335640Shselasky/*
2335640Shselasky * pcap-septel.c: Packet capture interface for Intel/Septel card.
3335640Shselasky *
4335640Shselasky * Authors: Gilbert HOYEK (gil_hoyek@hotmail.com), Elias M. KHOURY
5335640Shselasky * (+961 3 485243)
6335640Shselasky */
7335640Shselasky
8335640Shselasky#ifdef HAVE_CONFIG_H
9335640Shselasky#include <config.h>
10335640Shselasky#endif
11335640Shselasky
12335640Shselasky#include <sys/param.h>
13335640Shselasky
14335640Shselasky#include <stdlib.h>
15335640Shselasky#include <string.h>
16335640Shselasky#include <errno.h>
17335640Shselasky
18335640Shselasky#include "pcap-int.h"
19335640Shselasky
20335640Shselasky#include <ctype.h>
21335640Shselasky#include <netinet/in.h>
22335640Shselasky#include <sys/mman.h>
23335640Shselasky#include <sys/socket.h>
24335640Shselasky#include <sys/types.h>
25335640Shselasky#include <unistd.h>
26335640Shselasky
27335640Shselasky#include <msg.h>
28335640Shselasky#include <ss7_inc.h>
29335640Shselasky#include <sysgct.h>
30335640Shselasky#include <pack.h>
31335640Shselasky#include <system.h>
32335640Shselasky
33335640Shselasky#include "pcap-septel.h"
34335640Shselasky
35335640Shselaskystatic int septel_setfilter(pcap_t *p, struct bpf_program *fp);
36335640Shselaskystatic int septel_stats(pcap_t *p, struct pcap_stat *ps);
37335640Shselaskystatic int septel_getnonblock(pcap_t *p);
38335640Shselaskystatic int septel_setnonblock(pcap_t *p, int nonblock);
39335640Shselasky
40335640Shselasky/*
41335640Shselasky * Private data for capturing on Septel devices.
42335640Shselasky */
43335640Shselaskystruct pcap_septel {
44335640Shselasky	struct pcap_stat stat;
45335640Shselasky}
46335640Shselasky
47335640Shselasky/*
48335640Shselasky *  Read at most max_packets from the capture queue and call the callback
49335640Shselasky *  for each of them. Returns the number of packets handled, -1 if an
50335640Shselasky *  error occured, or -2 if we were told to break out of the loop.
51335640Shselasky */
52335640Shselaskystatic int septel_read(pcap_t *p, int cnt, pcap_handler callback, u_char *user) {
53335640Shselasky
54335640Shselasky  struct pcap_septel *ps = p->priv;
55335640Shselasky  HDR *h;
56335640Shselasky  MSG *m;
57335640Shselasky  int processed = 0 ;
58335640Shselasky  int t = 0 ;
59335640Shselasky
60335640Shselasky  /* identifier for the message queue of the module(upe) from which we are capturing
61335640Shselasky   * packets.These IDs are defined in system.txt . By default it is set to 0x2d
62335640Shselasky   * so change it to 0xdd for technical reason and therefore the module id for upe becomes:
63335640Shselasky   * LOCAL        0xdd           * upe - Example user part task */
64335640Shselasky  unsigned int id = 0xdd;
65335640Shselasky
66335640Shselasky  /* process the packets */
67335640Shselasky  do  {
68335640Shselasky
69335640Shselasky    unsigned short packet_len = 0;
70335640Shselasky    int caplen = 0;
71335640Shselasky    int counter = 0;
72335640Shselasky    struct pcap_pkthdr   pcap_header;
73335640Shselasky    u_char *dp ;
74335640Shselasky
75335640Shselasky    /*
76335640Shselasky     * Has "pcap_breakloop()" been called?
77335640Shselasky     */
78335640Shselaskyloop:
79335640Shselasky    if (p->break_loop) {
80335640Shselasky      /*
81335640Shselasky       * Yes - clear the flag that indicates that
82335640Shselasky       * it has, and return -2 to indicate that
83335640Shselasky       * we were told to break out of the loop.
84335640Shselasky       */
85335640Shselasky      p->break_loop = 0;
86335640Shselasky      return -2;
87335640Shselasky    }
88335640Shselasky
89335640Shselasky    /*repeat until a packet is read
90335640Shselasky     *a NULL message means :
91335640Shselasky     * when no packet is in queue or all packets in queue already read */
92335640Shselasky    do  {
93335640Shselasky      /* receive packet in non-blocking mode
94335640Shselasky       * GCT_grab is defined in the septel library software */
95335640Shselasky      h = GCT_grab(id);
96335640Shselasky
97335640Shselasky      m = (MSG*)h;
98335640Shselasky      /* a couter is added here to avoid an infinite loop
99335640Shselasky       * that will cause our capture program GUI to freeze while waiting
100335640Shselasky       * for a packet*/
101335640Shselasky      counter++ ;
102335640Shselasky
103335640Shselasky    }
104335640Shselasky    while  ((m == NULL)&& (counter< 100)) ;
105335640Shselasky
106335640Shselasky    if (m != NULL) {
107335640Shselasky
108335640Shselasky      t = h->type ;
109335640Shselasky
110335640Shselasky      /* catch only messages with type = 0xcf00 or 0x8f01 corrsponding to ss7 messages*/
111335640Shselasky      /* XXX = why not use API_MSG_TX_REQ for 0xcf00 and API_MSG_RX_IND
112335640Shselasky       * for 0x8f01? */
113335640Shselasky      if ((t != 0xcf00) && (t != 0x8f01)) {
114335640Shselasky        relm(h);
115335640Shselasky        goto loop ;
116335640Shselasky      }
117335640Shselasky
118335640Shselasky      /* XXX - is API_MSG_RX_IND for an MTP2 or MTP3 message? */
119335640Shselasky      dp = get_param(m);/* get pointer to MSG parameter area (m->param) */
120335640Shselasky      packet_len = m->len;
121335640Shselasky      caplen =  p->snapshot ;
122335640Shselasky
123335640Shselasky
124335640Shselasky      if (caplen > packet_len) {
125335640Shselasky
126335640Shselasky        caplen = packet_len;
127335640Shselasky      }
128335640Shselasky      /* Run the packet filter if there is one. */
129335640Shselasky      if ((p->fcode.bf_insns == NULL) || bpf_filter(p->fcode.bf_insns, dp, packet_len, caplen)) {
130335640Shselasky
131335640Shselasky
132335640Shselasky        /*  get a time stamp , consisting of :
133335640Shselasky         *
134335640Shselasky         *  pcap_header.ts.tv_sec:
135335640Shselasky         *  ----------------------
136335640Shselasky         *   a UNIX format time-in-seconds when he packet was captured,
137335640Shselasky         *   i.e. the number of seconds since Epoch time (January 1,1970, 00:00:00 GMT)
138335640Shselasky         *
139335640Shselasky         *  pcap_header.ts.tv_usec :
140335640Shselasky         *  ------------------------
141335640Shselasky         *   the number of microseconds since that second
142335640Shselasky         *   when the packet was captured
143335640Shselasky         */
144335640Shselasky
145335640Shselasky        (void)gettimeofday(&pcap_header.ts, NULL);
146335640Shselasky
147335640Shselasky        /* Fill in our own header data */
148335640Shselasky        pcap_header.caplen = caplen;
149335640Shselasky        pcap_header.len = packet_len;
150335640Shselasky
151335640Shselasky        /* Count the packet. */
152335640Shselasky        ps->stat.ps_recv++;
153335640Shselasky
154335640Shselasky        /* Call the user supplied callback function */
155335640Shselasky        callback(user, &pcap_header, dp);
156335640Shselasky
157335640Shselasky        processed++ ;
158335640Shselasky
159335640Shselasky      }
160335640Shselasky      /* after being processed the packet must be
161335640Shselasky       *released in order to receive another one */
162335640Shselasky      relm(h);
163335640Shselasky    }else
164335640Shselasky      processed++;
165335640Shselasky
166335640Shselasky  }
167335640Shselasky  while (processed < cnt) ;
168335640Shselasky
169335640Shselasky  return processed ;
170335640Shselasky}
171335640Shselasky
172335640Shselasky
173335640Shselaskystatic int
174335640Shselaskyseptel_inject(pcap_t *handle, const void *buf _U_, size_t size _U_)
175335640Shselasky{
176356341Scy  pcap_strlcpy(handle->errbuf, "Sending packets isn't supported on Septel cards",
177335640Shselasky          PCAP_ERRBUF_SIZE);
178335640Shselasky  return (-1);
179335640Shselasky}
180335640Shselasky
181335640Shselasky/*
182335640Shselasky *  Activate a handle for a live capture from the given Septel device.  Always pass a NULL device
183335640Shselasky *  The promisc flag is ignored because Septel cards have built-in tracing.
184335640Shselasky *  The timeout is also ignored as it is not supported in hardware.
185335640Shselasky *
186335640Shselasky *  See also pcap(3).
187335640Shselasky */
188335640Shselaskystatic pcap_t *septel_activate(pcap_t* handle) {
189335640Shselasky  /* Initialize some components of the pcap structure. */
190335640Shselasky  handle->linktype = DLT_MTP2;
191335640Shselasky
192335640Shselasky  /*
193335640Shselasky   * Turn a negative snapshot value (invalid), a snapshot value of
194335640Shselasky   * 0 (unspecified), or a value bigger than the normal maximum
195335640Shselasky   * value, into the maximum allowed value.
196335640Shselasky   *
197335640Shselasky   * If some application really *needs* a bigger snapshot
198335640Shselasky   * length, we should just increase MAXIMUM_SNAPLEN.
199335640Shselasky   */
200335640Shselasky  if (handle->snapshot <= 0 || handle->snapshot > MAXIMUM_SNAPLEN)
201335640Shselasky    handle->snapshot = MAXIMUM_SNAPLEN;
202335640Shselasky
203335640Shselasky  handle->bufsize = 0;
204335640Shselasky
205335640Shselasky  /*
206335640Shselasky   * "select()" and "poll()" don't work on Septel queues
207335640Shselasky   */
208335640Shselasky  handle->selectable_fd = -1;
209335640Shselasky
210335640Shselasky  handle->read_op = septel_read;
211335640Shselasky  handle->inject_op = septel_inject;
212335640Shselasky  handle->setfilter_op = septel_setfilter;
213335640Shselasky  handle->set_datalink_op = NULL; /* can't change data link type */
214335640Shselasky  handle->getnonblock_op = septel_getnonblock;
215335640Shselasky  handle->setnonblock_op = septel_setnonblock;
216335640Shselasky  handle->stats_op = septel_stats;
217335640Shselasky
218335640Shselasky  return 0;
219335640Shselasky}
220335640Shselasky
221335640Shselaskypcap_t *septel_create(const char *device, char *ebuf, int *is_ours) {
222335640Shselasky	const char *cp;
223335640Shselasky	pcap_t *p;
224335640Shselasky
225335640Shselasky	/* Does this look like the Septel device? */
226335640Shselasky	cp = strrchr(device, '/');
227335640Shselasky	if (cp == NULL)
228335640Shselasky		cp = device;
229335640Shselasky	if (strcmp(cp, "septel") != 0) {
230335640Shselasky		/* Nope, it's not "septel" */
231335640Shselasky		*is_ours = 0;
232335640Shselasky		return NULL;
233335640Shselasky	}
234335640Shselasky
235335640Shselasky	/* OK, it's probably ours. */
236335640Shselasky	*is_ours = 1;
237335640Shselasky
238335640Shselasky	p = pcap_create_common(ebuf, sizeof (struct pcap_septel));
239335640Shselasky	if (p == NULL)
240335640Shselasky		return NULL;
241335640Shselasky
242335640Shselasky	p->activate_op = septel_activate;
243335640Shselasky	/*
244335640Shselasky	 * Set these up front, so that, even if our client tries
245335640Shselasky	 * to set non-blocking mode before we're activated, or
246335640Shselasky	 * query the state of non-blocking mode, they get an error,
247335640Shselasky	 * rather than having the non-blocking mode option set
248335640Shselasky	 * for use later.
249335640Shselasky	 */
250335640Shselasky	p->getnonblock_op = septel_getnonblock;
251335640Shselasky	p->setnonblock_op = septel_setnonblock;
252335640Shselasky	return p;
253335640Shselasky}
254335640Shselasky
255335640Shselaskystatic int septel_stats(pcap_t *p, struct pcap_stat *ps) {
256335640Shselasky  struct pcap_septel *handlep = p->priv;
257335640Shselasky  /*handlep->stat.ps_recv = 0;*/
258335640Shselasky  /*handlep->stat.ps_drop = 0;*/
259335640Shselasky
260335640Shselasky  *ps = handlep->stat;
261335640Shselasky
262335640Shselasky  return 0;
263335640Shselasky}
264335640Shselasky
265335640Shselasky
266335640Shselaskyint
267335640Shselaskyseptel_findalldevs(pcap_if_list_t *devlistp, char *errbuf)
268335640Shselasky{
269335640Shselasky  /*
270335640Shselasky   * XXX - do the notions of "up", "running", or "connected" apply here?
271335640Shselasky   */
272335640Shselasky  if (add_dev(devlistp,"septel",0,"Intel/Septel device",errbuf) == NULL)
273335640Shselasky    return -1;
274335640Shselasky  return 0;
275335640Shselasky}
276335640Shselasky
277335640Shselasky
278335640Shselasky/*
279335640Shselasky * Installs the given bpf filter program in the given pcap structure.  There is
280335640Shselasky * no attempt to store the filter in kernel memory as that is not supported
281335640Shselasky * with Septel cards.
282335640Shselasky */
283335640Shselaskystatic int septel_setfilter(pcap_t *p, struct bpf_program *fp) {
284335640Shselasky  if (!p)
285335640Shselasky    return -1;
286335640Shselasky  if (!fp) {
287335640Shselasky    strncpy(p->errbuf, "setfilter: No filter specified",
288335640Shselasky	    sizeof(p->errbuf));
289335640Shselasky    return -1;
290335640Shselasky  }
291335640Shselasky
292335640Shselasky  /* Make our private copy of the filter */
293335640Shselasky
294335640Shselasky  if (install_bpf_program(p, fp) < 0)
295335640Shselasky    return -1;
296335640Shselasky
297335640Shselasky  return (0);
298335640Shselasky}
299335640Shselasky
300335640Shselasky/*
301335640Shselasky * We don't support non-blocking mode.  I'm not sure what we'd
302335640Shselasky * do to support it and, given that we don't support select()/
303335640Shselasky * poll()/epoll_wait()/kevent() etc., it probably doesn't
304335640Shselasky * matter.
305335640Shselasky */
306335640Shselaskystatic int
307335640Shselaskyseptel_getnonblock(pcap_t *p)
308335640Shselasky{
309335640Shselasky  fprintf(p->errbuf, PCAP_ERRBUF_SIZE, "Non-blocking mode not supported on Septel devices");
310335640Shselasky  return (-1);
311335640Shselasky}
312335640Shselasky
313335640Shselaskystatic int
314335640Shselaskyseptel_setnonblock(pcap_t *p, int nonblock _U_)
315335640Shselasky{
316335640Shselasky  fprintf(p->errbuf, PCAP_ERRBUF_SIZE, "Non-blocking mode not supported on Septel devices");
317335640Shselasky  return (-1);
318335640Shselasky}
319335640Shselasky
320335640Shselasky#ifdef SEPTEL_ONLY
321335640Shselasky/*
322335640Shselasky * This libpcap build supports only Septel cards, not regular network
323335640Shselasky * interfaces.
324335640Shselasky */
325335640Shselasky
326335640Shselasky/*
327335640Shselasky * There are no regular interfaces, just Septel interfaces.
328335640Shselasky */
329335640Shselaskyint
330335640Shselaskypcap_platform_finddevs(pcap_if_list_t *devlistp, char *errbuf)
331335640Shselasky{
332335640Shselasky  return (0);
333335640Shselasky}
334335640Shselasky
335335640Shselasky/*
336335640Shselasky * Attempts to open a regular interface fail.
337335640Shselasky */
338335640Shselaskypcap_t *
339335640Shselaskypcap_create_interface(const char *device, char *errbuf)
340335640Shselasky{
341335640Shselasky  pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE,
342335640Shselasky                "This version of libpcap only supports Septel cards");
343335640Shselasky  return (NULL);
344335640Shselasky}
345335640Shselasky
346335640Shselasky/*
347335640Shselasky * Libpcap version string.
348335640Shselasky */
349335640Shselaskyconst char *
350335640Shselaskypcap_lib_version(void)
351335640Shselasky{
352335640Shselasky  return (PCAP_VERSION_STRING " (Septel-only)");
353335640Shselasky}
354335640Shselasky#endif
355