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
29 #include <sys/socket.h>
31 #include <linux/socket.h>
34 #include <near/types.h>
36 #include <near/adapter.h>
37 #include <near/device.h>
39 #include <near/ndef.h>
44 #define NDEF_HR_MSG_MIN_LENGTH 0x06
45 #define HR_HEADER_SIZE 6 /* header (1) + type len (1) +
46 * payload len (1) + rec type (2) 'Hx'
50 #define RECORD_TYPE_WKT_ALTERNATIVE_CARRIER 0x0a
51 #define FRAME_TYPE_OFFSET 3
53 enum loop_stage_flag {
54 STATE_MAIN_NDEF = 0x00,
55 STATE_CFG_RECORD = 0x01,
58 static GHashTable *hr_ndef_hash = NULL;
75 near_bool_t cfg_record_state;
76 near_bool_t in_extra_read;
79 struct hr_push_client {
87 static void free_hr_ndef(gpointer data)
89 struct hr_ndef *ndef = data;
97 static void handover_close(int client_fd, int err)
103 ndef = g_hash_table_lookup(hr_ndef_hash, GINT_TO_POINTER(client_fd));
107 g_hash_table_remove(hr_ndef_hash, GINT_TO_POINTER(client_fd));
110 /* Parse an incoming handover buffer*/
111 static int handover_ndef_parse(int client_fd, struct hr_ndef *ndef)
115 struct near_ndef_message *msg;
119 if ((ndef->ndef == NULL) ||
120 (ndef->cur_ptr < NDEF_HR_MSG_MIN_LENGTH)) {
125 /* call the global parse function */
126 records = near_ndef_parse_msg(ndef->ndef, ndef->cur_ptr);
127 if (records == NULL) {
133 * If we receive a request, we should reply with a Hs but
134 * if the initial frame is Hs (it means we initiated the
135 * exchange with a Hr), so we have to do some actions (e.g.:
136 * pairing with bluetooth)
138 if (strncmp((char *) (ndef->ndef + FRAME_TYPE_OFFSET), "Hr", 2) == 0) {
140 * The first entry on the record list is the Hr record.
141 * We build the Hs based on it.
143 msg = near_ndef_prepare_handover_record("Hs", records->data,
144 NEAR_CARRIER_UNKNOWN);
150 near_info("Send Hs frame");
151 err = send(client_fd, msg->data, msg->length, MSG_DONTWAIT);
159 near_ndef_records_free(records);
164 near_error("ndef parsing failed %d", err);
166 handover_close(client_fd, 0);
171 static near_bool_t handover_recv_error(void)
173 near_error("%s", strerror(errno));
181 /* Add extra records right after the end of the "Hr" ndef record */
182 static near_bool_t handover_read_cfg_records(int client_fd,
183 uint32_t adapter_idx, uint32_t target_idx,
186 struct hr_ndef *ndef;
191 ndef = g_hash_table_lookup(hr_ndef_hash, GINT_TO_POINTER(client_fd));
193 near_error("hr_ndef should exist");
197 if (ndef->in_extra_read == TRUE) {
198 /* Next prepare read to complete the Hr */
199 ndef->ndef = g_try_realloc(ndef->ndef, ndef->cur_record_len +
200 NDEF_HR_MSG_MIN_LENGTH);
204 /* Read header bytes */
205 bytes_recv = recv(client_fd, ndef->ndef + ndef->cur_ptr,
206 NDEF_HR_MSG_MIN_LENGTH, MSG_DONTWAIT);
208 return handover_recv_error();
210 /* Now, check the ndef payload size plus header bytes */
211 ndef_size = near_ndef_record_length(ndef->ndef + ndef->cur_ptr,
216 ndef->cur_ptr += bytes_recv;
217 ndef->missing_bytes = ndef_size - bytes_recv;
219 /* Next prepare read to complete the NDEF */
220 ndef->ndef = g_try_realloc(ndef->ndef, ndef->cur_record_len
222 if (ndef->ndef == NULL) {
226 ndef->cur_record_len += ndef_size;
227 ndef->in_extra_read = FALSE;
232 /* Read remaining bytes */
233 bytes_recv = recv(client_fd, ndef->ndef + ndef->cur_ptr,
234 ndef->missing_bytes, MSG_DONTWAIT);
236 return handover_recv_error();
238 ndef->cur_ptr += bytes_recv;
239 ndef->missing_bytes -= bytes_recv;
241 /* Is the NDEF read complete ? */
242 if (ndef->missing_bytes)
243 return TRUE; /* more bytes to come... */
245 ndef->extra_ndef_count--;
246 ndef->in_extra_read = TRUE;
248 if (ndef->extra_ndef_count == 0) {
249 /* All the bytes are read so now, parse the frame */
250 err = handover_ndef_parse(client_fd, ndef);
253 handover_close(client_fd, 0);
260 /* Process the next NDEF */
264 near_error("Handover read NDEFs failed");
268 static near_bool_t handover_read_hr(int client_fd,
269 uint32_t adapter_idx, uint32_t target_idx, near_tag_io_cb cb)
273 struct hr_ndef *ndef;
277 ndef = g_hash_table_lookup(hr_ndef_hash, GINT_TO_POINTER(client_fd));
281 /* Read remaining bytes */
282 bytes_recv = recv(client_fd, ndef->ndef + ndef->cur_ptr,
283 ndef->missing_bytes, MSG_DONTWAIT);
285 return handover_recv_error();
287 ndef->cur_ptr += bytes_recv;
288 ndef->missing_bytes -= bytes_recv;
290 /* Is the ndef "Hr" read complete or should we loop */
291 if (ndef->missing_bytes)
295 * The first NDEF frame is read. We now should determine how many
296 * extra records follow the NDEF frame.
297 * We skip the first 6 bytes (Hr header) to jump on the first record
299 extra_ndefs = near_ndef_count_records(ndef->ndef + HR_HEADER_SIZE,
300 ndef->cur_record_len - HR_HEADER_SIZE,
301 RECORD_TYPE_WKT_ALTERNATIVE_CARRIER);
305 /* There's still some extra ndefs to read */
306 ndef->extra_ndef_count = extra_ndefs;
308 /* End of Handover message - now process extra records */
309 ndef->in_extra_read = TRUE;
310 ndef->cfg_record_state = TRUE;
312 /* But, if there's no ac record, we jump to the parsing */
313 if (ndef->extra_ndef_count == 0) {
314 handover_ndef_parse(client_fd, ndef);
321 near_error("Handover read failed");
325 static near_bool_t handover_read_initialize(int client_fd,
326 uint32_t adapter_idx, uint32_t target_idx, near_tag_io_cb cb)
329 struct hr_ndef *ndef;
333 /* Allocate the ndef structure */
334 ndef = g_try_malloc0(sizeof(struct hr_ndef));
338 /* Allocate and read frame header (6 bytes) */
339 ndef->ndef = g_try_malloc0(NDEF_HR_MSG_MIN_LENGTH);
340 if (ndef->ndef == NULL)
343 /* Initialize default values */
345 ndef->cur_record_len = -1;
346 ndef->adapter_idx = adapter_idx;
347 ndef->target_idx = target_idx;
349 ndef->cfg_record_state = FALSE;
351 g_hash_table_insert(hr_ndef_hash, GINT_TO_POINTER(client_fd), ndef);
353 /* Read header bytes (6) */
354 bytes_recv = recv(client_fd, ndef->ndef,
355 NDEF_HR_MSG_MIN_LENGTH, MSG_DONTWAIT);
357 return handover_recv_error();
359 /* Now, check the ndef payload size plus header bytes */
360 ndef->cur_record_len = near_ndef_record_length(ndef->ndef, bytes_recv);
361 if (ndef->cur_record_len < 0)
364 ndef->cur_ptr += bytes_recv;
365 ndef->missing_bytes = ndef->cur_record_len - bytes_recv;
367 DBG("Handover frame size is %d", ndef->cur_ptr);
369 /* Next prepare read to complete the read */
370 ndef->ndef = g_try_realloc(ndef->ndef, ndef->cur_record_len);
371 if (ndef->ndef == NULL)
383 * This function is a "dispatcher", to read Hr/Hs messages,
384 * and/or additional NDEF messages
386 static near_bool_t handover_read(int client_fd,
387 uint32_t adapter_idx, uint32_t target_idx,
390 struct hr_ndef *ndef;
392 ndef = g_hash_table_lookup(hr_ndef_hash, GINT_TO_POINTER(client_fd));
394 /* First call: allocate and read header bytes */
395 return handover_read_initialize(client_fd, adapter_idx,
399 if (ndef->cfg_record_state == TRUE) {
400 return handover_read_cfg_records(client_fd, adapter_idx,
404 return handover_read_hr(client_fd, adapter_idx, target_idx, cb);
407 static void free_hr_push_client(struct hr_push_client *client, int status)
411 handover_close(client->fd, 0);
414 client->cb(client->adapter_idx, client->target_idx, status);
416 if (client->watch > 0)
417 g_source_remove(client->watch);
422 static gboolean handover_push_event(GIOChannel *channel,
423 GIOCondition condition, gpointer data)
426 struct hr_push_client *client = (struct hr_push_client *) data;
428 DBG("condition 0x%x", condition);
430 if (condition & (G_IO_NVAL | G_IO_ERR | G_IO_HUP)) {
431 near_error("Error with Handover client");
433 free_hr_push_client(client, -EIO);
438 ret = handover_read(client->fd,
439 client->adapter_idx, client->target_idx,
443 free_hr_push_client(client, 0);
448 static int handover_push(int client_fd,
449 uint32_t adapter_idx, uint32_t target_idx,
450 struct near_ndef_message *ndef,
451 near_device_io_cb cb)
454 struct hr_push_client *client;
459 client = g_try_malloc0(sizeof(struct hr_push_client));
463 channel = g_io_channel_unix_new(client_fd);
464 g_io_channel_set_close_on_unref(channel, TRUE);
466 client->fd = client_fd;
467 client->adapter_idx = adapter_idx;
468 client->target_idx = target_idx;
470 client->watch = g_io_add_watch(channel,
471 G_IO_IN | G_IO_HUP | G_IO_NVAL |
472 G_IO_ERR, handover_push_event,
475 g_io_channel_unref(channel);
477 err = send(client_fd, ndef->data, ndef->length, MSG_DONTWAIT);
479 free_hr_push_client(client, err);
480 g_io_channel_unref(channel);
486 struct near_p2p_driver handover_driver = {
488 .service_name = NEAR_DEVICE_SN_HANDOVER,
489 .fallback_service_name = NEAR_DEVICE_SN_SNEP,
490 .read = handover_read,
491 .push = handover_push,
492 .close = handover_close,
495 int handover_init(void)
497 hr_ndef_hash = g_hash_table_new_full(g_direct_hash, g_direct_equal,
500 return near_p2p_register(&handover_driver);
503 void handover_exit(void)
505 near_p2p_unregister(&handover_driver);
507 g_hash_table_destroy(hr_ndef_hash);