blob: 7c1c389e8120d4b24e71c5fde38c0d794e722347 [file] [log] [blame]
Amit Pundir33109f72020-02-07 22:26:08 +05301#include <sys/types.h>
2#include <sys/socket.h>
3#include <sys/time.h>
4#include <linux/qrtr.h>
5#include <unistd.h>
6#include <stdlib.h>
7#include <string.h>
8#include <stdio.h>
9#include <errno.h>
10#include <poll.h>
11
12#include "libqrtr.h"
13#include "logging.h"
14#include "ns.h"
15
16static int qrtr_getname(int sock, struct sockaddr_qrtr *sq)
17{
18 socklen_t sl = sizeof(*sq);
19 int rc;
20
21 rc = getsockname(sock, (void *)sq, &sl);
22 if (rc) {
23 PLOGE("getsockname()");
24 return -1;
25 }
26
27 if (sq->sq_family != AF_QIPCRTR || sl != sizeof(*sq))
28 return -1;
29
30 return 0;
31}
32
33int qrtr_open(int rport)
34{
35 struct timeval tv;
36 int sock;
37 int rc;
38
39 sock = socket(AF_QIPCRTR, SOCK_DGRAM, 0);
40 if (sock < 0) {
41 PLOGE("socket(AF_QIPCRTR)");
42 return -1;
43 }
44
45 tv.tv_sec = 1;
46 tv.tv_usec = 0;
47
48 rc = setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv));
49 if (rc) {
50 PLOGE("setsockopt(SO_RCVTIMEO)");
51 goto err;
52 }
53
54 if (rport != 0) {
55 struct sockaddr_qrtr sq;
56
57 sq.sq_family = AF_QIPCRTR;
58 sq.sq_node = 1;
59 sq.sq_port = rport;
60
61 rc = bind(sock, (void *)&sq, sizeof(sq));
62 if (rc < 0) {
63 PLOGE("bind(%d)", rport);
64 goto err;
65 }
66 }
67
68 return sock;
69err:
70 close(sock);
71 return -1;
72}
73
74void qrtr_close(int sock)
75{
76 close(sock);
77}
78
79int qrtr_sendto(int sock, uint32_t node, uint32_t port, const void *data, unsigned int sz)
80{
81 struct sockaddr_qrtr sq;
82 int rc;
83
84 sq.sq_family = AF_QIPCRTR;
85 sq.sq_node = node;
86 sq.sq_port = port;
87
88 rc = sendto(sock, data, sz, 0, (void *)&sq, sizeof(sq));
89 if (rc < 0) {
90 PLOGE("sendto()");
91 return -1;
92 }
93
94 return 0;
95}
96
97int qrtr_new_server(int sock, uint32_t service, uint16_t version, uint16_t instance)
98{
99 struct qrtr_ctrl_pkt pkt;
100 struct sockaddr_qrtr sq;
101
102 if (qrtr_getname(sock, &sq))
103 return -1;
104
105 memset(&pkt, 0, sizeof(pkt));
106
107 pkt.cmd = cpu_to_le32(QRTR_TYPE_NEW_SERVER);
108 pkt.server.service = cpu_to_le32(service);
109 pkt.server.instance = cpu_to_le32(instance << 8 | version);
110
111 return qrtr_sendto(sock, sq.sq_node, QRTR_PORT_CTRL, &pkt, sizeof(pkt));
112}
113
114int qrtr_remove_server(int sock, uint32_t service, uint16_t version, uint16_t instance)
115{
116 struct qrtr_ctrl_pkt pkt;
117 struct sockaddr_qrtr sq;
118
119 if (qrtr_getname(sock, &sq))
120 return -1;
121
122 memset(&pkt, 0, sizeof(pkt));
123
124 pkt.cmd = cpu_to_le32(QRTR_TYPE_DEL_SERVER);
125 pkt.server.service = cpu_to_le32(service);
126 pkt.server.instance = cpu_to_le32(instance << 8 | version);
127 pkt.server.node = cpu_to_le32(sq.sq_node);
128 pkt.server.port = cpu_to_le32(sq.sq_port);
129
130 return qrtr_sendto(sock, sq.sq_node, QRTR_PORT_CTRL, &pkt, sizeof(pkt));
131}
132
133int qrtr_publish(int sock, uint32_t service, uint16_t version, uint16_t instance)
134{
135 return qrtr_new_server(sock, service, version, instance);
136}
137
138int qrtr_bye(int sock, uint32_t service, uint16_t version, uint16_t instance)
139{
140 return qrtr_remove_server(sock, service, version, instance);
141}
142
143int qrtr_new_lookup(int sock, uint32_t service, uint16_t version, uint16_t instance)
144{
145 struct qrtr_ctrl_pkt pkt;
146 struct sockaddr_qrtr sq;
147
148 if (qrtr_getname(sock, &sq))
149 return -1;
150
151 memset(&pkt, 0, sizeof(pkt));
152
153 pkt.cmd = cpu_to_le32(QRTR_TYPE_NEW_LOOKUP);
154 pkt.server.service = cpu_to_le32(service);
155 pkt.server.instance = cpu_to_le32(instance << 8 | version);
156
157 return qrtr_sendto(sock, sq.sq_node, QRTR_PORT_CTRL, &pkt, sizeof(pkt));
158}
159
160int qrtr_remove_lookup(int sock, uint32_t service, uint16_t version, uint16_t instance)
161{
162 struct qrtr_ctrl_pkt pkt;
163 struct sockaddr_qrtr sq;
164
165 if (qrtr_getname(sock, &sq))
166 return -1;
167
168 memset(&pkt, 0, sizeof(pkt));
169
170 pkt.cmd = cpu_to_le32(QRTR_TYPE_DEL_LOOKUP);
171 pkt.server.service = cpu_to_le32(service);
172 pkt.server.instance = cpu_to_le32(instance << 8 | version);
173 pkt.server.node = cpu_to_le32(sq.sq_node);
174 pkt.server.port = cpu_to_le32(sq.sq_port);
175
176 return qrtr_sendto(sock, sq.sq_node, QRTR_PORT_CTRL, &pkt, sizeof(pkt));
177}
178
179int qrtr_poll(int sock, unsigned int ms)
180{
181 struct pollfd fds;
182
183 fds.fd = sock;
184 fds.revents = 0;
185 fds.events = POLLIN | POLLERR;
186
187 return poll(&fds, 1, ms);
188}
189
190int qrtr_recv(int sock, void *buf, unsigned int bsz)
191{
192 int rc;
193
194 rc = recv(sock, buf, bsz, 0);
195 if (rc < 0)
196 PLOGE("recv()");
197 return rc;
198}
199
200int qrtr_recvfrom(int sock, void *buf, unsigned int bsz, uint32_t *node, uint32_t *port)
201{
202 struct sockaddr_qrtr sq;
203 socklen_t sl;
204 int rc;
205
206 sl = sizeof(sq);
207 rc = recvfrom(sock, buf, bsz, 0, (void *)&sq, &sl);
208 if (rc < 0) {
209 PLOGE("recvfrom()");
210 return rc;
211 }
212 if (node)
213 *node = sq.sq_node;
214 if (port)
215 *port = sq.sq_port;
216 return rc;
217}
218
219int qrtr_decode(struct qrtr_packet *dest, void *buf, size_t len,
220 const struct sockaddr_qrtr *sq)
221{
222 const struct qrtr_ctrl_pkt *ctrl = buf;
223
224 if (sq->sq_port == QRTR_PORT_CTRL){
225 if (len < sizeof(*ctrl))
226 return -EMSGSIZE;
227
228 dest->type = le32_to_cpu(ctrl->cmd);
229 switch (dest->type) {
230 case QRTR_TYPE_BYE:
231 dest->node = le32_to_cpu(ctrl->client.node);
232 break;
233 case QRTR_TYPE_DEL_CLIENT:
234 dest->node = le32_to_cpu(ctrl->client.node);
235 dest->port = le32_to_cpu(ctrl->client.port);
236 break;
237 case QRTR_TYPE_NEW_SERVER:
238 case QRTR_TYPE_DEL_SERVER:
239 dest->node = le32_to_cpu(ctrl->server.node);
240 dest->port = le32_to_cpu(ctrl->server.port);
241 dest->service = le32_to_cpu(ctrl->server.service);
242 dest->version = le32_to_cpu(ctrl->server.instance) & 0xff;
243 dest->instance = le32_to_cpu(ctrl->server.instance) >> 8;
244 break;
245 default:
246 dest->type = 0;
247 }
248 } else {
249 dest->type = QRTR_TYPE_DATA;
250 dest->node = sq->sq_node;
251 dest->port = sq->sq_port;
252
253 dest->data = buf;
254 dest->data_len = len;
255 }
256
257 return 0;
258}