#include "p2p.h"
-#define NPP_SN "com.android.npp"
-
-struct p2p_npp_channel {
- near_tag_io_cb cb;
- uint32_t adapter_idx;
- uint32_t target_idx;
- int fd;
- guint watch;
- GIOChannel *channel;
-};
-
struct p2p_npp_ndef_entry {
uint8_t action;
uint32_t ndef_length;
struct p2p_npp_ndef_entry ndefs[];
} __attribute__((packed));
-static struct p2p_npp_channel npp_server;
-
-static void npp_read_ndef(int client_fd)
+static int npp_read(int client_fd, uint32_t adapter_idx, uint32_t target_idx,
+ near_tag_io_cb cb)
{
struct near_tag *tag;
struct p2p_npp_frame frame;
struct p2p_npp_ndef_entry entry;
- int bytes_recv, n_ndef, i, ndef_length, total_ndef_length;
+ int bytes_recv, n_ndef, i, ndef_length, total_ndef_length, err;
size_t tag_length;
uint8_t *ndefs, *nfc_data, *current_ndef;
ndefs = NULL;
total_ndef_length = 0;
+ err = 0;
bytes_recv = recv(client_fd, &frame, sizeof(frame), 0);
if (bytes_recv < 0) {
near_error("Could not read NPP frame %d", bytes_recv);
- return;
+ return bytes_recv;
}
n_ndef = GINT_FROM_BE(frame.n_ndef);
if (bytes_recv < 0) {
near_error("Could not read NPP NDEF entry %d",
bytes_recv);
+ err = bytes_recv;
break;
}
if (ndefs == NULL) {
near_error("Could not allocate NDEF buffer %d",
bytes_recv);
+ err = -ENOMEM;
break;
}
if (bytes_recv < 0) {
near_error("Could not read NDEF entry %d",
bytes_recv);
+ err = bytes_recv;
break;
}
}
if (total_ndef_length == 0)
- return;
+ return err;
DBG("Total NDEF length %d", total_ndef_length);
- tag = near_target_add_tag(npp_server.adapter_idx,
- npp_server.target_idx,
+ tag = near_target_add_tag(adapter_idx, target_idx,
total_ndef_length);
if (tag == NULL) {
g_free(ndefs);
- return;
+ return -ENOMEM;
}
for (i = 0; i < total_ndef_length; i++)
nfc_data = near_tag_get_data(tag, &tag_length);
memcpy(nfc_data, ndefs, total_ndef_length);
- near_tlv_parse(tag, npp_server.cb, nfc_data, total_ndef_length);
+ near_tlv_parse(tag, cb, nfc_data, total_ndef_length);
g_free(ndefs);
-}
-
-static gboolean npp_listener_event(GIOChannel *channel, GIOCondition condition,
- gpointer user_data)
-{
- struct sockaddr_nfc_llcp client_addr;
- int server_fd, client_fd;
- socklen_t client_addr_len;
-
- DBG("condition 0x%x", condition);
-
- if (condition & (G_IO_NVAL | G_IO_ERR | G_IO_HUP)) {
- if (npp_server.watch > 0)
- g_source_remove(npp_server.watch);
- npp_server.watch = 0;
-
- near_error("Error with NPP server channel");
-
- return FALSE;
- }
-
- if (condition & G_IO_IN) {
- server_fd = g_io_channel_unix_get_fd(channel);
-
- client_fd = accept(server_fd, (struct sockaddr *)&client_addr, &client_addr_len);
- if (client_fd < 0) {
- near_error("accept failed %d", client_fd);
-
- close(server_fd);
- return FALSE;
- }
-
- DBG("client dsap %d ssap %d",
- client_addr.dsap, client_addr.ssap);
- npp_read_ndef(client_fd);
-
- close(client_fd);
+ return 0;
+}
- return FALSE;
- }
+struct near_p2p_driver npp_driver = {
+ .name = "NPP",
+ .service_name = "com.android.npp",
+ .read = npp_read,
+};
- return FALSE;
+int npp_init(void)
+{
+ return near_p2p_register(&npp_driver);
}
-int npp_bind(uint32_t adapter_idx, uint32_t target_idx,
- near_tag_io_cb cb)
+void npp_exit(void)
{
- int err;
- struct sockaddr_nfc_llcp addr;
-
- npp_server.adapter_idx = adapter_idx;
- npp_server.target_idx = target_idx;
- npp_server.cb = cb;
- npp_server.fd = socket(AF_NFC, SOCK_STREAM, NFC_SOCKPROTO_LLCP);
- if (npp_server.fd < 0)
- return -errno;
-
- memset(&addr, 0, sizeof(struct sockaddr_nfc_llcp));
- addr.sa_family = AF_NFC;
- addr.dev_idx = adapter_idx;
- addr.nfc_protocol = NFC_PROTO_NFC_DEP;
- addr.service_name_len = strlen(NPP_SN);
- strcpy(addr.service_name, NPP_SN);
-
- err = bind(npp_server.fd, (struct sockaddr *)&addr, sizeof(struct sockaddr_nfc_llcp));
- if (err < 0) {
- near_error("NPP bind failed %d", err);
-
- close(npp_server.fd);
- return err;
- }
-
- err = listen(npp_server.fd, 10);
- if (err < 0) {
- near_error("NPP listen failed %d", err);
-
- close(npp_server.fd);
- return err;
- }
-
- npp_server.channel = g_io_channel_unix_new(npp_server.fd);
- g_io_channel_set_close_on_unref(npp_server.channel, TRUE);
-
- npp_server.watch = g_io_add_watch(npp_server.channel,
- G_IO_IN | G_IO_HUP | G_IO_NVAL | G_IO_ERR,
- npp_listener_event,
- (gpointer) &npp_server.channel);
-
- return 0;
+ near_p2p_unregister(&npp_driver);
}
#include <config.h>
#endif
+#include <unistd.h>
+#include <stdint.h>
+#include <errno.h>
+#include <string.h>
+#include <sys/socket.h>
+
+#include <linux/socket.h>
+#include <linux/nfc.h>
+
#include <near/plugin.h>
#include <near/log.h>
#include <near/types.h>
-#include <near/tag.h>
+#include <near/target.h>
+#include <near/tlv.h>
#include "p2p.h"
-static int p2p_read(uint32_t adapter_idx,
+static GSList *driver_list = NULL;
+
+struct p2p_driver_data {
+ struct near_p2p_driver *driver;
+ uint32_t adapter_idx;
+ uint32_t target_idx;
+ near_tag_io_cb cb;
+ int server_fd;
+ guint watch;
+};
+
+static gboolean p2p_listener_event(GIOChannel *channel, GIOCondition condition,
+ gpointer user_data)
+{
+ struct sockaddr_nfc_llcp client_addr;
+ int server_fd, client_fd;
+ socklen_t client_addr_len;
+ struct p2p_driver_data *driver_data = user_data;
+ struct near_p2p_driver *driver = driver_data->driver;
+
+ DBG("condition 0x%x", condition);
+
+ if (condition & (G_IO_NVAL | G_IO_ERR | G_IO_HUP)) {
+ if (driver_data->watch > 0)
+ g_source_remove(driver_data->watch);
+ driver_data->watch = 0;
+
+ near_error("Error with %s server channel", driver->name);
+
+ return FALSE;
+ }
+
+ if (condition & G_IO_IN) {
+ server_fd = g_io_channel_unix_get_fd(channel);
+
+ client_fd = accept(server_fd, (struct sockaddr *)&client_addr,
+ &client_addr_len);
+ if (client_fd < 0) {
+ near_error("accept failed %d", client_fd);
+
+ close(server_fd);
+ return FALSE;
+ }
+
+ DBG("client dsap %d ssap %d",
+ client_addr.dsap, client_addr.ssap);
+
+ driver->read(client_fd, driver_data->adapter_idx,
+ driver_data->target_idx, driver_data->cb);
+
+ close(client_fd);
+
+ return FALSE;
+ }
+
+ return FALSE;
+}
+
+static int p2p_bind(struct near_p2p_driver *driver, uint32_t adapter_idx,
uint32_t target_idx, near_tag_io_cb cb)
{
- int err;
+ int err, fd;
+ struct sockaddr_nfc_llcp addr;
+ GIOChannel *channel;
+ struct p2p_driver_data *driver_data;
+
+ DBG("Binding %s", driver->name);
+
+ fd = socket(AF_NFC, SOCK_STREAM, NFC_SOCKPROTO_LLCP);
+ if (fd < 0)
+ return -errno;
+
+ memset(&addr, 0, sizeof(struct sockaddr_nfc_llcp));
+ addr.sa_family = AF_NFC;
+ addr.dev_idx = adapter_idx;
+ addr.nfc_protocol = NFC_PROTO_NFC_DEP;
+ addr.service_name_len = strlen(driver->service_name);
+ strcpy(addr.service_name, driver->service_name);
+
+ err = bind(fd, (struct sockaddr *)&addr,
+ sizeof(struct sockaddr_nfc_llcp));
+ if (err < 0) {
+ near_error("%s bind failed %d", driver->name, err);
+
+ close(fd);
+ return err;
+ }
+
+ err = listen(fd, 10);
+ if (err < 0) {
+ near_error("%s listen failed %d", driver->name, err);
- err = snep_bind(adapter_idx, target_idx, cb);
- if (err < 0)
+ close(fd);
return err;
+ }
+
+ driver_data = g_try_malloc0(sizeof(struct p2p_driver_data));
+ if (driver_data == NULL) {
+ close(fd);
+ return -ENOMEM;
+ }
+
+ driver_data->driver = driver;
+ driver_data->adapter_idx = adapter_idx;
+ driver_data->target_idx = target_idx;
+ driver_data->server_fd = fd;
+ driver_data->cb = cb;
+
+ channel = g_io_channel_unix_new(fd);
+ g_io_channel_set_close_on_unref(channel, TRUE);
+
+ driver_data->watch = g_io_add_watch(channel,
+ G_IO_IN | G_IO_HUP | G_IO_NVAL | G_IO_ERR,
+ p2p_listener_event,
+ (gpointer) driver_data);
+
+ return 0;
+}
+
+static int p2p_read(uint32_t adapter_idx,
+ uint32_t target_idx, near_tag_io_cb cb)
+{
+ int err = 0;
+ GSList *list;
+
+ for (list = driver_list; list != NULL; list = list->next) {
+ struct near_p2p_driver *driver = list->data;
- return npp_bind(adapter_idx, target_idx, cb);
+ err &= p2p_bind(driver, adapter_idx, target_idx, cb);
+ }
+
+ return err;
}
static struct near_tag_driver p2p_driver = {
.read_tag = p2p_read,
};
+
+int near_p2p_register(struct near_p2p_driver *driver)
+{
+ DBG("driver %p name %s", driver, driver->name);
+
+ driver_list = g_slist_prepend(driver_list, driver);
+
+ return 0;
+}
+
+void near_p2p_unregister(struct near_p2p_driver *driver)
+{
+ DBG("driver %p name %s", driver, driver->name);
+
+ driver_list = g_slist_remove(driver_list, driver);
+}
+
static int p2p_init(void)
{
DBG("");
+ npp_init();
+ snep_init();
+
return near_tag_driver_register(&p2p_driver);
}
{
DBG("");
+ snep_exit();
+ npp_exit();
+
near_tag_driver_unregister(&p2p_driver);
}
#define AF_NFC 39
#endif
+struct near_p2p_driver {
+ const char *name;
+ const char *service_name;
+ int (*read)(int client_fd, uint32_t adapter_idx, uint32_t target_idx,
+ near_tag_io_cb cb);
+};
+
#define TLV_SIZE 2
-int npp_bind(uint32_t adapter_idx, uint32_t target_idx, near_tag_io_cb cb);
-int snep_bind(uint32_t adapter_idx, uint32_t target_idx, near_tag_io_cb cb);
+int npp_init(void);
+void npp_exit(void);
+
+int snep_init(void);
+void snep_exit(void);
+
+int near_p2p_register(struct near_p2p_driver *driver);
+void near_p2p_unregister(struct near_p2p_driver *driver);
#define SNEP_RESP_VERSION 0x80
#define SNEP_RESP_REJECT 0x80
-struct p2p_snep_channel {
- near_tag_io_cb cb;
- uint32_t adapter_idx;
- uint32_t target_idx;
- int fd;
- guint watch;
- GIOChannel *channel;
+struct p2p_snep_data {
uint8_t *nfc_data;
uint32_t nfc_data_length;
uint32_t nfc_data_current_length;
uint8_t info[];
} __attribute__((packed));
-static struct p2p_snep_channel snep_server;
+static struct p2p_snep_data snep_data;
static void snep_response_noinfo(int client_fd, uint8_t response)
{
send(client_fd, &resp, sizeof(resp), 0);
}
-static void snep_read_ndef(int client_fd, int ndef_length,
- near_bool_t allocate)
+static void snep_read_ndef(int client_fd,
+ uint32_t adapter_idx, uint32_t target_idx,
+ near_tag_io_cb cb, int ndef_length, near_bool_t allocate)
{
int bytes_recv, remaining_bytes;
DBG("");
if (allocate == TRUE) {
- g_free(snep_server.nfc_data);
+ g_free(snep_data.nfc_data);
- snep_server.nfc_data = g_try_malloc0(ndef_length + TLV_SIZE);
- if (snep_server.nfc_data == NULL)
+ snep_data.nfc_data = g_try_malloc0(ndef_length + TLV_SIZE);
+ if (snep_data.nfc_data == NULL)
return;
- snep_server.nfc_data[0] = TLV_NDEF;
- snep_server.nfc_data[1] = ndef_length;
+ snep_data.nfc_data[0] = TLV_NDEF;
+ snep_data.nfc_data[1] = ndef_length;
- snep_server.nfc_data_length = ndef_length + TLV_SIZE;
- snep_server.nfc_data_current_length = TLV_SIZE;
- snep_server.nfc_data_ptr = snep_server.nfc_data + TLV_SIZE;
+ snep_data.nfc_data_length = ndef_length + TLV_SIZE;
+ snep_data.nfc_data_current_length = TLV_SIZE;
+ snep_data.nfc_data_ptr = snep_data.nfc_data + TLV_SIZE;
}
- remaining_bytes = snep_server.nfc_data_length - snep_server.nfc_data_current_length;
- bytes_recv = recv(client_fd, snep_server.nfc_data_ptr, remaining_bytes, 0);
+ remaining_bytes = snep_data.nfc_data_length - snep_data.nfc_data_current_length;
+ bytes_recv = recv(client_fd, snep_data.nfc_data_ptr, remaining_bytes, 0);
if (bytes_recv < 0) {
near_error("Could not read SNEP NDEF buffer %d", bytes_recv);
return;
DBG("Received %d bytes", bytes_recv);
- snep_server.nfc_data_current_length += bytes_recv;
+ snep_data.nfc_data_current_length += bytes_recv;
- if (snep_server.nfc_data_length == snep_server.nfc_data_current_length) {
+ if (snep_data.nfc_data_length == snep_data.nfc_data_current_length) {
struct near_tag *tag;
size_t tag_length;
uint8_t *nfc_data;
- snep_server.nfc_data_current_length = 0;
+ snep_data.nfc_data_current_length = 0;
snep_response_noinfo(client_fd, SNEP_RESP_SUCCESS);
- tag = near_target_add_tag(snep_server.adapter_idx,
- snep_server.target_idx,
- snep_server.nfc_data_length);
+ tag = near_target_add_tag(adapter_idx, target_idx,
+ snep_data.nfc_data_length);
if (tag == NULL) {
- g_free(snep_server.nfc_data);
+ g_free(snep_data.nfc_data);
return;
}
nfc_data = near_tag_get_data(tag, &tag_length);
- memcpy(nfc_data, snep_server.nfc_data, tag_length);
+ memcpy(nfc_data, snep_data.nfc_data, tag_length);
- near_tlv_parse(tag, snep_server.cb, nfc_data, tag_length);
- g_free(snep_server.nfc_data);
+ near_tlv_parse(tag, cb, nfc_data, tag_length);
+ g_free(snep_data.nfc_data);
} else {
snep_response_noinfo(client_fd, SNEP_RESP_CONTINUE);
}
}
-static void snep_read(int client_fd)
+static int snep_read(int client_fd, uint32_t adapter_idx, uint32_t target_idx,
+ near_tag_io_cb cb)
{
struct p2p_snep_req_frame frame;
int bytes_recv;
DBG("");
/* If current length is not 0, we're waiting for a fragment */
- if (snep_server.nfc_data_current_length > 0) {
- snep_read_ndef(client_fd, 0, FALSE);
- return;
+ if (snep_data.nfc_data_current_length > 0) {
+ snep_read_ndef(client_fd, adapter_idx, target_idx, cb,
+ 0, FALSE);
+ return 0;
}
bytes_recv = recv(client_fd, &frame, sizeof(frame), 0);
if (bytes_recv < 0) {
near_error("Could not read SNEP frame %d", bytes_recv);
- return;
+ return bytes_recv;
}
DBG("Request 0x%x", frame.request);
case SNEP_REQ_GET:
near_error("Unsupported SNEP request code");
snep_response_noinfo(client_fd, SNEP_RESP_NOT_IMPL);
- break;
+ return -EOPNOTSUPP;
case SNEP_REQ_PUT:
ndef_length = GINT_FROM_BE(frame.length);
- snep_read_ndef(client_fd, ndef_length, TRUE);
- }
-}
-
-static gboolean snep_listener_event(GIOChannel *channel, GIOCondition condition,
- gpointer user_data)
-{
- struct sockaddr_nfc_llcp client_addr;
- int server_fd, client_fd;
- socklen_t client_addr_len;
-
- DBG("condition 0x%x", condition);
-
- if (condition & (G_IO_NVAL | G_IO_ERR | G_IO_HUP)) {
- if (snep_server.watch > 0)
- g_source_remove(snep_server.watch);
- snep_server.watch = 0;
-
- near_error("Error with SNEP server channel");
-
- return FALSE;
+ snep_read_ndef(client_fd, adapter_idx, target_idx, cb,
+ ndef_length, TRUE);
+ break;
}
- if (condition & G_IO_IN) {
- server_fd = g_io_channel_unix_get_fd(channel);
-
- client_fd = accept(server_fd, (struct sockaddr *)&client_addr,
- &client_addr_len);
- if (client_fd < 0) {
- near_error("SNEP accept failed %d", client_fd);
-
- close(server_fd);
- return FALSE;
- }
-
- DBG("client dsap %d ssap %d",
- client_addr.dsap, client_addr.ssap);
-
- snep_read(client_fd);
-
- close(client_fd);
+ return 0;
+}
- return FALSE;
- }
+struct near_p2p_driver snep_driver = {
+ .name = "SNEP",
+ .service_name = "urn:nfc:sn:snep",
+ .read = snep_read,
+};
- return FALSE;
+int snep_init(void)
+{
+ return near_p2p_register(&snep_driver);
}
-int snep_bind(uint32_t adapter_idx, uint32_t target_idx,
- near_tag_io_cb cb)
+void snep_exit(void)
{
- int err;
- struct sockaddr_nfc_llcp addr;
-
- DBG("");
-
- snep_server.adapter_idx = adapter_idx;
- snep_server.target_idx = target_idx;
- snep_server.cb = cb;
- snep_server.fd = socket(AF_NFC, SOCK_STREAM, NFC_SOCKPROTO_LLCP);
- if (snep_server.fd < 0)
- return -errno;
-
- memset(&addr, 0, sizeof(struct sockaddr_nfc_llcp));
- addr.sa_family = AF_NFC;
- addr.dev_idx = adapter_idx;
- addr.nfc_protocol = NFC_PROTO_NFC_DEP;
- addr.service_name_len = strlen(SNEP_SN);
- strcpy(addr.service_name, SNEP_SN);
-
- err = bind(snep_server.fd, (struct sockaddr *)&addr, sizeof(struct sockaddr_nfc_llcp));
- if (err < 0) {
- near_error("SNEP bind failed %d", err);
-
- close(snep_server.fd);
- return err;
- }
-
- err = listen(snep_server.fd, 10);
- if (err < 0) {
- near_error("SNEP listen failed %d", err);
-
- close(snep_server.fd);
- return err;
- }
-
- snep_server.channel = g_io_channel_unix_new(snep_server.fd);
- g_io_channel_set_close_on_unref(snep_server.channel, TRUE);
-
- snep_server.watch = g_io_add_watch(snep_server.channel,
- G_IO_IN | G_IO_HUP | G_IO_NVAL | G_IO_ERR,
- snep_listener_event,
- (gpointer) &snep_server.channel);
-
- return 0;
+ near_p2p_unregister(&snep_driver);
}