Ticket #90: 0003-TS-07.10-multiplexing.patch

File 0003-TS-07.10-multiplexing.patch, 31.7 KB (added by balrogg@…, 12 years ago)

TS 07.10 multiplexing (incomplete).

  • include/gsmd/atcmd.h

    From a2863463efe573119e6b58df57ed7c0b6ad000bc Mon Sep 17 00:00:00 2001
    From: Andrzej Zaborowski <balrog@zabor.org>
    Date: Sat, 4 Aug 2007 23:36:43 +0200
    Subject: [PATCH] TS 07.10 multiplexing.
    
    ---
     include/gsmd/atcmd.h            |    4 +-
     include/gsmd/gsmd.h             |    2 +
     include/gsmd/uart.h             |   13 +
     include/gsmd/usock.h            |    7 +
     include/libgsmd/misc.h          |    3 +
     src/gsmd/Makefile.am            |    2 +-
     src/gsmd/atcmd.c                |   27 +-
     src/gsmd/gsmd.c                 |    4 +-
     src/gsmd/ts0710.c               |  797 +++++++++++++++++++++++++++++++++++++++
     src/gsmd/usock.c                |   98 +++++
     src/libgsmd/Makefile.am         |    2 +-
     src/libgsmd/libgsmd_multiplex.c |   36 ++
     src/util/shell.c                |    6 +
     13 files changed, 989 insertions(+), 12 deletions(-)
     create mode 100644 src/gsmd/ts0710.c
     create mode 100644 src/libgsmd/libgsmd_multiplex.c
    
    diff --git a/include/gsmd/atcmd.h b/include/gsmd/atcmd.h
    index a1af6a0..01d354e 100644
    a b typedef int atcmd_cb_t(struct gsmd_atcmd *cmd, void *ctx, char *resp); 
    99 
    1010extern struct gsmd_atcmd *atcmd_fill(const char *cmd, int rlen, atcmd_cb_t *cb, void *ctx, u_int16_t id); 
    1111extern int atcmd_submit(struct gsmd *g, struct gsmd_atcmd *cmd); 
    12 extern int atcmd_init(struct gsmd *g, struct gsmd_port *port); 
    13 extern void atcmd_drain(int fd); 
     12extern int atcmd_init(struct gsmd *g); 
     13extern void atcmd_set_port(struct gsmd *g, struct gsmd_port *port); 
    1414 
    1515#endif /* __GSMD__ */ 
    1616 
  • include/gsmd/gsmd.h

    diff --git a/include/gsmd/gsmd.h b/include/gsmd/gsmd.h
    index d8d293e..97011c0 100644
    a b struct gsmd { 
    8282        unsigned int mlbuf_len; 
    8383        int mlunsolicited; 
    8484        int clear_to_send; 
     85 
     86        struct ts0710_muxer *muxer; 
    8587}; 
    8688 
    8789struct gsmd_user { 
  • include/gsmd/uart.h

    diff --git a/include/gsmd/uart.h b/include/gsmd/uart.h
    index a006fa7..1f9df4f 100644
    a b struct gsmd_port { 
    1111        void *newdata_opaque; 
    1212}; 
    1313 
     14enum mux_event { 
     15        TS0710_CONNECTED, 
     16        TS0710_DISCONNECTED, 
     17}; 
     18 
     19struct ts0710_muxer; 
     20extern struct ts0710_muxer *mux_init(struct gsmd_port *uart, int advanced, 
     21                void (*event_cb)(enum mux_event ev, void *opaque), 
     22                void *event_opaque); 
     23extern struct gsmd_port *mux_dlc_open(struct ts0710_muxer *muxer, int dlci, 
     24                void (*event_cb)(enum mux_event ev, void *opaque), 
     25                void *event_opaque); 
     26 
    1427struct gsmd_uart { 
    1528        struct gsmd_port port; 
    1629        struct gsmd_fd gfd; 
  • include/gsmd/usock.h

    diff --git a/include/gsmd/usock.h b/include/gsmd/usock.h
    index c920480..bbc2b53 100644
    a b enum gsmd_msg_type { 
    2424        GSMD_MSG_PIN            = 8, 
    2525        GSMD_MSG_SMS            = 9, 
    2626        GSMD_MSG_CB             = 10, 
     27        GSMD_MSG_MULTIPLEX      = 11, 
    2728        __NUM_GSMD_MSGS 
    2829}; 
    2930 
    enum gsmd_msg_cb { 
    6263        GSMD_CB_UNSUBSCRIBE     = 2, 
    6364}; 
    6465 
     66enum gsmd_msg_multiplex { 
     67        GSMD_MULTIPLEX_ON       = 1, 
     68        GSMD_MULTIPLEX_OFF      = 2, 
     69        GSMD_MULTIPLEX_NEW_CH   = 3, 
     70}; 
     71 
    6572enum gsmd_msg_network { 
    6673        GSMD_NETWORK_REGISTER   = 1, 
    6774        GSMD_NETWORK_SIGQ_GET   = 2, 
  • include/libgsmd/misc.h

    diff --git a/include/libgsmd/misc.h b/include/libgsmd/misc.h
    index 8fa1ba6..5115e52 100644
    a b extern int lgsm_get_subscriber_num(struct lgsm_handle *lh); 
    7777/* GPRS related functions */ 
    7878/* TBD */ 
    7979 
     80/* TS07.10 Multiplexing */ 
     81extern int lgsm_mux_on(struct lgsm_handle *lh); 
     82extern int lgsm_mux_off(struct lgsm_handle *lh); 
    8083 
    8184#endif 
  • src/gsmd/Makefile.am

    diff --git a/src/gsmd/Makefile.am b/src/gsmd/Makefile.am
    index 3c71001..1ed659a 100644
    a b sbin_PROGRAMS = gsmd 
    77gsmd_CFLAGS = -D PLUGINDIR=\"$(plugindir)\" 
    88gsmd_SOURCES = gsmd.c atcmd.c select.c machine.c vendor.c unsolicited.c log.c \ 
    99               usock.c talloc.c timer.c operator_cache.c ext_response.c \ 
    10                sms_cb.c sms_pdu.c uart.c 
     10               sms_cb.c sms_pdu.c uart.c ts0710.c 
    1111gsmd_LDADD = -ldl 
    1212gsmd_LDFLAGS = -Wl,--export-dynamic 
    1313 
  • src/gsmd/atcmd.c

    diff --git a/src/gsmd/atcmd.c b/src/gsmd/atcmd.c
    index 947aabb..7fa7195 100644
    a b static void atcmd_wake_queue(struct gsmd *g) 
    185185        char *cr; 
    186186 
    187187        /* write pending commands to UART */ 
    188         while (g->interpreter_ready && g->clear_to_send) { 
     188        while (g->interpreter_ready && g->clear_to_send && 
     189                        !llist_empty(&g->pending_atcmds)) { 
    189190                struct gsmd_atcmd *pos, *pos2; 
    190191                llist_for_each_entry_safe(pos, pos2, &g->pending_atcmds, list) { 
    191192                        cr = strchr(pos->cur, '\n'); 
    int atcmd_submit(struct gsmd *g, struct gsmd_atcmd *cmd) 
    535536        return 0; 
    536537} 
    537538 
     539void atcmd_set_port(struct gsmd *g, struct gsmd_port *port) 
     540{ 
     541        if (!port) { 
     542                g->clear_to_send = 0; 
     543                return; 
     544        } 
     545 
     546        port->newdata_opaque = g; 
     547        port->newdata_cb = atcmd_newdata_cb; 
     548 
     549        g->llp.port = port; 
     550        g->clear_to_send = 1; 
     551        atcmd_wake_queue(g); 
     552} 
     553 
    538554/* init atcmd parser */ 
    539 int atcmd_init(struct gsmd *g, struct gsmd_port *port) 
     555int atcmd_init(struct gsmd *g) 
    540556{ 
    541557        __atcmd_ctx = talloc_named_const(gsmd_tallocs, 1, "atcmds"); 
    542558 
    int atcmd_init(struct gsmd *g, struct gsmd_port *port) 
    547563 
    548564        g->mlbuf_len = 0; 
    549565        g->mlunsolicited = 0; 
    550         g->clear_to_send = 1; 
     566        g->clear_to_send = 0; 
    551567 
    552         g->llp.port = port; 
     568        g->llp.port = 0; 
    553569        g->llp.cur = g->llp.buf; 
    554570        g->llp.len = sizeof(g->llp.buf); 
    555571        g->llp.cb = &ml_parse; 
    int atcmd_init(struct gsmd *g, struct gsmd_port *port) 
    557573        g->llp.ctx = g; 
    558574        g->llp.flags = LGSM_ATCMD_F_EXTENDED; 
    559575 
    560         port->newdata_opaque = g; 
    561         port->newdata_cb = atcmd_newdata_cb; 
    562  
    563576        return 0; 
    564577} 
  • src/gsmd/gsmd.c

    diff --git a/src/gsmd/gsmd.c b/src/gsmd/gsmd.c
    index 1f71788..f185b76 100644
    a b int main(int argc, char **argv) 
    414414                exit(1); 
    415415        } 
    416416 
    417         if (atcmd_init(&g, &g.uart.port) < 0) { 
     417        if (atcmd_init(&g) < 0) { 
    418418                fprintf(stderr, "can't initialize AT parser\n"); 
    419419                exit(1); 
    420420        } 
     421        atcmd_set_port(&g, &g.uart.port); 
     422 
    421423        uart_drain(fd); 
    422424 
    423425        if (usock_init(&g) < 0) { 
  • new file src/gsmd/ts0710.c

    diff --git a/src/gsmd/ts0710.c b/src/gsmd/ts0710.c
    new file mode 100644
    index 0000000..96d5bbf
    - +  
     1/* 
     2 * G3 TS 07.10 multiplexing. 
     3 * 
     4 * Copyright (C) 2007 OpenMoko, Inc. 
     5 * Written by Andrzej Zaborowski <andrew@openedhand.com> 
     6 * 
     7 * This program is free software; you can redistribute it and/or 
     8 * modify it under the terms of the GNU General Public License as 
     9 * published by the Free Software Foundation; either version 2 of 
     10 * the License, or (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 
     18 * along with this program; if not, write to the Free Software 
     19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, 
     20 * MA 02111-1307 USA 
     21 */ 
     22 
     23#include <string.h> 
     24#include <errno.h> 
     25 
     26#include "gsmd.h" 
     27 
     28#include <gsmd/gsmd.h> 
     29#include <gsmd/talloc.h> 
     30 
     31#define MUX_MAX_DLCS    64 
     32 
     33struct mux_dlc { 
     34        enum { 
     35                mux_dlc_waiting_for_ua, 
     36                /* TODO: mux_dlc_negotiating, */ 
     37                mux_dlc_established, 
     38                /* Switching to other states closes the DLC so not listed.  */ 
     39        } state; 
     40        struct gsmd_port port; 
     41        struct ts0710_muxer *muxer; 
     42        int dlci; 
     43        void (*event_cb)(enum mux_event ev, void *opaque); 
     44        void *event_opaque; 
     45 
     46        int flow_ctrl; 
     47        int initiator; 
     48}; 
     49 
     50struct ts0710_muxer { 
     51        struct gsmd_port *port; 
     52        enum { 
     53                mux_option_basic, 
     54                mux_option_advanced, 
     55        } option; 
     56        int max_frame; 
     57        void (*event_cb)(enum mux_event ev, void *opaque); 
     58        void *event_opaque; 
     59 
     60        enum { 
     61                mux_state_connecting, 
     62                /* TODO: mux_state_negotiating, */ 
     63                mux_state_connected, 
     64                /* Switching to other states effectively signifies 
     65                 * a muxer close-down, so we will never see them here. 
     66                 * The multiplexer's lifetime begins with a request to 
     67                 * start multiplexing and terminates with either: 
     68                 *   determining an unsuccessful start, 
     69                 *   close-down request after a successfull start, or 
     70                 *   gsmd exiting (regardless of muxer state). 
     71                 */ 
     72        } state; 
     73 
     74        struct mux_dlc dlc0; 
     75        struct mux_dlc *dlc[MUX_MAX_DLCS]; 
     76 
     77        u_int8_t buf[2048]; 
     78        int buflen; 
     79}; 
     80 
     81enum mux_frametype { 
     82        MUX_SABM        = 0x2f, 
     83        MUX_UA          = 0x63, 
     84        MUX_DM          = 0x0f, 
     85        MUX_DISC        = 0x43, 
     86        MUX_UIH         = 0xef, 
     87        MUX_UI          = 0x03, 
     88}; 
     89 
     90/* See TS 07.10's Section 5.2.1.6 */ 
     91static u_int8_t fcs_table[0x100]; 
     92static u_int8_t fcs_init(void) 
     93{ 
     94        int i, bit; 
     95        u_int8_t reg, nreg; 
     96 
     97        for (i = 0; i < 0x100; i ++) { 
     98                for (reg = bit = 0; bit < 8; bit ++, reg = nreg) { 
     99                        nreg = reg >> 1; 
     100                        if (((i >> bit) ^ reg) & 1) 
     101                                nreg ^= 0xe0;   /* x^8 + x^2 + x + 1 */ 
     102                } 
     103 
     104                fcs_table[i] = reg; 
     105        } 
     106} 
     107 
     108/* Computes the FCS checksum for a chunk of data.  */ 
     109static u_int8_t mux_fcs_compute(const u_int8_t payload[], int len) 
     110{ 
     111        u_int8_t gen_reg; 
     112 
     113        gen_reg = ~0; 
     114        while (len --) 
     115                gen_reg = fcs_table[gen_reg ^ *(payload ++)]; 
     116 
     117        return ~gen_reg; 
     118} 
     119 
     120/* Returns 1 if the given chunk of data has a correct FCS appended.  */ 
     121static int mux_fcs_check(const u_int8_t payload[], int len) 
     122{ 
     123        return mux_fcs_compute(payload, len + 1) == 0xcf; 
     124} 
     125 
     126#define MUX_EA                  1 
     127#define MUX_BASIC_FLAG_SEQ      0xf9 
     128#define MUX_ADVANCED_FLAG_SEQ   0x7e 
     129#define MUX_CONTROL_ESCAPE      0x7d 
     130 
     131static int mux_frame_escape(u_int8_t *frame, int len) 
     132{ 
     133        int chunk; 
     134        u_int8_t framebuf[2048]; 
     135        u_int8_t *src = frame; 
     136        u_int8_t *dest = framebuf; 
     137        u_int8_t *end = frame + len; 
     138        u_int8_t *esc = memchr(src, MUX_CONTROL_ESCAPE, len) ?: end; 
     139        u_int8_t *flag = memchr(src, MUX_ADVANCED_FLAG_SEQ, len) ?: end; 
     140 
     141        while ((chunk = (esc < flag ? esc : flag) - src) < len) { 
     142                len -= chunk + 1; 
     143 
     144                dest = memcpy(dest, src, chunk) + chunk; 
     145                src += chunk; 
     146                *(dest ++) = MUX_CONTROL_ESCAPE; 
     147                *(dest ++) = *(src ++) ^ (1 << 5); 
     148                if (esc < flag) 
     149                        esc = memchr(src, MUX_CONTROL_ESCAPE, len) ?: end; 
     150                else 
     151                        flag = memchr(src, MUX_ADVANCED_FLAG_SEQ, len) ?: end; 
     152        } 
     153        len += memcpy(dest, src, len) - (void *) framebuf; 
     154        memcpy(frame, framebuf, len); 
     155        return len; 
     156} 
     157 
     158/* See TS 07.10's Section 5.2.1 */ 
     159static int mux_send_frame(struct mux_dlc *dlc, int cr, 
     160                enum mux_frametype frametype, const u_int8_t data[], int len) 
     161{ 
     162        struct gsmd_port *port = dlc->muxer->port; 
     163        u_int8_t framebuf[2048]; 
     164        int pos = 0; 
     165        int pf = 1; 
     166 
     167        if (frametype == MUX_UIH || frametype == MUX_UI) 
     168                pf = 0; 
     169 
     170        if (dlc->muxer->option == mux_option_basic) 
     171                framebuf[pos ++] = MUX_BASIC_FLAG_SEQ; 
     172        else 
     173                framebuf[pos ++] = MUX_ADVANCED_FLAG_SEQ; 
     174 
     175        /* Address field.  */ 
     176        framebuf[pos ++] = MUX_EA | (cr << 1) | (dlc->dlci << 2); 
     177 
     178        /* Control field.  */ 
     179        framebuf[pos ++] = frametype | (pf << 4); 
     180 
     181        /* Length indicator.  */ 
     182        if (dlc->muxer->option == mux_option_basic) { 
     183                if (len & ~0x7f) { 
     184                        framebuf[pos ++] = 0 | ((len & 0x7f) << 1); 
     185                        framebuf[pos ++] = len >> 7; 
     186                } else 
     187                        framebuf[pos ++] = 1 | (len << 1); 
     188        } 
     189 
     190        /* Information field.  */ 
     191        if (len) 
     192                memcpy(&framebuf[pos], data, len); 
     193        pos += len; 
     194 
     195        /* FCS field.  */ 
     196        if (frametype == MUX_UIH) 
     197                framebuf[pos] = mux_fcs_compute(framebuf + 1, pos - 1 - len); 
     198        else 
     199                framebuf[pos] = mux_fcs_compute(framebuf + 1, pos - 1); 
     200        pos ++; 
     201 
     202        if (dlc->muxer->option == mux_option_advanced) 
     203                pos = mux_frame_escape(framebuf + 1, pos - 1) + 1; 
     204 
     205        if (dlc->muxer->option == mux_option_basic) 
     206                framebuf[pos ++] = MUX_BASIC_FLAG_SEQ; 
     207        else 
     208                framebuf[pos ++] = MUX_ADVANCED_FLAG_SEQ; 
     209 
     210        if (port->write(port, (const char *) framebuf, pos) < pos) 
     211                return -EIO; 
     212        else 
     213                return 0; 
     214} 
     215 
     216enum mux_iframetype { 
     217        MUX_FRAMETYPE_UIH       = 0, 
     218        MUX_FRAMETYPE_UI        = 1, 
     219        MUX_FRAMETYPE_I         = 2, 
     220}; 
     221 
     222static int mux_send_sabm(struct mux_dlc *dlc) 
     223{ 
     224        return mux_send_frame(dlc, dlc->initiator, MUX_SABM, 0, 0); 
     225} 
     226 
     227static int mux_send_ua(struct mux_dlc *dlc) 
     228{ 
     229        return mux_send_frame(dlc, !dlc->initiator, MUX_UA, 0, 0); 
     230} 
     231 
     232static int mux_send_dm(struct mux_dlc *dlc) 
     233{ 
     234        return mux_send_frame(dlc, !dlc->initiator, MUX_DM, 0, 0); 
     235} 
     236 
     237static int mux_send_disc(struct mux_dlc *dlc) 
     238{ 
     239        return mux_send_frame(dlc, dlc->initiator, MUX_DISC, 0, 0); 
     240} 
     241 
     242static int mux_send_uih(struct mux_dlc *dlc, const u_int8_t data[], int len) 
     243{ 
     244        return mux_send_frame(dlc, dlc->initiator, MUX_UIH, data, len); 
     245} 
     246 
     247static int mux_send_ui(struct mux_dlc *dlc, const u_int8_t data[], int len) 
     248{ 
     249        return mux_send_frame(dlc, dlc->initiator, MUX_UI, data, len); 
     250} 
     251 
     252#if 0 /* FIXME */ 
     253/* MCC commands */ 
     254#define MUX_PN          0x20 
     255#define MUX_PSC         0x10 
     256#define MUX_CLD         0x30 
     257#define MUX_TEST        0x08 
     258#define MUX_FCON        0x28 
     259#define MUX_FCOF        0x18 
     260#define MUX_MSC         0x38 
     261#define MUX_NSC         0x04 
     262#define MUX_RPN         0x24 
     263#define MUX_RLS         0x14 
     264#define MUX_SNC         0x34 
     265 
     266/* Control channel message: DLC parameter negotiation (5.4.6.3.1) */ 
     267static int mux_send_pn(struct ts0710_muxer *muxer, int dlci, 
     268                enum imux_frametype i, enum mux_conv_layer cl, int p, 
     269                int t, int n, int na, int k) 
     270{ 
     271        framebuf[pos ++] = 1 | (cr << 1) | (MUX_PN << 2); 
     272        framebuf[pos ++] = dlci; 
     273        framebuf[pos ++] = i | (cl << 4); 
     274        framebuf[pos ++] = p; 
     275        framebuf[pos ++] = t; 
     276        framebuf[pos ++] = n & 0xff; 
     277        framebuf[pos ++] = n >> 8; 
     278        framebuf[pos ++] = na; 
     279        framebuf[pos ++] = k; 
     280} 
     281 
     282/* Control channel message: Power Saving Control (5.4.6.3.2) */ 
     283static int mux_send_psc(struct ts0710_muxer *muxer) 
     284{ 
     285        framebuf[pos ++] = 1 | (cr << 1) | (MUX_PSC << 2); 
     286} 
     287 
     288/* Control channel message: Multiplexer close down (5.4.6.3.3) */ 
     289static int mux_send_cld(struct ts0710_muxer *muxer) 
     290{ 
     291        framebuf[pos ++] = 1 | (cr << 1) | (MUX_CLD << 2); 
     292} 
     293 
     294/* Control channel message: Test Command (5.4.6.3.4) */ 
     295static int mux_send_test(struct ts0710_muxer *muxer, u_int8_t data[], int len) 
     296{ 
     297        framebuf[pos ++] = 1 | (cr << 1) | (MUX_TEST << 2); 
     298} 
     299 
     300/* Control channel message: Flow Control On Command (5.4.6.3.5) */ 
     301static int mux_send_fcon(struct ts0710_muxer *muxer) 
     302{ 
     303        framebuf[pos ++] = 1 | (cr << 1) | (MUX_FCON << 2); 
     304} 
     305 
     306/* Control channel message: Flow Control Off Command (5.4.6.3.6) */ 
     307static int mux_send_fcof(struct ts0710_muxer *muxer) 
     308{ 
     309        framebuf[pos ++] = 1 | (cr << 1) | (MUX_FCOF << 2); 
     310} 
     311 
     312/* Control channel message: Modem Status Command (5.4.6.3.7) */ 
     313static int mux_send_msc(struct ts0710_muxer *muxer, int dlci, int ea, int fc, 
     314                int rtc, int rtr, int ic, int dv) 
     315{ 
     316        framebuf[pos ++] = 1 | (cr << 1) | (MUX_MSC << 2); 
     317        framebuf[pos ++] = ea | 2 | (dlci << 2); 
     318        framebuf[pos ++] = ea | (fc << 1) | (rtc << 2) | (rtr << 3) | 
     319                (ic << 6) | (dv << 7); 
     320        /* break */ 
     321} 
     322 
     323/* Control channel message: Not Supported Command Response (5.4.6.3.8) */ 
     324static int mux_send_nsc(struct ts0710_muxer *muxer, int cmd) 
     325{ 
     326        framebuf[pos ++] = 1 | (cr << 1) | (MUX_NSC << 2); 
     327        framebuf[pos ++] = ea | (cmd << 1); 
     328} 
     329 
     330/* Control channel message: Remote Port Negotiation Command (5.4.6.3.9) */ 
     331static int mux_send_rpn(struct ts0710_muxer *muxer, int dlci, int baud, int d, 
     332                int s, int p, int pt, int flc, int xon, int xof, int pm) 
     333{ 
     334        framebuf[pos ++] = 1 | (cr << 1) | (MUX_RPN << 2); 
     335        framebuf[pos ++] = ea | 2 | (dlci << 2); 
     336        framebuf[pos ++] = baud; 
     337        framebuf[pos ++] = d | (s << 2) | (p << 3) | (pt << 4); 
     338        framebuf[pos ++] = flc; 
     339        framebuf[pos ++] = xon; 
     340        framebuf[pos ++] = xof; 
     341        framebuf[pos ++] = pm & 0xff; 
     342        framebuf[pos ++] = pm >> 8; 
     343} 
     344 
     345static int mux_send_rpn_req(struct ts0710_muxer *muxer, int dlci) 
     346{ 
     347        framebuf[pos ++] = 1 | (cr << 1) | (MUX_RPN << 2); 
     348        framebuf[pos ++] = ea | 2 | (dlci << 2); 
     349} 
     350 
     351/* Control channel message: Remote Line Status Command (5.4.6.3.10) */ 
     352static int mux_send_rls(struct ts0710_muxer *muxer, int dlci, int baud, int l) 
     353{ 
     354        framebuf[pos ++] = 1 | (cr << 1) | (MUX_RLS << 2); 
     355        framebuf[pos ++] = ea | cr | (dlci << 2); 
     356        framebuf[pos ++] = l; 
     357} 
     358 
     359/* Control channel message: Service Negotiation Command (5.4.6.3.11) */ 
     360static int mux_send_snc(struct ts0710_muxer *muxer, int dlci, int baud, 
     361                int data, int voice, int codec) 
     362{ 
     363        framebuf[pos ++] = 1 | (cr << 1) | (MUX_SNC << 2); 
     364        framebuf[pos ++] = ea | cr | (dlci << 2); 
     365        framebuf[pos ++] = ea | (data << 1) | (voice << 2); 
     366        if (codec >= 0) 
     367                framebuf[pos ++] = ea | (codec << 1); 
     368} 
     369 
     370static int mux_send_snc_req(struct ts0710_muxer *muxer, int dlci) 
     371{ 
     372        framebuf[pos ++] = 1 | (cr << 1) | (MUX_SNC << 2); 
     373        framebuf[pos ++] = ea | cr | (dlci << 2); 
     374} 
     375#endif 
     376 
     377static void mux_dlc_free(struct mux_dlc *dlc) 
     378{ 
     379        dlc->muxer->dlc[dlc->dlci] = 0; 
     380        /* TODO: notify anyone who might be using the DLC, destroy the PTY.. */ 
     381        talloc_free(dlc); 
     382} 
     383 
     384static void mux_free(struct ts0710_muxer *muxer) 
     385{ 
     386        int i; 
     387 
     388        for (i = 1; i < MUX_MAX_DLCS; i ++) 
     389                if (muxer->dlc[i]) 
     390                        mux_dlc_free(muxer->dlc[i]); 
     391} 
     392 
     393static int mux_frame_dequeue_basic(struct ts0710_muxer *muxer, u_int8_t *dest, 
     394                const u_int8_t *src, int len, int *cmd, int *pf, int *dlci, 
     395                int *cr) 
     396{ 
     397        int ea; 
     398        int dlen; 
     399 
     400        /* FIXME: size check */ 
     401        src = memcpy(muxer->buf + muxer->buflen, src, len); 
     402        muxer->buflen = len = muxer->buflen + len; 
     403 
     404        while (len && *src == MUX_BASIC_FLAG_SEQ) { 
     405                src ++; 
     406                len --; 
     407        } 
     408        if (len < 3) 
     409                return -EAGAIN; 
     410        /* Address Field (5.2.1.2) */ 
     411        ea = *src & 1; 
     412        *cr = (*src >> 1) & 1; 
     413        *dlci = *src >> 2; 
     414        src ++; 
     415        /* Control Field (5.2.1.3) */ 
     416        *cmd = *src & ~(1 << 4); 
     417        *pf = (*src >> 4) & 1; 
     418        src ++; 
     419        /* Lenght Indicator (5.2.1.5) */ 
     420        dlen = *src >> 1; 
     421        if (!(*src & 1)) { 
     422                src ++; 
     423                if (len < 4) 
     424                        return -EAGAIN; 
     425                dlen |= *src << 7; 
     426                len --; 
     427        } 
     428        len -= 3; 
     429        if (len < dlen) 
     430                return -EAGAIN; 
     431        src ++; 
     432 
     433        /* Information Field (5.2.1.4) */ 
     434        memcpy(dest, src, dlen); 
     435        src += dlen; 
     436        len -= dlen; 
     437 
     438        memmove(muxer->buf, src, len); 
     439        muxer->buflen = len; 
     440        if (!ea) { 
     441                gsmd_log(GSMD_NOTICE, "Unsupported frame with EA != 1, " 
     442                                "discarding\n"); 
     443                return -EAGAIN; 
     444        } 
     445        return dlen; 
     446} 
     447 
     448static int mux_frame_dequeue_advanced(struct ts0710_muxer *muxer, 
     449                u_int8_t *dest, const u_int8_t *src, int len, int *cmd, 
     450                int *pf, int *dlci, int *cr) 
     451{ 
     452        int ea, i, ret; 
     453        const u_int8_t *end, *ctrl; 
     454        u_int8_t header[2], *start = dest; 
     455 
     456        /* FIXME: size check */ 
     457        src = memcpy(muxer->buf + muxer->buflen, src, len); 
     458        muxer->buflen = len = muxer->buflen + len; 
     459 
     460        while (len && *src == MUX_ADVANCED_FLAG_SEQ) { 
     461                src ++; 
     462                len --; 
     463        } 
     464 
     465        end = memchr(src, MUX_ADVANCED_FLAG_SEQ, len); 
     466        if (!end) 
     467                return -EAGAIN; 
     468 
     469        for (i = 0; i < 2 && src < end; i ++, src ++) { 
     470                if (*src == MUX_CONTROL_ESCAPE) 
     471                        header[i] = (*++ src) ^ (1 << 5); 
     472                else 
     473                        header[i] = *src; 
     474        } 
     475        if (i < 2) { 
     476                ret = -EAGAIN; 
     477                goto out; 
     478        } 
     479 
     480        /* Address Field (5.2.1.2) */ 
     481        ea = header[0] & 1; 
     482        *cr = (header[0] >> 1) & 1; 
     483        *dlci = header[0] >> 2; 
     484        /* Control Field (5.2.1.3) */ 
     485        *cmd = header[1] & ~(1 << 4); 
     486        *pf = (header[1] >> 4) & 1; 
     487 
     488        /* Information Field (5.2.1.4) */ 
     489        while (src < end) { 
     490                ctrl = memchr(src, MUX_CONTROL_ESCAPE, end - src) ?: end; 
     491                dest = memcpy(dest, src, ctrl - src) + (ctrl - src); 
     492                src = ctrl; 
     493                if (src + 1 >= end) 
     494                        break; 
     495                src ++; 
     496                *(dest ++) = *(src ++) ^ (1 << 5); 
     497        } 
     498 
     499        if (src < end || !ea) { 
     500                gsmd_log(GSMD_NOTICE, "Invalid frame, discarding\n"); 
     501                ret = -EAGAIN; 
     502                goto out; 
     503        } 
     504 
     505        ret = dest - start; 
     506out: 
     507        muxer->buflen -= end + 1 - muxer->buf; 
     508        memmove(muxer->buf, end + 1, muxer->buflen); 
     509        return ret; 
     510} 
     511 
     512/* Called when new data comes in from the physical port */ 
     513static int mux_demux(void *opaque, const char *d, int len) 
     514{ 
     515        struct ts0710_muxer *muxer = (struct ts0710_muxer *) opaque; 
     516        u_int8_t framebuf[2048]; 
     517        int cmd, pf, dlci, cr, rc; 
     518        struct mux_dlc temp_dlc, *dlc; 
     519        const u_int8_t *data = (const u_int8_t *) d; 
     520 
     521        if (muxer->option == mux_option_basic) 
     522                len = mux_frame_dequeue_basic(muxer, framebuf, 
     523                                data, len, &cmd, &pf, &dlci, &cr); 
     524        else 
     525                len = mux_frame_dequeue_advanced(muxer, framebuf, 
     526                                data, len, &cmd, &pf, &dlci, &cr); 
     527 
     528        if (len < 0) 
     529                return 0; 
     530        /* FIXME: check if more frames can be dequeued and do it */ 
     531        /* FIXME: Check the FCS.  */ 
     532 
     533        dlc = muxer->dlc[dlci]; 
     534        if (!dlc) { 
     535                /* Make a temporary DLC through which a respnose can be sent 
     536                 * if the MS sent a command on a non-existent DLC.  */ 
     537                temp_dlc.dlci = dlci; 
     538                temp_dlc.initiator = 0; 
     539                temp_dlc.muxer = muxer; 
     540        } 
     541 
     542        switch (cmd) { 
     543        case MUX_SABM: 
     544                if (!pf) 
     545                        return; 
     546 
     547                if (dlc && dlc->dlci == 0) { 
     548                        mux_send_ua(dlc); 
     549                        if (muxer->state != mux_state_connected) { 
     550                                muxer->event_cb(TS0710_CONNECTED, 
     551                                                muxer->event_opaque); 
     552                                muxer->state = mux_state_connected; 
     553                        } 
     554                        break; 
     555                } else if (dlc) { 
     556                        if (dlc->state != mux_dlc_established) { 
     557                                /* TODO: send an event to DLC user, make pty */ 
     558                                dlc->state = mux_dlc_established; 
     559                        } 
     560                        mux_send_ua(dlc); 
     561                        break; 
     562                } 
     563 
     564                /* Reject any attempts of establishing DLCs by the MS.  */ 
     565                mux_send_dm(&temp_dlc); 
     566                gsmd_log(GSMD_NOTICE, "Strange, modem tried to establish " 
     567                                "a new DLC (%i)\n", temp_dlc.dlci); 
     568                break; 
     569 
     570        case MUX_UA: 
     571                if (!pf) 
     572                        return; 
     573 
     574                if (dlc && dlc->dlci == 0) { 
     575                        if (muxer->state != mux_state_connected) { 
     576                                muxer->state = mux_state_connected; 
     577                                muxer->event_cb(TS0710_CONNECTED, 
     578                                                muxer->event_opaque); 
     579                        } 
     580                        break; 
     581                } else if (dlc) { 
     582                        if (dlc->state == mux_dlc_waiting_for_ua) { 
     583                                /* TODO: acknowledge whoever requested 
     584                                 * the new DLC.  */ 
     585                                dlc->event_cb(TS0710_CONNECTED, 
     586                                                dlc->event_opaque); 
     587                                /* TODO: make a pty.  */ 
     588                                dlc->state = mux_dlc_established; 
     589                        } 
     590                        mux_send_ua(dlc); 
     591                        break; 
     592                } 
     593 
     594                gsmd_log(GSMD_NOTICE, "Stray UA on the DLC %i \n", 
     595                                temp_dlc.dlci); 
     596                break; 
     597 
     598        case MUX_DM: 
     599        case MUX_DISC: 
     600                if (dlc && cmd == MUX_DISC) 
     601                        mux_send_ua(dlc); 
     602 
     603                if (dlc && dlc->dlci == 0) { 
     604                        if (cmd == MUX_DISC) 
     605                                mux_send_ua(dlc); 
     606                        /* TODO: send an event through usock */ 
     607                        muxer->event_cb(TS0710_DISCONNECTED, 
     608                                        muxer->event_opaque); 
     609                        mux_free(muxer); 
     610                        break; 
     611                } else if (dlc) { 
     612                        if (dlc->state == mux_dlc_established) { 
     613                                /* TODO: destroy the pty.  */ 
     614                                dlc->event_cb(TS0710_DISCONNECTED, 
     615                                                dlc->event_opaque); 
     616                        } 
     617                        if (dlc->state == mux_dlc_waiting_for_ua) { 
     618                                /* TODO: acknowledge the failure to whoever 
     619                                 * requested the new DLC.  */ 
     620                                dlc->event_cb(TS0710_DISCONNECTED, 
     621                                                dlc->event_opaque); 
     622                        } 
     623                        mux_dlc_free(dlc); 
     624                        break; 
     625                } 
     626                /* Ignore.  */ 
     627                break; 
     628 
     629        case MUX_UIH: 
     630        case MUX_UI: 
     631                if (dlc->port.newdata_cb) { 
     632                        rc = dlc->port.newdata_cb(dlc->port.newdata_opaque, 
     633                                        (const char *) framebuf, len); 
     634                        if (rc < 0) 
     635                                return rc; 
     636                } 
     637                break; 
     638        } 
     639 
     640        return len; 
     641} 
     642 
     643static int mux_dlc_write(struct gsmd_port *port, const char *data, int len) 
     644{ 
     645        struct mux_dlc *dlc = (struct mux_dlc *) port; 
     646        int chunk, rc, sent = 0; 
     647 
     648        if (dlc->state != mux_dlc_established) 
     649                return -EIO; 
     650 
     651        while (len) { 
     652                chunk = dlc->muxer->max_frame > len ? 
     653                        len : dlc->muxer->max_frame; 
     654                rc = mux_send_uih(dlc, (const u_int8_t *) data, chunk); 
     655                if (rc < 0) 
     656                        return sent; 
     657                sent += chunk; 
     658                data += chunk; 
     659                len -= chunk; 
     660        } 
     661        return sent; 
     662} 
     663 
     664struct gsmd_port *mux_dlc_open(struct ts0710_muxer *muxer, int dlci, 
     665                void (*event_cb)(enum mux_event ev, void *opaque), 
     666                void *event_opaque) 
     667{ 
     668        struct mux_dlc *dlc; 
     669 
     670        if (dlci < 1 || dlci >= MUX_MAX_DLCS || 
     671                        muxer->state != mux_state_connected) 
     672                return 0; 
     673        if (muxer->dlc[dlci]) { 
     674                gsmd_log(GSMD_NOTICE, "DLC %i already opened\n", dlci); 
     675                return &muxer->dlc[dlci]->port; 
     676        } 
     677 
     678        dlc = talloc(gsmd_tallocs, struct mux_dlc); 
     679        dlc->dlci = dlci; 
     680        dlc->muxer = muxer; 
     681        dlc->event_cb = event_cb; 
     682        dlc->event_opaque = event_opaque; 
     683        dlc->flow_ctrl = 0; 
     684        dlc->port.write = mux_dlc_write; 
     685        dlc->state = mux_dlc_waiting_for_ua; 
     686 
     687        muxer->dlc[dlci] = dlc; 
     688 
     689        /* Request the establishment of the actual DLC.  */ 
     690        dlc->initiator = 1; 
     691        mux_send_sabm(dlc); 
     692        /* FIXME: setup a timeout timer */ 
     693 
     694        return &dlc->port; 
     695} 
     696 
     697int mux_dlc_close(struct mux_dlc *dlc) 
     698{ 
     699        /* Send a DLC Release.  */ 
     700        dlc->initiator = 1; 
     701        mux_send_disc(dlc); 
     702 
     703        mux_dlc_free(dlc); 
     704        return 0; 
     705} 
     706 
     707static inline int parse_value(const u_int8_t **data, int *len) 
     708{ 
     709        int i, val = 0; 
     710 
     711        for (i = 0; *len && !(**data & 1); i ++, (*len) --) 
     712                val |= (*((*data) ++) >> 1) << (i * 7); 
     713        if ((*len) --) 
     714                val |= (*((*data) ++) >> 1) << (i * 7); 
     715        return val; 
     716} 
     717 
     718/* DLC 0 is special because it's the first DLC opened, through which all 
     719 * multiplexer control commands go.  */ 
     720static int mux_dlc0_handledata(void *opaque, const char *d, int len) 
     721{ 
     722        int cr, type, dlen, i; 
     723        const u_int8_t *data = (const u_int8_t *) d; 
     724 
     725        /* Parse an MCC command (Type, Length, Value 1, Value 2, ...) */ 
     726        /* TODO: should also handle concatenated commands in a frame */ 
     727 
     728        /* Type */ 
     729        type = parse_value(&data, &len); 
     730        cr = type & 1; 
     731        type >>= 1; 
     732        if (len < 0) 
     733                goto too_short; 
     734 
     735        /* Length */ 
     736        dlen = parse_value(&data, &len); 
     737        if (len < 0) 
     738                goto too_short; 
     739 
     740        switch (type) { 
     741        default: 
     742                gsmd_log(GSMD_ERROR, "Unexpected MCC command type %02x\n", 
     743                                type); 
     744                return -EINVAL; 
     745        } 
     746 
     747        return 0; 
     748 
     749too_short: 
     750        gsmd_log(GSMD_ERROR, "MCC frame too short\n"); 
     751        return -EINVAL; 
     752} 
     753 
     754static struct mux_dlc *mux_dlc0_open(struct ts0710_muxer *muxer) 
     755{ 
     756        muxer->dlc[0] = &muxer->dlc0; 
     757        muxer->state = mux_state_connecting; 
     758        muxer->dlc0.port.write = mux_dlc_write; 
     759        muxer->dlc0.port.newdata_opaque = muxer; 
     760        muxer->dlc0.port.newdata_cb = mux_dlc0_handledata; 
     761        muxer->dlc0.muxer = muxer; 
     762 
     763        /* Request the establishment of the actual DLC.  */ 
     764        muxer->dlc0.initiator = 1; 
     765        mux_send_sabm(&muxer->dlc0); 
     766        /* FIXME: setup a timeout timer */ 
     767 
     768        return &muxer->dlc0; 
     769} 
     770 
     771struct ts0710_muxer *mux_init(struct gsmd_port *uart, int advanced, 
     772                void (*event_cb)(enum mux_event ev, void *opaque), 
     773                void *event_opaque) 
     774{ 
     775        struct ts0710_muxer *muxer = talloc(gsmd_tallocs, struct ts0710_muxer); 
     776 
     777        fcs_init(); 
     778 
     779        muxer->port = uart; 
     780        muxer->port->newdata_cb = mux_demux; 
     781        muxer->port->newdata_opaque = muxer; 
     782 
     783        muxer->event_cb = event_cb; 
     784        muxer->event_opaque = event_opaque; 
     785 
     786        memset(muxer->dlc, 0, sizeof(muxer->dlc)); 
     787        muxer->buflen = 0; 
     788 
     789        /* TODO: Query the capabilities with AT+CMUX first.  */ 
     790        muxer->option = advanced ? mux_option_advanced : mux_option_basic; 
     791        muxer->max_frame = 64; 
     792 
     793        mux_dlc0_open(muxer); 
     794        return muxer; 
     795} 
     796 
     797/* TODO: the close-down sequence */ 
  • src/gsmd/usock.c

    diff --git a/src/gsmd/usock.c b/src/gsmd/usock.c
    index f559661..1704c58 100644
    a b static int usock_rcv_phonebook(struct gsmd_user *gu, 
    984984                return 0; 
    985985} 
    986986 
     987static void mux_dlc_event_cb(enum mux_event ev, void *ctx) 
     988{ 
     989        struct gsmd *g = (struct gsmd *) ctx; 
     990 
     991        switch (ev) { 
     992        case TS0710_CONNECTED: 
     993                gsmd_log(GSMD_NOTICE, "First DLC opened\n"); 
     994 
     995                /* XXX Restore some settings */ 
     996                gsmd_simplecmd(g, "ATE0V1"); 
     997                gsmd_simplecmd(g, "AT+CMEE=1"); 
     998                gsmd_simplecmd(g, "AT+CLIP=1"); 
     999                gsmd_simplecmd(g, "AT+COLP=1"); 
     1000                gsmd_simplecmd(g, "AT+CMGF=0"); 
     1001 
     1002                break; 
     1003        case TS0710_DISCONNECTED: 
     1004                /* XXX Close-down the multiplexer, reattach atcmd to UART */ 
     1005                break; 
     1006        } 
     1007} 
     1008 
     1009static void mux_event_cb(enum mux_event ev, void *ctx) 
     1010{ 
     1011        struct gsmd *g = (struct gsmd *) ctx; 
     1012 
     1013        switch (ev) { 
     1014        case TS0710_CONNECTED: 
     1015                gsmd_log(GSMD_NOTICE, "Multiplexing enabled successfully\n"); 
     1016 
     1017                /* Open a channel (DLCI 1) and attach the AT parser to it.  */ 
     1018                atcmd_set_port(g, mux_dlc_open(g->muxer, 1, 
     1019                                        mux_dlc_event_cb, g)); 
     1020                break; 
     1021        case TS0710_DISCONNECTED: 
     1022                gsmd_log(GSMD_NOTICE, "Multiplexer functionality closed\n"); 
     1023                atcmd_set_port(g, &g->uart.port); 
     1024                break; 
     1025        } 
     1026} 
     1027 
     1028static int usock_mux_on_cb(struct gsmd_atcmd *cmd, void *ctx, char *resp) 
     1029{ 
     1030        struct gsmd_user *gu = (struct gsmd_user *) ctx; 
     1031        struct gsmd *g = gu->gsmd; 
     1032 
     1033        if (cmd->ret != 0) { 
     1034                gsmd_log(GSMD_NOTICE, "Starting the multiplexer failed " 
     1035                                "with %i\n", cmd->ret); 
     1036                return -ENOMEM; 
     1037        } 
     1038 
     1039        /* Detach the AT parser from the port.  */ 
     1040        atcmd_set_port(g, NULL); 
     1041 
     1042        /* The modem is supposedly in multiplexing mode now, 
     1043         * so quickly attach our half of the multiplexer to the UART, 
     1044         * and wait for a confirmation from it.  */ 
     1045        g->muxer = mux_init(&g->uart.port, 1, mux_event_cb, g); 
     1046 
     1047        return 0; 
     1048} 
     1049 
     1050static int usock_rcv_mux(struct gsmd_user *gu, 
     1051                struct gsmd_msg_hdr *gph, int len) 
     1052{        
     1053        struct gsmd_atcmd *cmd = NULL; 
     1054        int rc; 
     1055 
     1056        switch (gph->msg_subtype) { 
     1057        case GSMD_MULTIPLEX_ON: 
     1058                if (gu->gsmd->muxer) { 
     1059                        gsmd_log(GSMD_ERROR, "Already in mux mode\n"); 
     1060                        return -EEXIST; 
     1061                } 
     1062 
     1063                /* XXX Save */ 
     1064                rc = gsmd_simplecmd(gu->gsmd, "AT&W"); 
     1065                if (rc < 0) 
     1066                        return rc; 
     1067 
     1068                /* FIXME probe supported modes everytime */ 
     1069                cmd = atcmd_fill("AT+CMUX=1,0,5", 13 + 1, 
     1070                                &usock_mux_on_cb, gu, gph->id); 
     1071                if (!cmd) 
     1072                        return -ENOMEM; 
     1073                rc = atcmd_submit(gu->gsmd, cmd); 
     1074                if (rc < 0) 
     1075                        return rc; 
     1076                break; 
     1077        default: 
     1078                return -EINVAL; 
     1079        }        
     1080 
     1081        return 0; 
     1082} 
     1083 
    9871084static usock_msg_handler *pcmd_type_handlers[__NUM_GSMD_MSGS] = { 
    9881085        [GSMD_MSG_PASSTHROUGH]  = &usock_rcv_passthrough, 
    9891086        [GSMD_MSG_EVENT]        = &usock_rcv_event, 
    static usock_msg_handler *pcmd_type_handlers[__NUM_GSMD_MSGS] = { 
    9941091        [GSMD_MSG_SMS]          = &usock_rcv_sms, 
    9951092        [GSMD_MSG_CB]           = &usock_rcv_cb, 
    9961093        [GSMD_MSG_PHONEBOOK]    = &usock_rcv_phonebook, 
     1094        [GSMD_MSG_MULTIPLEX]    = &usock_rcv_mux, 
    9971095}; 
    9981096 
    9991097static int usock_rcv_pcmd(struct gsmd_user *gu, char *buf, int len) 
  • src/libgsmd/Makefile.am

    diff --git a/src/libgsmd/Makefile.am b/src/libgsmd/Makefile.am
    index 20a6725..4dfdf3f 100644
    a b AM_CFLAGS = -std=gnu99 
    55lib_LTLIBRARIES = libgsmd.la 
    66 
    77libgsmd_la_LDFLAGS = -Wc,-nostartfiles -version-info $(LIBVERSION) 
    8 libgsmd_la_SOURCES = libgsmd.c libgsmd_input.c libgsmd_voicecall.c libgsmd_passthrough.c libgsmd_event.c libgsmd_phone.c libgsmd_network.c libgsmd_pin.c libgsmd_sms.c libgsmd_phonebook.c 
     8libgsmd_la_SOURCES = libgsmd.c libgsmd_input.c libgsmd_voicecall.c libgsmd_passthrough.c libgsmd_event.c libgsmd_phone.c libgsmd_network.c libgsmd_pin.c libgsmd_sms.c libgsmd_phonebook.c libgsmd_multiplex.c 
    99 
    1010noinst_HEADERS = lgsm_internals.h 
  • new file src/libgsmd/libgsmd_multiplex.c

    diff --git a/src/libgsmd/libgsmd_multiplex.c b/src/libgsmd/libgsmd_multiplex.c
    new file mode 100644
    index 0000000..5cdea86
    - +  
     1/* libgsmd TE-MS channel multiplexing related functions 
     2 * 
     3 * (C) 2006-2007 by OpenMoko, Inc. 
     4 * Written by Harald Welte <laforge@openmoko.org> 
     5 * All Rights Reserved 
     6 * 
     7 * This library is free software; you can redistribute it and/or 
     8 * modify it under the terms of the GNU Lesser General Public 
     9 * License as published by the Free Software Foundation; either 
     10 * version 2.1 of the License, or (at your option) any later version. 
     11 * 
     12 * This library 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 GNU 
     15 * Lesser General Public License for more details. 
     16 * 
     17 * You should have received a copy of the GNU Lesser General Public 
     18 * License along with this library; if not, write to the Free Software 
     19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA 
     20 * 
     21 */  
     22 
     23#include <libgsmd/libgsmd.h> 
     24#include <libgsmd/misc.h> 
     25 
     26#include "lgsm_internals.h" 
     27 
     28int lgsm_mux_on(struct lgsm_handle *lh) 
     29{ 
     30        return lgsm_send_simple(lh, GSMD_MSG_MULTIPLEX, GSMD_MULTIPLEX_ON); 
     31} 
     32 
     33int lgsm_mux_off(struct lgsm_handle *lh) 
     34{ 
     35        return lgsm_send_simple(lh, GSMD_MSG_MULTIPLEX, GSMD_MULTIPLEX_OFF); 
     36} 
  • src/util/shell.c

    diff --git a/src/util/shell.c b/src/util/shell.c
    index af21f68..f1251a0 100644
    a b static int shell_help(void) 
    389389                "\tsM\tSMS Set preferred storage (sM=mem1,mem2,mem3)\n" 
    390390                "\tsc\tSMS Show Service Centre\n" 
    391391                "\tsC\tSMS Set Service Centre (sC=number)\n" 
     392                "\tms\tSMS Start multiplexing\n" 
     393                "\tmc\tSMS Close multiplexer down\n" 
    392394                "\tq\tQuit\n" 
    393395                ); 
    394396} 
    int shell_main(struct lgsm_handle *lgsmh) 
    649651                                        lgsm_sms_set_smsc(lgsmh, ptr + 1); 
    650652                        } else if (!strcmp(buf, "n")) { 
    651653                                lgsm_get_subscriber_num(lgsmh); 
     654                        } else if (!strcmp(buf, "ms")) { 
     655                                lgsm_mux_on(lgsmh); 
     656                        } else if (!strcmp(buf, "mc")) { 
     657                                lgsm_mux_off(lgsmh); 
    652658                        } else { 
    653659                                printf("Unknown command `%s'\n", buf); 
    654660                        }