blob: 0d54c792888f1d05ac393dfc904394d23add3084 [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>
Holger Freyther9a3ee0f2009-01-02 00:40:15 +00004 * (C) 2009 by Holger Hans Peter Freyther <zecke@selfish.org>
Harald Welte52b1f982008-12-23 20:25:15 +00005 *
6 * All Rights Reserved
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License along
19 * with this program; if not, write to the Free Software Foundation, Inc.,
20 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
21 *
22 */
23
24#include <stdio.h>
25#include <unistd.h>
26#include <stdlib.h>
27#include <errno.h>
28#include <string.h>
Harald Weltee9a82612008-12-27 16:45:29 +000029#include <sys/fcntl.h>
Harald Welte52b1f982008-12-23 20:25:15 +000030#include <sys/types.h>
31#include <sys/socket.h>
32#include <sys/ioctl.h>
33#include <mISDNif.h>
34
Harald Welte8470bf22008-12-25 23:28:35 +000035//#define AF_COMPATIBILITY_FUNC
36//#include <compat_af_isdn.h>
37#define AF_ISDN 34
38#define PF_ISDN AF_ISDN
39
40#include <openbsc/select.h>
41#include <openbsc/msgb.h>
42#include <openbsc/debug.h>
43#include <openbsc/gsm_data.h>
44#include <openbsc/abis_nm.h>
45#include <openbsc/abis_rsl.h>
Harald Welte52b1f982008-12-23 20:25:15 +000046
47#define NUM_E1_TS 32
48
Holger Freyther9a3ee0f2009-01-02 00:40:15 +000049
50/*
51 * pcap writing of the misdn load
52 * pcap format is from http://wiki.wireshark.org/Development/LibpcapFileFormat
53 */
54#define WTAP_ENCAP_ISDN 17
55#define PCAP_INPUT 0
56#define PCAP_OUTPUT 1
57
58struct pcap_hdr {
59 u_int32_t magic_number;
60 u_int16_t version_major;
61 u_int16_t version_minor;
62 int32_t thiszone;
63 u_int32_t sigfigs;
64 u_int32_t snaplen;
65 u_int32_t network;
66} __attribute__((packed));
67
68struct pcaprec_hdr {
69 u_int32_t ts_sec;
70 u_int32_t ts_usec;
71 u_int32_t incl_len;
72 u_int32_t orig_len;
73} __attribute__((packed));
74
75struct fake_lapd_frame {
76 u_int8_t ea1 : 1;
77 u_int8_t cr : 1;
78 u_int8_t sapi : 6;
79 u_int8_t ea2 : 1;
80 u_int8_t tei : 7;
81 u_int8_t control_foo; /* fake UM's ... */
82} __attribute__((packed));
83
84static int pcap_fd = -1;
85
86void mi_set_pcap_fd(int fd)
87{
88 int ret;
89 struct pcap_hdr header = {
90 .magic_number = 0xa1b2c3d4,
91 .version_major = 2,
92 .version_minor = 4,
93 .thiszone = 0,
94 .sigfigs = 0,
95 .snaplen = 65535,
96 .network = WTAP_ENCAP_ISDN,
97 };
98
99 pcap_fd = fd;
100 ret = write(pcap_fd, &header, sizeof(header));
101}
102
103static void write_pcap_packet(int direction, struct sockaddr_mISDN* addr,
104 struct msgb *msg) {
105 if (pcap_fd < 0)
106 return;
107
108 int ret;
109 struct fake_lapd_frame header = {
110 .ea1 = 0,
111 .cr = PCAP_OUTPUT ? 1 : 0,
112 .sapi = addr->sapi & 0x3F,
113 .ea2 = 1,
114 .tei = addr->tei & 0x7F,
115 .control_foo = 0x13 /* UI with P set */,
116 };
117
118 struct pcaprec_hdr payload_header = {
119 .ts_sec = 0,
120 .ts_usec = 0,
121 .incl_len = msg->len + sizeof(header) - MISDN_HEADER_LEN,
122 .orig_len = msg->len + sizeof(header) - MISDN_HEADER_LEN,
123 };
124
125 ret = write(pcap_fd, &header, sizeof(header));
126 ret = write(pcap_fd, &payload_header, sizeof(payload_header));
127 ret = write(pcap_fd, msg->data + MISDN_HEADER_LEN,
128 msg->len - MISDN_HEADER_LEN);
129}
130
Harald Welte52b1f982008-12-23 20:25:15 +0000131/* data structure for one E1 interface with A-bis */
132struct mi_e1_handle {
133 struct gsm_bts *bts;
Harald Welte52b1f982008-12-23 20:25:15 +0000134 /* The mISDN card number of the card we use */
135 int cardnr;
Harald Welte52b1f982008-12-23 20:25:15 +0000136 /* The RSL adress */
137 struct sockaddr_mISDN l2addr;
Harald Welte52b1f982008-12-23 20:25:15 +0000138 /* The OML adress */
139 struct sockaddr_mISDN omladdr;
Harald Welte8470bf22008-12-25 23:28:35 +0000140 /* list (queue) of to-be-sent msgb's */
141 struct llist_head rsl_tx_list;
142 struct llist_head oml_tx_list;
Harald Welte52b1f982008-12-23 20:25:15 +0000143
Harald Weltead384642008-12-26 10:20:07 +0000144 void (*cb)(int event, struct gsm_bts *bts);
Harald Welte8470bf22008-12-25 23:28:35 +0000145 struct bsc_fd fd[NUM_E1_TS];
Harald Weltee9a82612008-12-27 16:45:29 +0000146
147 int ts2_fd;
Harald Welte52b1f982008-12-23 20:25:15 +0000148};
149
Harald Welte8470bf22008-12-25 23:28:35 +0000150/* FIXME: this needs to go */
151static struct mi_e1_handle *global_e1h;
152
Harald Welte52b1f982008-12-23 20:25:15 +0000153#define SAPI_L2ML 0
154#define SAPI_OML 62
Harald Weltead384642008-12-26 10:20:07 +0000155#define SAPI_RSL 0 /* 63 ? */
Harald Welte52b1f982008-12-23 20:25:15 +0000156
157#define TEI_L2ML 127
158#define TEI_OML 25
159#define TEI_RSL 1
160
Harald Welte702d8702008-12-26 20:25:35 +0000161void hexdump(unsigned char *buf, int len)
Harald Welte52b1f982008-12-23 20:25:15 +0000162{
163 int i;
164 for (i = 0; i < len; i++) {
165 fprintf(stdout, "%02x ", buf[i]);
166 }
167 fprintf(stdout, "\n");
168}
169
170#define TS1_ALLOC_SIZE 300
171
172static int handle_ts1_read(struct bsc_fd *bfd)
173{
174 struct mi_e1_handle *e1h = bfd->data;
175 struct msgb *msg = msgb_alloc(TS1_ALLOC_SIZE);
Harald Welte8470bf22008-12-25 23:28:35 +0000176 struct sockaddr_mISDN l2addr;
177 struct mISDNhead *hh;
Harald Welte52b1f982008-12-23 20:25:15 +0000178 socklen_t alen;
Harald Welte8470bf22008-12-25 23:28:35 +0000179 int ret;
Harald Welte52b1f982008-12-23 20:25:15 +0000180
181 if (!msg)
182 return -ENOMEM;
183
Harald Welte8470bf22008-12-25 23:28:35 +0000184 hh = (struct mISDNhead *) msg->data;
185
186 /* FIXME: Map TEI/SAPI to TRX */
187 msg->trx = e1h->bts->c0;
Harald Welte52b1f982008-12-23 20:25:15 +0000188
189 alen = sizeof(l2addr);
190 ret = recvfrom(bfd->fd, msg->data, 300, 0,
191 (struct sockaddr *) &l2addr, &alen);
192 if (ret < 0) {
193 fprintf(stderr, "recvfrom error %s\n", strerror(errno));
194 return ret;
195 }
196
197 if (alen != sizeof(l2addr))
198 return -EINVAL;
199
200 msgb_put(msg, ret);
201
202 DEBUGP(DMI, "alen =%d, dev(%d) channel(%d) sapi(%d) tei(%d)\n",
203 alen, l2addr.dev, l2addr.channel, l2addr.sapi, l2addr.tei);
204
205 DEBUGP(DMI, "<= len = %d, prim(0x%x) id(0x%x)\n",
206 ret, hh->prim, hh->id);
207
Holger Freyther9a3ee0f2009-01-02 00:40:15 +0000208 write_pcap_packet(PCAP_INPUT, &l2addr, msg);
209
Harald Welte52b1f982008-12-23 20:25:15 +0000210 switch (hh->prim) {
211 case DL_INFORMATION_IND:
212 DEBUGP(DMI, "got DL_INFORMATION_IND\n");
Harald Welte8470bf22008-12-25 23:28:35 +0000213 struct sockaddr_mISDN *sa = NULL;
Harald Welte52b1f982008-12-23 20:25:15 +0000214 char *lstr = "UNKN";
215
216 switch (l2addr.tei) {
217 case TEI_OML:
218 sa = &e1h->omladdr;
219 lstr = "OML";
220 break;
221 case TEI_RSL:
222 sa = &e1h->l2addr;
223 lstr = "RSL";
224 break;
225 default:
Harald Welte8470bf22008-12-25 23:28:35 +0000226 break;
Harald Welte52b1f982008-12-23 20:25:15 +0000227 }
Harald Welte8470bf22008-12-25 23:28:35 +0000228 if (sa) {
229 DEBUGP(DMI, "%s use channel(%d) sapi(%d) tei(%d) for now\n",
230 lstr, l2addr.channel, l2addr.sapi, l2addr.tei);
231 memcpy(sa, &l2addr, sizeof(l2addr));
232 }
Harald Welte52b1f982008-12-23 20:25:15 +0000233 break;
234 case DL_ESTABLISH_IND:
235 DEBUGP(DMI, "got DL_ESTABLISH_IND\n");
236 break;
237 case DL_ESTABLISH_CNF:
238 DEBUGP(DMI, "got DL_ESTABLISH_CNF\n");
239 break;
240 case DL_RELEASE_IND:
Harald Weltead384642008-12-26 10:20:07 +0000241 DEBUGP(DMI, "got DL_RELEASE_IND: E1 Layer 1 disappeared?\n");
Harald Welte52b1f982008-12-23 20:25:15 +0000242 break;
243 case MPH_ACTIVATE_IND:
244 DEBUGP(DMI, "got MPH_ACTIVATE_IND\n");
Harald Weltead384642008-12-26 10:20:07 +0000245 if (l2addr.tei == TEI_OML && l2addr.sapi == SAPI_OML)
246 e1h->cb(EVT_E1_OML_UP, e1h->bts);
247 else if (l2addr.tei == TEI_RSL && l2addr.sapi == SAPI_RSL)
248 e1h->cb(EVT_E1_RSL_UP, e1h->bts);
Harald Welte52b1f982008-12-23 20:25:15 +0000249 break;
250 case MPH_DEACTIVATE_IND:
Harald Weltead384642008-12-26 10:20:07 +0000251 DEBUGP(DMI, "got MPH_DEACTIVATE_IND: TEI link closed?\n");
252 if (l2addr.tei == TEI_OML && l2addr.sapi == SAPI_OML)
253 e1h->cb(EVT_E1_OML_DN, e1h->bts);
254 else if (l2addr.tei == TEI_RSL && l2addr.sapi == SAPI_RSL)
255 e1h->cb(EVT_E1_RSL_DN, e1h->bts);
256 break;
Harald Welte52b1f982008-12-23 20:25:15 +0000257 case DL_DATA_IND:
258 DEBUGP(DMI, "got DL_DATA_IND\n");
Harald Weltead384642008-12-26 10:20:07 +0000259
Harald Weltead384642008-12-26 10:20:07 +0000260 msg->l2h = msg->data + MISDN_HEADER_LEN;
261
Harald Welte6cc38d72008-12-30 14:58:19 +0000262 if (debug_mask & DMI) {
263 fprintf(stdout, "RX: ");
264 hexdump(msgb_l2(msg), ret - MISDN_HEADER_LEN);
265 }
Harald Welte52b1f982008-12-23 20:25:15 +0000266 switch (l2addr.tei) {
267 case TEI_OML:
268 ret = abis_nm_rcvmsg(msg);
269 break;
270 case TEI_RSL:
271 ret = abis_rsl_rcvmsg(msg);
272 break;
273 default:
274 fprintf(stderr, "DATA_IND for unknown TEI\n");
275 break;
276 }
277 break;
278 default:
279 DEBUGP(DMI, "got unexpected 0x%x prim\n", hh->prim);
280 break;
281 }
282 return ret;
283}
284
285static int handle_ts1_write(struct bsc_fd *bfd)
286{
287 struct mi_e1_handle *e1h = bfd->data;
Harald Welte8470bf22008-12-25 23:28:35 +0000288 struct msgb *msg;
289 struct mISDNhead *hh;
Harald Weltead384642008-12-26 10:20:07 +0000290 int ret, no_oml = 0;
Harald Welte52b1f982008-12-23 20:25:15 +0000291
Harald Weltead384642008-12-26 10:20:07 +0000292 msg = msgb_dequeue(&e1h->oml_tx_list);
Harald Welte8470bf22008-12-25 23:28:35 +0000293 if (!msg)
Harald Weltead384642008-12-26 10:20:07 +0000294 no_oml = 1;
Harald Welte8470bf22008-12-25 23:28:35 +0000295 else {
Harald Weltead384642008-12-26 10:20:07 +0000296 u_int8_t *l2_data = msg->data;
297
Harald Welte8470bf22008-12-25 23:28:35 +0000298 /* prepend the mISDNhead */
299 hh = (struct mISDNhead *) msgb_push(msg, sizeof(*hh));
300 hh->prim = DL_DATA_REQ;
Harald Welte52b1f982008-12-23 20:25:15 +0000301
Harald Welte6cc38d72008-12-30 14:58:19 +0000302 if (debug_mask & DMI) {
303 fprintf(stdout, "OML TX: ");
304 hexdump(l2_data, msg->len - MISDN_HEADER_LEN);
305 }
Holger Freyther9a3ee0f2009-01-02 00:40:15 +0000306
307 write_pcap_packet(PCAP_OUTPUT, &e1h->omladdr, msg);
Harald Welte8470bf22008-12-25 23:28:35 +0000308 ret = sendto(bfd->fd, msg->data, msg->len, 0,
Harald Welte5d2f8ec2008-12-26 10:46:24 +0000309 (struct sockaddr *)&e1h->omladdr,
310 sizeof(e1h->omladdr));
Harald Weltee571fb82008-12-25 23:50:30 +0000311 msgb_free(msg);
Harald Welte8470bf22008-12-25 23:28:35 +0000312 usleep(100000);
Harald Weltead384642008-12-26 10:20:07 +0000313 /* we always dequeue all OML messages */
314 return ret;
Harald Welte8470bf22008-12-25 23:28:35 +0000315 }
Harald Weltead384642008-12-26 10:20:07 +0000316
Harald Welte8470bf22008-12-25 23:28:35 +0000317 msg = msgb_dequeue(&e1h->rsl_tx_list);
318 if (!msg) {
Harald Weltead384642008-12-26 10:20:07 +0000319 if (no_oml)
Harald Welte8470bf22008-12-25 23:28:35 +0000320 bfd->when &= ~BSC_FD_WRITE;
321 } else {
Harald Weltead384642008-12-26 10:20:07 +0000322 u_int8_t *l2_data = msg->data;
323
Harald Welte8470bf22008-12-25 23:28:35 +0000324 /* prepend the mISDNhead */
325 hh = (struct mISDNhead *) msgb_push(msg, sizeof(*hh));
326 hh->prim = DL_DATA_REQ;
327
Harald Welte6cc38d72008-12-30 14:58:19 +0000328 if (debug_mask & DMI) {
329 fprintf(stdout, "RSL TX: ");
330 hexdump(l2_data, msg->len - MISDN_HEADER_LEN);
331 }
Harald Weltead384642008-12-26 10:20:07 +0000332
Holger Freyther9a3ee0f2009-01-02 00:40:15 +0000333 write_pcap_packet(PCAP_OUTPUT, &e1h->l2addr, msg);
Harald Welte8470bf22008-12-25 23:28:35 +0000334 ret = sendto(bfd->fd, msg->data, msg->len, 0,
Harald Welte5d2f8ec2008-12-26 10:46:24 +0000335 (struct sockaddr *)&e1h->l2addr,
336 sizeof(e1h->l2addr));
Harald Weltee571fb82008-12-25 23:50:30 +0000337 msgb_free(msg);
Harald Welteb2750422008-12-27 11:24:23 +0000338 usleep(10000);
Harald Welte702d8702008-12-26 20:25:35 +0000339 //sleep(1);
Harald Welte8470bf22008-12-25 23:28:35 +0000340 }
341
342 return ret;
Harald Welte52b1f982008-12-23 20:25:15 +0000343}
344
Harald Weltee9a82612008-12-27 16:45:29 +0000345#define TSX_ALLOC_SIZE 4096
346
347/* FIXME: read from a B channel TS */
Harald Welte52b1f982008-12-23 20:25:15 +0000348static int handle_tsX_read(struct bsc_fd *bfd)
349{
Harald Weltee9a82612008-12-27 16:45:29 +0000350 struct mi_e1_handle *e1h = bfd->data;
351 struct msgb *msg = msgb_alloc(TSX_ALLOC_SIZE);
352 struct mISDNhead *hh;
353 int ret;
354
355 if (!msg)
356 return -ENOMEM;
357
358 hh = (struct mISDNhead *) msg->data;
359
360 /* FIXME: Map TEI/SAPI to TRX */
361 msg->trx = e1h->bts->c0;
362
363 ret = recv(bfd->fd, msg->data, TSX_ALLOC_SIZE, 0);
364 if (ret < 0) {
365 fprintf(stderr, "recvfrom error %s\n", strerror(errno));
366 return ret;
367 }
368
369 msgb_put(msg, ret);
370
371 DEBUGP(DMIB, "<= BCHAN len = %d, prim(0x%x) id(0x%x)\n", ret, hh->prim, hh->id);
372
373 switch (hh->prim) {
374 case PH_CONTROL_IND:
375 DEBUGP(DMIB, "got PH_CONTROL_IND\n");
376 break;
377 case PH_DATA_IND:
378 DEBUGP(DMIB, "got PH_DATA_IND\n");
379
380 msg->l2h = msg->data + MISDN_HEADER_LEN;
381
Harald Welte6cc38d72008-12-30 14:58:19 +0000382 if (debug_mask & DMIB) {
383 fprintf(stdout, "BCHAN RX: ");
384 hexdump(msgb_l2(msg), ret - MISDN_HEADER_LEN);
385 }
Harald Weltee9a82612008-12-27 16:45:29 +0000386 if (!e1h->ts2_fd)
387 e1h->ts2_fd = open("/tmp/ts2.dump", O_WRONLY|O_APPEND|O_CREAT, 0660);
388
389 write(e1h->ts2_fd, msgb_l2(msg), ret - MISDN_HEADER_LEN);
390
391 break;
392 default:
393 DEBUGP(DMIB, "got unexpected 0x%x prim\n", hh->prim);
394 break;
395 }
Harald Weltee27bb342008-12-29 06:06:35 +0000396 /* FIXME: don't free it if we still hold reference! */
397 msgb_free(msg);
398
Harald Weltee9a82612008-12-27 16:45:29 +0000399 return ret;
Harald Welte52b1f982008-12-23 20:25:15 +0000400}
401
Harald Welte8470bf22008-12-25 23:28:35 +0000402static int handle_tsX_write(struct bsc_fd *bfd)
Harald Welte52b1f982008-12-23 20:25:15 +0000403{
404 /* FIXME: write to a B channel TS */
Holger Freyther059c2542008-12-27 09:39:48 +0000405 return -1;
Harald Welte52b1f982008-12-23 20:25:15 +0000406}
407
408/* callback from select.c in case one of the fd's can be read/written */
Harald Welte8470bf22008-12-25 23:28:35 +0000409static int misdn_fd_cb(struct bsc_fd *bfd, unsigned int what)
Harald Welte52b1f982008-12-23 20:25:15 +0000410{
411 unsigned int e1_ts = bfd->priv_nr;
412 int rc = 0;
413
414 switch (e1_ts) {
415 case 1:
416 if (what & BSC_FD_READ)
417 rc = handle_ts1_read(bfd);
418 if (what & BSC_FD_WRITE)
419 rc = handle_ts1_write(bfd);
420 break;
421 default:
422 if (what & BSC_FD_READ)
423 rc = handle_tsX_read(bfd);
424 if (what & BSC_FD_WRITE)
425 rc = handle_tsX_write(bfd);
426 break;
427 }
428
429 return rc;
430}
431
Harald Welte8470bf22008-12-25 23:28:35 +0000432int abis_rsl_sendmsg(struct msgb *msg)
Harald Welte52b1f982008-12-23 20:25:15 +0000433{
Harald Welte8470bf22008-12-25 23:28:35 +0000434 struct mi_e1_handle *e1h = global_e1h;
435
Harald Weltead384642008-12-26 10:20:07 +0000436 msg->l2h = msg->data;
Harald Welte8470bf22008-12-25 23:28:35 +0000437 msgb_enqueue(&e1h->rsl_tx_list, msg);
438 e1h->fd[0].when |= BSC_FD_WRITE;
439
440 return 0;
441}
442
Harald Weltead384642008-12-26 10:20:07 +0000443int _abis_nm_sendmsg(struct msgb *msg)
Harald Welte8470bf22008-12-25 23:28:35 +0000444{
445 struct mi_e1_handle *e1h = global_e1h;
446
Harald Weltead384642008-12-26 10:20:07 +0000447 msg->l2h = msg->data;
Harald Welte8470bf22008-12-25 23:28:35 +0000448 msgb_enqueue(&e1h->oml_tx_list, msg);
449 e1h->fd[0].when |= BSC_FD_WRITE;
450
451 return 0;
452}
453
Harald Weltee9a82612008-12-27 16:45:29 +0000454static int activate_bchan(struct mi_e1_handle *e1h, int ts)
455{
456 struct mISDNhead hh;
457 int ret;
458 struct bsc_fd *bfd = &e1h->fd[ts-1];
459
460 fprintf(stdout, "activate bchan\n");
461 hh.prim = PH_ACTIVATE_REQ;
462 hh.id = MISDN_ID_ANY;
463 ret = sendto(bfd->fd, &hh, sizeof(hh), 0, NULL, 0);
464 if (ret < 0) {
465 fprintf(stdout, "could not send ACTIVATE_RQ %s\n",
466 strerror(errno));
467 return 0;
468 }
469
470 return ret;
471}
472
Harald Welte8470bf22008-12-25 23:28:35 +0000473static int mi_e1_setup(struct mi_e1_handle *e1h)
474{
475 int ts, sk, ret, cnt;
476 struct mISDN_devinfo devinfo;
Harald Welte52b1f982008-12-23 20:25:15 +0000477
478 sk = socket(PF_ISDN, SOCK_RAW, ISDN_P_BASE);
Harald Welte8470bf22008-12-25 23:28:35 +0000479 if (sk < 0) {
Harald Welte52b1f982008-12-23 20:25:15 +0000480 fprintf(stderr, "could not open socket %s\n", strerror(errno));
481 return sk;
482 }
483
484 ret = ioctl(sk, IMGETCOUNT, &cnt);
485 if (ret) {
486 fprintf(stderr, "error getting interf count: %s\n",
487 strerror(errno));
488 close(sk);
489 return -ENODEV;
490 }
Harald Weltead384642008-12-26 10:20:07 +0000491 //DEBUGP(DMI,"%d device%s found\n", cnt, (cnt==1)?"":"s");
492 printf("%d device%s found\n", cnt, (cnt==1)?"":"s");
493#if 1
494 devinfo.id = e1h->cardnr;
Harald Welte52b1f982008-12-23 20:25:15 +0000495 ret = ioctl(sk, IMGETDEVINFO, &devinfo);
496 if (ret < 0) {
497 fprintf(stdout, "error getting info for device %d: %s\n",
Harald Weltead384642008-12-26 10:20:07 +0000498 e1h->cardnr, strerror(errno));
Harald Welte52b1f982008-12-23 20:25:15 +0000499 return -ENODEV;
500 }
501 fprintf(stdout, " id: %d\n", devinfo.id);
502 fprintf(stdout, " Dprotocols: %08x\n", devinfo.Dprotocols);
503 fprintf(stdout, " Bprotocols: %08x\n", devinfo.Bprotocols);
504 fprintf(stdout, " protocol: %d\n", devinfo.protocol);
505 fprintf(stdout, " nrbchan: %d\n", devinfo.nrbchan);
506 fprintf(stdout, " name: %s\n", devinfo.name);
507#endif
508
509 /* TS0 is CRC4, don't need any fd for it */
510 for (ts = 1; ts < NUM_E1_TS; ts++) {
Harald Welte8470bf22008-12-25 23:28:35 +0000511 unsigned int idx = ts-1;
Harald Welte52b1f982008-12-23 20:25:15 +0000512 struct bsc_fd *bfd = &e1h->fd[idx];
513 struct sockaddr_mISDN addr;
514
Harald Welte8470bf22008-12-25 23:28:35 +0000515 bfd->data = e1h;
516 bfd->priv_nr = ts;
517 bfd->cb = misdn_fd_cb;
518
519 if (ts == 1) {
Harald Weltead384642008-12-26 10:20:07 +0000520 bfd->fd = socket(PF_ISDN, SOCK_DGRAM, ISDN_P_LAPD_NT);
Harald Welte8470bf22008-12-25 23:28:35 +0000521 bfd->when = BSC_FD_READ;
Harald Welte6cc38d72008-12-30 14:58:19 +0000522 } else
Harald Welte52b1f982008-12-23 20:25:15 +0000523 bfd->fd = socket(PF_ISDN, SOCK_DGRAM, ISDN_P_B_RAW);
524
Harald Welte8470bf22008-12-25 23:28:35 +0000525 if (bfd->fd < 0) {
Harald Welte52b1f982008-12-23 20:25:15 +0000526 fprintf(stderr, "could not open socket %s\n",
527 strerror(errno));
528 return bfd->fd;
529 }
530
531 memset(&addr, 0, sizeof(addr));
532 addr.family = AF_ISDN;
533 addr.dev = e1h->cardnr;
534 if (ts == 1) {
535 addr.channel = 0;
536 addr.sapi = 0;/* SAPI not supported yet in kernel */
537 addr.tei = TEI_L2ML;
538 } else
Harald Welte6cc38d72008-12-30 14:58:19 +0000539 addr.channel = ts;
Harald Welte52b1f982008-12-23 20:25:15 +0000540
541 ret = bind(bfd->fd, (struct sockaddr *) &addr, sizeof(addr));
542 if (ret < 0) {
Harald Welte8470bf22008-12-25 23:28:35 +0000543 fprintf(stderr, "could not bind l2 socket %s\n",
Harald Welte52b1f982008-12-23 20:25:15 +0000544 strerror(errno));
545 return -EIO;
546 }
Harald Welte8470bf22008-12-25 23:28:35 +0000547
Harald Weltee9a82612008-12-27 16:45:29 +0000548 if (ts == 2) {
549 bfd->when = BSC_FD_READ;
550 activate_bchan(e1h, ts);
551 }
552
Harald Welte8470bf22008-12-25 23:28:35 +0000553 ret = bsc_register_fd(bfd);
554 if (ret < 0) {
555 fprintf(stderr, "could not register FD: %s\n",
556 strerror(ret));
557 return ret;
558 }
Harald Welte52b1f982008-12-23 20:25:15 +0000559 }
Harald Welte8470bf22008-12-25 23:28:35 +0000560
561 return 0;
Harald Welte52b1f982008-12-23 20:25:15 +0000562}
563
Harald Weltead384642008-12-26 10:20:07 +0000564int mi_setup(struct gsm_bts *bts, int cardnr,
565 void (cb)(int event, struct gsm_bts *bts))
Harald Welte8470bf22008-12-25 23:28:35 +0000566{
567 struct mi_e1_handle *e1h;
568
569 e1h = malloc(sizeof(*e1h));
570 memset(e1h, 0, sizeof(*e1h));
571
572 e1h->cardnr = cardnr;
573 e1h->bts = bts;
Harald Weltead384642008-12-26 10:20:07 +0000574 e1h->cb = cb;
Harald Welte8470bf22008-12-25 23:28:35 +0000575 INIT_LLIST_HEAD(&e1h->oml_tx_list);
576 INIT_LLIST_HEAD(&e1h->rsl_tx_list);
577
578 global_e1h = e1h;
579
580 return mi_e1_setup(e1h);
581}