blob: 5c37d64305da99334df64c3662c45ab1696fe68c [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
Harald Welte96e2a002017-06-12 21:44:18 +020044/*! \addtogroup ipa
45 * @{
46 * \brief IPA Multiplex utility routines
47 */
48
Harald Welte28aa9912014-08-20 22:06:04 +020049#define IPA_ALLOC_SIZE 1200
50
51/*
52 * Common propietary IPA messages:
53 * - PONG: in reply to PING.
54 * - ID_REQUEST: first messages once OML has been established.
55 * - ID_ACK: in reply to ID_ACK.
56 */
57static const uint8_t ipa_pong_msg[] = {
58 0, 1, IPAC_PROTO_IPACCESS, IPAC_MSGT_PONG
59};
60
61static const uint8_t ipa_id_ack_msg[] = {
62 0, 1, IPAC_PROTO_IPACCESS, IPAC_MSGT_ID_ACK
63};
64
65static const uint8_t ipa_id_req_msg[] = {
66 0, 17, IPAC_PROTO_IPACCESS, IPAC_MSGT_ID_GET,
67 0x01, IPAC_IDTAG_UNIT,
68 0x01, IPAC_IDTAG_MACADDR,
69 0x01, IPAC_IDTAG_LOCATION1,
70 0x01, IPAC_IDTAG_LOCATION2,
71 0x01, IPAC_IDTAG_EQUIPVERS,
72 0x01, IPAC_IDTAG_SWVERSION,
73 0x01, IPAC_IDTAG_UNITNAME,
74 0x01, IPAC_IDTAG_SERNR,
75};
76
77
78static const char *idtag_names[] = {
79 [IPAC_IDTAG_SERNR] = "Serial_Number",
80 [IPAC_IDTAG_UNITNAME] = "Unit_Name",
81 [IPAC_IDTAG_LOCATION1] = "Location_1",
82 [IPAC_IDTAG_LOCATION2] = "Location_2",
83 [IPAC_IDTAG_EQUIPVERS] = "Equipment_Version",
84 [IPAC_IDTAG_SWVERSION] = "Software_Version",
85 [IPAC_IDTAG_IPADDR] = "IP_Address",
86 [IPAC_IDTAG_MACADDR] = "MAC_Address",
87 [IPAC_IDTAG_UNIT] = "Unit_ID",
88};
89
Harald Weltee3919962014-08-20 22:28:23 +020090const char *ipa_ccm_idtag_name(uint8_t tag)
Harald Welte28aa9912014-08-20 22:06:04 +020091{
92 if (tag >= ARRAY_SIZE(idtag_names))
93 return "unknown";
94
95 return idtag_names[tag];
96}
97
Harald Weltee3919962014-08-20 22:28:23 +020098int ipa_ccm_idtag_parse(struct tlv_parsed *dec, unsigned char *buf, int len)
Harald Welte28aa9912014-08-20 22:06:04 +020099{
Holger Hans Peter Freytherf558ed42015-06-02 15:52:06 +0200100 return ipa_ccm_idtag_parse_off(dec, buf, len, 0);
101}
102
103int ipa_ccm_idtag_parse_off(struct tlv_parsed *dec, unsigned char *buf, int len, const int len_offset)
104{
Harald Welte28aa9912014-08-20 22:06:04 +0200105 uint8_t t_len;
106 uint8_t t_tag;
107 uint8_t *cur = buf;
108
109 memset(dec, 0, sizeof(*dec));
110
111 while (len >= 2) {
112 len -= 2;
113 t_len = *cur++;
114 t_tag = *cur++;
115
Holger Hans Peter Freytherf558ed42015-06-02 15:52:06 +0200116 if (t_len < len_offset) {
Max9b4d0652016-11-15 19:21:23 +0100117 LOGP(DLMI, LOGL_ERROR, "minimal offset not included: %d < %d\n", t_len, len_offset);
Holger Hans Peter Freytherf558ed42015-06-02 15:52:06 +0200118 return -EINVAL;
119 }
120
Harald Welte28aa9912014-08-20 22:06:04 +0200121 if (t_len > len + 1) {
Max9b4d0652016-11-15 19:21:23 +0100122 LOGP(DLMI, LOGL_ERROR, "The tag does not fit: %d > %d\n", t_len, len + 1);
Harald Welte28aa9912014-08-20 22:06:04 +0200123 return -EINVAL;
124 }
125
Harald Weltee3919962014-08-20 22:28:23 +0200126 DEBUGPC(DLMI, "%s='%s' ", ipa_ccm_idtag_name(t_tag), cur);
Harald Welte28aa9912014-08-20 22:06:04 +0200127
Holger Hans Peter Freytherf558ed42015-06-02 15:52:06 +0200128 dec->lv[t_tag].len = t_len - len_offset;
Harald Welte28aa9912014-08-20 22:06:04 +0200129 dec->lv[t_tag].val = cur;
130
Holger Hans Peter Freytherf558ed42015-06-02 15:52:06 +0200131 cur += t_len - len_offset;
132 len -= t_len - len_offset;
Harald Welte28aa9912014-08-20 22:06:04 +0200133 }
134 return 0;
135}
136
Harald Weltee3919962014-08-20 22:28:23 +0200137int ipa_parse_unitid(const char *str, struct ipaccess_unit *unit_data)
Harald Welte28aa9912014-08-20 22:06:04 +0200138{
139 unsigned long ul;
140 char *endptr;
141 const char *nptr;
142
143 nptr = str;
144 ul = strtoul(nptr, &endptr, 10);
145 if (endptr <= nptr)
146 return -EINVAL;
147 unit_data->site_id = ul & 0xffff;
148
149 if (*endptr++ != '/')
150 return -EINVAL;
151
152 nptr = endptr;
153 ul = strtoul(nptr, &endptr, 10);
154 if (endptr <= nptr)
155 return -EINVAL;
156 unit_data->bts_id = ul & 0xffff;
157
158 if (*endptr++ != '/')
159 return -EINVAL;
160
161 nptr = endptr;
162 ul = strtoul(nptr, &endptr, 10);
163 if (endptr <= nptr)
164 return -EINVAL;
165 unit_data->trx_id = ul & 0xffff;
166
167 return 0;
168}
169
Harald Weltee3919962014-08-20 22:28:23 +0200170int ipa_ccm_tlv_to_unitdata(struct ipaccess_unit *ud,
Harald Welte28aa9912014-08-20 22:06:04 +0200171 const struct tlv_parsed *tp)
172{
173 int rc = 0;
174
175 if (TLVP_PRES_LEN(tp, IPAC_IDTAG_SERNR, 1))
176 ud->serno = talloc_strdup(ud, (char *)
177 TLVP_VAL(tp, IPAC_IDTAG_SERNR));
178
179 if (TLVP_PRES_LEN(tp, IPAC_IDTAG_UNITNAME, 1))
180 ud->unit_name = talloc_strdup(ud, (char *)
181 TLVP_VAL(tp, IPAC_IDTAG_UNITNAME));
182
183 if (TLVP_PRES_LEN(tp, IPAC_IDTAG_LOCATION1, 1))
184 ud->location1 = talloc_strdup(ud, (char *)
185 TLVP_VAL(tp, IPAC_IDTAG_LOCATION1));
186
187 if (TLVP_PRES_LEN(tp, IPAC_IDTAG_LOCATION2, 1))
188 ud->location2 = talloc_strdup(ud, (char *)
189 TLVP_VAL(tp, IPAC_IDTAG_LOCATION2));
190
191 if (TLVP_PRES_LEN(tp, IPAC_IDTAG_EQUIPVERS, 1))
192 ud->equipvers = talloc_strdup(ud, (char *)
193 TLVP_VAL(tp, IPAC_IDTAG_EQUIPVERS));
194
195 if (TLVP_PRES_LEN(tp, IPAC_IDTAG_SWVERSION, 1))
196 ud->swversion = talloc_strdup(ud, (char *)
197 TLVP_VAL(tp, IPAC_IDTAG_SWVERSION));
198
199 if (TLVP_PRES_LEN(tp, IPAC_IDTAG_MACADDR, 17)) {
200 rc = osmo_macaddr_parse(ud->mac_addr, (char *)
201 TLVP_VAL(tp, IPAC_IDTAG_MACADDR));
202 if (rc < 0)
203 goto out;
204 }
205
206 if (TLVP_PRES_LEN(tp, IPAC_IDTAG_UNIT, 1))
Harald Weltee3919962014-08-20 22:28:23 +0200207 rc = ipa_parse_unitid((char *)
Harald Welte28aa9912014-08-20 22:06:04 +0200208 TLVP_VAL(tp, IPAC_IDTAG_UNIT), ud);
209
210out:
211 return rc;
212}
213
Harald Welte7bc88bb2017-04-15 19:05:33 +0200214#define IPA_STRING_MAX 64
215
216/*! \brief Generate IPA CCM ID RESP based on list of IEs
217 * \param[in] dev Descriptor describing identity data for response
218 * \param[in] ies_req List of IEIs to include in response
219 * \param[in] num_ies_req Number of IEIs in \a ies_req
220 * \returns Message buffer with IPA CCM ID RESP */
221struct msgb *ipa_ccm_make_id_resp(const struct ipaccess_unit *dev,
222 const uint8_t *ies_req, unsigned int num_ies_req)
223{
224 struct msgb *msg = ipa_msg_alloc(16);
225 char str[IPA_STRING_MAX];
226 unsigned int i;
227
228 if (!msg)
229 return NULL;
230
231 *msgb_put(msg, 1) = IPAC_MSGT_ID_RESP;
232
233 for (i = 0; i < num_ies_req; i++) {
234 uint8_t *tag;
235
236 str[0] = '\0';
237 switch (ies_req[i]) {
238 case IPAC_IDTAG_UNIT:
239 snprintf(str, sizeof(str), "%u/%u/%u",
240 dev->site_id, dev->bts_id, dev->trx_id);
241 break;
242 case IPAC_IDTAG_MACADDR:
243 snprintf(str, sizeof(str),
244 "%02x:%02x:%02x:%02x:%02x:%02x",
245 dev->mac_addr[0], dev->mac_addr[1],
246 dev->mac_addr[2], dev->mac_addr[3],
247 dev->mac_addr[4], dev->mac_addr[5]);
248 break;
249 case IPAC_IDTAG_LOCATION1:
250 if (dev->location1)
251 strncpy(str, dev->location1, IPA_STRING_MAX);
252 break;
253 case IPAC_IDTAG_LOCATION2:
254 if (dev->location2)
255 strncpy(str, dev->location2, IPA_STRING_MAX);
256 break;
257 case IPAC_IDTAG_EQUIPVERS:
258 if (dev->equipvers)
259 strncpy(str, dev->equipvers, IPA_STRING_MAX);
260 break;
261 case IPAC_IDTAG_SWVERSION:
262 if (dev->swversion)
263 strncpy(str, dev->swversion, IPA_STRING_MAX);
264 break;
265 case IPAC_IDTAG_UNITNAME:
266 if (dev->unit_name) {
267 snprintf(str, sizeof(str), dev->unit_name, IPA_STRING_MAX);
268 } else {
269 snprintf(str, sizeof(str),
270 "%02x-%02x-%02x-%02x-%02x-%02x",
271 dev->mac_addr[0], dev->mac_addr[1],
272 dev->mac_addr[2], dev->mac_addr[3],
273 dev->mac_addr[4], dev->mac_addr[5]);
274 }
275 break;
276 case IPAC_IDTAG_SERNR:
277 if (dev->serno)
278 strncpy(str, dev->serno, IPA_STRING_MAX);
279 break;
280 default:
281 LOGP(DLINP, LOGL_NOTICE,
282 "Unknown ipaccess tag 0x%02x\n", ies_req[i]);
283 msgb_free(msg);
284 return NULL;
285 }
286 str[IPA_STRING_MAX-1] = '\0';
287
288 LOGP(DLINP, LOGL_INFO, " tag %d: %s\n", ies_req[i], str);
289 tag = msgb_put(msg, 3 + strlen(str) + 1);
290 tag[0] = 0x00;
291 tag[1] = 1 + strlen(str) + 1;
292 tag[2] = ies_req[1];
293 memcpy(tag + 3, str, strlen(str) + 1);
294 }
295 ipa_prepend_header(msg, IPAC_PROTO_IPACCESS);
296 return msg;
297}
298
299/*! \brief Generate IPA CCM ID RESP based on requets payload
300 * \param[in] dev Descriptor describing identity data for response
301 * \param[in] data Payload of the IPA CCM ID GET request
302 * \param[in] len Length of \a data in octets
303 * \returns Message buffer with IPA CCM ID RESP */
304struct msgb *ipa_ccm_make_id_resp_from_req(const struct ipaccess_unit *dev,
305 const uint8_t *data, unsigned int len)
306{
307 uint8_t ies[len/2];
308 unsigned int num_ies = 0;
309 const uint8_t *cur = data;
310
Harald Welte8a4895c2017-04-27 10:25:10 +0200311 memset(ies, 0, sizeof(ies));
312
Harald Welte7bc88bb2017-04-15 19:05:33 +0200313 /* build a array of the IEIs */
314 while (len >= 2) {
315 uint8_t t_len, t_tag;
316 len -= 2;
317 t_len = *cur++;
318 t_tag = *cur++;
319
320 if (t_len > len + 1) {
321 LOGP(DLINP, LOGL_ERROR, "IPA CCM tage 0x%02x does not fit\n", t_tag);
322 break;
323 }
324
325 ies[num_ies++] = t_tag;
326
327 cur += t_len;
328 len -= t_len;
329 }
330 return ipa_ccm_make_id_resp(dev, ies, num_ies);
331}
332
Harald Weltee3919962014-08-20 22:28:23 +0200333int ipa_send(int fd, const void *msg, size_t msglen)
Harald Welte28aa9912014-08-20 22:06:04 +0200334{
335 int ret;
336
337 ret = write(fd, msg, msglen);
338 if (ret < 0)
Jacob Erlbecka6be2242014-12-22 10:58:46 +0100339 return -errno;
Harald Welte28aa9912014-08-20 22:06:04 +0200340 if (ret < msglen) {
Harald Weltee3919962014-08-20 22:28:23 +0200341 LOGP(DLINP, LOGL_ERROR, "ipa_send: short write\n");
Harald Welte28aa9912014-08-20 22:06:04 +0200342 return -EIO;
343 }
344 return ret;
345}
346
Harald Weltee3919962014-08-20 22:28:23 +0200347int ipa_ccm_send_pong(int fd)
Harald Welte28aa9912014-08-20 22:06:04 +0200348{
Harald Weltee3919962014-08-20 22:28:23 +0200349 return ipa_send(fd, ipa_pong_msg, sizeof(ipa_pong_msg));
Harald Welte28aa9912014-08-20 22:06:04 +0200350}
351
Harald Weltee3919962014-08-20 22:28:23 +0200352int ipa_ccm_send_id_ack(int fd)
Harald Welte28aa9912014-08-20 22:06:04 +0200353{
Harald Weltee3919962014-08-20 22:28:23 +0200354 return ipa_send(fd, ipa_id_ack_msg, sizeof(ipa_id_ack_msg));
Harald Welte28aa9912014-08-20 22:06:04 +0200355}
356
Harald Weltee3919962014-08-20 22:28:23 +0200357int ipa_ccm_send_id_req(int fd)
Harald Welte28aa9912014-08-20 22:06:04 +0200358{
Harald Weltee3919962014-08-20 22:28:23 +0200359 return ipa_send(fd, ipa_id_req_msg, sizeof(ipa_id_req_msg));
Harald Welte28aa9912014-08-20 22:06:04 +0200360}
361
362/* base handling of the ip.access protocol */
Harald Weltee3919962014-08-20 22:28:23 +0200363int ipa_ccm_rcvmsg_base(struct msgb *msg, struct osmo_fd *bfd)
Harald Welte28aa9912014-08-20 22:06:04 +0200364{
365 uint8_t msg_type = *(msg->l2h);
366 int ret;
367
368 switch (msg_type) {
369 case IPAC_MSGT_PING:
Harald Weltee3919962014-08-20 22:28:23 +0200370 ret = ipa_ccm_send_pong(bfd->fd);
Harald Welte28aa9912014-08-20 22:06:04 +0200371 if (ret < 0) {
372 LOGP(DLINP, LOGL_ERROR, "Cannot send PING "
373 "message. Reason: %s\n", strerror(errno));
374 break;
375 }
376 ret = 1;
377 break;
378 case IPAC_MSGT_PONG:
379 DEBUGP(DLMI, "PONG!\n");
380 ret = 1;
381 break;
382 case IPAC_MSGT_ID_ACK:
383 DEBUGP(DLMI, "ID_ACK? -> ACK!\n");
Harald Weltee3919962014-08-20 22:28:23 +0200384 ret = ipa_ccm_send_id_ack(bfd->fd);
Harald Welte28aa9912014-08-20 22:06:04 +0200385 if (ret < 0) {
386 LOGP(DLINP, LOGL_ERROR, "Cannot send ID_ACK "
387 "message. Reason: %s\n", strerror(errno));
388 break;
389 }
390 ret = 1;
391 break;
392 default:
393 /* This is not an IPA PING, PONG or ID_ACK message */
394 ret = 0;
395 break;
396 }
397 return ret;
398}
399
400/* base handling of the ip.access protocol */
Harald Weltee3919962014-08-20 22:28:23 +0200401int ipa_ccm_rcvmsg_bts_base(struct msgb *msg, struct osmo_fd *bfd)
Harald Welte28aa9912014-08-20 22:06:04 +0200402{
403 uint8_t msg_type = *(msg->l2h);
404 int ret = 0;
405
406 switch (msg_type) {
407 case IPAC_MSGT_PING:
Harald Weltee3919962014-08-20 22:28:23 +0200408 ret = ipa_ccm_send_pong(bfd->fd);
Harald Welte28aa9912014-08-20 22:06:04 +0200409 if (ret < 0) {
410 LOGP(DLINP, LOGL_ERROR, "Cannot send PONG "
411 "message. Reason: %s\n", strerror(errno));
412 }
413 break;
414 case IPAC_MSGT_PONG:
415 DEBUGP(DLMI, "PONG!\n");
416 break;
417 case IPAC_MSGT_ID_ACK:
418 DEBUGP(DLMI, "ID_ACK\n");
419 break;
420 }
421 return ret;
422}
423
424
Harald Weltee3919962014-08-20 22:28:23 +0200425void ipa_prepend_header_ext(struct msgb *msg, int proto)
Harald Welte28aa9912014-08-20 22:06:04 +0200426{
427 struct ipaccess_head_ext *hh_ext;
428
429 /* prepend the osmo ip.access header extension */
430 hh_ext = (struct ipaccess_head_ext *) msgb_push(msg, sizeof(*hh_ext));
431 hh_ext->proto = proto;
432}
433
Harald Weltee3919962014-08-20 22:28:23 +0200434void ipa_prepend_header(struct msgb *msg, int proto)
Harald Welte28aa9912014-08-20 22:06:04 +0200435{
436 struct ipaccess_head *hh;
437
438 /* prepend the ip.access header */
439 hh = (struct ipaccess_head *) msgb_push(msg, sizeof(*hh));
Harald Welte95871da2017-05-15 12:11:36 +0200440 hh->len = osmo_htons(msg->len - sizeof(*hh));
Harald Welte28aa9912014-08-20 22:06:04 +0200441 hh->proto = proto;
442}
443
Harald Welte20725b92017-05-15 12:50:04 +0200444#ifdef HAVE_SYS_SOCKET_H
445#include <sys/socket.h>
446
Harald Welte28aa9912014-08-20 22:06:04 +0200447int ipa_msg_recv(int fd, struct msgb **rmsg)
448{
449 int rc = ipa_msg_recv_buffered(fd, rmsg, NULL);
450 if (rc < 0) {
451 errno = -rc;
452 rc = -1;
453 }
454 return rc;
455}
456
457int ipa_msg_recv_buffered(int fd, struct msgb **rmsg, struct msgb **tmp_msg)
458{
459 struct msgb *msg = tmp_msg ? *tmp_msg : NULL;
460 struct ipaccess_head *hh;
461 int len, ret;
462 int needed;
463
464 if (msg == NULL) {
465 msg = ipa_msg_alloc(0);
466 if (msg == NULL) {
467 ret = -ENOMEM;
468 goto discard_msg;
469 }
470 msg->l1h = msg->tail;
471 }
472
473 if (msg->l2h == NULL) {
474 /* first read our 3-byte header */
475 needed = sizeof(*hh) - msg->len;
476 ret = recv(fd, msg->tail, needed, 0);
477 if (ret == 0)
478 goto discard_msg;
479
480 if (ret < 0) {
481 if (errno == EAGAIN || errno == EINTR)
482 ret = 0;
483 else {
484 ret = -errno;
485 goto discard_msg;
486 }
487 }
488
489 msgb_put(msg, ret);
490
491 if (ret < needed) {
492 if (msg->len == 0) {
493 ret = -EAGAIN;
494 goto discard_msg;
495 }
496
497 LOGP(DLINP, LOGL_INFO,
Harald Weltef196a022014-08-21 09:42:03 +0200498 "Received part of IPA message header (%d/%zu)\n",
Harald Welte28aa9912014-08-20 22:06:04 +0200499 msg->len, sizeof(*hh));
500 if (!tmp_msg) {
501 ret = -EIO;
502 goto discard_msg;
503 }
504 *tmp_msg = msg;
505 return -EAGAIN;
506 }
507
508 msg->l2h = msg->tail;
509 }
510
511 hh = (struct ipaccess_head *) msg->data;
512
513 /* then read the length as specified in header */
Harald Welte95871da2017-05-15 12:11:36 +0200514 len = osmo_ntohs(hh->len);
Harald Welte28aa9912014-08-20 22:06:04 +0200515
516 if (len < 0 || IPA_ALLOC_SIZE < len + sizeof(*hh)) {
517 LOGP(DLINP, LOGL_ERROR, "bad message length of %d bytes, "
518 "received %d bytes\n", len, msg->len);
519 ret = -EIO;
520 goto discard_msg;
521 }
522
523 needed = len - msgb_l2len(msg);
524
525 if (needed > 0) {
526 ret = recv(fd, msg->tail, needed, 0);
527
528 if (ret == 0)
529 goto discard_msg;
530
531 if (ret < 0) {
532 if (errno == EAGAIN || errno == EINTR)
533 ret = 0;
534 else {
535 ret = -errno;
536 goto discard_msg;
537 }
538 }
539
540 msgb_put(msg, ret);
541
542 if (ret < needed) {
543 LOGP(DLINP, LOGL_INFO,
544 "Received part of IPA message L2 data (%d/%d)\n",
545 msgb_l2len(msg), len);
546 if (!tmp_msg) {
547 ret = -EIO;
548 goto discard_msg;
549 }
550 *tmp_msg = msg;
551 return -EAGAIN;
552 }
553 }
554
555 ret = msgb_l2len(msg);
556
557 if (ret == 0) {
558 LOGP(DLINP, LOGL_INFO,
559 "Discarding IPA message without payload\n");
560 ret = -EAGAIN;
561 goto discard_msg;
562 }
563
564 if (tmp_msg)
565 *tmp_msg = NULL;
566 *rmsg = msg;
567 return ret;
568
569discard_msg:
570 if (tmp_msg)
571 *tmp_msg = NULL;
572 msgb_free(msg);
573 return ret;
574}
575
Harald Welte20725b92017-05-15 12:50:04 +0200576#endif /* SYS_SOCKET_H */
577
Harald Welte28aa9912014-08-20 22:06:04 +0200578struct msgb *ipa_msg_alloc(int headroom)
579{
580 struct msgb *nmsg;
581
582 headroom += sizeof(struct ipaccess_head);
583
584 nmsg = msgb_alloc_headroom(1200 + headroom, headroom, "Abis/IP");
585 if (!nmsg)
586 return NULL;
587 return nmsg;
588}
Harald Welte96e2a002017-06-12 21:44:18 +0200589
590/*! @} */