Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
77 changes: 55 additions & 22 deletions applications/serial_lte_modem/doc/PPP_AT_commands.rst
Original file line number Diff line number Diff line change
Expand Up @@ -27,53 +27,62 @@ Control PPP #XPPP
Set command
-----------

The set command allows you to start and stop PPP.
The set command allows you to start and stop PPP, and optionally define the PDN connection used for PPP.

.. note::

PPP is automatically started and stopped by SLM when the default PDN connection is established and lost, respectively.
PPP is automatically started and stopped by SLM when the PDN connection requested for PPP
is established and lost, respectively.
This happens even if PPP has previously been stopped or started with this command.

Syntax
~~~~~~

::

#XPPP=<op>
#XPPP=<op>[,<cid>]

* The ``<op>`` parameter can be the following:

* ``0`` - Stop PPP.
* ``1`` - Start PPP.

* The ``<cid>`` parameter is an integer indicating the PDN connection to be used for PPP.
It represents ``cid`` in the ``+CGDCONT`` command.
Its default value is ``0``, which represents the default PDN connection.

Unsolicited notification
~~~~~~~~~~~~~~~~~~~~~~~~

.. slm_ppp_status_notif_start

::

#XPPP: <running>,<peer_connected>
#XPPP: <running>,<peer_connected>,<cid>

* The ``<running>`` parameter is an integer that indicates whether PPP is running.
It is ``1`` for running or ``0`` for stopped.

* The ``<peer_connected>`` parameter is an integer that indicates whether a peer is connected to PPP.
It is ``1`` for connected or ``0`` for not connected.

* The ``<cid>`` parameter is an integer that indicates the PDN connection used for PPP.

.. slm_ppp_status_notif_end

Example
-------
Examples
--------

PPP with default PDN connection:

::

AT+CFUN=1

OK

// PPP is automatically started when the modem is registered to the network.
#XPPP: 1,0
// PPP is automatically started when the default PDN is activated.
#XPPP: 1,0,0

// Stop PPP.
AT#XPPP=0
Expand All @@ -87,25 +96,54 @@ Example

OK

#XPPP: 1,0
#XPPP: 1,0,0

// Have the peer connect to SLM's PPP.
#XPPP: 1,1
#XPPP: 1,1,0

// Peer disconnects.
#XPPP: 1,0
#XPPP: 1,0,0

// SLM restarts PPP automatically when peer disconnects.
#XPPP: 0,0
#XPPP: 0,0,0

#XPPP: 1,0
#XPPP: 1,0,0

AT+CFUN=4

OK

#XPPP: 0,0

PPP with non-default PDN connection:

::

// Exemplary PDN connection creation.
// Note: APN depends on operator and additional APNs may not be supported by the operator.
AT+CGDCONT=1,"IP","internet2"

OK

// Start PPP with the created PDN connection. This must be before AT+CFUN=1 command or
// otherwise PPP will be started for the default PDN connection.
AT#XPPP=1,1

OK

AT+CFUN=1

OK

// Activate the created PDN connection.
AT+CGACT=1,1

// PPP is automatically started when the PDN connection set for PPP has been activated.
#XPPP: 1,0,1

// Have the peer connect to SLM's PPP.
#XPPP: 1,1,1

Read command
------------

Expand All @@ -128,20 +166,15 @@ Response syntax
Testing on Linux
================

You can test SLM's PPP on Linux by using the ``pppd`` command, though SLM must be compiled without CMUX because there is no widely available utility that allows multiplexing a device file on Linux.

.. note::

If you have a utility that allows multiplexing a device file on Linux, you can use SLM's PPP with the ``pppd`` command through CMUX.
To do this, you must first set up the CMUX link.
Then, make sure to replace the device file argument in the ``pppd`` command with that of SLM's PPP channel, which will have been created by the CMUX utility.
See :ref:`SLM_AT_CMUX` for more information on SLM's CMUX.
You can test SLM's PPP on Linux by using the ``pppd`` command.
This section describes a configuration without CMUX.
If you are using CMUX, see :ref:`slm_as_linux_modem` for more information on setting it up.

