diff --git a/include/openbsc/misdn.h b/include/openbsc/misdn.h index f3f198022..09dc5ba3f 100644 --- a/include/openbsc/misdn.h +++ b/include/openbsc/misdn.h @@ -22,5 +22,6 @@ int mi_setup(struct gsm_bts *bts, int cardnr, void (cb)(int event, struct gsm_bts *bts)); +void mi_set_pcap_fd(int fd); #endif diff --git a/src/bsc_hack.c b/src/bsc_hack.c index 9fa0157de..c59024a90 100644 --- a/src/bsc_hack.c +++ b/src/bsc_hack.c @@ -27,6 +27,8 @@ #include #include #include +#include +#include #define _GNU_SOURCE #include @@ -689,6 +691,20 @@ static int bootstrap_network(void) return 0; } + +static void create_pcap_file(char *file) +{ + mode_t mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH; + int fd = open(file, O_WRONLY|O_TRUNC|O_CREAT, mode); + + if (fd < 0) { + perror("Failed to open file for pcap"); + return; + } + + mi_set_pcap_fd(fd); +} + static void print_usage() { printf("Usage: bsc_hack\n"); @@ -704,6 +720,7 @@ static void print_help() printf(" -l --database db-name The database to use\n"); printf(" -a --authorize-everyone Allow everyone into the network.\n"); printf(" -r --reject-cause number The reject cause for LOCATION UPDATING REJECT.\n"); + printf(" -p --pcap file The filename of the pcap file\n"); printf(" -h --help this text\n"); } @@ -720,10 +737,11 @@ static void handle_options(int argc, char** argv) {"database", 1, 0, 'l'}, {"authorize-everyone", 0, 0, 'a'}, {"reject-cause", 1, 0, 'r'}, + {"pcap", 1, 0, 'p'}, {0, 0, 0, 0} }; - c = getopt_long(argc, argv, "hc:n:d:sar:", + c = getopt_long(argc, argv, "hc:n:d:sar:p:", long_options, &option_index); if (c == -1) break; @@ -754,6 +772,9 @@ static void handle_options(int argc, char** argv) case 'r': gsm0408_set_reject_cause(atoi(optarg)); break; + case 'p': + create_pcap_file(optarg); + break; default: /* ignore */ break; diff --git a/src/misdn.c b/src/misdn.c index ab378da34..0d54c7928 100644 --- a/src/misdn.c +++ b/src/misdn.c @@ -1,6 +1,7 @@ /* OpenBSC Abis interface to mISDNuser */ /* (C) 2008 by Harald Welte + * (C) 2009 by Holger Hans Peter Freyther * * All Rights Reserved * @@ -45,6 +46,88 @@ #define NUM_E1_TS 32 + +/* + * pcap writing of the misdn load + * pcap format is from http://wiki.wireshark.org/Development/LibpcapFileFormat + */ +#define WTAP_ENCAP_ISDN 17 +#define PCAP_INPUT 0 +#define PCAP_OUTPUT 1 + +struct pcap_hdr { + u_int32_t magic_number; + u_int16_t version_major; + u_int16_t version_minor; + int32_t thiszone; + u_int32_t sigfigs; + u_int32_t snaplen; + u_int32_t network; +} __attribute__((packed)); + +struct pcaprec_hdr { + u_int32_t ts_sec; + u_int32_t ts_usec; + u_int32_t incl_len; + u_int32_t orig_len; +} __attribute__((packed)); + +struct fake_lapd_frame { + u_int8_t ea1 : 1; + u_int8_t cr : 1; + u_int8_t sapi : 6; + u_int8_t ea2 : 1; + u_int8_t tei : 7; + u_int8_t control_foo; /* fake UM's ... */ +} __attribute__((packed)); + +static int pcap_fd = -1; + +void mi_set_pcap_fd(int fd) +{ + int ret; + struct pcap_hdr header = { + .magic_number = 0xa1b2c3d4, + .version_major = 2, + .version_minor = 4, + .thiszone = 0, + .sigfigs = 0, + .snaplen = 65535, + .network = WTAP_ENCAP_ISDN, + }; + + pcap_fd = fd; + ret = write(pcap_fd, &header, sizeof(header)); +} + +static void write_pcap_packet(int direction, struct sockaddr_mISDN* addr, + struct msgb *msg) { + if (pcap_fd < 0) + return; + + int ret; + struct fake_lapd_frame header = { + .ea1 = 0, + .cr = PCAP_OUTPUT ? 1 : 0, + .sapi = addr->sapi & 0x3F, + .ea2 = 1, + .tei = addr->tei & 0x7F, + .control_foo = 0x13 /* UI with P set */, + }; + + struct pcaprec_hdr payload_header = { + .ts_sec = 0, + .ts_usec = 0, + .incl_len = msg->len + sizeof(header) - MISDN_HEADER_LEN, + .orig_len = msg->len + sizeof(header) - MISDN_HEADER_LEN, + }; + + ret = write(pcap_fd, &header, sizeof(header)); + ret = write(pcap_fd, &payload_header, sizeof(payload_header)); + ret = write(pcap_fd, msg->data + MISDN_HEADER_LEN, + msg->len - MISDN_HEADER_LEN); +} + /* data structure for one E1 interface with A-bis */ struct mi_e1_handle { struct gsm_bts *bts; @@ -122,6 +205,8 @@ static int handle_ts1_read(struct bsc_fd *bfd) DEBUGP(DMI, "<= len = %d, prim(0x%x) id(0x%x)\n", ret, hh->prim, hh->id); + write_pcap_packet(PCAP_INPUT, &l2addr, msg); + switch (hh->prim) { case DL_INFORMATION_IND: DEBUGP(DMI, "got DL_INFORMATION_IND\n"); @@ -218,6 +303,8 @@ static int handle_ts1_write(struct bsc_fd *bfd) fprintf(stdout, "OML TX: "); hexdump(l2_data, msg->len - MISDN_HEADER_LEN); } + + write_pcap_packet(PCAP_OUTPUT, &e1h->omladdr, msg); ret = sendto(bfd->fd, msg->data, msg->len, 0, (struct sockaddr *)&e1h->omladdr, sizeof(e1h->omladdr)); @@ -243,6 +330,7 @@ static int handle_ts1_write(struct bsc_fd *bfd) hexdump(l2_data, msg->len - MISDN_HEADER_LEN); } + write_pcap_packet(PCAP_OUTPUT, &e1h->l2addr, msg); ret = sendto(bfd->fd, msg->data, msg->len, 0, (struct sockaddr *)&e1h->l2addr, sizeof(e1h->l2addr));