Integrate neard post 0.6 changes - handover code
[profile/ivi/neard.git] / plugins / npp.c
1 /*
2  *
3  *  neard - Near Field Communication manager
4  *
5  *  Copyright (C) 2012  Intel Corporation. All rights reserved.
6  *
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.
10  *
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.
15  *
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
19  *
20  */
21
22 #ifdef HAVE_CONFIG_H
23 #include <config.h>
24 #endif
25
26 #include <stdint.h>
27 #include <errno.h>
28 #include <string.h>
29 #include <sys/socket.h>
30
31 #include <linux/socket.h>
32 #include <linux/nfc.h>
33
34 #include <near/plugin.h>
35 #include <near/log.h>
36 #include <near/types.h>
37 #include <near/adapter.h>
38 #include <near/device.h>
39 #include <near/ndef.h>
40 #include <near/tlv.h>
41
42 #include "p2p.h"
43
44 struct p2p_npp_ndef_entry {
45         uint8_t action;
46         uint32_t ndef_length;
47         uint8_t ndef[];
48 } __attribute__((packed));
49
50 struct p2p_npp_frame {
51         uint8_t version;
52         uint32_t n_ndef;
53         struct p2p_npp_ndef_entry ndefs[];
54 } __attribute__((packed));
55
56 static near_bool_t npp_read(int client_fd,
57                         uint32_t adapter_idx, uint32_t target_idx,
58                         near_tag_io_cb cb)
59 {
60         struct near_device *device;
61         struct p2p_npp_frame frame;
62         struct p2p_npp_ndef_entry entry;
63         int bytes_recv, n_ndef, i, ndef_length, total_ndef_length, err;
64         uint8_t *ndefs, *current_ndef;
65         GList *records;
66
67         ndefs = NULL;
68         total_ndef_length = 0;
69         err = 0;
70
71         bytes_recv = recv(client_fd, &frame, sizeof(frame), 0);
72         if (bytes_recv < 0) {
73                 near_error("Could not read NPP frame %d", bytes_recv);
74                 return bytes_recv;
75         }
76
77         n_ndef = GINT_FROM_BE(frame.n_ndef);
78
79         DBG("version %d %d NDEFs", frame.version, n_ndef);
80
81         for (i = 0; i < n_ndef; i++) {
82                 bytes_recv = recv(client_fd, &entry, sizeof(entry), 0);
83                 if (bytes_recv < 0) {
84                         near_error("Could not read NPP NDEF entry %d",
85                                                                 bytes_recv);
86                         err = bytes_recv;
87                         break;
88                 }
89
90                 ndef_length = GINT_FROM_BE(entry.ndef_length);
91                 total_ndef_length += ndef_length + TLV_SIZE;
92                 DBG("NDEF %d length %d", i, ndef_length);
93
94                 ndefs = g_try_realloc(ndefs, total_ndef_length);
95                 if (ndefs == NULL) {
96                         near_error("Could not allocate NDEF buffer %d",
97                                                                 bytes_recv);
98                         err = -ENOMEM;
99                         break;
100                 }
101
102                 current_ndef = ndefs + total_ndef_length
103                                         - (ndef_length + TLV_SIZE);
104                 current_ndef[0] = TLV_NDEF;
105                 current_ndef[1] = ndef_length;
106
107                 bytes_recv = recv(client_fd, current_ndef + TLV_SIZE,
108                                         ndef_length, 0);
109                 if (bytes_recv < 0) {
110                         near_error("Could not read NDEF entry %d",
111                                                         bytes_recv);
112                         err = bytes_recv;
113                         break;
114                 }
115         }
116
117         if (total_ndef_length == 0)
118                 return err;
119
120         DBG("Total NDEF length %d", total_ndef_length);
121
122         err = near_tag_add_data(adapter_idx, target_idx,
123                                         ndefs, total_ndef_length);
124         if (err < 0)
125                 return FALSE;
126
127         device = near_device_get_device(adapter_idx, target_idx);
128         if (device == NULL) {
129                 g_free(ndefs);
130                 return -ENOMEM;
131         }
132
133         for (i = 0; i < total_ndef_length; i++)
134                 DBG("NDEF[%d] 0x%x", i, ndefs[i]);
135
136         records = near_tlv_parse(ndefs, total_ndef_length);
137         near_device_add_records(device, records, cb, 0);
138
139         g_free(ndefs);
140
141         return FALSE;
142 }
143
144 struct near_p2p_driver npp_driver = {
145         .name = "NPP",
146         .service_name = NEAR_DEVICE_SN_NPP,
147         .fallback_service_name = NULL,
148         .read = npp_read,
149 };
150
151 int npp_init(void)
152 {
153         return near_p2p_register(&npp_driver);
154 }
155
156 void npp_exit(void)
157 {
158         near_p2p_unregister(&npp_driver);
159 }