blob: fef73c3d2e1aa2e1b5d509d25cb44c0c4fc7eafb [file] [log] [blame]
Neels Hofmeyr17518fe2017-06-20 04:35:06 +02001/*! \file ipa.c
2 * OpenBSC Abis input driver for ip.access */
3/*
4 * (C) 2009-2017 by Harald Welte <laforge@gnumonks.org>
Harald Welte28aa9912014-08-20 22:06:04 +02005 * (C) 2010 by Holger Hans Peter Freyther
6 * (C) 2010 by On-Waves
7 *
8 * All Rights Reserved
9 *
10 * This program is free software; you can redistribute it and/or modify
Harald Weltefd5ad172014-10-26 20:47:42 +010011 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
Harald Welte28aa9912014-08-20 22:06:04 +020013 * (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
Harald Weltefd5ad172014-10-26 20:47:42 +010018 * GNU General Public License for more details.
Harald Welte28aa9912014-08-20 22:06:04 +020019 *
Harald Weltefd5ad172014-10-26 20:47:42 +010020 * You should have received a copy of the GNU General Public License
Harald Welte28aa9912014-08-20 22:06:04 +020021 * along with this program. If not, see <http://www.gnu.org/licenses/>.
22 *
23 */
24
Harald Welte20725b92017-05-15 12:50:04 +020025#include "config.h"
26
Harald Welte28aa9912014-08-20 22:06:04 +020027#include <unistd.h>
28#include <stdint.h>
29#include <errno.h>
30#include <stdlib.h>
31
Holger Hans Peter Freytheree6652b2015-11-09 16:21:19 +000032#include <sys/types.h>
Harald Welte28aa9912014-08-20 22:06:04 +020033
Harald Welte95871da2017-05-15 12:11:36 +020034#include <osmocom/core/byteswap.h>
Harald Welte28aa9912014-08-20 22:06:04 +020035#include <osmocom/core/msgb.h>
36#include <osmocom/core/talloc.h>
37#include <osmocom/core/logging.h>
38#include <osmocom/core/macaddr.h>
39#include <osmocom/core/select.h>
40
41#include <osmocom/gsm/tlv.h>
42#include <osmocom/gsm/protocol/ipaccess.h>
Harald Weltee3919962014-08-20 22:28:23 +020043#include <osmocom/gsm/ipa.h>
Harald Welte28aa9912014-08-20 22:06:04 +020044
Harald Welte96e2a002017-06-12 21:44:18 +020045/*! \addtogroup ipa
46 * @{
Neels Hofmeyr87e45502017-06-20 00:17:59 +020047 * IPA Multiplex utility routines
Harald Welte96e2a002017-06-12 21:44:18 +020048 */
49
Harald Welte28aa9912014-08-20 22:06:04 +020050#define IPA_ALLOC_SIZE 1200
51
52/*
53 * Common propietary IPA messages:
54 * - PONG: in reply to PING.
55 * - ID_REQUEST: first messages once OML has been established.
56 * - ID_ACK: in reply to ID_ACK.
57 */
58static const uint8_t ipa_pong_msg[] = {
59 0, 1, IPAC_PROTO_IPACCESS, IPAC_MSGT_PONG
60};
61
62static const uint8_t ipa_id_ack_msg[] = {
63 0, 1, IPAC_PROTO_IPACCESS, IPAC_MSGT_ID_ACK
64};
65
66static const uint8_t ipa_id_req_msg[] = {
67 0, 17, IPAC_PROTO_IPACCESS, IPAC_MSGT_ID_GET,
68 0x01, IPAC_IDTAG_UNIT,
69 0x01, IPAC_IDTAG_MACADDR,
70 0x01, IPAC_IDTAG_LOCATION1,
71 0x01, IPAC_IDTAG_LOCATION2,
72 0x01, IPAC_IDTAG_EQUIPVERS,
73 0x01, IPAC_IDTAG_SWVERSION,
74 0x01, IPAC_IDTAG_UNITNAME,
75 0x01, IPAC_IDTAG_SERNR,
76};
77
78
79static const char *idtag_names[] = {
80 [IPAC_IDTAG_SERNR] = "Serial_Number",
81 [IPAC_IDTAG_UNITNAME] = "Unit_Name",
82 [IPAC_IDTAG_LOCATION1] = "Location_1",
83 [IPAC_IDTAG_LOCATION2] = "Location_2",
84 [IPAC_IDTAG_EQUIPVERS] = "Equipment_Version",
85 [IPAC_IDTAG_SWVERSION] = "Software_Version",
86 [IPAC_IDTAG_IPADDR] = "IP_Address",
87 [IPAC_IDTAG_MACADDR] = "MAC_Address",
88 [IPAC_IDTAG_UNIT] = "Unit_ID",
89};
90
Harald Weltee3919962014-08-20 22:28:23 +020091const char *ipa_ccm_idtag_name(uint8_t tag)
Harald Welte28aa9912014-08-20 22:06:04 +020092{
93 if (tag >= ARRAY_SIZE(idtag_names))
94 return "unknown";
95
96 return idtag_names[tag];
97}
98
Harald Weltee3919962014-08-20 22:28:23 +020099int ipa_ccm_idtag_parse(struct tlv_parsed *dec, unsigned char *buf, int len)
Harald Welte28aa9912014-08-20 22:06:04 +0200100{
Holger Hans Peter Freytherf558ed42015-06-02 15:52:06 +0200101 return ipa_ccm_idtag_parse_off(dec, buf, len, 0);
102}
103
104int ipa_ccm_idtag_parse_off(struct tlv_parsed *dec, unsigned char *buf, int len, const int len_offset)
105{
Harald Welte28aa9912014-08-20 22:06:04 +0200106 uint8_t t_len;
107 uint8_t t_tag;
108 uint8_t *cur = buf;
109
110 memset(dec, 0, sizeof(*dec));
111
112 while (len >= 2) {
113 len -= 2;
114 t_len = *cur++;
115 t_tag = *cur++;
116
Holger Hans Peter Freytherf558ed42015-06-02 15:52:06 +0200117 if (t_len < len_offset) {
Max9b4d0652016-11-15 19:21:23 +0100118 LOGP(DLMI, LOGL_ERROR, "minimal offset not included: %d < %d\n", t_len, len_offset);
Holger Hans Peter Freytherf558ed42015-06-02 15:52:06 +0200119 return -EINVAL;
120 }
121
Harald Welte28aa9912014-08-20 22:06:04 +0200122 if (t_len > len + 1) {
Max9b4d0652016-11-15 19:21:23 +0100123 LOGP(DLMI, LOGL_ERROR, "The tag does not fit: %d > %d\n", t_len, len + 1);
Harald Welte28aa9912014-08-20 22:06:04 +0200124 return -EINVAL;
125 }
126
Harald Weltee3919962014-08-20 22:28:23 +0200127 DEBUGPC(DLMI, "%s='%s' ", ipa_ccm_idtag_name(t_tag), cur);
Harald Welte28aa9912014-08-20 22:06:04 +0200128
Holger Hans Peter Freytherf558ed42015-06-02 15:52:06 +0200129 dec->lv[t_tag].len = t_len - len_offset;
Harald Welte28aa9912014-08-20 22:06:04 +0200130 dec->lv[t_tag].val = cur;
131
Holger Hans Peter Freytherf558ed42015-06-02 15:52:06 +0200132 cur += t_len - len_offset;
133 len -= t_len - len_offset;
Harald Welte28aa9912014-08-20 22:06:04 +0200134 }
135 return 0;
136}
137
Harald Weltee3919962014-08-20 22:28:23 +0200138int ipa_parse_unitid(const char *str, struct ipaccess_unit *unit_data)
Harald Welte28aa9912014-08-20 22:06:04 +0200139{
140 unsigned long ul;
141 char *endptr;
142 const char *nptr;
143
144 nptr = str;
145 ul = strtoul(nptr, &endptr, 10);
146 if (endptr <= nptr)
147 return -EINVAL;
148 unit_data->site_id = ul & 0xffff;
149
150 if (*endptr++ != '/')
151 return -EINVAL;
152
153 nptr = endptr;
154 ul = strtoul(nptr, &endptr, 10);
155 if (endptr <= nptr)
156 return -EINVAL;
157 unit_data->bts_id = ul & 0xffff;
158
159 if (*endptr++ != '/')
160 return -EINVAL;
161
162 nptr = endptr;
163 ul = strtoul(nptr, &endptr, 10);
164 if (endptr <= nptr)
165 return -EINVAL;
166 unit_data->trx_id = ul & 0xffff;
167
168 return 0;
169}
170
Harald Weltee3919962014-08-20 22:28:23 +0200171int ipa_ccm_tlv_to_unitdata(struct ipaccess_unit *ud,
Harald Welte28aa9912014-08-20 22:06:04 +0200172 const struct tlv_parsed *tp)
173{
174 int rc = 0;
175
176 if (TLVP_PRES_LEN(tp, IPAC_IDTAG_SERNR, 1))
177 ud->serno = talloc_strdup(ud, (char *)
178 TLVP_VAL(tp, IPAC_IDTAG_SERNR));
179
180 if (TLVP_PRES_LEN(tp, IPAC_IDTAG_UNITNAME, 1))
181 ud->unit_name = talloc_strdup(ud, (char *)
182 TLVP_VAL(tp, IPAC_IDTAG_UNITNAME));
183
184 if (TLVP_PRES_LEN(tp, IPAC_IDTAG_LOCATION1, 1))
185 ud->location1 = talloc_strdup(ud, (char *)
186 TLVP_VAL(tp, IPAC_IDTAG_LOCATION1));
187
188 if (TLVP_PRES_LEN(tp, IPAC_IDTAG_LOCATION2, 1))
189 ud->location2 = talloc_strdup(ud, (char *)
190 TLVP_VAL(tp, IPAC_IDTAG_LOCATION2));
191
192 if (TLVP_PRES_LEN(tp, IPAC_IDTAG_EQUIPVERS, 1))
193 ud->equipvers = talloc_strdup(ud, (char *)
194 TLVP_VAL(tp, IPAC_IDTAG_EQUIPVERS));
195
196 if (TLVP_PRES_LEN(tp, IPAC_IDTAG_SWVERSION, 1))
197 ud->swversion = talloc_strdup(ud, (char *)
198 TLVP_VAL(tp, IPAC_IDTAG_SWVERSION));
199
200 if (TLVP_PRES_LEN(tp, IPAC_IDTAG_MACADDR, 17)) {
201 rc = osmo_macaddr_parse(ud->mac_addr, (char *)
202 TLVP_VAL(tp, IPAC_IDTAG_MACADDR));
203 if (rc < 0)
204 goto out;
205 }
206
207 if (TLVP_PRES_LEN(tp, IPAC_IDTAG_UNIT, 1))
Harald Weltee3919962014-08-20 22:28:23 +0200208 rc = ipa_parse_unitid((char *)
Harald Welte28aa9912014-08-20 22:06:04 +0200209 TLVP_VAL(tp, IPAC_IDTAG_UNIT), ud);
210
211out:
212 return rc;
213}
214
Harald Welte7bc88bb2017-04-15 19:05:33 +0200215#define IPA_STRING_MAX 64
216
Neels Hofmeyr87e45502017-06-20 00:17:59 +0200217/*! Generate IPA CCM ID RESP based on list of IEs
Harald Welte7bc88bb2017-04-15 19:05:33 +0200218 * \param[in] dev Descriptor describing identity data for response
219 * \param[in] ies_req List of IEIs to include in response
220 * \param[in] num_ies_req Number of IEIs in \a ies_req
221 * \returns Message buffer with IPA CCM ID RESP */
222struct msgb *ipa_ccm_make_id_resp(const struct ipaccess_unit *dev,
223 const uint8_t *ies_req, unsigned int num_ies_req)
224{
225 struct msgb *msg = ipa_msg_alloc(16);
226 char str[IPA_STRING_MAX];
227 unsigned int i;
228
229 if (!msg)
230 return NULL;
231
232 *msgb_put(msg, 1) = IPAC_MSGT_ID_RESP;
233
234 for (i = 0; i < num_ies_req; i++) {
235 uint8_t *tag;
236
237 str[0] = '\0';
238 switch (ies_req[i]) {
239 case IPAC_IDTAG_UNIT:
240 snprintf(str, sizeof(str), "%u/%u/%u",
241 dev->site_id, dev->bts_id, dev->trx_id);
242 break;
243 case IPAC_IDTAG_MACADDR:
244 snprintf(str, sizeof(str),
245 "%02x:%02x:%02x:%02x:%02x:%02x",
246 dev->mac_addr[0], dev->mac_addr[1],
247 dev->mac_addr[2], dev->mac_addr[3],
248 dev->mac_addr[4], dev->mac_addr[5]);
249 break;
250 case IPAC_IDTAG_LOCATION1:
251 if (dev->location1)
252 strncpy(str, dev->location1, IPA_STRING_MAX);
253 break;
254 case IPAC_IDTAG_LOCATION2:
255 if (dev->location2)
256 strncpy(str, dev->location2, IPA_STRING_MAX);
257 break;
258 case IPAC_IDTAG_EQUIPVERS:
259 if (dev->equipvers)
260 strncpy(str, dev->equipvers, IPA_STRING_MAX);
261 break;
262 case IPAC_IDTAG_SWVERSION:
263 if (dev->swversion)
264 strncpy(str, dev->swversion, IPA_STRING_MAX);
265 break;
266 case IPAC_IDTAG_UNITNAME:
267 if (dev->unit_name) {
268 snprintf(str, sizeof(str), dev->unit_name, IPA_STRING_MAX);
269 } else {
270 snprintf(str, sizeof(str),
271 "%02x-%02x-%02x-%02x-%02x-%02x",
272 dev->mac_addr[0], dev->mac_addr[1],
273 dev->mac_addr[2], dev->mac_addr[3],
274 dev->mac_addr[4], dev->mac_addr[5]);
275 }
276 break;
277 case IPAC_IDTAG_SERNR:
278 if (dev->serno)
279 strncpy(str, dev->serno, IPA_STRING_MAX);
280 break;
281 default:
282 LOGP(DLINP, LOGL_NOTICE,
283 "Unknown ipaccess tag 0x%02x\n", ies_req[i]);
284 msgb_free(msg);
285 return NULL;
286 }
287 str[IPA_STRING_MAX-1] = '\0';
288
289 LOGP(DLINP, LOGL_INFO, " tag %d: %s\n", ies_req[i], str);
290 tag = msgb_put(msg, 3 + strlen(str) + 1);
291 tag[0] = 0x00;
292 tag[1] = 1 + strlen(str) + 1;
293 tag[2] = ies_req[1];
294 memcpy(tag + 3, str, strlen(str) + 1);
295 }
296 ipa_prepend_header(msg, IPAC_PROTO_IPACCESS);
297 return msg;
298}
299
Neels Hofmeyr87e45502017-06-20 00:17:59 +0200300/*! Generate IPA CCM ID RESP based on requets payload
Harald Welte7bc88bb2017-04-15 19:05:33 +0200301 * \param[in] dev Descriptor describing identity data for response
302 * \param[in] data Payload of the IPA CCM ID GET request
303 * \param[in] len Length of \a data in octets
304 * \returns Message buffer with IPA CCM ID RESP */
305struct msgb *ipa_ccm_make_id_resp_from_req(const struct ipaccess_unit *dev,
306 const uint8_t *data, unsigned int len)
307{
308 uint8_t ies[len/2];
309 unsigned int num_ies = 0;
310 const uint8_t *cur = data;
311
Harald Welte8a4895c2017-04-27 10:25:10 +0200312 memset(ies, 0, sizeof(ies));
313
Harald Welte7bc88bb2017-04-15 19:05:33 +0200314 /* build a array of the IEIs */
315 while (len >= 2) {
316 uint8_t t_len, t_tag;
317 len -= 2;
318 t_len = *cur++;
319 t_tag = *cur++;
320
321 if (t_len > len + 1) {
322 LOGP(DLINP, LOGL_ERROR, "IPA CCM tage 0x%02x does not fit\n", t_tag);
323 break;
324 }
325
326 ies[num_ies++] = t_tag;
327
328 cur += t_len;
329 len -= t_len;
330 }
331 return ipa_ccm_make_id_resp(dev, ies, num_ies);
332}
333
Harald Weltee3919962014-08-20 22:28:23 +0200334int ipa_send(int fd, const void *msg, size_t msglen)
Harald Welte28aa9912014-08-20 22:06:04 +0200335{
336 int ret;
337
338 ret = write(fd, msg, msglen);
339 if (ret < 0)
Jacob Erlbecka6be2242014-12-22 10:58:46 +0100340 return -errno;
Harald Welte28aa9912014-08-20 22:06:04 +0200341 if (ret < msglen) {
Harald Weltee3919962014-08-20 22:28:23 +0200342 LOGP(DLINP, LOGL_ERROR, "ipa_send: short write\n");
Harald Welte28aa9912014-08-20 22:06:04 +0200343 return -EIO;
344 }
345 return ret;
346}
347
Harald Weltee3919962014-08-20 22:28:23 +0200348int ipa_ccm_send_pong(int fd)
Harald Welte28aa9912014-08-20 22:06:04 +0200349{
Harald Weltee3919962014-08-20 22:28:23 +0200350 return ipa_send(fd, ipa_pong_msg, sizeof(ipa_pong_msg));
Harald Welte28aa9912014-08-20 22:06:04 +0200351}
352
Harald Weltee3919962014-08-20 22:28:23 +0200353int ipa_ccm_send_id_ack(int fd)
Harald Welte28aa9912014-08-20 22:06:04 +0200354{
Harald Weltee3919962014-08-20 22:28:23 +0200355 return ipa_send(fd, ipa_id_ack_msg, sizeof(ipa_id_ack_msg));
Harald Welte28aa9912014-08-20 22:06:04 +0200356}
357
Harald Weltee3919962014-08-20 22:28:23 +0200358int ipa_ccm_send_id_req(int fd)
Harald Welte28aa9912014-08-20 22:06:04 +0200359{
Harald Weltee3919962014-08-20 22:28:23 +0200360 return ipa_send(fd, ipa_id_req_msg, sizeof(ipa_id_req_msg));
Harald Welte28aa9912014-08-20 22:06:04 +0200361}
362
363/* base handling of the ip.access protocol */
Harald Weltee3919962014-08-20 22:28:23 +0200364int ipa_ccm_rcvmsg_base(struct msgb *msg, struct osmo_fd *bfd)
Harald Welte28aa9912014-08-20 22:06:04 +0200365{
366 uint8_t msg_type = *(msg->l2h);
367 int ret;
368
369 switch (msg_type) {
370 case IPAC_MSGT_PING:
Harald Weltee3919962014-08-20 22:28:23 +0200371 ret = ipa_ccm_send_pong(bfd->fd);
Harald Welte28aa9912014-08-20 22:06:04 +0200372 if (ret < 0) {
373 LOGP(DLINP, LOGL_ERROR, "Cannot send PING "
374 "message. Reason: %s\n", strerror(errno));
375 break;
376 }
377 ret = 1;
378 break;
379 case IPAC_MSGT_PONG:
380 DEBUGP(DLMI, "PONG!\n");
381 ret = 1;
382 break;
383 case IPAC_MSGT_ID_ACK:
384 DEBUGP(DLMI, "ID_ACK? -> ACK!\n");
Harald Weltee3919962014-08-20 22:28:23 +0200385 ret = ipa_ccm_send_id_ack(bfd->fd);
Harald Welte28aa9912014-08-20 22:06:04 +0200386 if (ret < 0) {
387 LOGP(DLINP, LOGL_ERROR, "Cannot send ID_ACK "
388 "message. Reason: %s\n", strerror(errno));
389 break;
390 }
391 ret = 1;
392 break;
393 default:
394 /* This is not an IPA PING, PONG or ID_ACK message */
395 ret = 0;
396 break;
397 }
398 return ret;
399}
400
401/* base handling of the ip.access protocol */
Harald Weltee3919962014-08-20 22:28:23 +0200402int ipa_ccm_rcvmsg_bts_base(struct msgb *msg, struct osmo_fd *bfd)
Harald Welte28aa9912014-08-20 22:06:04 +0200403{
404 uint8_t msg_type = *(msg->l2h);
405 int ret = 0;
406
407 switch (msg_type) {
408 case IPAC_MSGT_PING:
Harald Weltee3919962014-08-20 22:28:23 +0200409 ret = ipa_ccm_send_pong(bfd->fd);
Harald Welte28aa9912014-08-20 22:06:04 +0200410 if (ret < 0) {
411 LOGP(DLINP, LOGL_ERROR, "Cannot send PONG "
412 "message. Reason: %s\n", strerror(errno));
413 }
414 break;
415 case IPAC_MSGT_PONG:
416 DEBUGP(DLMI, "PONG!\n");
417 break;
418 case IPAC_MSGT_ID_ACK:
419 DEBUGP(DLMI, "ID_ACK\n");
420 break;
421 }
422 return ret;
423}
424
425
Harald Weltee3919962014-08-20 22:28:23 +0200426void ipa_prepend_header_ext(struct msgb *msg, int proto)
Harald Welte28aa9912014-08-20 22:06:04 +0200427{
428 struct ipaccess_head_ext *hh_ext;
429
430 /* prepend the osmo ip.access header extension */
431 hh_ext = (struct ipaccess_head_ext *) msgb_push(msg, sizeof(*hh_ext));
432 hh_ext->proto = proto;
433}
434
Harald Weltee3919962014-08-20 22:28:23 +0200435void ipa_prepend_header(struct msgb *msg, int proto)
Harald Welte28aa9912014-08-20 22:06:04 +0200436{
437 struct ipaccess_head *hh;
438
439 /* prepend the ip.access header */
440 hh = (struct ipaccess_head *) msgb_push(msg, sizeof(*hh));
Harald Welte95871da2017-05-15 12:11:36 +0200441 hh->len = osmo_htons(msg->len - sizeof(*hh));
Harald Welte28aa9912014-08-20 22:06:04 +0200442 hh->proto = proto;
443}
444
Harald Welte20725b92017-05-15 12:50:04 +0200445#ifdef HAVE_SYS_SOCKET_H
446#include <sys/socket.h>
447
Harald Welte28aa9912014-08-20 22:06:04 +0200448int ipa_msg_recv(int fd, struct msgb **rmsg)
449{
450 int rc = ipa_msg_recv_buffered(fd, rmsg, NULL);
451 if (rc < 0) {
452 errno = -rc;
453 rc = -1;
454 }
455 return rc;
456}
457
458int ipa_msg_recv_buffered(int fd, struct msgb **rmsg, struct msgb **tmp_msg)
459{
460 struct msgb *msg = tmp_msg ? *tmp_msg : NULL;
461 struct ipaccess_head *hh;
462 int len, ret;
463 int needed;
464
465 if (msg == NULL) {
466 msg = ipa_msg_alloc(0);
467 if (msg == NULL) {
468 ret = -ENOMEM;
469 goto discard_msg;
470 }
471 msg->l1h = msg->tail;
472 }
473
474 if (msg->l2h == NULL) {
475 /* first read our 3-byte header */
476 needed = sizeof(*hh) - msg->len;
477 ret = recv(fd, msg->tail, needed, 0);
478 if (ret == 0)
479 goto discard_msg;
480
481 if (ret < 0) {
482 if (errno == EAGAIN || errno == EINTR)
483 ret = 0;
484 else {
485 ret = -errno;
486 goto discard_msg;
487 }
488 }
489
490 msgb_put(msg, ret);
491
492 if (ret < needed) {
493 if (msg->len == 0) {
494 ret = -EAGAIN;
495 goto discard_msg;
496 }
497
498 LOGP(DLINP, LOGL_INFO,
Harald Weltef196a022014-08-21 09:42:03 +0200499 "Received part of IPA message header (%d/%zu)\n",
Harald Welte28aa9912014-08-20 22:06:04 +0200500 msg->len, sizeof(*hh));
501 if (!tmp_msg) {
502 ret = -EIO;
503 goto discard_msg;
504 }
505 *tmp_msg = msg;
506 return -EAGAIN;
507 }
508
509 msg->l2h = msg->tail;
510 }
511
512 hh = (struct ipaccess_head *) msg->data;
513
514 /* then read the length as specified in header */
Harald Welte95871da2017-05-15 12:11:36 +0200515 len = osmo_ntohs(hh->len);
Harald Welte28aa9912014-08-20 22:06:04 +0200516
517 if (len < 0 || IPA_ALLOC_SIZE < len + sizeof(*hh)) {
518 LOGP(DLINP, LOGL_ERROR, "bad message length of %d bytes, "
519 "received %d bytes\n", len, msg->len);
520 ret = -EIO;
521 goto discard_msg;
522 }
523
524 needed = len - msgb_l2len(msg);
525
526 if (needed > 0) {
527 ret = recv(fd, msg->tail, needed, 0);
528
529 if (ret == 0)
530 goto discard_msg;
531
532 if (ret < 0) {
533 if (errno == EAGAIN || errno == EINTR)
534 ret = 0;
535 else {
536 ret = -errno;
537 goto discard_msg;
538 }
539 }
540
541 msgb_put(msg, ret);
542
543 if (ret < needed) {
544 LOGP(DLINP, LOGL_INFO,
545 "Received part of IPA message L2 data (%d/%d)\n",
546 msgb_l2len(msg), len);
547 if (!tmp_msg) {
548 ret = -EIO;
549 goto discard_msg;
550 }
551 *tmp_msg = msg;
552 return -EAGAIN;
553 }
554 }
555
556 ret = msgb_l2len(msg);
557
558 if (ret == 0) {
559 LOGP(DLINP, LOGL_INFO,
560 "Discarding IPA message without payload\n");
561 ret = -EAGAIN;
562 goto discard_msg;
563 }
564
565 if (tmp_msg)
566 *tmp_msg = NULL;
567 *rmsg = msg;
568 return ret;
569
570discard_msg:
571 if (tmp_msg)
572 *tmp_msg = NULL;
573 msgb_free(msg);
574 return ret;
575}
576
Harald Welte20725b92017-05-15 12:50:04 +0200577#endif /* SYS_SOCKET_H */
578
Harald Welte28aa9912014-08-20 22:06:04 +0200579struct msgb *ipa_msg_alloc(int headroom)
580{
581 struct msgb *nmsg;
582
583 headroom += sizeof(struct ipaccess_head);
584
Neels Hofmeyr889ab162017-09-07 20:41:12 +0200585 nmsg = msgb_alloc_headroom(1200 + headroom, headroom, "IPA Multiplex");
Harald Welte28aa9912014-08-20 22:06:04 +0200586 if (!nmsg)
587 return NULL;
588 return nmsg;
589}
Harald Welte96e2a002017-06-12 21:44:18 +0200590
591/*! @} */