blob: 8f9aed8b1ddd4bd95aa5fd95babce7d0f67bbc07 [file] [log] [blame]
Harald Welte8470bf22008-12-25 23:28:35 +00001/* OpenBSC Abis interface to mISDNuser */
2
3/* (C) 2008 by Harald Welte <laforge@gnumonks.org>
Harald Welte52b1f982008-12-23 20:25:15 +00004 *
5 * All Rights Reserved
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (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
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License along
18 * with this program; if not, write to the Free Software Foundation, Inc.,
19 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 */
22
23#include <stdio.h>
24#include <unistd.h>
25#include <stdlib.h>
26#include <errno.h>
27#include <string.h>
28#include <sys/types.h>
29#include <sys/socket.h>
30#include <sys/ioctl.h>
31#include <mISDNif.h>
32
Harald Welte8470bf22008-12-25 23:28:35 +000033//#define AF_COMPATIBILITY_FUNC
34//#include <compat_af_isdn.h>
35#define AF_ISDN 34
36#define PF_ISDN AF_ISDN
37
38#include <openbsc/select.h>
39#include <openbsc/msgb.h>
40#include <openbsc/debug.h>
41#include <openbsc/gsm_data.h>
42#include <openbsc/abis_nm.h>
43#include <openbsc/abis_rsl.h>
Harald Welte52b1f982008-12-23 20:25:15 +000044
45#define NUM_E1_TS 32
46
47/* data structure for one E1 interface with A-bis */
48struct mi_e1_handle {
49 struct gsm_bts *bts;
Harald Welte52b1f982008-12-23 20:25:15 +000050 /* The mISDN card number of the card we use */
51 int cardnr;
Harald Welte52b1f982008-12-23 20:25:15 +000052 /* The RSL adress */
53 struct sockaddr_mISDN l2addr;
Harald Welte52b1f982008-12-23 20:25:15 +000054 /* The OML adress */
55 struct sockaddr_mISDN omladdr;
Harald Welte8470bf22008-12-25 23:28:35 +000056 /* list (queue) of to-be-sent msgb's */
57 struct llist_head rsl_tx_list;
58 struct llist_head oml_tx_list;
Harald Welte52b1f982008-12-23 20:25:15 +000059
Harald Welte8470bf22008-12-25 23:28:35 +000060 struct bsc_fd fd[NUM_E1_TS];
Harald Welte52b1f982008-12-23 20:25:15 +000061};
62
Harald Welte8470bf22008-12-25 23:28:35 +000063/* FIXME: this needs to go */
64static struct mi_e1_handle *global_e1h;
65
Harald Welte52b1f982008-12-23 20:25:15 +000066#define SAPI_L2ML 0
67#define SAPI_OML 62
68#define SAPI_RSL 63
69
70#define TEI_L2ML 127
71#define TEI_OML 25
72#define TEI_RSL 1
73
74static void hexdump(unsigned char *buf, int len)
75{
76 int i;
77 for (i = 0; i < len; i++) {
78 fprintf(stdout, "%02x ", buf[i]);
79 }
80 fprintf(stdout, "\n");
81}
82
83#define TS1_ALLOC_SIZE 300
84
85static int handle_ts1_read(struct bsc_fd *bfd)
86{
87 struct mi_e1_handle *e1h = bfd->data;
88 struct msgb *msg = msgb_alloc(TS1_ALLOC_SIZE);
Harald Welte8470bf22008-12-25 23:28:35 +000089 struct sockaddr_mISDN l2addr;
90 struct mISDNhead *hh;
Harald Welte52b1f982008-12-23 20:25:15 +000091 socklen_t alen;
Harald Welte8470bf22008-12-25 23:28:35 +000092 int ret;
Harald Welte52b1f982008-12-23 20:25:15 +000093
94 if (!msg)
95 return -ENOMEM;
96
Harald Welte8470bf22008-12-25 23:28:35 +000097 hh = (struct mISDNhead *) msg->data;
98
99 /* FIXME: Map TEI/SAPI to TRX */
100 msg->trx = e1h->bts->c0;
Harald Welte52b1f982008-12-23 20:25:15 +0000101
102 alen = sizeof(l2addr);
103 ret = recvfrom(bfd->fd, msg->data, 300, 0,
104 (struct sockaddr *) &l2addr, &alen);
105 if (ret < 0) {
106 fprintf(stderr, "recvfrom error %s\n", strerror(errno));
107 return ret;
108 }
109
110 if (alen != sizeof(l2addr))
111 return -EINVAL;
112
113 msgb_put(msg, ret);
114
115 DEBUGP(DMI, "alen =%d, dev(%d) channel(%d) sapi(%d) tei(%d)\n",
116 alen, l2addr.dev, l2addr.channel, l2addr.sapi, l2addr.tei);
117
118 DEBUGP(DMI, "<= len = %d, prim(0x%x) id(0x%x)\n",
119 ret, hh->prim, hh->id);
120
121 switch (hh->prim) {
122 case DL_INFORMATION_IND:
123 DEBUGP(DMI, "got DL_INFORMATION_IND\n");
Harald Welte8470bf22008-12-25 23:28:35 +0000124 struct sockaddr_mISDN *sa = NULL;
Harald Welte52b1f982008-12-23 20:25:15 +0000125 char *lstr = "UNKN";
126
127 switch (l2addr.tei) {
128 case TEI_OML:
129 sa = &e1h->omladdr;
130 lstr = "OML";
131 break;
132 case TEI_RSL:
133 sa = &e1h->l2addr;
134 lstr = "RSL";
135 break;
136 default:
Harald Welte8470bf22008-12-25 23:28:35 +0000137 break;
Harald Welte52b1f982008-12-23 20:25:15 +0000138 }
Harald Welte8470bf22008-12-25 23:28:35 +0000139 if (sa) {
140 DEBUGP(DMI, "%s use channel(%d) sapi(%d) tei(%d) for now\n",
141 lstr, l2addr.channel, l2addr.sapi, l2addr.tei);
142 memcpy(sa, &l2addr, sizeof(l2addr));
143 }
Harald Welte52b1f982008-12-23 20:25:15 +0000144 break;
145 case DL_ESTABLISH_IND:
146 DEBUGP(DMI, "got DL_ESTABLISH_IND\n");
147 break;
148 case DL_ESTABLISH_CNF:
149 DEBUGP(DMI, "got DL_ESTABLISH_CNF\n");
150 break;
151 case DL_RELEASE_IND:
152 DEBUGP(DMI, "got DL_RELEASE_IND\n");
153 break;
154 case MPH_ACTIVATE_IND:
155 DEBUGP(DMI, "got MPH_ACTIVATE_IND\n");
156 break;
157 case MPH_DEACTIVATE_IND:
158 DEBUGP(DMI, "got MPH_DEACTIVATE_IND\n");
159 break;
160 case DL_DATA_IND:
161 DEBUGP(DMI, "got DL_DATA_IND\n");
162 msg->l2_off = MISDN_HEADER_LEN;
163 hexdump(msgb_l2(msg), ret - MISDN_HEADER_LEN);
164 switch (l2addr.tei) {
165 case TEI_OML:
166 ret = abis_nm_rcvmsg(msg);
167 break;
168 case TEI_RSL:
169 ret = abis_rsl_rcvmsg(msg);
170 break;
171 default:
172 fprintf(stderr, "DATA_IND for unknown TEI\n");
173 break;
174 }
175 break;
176 default:
177 DEBUGP(DMI, "got unexpected 0x%x prim\n", hh->prim);
178 break;
179 }
180 return ret;
181}
182
183static int handle_ts1_write(struct bsc_fd *bfd)
184{
185 struct mi_e1_handle *e1h = bfd->data;
Harald Welte8470bf22008-12-25 23:28:35 +0000186 struct msgb *msg;
187 struct mISDNhead *hh;
188 int ret, no_rsl = 0;
Harald Welte52b1f982008-12-23 20:25:15 +0000189
Harald Welte8470bf22008-12-25 23:28:35 +0000190 msg = msgb_dequeue(&e1h->rsl_tx_list);
191 if (!msg)
192 no_rsl = 1;
193 else {
194 /* prepend the mISDNhead */
195 hh = (struct mISDNhead *) msgb_push(msg, sizeof(*hh));
196 hh->prim = DL_DATA_REQ;
Harald Welte52b1f982008-12-23 20:25:15 +0000197
Harald Welte8470bf22008-12-25 23:28:35 +0000198 ret = sendto(bfd->fd, msg->data, msg->len, 0,
199 (struct sockaddr *)&e1h->l2addr,
200 sizeof(e1h->l2addr));
Harald Weltee571fb82008-12-25 23:50:30 +0000201 msgb_free(msg);
Harald Welte8470bf22008-12-25 23:28:35 +0000202 usleep(100000);
203 }
204 msg = msgb_dequeue(&e1h->rsl_tx_list);
205 if (!msg) {
206 if (no_rsl)
207 bfd->when &= ~BSC_FD_WRITE;
208 } else {
209 /* prepend the mISDNhead */
210 hh = (struct mISDNhead *) msgb_push(msg, sizeof(*hh));
211 hh->prim = DL_DATA_REQ;
212
213 ret = sendto(bfd->fd, msg->data, msg->len, 0,
214 (struct sockaddr *)&e1h->omladdr,
215 sizeof(e1h->omladdr));
Harald Weltee571fb82008-12-25 23:50:30 +0000216 msgb_free(msg);
Harald Welte8470bf22008-12-25 23:28:35 +0000217 usleep(100000);
218 }
219
220 return ret;
Harald Welte52b1f982008-12-23 20:25:15 +0000221}
222
223static int handle_tsX_read(struct bsc_fd *bfd)
224{
225 /* FIXME: read from a B channel TS */
226}
227
Harald Welte8470bf22008-12-25 23:28:35 +0000228static int handle_tsX_write(struct bsc_fd *bfd)
Harald Welte52b1f982008-12-23 20:25:15 +0000229{
230 /* FIXME: write to a B channel TS */
231}
232
233/* callback from select.c in case one of the fd's can be read/written */
Harald Welte8470bf22008-12-25 23:28:35 +0000234static int misdn_fd_cb(struct bsc_fd *bfd, unsigned int what)
Harald Welte52b1f982008-12-23 20:25:15 +0000235{
236 unsigned int e1_ts = bfd->priv_nr;
237 int rc = 0;
238
239 switch (e1_ts) {
240 case 1:
241 if (what & BSC_FD_READ)
242 rc = handle_ts1_read(bfd);
243 if (what & BSC_FD_WRITE)
244 rc = handle_ts1_write(bfd);
245 break;
246 default:
247 if (what & BSC_FD_READ)
248 rc = handle_tsX_read(bfd);
249 if (what & BSC_FD_WRITE)
250 rc = handle_tsX_write(bfd);
251 break;
252 }
253
254 return rc;
255}
256
Harald Welte8470bf22008-12-25 23:28:35 +0000257int abis_rsl_sendmsg(struct msgb *msg)
Harald Welte52b1f982008-12-23 20:25:15 +0000258{
Harald Welte8470bf22008-12-25 23:28:35 +0000259 struct mi_e1_handle *e1h = global_e1h;
260
261 msgb_enqueue(&e1h->rsl_tx_list, msg);
262 e1h->fd[0].when |= BSC_FD_WRITE;
263
264 return 0;
265}
266
267int abis_nm_sendmsg(struct msgb *msg)
268{
269 struct mi_e1_handle *e1h = global_e1h;
270
271 msgb_enqueue(&e1h->oml_tx_list, msg);
272 e1h->fd[0].when |= BSC_FD_WRITE;
273
274 return 0;
275}
276
277static int mi_e1_setup(struct mi_e1_handle *e1h)
278{
279 int ts, sk, ret, cnt;
280 struct mISDN_devinfo devinfo;
Harald Welte52b1f982008-12-23 20:25:15 +0000281
282 sk = socket(PF_ISDN, SOCK_RAW, ISDN_P_BASE);
Harald Welte8470bf22008-12-25 23:28:35 +0000283 if (sk < 0) {
Harald Welte52b1f982008-12-23 20:25:15 +0000284 fprintf(stderr, "could not open socket %s\n", strerror(errno));
285 return sk;
286 }
287
288 ret = ioctl(sk, IMGETCOUNT, &cnt);
289 if (ret) {
290 fprintf(stderr, "error getting interf count: %s\n",
291 strerror(errno));
292 close(sk);
293 return -ENODEV;
294 }
295 DEBUGP(DMI,"%d device%s found\n", cnt, (cnt==1)?"":"s");
296#if 0
297 devinfo.id = di->cardnr;
298 ret = ioctl(sk, IMGETDEVINFO, &devinfo);
299 if (ret < 0) {
300 fprintf(stdout, "error getting info for device %d: %s\n",
301 di->cardnr, strerror(errno));
302 return -ENODEV;
303 }
304 fprintf(stdout, " id: %d\n", devinfo.id);
305 fprintf(stdout, " Dprotocols: %08x\n", devinfo.Dprotocols);
306 fprintf(stdout, " Bprotocols: %08x\n", devinfo.Bprotocols);
307 fprintf(stdout, " protocol: %d\n", devinfo.protocol);
308 fprintf(stdout, " nrbchan: %d\n", devinfo.nrbchan);
309 fprintf(stdout, " name: %s\n", devinfo.name);
310#endif
311
312 /* TS0 is CRC4, don't need any fd for it */
313 for (ts = 1; ts < NUM_E1_TS; ts++) {
Harald Welte8470bf22008-12-25 23:28:35 +0000314 unsigned int idx = ts-1;
Harald Welte52b1f982008-12-23 20:25:15 +0000315 struct bsc_fd *bfd = &e1h->fd[idx];
316 struct sockaddr_mISDN addr;
317
Harald Welte8470bf22008-12-25 23:28:35 +0000318 bfd->data = e1h;
319 bfd->priv_nr = ts;
320 bfd->cb = misdn_fd_cb;
321
322 if (ts == 1) {
Harald Welte52b1f982008-12-23 20:25:15 +0000323 bfd->fd = socket(PF_ISDN, SOCK_RAW, ISDN_P_LAPD_NT);
Harald Welte8470bf22008-12-25 23:28:35 +0000324 bfd->when = BSC_FD_READ;
325 } else
Harald Welte52b1f982008-12-23 20:25:15 +0000326 bfd->fd = socket(PF_ISDN, SOCK_DGRAM, ISDN_P_B_RAW);
327
Harald Welte8470bf22008-12-25 23:28:35 +0000328
329 if (bfd->fd < 0) {
Harald Welte52b1f982008-12-23 20:25:15 +0000330 fprintf(stderr, "could not open socket %s\n",
331 strerror(errno));
332 return bfd->fd;
333 }
334
335 memset(&addr, 0, sizeof(addr));
336 addr.family = AF_ISDN;
337 addr.dev = e1h->cardnr;
338 if (ts == 1) {
339 addr.channel = 0;
340 addr.sapi = 0;/* SAPI not supported yet in kernel */
341 addr.tei = TEI_L2ML;
342 } else
343 addr.channel = ts;
344
345 ret = bind(bfd->fd, (struct sockaddr *) &addr, sizeof(addr));
346 if (ret < 0) {
Harald Welte8470bf22008-12-25 23:28:35 +0000347 fprintf(stderr, "could not bind l2 socket %s\n",
Harald Welte52b1f982008-12-23 20:25:15 +0000348 strerror(errno));
349 return -EIO;
350 }
Harald Welte8470bf22008-12-25 23:28:35 +0000351
352 ret = bsc_register_fd(bfd);
353 if (ret < 0) {
354 fprintf(stderr, "could not register FD: %s\n",
355 strerror(ret));
356 return ret;
357 }
Harald Welte52b1f982008-12-23 20:25:15 +0000358 }
Harald Welte8470bf22008-12-25 23:28:35 +0000359
360 return 0;
Harald Welte52b1f982008-12-23 20:25:15 +0000361}
362
Harald Welte8470bf22008-12-25 23:28:35 +0000363int mi_setup(struct gsm_bts *bts, int cardnr)
364{
365 struct mi_e1_handle *e1h;
366
367 e1h = malloc(sizeof(*e1h));
368 memset(e1h, 0, sizeof(*e1h));
369
370 e1h->cardnr = cardnr;
371 e1h->bts = bts;
372 INIT_LLIST_HEAD(&e1h->oml_tx_list);
373 INIT_LLIST_HEAD(&e1h->rsl_tx_list);
374
375 global_e1h = e1h;
376
377 return mi_e1_setup(e1h);
378}