For the process described here, SLM's UARTs must be connected to the Linux host.

1. Get PPP running on SLM.
To do this, start SLM and issue an ``AT+CFUN=1`` command.
#. Wait for ``#XPPP: 1,0``, which is sent when the network registration succeeds and PPP has started successfully.
#. Wait for ``#XPPP: 1,0,0``, which is sent when the network registration succeeds and PPP has started successfully with the default PDN connection.
#. Run the following command on the Linux host:

.. code-block:: console
Expand Down
85 changes: 59 additions & 26 deletions applications/serial_lte_modem/src/slm_ppp.c
Original file line number Diff line number Diff line change
Expand Up @@ -81,8 +81,8 @@ MODEM_PPP_DEFINE(ppp_module, NULL, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT,

static struct modem_pipe *ppp_pipe;

/* We use only the default PDP context. */
enum { PDP_CID = 0 };
/* Default PPP PDN is the default PDP context (CID 0). */
static unsigned int ppp_pdn_cid;

enum {
ZEPHYR_FD_IDX, /* Raw Zephyr socket to pass data to/from the PPP link. */
Expand Down Expand Up @@ -123,6 +123,18 @@ static bool open_ppp_sockets(void)
return false;
}

/* Bind PPP to PDN */
ret = zsock_setsockopt(
ppp_fds[MODEM_FD_IDX],
SOL_SOCKET, SO_BINDTOPDN,
&ppp_pdn_cid, sizeof(int));
if (ret == 0) {
LOG_INF("PPP socket bound to PDN %d", ppp_pdn_cid);
} else {
LOG_ERR("Failed to bind PPP to PDN %d (%d)", ppp_pdn_cid, -errno);
return false;
}

return true;
}

Expand All @@ -147,7 +159,7 @@ static bool configure_ppp_link_ip_addresses(struct ppp_context *ctx)
char addr4[INET_ADDRSTRLEN];
char addr6[INET6_ADDRSTRLEN];

util_get_ip_addr(PDP_CID, addr4, addr6);
util_get_ip_addr(ppp_pdn_cid, addr4, addr6);

