3 * Near Field Communication nfctool
5 * Copyright (C) 2012 Intel Corporation. All rights reserved.
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as
9 * published by the Free Software Foundation.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
26 #include <sys/socket.h>
29 #include <near/nfc_copy.h>
36 #define LLCP_MAX_LTO 0xff
37 #define LLCP_MAX_RW 0x0f
38 #define LLCP_MAX_MIUX 0x7ff
40 static GMainLoop *main_loop = NULL;
42 static int nfctool_poll_cb(guint8 cmd, guint32 idx, gpointer data);
44 static void nfctool_quit(gboolean force);
46 static gchar *nfctool_poll_mode_str(int mode)
48 if (mode == POLLING_MODE_TARGET)
51 if (mode == POLLING_MODE_BOTH)
52 return "both initiator and target";
57 static int nfctool_start_poll(void)
61 struct nfc_adapter *adapter;
63 adapter = adapter_get(opts.adapter_idx);
65 if (adapter == NULL) {
66 print_error("Invalid adapter index: %d", opts.adapter_idx);
71 nl_add_event_handler(NFC_EVENT_TARGETS_FOUND, nfctool_poll_cb);
72 nl_add_event_handler(NFC_EVENT_TM_ACTIVATED, nfctool_poll_cb);
74 err = nl_start_poll(adapter, opts.poll_mode);
77 printf("Start polling on nfc%d as %s\n\n",
78 adapter->idx, nfctool_poll_mode_str(opts.poll_mode));
85 if (adapter->rf_mode == NFC_RF_NONE)
86 printf("nfc%d already in polling mode\n\n", adapter->idx);
88 printf("nfc%d already activated\n\n", adapter->idx);
93 static int nfctool_set_params(void)
95 struct nfc_adapter *adapter;
98 adapter = adapter_get(opts.adapter_idx);
102 err = nl_set_params(adapter, opts.lto, opts.rw, opts.miux);
104 print_error("Error setting one of the parameters.");
108 nl_get_params(adapter);
110 adapter_print_info(adapter);
116 static void nfctool_send_dep_link_up(guint32 target_idx, guint32 adapter_idx)
118 nl_send_dep_link_up(adapter_idx, target_idx);
121 static int nfctool_targets_found(guint32 adapter_idx)
124 struct nfc_adapter *adapter;
126 DBG("adapter_idx: %d", adapter_idx);
128 if (adapter_idx == INVALID_ADAPTER_IDX)
131 adapter = adapter_get(adapter_idx);
136 err = nl_get_targets(adapter);
138 print_error("Error getting targets\n");
142 printf("Targets found for nfc%d\n", adapter_idx);
143 adpater_print_targets(adapter, " ");
145 if (adapter->polling) {
146 g_slist_foreach(adapter->devices,
147 (GFunc)nfctool_send_dep_link_up,
148 GINT_TO_POINTER(adapter_idx));
150 adapter->polling = FALSE;
157 static int nfctool_poll_cb(guint8 cmd, guint32 idx, gpointer data)
161 DBG("cmd: %d, idx: %d", cmd, idx);
164 case NFC_EVENT_TARGETS_FOUND:
165 err = nfctool_targets_found(idx);
167 case NFC_EVENT_TM_ACTIVATED:
168 printf("Target mode activated\n");
177 static volatile sig_atomic_t __terminated = 0;
179 static void sig_term(int sig)
181 if (__terminated > 0)
191 struct nfctool_options opts = {
194 .poll_mode = POLLING_MODE_INITIATOR,
196 .adapter_idx = INVALID_ADAPTER_IDX,
201 .need_netlink = FALSE,
205 .show_timestamp = SNIFFER_SHOW_TIMESTAMP_NONE,
206 .pcap_filename = NULL,
209 static gboolean opt_parse_poll_arg(const gchar *option_name, const gchar *value,
210 gpointer data, GError **error)
214 opts.poll_mode = POLLING_MODE_INITIATOR;
217 if (*value == 't' || *value == 'T')
218 opts.poll_mode = POLLING_MODE_TARGET;
219 else if (*value == 'b' || *value == 'B')
220 opts.poll_mode = POLLING_MODE_BOTH;
226 static gboolean opt_parse_set_param_arg(const gchar *option_name,
228 gpointer data, GError **error)
230 gchar **params = NULL, **keyval = NULL;
235 params = g_strsplit(value, ",", -1);
238 while (params[i] != NULL) {
239 keyval = g_strsplit(params[i], "=", 2);
241 if (keyval[0] == NULL || keyval[1] == NULL) {
246 intval = strtol(keyval[1], &end, 10);
247 if (keyval[1] == end) {
252 if (g_ascii_strcasecmp(keyval[0], "lto") == 0) {
253 if (intval < 0 || intval > LLCP_MAX_LTO) {
254 print_error("Bad value: max lto value is %d",
261 } else if (g_ascii_strcasecmp(keyval[0], "rw") == 0) {
262 if (intval < 0 || intval > LLCP_MAX_RW) {
263 print_error("Bad value: max rw value is %d",
270 } else if (g_ascii_strcasecmp(keyval[0], "miux") == 0) {
271 if (intval < 0 || intval > LLCP_MAX_MIUX) {
272 print_error("Bad value: max miux value is %d",
284 opts.set_param = TRUE;
304 static gboolean opt_parse_show_timestamp_arg(const gchar *option_name,
306 gpointer data, GError **error)
308 if (value != NULL && (*value == 'a' || *value == 'A'))
309 opts.show_timestamp = SNIFFER_SHOW_TIMESTAMP_ABS;
311 opts.show_timestamp = SNIFFER_SHOW_TIMESTAMP_DELTA;
316 static GOptionEntry option_entries[] = {
317 { "list", 'l', 0, G_OPTION_ARG_NONE, &opts.list,
318 "list attached NFC devices", NULL },
319 { "device", 'd', 0, G_OPTION_ARG_STRING, &opts.device_name,
320 "specify a nfc device", "nfcX" },
321 { "poll", 'p', G_OPTION_FLAG_OPTIONAL_ARG, G_OPTION_ARG_CALLBACK,
322 opt_parse_poll_arg, "start polling as initiator, target, or both; "
323 "default mode is initiator", "[Initiator|Target|Both]" },
324 { "set-param", 's', 0, G_OPTION_ARG_CALLBACK, opt_parse_set_param_arg,
325 "set lto, rw, and/or miux parameters", "lto=150,rw=1,miux=100" },
326 { "sniff", 'n', 0, G_OPTION_ARG_NONE, &opts.sniff,
327 "start LLCP sniffer on the specified device", NULL },
328 { "snapshot-len", 'a', 0, G_OPTION_ARG_INT, &opts.snap_len,
329 "packet snapshot length (in bytes); only relevant with -n", "1024" },
330 { "dump-symm", 'y', 0, G_OPTION_ARG_NONE, &opts.dump_symm,
331 "dump SYMM packets to stdout (flooding); only relevant with -n",
333 { "show-timestamp", 't', G_OPTION_FLAG_OPTIONAL_ARG,
334 G_OPTION_ARG_CALLBACK, opt_parse_show_timestamp_arg,
335 "show packet timestamp as the delta from first frame (default) "
336 "or absolute value; only relevant with -n", "[delta|abs]" },
337 { "pcap-file", 'f', 0, G_OPTION_ARG_STRING, &opts.pcap_filename,
338 "specify a filename to save traffic in pcap format; "
339 "only relevant with -n", "filename" },
343 static int nfctool_options_parse(int argc, char **argv)
345 GOptionContext *context;
346 GError *error = NULL;
350 context = g_option_context_new("- A small NFC tool box");
352 g_option_context_add_main_entries(context, option_entries, NULL);
354 if (!g_option_context_parse(context, &argc, &argv, &error)) {
355 print_error("%s: %s", argv[0], error->message);
362 if (opts.device_name != NULL) {
363 if (strncmp("nfc", opts.device_name, 3) != 0) {
364 print_error("Invalid device name: %s",
370 start = opts.device_name + 3;
372 opts.adapter_idx = strtol(start, &end, 10);
374 print_error("Invalid NFC adapter %s", opts.device_name);
380 opts.need_netlink = opts.list || opts.poll || opts.set_param;
382 if (!opts.need_netlink && !opts.sniff) {
383 printf("%s", g_option_context_get_help(context, TRUE, NULL));
388 if ((opts.poll || opts.set_param || opts.sniff) &&
389 opts.adapter_idx == INVALID_ADAPTER_IDX) {
390 print_error("Please specify a device with -d nfcX option");
398 g_option_context_free(context);
403 static void nfctool_main_loop_start(void)
407 memset(&sa, 0, sizeof(sa));
408 sa.sa_handler = sig_term;
409 sigaction(SIGINT, &sa, NULL);
410 sigaction(SIGTERM, &sa, NULL);
412 main_loop = g_main_loop_new(NULL, FALSE);
414 g_main_loop_run(main_loop);
417 static void nfctool_options_cleanup(void)
419 if (opts.device_name != NULL)
420 g_free(opts.device_name);
422 if (opts.pcap_filename != NULL)
423 g_free(opts.pcap_filename);
426 static void nfctool_main_loop_clean(void)
428 if (main_loop != NULL)
429 g_main_loop_unref(main_loop);
432 static void nfctool_quit(gboolean force)
434 if (force || !opts.sniff)
435 g_main_loop_quit(main_loop);
438 int main(int argc, char **argv)
442 err = nfctool_options_parse(argc, argv);
448 if (opts.need_netlink) {
453 err = adapter_all_get_devices();
457 if (opts.list && !opts.set_param)
458 adapter_idx_print_info(opts.adapter_idx);
460 if (opts.set_param) {
461 err = nfctool_set_params();
467 err = nfctool_start_poll();
469 if (err == -EBUSY && opts.sniff)
478 err = sniffer_init();
483 if (opts.poll || opts.sniff)
484 nfctool_main_loop_start();
489 nfctool_main_loop_clean();
497 nfctool_options_cleanup();