dect
/
libdect
Archived
13
0
Fork 0
This repository has been archived on 2022-02-17. You can view files and clone it, but cannot push or open issues or pull requests.
libdect/src/ss.c

388 lines
12 KiB
C

/*
* DECT Supplementary Services (SS)
*
* Copyright (c) 2009-2010 Patrick McHardy <kaber@trash.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
/**
* @defgroup ss Supplementary Services
* @{
*/
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <linux/dect.h>
#include <libdect.h>
#include <utils.h>
#include <io.h>
#include <s_fmt.h>
#include <lce.h>
#include <ss.h>
static DECT_SFMT_MSG_DESC(ciss_register,
DECT_SFMT_IE(DECT_IE_PORTABLE_IDENTITY, IE_OPTIONAL, IE_MANDATORY, 0),
DECT_SFMT_IE(DECT_IE_REPEAT_INDICATOR, IE_OPTIONAL, IE_OPTIONAL, 0),
DECT_SFMT_IE(DECT_IE_FACILITY, IE_OPTIONAL, IE_OPTIONAL, DECT_SFMT_IE_REPEAT),
DECT_SFMT_IE(DECT_IE_SINGLE_DISPLAY, IE_OPTIONAL, IE_NONE, 0),
DECT_SFMT_IE(DECT_IE_SINGLE_KEYPAD, IE_NONE, IE_OPTIONAL, 0),
DECT_SFMT_IE(DECT_IE_FEATURE_ACTIVATE, IE_NONE, IE_OPTIONAL, 0),
DECT_SFMT_IE(DECT_IE_FEATURE_INDICATE, IE_OPTIONAL, IE_NONE, 0),
DECT_SFMT_IE(DECT_IE_ESCAPE_TO_PROPRIETARY, IE_OPTIONAL, IE_OPTIONAL, 0),
DECT_SFMT_IE_END_MSG
);
static DECT_SFMT_MSG_DESC(ciss_release_com,
DECT_SFMT_IE(DECT_IE_RELEASE_REASON, IE_OPTIONAL, IE_OPTIONAL, 0),
DECT_SFMT_IE(DECT_IE_REPEAT_INDICATOR, IE_OPTIONAL, IE_OPTIONAL, 0),
DECT_SFMT_IE(DECT_IE_FACILITY, IE_OPTIONAL, IE_OPTIONAL, DECT_SFMT_IE_REPEAT),
DECT_SFMT_IE(DECT_IE_SINGLE_DISPLAY, IE_OPTIONAL, IE_NONE, 0),
DECT_SFMT_IE(DECT_IE_SINGLE_KEYPAD, IE_NONE, IE_OPTIONAL, 0),
DECT_SFMT_IE(DECT_IE_FEATURE_ACTIVATE, IE_NONE, IE_OPTIONAL, 0),
DECT_SFMT_IE(DECT_IE_FEATURE_INDICATE, IE_OPTIONAL, IE_NONE, 0),
DECT_SFMT_IE(DECT_IE_ESCAPE_TO_PROPRIETARY, IE_OPTIONAL, IE_OPTIONAL, 0),
DECT_SFMT_IE_END_MSG
);
static DECT_SFMT_MSG_DESC(ciss_facility,
DECT_SFMT_IE(DECT_IE_REPEAT_INDICATOR, IE_OPTIONAL, IE_OPTIONAL, 0),
DECT_SFMT_IE(DECT_IE_FACILITY, IE_OPTIONAL, IE_OPTIONAL, DECT_SFMT_IE_REPEAT),
DECT_SFMT_IE(DECT_IE_SINGLE_DISPLAY, IE_OPTIONAL, IE_NONE, 0),
DECT_SFMT_IE(DECT_IE_SINGLE_KEYPAD, IE_NONE, IE_OPTIONAL, 0),
DECT_SFMT_IE(DECT_IE_FEATURE_ACTIVATE, IE_NONE, IE_OPTIONAL, 0),
DECT_SFMT_IE(DECT_IE_FEATURE_INDICATE, IE_OPTIONAL, IE_NONE, 0),
DECT_SFMT_IE(DECT_IE_REPEAT_INDICATOR, IE_OPTIONAL, IE_OPTIONAL, 0),
DECT_SFMT_IE(DECT_IE_IWU_TO_IWU, IE_OPTIONAL, IE_OPTIONAL, DECT_SFMT_IE_REPEAT),
DECT_SFMT_IE(DECT_IE_ESCAPE_TO_PROPRIETARY, IE_OPTIONAL, IE_OPTIONAL, 0),
DECT_SFMT_IE(DECT_IE_TIME_DATE, IE_OPTIONAL, IE_OPTIONAL, 0),
DECT_SFMT_IE(DECT_IE_EVENTS_NOTIFICATION, IE_OPTIONAL, IE_OPTIONAL, 0),
DECT_SFMT_IE(DECT_IE_CALL_INFORMATION, IE_OPTIONAL, IE_OPTIONAL, 0),
DECT_SFMT_IE_END_MSG
);
#define __ss_debug(pfx, fmt, args...) \
dect_debug(DECT_DEBUG_SS, "%sSS (link %d): " fmt "\n", pfx, \
(sse)->transaction.link && (sse)->transaction.link->dfd ? \
(sse)->transaction.link->dfd->fd : -1, \
## args)
#define ss_debug(sse, fmt, args...) \
__ss_debug("", fmt, ## args)
#define ss_debug_entry(sse, fmt, args...) \
__ss_debug("\n", fmt, ## args)
void dect_clss_rcv(struct dect_handle *dh, struct dect_msg_buf *mb)
{
struct dect_ciss_facility_msg msg;
if (mb->type != DECT_CISS_FACILITY)
return;
if (dect_parse_sfmt_msg(dh, &ciss_facility_msg_desc, &msg.common, mb) < 0)
return;
dect_msg_free(dh, &ciss_facility_msg_desc, &msg.common);
}
/**
* Get a pointer to the private data area from a Supplementary Services Endpoint
*
* @param sse Supplementary Services Endpoint
*/
void *dect_ss_priv(struct dect_ss_endpoint *sse)
{
return sse->priv;
}
EXPORT_SYMBOL(dect_ss_priv);
struct dect_ss_endpoint *dect_ss_endpoint_alloc(struct dect_handle *dh,
const struct dect_ipui *ipui)
{
struct dect_ss_endpoint *sse;
sse = dect_zalloc(dh, sizeof(*sse) + dh->ops->ss_ops->priv_size);
if (sse == NULL)
goto err1;
sse->ipui = *ipui;
return sse;
err1:
return NULL;
}
EXPORT_SYMBOL(dect_ss_endpoint_alloc);
void dect_ss_endpoint_destroy(struct dect_handle *dh, struct dect_ss_endpoint *sse)
{
dect_free(dh, sse);
}
EXPORT_SYMBOL(dect_ss_endpoint_destroy);
static struct dect_ss_endpoint *dect_ss_endpoint(struct dect_transaction *ta)
{
return container_of(ta, struct dect_ss_endpoint, transaction);
}
/**
* MNSS_SETUP-req primitive
*
* @param dh libdect DECT handle
* @param sse Supplementary Services Endpoint
* @param ipui PT IPUI
* @param param Supplementary Services parameters
*/
int dect_mnss_setup_req(struct dect_handle *dh, struct dect_ss_endpoint *sse,
const struct dect_mnss_param *param)
{
struct dect_ie_portable_identity portable_identity;
struct dect_ciss_register_msg msg = {
.facility = param->facility,
.display = param->display,
.keypad = param->keypad,
.feature_activate = param->feature_activate,
.feature_indicate = param->feature_indicate,
};
ss_debug_entry(sse, "MNSS_SETUP-req");
if (dect_transaction_open(dh, &sse->transaction, &sse->ipui,
DECT_PD_CISS) < 0)
goto err1;
if (dh->mode == DECT_MODE_PP) {
portable_identity.type = DECT_PORTABLE_ID_TYPE_IPUI;
portable_identity.ipui = sse->ipui;
msg.portable_identity = &portable_identity;
}
if (dect_lce_send(dh, &sse->transaction, &ciss_register_msg_desc,
&msg.common, DECT_CISS_REGISTER) < 0)
goto err2;
return 0;
err2:
dect_transaction_close(dh, &sse->transaction, DECT_DDL_RELEASE_NORMAL);
err1:
return -1;
}
EXPORT_SYMBOL(dect_mnss_setup_req);
/**
* MNSS_FACILITY-req primitive
*
* @param dh libdect DECT handle
* @param sse Supplementary Services Endpoint
* @param param Supplementary Services parameters
*/
int dect_mnss_facility_req(struct dect_handle *dh, struct dect_ss_endpoint *sse,
const struct dect_mnss_param *param)
{
struct dect_ciss_facility_msg msg = {
.facility = param->facility,
.display = param->display,
.keypad = param->keypad,
.feature_activate = param->feature_activate,
.feature_indicate = param->feature_indicate,
.iwu_to_iwu = param->iwu_to_iwu,
.escape_to_proprietary = param->escape_to_proprietary,
.time_date = param->time_date,
.events_notification = param->events_notification,
.call_information = param->call_information,
};
ss_debug_entry(sse, "MNSS_FACILITY-req");
if (sse->transaction.link != NULL)
return dect_lce_send(dh, &sse->transaction, &ciss_facility_msg_desc,
&msg.common, DECT_CISS_FACILITY);
else
return dect_lce_send_cl(dh, &sse->ipui, &ciss_facility_msg_desc,
&msg.common, DECT_PD_CISS,
DECT_CISS_FACILITY);
}
EXPORT_SYMBOL(dect_mnss_facility_req);
static void dect_ciss_rcv_facility(struct dect_handle *dh,
struct dect_ss_endpoint *sse,
struct dect_msg_buf *mb)
{
struct dect_ciss_facility_msg msg;
struct dect_mnss_param *param;
ss_debug(sse, "CISS-FACILITY");
if (dect_parse_sfmt_msg(dh, &ciss_facility_msg_desc, &msg.common, mb) < 0)
return;
param = dect_ie_collection_alloc(dh, sizeof(*param));
if (param == NULL)
goto out;
param->facility = *dect_ie_list_hold(&msg.facility);
param->display = dect_ie_hold(msg.display);
param->keypad = dect_ie_hold(msg.keypad);
param->feature_activate = dect_ie_hold(msg.feature_activate);
param->feature_indicate = dect_ie_hold(msg.feature_indicate);
param->escape_to_proprietary = dect_ie_hold(msg.escape_to_proprietary);
ss_debug(sse, "MNSS_FACILITY-ind");
dh->ops->ss_ops->mnss_facility_ind(dh, sse, param);
dect_ie_collection_put(dh, param);
out:
dect_msg_free(dh, &ciss_facility_msg_desc, &msg.common);
}
/**
* MNSS_RELEASE-req primitive
*
* @param dh libdect DECT handle
* @param sse Supplementary Services Endpoint
* @param param Supplementary Services parameters
*/
int dect_mnss_release_req(struct dect_handle *dh, struct dect_ss_endpoint *sse,
const struct dect_mnss_param *param)
{
struct dect_ciss_release_com_msg msg = {
.facility = param->facility,
.display = param->display,
.keypad = param->keypad,
.feature_activate = param->feature_activate,
.feature_indicate = param->feature_indicate,
};
ss_debug_entry(sse, "MNSS_RELEASE-req");
return dect_lce_send(dh, &sse->transaction, &ciss_release_com_msg_desc,
&msg.common, DECT_CISS_RELEASE_COM);
}
EXPORT_SYMBOL(dect_mnss_release_req);
static void dect_ciss_rcv_release_com(struct dect_handle *dh,
struct dect_ss_endpoint *sse,
struct dect_msg_buf *mb)
{
struct dect_ciss_release_com_msg msg;
struct dect_mnss_param *param;
ss_debug(sse, "CISS-RELEASE-COM");
if (dect_parse_sfmt_msg(dh, &ciss_release_com_msg_desc, &msg.common, mb) < 0)
return;
param = dect_ie_collection_alloc(dh, sizeof(*param));
if (param == NULL)
goto out;
param->release_reason = dect_ie_hold(msg.release_reason);
param->facility = *dect_ie_list_hold(&msg.facility);
param->display = dect_ie_hold(msg.display);
param->keypad = dect_ie_hold(msg.keypad);
param->feature_activate = dect_ie_hold(msg.feature_activate);
param->feature_indicate = dect_ie_hold(msg.feature_indicate);
param->escape_to_proprietary = dect_ie_hold(msg.escape_to_proprietary);
ss_debug(sse, "MNSS_RELEASE-ind");
dh->ops->ss_ops->mnss_release_ind(dh, sse, param);
dect_ie_collection_put(dh, param);
dect_transaction_close(dh, &sse->transaction, DECT_DDL_RELEASE_PARTIAL);
dect_ss_endpoint_destroy(dh, sse);
out:
dect_msg_free(dh, &ciss_release_com_msg_desc, &msg.common);
}
static void dect_ciss_rcv(struct dect_handle *dh, struct dect_transaction *ta,
struct dect_msg_buf *mb)
{
struct dect_ss_endpoint *sse = dect_ss_endpoint(ta);
switch (mb->type) {
case DECT_CISS_FACILITY:
return dect_ciss_rcv_facility(dh, sse, mb);
case DECT_CISS_RELEASE_COM:
return dect_ciss_rcv_release_com(dh, sse, mb);
}
ss_debug(sse, "receive unknown msg type %x", mb->type);
}
static void dect_ciss_rcv_register(struct dect_handle *dh,
const struct dect_transaction *req,
struct dect_msg_buf *mb)
{
struct dect_ciss_register_msg msg;
struct dect_mnss_param *param;
struct dect_ss_endpoint *sse;
dect_debug(DECT_DEBUG_SS, "CISS-REGISTER\n");
if (dect_parse_sfmt_msg(dh, &ciss_register_msg_desc, &msg.common, mb) < 0)
return;
if (msg.portable_identity->type != DECT_PORTABLE_ID_TYPE_IPUI &&
msg.portable_identity->type != DECT_PORTABLE_ID_TYPE_IPEI)
goto out;
if (dect_ddl_set_ipui(dh, req->link, &msg.portable_identity->ipui) < 0)
goto out;
sse = dect_ss_endpoint_alloc(dh, &msg.portable_identity->ipui);
if (sse == NULL)
goto out;
param = dect_ie_collection_alloc(dh, sizeof(*param));
if (param == NULL)
goto out;
param->facility = *dect_ie_list_hold(&msg.facility);
param->display = dect_ie_hold(msg.display);
param->keypad = dect_ie_hold(msg.keypad);
param->feature_activate = dect_ie_hold(msg.feature_activate);
param->feature_indicate = dect_ie_hold(msg.feature_indicate);
param->escape_to_proprietary = dect_ie_hold(msg.escape_to_proprietary);
dect_transaction_confirm(dh, &sse->transaction, req);
ss_debug(sse, "MNSS_SETUP-ind");
dh->ops->ss_ops->mnss_setup_ind(dh, sse, param);
dect_ie_collection_put(dh, param);
out:
dect_msg_free(dh, &ciss_register_msg_desc, &msg.common);
}
static void dect_ciss_open(struct dect_handle *dh,
struct dect_transaction *req,
struct dect_msg_buf *mb)
{
dect_debug(DECT_DEBUG_SS, "SS: unknown transaction: msg type: %x\n", mb->type);
switch (mb->type) {
case DECT_CISS_REGISTER:
return dect_ciss_rcv_register(dh, req, mb);
default:
return;
}
}
static void dect_ciss_shutdown(struct dect_handle *dh,
struct dect_transaction *ta)
{
struct dect_ss_endpoint *sse = dect_ss_endpoint(ta);
ss_debug(sse, "shutdown");
dect_transaction_close(dh, &sse->transaction, DECT_DDL_RELEASE_NORMAL);
dect_ss_endpoint_destroy(dh, sse);
}
const struct dect_nwk_protocol dect_ciss_protocol = {
.name = "Call Independant Supplementary Services",
.pd = DECT_PD_CISS,
.max_transactions = 7,
.open = dect_ciss_open,
.shutdown = dect_ciss_shutdown,
.rcv = dect_ciss_rcv,
};
/** @} */