blob: 716c1e76faea96a03e55e1e1f4558a4a5b88c61b [file] [log] [blame]
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +02001/* OpenBSC Abis input driver for mISDNuser */
2
Harald Weltece307b42011-08-21 01:18:05 +02003/* (C) 2008-2011 by Harald Welte <laforge@gnumonks.org>
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +02004 * (C) 2009 by Holger Hans Peter Freyther <zecke@selfish.org>
5 *
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 Affero General Public License as published by
10 * the Free Software Foundation; either version 3 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 Affero General Public License for more details.
17 *
18 * You should have received a copy of the GNU Affero General Public License
19 * along with this program. If not, see <http://www.gnu.org/licenses/>.
20 *
21 */
22
Harald Weltece307b42011-08-21 01:18:05 +020023/*! \file misdn.c
24 * \brief Osmocom A-bis input driver for mISDN
25 *
26 * This driver has two modes of operations, exported via two different
27 * \ref e1_input_driver structures:
28 * "misdn" is the classic version and it uses the in-kernel LAPD
29 * implementation. This is somewhat limited in e.g. the fact that
30 * you can only have one E1 timeslot in signaling mode.
31 * "misdn_lapd" is a newer version which uses userspace LAPD code
32 * contained in libosmo-abis. It offers the same flexibilty as the
33 * DAHDI driver, i.e. any number of signaling slots.
34 */
35
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +020036#include "internal.h"
37
38#include <stdio.h>
39#include <unistd.h>
40#include <stdlib.h>
41#include <errno.h>
42#include <string.h>
43#include <time.h>
44#include <sys/fcntl.h>
45#include <sys/socket.h>
46#include <sys/ioctl.h>
47#include <arpa/inet.h>
48#include <mISDNif.h>
49
50//#define AF_COMPATIBILITY_FUNC
51//#include <compat_af_isdn.h>
52#ifndef AF_ISDN
53#define AF_ISDN 34
54#define PF_ISDN AF_ISDN
55#endif
56
57#include <osmocom/core/select.h>
Harald Welte6341aa02011-08-21 00:55:23 +020058#include <osmocom/core/utils.h>
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +020059#include <osmocom/core/msgb.h>
60#include <osmocom/core/logging.h>
Pablo Neira Ayuso177094b2011-06-07 12:21:51 +020061#include <osmocom/abis/e1_input.h>
Harald Weltece307b42011-08-21 01:18:05 +020062#include <osmocom/abis/lapd.h>
Harald Welte71d87b22011-07-18 14:49:56 +020063#include <osmocom/core/talloc.h>
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +020064
65#define TS1_ALLOC_SIZE 300
66
Harald Weltece307b42011-08-21 01:18:05 +020067/*! \brief driver-specific data for \ref e1inp_line::driver_data */
68struct misdn_line {
69 int use_userspace_lapd;
70};
71
Harald Welte6341aa02011-08-21 00:55:23 +020072const struct value_string prim_names[] = {
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +020073 { PH_CONTROL_IND, "PH_CONTROL_IND" },
74 { PH_DATA_IND, "PH_DATA_IND" },
75 { PH_DATA_CNF, "PH_DATA_CNF" },
76 { PH_ACTIVATE_IND, "PH_ACTIVATE_IND" },
77 { DL_ESTABLISH_IND, "DL_ESTABLISH_IND" },
78 { DL_ESTABLISH_CNF, "DL_ESTABLISH_CNF" },
79 { DL_RELEASE_IND, "DL_RELEASE_IND" },
80 { DL_RELEASE_CNF, "DL_RELEASE_CNF" },
81 { DL_DATA_IND, "DL_DATA_IND" },
82 { DL_UNITDATA_IND, "DL_UNITDATA_IND" },
83 { DL_INFORMATION_IND, "DL_INFORMATION_IND" },
84 { MPH_ACTIVATE_IND, "MPH_ACTIVATE_IND" },
85 { MPH_DEACTIVATE_IND, "MPH_DEACTIVATE_IND" },
Harald Welte6341aa02011-08-21 00:55:23 +020086 { 0, NULL }
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +020087};
88
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +020089static int handle_ts1_read(struct osmo_fd *bfd)
90{
91 struct e1inp_line *line = bfd->data;
Harald Weltece307b42011-08-21 01:18:05 +020092 struct misdn_line *mline = line->driver_data;
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +020093 unsigned int ts_nr = bfd->priv_nr;
94 struct e1inp_ts *e1i_ts = &line->ts[ts_nr-1];
95 struct e1inp_sign_link *link;
96 struct msgb *msg = msgb_alloc(TS1_ALLOC_SIZE, "mISDN TS1");
97 struct sockaddr_mISDN l2addr;
98 struct mISDNhead *hh;
99 socklen_t alen;
100 int ret;
101
102 if (!msg)
103 return -ENOMEM;
104
105 hh = (struct mISDNhead *) msg->data;
106
107 alen = sizeof(l2addr);
108 ret = recvfrom(bfd->fd, msg->data, 300, 0,
109 (struct sockaddr *) &l2addr, &alen);
110 if (ret < 0) {
111 fprintf(stderr, "recvfrom error %s\n", strerror(errno));
112 return ret;
113 }
114
115 if (alen != sizeof(l2addr)) {
Pablo Neira Ayusoc9c4fd32011-06-30 12:19:42 +0200116 fprintf(stderr, "%s error len\n", __func__);
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +0200117 return -EINVAL;
118 }
119
120 msgb_put(msg, ret);
121
Harald Weltecc2241b2011-07-19 16:06:06 +0200122 DEBUGP(DLMI, "alen =%d, dev(%d) channel(%d) sapi(%d) tei(%d)\n",
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +0200123 alen, l2addr.dev, l2addr.channel, l2addr.sapi, l2addr.tei);
124
Harald Weltecc2241b2011-07-19 16:06:06 +0200125 DEBUGP(DLMI, "<= len = %d, prim(0x%x) id(0x%x): %s\n",
Harald Welte6341aa02011-08-21 00:55:23 +0200126 ret, hh->prim, hh->id, get_value_string(prim_names, hh->prim));
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +0200127
128 switch (hh->prim) {
129 case DL_INFORMATION_IND:
130 /* mISDN tells us which channel number is allocated for this
131 * tuple of (SAPI, TEI). */
Harald Weltecc2241b2011-07-19 16:06:06 +0200132 DEBUGP(DLMI, "DL_INFORMATION_IND: use channel(%d) sapi(%d) tei(%d) for now\n",
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +0200133 l2addr.channel, l2addr.sapi, l2addr.tei);
134 link = e1inp_lookup_sign_link(e1i_ts, l2addr.tei, l2addr.sapi);
135 if (!link) {
Harald Weltecc2241b2011-07-19 16:06:06 +0200136 DEBUGPC(DLMI, "mISDN message for unknown sign_link\n");
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +0200137 msgb_free(msg);
138 return -EINVAL;
139 }
140 /* save the channel number in the driver private struct */
141 link->driver.misdn.channel = l2addr.channel;
142 break;
143 case DL_ESTABLISH_IND:
Harald Weltecc2241b2011-07-19 16:06:06 +0200144 DEBUGP(DLMI, "DL_ESTABLISH_IND: channel(%d) sapi(%d) tei(%d)\n",
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +0200145 l2addr.channel, l2addr.sapi, l2addr.tei);
146 /* For some strange reason, sometimes the DL_INFORMATION_IND tells
147 * us the wrong channel, and we only get the real channel number
148 * during the DL_ESTABLISH_IND */
149 link = e1inp_lookup_sign_link(e1i_ts, l2addr.tei, l2addr.sapi);
150 if (!link) {
Harald Weltecc2241b2011-07-19 16:06:06 +0200151 DEBUGPC(DLMI, "mISDN message for unknown sign_link\n");
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +0200152 msgb_free(msg);
153 return -EINVAL;
154 }
155 /* save the channel number in the driver private struct */
156 link->driver.misdn.channel = l2addr.channel;
Pablo Neira Ayusode668912011-08-16 17:26:23 +0200157 ret = e1inp_event(e1i_ts, S_L_INP_TEI_UP, l2addr.tei, l2addr.sapi);
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +0200158 break;
159 case DL_RELEASE_IND:
Harald Weltecc2241b2011-07-19 16:06:06 +0200160 DEBUGP(DLMI, "DL_RELEASE_IND: channel(%d) sapi(%d) tei(%d)\n",
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +0200161 l2addr.channel, l2addr.sapi, l2addr.tei);
Pablo Neira Ayusode668912011-08-16 17:26:23 +0200162 ret = e1inp_event(e1i_ts, S_L_INP_TEI_DN, l2addr.tei, l2addr.sapi);
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +0200163 break;
164 case DL_DATA_IND:
165 case DL_UNITDATA_IND:
166 msg->l2h = msg->data + MISDN_HEADER_LEN;
Harald Weltecc2241b2011-07-19 16:06:06 +0200167 DEBUGP(DLMI, "RX: %s\n", osmo_hexdump(msgb_l2(msg), ret - MISDN_HEADER_LEN));
Harald Weltece307b42011-08-21 01:18:05 +0200168 if (mline->use_userspace_lapd) {
169 LOGP(DLMI, LOGL_ERROR, "DL_DATA_IND but userspace LAPD ?!?\n");
170 return -EIO;
171 }
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +0200172 ret = e1inp_rx_ts(e1i_ts, msg, l2addr.tei, l2addr.sapi);
173 break;
174 case PH_ACTIVATE_IND:
Harald Weltecc2241b2011-07-19 16:06:06 +0200175 DEBUGP(DLMI, "PH_ACTIVATE_IND: channel(%d) sapi(%d) tei(%d)\n",
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +0200176 l2addr.channel, l2addr.sapi, l2addr.tei);
177 break;
178 case PH_DEACTIVATE_IND:
Harald Weltecc2241b2011-07-19 16:06:06 +0200179 DEBUGP(DLMI, "PH_DEACTIVATE_IND: channel(%d) sapi(%d) tei(%d)\n",
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +0200180 l2addr.channel, l2addr.sapi, l2addr.tei);
181 break;
Harald Weltece307b42011-08-21 01:18:05 +0200182 case PH_DATA_IND:
183 if (!mline->use_userspace_lapd) {
184 LOGP(DLMI, LOGL_ERROR, "PH_DATA_IND but kernel LAPD ?!?\n");
185 return -EIO;
186 }
187 /* remove the Misdn Header */
188 msgb_pull(msg, MISDN_HEADER_LEN);
189 /* hand into the LAPD code */
190 DEBUGP(DLMI, "RX: %s\n", osmo_hexdump(msg->data, msg->len));
191 ret = e1inp_rx_ts_lapd(e1i_ts, msg);
192 break;
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +0200193 default:
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +0200194 break;
195 }
196 return ret;
197}
198
199static int ts_want_write(struct e1inp_ts *e1i_ts)
200{
201 /* We never include the mISDN B-Channel FD into the
202 * writeset, since it doesn't support poll() based
203 * write flow control */
204 if (e1i_ts->type == E1INP_TS_TYPE_TRAU)
205 return 0;
206
207 e1i_ts->driver.misdn.fd.when |= BSC_FD_WRITE;
208
209 return 0;
210}
211
212static void timeout_ts1_write(void *data)
213{
214 struct e1inp_ts *e1i_ts = (struct e1inp_ts *)data;
215
216 /* trigger write of ts1, due to tx delay timer */
217 ts_want_write(e1i_ts);
218}
219
220static int handle_ts1_write(struct osmo_fd *bfd)
221{
222 struct e1inp_line *line = bfd->data;
Harald Weltece307b42011-08-21 01:18:05 +0200223 struct misdn_line *mline = line->driver_data;
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +0200224 unsigned int ts_nr = bfd->priv_nr;
225 struct e1inp_ts *e1i_ts = &line->ts[ts_nr-1];
226 struct e1inp_sign_link *sign_link;
227 struct sockaddr_mISDN sa;
228 struct msgb *msg;
229 struct mISDNhead *hh;
230 uint8_t *l2_data;
231 int ret;
232
233 bfd->when &= ~BSC_FD_WRITE;
234
235 /* get the next msg for this timeslot */
236 msg = e1inp_tx_ts(e1i_ts, &sign_link);
237 if (!msg) {
238 /* no message after tx delay timer */
239 return 0;
240 }
241
Harald Weltece307b42011-08-21 01:18:05 +0200242 if (mline->use_userspace_lapd) {
243 DEBUGP(DLMI, "TX %u/%u/%u: %s\n",
244 line->num, sign_link->tei, sign_link->sapi,
245 osmo_hexdump(msg->data, msg->len));
246 lapd_transmit(e1i_ts->lapd, sign_link->tei,
247 sign_link->sapi, msg->data, msg->len);
248 } else {
249 l2_data = msg->data;
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +0200250
Harald Weltece307b42011-08-21 01:18:05 +0200251 /* prepend the mISDNhead */
252 hh = (struct mISDNhead *) msgb_push(msg, sizeof(*hh));
253 hh->prim = DL_DATA_REQ;
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +0200254
Harald Weltece307b42011-08-21 01:18:05 +0200255 DEBUGP(DLMI, "TX channel(%d) TEI(%d) SAPI(%d): %s\n",
256 sign_link->driver.misdn.channel, sign_link->tei,
257 sign_link->sapi, osmo_hexdump(l2_data, msg->len - MISDN_HEADER_LEN));
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +0200258
Harald Weltece307b42011-08-21 01:18:05 +0200259 /* construct the sockaddr */
260 sa.family = AF_ISDN;
261 sa.sapi = sign_link->sapi;
262 sa.dev = sign_link->tei;
263 sa.channel = sign_link->driver.misdn.channel;
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +0200264
Harald Weltece307b42011-08-21 01:18:05 +0200265 ret = sendto(bfd->fd, msg->data, msg->len, 0,
266 (struct sockaddr *)&sa, sizeof(sa));
267 if (ret < 0)
268 fprintf(stderr, "%s sendto failed %d\n", __func__, ret);
269 }
270
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +0200271 msgb_free(msg);
272
273 /* set tx delay timer for next event */
274 e1i_ts->sign.tx_timer.cb = timeout_ts1_write;
275 e1i_ts->sign.tx_timer.data = e1i_ts;
276 osmo_timer_schedule(&e1i_ts->sign.tx_timer, 0, e1i_ts->sign.delay);
277
278 return ret;
279}
280
Harald Weltece307b42011-08-21 01:18:05 +0200281/*! \brief call-back from LAPD code, called when it wants to Tx data */
282static void misdn_write_msg(uint8_t *data, int len, void *cbdata)
283{
284 struct osmo_fd *bfd = cbdata;
285 struct e1inp_line *line = bfd->data;
286 unsigned int ts_nr = bfd->priv_nr;
287 struct e1inp_ts *e1i_ts = &line->ts[ts_nr-1];
288 struct msgb *msg = msgb_alloc(1024, "mISDN PH_DATA_REQ");
289 struct mISDNhead *hh;
290 int ret;
291
292 hh = (struct mISDNhead *) msgb_put(msg, MISDN_HEADER_LEN);
293 hh->prim = PH_DATA_REQ;
294
295 memcpy(msgb_put(msg, len), data, len);
296
297 ret = write(bfd->fd, msg->data, msg->len);
298 if (ret < 0)
299 LOGP(DLMI, LOGL_NOTICE, "write failed %d\n", ret);
300
301 msgb_free(msg);
302}
303
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +0200304#define BCHAN_TX_GRAN 160
305/* write to a B channel TS */
306static int handle_tsX_write(struct osmo_fd *bfd)
307{
308 struct e1inp_line *line = bfd->data;
309 unsigned int ts_nr = bfd->priv_nr;
310 struct e1inp_ts *e1i_ts = &line->ts[ts_nr-1];
311 struct mISDNhead *hh;
312 uint8_t tx_buf[BCHAN_TX_GRAN + sizeof(*hh)];
313 struct subch_mux *mx = &e1i_ts->trau.mux;
314 int ret;
315
316 hh = (struct mISDNhead *) tx_buf;
317 hh->prim = PH_DATA_REQ;
318
319 subchan_mux_out(mx, tx_buf+sizeof(*hh), BCHAN_TX_GRAN);
320
Harald Weltecc2241b2011-07-19 16:06:06 +0200321 DEBUGP(DLMIB, "BCHAN TX: %s\n",
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +0200322 osmo_hexdump(tx_buf+sizeof(*hh), BCHAN_TX_GRAN));
323
324 ret = send(bfd->fd, tx_buf, sizeof(*hh) + BCHAN_TX_GRAN, 0);
325 if (ret < sizeof(*hh) + BCHAN_TX_GRAN)
Harald Weltecc2241b2011-07-19 16:06:06 +0200326 DEBUGP(DLMIB, "send returns %d instead of %zu\n", ret,
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +0200327 sizeof(*hh) + BCHAN_TX_GRAN);
328
329 return ret;
330}
331
332#define TSX_ALLOC_SIZE 4096
333/* FIXME: read from a B channel TS */
334static int handle_tsX_read(struct osmo_fd *bfd)
335{
336 struct e1inp_line *line = bfd->data;
337 unsigned int ts_nr = bfd->priv_nr;
338 struct e1inp_ts *e1i_ts = &line->ts[ts_nr-1];
339 struct msgb *msg = msgb_alloc(TSX_ALLOC_SIZE, "mISDN TSx");
340 struct mISDNhead *hh;
341 int ret;
342
343 if (!msg)
344 return -ENOMEM;
345
346 hh = (struct mISDNhead *) msg->data;
347
348 ret = recv(bfd->fd, msg->data, TSX_ALLOC_SIZE, 0);
349 if (ret < 0) {
350 fprintf(stderr, "recvfrom error %s\n", strerror(errno));
351 return ret;
352 }
353
354 msgb_put(msg, ret);
355
356 if (hh->prim != PH_CONTROL_IND)
Harald Weltecc2241b2011-07-19 16:06:06 +0200357 DEBUGP(DLMIB, "<= BCHAN len = %d, prim(0x%x) id(0x%x): %s\n",
Harald Welte6341aa02011-08-21 00:55:23 +0200358 ret, hh->prim, hh->id,
359 get_value_string(prim_names, hh->prim));
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +0200360
361 switch (hh->prim) {
362 case PH_DATA_IND:
363 msg->l2h = msg->data + MISDN_HEADER_LEN;
Harald Weltecc2241b2011-07-19 16:06:06 +0200364 DEBUGP(DLMIB, "BCHAN RX: %s\n",
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +0200365 osmo_hexdump(msgb_l2(msg), ret - MISDN_HEADER_LEN));
366 ret = e1inp_rx_ts(e1i_ts, msg, 0, 0);
367 break;
368 case PH_ACTIVATE_IND:
369 case PH_DATA_CNF:
370 /* physical layer indicates that data has been sent,
371 * we thus can send some more data */
372 ret = handle_tsX_write(bfd);
373 default:
374 break;
375 }
376 /* FIXME: why do we free signalling msgs in the caller, and trau not? */
377 msgb_free(msg);
378
379 return ret;
380}
381
382/* callback from select.c in case one of the fd's can be read/written */
383static int misdn_fd_cb(struct osmo_fd *bfd, unsigned int what)
384{
385 struct e1inp_line *line = bfd->data;
386 unsigned int ts_nr = bfd->priv_nr;
387 unsigned int idx = ts_nr-1;
388 struct e1inp_ts *e1i_ts = &line->ts[idx];
389 int rc = 0;
390
391 switch (e1i_ts->type) {
392 case E1INP_TS_TYPE_SIGN:
393 if (what & BSC_FD_READ)
394 rc = handle_ts1_read(bfd);
395 if (what & BSC_FD_WRITE)
396 rc = handle_ts1_write(bfd);
397 break;
398 case E1INP_TS_TYPE_TRAU:
399 if (what & BSC_FD_READ)
400 rc = handle_tsX_read(bfd);
401 /* We never include the mISDN B-Channel FD into the
402 * writeset, since it doesn't support poll() based
403 * write flow control */
404 break;
405 default:
406 fprintf(stderr, "unknown E1 TS type %u\n", e1i_ts->type);
407 break;
408 }
409
410 return rc;
411}
412
413static int activate_bchan(struct e1inp_line *line, int ts, int act)
414{
415 struct mISDNhead hh;
416 int ret;
417 unsigned int idx = ts-1;
418 struct e1inp_ts *e1i_ts = &line->ts[idx];
419 struct osmo_fd *bfd = &e1i_ts->driver.misdn.fd;
420
421 fprintf(stdout, "activate bchan\n");
422 if (act)
423 hh.prim = PH_ACTIVATE_REQ;
424 else
425 hh.prim = PH_DEACTIVATE_REQ;
426
427 hh.id = MISDN_ID_ANY;
428 ret = sendto(bfd->fd, &hh, sizeof(hh), 0, NULL, 0);
429 if (ret < 0) {
430 fprintf(stdout, "could not send ACTIVATE_RQ %s\n",
431 strerror(errno));
432 }
433
434 return ret;
435}
436
Pablo Neira Ayuso4e862cb2011-08-19 18:43:38 +0200437static int mi_e1_line_update(struct e1inp_line *line);
Harald Weltece307b42011-08-21 01:18:05 +0200438static int mi_e1_line_update_lapd(struct e1inp_line *line);
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +0200439
440struct e1inp_driver misdn_driver = {
441 .name = "misdn",
442 .want_write = ts_want_write,
443 .default_delay = 50000,
444 .line_update = &mi_e1_line_update,
445};
446
Harald Weltece307b42011-08-21 01:18:05 +0200447struct e1inp_driver misdn_lapd_driver = {
448 .name = "misdn_lapd",
449 .want_write = ts_want_write,
450 .default_delay = 50000,
451 .line_update = &mi_e1_line_update_lapd,
452};
453
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +0200454static int mi_e1_setup(struct e1inp_line *line, int release_l2)
455{
Harald Weltece307b42011-08-21 01:18:05 +0200456 struct misdn_line *mline = line->driver_data;
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +0200457 int ts, ret;
458
459 /* TS0 is CRC4, don't need any fd for it */
460 for (ts = 1; ts < NUM_E1_TS; ts++) {
461 unsigned int idx = ts-1;
462 struct e1inp_ts *e1i_ts = &line->ts[idx];
463 struct osmo_fd *bfd = &e1i_ts->driver.misdn.fd;
464 struct sockaddr_mISDN addr;
465
466 bfd->data = line;
467 bfd->priv_nr = ts;
468 bfd->cb = misdn_fd_cb;
469
470 switch (e1i_ts->type) {
471 case E1INP_TS_TYPE_NONE:
472 continue;
473 break;
474 case E1INP_TS_TYPE_SIGN:
Harald Weltece307b42011-08-21 01:18:05 +0200475 if (mline->use_userspace_lapd)
476 bfd->fd = socket(PF_ISDN, SOCK_DGRAM, ISDN_P_B_HDLC);
477 else
478 bfd->fd = socket(PF_ISDN, SOCK_DGRAM, ISDN_P_LAPD_NT);
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +0200479 bfd->when = BSC_FD_READ;
480 break;
481 case E1INP_TS_TYPE_TRAU:
482 bfd->fd = socket(PF_ISDN, SOCK_DGRAM, ISDN_P_B_RAW);
483 /* We never include the mISDN B-Channel FD into the
484 * writeset, since it doesn't support poll() based
485 * write flow control */
486 bfd->when = BSC_FD_READ;
487 break;
488 }
489
490 if (bfd->fd < 0) {
491 fprintf(stderr, "%s could not open socket %s\n",
492 __func__, strerror(errno));
493 return bfd->fd;
494 }
495
496 memset(&addr, 0, sizeof(addr));
497 addr.family = AF_ISDN;
498 addr.dev = line->num;
499 switch (e1i_ts->type) {
500 case E1INP_TS_TYPE_SIGN:
Harald Weltece307b42011-08-21 01:18:05 +0200501 if (mline->use_userspace_lapd) {
502 addr.channel = ts;
503 e1i_ts->lapd = lapd_instance_alloc(1, misdn_write_msg, bfd);
504 } else {
505 addr.channel = 0;
506 /* SAPI not supported yet in kernel */
507 //addr.sapi = e1inp_ts->sign.sapi;
508 addr.sapi = 0;
509 addr.tei = GROUP_TEI;
510 }
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +0200511 break;
512 case E1INP_TS_TYPE_TRAU:
513 addr.channel = ts;
514 break;
515 default:
Harald Weltecc2241b2011-07-19 16:06:06 +0200516 DEBUGP(DLMI, "unsupported E1 TS type: %u\n",
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +0200517 e1i_ts->type);
518 break;
519 }
520
521 ret = bind(bfd->fd, (struct sockaddr *) &addr, sizeof(addr));
522 if (ret < 0) {
523 fprintf(stderr, "could not bind l2 socket %s\n",
524 strerror(errno));
525 return -EIO;
526 }
527
528 if (e1i_ts->type == E1INP_TS_TYPE_SIGN) {
Harald Weltece307b42011-08-21 01:18:05 +0200529 if (!mline->use_userspace_lapd) {
530 ret = ioctl(bfd->fd, IMCLEAR_L2, &release_l2);
531 if (ret < 0) {
532 fprintf(stderr, "could not send IOCTL IMCLEAN_L2 %s\n", strerror(errno));
533 return -EIO;
534 }
535 } else
536 activate_bchan(line, ts, 1);
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +0200537 }
538
539 /* FIXME: only activate B-Channels once we start to
540 * use them to conserve CPU power */
541 if (e1i_ts->type == E1INP_TS_TYPE_TRAU)
542 activate_bchan(line, ts, 1);
543
544 ret = osmo_fd_register(bfd);
545 if (ret < 0) {
546 fprintf(stderr, "could not register FD: %s\n",
547 strerror(ret));
548 return ret;
549 }
550 }
551
552 return 0;
553}
554
Harald Weltece307b42011-08-21 01:18:05 +0200555static int _mi_e1_line_update(struct e1inp_line *line)
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +0200556{
557 struct mISDN_devinfo devinfo;
558 int sk, ret, cnt;
559
Harald Weltece307b42011-08-21 01:18:05 +0200560 if (line->driver != &misdn_driver &&
561 line->driver != &misdn_lapd_driver)
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +0200562 return -EINVAL;
563
564 /* open the ISDN card device */
565 sk = socket(PF_ISDN, SOCK_RAW, ISDN_P_BASE);
566 if (sk < 0) {
567 fprintf(stderr, "%s could not open socket %s\n",
568 __func__, strerror(errno));
569 return sk;
570 }
571
572 ret = ioctl(sk, IMGETCOUNT, &cnt);
573 if (ret) {
574 fprintf(stderr, "%s error getting interf count: %s\n",
575 __func__, strerror(errno));
576 close(sk);
577 return -ENODEV;
578 }
Harald Weltecc2241b2011-07-19 16:06:06 +0200579 //DEBUGP(DLMI,"%d device%s found\n", cnt, (cnt==1)?"":"s");
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +0200580 printf("%d device%s found\n", cnt, (cnt==1)?"":"s");
581#if 1
582 devinfo.id = line->num;
583 ret = ioctl(sk, IMGETDEVINFO, &devinfo);
584 if (ret < 0) {
585 fprintf(stdout, "error getting info for device %d: %s\n",
586 line->num, strerror(errno));
587 return -ENODEV;
588 }
589 fprintf(stdout, " id: %d\n", devinfo.id);
590 fprintf(stdout, " Dprotocols: %08x\n", devinfo.Dprotocols);
591 fprintf(stdout, " Bprotocols: %08x\n", devinfo.Bprotocols);
592 fprintf(stdout, " protocol: %d\n", devinfo.protocol);
593 fprintf(stdout, " nrbchan: %d\n", devinfo.nrbchan);
594 fprintf(stdout, " name: %s\n", devinfo.name);
595#endif
596
597 if (!(devinfo.Dprotocols & (1 << ISDN_P_NT_E1))) {
598 fprintf(stderr, "error: card is not of type E1 (NT-mode)\n");
599 return -EINVAL;
600 }
601
602 ret = mi_e1_setup(line, 1);
603 if (ret)
604 return ret;
605
606 return 0;
607}
608
Harald Weltece307b42011-08-21 01:18:05 +0200609static int mi_e1_line_update(struct e1inp_line *line)
610{
611 struct misdn_line *ml;
612
613 if (!line->driver_data)
614 line->driver_data = talloc_zero(line, struct misdn_line);
615
616 ml = line->driver_data;
617 ml->use_userspace_lapd = 0;
618
619 return _mi_e1_line_update(line);
620}
621
622static int mi_e1_line_update_lapd(struct e1inp_line *line)
623{
624 struct misdn_line *ml;
625
626 if (!line->driver_data)
627 line->driver_data = talloc_zero(line, struct misdn_line);
628
629 ml = line->driver_data;
630 ml->use_userspace_lapd = 1;
631
632 return _mi_e1_line_update(line);
633}
634
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +0200635void e1inp_misdn_init(void)
636{
637 /* register the driver with the core */
638 e1inp_driver_register(&misdn_driver);
Harald Weltece307b42011-08-21 01:18:05 +0200639 e1inp_driver_register(&misdn_lapd_driver);
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +0200640}