blob: fa6a8b0d9c6ea4a27abf021c682855cf92d9e19f [file] [log] [blame]
Harald Welte28aa9912014-08-20 22:06:04 +02001/* OpenBSC Abis input driver for ip.access */
2
Harald Welte7bc88bb2017-04-15 19:05:33 +02003/* (C) 2009-2017 by Harald Welte <laforge@gnumonks.org>
Harald Welte28aa9912014-08-20 22:06:04 +02004 * (C) 2010 by Holger Hans Peter Freyther
5 * (C) 2010 by On-Waves
6 *
7 * All Rights Reserved
8 *
9 * This program is free software; you can redistribute it and/or modify
Harald Weltefd5ad172014-10-26 20:47:42 +010010 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
Harald Welte28aa9912014-08-20 22:06:04 +020012 * (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
Harald Weltefd5ad172014-10-26 20:47:42 +010017 * GNU General Public License for more details.
Harald Welte28aa9912014-08-20 22:06:04 +020018 *
Harald Weltefd5ad172014-10-26 20:47:42 +010019 * You should have received a copy of the GNU General Public License
Harald Welte28aa9912014-08-20 22:06:04 +020020 * along with this program. If not, see <http://www.gnu.org/licenses/>.
21 *
22 */
23
Harald Welte20725b92017-05-15 12:50:04 +020024#include "config.h"
25
Harald Welte28aa9912014-08-20 22:06:04 +020026#include <unistd.h>
27#include <stdint.h>
28#include <errno.h>
29#include <stdlib.h>
30
Holger Hans Peter Freytheree6652b2015-11-09 16:21:19 +000031#include <sys/types.h>
Harald Welte28aa9912014-08-20 22:06:04 +020032
Harald Welte95871da2017-05-15 12:11:36 +020033#include <osmocom/core/byteswap.h>
Harald Welte28aa9912014-08-20 22:06:04 +020034#include <osmocom/core/msgb.h>
35#include <osmocom/core/talloc.h>
36#include <osmocom/core/logging.h>
37#include <osmocom/core/macaddr.h>
38#include <osmocom/core/select.h>
39
40#include <osmocom/gsm/tlv.h>
41#include <osmocom/gsm/protocol/ipaccess.h>
Harald Weltee3919962014-08-20 22:28:23 +020042#include <osmocom/gsm/ipa.h>
Harald Welte28aa9912014-08-20 22:06:04 +020043
44#define IPA_ALLOC_SIZE 1200
45
46/*
47 * Common propietary IPA messages:
48 * - PONG: in reply to PING.
49 * - ID_REQUEST: first messages once OML has been established.
50 * - ID_ACK: in reply to ID_ACK.
51 */
52static const uint8_t ipa_pong_msg[] = {
53 0, 1, IPAC_PROTO_IPACCESS, IPAC_MSGT_PONG
54};
55
56static const uint8_t ipa_id_ack_msg[] = {
57 0, 1, IPAC_PROTO_IPACCESS, IPAC_MSGT_ID_ACK
58};
59
60static const uint8_t ipa_id_req_msg[] = {
61 0, 17, IPAC_PROTO_IPACCESS, IPAC_MSGT_ID_GET,
62 0x01, IPAC_IDTAG_UNIT,
63 0x01, IPAC_IDTAG_MACADDR,
64 0x01, IPAC_IDTAG_LOCATION1,
65 0x01, IPAC_IDTAG_LOCATION2,
66 0x01, IPAC_IDTAG_EQUIPVERS,
67 0x01, IPAC_IDTAG_SWVERSION,
68 0x01, IPAC_IDTAG_UNITNAME,
69 0x01, IPAC_IDTAG_SERNR,
70};
71
72
73static const char *idtag_names[] = {
74 [IPAC_IDTAG_SERNR] = "Serial_Number",
75 [IPAC_IDTAG_UNITNAME] = "Unit_Name",
76 [IPAC_IDTAG_LOCATION1] = "Location_1",
77 [IPAC_IDTAG_LOCATION2] = "Location_2",
78 [IPAC_IDTAG_EQUIPVERS] = "Equipment_Version",
79 [IPAC_IDTAG_SWVERSION] = "Software_Version",
80 [IPAC_IDTAG_IPADDR] = "IP_Address",
81 [IPAC_IDTAG_MACADDR] = "MAC_Address",
82 [IPAC_IDTAG_UNIT] = "Unit_ID",
83};
84
Harald Weltee3919962014-08-20 22:28:23 +020085const char *ipa_ccm_idtag_name(uint8_t tag)
Harald Welte28aa9912014-08-20 22:06:04 +020086{
87 if (tag >= ARRAY_SIZE(idtag_names))
88 return "unknown";
89
90 return idtag_names[tag];
91}
92
Harald Weltee3919962014-08-20 22:28:23 +020093int ipa_ccm_idtag_parse(struct tlv_parsed *dec, unsigned char *buf, int len)
Harald Welte28aa9912014-08-20 22:06:04 +020094{
Holger Hans Peter Freytherf558ed42015-06-02 15:52:06 +020095 return ipa_ccm_idtag_parse_off(dec, buf, len, 0);
96}
97
98int ipa_ccm_idtag_parse_off(struct tlv_parsed *dec, unsigned char *buf, int len, const int len_offset)
99{
Harald Welte28aa9912014-08-20 22:06:04 +0200100 uint8_t t_len;
101 uint8_t t_tag;
102 uint8_t *cur = buf;
103
104 memset(dec, 0, sizeof(*dec));
105
106 while (len >= 2) {
107 len -= 2;
108 t_len = *cur++;
109 t_tag = *cur++;
110
Holger Hans Peter Freytherf558ed42015-06-02 15:52:06 +0200111 if (t_len < len_offset) {
Max9b4d0652016-11-15 19:21:23 +0100112 LOGP(DLMI, LOGL_ERROR, "minimal offset not included: %d < %d\n", t_len, len_offset);
Holger Hans Peter Freytherf558ed42015-06-02 15:52:06 +0200113 return -EINVAL;
114 }
115
Harald Welte28aa9912014-08-20 22:06:04 +0200116 if (t_len > len + 1) {
Max9b4d0652016-11-15 19:21:23 +0100117 LOGP(DLMI, LOGL_ERROR, "The tag does not fit: %d > %d\n", t_len, len + 1);
Harald Welte28aa9912014-08-20 22:06:04 +0200118 return -EINVAL;
119 }
120
Harald Weltee3919962014-08-20 22:28:23 +0200121 DEBUGPC(DLMI, "%s='%s' ", ipa_ccm_idtag_name(t_tag), cur);
Harald Welte28aa9912014-08-20 22:06:04 +0200122
Holger Hans Peter Freytherf558ed42015-06-02 15:52:06 +0200123 dec->lv[t_tag].len = t_len - len_offset;
Harald Welte28aa9912014-08-20 22:06:04 +0200124 dec->lv[t_tag].val = cur;
125
Holger Hans Peter Freytherf558ed42015-06-02 15:52:06 +0200126 cur += t_len - len_offset;
127 len -= t_len - len_offset;
Harald Welte28aa9912014-08-20 22:06:04 +0200128 }
129 return 0;
130}
131
Harald Weltee3919962014-08-20 22:28:23 +0200132int ipa_parse_unitid(const char *str, struct ipaccess_unit *unit_data)
Harald Welte28aa9912014-08-20 22:06:04 +0200133{
134 unsigned long ul;
135 char *endptr;
136 const char *nptr;
137
138 nptr = str;
139 ul = strtoul(nptr, &endptr, 10);
140 if (endptr <= nptr)
141 return -EINVAL;
142 unit_data->site_id = ul & 0xffff;
143
144 if (*endptr++ != '/')
145 return -EINVAL;
146
147 nptr = endptr;
148 ul = strtoul(nptr, &endptr, 10);
149 if (endptr <= nptr)
150 return -EINVAL;
151 unit_data->bts_id = ul & 0xffff;
152
153 if (*endptr++ != '/')
154 return -EINVAL;
155
156 nptr = endptr;
157 ul = strtoul(nptr, &endptr, 10);
158 if (endptr <= nptr)
159 return -EINVAL;
160 unit_data->trx_id = ul & 0xffff;
161
162 return 0;
163}
164
Harald Weltee3919962014-08-20 22:28:23 +0200165int ipa_ccm_tlv_to_unitdata(struct ipaccess_unit *ud,
Harald Welte28aa9912014-08-20 22:06:04 +0200166 const struct tlv_parsed *tp)
167{
168 int rc = 0;
169
170 if (TLVP_PRES_LEN(tp, IPAC_IDTAG_SERNR, 1))
171 ud->serno = talloc_strdup(ud, (char *)
172 TLVP_VAL(tp, IPAC_IDTAG_SERNR));
173
174 if (TLVP_PRES_LEN(tp, IPAC_IDTAG_UNITNAME, 1))
175 ud->unit_name = talloc_strdup(ud, (char *)
176 TLVP_VAL(tp, IPAC_IDTAG_UNITNAME));
177
178 if (TLVP_PRES_LEN(tp, IPAC_IDTAG_LOCATION1, 1))
179 ud->location1 = talloc_strdup(ud, (char *)
180 TLVP_VAL(tp, IPAC_IDTAG_LOCATION1));
181
182 if (TLVP_PRES_LEN(tp, IPAC_IDTAG_LOCATION2, 1))
183 ud->location2 = talloc_strdup(ud, (char *)
184 TLVP_VAL(tp, IPAC_IDTAG_LOCATION2));
185
186 if (TLVP_PRES_LEN(tp, IPAC_IDTAG_EQUIPVERS, 1))
187 ud->equipvers = talloc_strdup(ud, (char *)
188 TLVP_VAL(tp, IPAC_IDTAG_EQUIPVERS));
189
190 if (TLVP_PRES_LEN(tp, IPAC_IDTAG_SWVERSION, 1))
191 ud->swversion = talloc_strdup(ud, (char *)
192 TLVP_VAL(tp, IPAC_IDTAG_SWVERSION));
193
194 if (TLVP_PRES_LEN(tp, IPAC_IDTAG_MACADDR, 17)) {
195 rc = osmo_macaddr_parse(ud->mac_addr, (char *)
196 TLVP_VAL(tp, IPAC_IDTAG_MACADDR));
197 if (rc < 0)
198 goto out;
199 }
200
201 if (TLVP_PRES_LEN(tp, IPAC_IDTAG_UNIT, 1))
Harald Weltee3919962014-08-20 22:28:23 +0200202 rc = ipa_parse_unitid((char *)
Harald Welte28aa9912014-08-20 22:06:04 +0200203 TLVP_VAL(tp, IPAC_IDTAG_UNIT), ud);
204
205out:
206 return rc;
207}
208
Harald Welte7bc88bb2017-04-15 19:05:33 +0200209#define IPA_STRING_MAX 64
210
211/*! \brief Generate IPA CCM ID RESP based on list of IEs
212 * \param[in] dev Descriptor describing identity data for response
213 * \param[in] ies_req List of IEIs to include in response
214 * \param[in] num_ies_req Number of IEIs in \a ies_req
215 * \returns Message buffer with IPA CCM ID RESP */
216struct msgb *ipa_ccm_make_id_resp(const struct ipaccess_unit *dev,
217 const uint8_t *ies_req, unsigned int num_ies_req)
218{
219 struct msgb *msg = ipa_msg_alloc(16);
220 char str[IPA_STRING_MAX];
221 unsigned int i;
222
223 if (!msg)
224 return NULL;
225
226 *msgb_put(msg, 1) = IPAC_MSGT_ID_RESP;
227
228 for (i = 0; i < num_ies_req; i++) {
229 uint8_t *tag;
230
231 str[0] = '\0';
232 switch (ies_req[i]) {
233 case IPAC_IDTAG_UNIT:
234 snprintf(str, sizeof(str), "%u/%u/%u",
235 dev->site_id, dev->bts_id, dev->trx_id);
236 break;
237 case IPAC_IDTAG_MACADDR:
238 snprintf(str, sizeof(str),
239 "%02x:%02x:%02x:%02x:%02x:%02x",
240 dev->mac_addr[0], dev->mac_addr[1],
241 dev->mac_addr[2], dev->mac_addr[3],
242 dev->mac_addr[4], dev->mac_addr[5]);
243 break;
244 case IPAC_IDTAG_LOCATION1:
245 if (dev->location1)
246 strncpy(str, dev->location1, IPA_STRING_MAX);
247 break;
248 case IPAC_IDTAG_LOCATION2:
249 if (dev->location2)
250 strncpy(str, dev->location2, IPA_STRING_MAX);
251 break;
252 case IPAC_IDTAG_EQUIPVERS:
253 if (dev->equipvers)
254 strncpy(str, dev->equipvers, IPA_STRING_MAX);
255 break;
256 case IPAC_IDTAG_SWVERSION:
257 if (dev->swversion)
258 strncpy(str, dev->swversion, IPA_STRING_MAX);
259 break;
260 case IPAC_IDTAG_UNITNAME:
261 if (dev->unit_name) {
262 snprintf(str, sizeof(str), dev->unit_name, IPA_STRING_MAX);
263 } else {
264 snprintf(str, sizeof(str),
265 "%02x-%02x-%02x-%02x-%02x-%02x",
266 dev->mac_addr[0], dev->mac_addr[1],
267 dev->mac_addr[2], dev->mac_addr[3],
268 dev->mac_addr[4], dev->mac_addr[5]);
269 }
270 break;
271 case IPAC_IDTAG_SERNR:
272 if (dev->serno)
273 strncpy(str, dev->serno, IPA_STRING_MAX);
274 break;
275 default:
276 LOGP(DLINP, LOGL_NOTICE,
277 "Unknown ipaccess tag 0x%02x\n", ies_req[i]);
278 msgb_free(msg);
279 return NULL;
280 }
281 str[IPA_STRING_MAX-1] = '\0';
282
283 LOGP(DLINP, LOGL_INFO, " tag %d: %s\n", ies_req[i], str);
284 tag = msgb_put(msg, 3 + strlen(str) + 1);
285 tag[0] = 0x00;
286 tag[1] = 1 + strlen(str) + 1;
287 tag[2] = ies_req[1];
288 memcpy(tag + 3, str, strlen(str) + 1);
289 }
290 ipa_prepend_header(msg, IPAC_PROTO_IPACCESS);
291 return msg;
292}
293
294/*! \brief Generate IPA CCM ID RESP based on requets payload
295 * \param[in] dev Descriptor describing identity data for response
296 * \param[in] data Payload of the IPA CCM ID GET request
297 * \param[in] len Length of \a data in octets
298 * \returns Message buffer with IPA CCM ID RESP */
299struct msgb *ipa_ccm_make_id_resp_from_req(const struct ipaccess_unit *dev,
300 const uint8_t *data, unsigned int len)
301{
302 uint8_t ies[len/2];
303 unsigned int num_ies = 0;
304 const uint8_t *cur = data;
305
Harald Welte8a4895c2017-04-27 10:25:10 +0200306 memset(ies, 0, sizeof(ies));
307
Harald Welte7bc88bb2017-04-15 19:05:33 +0200308 /* build a array of the IEIs */
309 while (len >= 2) {
310 uint8_t t_len, t_tag;
311 len -= 2;
312 t_len = *cur++;
313 t_tag = *cur++;
314
315 if (t_len > len + 1) {
316 LOGP(DLINP, LOGL_ERROR, "IPA CCM tage 0x%02x does not fit\n", t_tag);
317 break;
318 }
319
320 ies[num_ies++] = t_tag;
321
322 cur += t_len;
323 len -= t_len;
324 }
325 return ipa_ccm_make_id_resp(dev, ies, num_ies);
326}
327
Harald Weltee3919962014-08-20 22:28:23 +0200328int ipa_send(int fd, const void *msg, size_t msglen)
Harald Welte28aa9912014-08-20 22:06:04 +0200329{
330 int ret;
331
332 ret = write(fd, msg, msglen);
333 if (ret < 0)
Jacob Erlbecka6be2242014-12-22 10:58:46 +0100334 return -errno;
Harald Welte28aa9912014-08-20 22:06:04 +0200335 if (ret < msglen) {
Harald Weltee3919962014-08-20 22:28:23 +0200336 LOGP(DLINP, LOGL_ERROR, "ipa_send: short write\n");
Harald Welte28aa9912014-08-20 22:06:04 +0200337 return -EIO;
338 }
339 return ret;
340}
341
Harald Weltee3919962014-08-20 22:28:23 +0200342int ipa_ccm_send_pong(int fd)
Harald Welte28aa9912014-08-20 22:06:04 +0200343{
Harald Weltee3919962014-08-20 22:28:23 +0200344 return ipa_send(fd, ipa_pong_msg, sizeof(ipa_pong_msg));
Harald Welte28aa9912014-08-20 22:06:04 +0200345}
346
Harald Weltee3919962014-08-20 22:28:23 +0200347int ipa_ccm_send_id_ack(int fd)
Harald Welte28aa9912014-08-20 22:06:04 +0200348{
Harald Weltee3919962014-08-20 22:28:23 +0200349 return ipa_send(fd, ipa_id_ack_msg, sizeof(ipa_id_ack_msg));
Harald Welte28aa9912014-08-20 22:06:04 +0200350}
351
Harald Weltee3919962014-08-20 22:28:23 +0200352int ipa_ccm_send_id_req(int fd)
Harald Welte28aa9912014-08-20 22:06:04 +0200353{
Harald Weltee3919962014-08-20 22:28:23 +0200354 return ipa_send(fd, ipa_id_req_msg, sizeof(ipa_id_req_msg));
Harald Welte28aa9912014-08-20 22:06:04 +0200355}
356
357/* base handling of the ip.access protocol */
Harald Weltee3919962014-08-20 22:28:23 +0200358int ipa_ccm_rcvmsg_base(struct msgb *msg, struct osmo_fd *bfd)
Harald Welte28aa9912014-08-20 22:06:04 +0200359{
360 uint8_t msg_type = *(msg->l2h);
361 int ret;
362
363 switch (msg_type) {
364 case IPAC_MSGT_PING:
Harald Weltee3919962014-08-20 22:28:23 +0200365 ret = ipa_ccm_send_pong(bfd->fd);
Harald Welte28aa9912014-08-20 22:06:04 +0200366 if (ret < 0) {
367 LOGP(DLINP, LOGL_ERROR, "Cannot send PING "
368 "message. Reason: %s\n", strerror(errno));
369 break;
370 }
371 ret = 1;
372 break;
373 case IPAC_MSGT_PONG:
374 DEBUGP(DLMI, "PONG!\n");
375 ret = 1;
376 break;
377 case IPAC_MSGT_ID_ACK:
378 DEBUGP(DLMI, "ID_ACK? -> ACK!\n");
Harald Weltee3919962014-08-20 22:28:23 +0200379 ret = ipa_ccm_send_id_ack(bfd->fd);
Harald Welte28aa9912014-08-20 22:06:04 +0200380 if (ret < 0) {
381 LOGP(DLINP, LOGL_ERROR, "Cannot send ID_ACK "
382 "message. Reason: %s\n", strerror(errno));
383 break;
384 }
385 ret = 1;
386 break;
387 default:
388 /* This is not an IPA PING, PONG or ID_ACK message */
389 ret = 0;
390 break;
391 }
392 return ret;
393}
394
395/* base handling of the ip.access protocol */
Harald Weltee3919962014-08-20 22:28:23 +0200396int ipa_ccm_rcvmsg_bts_base(struct msgb *msg, struct osmo_fd *bfd)
Harald Welte28aa9912014-08-20 22:06:04 +0200397{
398 uint8_t msg_type = *(msg->l2h);
399 int ret = 0;
400
401 switch (msg_type) {
402 case IPAC_MSGT_PING:
Harald Weltee3919962014-08-20 22:28:23 +0200403 ret = ipa_ccm_send_pong(bfd->fd);
Harald Welte28aa9912014-08-20 22:06:04 +0200404 if (ret < 0) {
405 LOGP(DLINP, LOGL_ERROR, "Cannot send PONG "
406 "message. Reason: %s\n", strerror(errno));
407 }
408 break;
409 case IPAC_MSGT_PONG:
410 DEBUGP(DLMI, "PONG!\n");
411 break;
412 case IPAC_MSGT_ID_ACK:
413 DEBUGP(DLMI, "ID_ACK\n");
414 break;
415 }
416 return ret;
417}
418
419
Harald Weltee3919962014-08-20 22:28:23 +0200420void ipa_prepend_header_ext(struct msgb *msg, int proto)
Harald Welte28aa9912014-08-20 22:06:04 +0200421{
422 struct ipaccess_head_ext *hh_ext;
423
424 /* prepend the osmo ip.access header extension */
425 hh_ext = (struct ipaccess_head_ext *) msgb_push(msg, sizeof(*hh_ext));
426 hh_ext->proto = proto;
427}
428
Harald Weltee3919962014-08-20 22:28:23 +0200429void ipa_prepend_header(struct msgb *msg, int proto)
Harald Welte28aa9912014-08-20 22:06:04 +0200430{
431 struct ipaccess_head *hh;
432
433 /* prepend the ip.access header */
434 hh = (struct ipaccess_head *) msgb_push(msg, sizeof(*hh));
Harald Welte95871da2017-05-15 12:11:36 +0200435 hh->len = osmo_htons(msg->len - sizeof(*hh));
Harald Welte28aa9912014-08-20 22:06:04 +0200436 hh->proto = proto;
437}
438
Harald Welte20725b92017-05-15 12:50:04 +0200439#ifdef HAVE_SYS_SOCKET_H
440#include <sys/socket.h>
441
Harald Welte28aa9912014-08-20 22:06:04 +0200442int ipa_msg_recv(int fd, struct msgb **rmsg)
443{
444 int rc = ipa_msg_recv_buffered(fd, rmsg, NULL);
445 if (rc < 0) {
446 errno = -rc;
447 rc = -1;
448 }
449 return rc;
450}
451
452int ipa_msg_recv_buffered(int fd, struct msgb **rmsg, struct msgb **tmp_msg)
453{
454 struct msgb *msg = tmp_msg ? *tmp_msg : NULL;
455 struct ipaccess_head *hh;
456 int len, ret;
457 int needed;
458
459 if (msg == NULL) {
460 msg = ipa_msg_alloc(0);
461 if (msg == NULL) {
462 ret = -ENOMEM;
463 goto discard_msg;
464 }
465 msg->l1h = msg->tail;
466 }
467
468 if (msg->l2h == NULL) {
469 /* first read our 3-byte header */
470 needed = sizeof(*hh) - msg->len;
471 ret = recv(fd, msg->tail, needed, 0);
472 if (ret == 0)
473 goto discard_msg;
474
475 if (ret < 0) {
476 if (errno == EAGAIN || errno == EINTR)
477 ret = 0;
478 else {
479 ret = -errno;
480 goto discard_msg;
481 }
482 }
483
484 msgb_put(msg, ret);
485
486 if (ret < needed) {
487 if (msg->len == 0) {
488 ret = -EAGAIN;
489 goto discard_msg;
490 }
491
492 LOGP(DLINP, LOGL_INFO,
Harald Weltef196a022014-08-21 09:42:03 +0200493 "Received part of IPA message header (%d/%zu)\n",
Harald Welte28aa9912014-08-20 22:06:04 +0200494 msg->len, sizeof(*hh));
495 if (!tmp_msg) {
496 ret = -EIO;
497 goto discard_msg;
498 }
499 *tmp_msg = msg;
500 return -EAGAIN;
501 }
502
503 msg->l2h = msg->tail;
504 }
505
506 hh = (struct ipaccess_head *) msg->data;
507
508 /* then read the length as specified in header */
Harald Welte95871da2017-05-15 12:11:36 +0200509 len = osmo_ntohs(hh->len);
Harald Welte28aa9912014-08-20 22:06:04 +0200510
511 if (len < 0 || IPA_ALLOC_SIZE < len + sizeof(*hh)) {
512 LOGP(DLINP, LOGL_ERROR, "bad message length of %d bytes, "
513 "received %d bytes\n", len, msg->len);
514 ret = -EIO;
515 goto discard_msg;
516 }
517
518 needed = len - msgb_l2len(msg);
519
520 if (needed > 0) {
521 ret = recv(fd, msg->tail, needed, 0);
522
523 if (ret == 0)
524 goto discard_msg;
525
526 if (ret < 0) {
527 if (errno == EAGAIN || errno == EINTR)
528 ret = 0;
529 else {
530 ret = -errno;
531 goto discard_msg;
532 }
533 }
534
535 msgb_put(msg, ret);
536
537 if (ret < needed) {
538 LOGP(DLINP, LOGL_INFO,
539 "Received part of IPA message L2 data (%d/%d)\n",
540 msgb_l2len(msg), len);
541 if (!tmp_msg) {
542 ret = -EIO;
543 goto discard_msg;
544 }
545 *tmp_msg = msg;
546 return -EAGAIN;
547 }
548 }
549
550 ret = msgb_l2len(msg);
551
552 if (ret == 0) {
553 LOGP(DLINP, LOGL_INFO,
554 "Discarding IPA message without payload\n");
555 ret = -EAGAIN;
556 goto discard_msg;
557 }
558
559 if (tmp_msg)
560 *tmp_msg = NULL;
561 *rmsg = msg;
562 return ret;
563
564discard_msg:
565 if (tmp_msg)
566 *tmp_msg = NULL;
567 msgb_free(msg);
568 return ret;
569}
570
Harald Welte20725b92017-05-15 12:50:04 +0200571#endif /* SYS_SOCKET_H */
572
Harald Welte28aa9912014-08-20 22:06:04 +0200573struct msgb *ipa_msg_alloc(int headroom)
574{
575 struct msgb *nmsg;
576
577 headroom += sizeof(struct ipaccess_head);
578
579 nmsg = msgb_alloc_headroom(1200 + headroom, headroom, "Abis/IP");
580 if (!nmsg)
581 return NULL;
582 return nmsg;
583}