laforge has submitted this change. ( https://gerrit.osmocom.org/c/libosmo-abis/+/31296 )
Change subject: Rework mi_e1_line_update() and some of its sub routines ......................................................................
Rework mi_e1_line_update() and some of its sub routines
Close file descriptor and free lapd resources, if time slot type changes or if it is released. Also, reset local states.
Change-Id: Iab0776fce6921661b39e9e53376cf01a80bcd42c --- M src/input/misdn.c 1 file changed, 60 insertions(+), 21 deletions(-)
Approvals: Jenkins Builder: Verified laforge: Looks good to me, approved
diff --git a/src/input/misdn.c b/src/input/misdn.c index c682392..8f04567 100644 --- a/src/input/misdn.c +++ b/src/input/misdn.c @@ -71,6 +71,7 @@ struct misdn_line { int use_userspace_lapd; int unconfirmed_ts[NUM_E1_TS]; + enum e1inp_ts_type type_ts[NUM_E1_TS]; int dummy_dchannel; int los, ais, rai; }; @@ -761,12 +762,18 @@ struct misdn_line *mline = line->driver_data; int ts, ret;
- mline->dummy_dchannel = -1; - if (mline->use_userspace_lapd) { + /* check if sign type is used */ + for (ts = 1; ts < line->num_ts; ts++) { + unsigned int idx = ts - 1; + struct e1inp_ts *e1i_ts = &line->ts[idx]; + if (e1i_ts->type == E1INP_TS_TYPE_SIGN) + break; + } + if (ts < line->num_ts && mline->use_userspace_lapd) { /* Open dummy d-channel in order to use b-channels. * Also it is required to define the mode. */ - if (mline->dummy_dchannel < 0) { + if (mline->dummy_dchannel <= 0) { struct sockaddr_mISDN addr;
mline->dummy_dchannel = socket(PF_ISDN, SOCK_DGRAM, @@ -788,50 +795,86 @@ return -EIO; } } + } else { + /* close dummy d-channel */ + if (mline->dummy_dchannel > 0) { + close(mline->dummy_dchannel); + mline->dummy_dchannel = -1; + } }
+ LOGPIL(line, DLINP, LOGL_NOTICE, "Line update %d %d %d\n", line->num, line->port_nr, line->num_ts); + /* TS0 is CRC4, don't need any fd for it */ - for (ts = 1; ts < NUM_E1_TS; ts++) { - unsigned int idx = ts-1; + for (ts = 1; ts < line->num_ts; ts++) { + unsigned int idx = ts - 1; struct e1inp_ts *e1i_ts = &line->ts[idx]; struct osmo_fd *bfd = &e1i_ts->driver.misdn.fd; struct sockaddr_mISDN addr;
+ /* no change in type */ + if (mline->type_ts[idx] == e1i_ts->type) + continue; + + LOGPIL(line, DLINP, LOGL_INFO, "Time slot %d changes from type %s to type %s\n", ts, + e1inp_tstype_name(mline->type_ts[idx]), e1inp_tstype_name(e1i_ts->type)); + + /* unregister FD if it was already registered */ + if (bfd->list.next && bfd->list.next != LLIST_POISON1) + osmo_fd_unregister(bfd); + + /* close/release LAPD instance, if any */ + if (e1i_ts->lapd) { + lapd_instance_free(e1i_ts->lapd); + e1i_ts->lapd = NULL; + } + + /* close old file descriptor */ + if (bfd->fd) { + close(bfd->fd); + bfd->fd = 0; + } + + /* clear 'unconfirmed' state */ + mline->unconfirmed_ts[idx] = 0; + + /* set new type */ + mline->type_ts[idx] = e1i_ts->type; + switch (e1i_ts->type) { case E1INP_TS_TYPE_NONE: + /* keep closed */ continue; - break; case E1INP_TS_TYPE_HDLC: + /* open hdlc socket */ /* TS 16 is the D-channel, so we use D-channel proto */ bfd->fd = socket(PF_ISDN, SOCK_DGRAM, (ts == 16) ? ISDN_P_NT_E1 : ISDN_P_B_HDLC); - bfd->when = OSMO_FD_READ; break; case E1INP_TS_TYPE_SIGN: + /* open and allocate user space lapd, if required */ if (mline->use_userspace_lapd) bfd->fd = socket(PF_ISDN, SOCK_DGRAM, ISDN_P_B_HDLC); else bfd->fd = socket(PF_ISDN, SOCK_DGRAM, ISDN_P_LAPD_NT); - bfd->when = OSMO_FD_READ; break; case E1INP_TS_TYPE_TRAU: case E1INP_TS_TYPE_I460: case E1INP_TS_TYPE_RAW: + /* open raw socket */ bfd->fd = socket(PF_ISDN, SOCK_DGRAM, ISDN_P_B_RAW); - /* We never include the mISDN B-Channel FD into the - * writeset, since it doesn't support poll() based - * write flow control */ - bfd->when = OSMO_FD_READ; break; }
+ /* failed to open? */ if (bfd->fd < 0) { LOGPITS(e1i_ts, DLMI, LOGL_ERROR, "could not open socket: %s\n", strerror(errno)); return bfd->fd; }
+ /* configure mISDN socket, also add user space lapd, if enabled */ memset(&addr, 0, sizeof(addr)); addr.family = AF_ISDN; addr.dev = line->port_nr; @@ -863,6 +906,7 @@ break; }
+ /* bind mISDN socket */ ret = bind(bfd->fd, (struct sockaddr *) &addr, sizeof(addr)); if (ret < 0) { LOGPITS(e1i_ts, DLMI, LOGL_ERROR, "could not bind l2 socket %s\n", @@ -870,6 +914,7 @@ return -EIO; }
+ /* release L2 in case of kernel space lapd, activate b-channel in other cases */ if (e1i_ts->type == E1INP_TS_TYPE_SIGN) { if (!mline->use_userspace_lapd) { ret = ioctl(bfd->fd, IMCLEAR_L2, &release_l2); @@ -880,17 +925,11 @@ } } else activate_bchan(line, ts, 1); - } - - /* FIXME: only activate B-Channels once we start to - * use them to conserve CPU power */ - if (e1i_ts->type == E1INP_TS_TYPE_HDLC - || e1i_ts->type == E1INP_TS_TYPE_RAW - || e1i_ts->type == E1INP_TS_TYPE_TRAU) + } else activate_bchan(line, ts, 1);
- osmo_fd_setup(bfd, bfd->fd, bfd->when, misdn_fd_cb, line, ts); - + /* register file descriptor with read set enabled */ + osmo_fd_setup(bfd, bfd->fd, OSMO_FD_READ, misdn_fd_cb, line, ts); ret = osmo_fd_register(bfd); if (ret < 0) { LOGPITS(e1i_ts, DLINP, LOGL_ERROR, "could not register FD: %s\n", strerror(ret));