diff options
author | Rémi Denis-Courmont <remi.denis-courmont@nokia.com> | 2009-08-07 15:19:12 +0300 |
---|---|---|
committer | Aki Niemi <aki.niemi@nokia.com> | 2009-08-14 16:56:52 +0300 |
commit | 2bfe1a24b939687d06ac22b9374468316f33eeac (patch) | |
tree | 19342c5f6a1f56e7d1b7ed85820be62abbef78e8 /gisi | |
parent | 2076a044ecc2e9af5e188ad2de312520d6540739 (diff) | |
download | ofono-2bfe1a24b939687d06ac22b9374468316f33eeac.tar.bz2 |
Phonet: basic pipe owner support
This will be needed for GPRS support.
Diffstat (limited to 'gisi')
-rw-r--r-- | gisi/Makefile.am | 3 | ||||
-rw-r--r-- | gisi/pipe.c | 314 | ||||
-rw-r--r-- | gisi/pipe.h | 30 |
3 files changed, 346 insertions, 1 deletions
diff --git a/gisi/Makefile.am b/gisi/Makefile.am index e999b89a..328f07c7 100644 --- a/gisi/Makefile.am +++ b/gisi/Makefile.am @@ -7,5 +7,6 @@ libgisi_la_SOURCES = \ phonet.h \ netlink.h netlink.c \ socket.h socket.c \ - client.h client.c + client.h client.c \ + pipe.h pipe.c libgisi_la_LIBADD = @GLIB_LIBS@ diff --git a/gisi/pipe.c b/gisi/pipe.c new file mode 100644 index 00000000..73116dc9 --- /dev/null +++ b/gisi/pipe.c @@ -0,0 +1,314 @@ +/* + * This file is part of oFono - Open Source Telephony + * + * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). + * + * Contact: Rémi Denis-Courmont <remi.denis-courmont@nokia.com> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <stdint.h> +#include <stdbool.h> +#include <errno.h> +#include <glib.h> +#include "client.h" +#include "pipe.h" + +#define PN_PIPE 0xd9 + +typedef struct { + uint8_t dummy; + uint8_t cmd; + uint8_t state_after; + uint8_t priority; + + uint16_t object1; + uint8_t type1; + uint8_t pad; + + uint16_t object2; + uint8_t type2; + uint8_t n_sb; +} _isi_pipe_create_req_t; + +typedef struct { + uint8_t cmd; + uint8_t pipe_handle; + uint8_t pad; +} isi_pipe_enable_req_t; + +typedef struct { + uint8_t cmd; + uint8_t pipe_handle; + uint8_t state_after; +} isi_pipe_reset_req_t; + +typedef struct { + uint8_t cmd; + uint8_t pipe_handle; +} isi_pipe_remove_req_t; + +typedef struct { + uint8_t cmd; + uint8_t pipe_handle; + uint8_t error_code; + + uint8_t error1; + uint8_t error2; +} isi_pipe_resp_t; + +#define PN_PIPE_INVALID_HANDLE 0xff + +enum { + PNS_PIPE_CREATE_REQ, + PNS_PIPE_CREATE_RESP, + PNS_PIPE_REMOVE_REQ, + PNS_PIPE_REMOVE_RESP, + PNS_PIPE_RESET_REQ, + PNS_PIPE_RESET_RESP, + PNS_PIPE_ENABLE_REQ, + PNS_PIPE_ENABLE_RESP, + PNS_PIPE_REDIRECT_REQ, + PNS_PIPE_REDIRECT_RESP, + PNS_PIPE_DISABLE_REQ, + PNS_PIPE_DISABLE_RESP, +}; + +enum { /* error codes */ + PN_PIPE_NO_ERROR, + PN_PIPE_ERR_INVALID_PARAM, + PN_PIPE_ERR_INVALID_HANDLE, + PN_PIPE_ERR_INVALID_CTRL_ID, + PN_PIPE_ERR_NOT_ALLOWED, + PN_PIPE_ERR_PEP_IN_USE, + PN_PIPE_ERR_OVERLOAD, + PN_PIPE_ERR_DEV_DISCONNECTED, + PN_PIPE_ERR_TIMEOUT, + PN_PIPE_ERR_ALL_PIPES_IN_USE, + PN_PIPE_ERR_GENERAL, + PN_PIPE_ERR_NOT_SUPPORTED, +}; + +enum { /* initial pipe state */ + PN_PIPE_DISABLE, + PN_PIPE_ENABLE, +}; + +enum { + PN_MSG_PRIORITY_LOW = 1, + PN_MSG_PRIORITY_HIGH, +}; + +struct _GIsiPipe { + GIsiClient *client; + int error; + uint8_t handle; + bool enabled; + bool enabling; +}; + +static int g_isi_pipe_error(uint8_t code) +{ + static const int codes[] = { + [PN_PIPE_NO_ERROR] = 0, + [PN_PIPE_ERR_INVALID_PARAM] = -EINVAL, + [PN_PIPE_ERR_INVALID_HANDLE] = -EBADF, + [PN_PIPE_ERR_INVALID_CTRL_ID] = -ENOTSUP, + [PN_PIPE_ERR_NOT_ALLOWED] = -EPERM, + [PN_PIPE_ERR_PEP_IN_USE] = -EBUSY, + [PN_PIPE_ERR_OVERLOAD] = -ENOBUFS, + [PN_PIPE_ERR_DEV_DISCONNECTED] = -ENETDOWN, + [PN_PIPE_ERR_TIMEOUT] = -ETIMEDOUT, + [PN_PIPE_ERR_ALL_PIPES_IN_USE] = -ENFILE, + [PN_PIPE_ERR_GENERAL] = -EAGAIN, + [PN_PIPE_ERR_NOT_SUPPORTED] = -ENOSYS, + }; + + if (code == PN_PIPE_NO_ERROR || + ((code < sizeof(codes) / sizeof(codes[0])) && codes[code])) + return codes[code]; + return -EBADMSG; +} + +static bool g_isi_pipe_created(GIsiClient *client, + const void *restrict data, size_t len, + uint16_t object, void *opaque) +{ + GIsiPipe *pipe = opaque; + const isi_pipe_resp_t *resp = data; + + if (len < 5 || + resp->cmd != PNS_PIPE_CREATE_RESP) + return false; + + if (resp->pipe_handle != PN_PIPE_INVALID_HANDLE) { + pipe->handle = resp->pipe_handle; + if (pipe->enabling) + g_isi_pipe_start(pipe); + } else + pipe->error = g_isi_pipe_error(resp->error_code); + return true; +} + +/** + * Create a Phonet pipe in disabled state and with low priority. + * @param obj1 Object handle of the first end point + * @param obj2 Object handle of the second end point + * @param type1 Type of the first end point + * @param type2 Type of the second end point + * @return a pipe object on success, NULL on error. + */ +GIsiPipe *g_isi_pipe_create(uint16_t obj1, uint16_t obj2, + uint8_t type1, uint8_t type2) +{ + _isi_pipe_create_req_t msg = { + .cmd = PNS_PIPE_CREATE_REQ, + .state_after = PN_PIPE_DISABLE, + .priority = PN_MSG_PRIORITY_LOW, + .object1 = obj1, + .type1 = type1, + .object2 = obj2, + .type2 = type2, + .n_sb = 0, + }; + GIsiPipe *pipe = g_malloc(sizeof(*pipe)); + + pipe->client = g_isi_client_create(PN_PIPE); + pipe->error = 0; + pipe->enabling = false; + pipe->enabled = false; + pipe->handle = PN_PIPE_INVALID_HANDLE; + + if (pipe->client == NULL || + g_isi_request_make(pipe->client, &msg.cmd, sizeof(msg) - 1, 3, + g_isi_pipe_created, pipe) == NULL) + goto error; + + return pipe; + +error: + if (pipe->client) + g_isi_client_destroy(pipe->client); + g_free(pipe); + return NULL; +} + +static const isi_pipe_resp_t * +g_isi_pipe_check_resp(const GIsiPipe *pipe, uint8_t cmd, + const void *restrict data, size_t len) +{ + const isi_pipe_resp_t *resp = data; + + if ((len < 5) || (resp->cmd != cmd) || + (resp->pipe_handle != pipe->handle)) + return NULL; + return resp; +} + +static bool g_isi_pipe_enabled(GIsiClient *client, + const void *restrict data, size_t len, + uint16_t object, void *opaque) +{ + GIsiPipe *pipe = opaque; + const isi_pipe_resp_t *resp; + + resp = g_isi_pipe_check_resp(pipe, PNS_PIPE_ENABLE_RESP, data, len); + if (!resp) + return false; + + pipe->error = g_isi_pipe_error(resp->error_code); + pipe->enabling = false; + if (!pipe->error) + pipe->enabled = true; + return true; +} + +static GIsiRequest *g_isi_pipe_enable(GIsiPipe *pipe) +{ + isi_pipe_enable_req_t msg = { + .cmd = PNS_PIPE_ENABLE_REQ, + .pipe_handle = pipe->handle, + }; + const size_t len = 3; + + return g_isi_request_make(pipe->client, &msg, len, 5, + g_isi_pipe_enabled, pipe); +} + +/** + * Enable a pipe, i.e. turn on data transfer between the two end points. + * @param pipe pipe as returned from g_isi_pipe_create() + * @return 0 on success or an error code + */ +int g_isi_pipe_start(GIsiPipe *pipe) +{ + if (pipe->error) + return pipe->error; + if (pipe->enabling || pipe->enabled) + return 0; + + if (pipe->handle != PN_PIPE_INVALID_HANDLE) + g_isi_pipe_enable(pipe); + else + pipe->enabling = true; +} + +/* Not very useful, it will never have time to trigger */ +static bool g_isi_pipe_removed(GIsiClient *client, + const void *restrict data, size_t len, + uint16_t object, void *opaque) +{ + GIsiPipe *pipe = opaque; + const isi_pipe_resp_t *resp; + + resp = g_isi_pipe_check_resp(pipe, PNS_PIPE_REMOVE_RESP, data, len); + if (!resp) + return false; + + pipe->handle = PN_PIPE_INVALID_HANDLE; + pipe->error = -EPIPE; + return true; +} + + +static GIsiRequest *g_isi_pipe_remove(GIsiPipe *pipe) +{ + isi_pipe_remove_req_t msg = { + .cmd = PNS_PIPE_REMOVE_REQ, + .pipe_handle = pipe->handle, + }; + const size_t len = 3; + + return g_isi_request_make(pipe->client, &msg, len, 5, + g_isi_pipe_removed, pipe); +} + +/** + * Destroy a pipe. If it was connected, it is removed. + * @param pipe pipe as returned from g_isi_pipe_create() + */ +void g_isi_pipe_destroy(GIsiPipe *pipe) +{ + if (!pipe->error) + g_isi_pipe_remove(pipe); + g_isi_client_destroy(pipe->client); + g_free(pipe); +} diff --git a/gisi/pipe.h b/gisi/pipe.h new file mode 100644 index 00000000..a0483df1 --- /dev/null +++ b/gisi/pipe.h @@ -0,0 +1,30 @@ +/* + * This file is part of oFono - Open Source Telephony + * + * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). + * + * Contact: Rémi Denis-Courmont <remi.denis-courmont@nokia.com> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +typedef struct _GIsiPipe GIsiPipe; + +GIsiPipe *g_isi_pipe_create(uint16_t obj1, uint16_t obj2, + uint8_t type1, uint8_t type2); +void g_isi_pipe_destroy(GIsiPipe *pipe); + +int g_isi_pipe_start(GIsiPipe *pipe); |