lce: implement normal link release procedure
Signed-off-by: Patrick McHardy <kaber@trash.net>
This commit is contained in:
parent
dbf68ba8b3
commit
88c949c44e
|
@ -125,15 +125,16 @@ enum dect_data_link_states {
|
|||
/**
|
||||
* struct dect_data_link
|
||||
*
|
||||
* @list: DECT handle link list node
|
||||
* @dfd: Associated socket file descriptor
|
||||
* @dlei: Data Link Endpoint identifier
|
||||
* @ipui: International Portable User ID
|
||||
* @state: Data link state
|
||||
* @sdu_timer: Establish without SDU timer
|
||||
* @page_timer: Indirect establish timer (LCE.03)
|
||||
* @page_count: Number of page messages sent
|
||||
* @msg_queue: Message queue used during ESTABLISH_PENDING state
|
||||
* @list: DECT handle link list node
|
||||
* @dfd: Associated socket file descriptor
|
||||
* @dlei: Data Link Endpoint identifier
|
||||
* @ipui: International Portable User ID
|
||||
* @state: Data link state
|
||||
* @sdu_timer: Establish without SDU timer (LCE.05)
|
||||
* @release_timer: Normal link release timer (LCE.01)
|
||||
* @page_timer: Indirect establish timer (LCE.03)
|
||||
* @page_count: Number of page messages sent
|
||||
* @msg_queue: Message queue used during ESTABLISH_PENDING state
|
||||
*/
|
||||
struct dect_data_link {
|
||||
struct list_head list;
|
||||
|
@ -142,12 +143,14 @@ struct dect_data_link {
|
|||
struct dect_fd *dfd;
|
||||
enum dect_data_link_states state;
|
||||
struct dect_timer *sdu_timer;
|
||||
struct dect_timer *release_timer;
|
||||
struct dect_timer *page_timer;
|
||||
uint8_t page_count;
|
||||
struct list_head msg_queue;
|
||||
struct list_head transactions;
|
||||
};
|
||||
|
||||
#define DECT_DDL_RELEASE_TIMEOUT 5 /* seconds */
|
||||
#define DECT_DDL_ESTABLISH_SDU_TIMEOUT 5 /* seconds */
|
||||
#define DECT_DDL_PAGE_TIMEOUT 5 /* seconds */
|
||||
#define DECT_DDL_PAGE_RETRANS_MAX 3 /* N.300 */
|
||||
|
|
89
src/lce.c
89
src/lce.c
|
@ -246,6 +246,7 @@ static void dect_ddl_destroy(struct dect_handle *dh, struct dect_data_link *ddl)
|
|||
dect_unregister_fd(dh, ddl->dfd);
|
||||
dect_close(dh, ddl->dfd);
|
||||
}
|
||||
dect_free(dh, ddl->release_timer);
|
||||
dect_free(dh, ddl);
|
||||
}
|
||||
|
||||
|
@ -264,6 +265,58 @@ static struct dect_data_link *dect_ddl_alloc(const struct dect_handle *dh)
|
|||
return ddl;
|
||||
}
|
||||
|
||||
static void dect_ddl_release_timer(struct dect_handle *dh, struct dect_timer *timer)
|
||||
{
|
||||
struct dect_data_link *ddl = timer->data;
|
||||
|
||||
ddl_debug(ddl, "normal release timeout");
|
||||
dect_ddl_destroy(dh, ddl);
|
||||
}
|
||||
|
||||
static void dect_ddl_release_complete(struct dect_handle *dh,
|
||||
struct dect_data_link *ddl)
|
||||
{
|
||||
ddl_debug(ddl, "normal release complete");
|
||||
ddl->state = DECT_DATA_LINK_RELEASED;
|
||||
dect_stop_timer(dh, ddl->release_timer);
|
||||
dect_ddl_destroy(dh, ddl);
|
||||
}
|
||||
|
||||
static void dect_ddl_release(struct dect_handle *dh,
|
||||
struct dect_data_link *ddl)
|
||||
{
|
||||
ddl_debug(ddl, "normal release");
|
||||
|
||||
/* Shut down transmission and wait until all outstanding frames
|
||||
* are successfully transmitted or the release timeout occurs.
|
||||
*/
|
||||
if (shutdown(ddl->dfd->fd, SHUT_WR) < 0)
|
||||
goto err1;
|
||||
ddl->state = DECT_DATA_LINK_RELEASE_PENDING;
|
||||
|
||||
ddl->release_timer = dect_alloc_timer(dh);
|
||||
if (ddl->release_timer == NULL)
|
||||
goto err1;
|
||||
dect_setup_timer(ddl->release_timer, dect_ddl_release_timer, ddl);
|
||||
dect_start_timer(dh, ddl->release_timer, DECT_DDL_RELEASE_TIMEOUT);
|
||||
return;
|
||||
|
||||
err1:
|
||||
dect_ddl_destroy(dh, ddl);
|
||||
}
|
||||
|
||||
static void dect_ddl_shutdown(struct dect_handle *dh,
|
||||
struct dect_data_link *ddl)
|
||||
{
|
||||
struct dect_transaction *ta, *next;
|
||||
LIST_HEAD(transactions);
|
||||
|
||||
ddl_debug(ddl, "shutdown");
|
||||
list_splice_init(&ddl->transactions, &transactions);
|
||||
list_for_each_entry_safe(ta, next, &transactions, list)
|
||||
protocols[ta->pd]->shutdown(dh, ta);
|
||||
}
|
||||
|
||||
static void dect_ddl_sdu_timer(struct dect_handle *dh, struct dect_timer *timer)
|
||||
{
|
||||
struct dect_data_link *ddl = timer->data;
|
||||
|
@ -350,18 +403,6 @@ int dect_lce_send(const struct dect_handle *dh,
|
|||
}
|
||||
}
|
||||
|
||||
static void dect_ddl_shutdown(struct dect_handle *dh,
|
||||
struct dect_data_link *ddl)
|
||||
{
|
||||
struct dect_transaction *ta, *next;
|
||||
LIST_HEAD(transactions);
|
||||
|
||||
ddl_debug(ddl, "shutdown");
|
||||
list_splice_init(&ddl->transactions, &transactions);
|
||||
list_for_each_entry_safe(ta, next, &transactions, list)
|
||||
protocols[ta->pd]->shutdown(dh, ta);
|
||||
}
|
||||
|
||||
static void dect_ddl_page_timer(struct dect_handle *dh, struct dect_timer *timer)
|
||||
{
|
||||
struct dect_data_link *ddl = timer->data;
|
||||
|
@ -525,7 +566,7 @@ static void dect_lce_rcv_page_response(struct dect_handle *dh,
|
|||
dect_ddl_complete_indirect_establish(dh, ta->link, req);
|
||||
else {
|
||||
dect_send_reject(dh, ta, DECT_REJECT_IPUI_UNKNOWN);
|
||||
dect_ddl_destroy(dh, ta->link);
|
||||
dect_ddl_release(dh, ta->link);
|
||||
}
|
||||
|
||||
dect_msg_free(dh, lce_page_response_msg, &msg.common);
|
||||
|
@ -583,8 +624,18 @@ static void dect_ddl_rcv_msg(struct dect_handle *dh, struct dect_data_link *ddl)
|
|||
uint8_t pd, tv;
|
||||
bool f;
|
||||
|
||||
if (dect_mbuf_rcv(ddl->dfd, mb) < 0)
|
||||
return dect_ddl_shutdown(dh, ddl);
|
||||
if (dect_mbuf_rcv(ddl->dfd, mb) < 0) {
|
||||
switch (errno) {
|
||||
case ENOTCONN:
|
||||
if (ddl->state == DECT_DATA_LINK_RELEASE_PENDING)
|
||||
return dect_ddl_release_complete(dh, ddl);
|
||||
case ECONNRESET:
|
||||
ddl->state = DECT_DATA_LINK_RELEASED;
|
||||
return dect_ddl_shutdown(dh, ddl);
|
||||
default:
|
||||
BUG();
|
||||
}
|
||||
}
|
||||
|
||||
if (ddl->sdu_timer != NULL)
|
||||
dect_ddl_stop_sdu_timer(dh, ddl);
|
||||
|
@ -699,11 +750,13 @@ void dect_close_transaction(struct dect_handle *dh, struct dect_transaction *ta)
|
|||
|
||||
ddl_debug(ddl, "close transaction");
|
||||
list_del(&ta->list);
|
||||
list_for_each_entry(ta, &ddl->transactions, list)
|
||||
dect_debug("\ttrans %p proto %u TV %u\n", ta, ta->pd, ta->tv);
|
||||
if (!list_empty(&ddl->transactions))
|
||||
return;
|
||||
dect_ddl_destroy(dh, ddl);
|
||||
|
||||
if (ddl->state != DECT_DATA_LINK_RELEASED)
|
||||
dect_ddl_release(dh, ddl);
|
||||
else
|
||||
dect_ddl_destroy(dh, ddl);
|
||||
}
|
||||
|
||||
void dect_transaction_get_ulei(struct sockaddr_dect_lu *addr,
|
||||
|
|
Reference in New Issue