blob: 10a92d1370cffbe9b37e8bf9ab65654fff37de59 [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 Weltead384642008-12-26 10:20:07 +000060 void (*cb)(int event, struct gsm_bts *bts);
Harald Welte8470bf22008-12-25 23:28:35 +000061 struct bsc_fd fd[NUM_E1_TS];
Harald Welte52b1f982008-12-23 20:25:15 +000062};
63
Harald Welte8470bf22008-12-25 23:28:35 +000064/* FIXME: this needs to go */
65static struct mi_e1_handle *global_e1h;
66
Harald Welte52b1f982008-12-23 20:25:15 +000067#define SAPI_L2ML 0
68#define SAPI_OML 62
Harald Weltead384642008-12-26 10:20:07 +000069#define SAPI_RSL 0 /* 63 ? */
Harald Welte52b1f982008-12-23 20:25:15 +000070
71#define TEI_L2ML 127
72#define TEI_OML 25
73#define TEI_RSL 1
74
75static void hexdump(unsigned char *buf, int len)
76{
77 int i;
78 for (i = 0; i < len; i++) {
79 fprintf(stdout, "%02x ", buf[i]);
80 }
81 fprintf(stdout, "\n");
82}
83
84#define TS1_ALLOC_SIZE 300
85
86static int handle_ts1_read(struct bsc_fd *bfd)
87{
88 struct mi_e1_handle *e1h = bfd->data;
89 struct msgb *msg = msgb_alloc(TS1_ALLOC_SIZE);
Harald Welte8470bf22008-12-25 23:28:35 +000090 struct sockaddr_mISDN l2addr;
91 struct mISDNhead *hh;
Harald Welte52b1f982008-12-23 20:25:15 +000092 socklen_t alen;
Harald Welte8470bf22008-12-25 23:28:35 +000093 int ret;
Harald Welte52b1f982008-12-23 20:25:15 +000094
95 if (!msg)
96 return -ENOMEM;
97
Harald Welte8470bf22008-12-25 23:28:35 +000098 hh = (struct mISDNhead *) msg->data;
99
100 /* FIXME: Map TEI/SAPI to TRX */
101 msg->trx = e1h->bts->c0;
Harald Welte52b1f982008-12-23 20:25:15 +0000102
103 alen = sizeof(l2addr);
104 ret = recvfrom(bfd->fd, msg->data, 300, 0,
105 (struct sockaddr *) &l2addr, &alen);
106 if (ret < 0) {
107 fprintf(stderr, "recvfrom error %s\n", strerror(errno));
108 return ret;
109 }
110
111 if (alen != sizeof(l2addr))
112 return -EINVAL;
113
114 msgb_put(msg, ret);
115
116 DEBUGP(DMI, "alen =%d, dev(%d) channel(%d) sapi(%d) tei(%d)\n",
117 alen, l2addr.dev, l2addr.channel, l2addr.sapi, l2addr.tei);
118
119 DEBUGP(DMI, "<= len = %d, prim(0x%x) id(0x%x)\n",
120 ret, hh->prim, hh->id);
121
122 switch (hh->prim) {
123 case DL_INFORMATION_IND:
124 DEBUGP(DMI, "got DL_INFORMATION_IND\n");
Harald Welte8470bf22008-12-25 23:28:35 +0000125 struct sockaddr_mISDN *sa = NULL;
Harald Welte52b1f982008-12-23 20:25:15 +0000126 char *lstr = "UNKN";
127
128 switch (l2addr.tei) {
129 case TEI_OML:
130 sa = &e1h->omladdr;
131 lstr = "OML";
132 break;
133 case TEI_RSL:
134 sa = &e1h->l2addr;
135 lstr = "RSL";
136 break;
137 default:
Harald Welte8470bf22008-12-25 23:28:35 +0000138 break;
Harald Welte52b1f982008-12-23 20:25:15 +0000139 }
Harald Welte8470bf22008-12-25 23:28:35 +0000140 if (sa) {
141 DEBUGP(DMI, "%s use channel(%d) sapi(%d) tei(%d) for now\n",
142 lstr, l2addr.channel, l2addr.sapi, l2addr.tei);
143 memcpy(sa, &l2addr, sizeof(l2addr));
144 }
Harald Welte52b1f982008-12-23 20:25:15 +0000145 break;
146 case DL_ESTABLISH_IND:
147 DEBUGP(DMI, "got DL_ESTABLISH_IND\n");
148 break;
149 case DL_ESTABLISH_CNF:
150 DEBUGP(DMI, "got DL_ESTABLISH_CNF\n");
151 break;
152 case DL_RELEASE_IND:
Harald Weltead384642008-12-26 10:20:07 +0000153 DEBUGP(DMI, "got DL_RELEASE_IND: E1 Layer 1 disappeared?\n");
Harald Welte52b1f982008-12-23 20:25:15 +0000154 break;
155 case MPH_ACTIVATE_IND:
156 DEBUGP(DMI, "got MPH_ACTIVATE_IND\n");
Harald Weltead384642008-12-26 10:20:07 +0000157 if (l2addr.tei == TEI_OML && l2addr.sapi == SAPI_OML)
158 e1h->cb(EVT_E1_OML_UP, e1h->bts);
159 else if (l2addr.tei == TEI_RSL && l2addr.sapi == SAPI_RSL)
160 e1h->cb(EVT_E1_RSL_UP, e1h->bts);
Harald Welte52b1f982008-12-23 20:25:15 +0000161 break;
162 case MPH_DEACTIVATE_IND:
Harald Weltead384642008-12-26 10:20:07 +0000163 DEBUGP(DMI, "got MPH_DEACTIVATE_IND: TEI link closed?\n");
164 if (l2addr.tei == TEI_OML && l2addr.sapi == SAPI_OML)
165 e1h->cb(EVT_E1_OML_DN, e1h->bts);
166 else if (l2addr.tei == TEI_RSL && l2addr.sapi == SAPI_RSL)
167 e1h->cb(EVT_E1_RSL_DN, e1h->bts);
168 break;
Harald Welte52b1f982008-12-23 20:25:15 +0000169 break;
170 case DL_DATA_IND:
171 DEBUGP(DMI, "got DL_DATA_IND\n");
Harald Weltead384642008-12-26 10:20:07 +0000172
173 /* FIXME: this stinks */
174 msg->trx = e1h->bts->c0;
175
176 msg->l2h = msg->data + MISDN_HEADER_LEN;
177
178 fprintf(stdout, "RX: ");
Harald Welte52b1f982008-12-23 20:25:15 +0000179 hexdump(msgb_l2(msg), ret - MISDN_HEADER_LEN);
180 switch (l2addr.tei) {
181 case TEI_OML:
182 ret = abis_nm_rcvmsg(msg);
183 break;
184 case TEI_RSL:
185 ret = abis_rsl_rcvmsg(msg);
186 break;
187 default:
188 fprintf(stderr, "DATA_IND for unknown TEI\n");
189 break;
190 }
191 break;
192 default:
193 DEBUGP(DMI, "got unexpected 0x%x prim\n", hh->prim);
194 break;
195 }
196 return ret;
197}
198
199static int handle_ts1_write(struct bsc_fd *bfd)
200{
201 struct mi_e1_handle *e1h = bfd->data;
Harald Welte8470bf22008-12-25 23:28:35 +0000202 struct msgb *msg;
203 struct mISDNhead *hh;
Harald Weltead384642008-12-26 10:20:07 +0000204 int ret, no_oml = 0;
Harald Welte52b1f982008-12-23 20:25:15 +0000205
Harald Weltead384642008-12-26 10:20:07 +0000206 msg = msgb_dequeue(&e1h->oml_tx_list);
Harald Welte8470bf22008-12-25 23:28:35 +0000207 if (!msg)
Harald Weltead384642008-12-26 10:20:07 +0000208 no_oml = 1;
Harald Welte8470bf22008-12-25 23:28:35 +0000209 else {
Harald Weltead384642008-12-26 10:20:07 +0000210 u_int8_t *l2_data = msg->data;
211
Harald Welte8470bf22008-12-25 23:28:35 +0000212 /* prepend the mISDNhead */
213 hh = (struct mISDNhead *) msgb_push(msg, sizeof(*hh));
214 hh->prim = DL_DATA_REQ;
Harald Welte52b1f982008-12-23 20:25:15 +0000215
Harald Weltead384642008-12-26 10:20:07 +0000216 fprintf(stdout, "OML TX: ");
217 hexdump(l2_data, msg->len - MISDN_HEADER_LEN);
218
Harald Welte8470bf22008-12-25 23:28:35 +0000219 ret = sendto(bfd->fd, msg->data, msg->len, 0,
220 (struct sockaddr *)&e1h->l2addr,
221 sizeof(e1h->l2addr));
Harald Weltee571fb82008-12-25 23:50:30 +0000222 msgb_free(msg);
Harald Welte8470bf22008-12-25 23:28:35 +0000223 usleep(100000);
Harald Weltead384642008-12-26 10:20:07 +0000224 /* we always dequeue all OML messages */
225 return ret;
Harald Welte8470bf22008-12-25 23:28:35 +0000226 }
Harald Weltead384642008-12-26 10:20:07 +0000227
Harald Welte8470bf22008-12-25 23:28:35 +0000228 msg = msgb_dequeue(&e1h->rsl_tx_list);
229 if (!msg) {
Harald Weltead384642008-12-26 10:20:07 +0000230 if (no_oml)
Harald Welte8470bf22008-12-25 23:28:35 +0000231 bfd->when &= ~BSC_FD_WRITE;
232 } else {
Harald Weltead384642008-12-26 10:20:07 +0000233 u_int8_t *l2_data = msg->data;
234
Harald Welte8470bf22008-12-25 23:28:35 +0000235 /* prepend the mISDNhead */
236 hh = (struct mISDNhead *) msgb_push(msg, sizeof(*hh));
237 hh->prim = DL_DATA_REQ;
238
Harald Weltead384642008-12-26 10:20:07 +0000239 fprintf(stdout, "RSL TX: ");
240 hexdump(l2_data, msg->len - MISDN_HEADER_LEN);
241
Harald Welte8470bf22008-12-25 23:28:35 +0000242 ret = sendto(bfd->fd, msg->data, msg->len, 0,
243 (struct sockaddr *)&e1h->omladdr,
244 sizeof(e1h->omladdr));
Harald Weltee571fb82008-12-25 23:50:30 +0000245 msgb_free(msg);
Harald Welte8470bf22008-12-25 23:28:35 +0000246 usleep(100000);
247 }
248
249 return ret;
Harald Welte52b1f982008-12-23 20:25:15 +0000250}
251
252static int handle_tsX_read(struct bsc_fd *bfd)
253{
254 /* FIXME: read from a B channel TS */
255}
256
Harald Welte8470bf22008-12-25 23:28:35 +0000257static int handle_tsX_write(struct bsc_fd *bfd)
Harald Welte52b1f982008-12-23 20:25:15 +0000258{
259 /* FIXME: write to a B channel TS */
260}
261
262/* callback from select.c in case one of the fd's can be read/written */
Harald Welte8470bf22008-12-25 23:28:35 +0000263static int misdn_fd_cb(struct bsc_fd *bfd, unsigned int what)
Harald Welte52b1f982008-12-23 20:25:15 +0000264{
265 unsigned int e1_ts = bfd->priv_nr;
266 int rc = 0;
267
268 switch (e1_ts) {
269 case 1:
270 if (what & BSC_FD_READ)
271 rc = handle_ts1_read(bfd);
272 if (what & BSC_FD_WRITE)
273 rc = handle_ts1_write(bfd);
274 break;
275 default:
276 if (what & BSC_FD_READ)
277 rc = handle_tsX_read(bfd);
278 if (what & BSC_FD_WRITE)
279 rc = handle_tsX_write(bfd);
280 break;
281 }
282
283 return rc;
284}
285
Harald Welte8470bf22008-12-25 23:28:35 +0000286int abis_rsl_sendmsg(struct msgb *msg)
Harald Welte52b1f982008-12-23 20:25:15 +0000287{
Harald Welte8470bf22008-12-25 23:28:35 +0000288 struct mi_e1_handle *e1h = global_e1h;
289
Harald Weltead384642008-12-26 10:20:07 +0000290 msg->l2h = msg->data;
Harald Welte8470bf22008-12-25 23:28:35 +0000291 msgb_enqueue(&e1h->rsl_tx_list, msg);
292 e1h->fd[0].when |= BSC_FD_WRITE;
293
294 return 0;
295}
296
Harald Weltead384642008-12-26 10:20:07 +0000297int _abis_nm_sendmsg(struct msgb *msg)
Harald Welte8470bf22008-12-25 23:28:35 +0000298{
299 struct mi_e1_handle *e1h = global_e1h;
300
Harald Weltead384642008-12-26 10:20:07 +0000301 msg->l2h = msg->data;
Harald Welte8470bf22008-12-25 23:28:35 +0000302 msgb_enqueue(&e1h->oml_tx_list, msg);
303 e1h->fd[0].when |= BSC_FD_WRITE;
304
305 return 0;
306}
307
308static int mi_e1_setup(struct mi_e1_handle *e1h)
309{
310 int ts, sk, ret, cnt;
311 struct mISDN_devinfo devinfo;
Harald Welte52b1f982008-12-23 20:25:15 +0000312
313 sk = socket(PF_ISDN, SOCK_RAW, ISDN_P_BASE);
Harald Welte8470bf22008-12-25 23:28:35 +0000314 if (sk < 0) {
Harald Welte52b1f982008-12-23 20:25:15 +0000315 fprintf(stderr, "could not open socket %s\n", strerror(errno));
316 return sk;
317 }
318
319 ret = ioctl(sk, IMGETCOUNT, &cnt);
320 if (ret) {
321 fprintf(stderr, "error getting interf count: %s\n",
322 strerror(errno));
323 close(sk);
324 return -ENODEV;
325 }
Harald Weltead384642008-12-26 10:20:07 +0000326 //DEBUGP(DMI,"%d device%s found\n", cnt, (cnt==1)?"":"s");
327 printf("%d device%s found\n", cnt, (cnt==1)?"":"s");
328#if 1
329 devinfo.id = e1h->cardnr;
Harald Welte52b1f982008-12-23 20:25:15 +0000330 ret = ioctl(sk, IMGETDEVINFO, &devinfo);
331 if (ret < 0) {
332 fprintf(stdout, "error getting info for device %d: %s\n",
Harald Weltead384642008-12-26 10:20:07 +0000333 e1h->cardnr, strerror(errno));
Harald Welte52b1f982008-12-23 20:25:15 +0000334 return -ENODEV;
335 }
336 fprintf(stdout, " id: %d\n", devinfo.id);
337 fprintf(stdout, " Dprotocols: %08x\n", devinfo.Dprotocols);
338 fprintf(stdout, " Bprotocols: %08x\n", devinfo.Bprotocols);
339 fprintf(stdout, " protocol: %d\n", devinfo.protocol);
340 fprintf(stdout, " nrbchan: %d\n", devinfo.nrbchan);
341 fprintf(stdout, " name: %s\n", devinfo.name);
342#endif
343
344 /* TS0 is CRC4, don't need any fd for it */
345 for (ts = 1; ts < NUM_E1_TS; ts++) {
Harald Welte8470bf22008-12-25 23:28:35 +0000346 unsigned int idx = ts-1;
Harald Welte52b1f982008-12-23 20:25:15 +0000347 struct bsc_fd *bfd = &e1h->fd[idx];
348 struct sockaddr_mISDN addr;
349
Harald Welte8470bf22008-12-25 23:28:35 +0000350 bfd->data = e1h;
351 bfd->priv_nr = ts;
352 bfd->cb = misdn_fd_cb;
353
354 if (ts == 1) {
Harald Weltead384642008-12-26 10:20:07 +0000355 bfd->fd = socket(PF_ISDN, SOCK_DGRAM, ISDN_P_LAPD_NT);
Harald Welte8470bf22008-12-25 23:28:35 +0000356 bfd->when = BSC_FD_READ;
357 } else
Harald Welte52b1f982008-12-23 20:25:15 +0000358 bfd->fd = socket(PF_ISDN, SOCK_DGRAM, ISDN_P_B_RAW);
359
Harald Welte8470bf22008-12-25 23:28:35 +0000360
361 if (bfd->fd < 0) {
Harald Welte52b1f982008-12-23 20:25:15 +0000362 fprintf(stderr, "could not open socket %s\n",
363 strerror(errno));
364 return bfd->fd;
365 }
366
367 memset(&addr, 0, sizeof(addr));
368 addr.family = AF_ISDN;
369 addr.dev = e1h->cardnr;
370 if (ts == 1) {
371 addr.channel = 0;
372 addr.sapi = 0;/* SAPI not supported yet in kernel */
373 addr.tei = TEI_L2ML;
374 } else
375 addr.channel = ts;
376
377 ret = bind(bfd->fd, (struct sockaddr *) &addr, sizeof(addr));
378 if (ret < 0) {
Harald Welte8470bf22008-12-25 23:28:35 +0000379 fprintf(stderr, "could not bind l2 socket %s\n",
Harald Welte52b1f982008-12-23 20:25:15 +0000380 strerror(errno));
381 return -EIO;
382 }
Harald Welte8470bf22008-12-25 23:28:35 +0000383
384 ret = bsc_register_fd(bfd);
385 if (ret < 0) {
386 fprintf(stderr, "could not register FD: %s\n",
387 strerror(ret));
388 return ret;
389 }
Harald Welte52b1f982008-12-23 20:25:15 +0000390 }
Harald Welte8470bf22008-12-25 23:28:35 +0000391
392 return 0;
Harald Welte52b1f982008-12-23 20:25:15 +0000393}
394
Harald Weltead384642008-12-26 10:20:07 +0000395int mi_setup(struct gsm_bts *bts, int cardnr,
396 void (cb)(int event, struct gsm_bts *bts))
Harald Welte8470bf22008-12-25 23:28:35 +0000397{
398 struct mi_e1_handle *e1h;
399
400 e1h = malloc(sizeof(*e1h));
401 memset(e1h, 0, sizeof(*e1h));
402
403 e1h->cardnr = cardnr;
404 e1h->bts = bts;
Harald Weltead384642008-12-26 10:20:07 +0000405 e1h->cb = cb;
Harald Welte8470bf22008-12-25 23:28:35 +0000406 INIT_LLIST_HEAD(&e1h->oml_tx_list);
407 INIT_LLIST_HEAD(&e1h->rsl_tx_list);
408
409 global_e1h = e1h;
410
411 return mi_e1_setup(e1h);
412}