dect
/
libdect
Archived
13
0
Fork 0

lce: implement normal link release procedure

Signed-off-by: Patrick McHardy <kaber@trash.net>
This commit is contained in:
Patrick McHardy 2009-05-22 02:49:13 +02:00
parent dbf68ba8b3
commit 88c949c44e
2 changed files with 83 additions and 27 deletions

View File

@ -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 */

View File

@ -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,