blob: 32c3b018bd4098bf6934e1de53cc25dc63191a51 [file] [log] [blame]
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +08001/* OpenBSC Abis input driver for ip.access */
2
3/* (C) 2009 by Harald Welte <laforge@gnumonks.org>
4 *
5 * All Rights Reserved
6 *
Holger Hans Peter Freytherde56c222011-01-16 17:45:14 +01007 * This program is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU Affero General Public License as published by
9 * the Free Software Foundation, either version 3 of the License, or
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +080010 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
Holger Hans Peter Freytherde56c222011-01-16 17:45:14 +010015 * GNU Affero General Public License for more details.
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +080016 *
Holger Hans Peter Freytherde56c222011-01-16 17:45:14 +010017 * You should have received a copy of the GNU Affero General Public License
18 * along with this program. If not, see <http://www.gnu.org/licenses/>.
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +080019 *
20 */
21
22#include <stdio.h>
23#include <unistd.h>
24#include <stdlib.h>
25#include <errno.h>
26#include <string.h>
27#include <time.h>
28#include <sys/fcntl.h>
29#include <sys/types.h>
30#include <sys/socket.h>
31#include <sys/ioctl.h>
32#include <arpa/inet.h>
33
Holger Hans Peter Freythercbf7d182010-07-31 05:25:35 +080034#include <osmocore/select.h>
35#include <osmocore/msgb.h>
36#include <osmocore/talloc.h>
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +080037#include <ipaccess.h>
38
39
40#ifndef ARRAY_SIZE
41#define ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0]))
42#endif
43
44#define TS1_ALLOC_SIZE 4096
45
Holger Hans Peter Freyther5aa17012010-07-31 04:37:26 +080046static const uint8_t pong[] = { 0, 1, IPAC_PROTO_IPACCESS, IPAC_MSGT_PONG };
47static const uint8_t id_ack[] = { 0, 1, IPAC_PROTO_IPACCESS, IPAC_MSGT_ID_ACK };
48static const uint8_t id_req[] = { 0, 17, IPAC_PROTO_IPACCESS, IPAC_MSGT_ID_GET,
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +080049 0x01, IPAC_IDTAG_UNIT,
50 0x01, IPAC_IDTAG_MACADDR,
51 0x01, IPAC_IDTAG_LOCATION1,
52 0x01, IPAC_IDTAG_LOCATION2,
53 0x01, IPAC_IDTAG_EQUIPVERS,
54 0x01, IPAC_IDTAG_SWVERSION,
55 0x01, IPAC_IDTAG_UNITNAME,
56 0x01, IPAC_IDTAG_SERNR,
57 };
58
59static const char *idtag_names[] = {
60 [IPAC_IDTAG_SERNR] = "Serial_Number",
61 [IPAC_IDTAG_UNITNAME] = "Unit_Name",
62 [IPAC_IDTAG_LOCATION1] = "Location_1",
63 [IPAC_IDTAG_LOCATION2] = "Location_2",
64 [IPAC_IDTAG_EQUIPVERS] = "Equipment_Version",
65 [IPAC_IDTAG_SWVERSION] = "Software_Version",
66 [IPAC_IDTAG_IPADDR] = "IP_Address",
67 [IPAC_IDTAG_MACADDR] = "MAC_Address",
68 [IPAC_IDTAG_UNIT] = "Unit_ID",
69};
70
71static const char *ipac_idtag_name(int tag)
72{
73 if (tag >= ARRAY_SIZE(idtag_names))
74 return "unknown";
75
76 return idtag_names[tag];
77}
78
79/* send the id ack */
80int ipaccess_send_id_ack(int fd)
81{
82 return write(fd, id_ack, sizeof(id_ack));
83}
84
85int ipaccess_send_id_req(int fd)
86{
87 return write(fd, id_req, sizeof(id_req));
88}
89
90/* base handling of the ip.access protocol */
91int ipaccess_rcvmsg_base(struct msgb *msg,
92 struct bsc_fd *bfd)
93{
Holger Hans Peter Freyther5aa17012010-07-31 04:37:26 +080094 uint8_t msg_type = *(msg->l2h);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +080095 int ret = 0;
96
97 switch (msg_type) {
98 case IPAC_MSGT_PING:
99 ret = write(bfd->fd, pong, sizeof(pong));
100 break;
101 case IPAC_MSGT_PONG:
102 break;
103 case IPAC_MSGT_ID_ACK:
104 ret = ipaccess_send_id_ack(bfd->fd);
105 break;
106 }
107 return 0;
108}
109
110/*
111 * read one ipa message from the socket
112 * return NULL in case of error
113 */
114struct msgb *ipaccess_read_msg(struct bsc_fd *bfd, int *error)
115{
116 struct msgb *msg = msgb_alloc(TS1_ALLOC_SIZE, "Abis/IP");
117 struct ipaccess_head *hh;
118 int len, ret = 0;
119
120 if (!msg) {
121 *error = -ENOMEM;
122 return NULL;
123 }
124
125 /* first read our 3-byte header */
126 hh = (struct ipaccess_head *) msg->data;
127 ret = recv(bfd->fd, msg->data, 3, 0);
128 if (ret < 0) {
129 msgb_free(msg);
130 *error = ret;
131 return NULL;
132 } else if (ret == 0) {
133 msgb_free(msg);
134 *error = ret;
135 return NULL;
136 }
137
138 msgb_put(msg, ret);
139
140 /* then read te length as specified in header */
141 msg->l2h = msg->data + sizeof(*hh);
142 len = ntohs(hh->len);
143 ret = recv(bfd->fd, msg->l2h, len, 0);
144 if (ret < len) {
145 msgb_free(msg);
146 *error = -EIO;
147 return NULL;
148 }
149 msgb_put(msg, ret);
150
151 return msg;
152}
153
154void ipaccess_prepend_header(struct msgb *msg, int proto)
155{
156 struct ipaccess_head *hh;
157
158 /* prepend the ip.access header */
159 hh = (struct ipaccess_head *) msgb_push(msg, sizeof(*hh));
160 hh->len = htons(msg->len - sizeof(*hh));
161 hh->proto = proto;
162}
163