3 * neard - Near Field Communication manager
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
30 #include <sys/socket.h>
32 #include <linux/socket.h>
34 #include <near/nfc_copy.h>
35 #include <near/types.h>
37 #include <near/adapter.h>
38 #include <near/device.h>
40 #include <near/ndef.h>
45 #define NDEF_HR_MSG_MIN_LENGTH 0x06
46 #define HR_HEADER_SIZE 6 /* header (1) + type len (1) +
47 * payload len (1) + rec type (2) 'Hx'
51 #define RECORD_TYPE_WKT_ALTERNATIVE_CARRIER 0x0a
52 #define FRAME_TYPE_OFFSET 3
54 enum loop_stage_flag {
55 STATE_MAIN_NDEF = 0x00,
56 STATE_CFG_RECORD = 0x01,
59 static GHashTable *hr_ndef_hash = NULL;
76 bool cfg_record_state;
80 struct hr_push_client {
88 static void free_hr_ndef(gpointer data)
90 struct hr_ndef *ndef = data;
98 static void handover_close(int client_fd, int err)
100 struct hr_ndef *ndef;
104 ndef = g_hash_table_lookup(hr_ndef_hash, GINT_TO_POINTER(client_fd));
108 g_hash_table_remove(hr_ndef_hash, GINT_TO_POINTER(client_fd));
111 /* Parse an incoming handover buffer*/
112 static int handover_ndef_parse(int client_fd, struct hr_ndef *ndef)
116 struct near_ndef_message *msg = NULL;
120 if ((ndef->ndef == NULL) ||
121 (ndef->cur_ptr < NDEF_HR_MSG_MIN_LENGTH)) {
126 /* call the global parse function */
127 records = near_ndef_parse_msg(ndef->ndef, ndef->cur_ptr, &msg);
128 if (records == NULL) {
133 near_ndef_records_free(records);
136 near_info("Send Hs frame");
137 err = send(client_fd, msg->data, msg->length, MSG_DONTWAIT);
148 near_error("ndef parsing failed %d", err);
150 handover_close(client_fd, 0);
155 static bool handover_recv_error(void)
157 near_error("%s", strerror(errno));
165 /* Add extra records right after the end of the "Hr" ndef record */
166 static bool handover_read_cfg_records(int client_fd,
167 uint32_t adapter_idx, uint32_t target_idx,
170 struct hr_ndef *ndef;
176 ndef = g_hash_table_lookup(hr_ndef_hash, GINT_TO_POINTER(client_fd));
178 near_error("hr_ndef should exist");
182 if (ndef->in_extra_read) {
183 /* Next prepare read to complete the Hr */
184 new_ndef = g_try_realloc(ndef->ndef, ndef->cur_record_len +
185 NDEF_HR_MSG_MIN_LENGTH);
186 if (new_ndef == NULL)
189 ndef->ndef = new_ndef;
191 /* Read header bytes */
192 bytes_recv = recv(client_fd, ndef->ndef + ndef->cur_ptr,
193 NDEF_HR_MSG_MIN_LENGTH, MSG_DONTWAIT);
195 return handover_recv_error();
197 /* Now, check the ndef payload size plus header bytes */
198 ndef_size = near_ndef_record_length(ndef->ndef + ndef->cur_ptr,
203 ndef->cur_ptr += bytes_recv;
204 ndef->missing_bytes = ndef_size - bytes_recv;
206 /* Next prepare read to complete the NDEF */
207 new_ndef = g_try_realloc(ndef->ndef, ndef->cur_record_len
209 if (new_ndef == NULL)
212 ndef->ndef = new_ndef;
214 ndef->cur_record_len += ndef_size;
215 ndef->in_extra_read = false;
220 /* Read remaining bytes */
221 bytes_recv = recv(client_fd, ndef->ndef + ndef->cur_ptr,
222 ndef->missing_bytes, MSG_DONTWAIT);
224 return handover_recv_error();
226 ndef->cur_ptr += bytes_recv;
227 ndef->missing_bytes -= bytes_recv;
229 /* Is the NDEF read complete ? */
230 if (ndef->missing_bytes)
231 return true; /* more bytes to come... */
233 if (ndef->extra_ndef_count > 0)
234 ndef->extra_ndef_count--;
236 ndef->in_extra_read = true;
238 if (ndef->extra_ndef_count == 0) {
239 /* All the bytes are read so now, parse the frame */
240 err = handover_ndef_parse(client_fd, ndef);
243 handover_close(client_fd, 0);
250 /* Process the next NDEF */
254 near_error("Handover read NDEFs failed");
258 static bool handover_read_hr(int client_fd,
259 uint32_t adapter_idx, uint32_t target_idx, near_tag_io_cb cb)
263 struct hr_ndef *ndef;
267 ndef = g_hash_table_lookup(hr_ndef_hash, GINT_TO_POINTER(client_fd));
271 /* Read remaining bytes */
272 bytes_recv = recv(client_fd, ndef->ndef + ndef->cur_ptr,
273 ndef->missing_bytes, MSG_DONTWAIT);
275 return handover_recv_error();
277 ndef->cur_ptr += bytes_recv;
278 ndef->missing_bytes -= bytes_recv;
280 /* Is the ndef "Hr" read complete or should we loop */
281 if (ndef->missing_bytes)
285 * The first NDEF frame is read. We now should determine how many
286 * extra records follow the NDEF frame.
287 * We skip the first 6 bytes (Hr header) to jump on the first record
289 extra_ndefs = near_ndef_count_records(ndef->ndef + HR_HEADER_SIZE,
290 ndef->cur_record_len - HR_HEADER_SIZE,
291 RECORD_TYPE_WKT_ALTERNATIVE_CARRIER);
295 /* There's still some extra ndefs to read */
296 ndef->extra_ndef_count = extra_ndefs;
298 /* End of Handover message - now process extra records */
299 ndef->in_extra_read = true;
300 ndef->cfg_record_state = true;
302 /* But, if there's no ac record, we jump to the parsing */
303 if (ndef->extra_ndef_count == 0) {
304 handover_ndef_parse(client_fd, ndef);
311 near_error("Handover read failed");
315 static bool handover_read_initialize(int client_fd,
316 uint32_t adapter_idx, uint32_t target_idx, near_tag_io_cb cb)
319 struct hr_ndef *ndef;
323 /* Allocate the ndef structure */
324 ndef = g_try_malloc0(sizeof(struct hr_ndef));
328 /* Allocate and read frame header (6 bytes) */
329 ndef->ndef = g_try_malloc0(NDEF_HR_MSG_MIN_LENGTH);
330 if (ndef->ndef == NULL)
333 /* Initialize default values */
335 ndef->cur_record_len = -1;
336 ndef->adapter_idx = adapter_idx;
337 ndef->target_idx = target_idx;
339 ndef->cfg_record_state = false;
341 g_hash_table_insert(hr_ndef_hash, GINT_TO_POINTER(client_fd), ndef);
343 /* Read header bytes (6) */
344 bytes_recv = recv(client_fd, ndef->ndef,
345 NDEF_HR_MSG_MIN_LENGTH, MSG_DONTWAIT);
347 return handover_recv_error();
349 /* Now, check the ndef payload size plus header bytes */
350 ndef->cur_record_len = near_ndef_record_length(ndef->ndef, bytes_recv);
351 if (ndef->cur_record_len < 0)
354 ndef->cur_ptr += bytes_recv;
355 ndef->missing_bytes = ndef->cur_record_len - bytes_recv;
357 if (ndef->cur_record_len == NDEF_HR_MSG_MIN_LENGTH) {
358 handover_ndef_parse(client_fd, ndef);
362 DBG("Handover frame size is %d", ndef->cur_ptr);
364 /* Next prepare read to complete the read */
365 ndef->ndef = g_try_realloc(ndef->ndef, ndef->cur_record_len);
366 if (ndef->ndef == NULL)
378 * This function is a "dispatcher", to read Hr/Hs messages,
379 * and/or additional NDEF messages
381 static bool handover_read(int client_fd,
382 uint32_t adapter_idx, uint32_t target_idx,
385 struct hr_ndef *ndef;
387 ndef = g_hash_table_lookup(hr_ndef_hash, GINT_TO_POINTER(client_fd));
389 /* First call: allocate and read header bytes */
390 return handover_read_initialize(client_fd, adapter_idx,
394 if (ndef->cfg_record_state) {
395 return handover_read_cfg_records(client_fd, adapter_idx,
399 return handover_read_hr(client_fd, adapter_idx, target_idx, cb);
402 static void free_hr_push_client(struct hr_push_client *client, int status)
406 handover_close(client->fd, 0);
409 client->cb(client->adapter_idx, client->target_idx, status);
411 if (client->watch > 0)
412 g_source_remove(client->watch);
417 static gboolean handover_push_event(GIOChannel *channel,
418 GIOCondition condition, gpointer data)
421 struct hr_push_client *client = (struct hr_push_client *) data;
423 DBG("condition 0x%x", condition);
425 if (condition & (G_IO_NVAL | G_IO_ERR | G_IO_HUP)) {
426 near_error("Error with Handover client");
428 free_hr_push_client(client, -EIO);
433 ret = handover_read(client->fd,
434 client->adapter_idx, client->target_idx,
438 free_hr_push_client(client, 0);
443 static int handover_push(int client_fd,
444 uint32_t adapter_idx, uint32_t target_idx,
445 struct near_ndef_message *ndef,
446 near_device_io_cb cb)
449 struct hr_push_client *client;
454 client = g_try_malloc0(sizeof(struct hr_push_client));
458 channel = g_io_channel_unix_new(client_fd);
459 g_io_channel_set_close_on_unref(channel, TRUE);
461 client->fd = client_fd;
462 client->adapter_idx = adapter_idx;
463 client->target_idx = target_idx;
465 client->watch = g_io_add_watch(channel,
466 G_IO_IN | G_IO_HUP | G_IO_NVAL |
467 G_IO_ERR, handover_push_event,
470 g_io_channel_unref(channel);
472 err = send(client_fd, ndef->data, ndef->length, MSG_DONTWAIT);
474 free_hr_push_client(client, err);
475 g_io_channel_unref(channel);
481 struct near_p2p_driver handover_driver = {
483 .service_name = NEAR_DEVICE_SN_HANDOVER,
484 .fallback_service_name = NEAR_DEVICE_SN_SNEP,
485 .sock_type = SOCK_STREAM,
486 .read = handover_read,
487 .push = handover_push,
488 .close = handover_close,
491 int handover_init(void)
493 hr_ndef_hash = g_hash_table_new_full(g_direct_hash, g_direct_equal,
496 return near_p2p_register(&handover_driver);
499 void handover_exit(void)
501 near_p2p_unregister(&handover_driver);
503 g_hash_table_destroy(hr_ndef_hash);