diff options
-rw-r--r-- | test/l2test.c | 295 |
1 files changed, 177 insertions, 118 deletions
diff --git a/test/l2test.c b/test/l2test.c index 272f40f6..ac831d97 100644 --- a/test/l2test.c +++ b/test/l2test.c @@ -76,8 +76,8 @@ static long data_size = 0; static bdaddr_t bdaddr; static unsigned short psm = 10; -/* Default number of frames to send */ -static int num_frames = -1; // Infinite +/* Default number of frames to send (-1 = infinite) */ +static int num_frames = -1; static int master = 0; static int auth = 0; @@ -166,46 +166,58 @@ static void hexdump(char *s, unsigned long l) static int do_connect(char *svr) { - struct sockaddr_l2 rem_addr, loc_addr; + struct sockaddr_l2 addr; struct l2cap_options opts; struct l2cap_conninfo conn; - int s, opt; + socklen_t optlen; + int sk, opt; - if ((s = socket(PF_BLUETOOTH, socktype, BTPROTO_L2CAP)) < 0) { - syslog(LOG_ERR, "Can't create socket: %s (%d)", strerror(errno), errno); + /* Create socket */ + sk = socket(PF_BLUETOOTH, socktype, BTPROTO_L2CAP); + if (sk < 0) { + syslog(LOG_ERR, "Can't create socket: %s (%d)", + strerror(errno), errno); return -1; } - memset(&loc_addr, 0, sizeof(loc_addr)); - loc_addr.l2_family = AF_BLUETOOTH; - bacpy(&loc_addr.l2_bdaddr, &bdaddr); - if (bind(s, (struct sockaddr *) &loc_addr, sizeof(loc_addr)) < 0) { - syslog(LOG_ERR, "Can't bind socket: %s (%d)", strerror(errno), errno); - exit(1); + /* Bind to local address */ + memset(&addr, 0, sizeof(addr)); + addr.l2_family = AF_BLUETOOTH; + bacpy(&addr.l2_bdaddr, &bdaddr); + + if (bind(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) { + syslog(LOG_ERR, "Can't bind socket: %s (%d)", + strerror(errno), errno); + goto error; } /* Get default options */ memset(&opts, 0, sizeof(opts)); - opt = sizeof(opts); - if (getsockopt(s, SOL_L2CAP, L2CAP_OPTIONS, &opts, &opt) < 0) { - syslog(LOG_ERR, "Can't get default L2CAP options: %s (%d)", strerror(errno), errno); - return -1; + optlen = sizeof(opts); + + if (getsockopt(sk, SOL_L2CAP, L2CAP_OPTIONS, &opts, &optlen) < 0) { + syslog(LOG_ERR, "Can't get default L2CAP options: %s (%d)", + strerror(errno), errno); + goto error; } /* Set new options */ opts.omtu = omtu; opts.imtu = imtu; - if (setsockopt(s, SOL_L2CAP, L2CAP_OPTIONS, &opts, opt) < 0) { - syslog(LOG_ERR, "Can't set L2CAP options: %s (%d)", strerror(errno), errno); - return -1; + + if (setsockopt(sk, SOL_L2CAP, L2CAP_OPTIONS, &opts, sizeof(opts)) < 0) { + syslog(LOG_ERR, "Can't set L2CAP options: %s (%d)", + strerror(errno), errno); + goto error; } /* Enable SO_LINGER */ if (linger) { struct linger l = { .l_onoff = 1, .l_linger = linger }; - if (setsockopt(s, SOL_SOCKET, SO_LINGER, &l, sizeof(l)) < 0) { + + if (setsockopt(sk, SOL_SOCKET, SO_LINGER, &l, sizeof(l)) < 0) { syslog(LOG_ERR, "Can't enable SO_LINGER: %s (%d)", - strerror(errno), errno); + strerror(errno), errno); return -1; } } @@ -215,63 +227,82 @@ static int do_connect(char *svr) if (reliable) opt |= L2CAP_LM_RELIABLE; - if (setsockopt(s, SOL_L2CAP, L2CAP_LM, &opt, sizeof(opt)) < 0) { - syslog(LOG_ERR, "Can't set L2CAP link mode: %s (%d)", strerror(errno), errno); - exit(1); + if (setsockopt(sk, SOL_L2CAP, L2CAP_LM, &opt, sizeof(opt)) < 0) { + syslog(LOG_ERR, "Can't set L2CAP link mode: %s (%d)", + strerror(errno), errno); + goto error; } - memset(&rem_addr, 0, sizeof(rem_addr)); - rem_addr.l2_family = AF_BLUETOOTH; - str2ba(svr, &rem_addr.l2_bdaddr); - rem_addr.l2_psm = htobs(psm); - if (connect(s, (struct sockaddr *) &rem_addr, sizeof(rem_addr)) < 0 ) { - syslog(LOG_ERR, "Can't connect: %s (%d)", strerror(errno), errno); - close(s); - return -1; + /* Connect to remote device */ + memset(&addr, 0, sizeof(addr)); + addr.l2_family = AF_BLUETOOTH; + str2ba(svr, &addr.l2_bdaddr); + addr.l2_psm = htobs(psm); + + if (connect(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0 ) { + syslog(LOG_ERR, "Can't connect: %s (%d)", + strerror(errno), errno); + goto error; } + /* Get current options */ memset(&opts, 0, sizeof(opts)); - opt = sizeof(opts); - if (getsockopt(s, SOL_L2CAP, L2CAP_OPTIONS, &opts, &opt) < 0) { - syslog(LOG_ERR, "Can't get L2CAP options: %s (%d)", strerror(errno), errno); - close(s); - return -1; + optlen = sizeof(opts); + + if (getsockopt(sk, SOL_L2CAP, L2CAP_OPTIONS, &opts, &optlen) < 0) { + syslog(LOG_ERR, "Can't get L2CAP options: %s (%d)", + strerror(errno), errno); + goto error; } + /* Get connection information */ memset(&conn, 0, sizeof(conn)); - opt = sizeof(conn); - if (getsockopt(s, SOL_L2CAP, L2CAP_CONNINFO, &conn, &opt) < 0) { - syslog(LOG_ERR, "Can't get L2CAP connection information: %s (%d)", strerror(errno), errno); - close(s); - return -1; + optlen = sizeof(conn); + + if (getsockopt(sk, SOL_L2CAP, L2CAP_CONNINFO, &conn, &optlen) < 0) { + syslog(LOG_ERR, "Can't get L2CAP connection information: %s (%d)", + strerror(errno), errno); + goto error; } - syslog(LOG_INFO, "Connected [imtu %d, omtu %d, flush_to %d, mode %d, handle %d, class 0x%02x%02x%02x]", + syslog(LOG_INFO, "Connected [imtu %d, omtu %d, flush_to %d, " + "mode %d, handle %d, class 0x%02x%02x%02x]", opts.imtu, opts.omtu, opts.flush_to, opts.mode, conn.hci_handle, conn.dev_class[2], conn.dev_class[1], conn.dev_class[0]); - return s; + return sk; + +error: + close(sk); + return -1; } static void do_listen(void (*handler)(int sk)) { - struct sockaddr_l2 loc_addr, rem_addr; + struct sockaddr_l2 addr; struct l2cap_options opts; struct l2cap_conninfo conn; - int s, s1, opt; + socklen_t optlen; + int sk, nsk, opt; char ba[18]; - if ((s = socket(PF_BLUETOOTH, socktype, BTPROTO_L2CAP)) < 0) { - syslog(LOG_ERR, "Can't create socket: %s (%d)", strerror(errno), errno); + /* Create socket */ + sk = socket(PF_BLUETOOTH, socktype, BTPROTO_L2CAP); + if (sk < 0) { + syslog(LOG_ERR, "Can't create socket: %s (%d)", + strerror(errno), errno); exit(1); } - loc_addr.l2_family = AF_BLUETOOTH; - bacpy(&loc_addr.l2_bdaddr, &bdaddr); - loc_addr.l2_psm = htobs(psm); - if (bind(s, (struct sockaddr *) &loc_addr, sizeof(loc_addr)) < 0) { - syslog(LOG_ERR, "Can't bind socket: %s (%d)", strerror(errno), errno); - exit(1); + /* Bind to local address */ + addr.l2_family = AF_BLUETOOTH; + bacpy(&addr.l2_bdaddr, &bdaddr); + addr.l2_psm = htobs(psm); + + if (bind(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) { + syslog(LOG_ERR, "Can't bind socket: %s (%d)", + strerror(errno), errno); + goto error; } /* Set link mode */ @@ -287,138 +318,166 @@ static void do_listen(void (*handler)(int sk)) if (secure) opt |= L2CAP_LM_SECURE; - if (opt && setsockopt(s, SOL_L2CAP, L2CAP_LM, &opt, sizeof(opt)) < 0) { - syslog(LOG_ERR, "Can't set L2CAP link mode: %s (%d)", strerror(errno), errno); - exit(1); + if (opt && setsockopt(sk, SOL_L2CAP, L2CAP_LM, &opt, sizeof(opt)) < 0) { + syslog(LOG_ERR, "Can't set L2CAP link mode: %s (%d)", + strerror(errno), errno); + goto error; } /* Get default options */ - opt = sizeof(opts); - if (getsockopt(s, SOL_L2CAP, L2CAP_OPTIONS, &opts, &opt) < 0) { - syslog(LOG_ERR, "Can't get default L2CAP options: %s (%d)", strerror(errno), errno); - exit(1); + memset(&opts, 0, sizeof(opts)); + optlen = sizeof(opts); + + if (getsockopt(sk, SOL_L2CAP, L2CAP_OPTIONS, &opts, &optlen) < 0) { + syslog(LOG_ERR, "Can't get default L2CAP options: %s (%d)", + strerror(errno), errno); + goto error; } /* Set new options */ opts.imtu = imtu; - if (setsockopt(s, SOL_L2CAP, L2CAP_OPTIONS, &opts, opt) < 0) { - syslog(LOG_ERR, "Can't set L2CAP options: %s (%d)", strerror(errno), errno); - exit(1); + + if (setsockopt(sk, SOL_L2CAP, L2CAP_OPTIONS, &opts, sizeof(opts)) < 0) { + syslog(LOG_ERR, "Can't set L2CAP options: %s (%d)", + strerror(errno), errno); + goto error; } if (socktype == SOCK_DGRAM) { - handler(s); + handler(sk); return; } - if (listen(s, 10)) { - syslog(LOG_ERR,"Can not listen on the socket: %s (%d)", strerror(errno), errno); - exit(1); + /* Listen for connections */ + if (listen(sk, 10)) { + syslog(LOG_ERR, "Can not listen on the socket: %s (%d)", + strerror(errno), errno); + goto error; } - syslog(LOG_INFO,"Waiting for connection on psm %d ...", psm); + syslog(LOG_INFO, "Waiting for connection on psm %d ...", psm); while(1) { - opt = sizeof(rem_addr); - if ((s1 = accept(s, (struct sockaddr *) &rem_addr, &opt)) < 0) { - syslog(LOG_ERR,"Accept failed: %s (%d)", strerror(errno), errno); - exit(1); + memset(&addr, 0, sizeof(addr)); + optlen = sizeof(addr); + + nsk = accept(sk, (struct sockaddr *) &addr, &optlen); + if (nsk < 0) { + syslog(LOG_ERR, "Accept failed: %s (%d)", + strerror(errno), errno); + goto error; } if (fork()) { /* Parent */ - close(s1); + close(nsk); continue; } /* Child */ + close(sk); - close(s); - + /* Get current options */ memset(&opts, 0, sizeof(opts)); - opt = sizeof(opts); - if (getsockopt(s1, SOL_L2CAP, L2CAP_OPTIONS, &opts, &opt) < 0) { - syslog(LOG_ERR, "Can't get L2CAP options: %s (%d)", strerror(errno), errno); - close(s1); - exit(1); + optlen = sizeof(opts); + + if (getsockopt(nsk, SOL_L2CAP, L2CAP_OPTIONS, &opts, &optlen) < 0) { + syslog(LOG_ERR, "Can't get L2CAP options: %s (%d)", + strerror(errno), errno); + close(nsk); + goto error; } + /* Get connection information */ memset(&conn, 0, sizeof(conn)); - opt = sizeof(conn); - if (getsockopt(s1, SOL_L2CAP, L2CAP_CONNINFO, &conn, &opt) < 0) { - syslog(LOG_ERR, "Can't get L2CAP connection information: %s (%d)", strerror(errno), errno); - close(s1); - exit(1); + optlen = sizeof(conn); + + if (getsockopt(nsk, SOL_L2CAP, L2CAP_CONNINFO, &conn, &optlen) < 0) { + syslog(LOG_ERR, "Can't get L2CAP connection information: %s (%d)", + strerror(errno), errno); + close(nsk); + goto error; } - ba2str(&rem_addr.l2_bdaddr, ba); - syslog(LOG_INFO, "Connect from %s [imtu %d, omtu %d, flush_to %d, mode %d, handle %d, class 0x%02x%02x%02x]\n", + ba2str(&addr.l2_bdaddr, ba); + syslog(LOG_INFO, "Connect from %s [imtu %d, omtu %d, flush_to %d, " + " mode %d, handle %d, class 0x%02x%02x%02x]", ba, opts.imtu, opts.omtu, opts.flush_to, opts.mode, conn.hci_handle, conn.dev_class[2], conn.dev_class[1], conn.dev_class[0]); /* Enable SO_LINGER */ if (linger) { struct linger l = { .l_onoff = 1, .l_linger = linger }; - if (setsockopt(s, SOL_SOCKET, SO_LINGER, &l, sizeof(l)) < 0) { + + if (setsockopt(nsk, SOL_SOCKET, SO_LINGER, &l, sizeof(l)) < 0) { syslog(LOG_ERR, "Can't enable SO_LINGER: %s (%d)", - strerror(errno), errno); - exit(1); + strerror(errno), errno); + close(nsk); + goto error; } } - handler(s1); + handler(nsk); syslog(LOG_INFO, "Disconnect: %m"); exit(0); } + + return; + +error: + close(sk); + exit(1); } -static void dump_mode(int s) +static void dump_mode(int sk) { - int len; - int opt, optl; + socklen_t optlen; + int opt, len; syslog(LOG_INFO, "Receiving ..."); while (1) { fd_set rset; FD_ZERO(&rset); - FD_SET(s, &rset); + FD_SET(sk, &rset); - if (select(s + 1, &rset, NULL, NULL, NULL) < 0) + if (select(sk + 1, &rset, NULL, NULL, NULL) < 0) return; - if (!FD_ISSET(s, &rset)) + if (!FD_ISSET(sk, &rset)) continue; - len = read(s, buf, data_size); + len = read(sk, buf, data_size); if (len <= 0) { if (len < 0) { if (reliable && (errno == ECOMM)) { - syslog(LOG_INFO, "L2CAP Error ECOMM - clearing error and continuing.\n"); - optl = sizeof(opt); - if (getsockopt(s, SOL_SOCKET, SO_ERROR, &opt, &optl ) < 0) { // Clear error - syslog(LOG_ERR, "Couldn't getsockopt(SO_ERROR): %s (%d)\n", + syslog(LOG_INFO, "L2CAP Error ECOMM - clearing error and continuing."); + optlen = sizeof(opt); + if (getsockopt(sk, SOL_SOCKET, SO_ERROR, &opt, &optlen) < 0) { + syslog(LOG_ERR, "Couldn't getsockopt(SO_ERROR): %s (%d)", strerror(errno), errno); return; } continue; } else { - syslog(LOG_ERR, "Read error: %s(%d)\n", strerror(errno), errno); + syslog(LOG_ERR, "Read error: %s(%d)", + strerror(errno), errno); } } return; } - syslog(LOG_INFO, "Recevied %d bytes\n", len); + syslog(LOG_INFO, "Recevied %d bytes", len); hexdump(buf,len); } } -static void recv_mode(int s) +static void recv_mode(int sk) { struct timeval tv_beg,tv_end,tv_diff; long total; uint32_t seq; - int opt, optl; + socklen_t optlen; + int opt; syslog(LOG_INFO,"Receiving ..."); @@ -431,19 +490,19 @@ static void recv_mode(int s) uint16_t l; int i, r; - if ((r = recv(s, buf, data_size, 0)) <= 0) { + if ((r = recv(sk, buf, data_size, 0)) <= 0) { if (r < 0) { if (reliable && (errno == ECOMM)) { syslog(LOG_INFO, "L2CAP Error ECOMM - clearing error and continuing.\n"); - optl = sizeof(opt); - if (getsockopt(s, SOL_SOCKET, SO_ERROR, &opt, &optl ) < 0) { // Clear error - syslog(LOG_ERR, "Couldn't getsockopt(SO_ERROR): %s (%d)\n", + optlen = sizeof(opt); + if (getsockopt(sk, SOL_SOCKET, SO_ERROR, &opt, &optlen) < 0) { + syslog(LOG_ERR, "Couldn't getsockopt(SO_ERROR): %s (%d)", strerror(errno), errno); return; } continue; } else { - syslog(LOG_ERR, "Read failed. %s(%d)", + syslog(LOG_ERR, "Read failed: %s (%d)", strerror(errno), errno); } } @@ -482,7 +541,7 @@ static void recv_mode(int s) } } -static void send_mode(int s) +static void send_mode(int sk) { uint32_t seq; int i; @@ -498,20 +557,20 @@ static void send_mode(int s) *(uint16_t *) (buf + 4) = htobs(data_size); seq++; - if (send(s, buf, data_size, 0) <= 0) { + if (send(sk, buf, data_size, 0) <= 0) { syslog(LOG_ERR, "Send failed: %s (%d)", strerror(errno), errno); exit(1); } } syslog(LOG_INFO, "Closing channel ..."); - if (shutdown(s, SHUT_RDWR) < 0) + if (shutdown(sk, SHUT_RDWR) < 0) syslog(LOG_INFO, "Close failed: %m"); else syslog(LOG_INFO, "Done"); } -static void senddump_mode(int s) +static void senddump_mode(int sk) { uint32_t seq; int i; @@ -527,13 +586,13 @@ static void senddump_mode(int s) *(uint16_t *) (buf + 4) = htobs(data_size); seq++; - if (send(s, buf, data_size, 0) <= 0) { + if (send(sk, buf, data_size, 0) <= 0) { syslog(LOG_ERR, "Send failed: %s (%d)", strerror(errno), errno); exit(1); } } - dump_mode(s); + dump_mode(sk); } static void reconnect_mode(char *svr) |