if (*addr4) {
if (zsock_inet_pton(AF_INET, addr4, &ctx->ipcp.my_options.address) != 1) {
Expand Down Expand Up @@ -190,7 +202,7 @@ static bool ppp_is_running(void)

static void send_status_notification(void)
{
rsp_send("\r\n#XPPP: %u,%u\r\n", ppp_is_running(), ppp_peer_connected);
rsp_send("\r\n#XPPP: %u,%u,%u\r\n", ppp_is_running(), ppp_peer_connected, ppp_pdn_cid);
}

static int ppp_start_failure(int ret)
Expand All @@ -204,7 +216,7 @@ static unsigned int ppp_retrieve_mtu(void)
{
struct pdn_dynamic_info populated_info = { 0 };

if (!pdn_dynamic_info_get(PDP_CID, &populated_info)) {
if (!pdn_dynamic_info_get(ppp_pdn_cid, &populated_info)) {
if (populated_info.ipv6_mtu) {
/* Set the PPP MTU to that of the LTE link. */
/* IPv6's MTU has more priority on dual-stack.
Expand Down Expand Up @@ -339,24 +351,6 @@ static void ppp_stop(void)
}
}

/* Automatically starts/stops PPP when the default PDN connection goes up/down. */
static void pdp_ctx_event_handler(uint8_t cid, enum pdn_event event, int reason)
{
switch (event) {
case PDN_EVENT_ACTIVATED:
LOG_INF("Connection up. Starting PPP.");
k_work_submit_to_queue(&slm_work_q, &ppp_restart_work.work);
break;
case PDN_EVENT_DEACTIVATED:
LOG_DBG("Connection down.");
ppp_stop();
break;
default:
LOG_DBG("Default PDN connection event %d received.", event);
break;
}
}

/* We need to receive CGEV notifications at all times.
* CGEREP AT commands are intercepted to prevent the user
* from unsubcribing us and make that behavior invisible.
Expand Down Expand Up @@ -415,6 +409,39 @@ static void subscribe_cgev_notifications(void)
}
}

AT_MONITOR(slm_ppp_on_cgev, "CGEV", at_notif_on_cgev);

static void at_notif_on_cgev(const char *notify)
{
char *str;
char *endptr;
uint8_t cid;
char cgev_pdn_act[] = "+CGEV: ME PDN ACT";

/* +2 for space and a number */
if (strlen(cgev_pdn_act) + 2 > strlen(notify)) {
/* Ignore notifications that are not long enough to be what we are interested in */
return;
}

/* Only activation of PPP PDN is monitored here.
* Deactivation of PPP PDN or detach from network will cause PPP socket to get closed
* from where stopping of PPP is triggered.
*/
str = strstr(notify, cgev_pdn_act);
if (str != NULL) {
str += strlen(cgev_pdn_act);
if (*str == ' ') {
str++;
cid = (uint8_t)strtoul(str, &endptr, 10);
if (endptr != str && cid == ppp_pdn_cid) {
LOG_INF("PPP PDN (%d) activated. Starting PPP.", ppp_pdn_cid);
k_work_submit_to_queue(&slm_work_q, &ppp_restart_work.work);
}
}
}
}

/* Notification subscriptions are reset on CFUN=0.
* We intercept CFUN set commands to automatically subscribe.
*/
Expand Down Expand Up @@ -523,8 +550,6 @@ int slm_ppp_init(void)

net_if_flag_set(ppp_iface, NET_IF_POINTOPOINT);

pdn_default_ctx_cb_reg(pdp_ctx_event_handler);

{
static struct net_mgmt_event_callback ppp_net_mgmt_event_cb;

Expand Down Expand Up @@ -553,7 +578,7 @@ static int handle_at_ppp(enum at_parser_cmd_type cmd_type, struct at_parser *par
send_status_notification();
return 0;
}
if (cmd_type != AT_PARSER_CMD_TYPE_SET || param_count != 2) {
if (cmd_type != AT_PARSER_CMD_TYPE_SET || param_count < 2 || param_count > 3) {
return -EINVAL;
}

Expand All @@ -564,9 +589,16 @@ static int handle_at_ppp(enum at_parser_cmd_type cmd_type, struct at_parser *par
return -EINVAL;
}

if (op == OP_STOP && param_count != 2) {
return -EINVAL;
}

/* Send "OK" first in case stopping PPP results in the CMUX AT channel switching. */
rsp_send_ok();
if (op == OP_START) {
ppp_pdn_cid = 0;
/* Store PPP PDN if given */
at_parser_num_get(parser, 2, &ppp_pdn_cid);
k_work_submit_to_queue(&slm_work_q, &ppp_start_work.work);
} else {
k_work_submit_to_queue(&slm_work_q, &ppp_stop_work.work);
Expand Down Expand Up @@ -607,6 +639,7 @@ static void ppp_data_passing_thread(void*, void*, void*)
LOG_WRN("Unexpected event 0x%x on %s socket.",
revents, ppp_socket_names[src]);
}
LOG_DBG("Socket closed or connection down. Stopping PPP.");
ppp_stop();
return;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -221,7 +221,10 @@ nRF Machine Learning (Edge Impulse)
Serial LTE modem
----------------

|no_changes_yet_note|
* Updated:

* The ``AT#XPPP`` command to support the CID parameter to specify the PDN connection used for PPP.
* The ``#XPPP`` notification to include the CID of the PDN connection used for PPP.

Thingy:53: Matter weather station
---------------------------------
Expand Down