diff --git a/lapv5.c b/lapv5.c index 143d785..34a5caf 100644 --- a/lapv5.c +++ b/lapv5.c @@ -24,6 +24,7 @@ #include "v5x_internal.h" #include "v5x_protocol.h" +#include "lapv5.h" #include #include @@ -73,9 +74,6 @@ #define LOGLI(li, level, fmt, args ...) \ LOGP(DLLAPD, level, "(%s): " fmt, (li)->name, ## args) -#define LOGTEI(teip, level, fmt, args ...) \ - LOGP(DLLAPD, level, "(%s-T%u): " fmt, (teip)->li->name, (teip)->tei, ## args) - #define LOGSAP(sap, level, fmt, args ...) \ LOGP(DLLAPD, level, "(%s): " fmt, (sap)->dl.name, ## args) @@ -92,85 +90,24 @@ const struct lapd_profile lapd_profile_lapv5dl = { .short_address = 0 }; -typedef enum { - LAPD_TEI_NONE = 0, - LAPD_TEI_ASSIGNED, - LAPD_TEI_ACTIVE, -} lapd_tei_state; - -const char *lapd_tei_states[] = { - "NONE", - "ASSIGNED", - "ACTIVE", -}; - -/* Structure representing an allocated TEI within a LAPD instance. */ -struct lapd_tei { - struct llist_head list; - struct lapd_instance *li; - uint8_t tei; - lapd_tei_state state; - - struct llist_head sap_list; -}; /* Structure representing a SAP within a TEI. It includes exactly one datalink * instance. */ -struct lapd_sap { - struct llist_head list; - struct lapd_tei *tei; - uint8_t sapi; +struct lapv5_sap { + struct llist_head list; /* list of SAP within instance */ + struct lapv5_instance *li; /* back-pointer */ + uint16_t dladdr; /* V5-Data Link Address */ - struct lapd_datalink dl; + struct lapd_datalink dl; /* the actual data link */ }; -/* Resolve TEI structure from given numeric TEI */ -static struct lapd_tei *teip_from_tei(struct lapd_instance *li, uint8_t tei) -{ - struct lapd_tei *lt; - - llist_for_each_entry(lt, &li->tei_list, list) { - if (lt->tei == tei) - return lt; - } - return NULL; -}; - -/* Change state of TEI */ -static void lapd_tei_set_state(struct lapd_tei *teip, int newstate) -{ - LOGTEI(teip, LOGL_INFO, "LAPD state change on TEI %d: %s -> %s\n", - teip->tei, lapd_tei_states[teip->state], - lapd_tei_states[newstate]); - teip->state = newstate; -}; - -/* Allocate a new TEI */ -struct lapd_tei *lapd_tei_alloc(struct lapd_instance *li, uint8_t tei) -{ - struct lapd_tei *teip; - - teip = talloc_zero(li, struct lapd_tei); - if (!teip) - return NULL; - - teip->li = li; - teip->tei = tei; - llist_add(&teip->list, &li->tei_list); - INIT_LLIST_HEAD(&teip->sap_list); - - lapd_tei_set_state(teip, LAPD_TEI_ASSIGNED); - - return teip; -} - /* Find a SAP within a given TEI */ -static struct lapd_sap *lapd_sap_find(struct lapd_tei *teip, uint8_t sapi) +static struct lapv5_sap *lapv5_sap_find(struct lapv5_instance *li, uint16_t dladdr) { - struct lapd_sap *sap; + struct lapv5_sap *sap; - llist_for_each_entry(sap, &teip->sap_list, list) { - if (sap->sapi == sapi) + llist_for_each_entry(sap, &li->sap_list, list) { + if (sap->dladdr == dladdr) return sap; } @@ -180,32 +117,29 @@ static struct lapd_sap *lapd_sap_find(struct lapd_tei *teip, uint8_t sapi) static int send_ph_data_req(struct lapd_msg_ctx *lctx, struct msgb *msg); static int send_dlsap(struct osmo_dlsap_prim *dp, struct lapd_msg_ctx *lctx); -/* Allocate a new SAP within a given TEI */ -static struct lapd_sap *lapd_sap_alloc(struct lapd_tei *teip, uint8_t sapi) +/* Allocate a new SAP within a given instance */ +static struct lapv5_sap *lapv5_sap_alloc(struct lapv5_instance *li, uint16_t v5dladdr) { - struct lapd_sap *sap; + struct lapv5_sap *sap; struct lapd_datalink *dl; - struct lapd_instance *li = teip->li; struct lapd_profile *profile; char name[256]; int k; - snprintf(name, sizeof(name), "%s-T%u-S%u", li->name, teip->tei, sapi); + snprintf(name, sizeof(name), "%s-%u", li->name, v5dladdr); - sap = talloc_zero(teip, struct lapd_sap); + sap = talloc_zero(li, struct lapv5_sap); if (!sap) return NULL; - LOGP(DLLAPD, LOGL_NOTICE, - "(%s): LAPD Allocating SAP for SAPI=%u / TEI=%u (dl=%p, sap=%p)\n", - name, sapi, teip->tei, &sap->dl, sap); + LOGP(DLLAPD, LOGL_NOTICE, "(%s): LAPV5 Allocating SAP for V5_DLADDR=%u (dl=%p, sap=%p)\n", + name, v5dladdr, &sap->dl, sap); - sap->sapi = sapi; - sap->tei = teip; + sap->dladdr = v5dladdr; dl = &sap->dl; profile = &li->profile; - k = profile->k[sapi & 0x3f]; + k = profile->k[0]; LOGP(DLLAPD, LOGL_NOTICE, "(%s): k=%d N200=%d N201=%d T200=%d.%d T203=%d.%d\n", name, k, profile->n200, profile->n201, profile->t200_sec, profile->t200_usec, profile->t203_sec, profile->t203_usec); @@ -218,24 +152,21 @@ static struct lapd_sap *lapd_sap_alloc(struct lapd_tei *teip, uint8_t sapi) dl->t200_sec = profile->t200_sec; dl->t200_usec = profile->t200_usec; dl->t203_sec = profile->t203_sec; dl->t203_usec = profile->t203_usec; dl->lctx.dl = &sap->dl; - dl->lctx.sapi = sapi; - dl->lctx.tei = teip->tei; + dl->lctx.sapi = v5dladdr & 0xff; + dl->lctx.tei = v5dladdr >> 8; dl->lctx.n201 = profile->n201; - lapd_set_mode(&sap->dl, (teip->li->network_side) ? LAPD_MODE_NETWORK - : LAPD_MODE_USER); + lapd_set_mode(&sap->dl, (li->network_side) ? LAPD_MODE_NETWORK : LAPD_MODE_USER); - llist_add(&sap->list, &teip->sap_list); + llist_add(&sap->list, &li->sap_list); return sap; } /* Free SAP instance, including the datalink */ -static void lapd_sap_free(struct lapd_sap *sap) +static void lapv5_sap_free(struct lapv5_sap *sap) { - LOGSAP(sap, LOGL_NOTICE, - "LAPD Freeing SAP for SAPI=%u / TEI=%u (dl=%p, sap=%p)\n", - sap->sapi, sap->tei->tei, &sap->dl, sap); + LOGSAP(sap, LOGL_NOTICE, "LAPV5 Freeing SAP for DLADDR=%u (dl=%p, sap=%p)\n", sap->dladdr, &sap->dl, sap); /* free datalink structures and timers */ lapd_dl_exit(&sap->dl); @@ -244,99 +175,21 @@ static void lapd_sap_free(struct lapd_sap *sap) talloc_free(sap); } -/* Free TEI instance */ -static void lapd_tei_free(struct lapd_tei *teip) +/* General input function for any data received for this LAPV5 instance */ +int lapv5_receive(struct lapv5_instance *li, struct msgb *msg, int *error) { - struct lapd_sap *sap, *sap2; - - llist_for_each_entry_safe(sap, sap2, &teip->sap_list, list) { - lapd_sap_free(sap); - } - - llist_del(&teip->list); - talloc_free(teip); -} - -/* Input function into TEI manager */ -static int lapd_tei_receive(struct lapd_instance *li, uint8_t *data, int len) -{ - uint8_t entity; - uint8_t ref; - uint8_t mt; - uint8_t action; - uint8_t e; - uint8_t resp[8]; - struct lapd_tei *teip; - struct msgb *msg; - - if (len < 5) { - LOGLI(li, LOGL_ERROR, "LAPD TEIMGR frame receive len %d < 5" - ", ignoring\n", len); - return -EINVAL; - }; - - entity = data[0]; - ref = data[1]; - mt = data[3]; - action = data[4] >> 1; - e = data[4] & 1; - - DEBUGP(DLLAPD, "LAPD TEIMGR: entity %x, ref %x, mt %x, action %x, " - "e %x\n", entity, ref, mt, action, e); - - switch (mt) { - case 0x01: /* IDENTITY REQUEST */ - DEBUGP(DLLAPD, "LAPD TEIMGR: identity request for TEI %u\n", - action); - - teip = teip_from_tei(li, action); - if (!teip) { - LOGLI(li, LOGL_INFO, "TEI MGR: New TEI %u\n", - action); - teip = lapd_tei_alloc(li, action); - if (!teip) - return -ENOMEM; - } - - /* Send ACCEPT */ - memmove(resp, "\xfe\xff\x03\x0f\x00\x00\x02\x00", 8); - resp[7] = (action << 1) | 1; - msg = msgb_alloc_headroom(DLSAP_MSGB_SIZE, DLSAP_MSGB_HEADROOM, "DL EST"); - msg->l2h = msgb_push(msg, 8); - memcpy(msg->l2h, resp, 8); - - /* write to PCAP file, if enabled. */ - osmo_pcap_lapd_write(li->pcap_fd, OSMO_LAPD_PCAP_OUTPUT, msg); - - LOGTEI(teip, LOGL_DEBUG, "TX: %s\n", osmo_hexdump(msg->data, msg->len)); - li->transmit_cb(msg, li->transmit_cbdata); - - if (teip->state == LAPD_TEI_NONE) - lapd_tei_set_state(teip, LAPD_TEI_ASSIGNED); - break; - default: - LOGLI(li, LOGL_NOTICE, "LAPD TEIMGR: unknown mt %x action %x\n", mt, action); - break; - }; - - return 0; -} - -/* General input function for any data received for this LAPD instance */ -int lapd_receive(struct lapd_instance *li, struct msgb *msg, int *error) -{ - int i; struct lapd_msg_ctx lctx; - int rc; - struct lapd_sap *sap; - struct lapd_tei *teip; + struct lapv5_sap *sap; + uint16_t dladdr; + bool is_isdn; + int i; /* write to PCAP file, if enabled. */ osmo_pcap_lapd_write(li->pcap_fd, OSMO_LAPD_PCAP_INPUT, msg); LOGLI(li, LOGL_DEBUG, "RX: %s\n", osmo_hexdump(msg->data, msg->len)); if (msg->len < 2) { - LOGLI(li, LOGL_ERROR, "LAPD frame receive len %d < 2, ignoring\n", msg->len); + LOGLI(li, LOGL_ERROR, "LAPV5 frame receive len %d < 2, ignoring\n", msg->len); *error = LAPD_ERR_BAD_LEN; return -EINVAL; }; @@ -346,55 +199,39 @@ int lapd_receive(struct lapd_instance *li, struct msgb *msg, int *error) i = 0; /* adress field */ - lctx.sapi = LAPD_ADDR_SAPI(msg->l2h[i]); - lctx.cr = LAPD_ADDR_CR(msg->l2h[i]); + dladdr = v51_l3_addr_dec(msg->l2h[0] << 8 | msg->l2h[1], &is_isdn); + if (!is_isdn) { + LOGLI(li, LOGL_ERROR, "LAPV5 frame with single-octet addr not permitted\n"); + *error = LAPD_ERR_BAD_LEN; + return -EINVAL; + }; lctx.lpd = 0; - if (!LAPD_ADDR_EA(msg->l2h[i])) { - if (msg->len < 3) { - LOGLI(li, LOGL_ERROR, "LAPD frame with TEI receive " - "len %d < 3, ignoring\n", msg->len); - *error = LAPD_ERR_BAD_LEN; - return -EINVAL; - }; - i++; - lctx.tei = LAPD_ADDR_TEI(msg->l2h[i]); - } - i++; + lctx.tei = dladdr >> 8; + lctx.sapi = dladdr & 0xff; + lctx.cr = LAPD_ADDR_CR(msg->l2h[0]); + i += 2; + /* control field */ if (LAPD_CTRL_is_I(msg->l2h[i])) { lctx.format = LAPD_FORM_I; lctx.n_send = LAPD_CTRL_I_Ns(msg->l2h[i]); i++; - if (msg->len < 3 && i == 2) { - LOGLI(li, LOGL_ERROR, "LAPD I frame without TEI " - "receive len %d < 3, ignoring\n", msg->len); + if (msg->len < 4) { + LOGLI(li, LOGL_ERROR, "LAPV5 I frame receive len %d < 4, ignoring\n", msg->len); *error = LAPD_ERR_BAD_LEN; return -EINVAL; - }; - if (msg->len < 4 && i == 3) { - LOGLI(li, LOGL_ERROR, "LAPD I frame with TEI " - "receive len %d < 4, ignoring\n", msg->len); - *error = LAPD_ERR_BAD_LEN; - return -EINVAL; - }; + } lctx.n_recv = LAPD_CTRL_Nr(msg->l2h[i]); lctx.p_f = LAPD_CTRL_I_P(msg->l2h[i]); } else if (LAPD_CTRL_is_S(msg->l2h[i])) { lctx.format = LAPD_FORM_S; lctx.s_u = LAPD_CTRL_S_BITS(msg->l2h[i]); i++; - if (msg->len < 3 && i == 2) { - LOGLI(li, LOGL_ERROR, "LAPD S frame without TEI " - "receive len %d < 3, ignoring\n", msg->len); - *error = LAPD_ERR_BAD_LEN; - return -EINVAL; - }; if (msg->len < 4 && i == 3) { - LOGLI(li, LOGL_ERROR, "LAPD S frame with TEI " - "receive len %d < 4, ignoring\n", msg->len); + LOGLI(li, LOGL_ERROR, "LAPV5 S frame receive len %d < 4, ignoring\n", msg->len); *error = LAPD_ERR_BAD_LEN; return -EINVAL; - }; + } lctx.n_recv = LAPD_CTRL_Nr(msg->l2h[i]); lctx.p_f = LAPD_CTRL_S_PF(msg->l2h[i]); } else if (LAPD_CTRL_is_U(msg->l2h[i])) { @@ -409,26 +246,10 @@ int lapd_receive(struct lapd_instance *li, struct msgb *msg, int *error) msgb_pull(msg, i); lctx.length = msg->len; - /* perform TEI assignment, if received */ - if (lctx.tei == 127) { - rc = lapd_tei_receive(li, msg->data, msg->len); - msgb_free(msg); - return rc; - } - - /* resolve TEI and SAPI */ - teip = teip_from_tei(li, lctx.tei); - if (!teip) { - LOGLI(li, LOGL_NOTICE, "LAPD Unknown TEI %u\n", lctx.tei); - *error = LAPD_ERR_UNKNOWN_TEI; - msgb_free(msg); - return -EINVAL; - } - sap = lapd_sap_find(teip, lctx.sapi); + sap = lapv5_sap_find(li, dladdr); if (!sap) { - LOGTEI(teip, LOGL_INFO, "LAPD No SAP for TEI=%u / SAPI=%u, " - "allocating\n", lctx.tei, lctx.sapi); - sap = lapd_sap_alloc(teip, lctx.sapi); + LOGLI(li, LOGL_INFO, "LAPV5 No SAP for DLADDR=%u, allocating\n", dladdr); + sap = lapv5_sap_alloc(li, dladdr); if (!sap) { *error = LAPD_ERR_NO_MEM; msgb_free(msg); @@ -439,8 +260,7 @@ int lapd_receive(struct lapd_instance *li, struct msgb *msg, int *error) lctx.n201 = lctx.dl->maxf; if (msg->len > lctx.n201) { - LOGSAP(sap, LOGL_ERROR, "message len %d > N201(%d) " - "(discarding)\n", msg->len, lctx.n201); + LOGSAP(sap, LOGL_ERROR, "message len %d > N201(%d) (discarding)\n", msg->len, lctx.n201); msgb_free(msg); *error = LAPD_ERR_BAD_LEN; return -EINVAL; @@ -451,26 +271,21 @@ int lapd_receive(struct lapd_instance *li, struct msgb *msg, int *error) } /* Start a (user-side) SAP for the specified TEI/SAPI on the LAPD instance */ -int lapd_sap_start(struct lapd_instance *li, uint8_t tei, uint8_t sapi) +int lapv5_sap_start(struct lapv5_instance *li, uint16_t dladdr) { - struct lapd_sap *sap; - struct lapd_tei *teip; + struct lapv5_sap *sap; struct osmo_dlsap_prim dp; struct msgb *msg; - teip = teip_from_tei(li, tei); - if (!teip) - teip = lapd_tei_alloc(li, tei); - - sap = lapd_sap_find(teip, sapi); + sap = lapv5_sap_find(li, dladdr); if (sap) return -EEXIST; - sap = lapd_sap_alloc(teip, sapi); + sap = lapv5_sap_alloc(li, dladdr); if (!sap) return -ENOMEM; - LOGSAP(sap, LOGL_NOTICE, "LAPD DL-ESTABLISH request TEI=%d SAPI=%d\n", tei, sapi); + LOGSAP(sap, LOGL_NOTICE, "LAPV5 DL-ESTABLISH request DLADDR=%u\n", dladdr); /* prepare prim */ msg = msgb_alloc_headroom(DLSAP_MSGB_SIZE, DLSAP_MSGB_HEADROOM, "DL EST"); @@ -482,22 +297,17 @@ int lapd_sap_start(struct lapd_instance *li, uint8_t tei, uint8_t sapi) } /* Stop a (user-side) SAP for the specified TEI/SAPI on the LAPD instance */ -int lapd_sap_stop(struct lapd_instance *li, uint8_t tei, uint8_t sapi) +int lapv5_sap_stop(struct lapv5_instance *li, uint16_t dladdr) { - struct lapd_tei *teip; - struct lapd_sap *sap; + struct lapv5_sap *sap; struct osmo_dlsap_prim dp; struct msgb *msg; - teip = teip_from_tei(li, tei); - if (!teip) - return -ENODEV; - - sap = lapd_sap_find(teip, sapi); + sap = lapv5_sap_find(li, dladdr); if (!sap) return -ENODEV; - LOGSAP(sap, LOGL_NOTICE, "LAPD DL-RELEASE request TEI=%d SAPI=%d\n", tei, sapi); + LOGSAP(sap, LOGL_NOTICE, "LAPV5 DL-RELEASE request DLADDR=%u\n", dladdr); /* prepare prim */ msg = msgb_alloc_headroom(DLSAP_MSGB_SIZE, DLSAP_MSGB_HEADROOM, "DL REL"); @@ -508,23 +318,15 @@ int lapd_sap_stop(struct lapd_instance *li, uint8_t tei, uint8_t sapi) return lapd_recv_dlsap(&dp, &sap->dl.lctx); } -/* Transmit Data (DL-DATA request) on the given LAPD Instance / TEI / SAPI */ -void lapd_transmit(struct lapd_instance *li, uint8_t tei, uint8_t sapi, - struct msgb *msg) +/* Transmit Data (DL-DATA request) on the given LAPD Instance / DLADDR */ +void lapv5_transmit(struct lapv5_instance *li, uint8_t dladdr, struct msgb *msg) { - struct lapd_tei *teip = teip_from_tei(li, tei); - struct lapd_sap *sap; + struct lapv5_sap *sap; struct osmo_dlsap_prim dp; - if (!teip) { - LOGLI(li, LOGL_ERROR, "LAPD Cannot transmit on non-existing TEI %u\n", tei); - msgb_free(msg); - return; - } - - sap = lapd_sap_find(teip, sapi); + sap = lapv5_sap_find(li, dladdr); if (!sap) { - LOGTEI(teip, LOGL_INFO, "LAPD Tx on unknown SAPI=%u in TEI=%u\n", sapi, tei); + LOGLI(li, LOGL_INFO, "LAPV5 Tx on unknown DLADDR=%u\n", dladdr); msgb_free(msg); return; } @@ -540,11 +342,9 @@ void lapd_transmit(struct lapd_instance *li, uint8_t tei, uint8_t sapi, static int send_ph_data_req(struct lapd_msg_ctx *lctx, struct msgb *msg) { struct lapd_datalink *dl = lctx->dl; - struct lapd_sap *sap = - container_of(dl, struct lapd_sap, dl); - struct lapd_instance *li = sap->tei->li; + struct lapv5_sap *sap = container_of(dl, struct lapv5_sap, dl); + struct lapv5_instance *li = sap->li; int format = lctx->format; - int addr_len; /* control field */ switch (format) { @@ -567,16 +367,9 @@ static int send_ph_data_req(struct lapd_msg_ctx *lctx, struct msgb *msg) return -EINVAL; } /* address field */ - if (li->profile.short_address && lctx->tei == 0) - addr_len = 1; - else - addr_len = 2; - msg->l2h = msgb_push(msg, addr_len); + msg->l2h = msgb_push(msg, 2); msg->l2h[0] = LAPD_ADDR2(lctx->sapi, lctx->cr); - if (addr_len == 1) - msg->l2h[0] |= 0x1; - else - msg->l2h[1] = LAPD_ADDR3(lctx->tei); + msg->l2h[1] = LAPD_ADDR3(lctx->tei); /* write to PCAP file, if enabled. */ osmo_pcap_lapd_write(li->pcap_fd, OSMO_LAPD_PCAP_OUTPUT, msg); @@ -592,47 +385,42 @@ static int send_ph_data_req(struct lapd_msg_ctx *lctx, struct msgb *msg) static int send_dlsap(struct osmo_dlsap_prim *dp, struct lapd_msg_ctx *lctx) { struct lapd_datalink *dl = lctx->dl; - struct lapd_sap *sap = - container_of(dl, struct lapd_sap, dl); - struct lapd_instance *li; - uint8_t tei, sapi; - char *op = (dp->oph.operation == PRIM_OP_INDICATION) ? "indication" - : "confirm"; + struct lapv5_sap *sap = container_of(dl, struct lapv5_sap, dl); + struct lapv5_instance *li; + const char *op = (dp->oph.operation == PRIM_OP_INDICATION) ? "indication" : "confirm"; + uint16_t dladdr; - li = sap->tei->li; - tei = lctx->tei; - sapi = lctx->sapi; + li = sap->li; + + dladdr = lctx->tei << 8 | lctx->sapi; switch (dp->oph.primitive) { case PRIM_DL_EST: - LOGDL(dl, LOGL_NOTICE, "LAPD DL-ESTABLISH %s TEI=%d " - "SAPI=%d\n", op, lctx->tei, lctx->sapi); + LOGDL(dl, LOGL_NOTICE, "LAPD DL-ESTABLISH %s DLADDR=%u\n", op, dladdr); break; case PRIM_DL_REL: - LOGDL(dl, LOGL_NOTICE, "LAPD DL-RELEASE %s TEI=%d " - "SAPI=%d\n", op, lctx->tei, lctx->sapi); - lapd_sap_free(sap); + LOGDL(dl, LOGL_NOTICE, "LAPD DL-RELEASE %s DLADDR=%u\n", op, dladdr); + lapv5_sap_free(sap); /* note: sap and dl is now gone, don't use it anymore */ break; default: ; } - li->receive_cb(dp, tei, sapi, li->receive_cbdata); + li->receive_cb(dp, dladdr, li->receive_cbdata); return 0; } -/* Allocate a new LAPD instance */ -struct lapd_instance *lapd_instance_alloc2(int network_side, +/* Allocate a new LAPV5 instance */ +struct lapv5_instance *lapv5_instance_alloc(int network_side, void (*tx_cb)(struct msgb *msg, void *cbdata), void *tx_cbdata, - void (*rx_cb)(struct osmo_dlsap_prim *odp, uint8_t tei, uint8_t sapi, - void *rx_cbdata), void *rx_cbdata, + void (*rx_cb)(struct osmo_dlsap_prim *odp, uint16_t dladdr, void *rx_cbdata), void *rx_cbdata, const struct lapd_profile *profile, const char *name) { - struct lapd_instance *li; + struct lapv5_instance *li; - li = talloc_zero(NULL, struct lapd_instance); + li = talloc_zero(NULL, struct lapv5_instance); if (!li) return NULL; @@ -645,35 +433,25 @@ struct lapd_instance *lapd_instance_alloc2(int network_side, li->name = talloc_strdup(li, name); memcpy(&li->profile, profile, sizeof(li->profile)); - INIT_LLIST_HEAD(&li->tei_list); + INIT_LLIST_HEAD(&li->sap_list); return li; } -struct lapd_instance *lapd_instance_alloc(int network_side, - void (*tx_cb)(struct msgb *msg, void *cbdata), void *tx_cbdata, - void (*rx_cb)(struct osmo_dlsap_prim *odp, uint8_t tei, uint8_t sapi, - void *rx_cbdata), void *rx_cbdata, - const struct lapd_profile *profile) -{ - return lapd_instance_alloc2(network_side, tx_cbdata, tx_cb, rx_cb, rx_cbdata, profile, NULL); -} - /* Change lapd-profile on the fly (use with caution!) */ -void lapd_instance_set_profile(struct lapd_instance *li, - const struct lapd_profile *profile) +void lapv5_instance_set_profile(struct lapv5_instance *li, const struct lapd_profile *profile) { memcpy(&li->profile, profile, sizeof(li->profile)); } -void lapd_instance_free(struct lapd_instance *li) +void lapv5_instance_free(struct lapv5_instance *li) { - struct lapd_tei *teip, *teip2; + struct lapv5_sap *sap, *sap2; - /* Free all TEI instances */ - llist_for_each_entry_safe(teip, teip2, &li->tei_list, list) { - lapd_tei_free(teip); + /* Free all SAP instances */ + llist_for_each_entry_safe(sap, sap2, &li->sap_list, list) { + lapv5_sap_free(sap); } talloc_free(li); @@ -692,6 +470,7 @@ void lapd_instance_free(struct lapd_instance *li) * while the last octet (before msg->tail) points to the last FCS octet. */ int lapv5ef_rx(struct v5x_link *link, struct msgb *msg) { + struct lapd_datalink *dl; uint16_t efaddr, efaddr_enc; bool is_isdn; @@ -715,13 +494,26 @@ int lapv5ef_rx(struct v5x_link *link, struct msgb *msg) switch (efaddr) { case V51_DLADDR_PSTN: /* hand-over to LAPD-DL instance for PSTN */ + dl = &link->interface->pstn.dl; + /* TODO */ break; case V51_DLADDR_CTRL: /* hand-over to LAPD-DL instance for CTRL */ + /* TODO */ + dl = &link->interface->control.dl; break; case V52_DLADDR_BCC: + dl = &link->interface->bcc.dl; + /* TOOD: implement V5.2 */ + msgb_free(msg); + break; case V52_DLADDR_PROTECTION: + dl = &link->interface->protection[0].dl; + /* TOOD: implement V5.2 */ + msgb_free(msg); + break; case V52_DLADDR_LCP: + dl = &link->interface->lcp.dl; /* TOOD: implement V5.2 */ msgb_free(msg); break; @@ -732,5 +524,8 @@ int lapv5ef_rx(struct v5x_link *link, struct msgb *msg) return -EINVAL; } /* relay function for LAPD of user ports */ + /* TODO */ } + + return 0; } diff --git a/lapv5.h b/lapv5.h new file mode 100644 index 0000000..16829cf --- /dev/null +++ b/lapv5.h @@ -0,0 +1,21 @@ +#pragma once + +#include + +struct lapv5_instance { + struct llist_head list; /* list of LAPV5 instances */ + bool network_side; + + void (*transmit_cb)(struct msgb *msg, void *cbdata); + void *transmit_cbdata; + void (*receive_cb)(struct osmo_dlsap_prim *odp, uint16_t dladdr, void *rx_cbdata); + void *receive_cbdata; + + struct lapd_profile profile; /* must be a copy */ + + struct llist_head sap_list; /* list of SAP/datalinks in this instance */ + int pcap_fd; /* PCAP file descriptor */ + char *name; /* human-readable name */ +}; + +int lapv5ef_rx(struct v5x_link *link, struct msgb *msg); diff --git a/v5x_data.c b/v5x_data.c new file mode 100644 index 0000000..ee27213 --- /dev/null +++ b/v5x_data.c @@ -0,0 +1,92 @@ +#include +#include + +#include "v5x_internal.h" + +static LLIST_HEAD(v5_instances); + +struct v5x_instance *v5x_instance_alloc(void *ctx) +{ + struct v5x_instance *v5i = talloc_zero(ctx, struct v5x_instance); + if (!v5i) + return NULL; + + INIT_LLIST_HEAD(&v5i->interfaces); + INIT_LLIST_HEAD(&v5i->user_ports); + /* TODO: allocate ctrl_fi */ + + llist_add_tail(&v5i->list, &v5_instances); + + return v5i; +} + +static void v5x_ts_init(struct v5x_timeslot *v5ts, uint8_t nr, struct v5x_link *v5l, uint16_t l3_addr) +{ + v5ts->nr = nr; + v5ts->link = v5l; + v5ts->l3_address = l3_addr; +} + +static void v5x_cchan_init(struct v5x_c_channel *v5cc, struct v5x_link *v5l, struct v5x_timeslot *v5ts, bool active) +{ + v5cc->link = v5l; + v5cc->ts = v5ts; + v5cc->active = active; +} + +static void v5x_link_init(struct v5x_link *v5l, struct v5x_interface *v5if, uint8_t id) +{ + unsigned int i; + + v5l->id = id; + v5l->interface = v5if; + + for (i = 1; i < ARRAY_SIZE(v5l->ts); i++) { + v5x_ts_init(&v5l->ts[i], i, v5l, 0 /*l3_addr*/); + } + + /* primary c-channel must always be present */ + v5x_cchan_init(&v5l->c_channel[0], v5l, &v5l->ts[16], true); +} + +struct v5x_interface *v5x_interface_alloc(struct v5x_instance *v5i, enum v5x_dialect dialect) +{ + struct v5x_interface *v5if = talloc_zero(v5i, struct v5x_interface); + //struct v5x_link *v5l; + struct v5x_c_channel *primary_c_chan; + + v5if->instance = v5i; + v5if->dialect = dialect; + + /* primary link must alwasy be present */ + v5x_link_init(&v5if->links[0], v5if, 0); + v5if->primary_link = &v5if->links[0]; + + primary_c_chan = &v5if->primary_link->c_channel[0]; + + + /* TODO: allocate fi */ + + //lapd_dl_init2(&v5if->control.dl, k, v_rnage, maxf, "control"); + v5if->control.c_chan = primary_c_chan; + + //lapd_dl_init2(&v5if->pstn.dl, k, v_rnage, maxf, "pstn"); + v5if->pstn.c_chan = primary_c_chan; + + if (v5if->dialect == V5X_DIALECT_V52) { + //lapd_dl_init2(&v5if->lcp.dl, k, v_rnage, maxf, "lcp"); + v5if->lcp.c_chan = primary_c_chan; + + //lapd_dl_init2(&v5if->bcc.dl, k, v_rnage, maxf, "bcc"); + v5if->bcc.c_chan = primary_c_chan; + + //lapd_dl_init2(&v5if->protection[0].dl, k, v_rnage, maxf, "protection0"); + v5if->protection[0].c_chan = primary_c_chan; + + //protection[1] ? + } + + llist_add_tail(&v5if->list, &v5i->interfaces); + + return v5if; +} diff --git a/v5x_internal.h b/v5x_internal.h index 37d9d0e..637bf64 100644 --- a/v5x_internal.h +++ b/v5x_internal.h @@ -118,3 +118,6 @@ struct v5x_instance { struct llist_head user_ports; /* list of v5x_user_port */ struct osmo_fsm_inst *ctrl_fi; /* common control FSM */ }; + +struct v5x_instance *v5x_instance_alloc(void *ctx); +struct v5x_interface *v5x_interface_alloc(struct v5x_instance *v5i, enum v5x_dialect dialect);