2012-03-20 13:09:27 +00:00
|
|
|
#!/bin/sh
|
2010-05-01 17:54:37 +00:00
|
|
|
|
2012-03-20 13:09:27 +00:00
|
|
|
[ -x /usr/sbin/pppd ] || exit 0
|
2010-05-01 17:54:37 +00:00
|
|
|
|
2012-03-20 13:09:27 +00:00
|
|
|
[ -n "$INCLUDE_ONLY" ] || {
|
2012-06-05 16:04:23 +00:00
|
|
|
. /lib/functions.sh
|
2015-06-12 07:37:53 +00:00
|
|
|
. /lib/functions/network.sh
|
2012-03-20 13:09:27 +00:00
|
|
|
. ../netifd-proto.sh
|
|
|
|
init_proto "$@"
|
|
|
|
}
|
|
|
|
|
2015-06-12 07:37:53 +00:00
|
|
|
ppp_select_ipaddr()
|
|
|
|
{
|
|
|
|
local subnets=$1
|
|
|
|
local res
|
|
|
|
local res_mask
|
|
|
|
|
|
|
|
for subnet in $subnets; do
|
|
|
|
local addr="${subnet%%/*}"
|
|
|
|
local mask="${subnet#*/}"
|
|
|
|
|
|
|
|
if [ -n "$res_mask" -a "$mask" != 32 ]; then
|
|
|
|
[ "$mask" -gt "$res_mask" ] || [ "$res_mask" = 32 ] && {
|
|
|
|
res="$addr"
|
|
|
|
res_mask="$mask"
|
|
|
|
}
|
|
|
|
elif [ -z "$res_mask" ]; then
|
|
|
|
res="$addr"
|
|
|
|
res_mask="$mask"
|
|
|
|
fi
|
|
|
|
done
|
|
|
|
|
|
|
|
echo "$res"
|
|
|
|
}
|
|
|
|
|
2015-04-09 10:32:54 +00:00
|
|
|
ppp_exitcode_tostring()
|
|
|
|
{
|
|
|
|
local errorcode=$1
|
|
|
|
[ -n "$errorcode" ] || errorcode=5
|
|
|
|
|
|
|
|
case "$errorcode" in
|
|
|
|
0) echo "OK" ;;
|
|
|
|
1) echo "FATAL_ERROR" ;;
|
|
|
|
2) echo "OPTION_ERROR" ;;
|
|
|
|
3) echo "NOT_ROOT" ;;
|
|
|
|
4) echo "NO_KERNEL_SUPPORT" ;;
|
|
|
|
5) echo "USER_REQUEST" ;;
|
|
|
|
6) echo "LOCK_FAILED" ;;
|
|
|
|
7) echo "OPEN_FAILED" ;;
|
|
|
|
8) echo "CONNECT_FAILED" ;;
|
|
|
|
9) echo "PTYCMD_FAILED" ;;
|
|
|
|
10) echo "NEGOTIATION_FAILED" ;;
|
|
|
|
11) echo "PEER_AUTH_FAILED" ;;
|
|
|
|
12) echo "IDLE_TIMEOUT" ;;
|
|
|
|
13) echo "CONNECT_TIME" ;;
|
|
|
|
14) echo "CALLBACK" ;;
|
|
|
|
15) echo "PEER_DEAD" ;;
|
|
|
|
16) echo "HANGUP" ;;
|
|
|
|
17) echo "LOOPBACK" ;;
|
|
|
|
18) echo "INIT_FAILED" ;;
|
|
|
|
19) echo "AUTH_TOPEER_FAILED" ;;
|
|
|
|
20) echo "TRAFFIC_LIMIT" ;;
|
|
|
|
21) echo "CNID_AUTH_FAILED";;
|
|
|
|
*) echo "UNKNOWN_ERROR" ;;
|
|
|
|
esac
|
|
|
|
}
|
|
|
|
|
2012-03-20 13:09:27 +00:00
|
|
|
ppp_generic_init_config() {
|
2014-02-18 13:33:56 +00:00
|
|
|
proto_config_add_string username
|
|
|
|
proto_config_add_string password
|
|
|
|
proto_config_add_string keepalive
|
2014-11-01 12:37:03 +00:00
|
|
|
proto_config_add_boolean keepalive_adaptive
|
2014-02-18 13:33:56 +00:00
|
|
|
proto_config_add_int demand
|
|
|
|
proto_config_add_string pppd_options
|
|
|
|
proto_config_add_string 'connect:file'
|
|
|
|
proto_config_add_string 'disconnect:file'
|
2018-10-04 06:46:40 +00:00
|
|
|
[ -e /proc/sys/net/ipv6 ] && proto_config_add_string ipv6
|
2014-02-18 13:33:56 +00:00
|
|
|
proto_config_add_boolean authfail
|
|
|
|
proto_config_add_int mtu
|
2014-06-02 12:44:36 +00:00
|
|
|
proto_config_add_string pppname
|
2015-06-12 07:37:53 +00:00
|
|
|
proto_config_add_string unnumbered
|
2016-07-14 08:35:40 +00:00
|
|
|
proto_config_add_boolean persist
|
|
|
|
proto_config_add_int maxfail
|
|
|
|
proto_config_add_int holdoff
|
2012-03-20 13:09:27 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
ppp_generic_setup() {
|
|
|
|
local config="$1"; shift
|
2015-06-12 07:37:53 +00:00
|
|
|
local localip
|
2012-03-20 13:09:27 +00:00
|
|
|
|
2018-10-04 06:46:40 +00:00
|
|
|
json_get_vars ip6table demand keepalive keepalive_adaptive username password pppd_options pppname unnumbered persist maxfail holdoff peerdns
|
|
|
|
|
|
|
|
[ ! -e /proc/sys/net/ipv6 ] && ipv6=0 || json_get_var ipv6 ipv6
|
|
|
|
|
2014-08-13 10:18:20 +00:00
|
|
|
if [ "$ipv6" = 0 ]; then
|
|
|
|
ipv6=""
|
2014-10-08 20:37:15 +00:00
|
|
|
elif [ -z "$ipv6" -o "$ipv6" = auto ]; then
|
2014-08-13 10:18:20 +00:00
|
|
|
ipv6=1
|
2015-09-15 14:52:47 +00:00
|
|
|
autoipv6=1
|
2014-08-13 10:18:20 +00:00
|
|
|
fi
|
2014-10-08 20:37:15 +00:00
|
|
|
|
2012-03-20 13:09:27 +00:00
|
|
|
if [ "${demand:-0}" -gt 0 ]; then
|
|
|
|
demand="precompiled-active-filter /etc/ppp/filter demand idle $demand"
|
|
|
|
else
|
2015-05-09 21:14:46 +00:00
|
|
|
demand=""
|
2012-03-20 13:09:27 +00:00
|
|
|
fi
|
2016-07-14 08:35:40 +00:00
|
|
|
if [ -n "$persist" ]; then
|
|
|
|
[ "${persist}" -lt 1 ] && persist="nopersist" || persist="persist"
|
|
|
|
fi
|
|
|
|
if [ -z "$maxfail" ]; then
|
|
|
|
[ "$persist" = "persist" ] && maxfail=0 || maxfail=1
|
|
|
|
fi
|
2012-03-20 13:09:27 +00:00
|
|
|
[ -n "$mtu" ] || json_get_var mtu mtu
|
2014-06-02 12:44:36 +00:00
|
|
|
[ -n "$pppname" ] || pppname="${proto:-ppp}-$config"
|
2015-06-12 07:37:53 +00:00
|
|
|
[ -n "$unnumbered" ] && {
|
|
|
|
local subnets
|
|
|
|
( proto_add_host_dependency "$config" "" "$unnumbered" )
|
|
|
|
network_get_subnets subnets "$unnumbered"
|
|
|
|
localip=$(ppp_select_ipaddr "$subnets")
|
|
|
|
[ -n "$localip" ] || {
|
|
|
|
proto_block_restart "$config"
|
|
|
|
return
|
|
|
|
}
|
|
|
|
}
|
2010-05-05 23:24:11 +00:00
|
|
|
|
2018-08-30 13:08:20 +00:00
|
|
|
[ -n "$keepalive" ] || keepalive="5 1"
|
|
|
|
|
2014-11-01 12:37:03 +00:00
|
|
|
local lcp_failure="${keepalive%%[, ]*}"
|
|
|
|
local lcp_interval="${keepalive##*[, ]}"
|
|
|
|
local lcp_adaptive="lcp-echo-adaptive"
|
|
|
|
[ "${lcp_failure:-0}" -lt 1 ] && lcp_failure=""
|
|
|
|
[ "$lcp_interval" != "$keepalive" ] || lcp_interval=5
|
|
|
|
[ "${keepalive_adaptive:-1}" -lt 1 ] && lcp_adaptive=""
|
2012-03-20 13:09:27 +00:00
|
|
|
[ -n "$connect" ] || json_get_var connect connect
|
|
|
|
[ -n "$disconnect" ] || json_get_var disconnect disconnect
|
|
|
|
|
|
|
|
proto_run_command "$config" /usr/sbin/pppd \
|
|
|
|
nodetach ipparam "$config" \
|
2014-06-02 12:44:36 +00:00
|
|
|
ifname "$pppname" \
|
2015-06-12 07:37:53 +00:00
|
|
|
${localip:+$localip:} \
|
2014-11-01 12:37:03 +00:00
|
|
|
${lcp_failure:+lcp-echo-interval $lcp_interval lcp-echo-failure $lcp_failure $lcp_adaptive} \
|
2012-12-06 18:17:21 +00:00
|
|
|
${ipv6:++ipv6} \
|
2015-09-15 14:52:47 +00:00
|
|
|
${autoipv6:+set AUTOIPV6=1} \
|
2017-02-10 13:28:09 +00:00
|
|
|
${ip6table:+set IP6TABLE=$ip6table} \
|
2017-03-06 12:47:50 +00:00
|
|
|
${peerdns:+set PEERDNS=$peerdns} \
|
2012-12-06 18:17:21 +00:00
|
|
|
nodefaultroute \
|
|
|
|
usepeerdns \
|
2016-07-14 08:35:40 +00:00
|
|
|
$demand $persist maxfail $maxfail \
|
|
|
|
${holdoff:+holdoff "$holdoff"} \
|
2012-03-20 13:09:27 +00:00
|
|
|
${username:+user "$username" password "$password"} \
|
|
|
|
${connect:+connect "$connect"} \
|
|
|
|
${disconnect:+disconnect "$disconnect"} \
|
|
|
|
ip-up-script /lib/netifd/ppp-up \
|
2018-10-04 06:46:40 +00:00
|
|
|
${ipv6:+ipv6-up-script /lib/netifd/ppp6-up} \
|
2012-03-20 13:09:27 +00:00
|
|
|
ip-down-script /lib/netifd/ppp-down \
|
2018-10-04 06:46:40 +00:00
|
|
|
${ipv6:+ipv6-down-script /lib/netifd/ppp-down} \
|
2012-03-20 13:09:27 +00:00
|
|
|
${mtu:+mtu $mtu mru $mtu} \
|
2013-11-25 14:09:16 +00:00
|
|
|
"$@" $pppd_options
|
2006-07-30 03:09:09 +00:00
|
|
|
}
|
|
|
|
|
2012-03-20 13:09:27 +00:00
|
|
|
ppp_generic_teardown() {
|
|
|
|
local interface="$1"
|
2015-04-09 10:32:54 +00:00
|
|
|
local errorstring=$(ppp_exitcode_tostring $ERROR)
|
2009-09-06 17:36:01 +00:00
|
|
|
|
2012-03-20 13:09:27 +00:00
|
|
|
case "$ERROR" in
|
2015-04-09 10:32:54 +00:00
|
|
|
0)
|
|
|
|
;;
|
|
|
|
2)
|
|
|
|
proto_notify_error "$interface" "$errorstring"
|
|
|
|
proto_block_restart "$interface"
|
|
|
|
;;
|
2012-03-20 13:09:27 +00:00
|
|
|
11|19)
|
2012-08-29 10:07:08 +00:00
|
|
|
json_get_var authfail authfail
|
2015-04-09 10:32:54 +00:00
|
|
|
proto_notify_error "$interface" "$errorstring"
|
2012-08-29 10:07:08 +00:00
|
|
|
if [ "${authfail:-0}" -gt 0 ]; then
|
|
|
|
proto_block_restart "$interface"
|
|
|
|
fi
|
2012-03-20 13:09:27 +00:00
|
|
|
;;
|
2015-04-09 10:32:54 +00:00
|
|
|
*)
|
|
|
|
proto_notify_error "$interface" "$errorstring"
|
2012-06-10 12:12:10 +00:00
|
|
|
;;
|
2011-10-04 23:10:36 +00:00
|
|
|
esac
|
2015-04-09 10:32:54 +00:00
|
|
|
|
2012-03-20 13:09:27 +00:00
|
|
|
proto_kill_command "$interface"
|
|
|
|
}
|
2011-10-04 23:10:36 +00:00
|
|
|
|
2012-03-20 13:09:27 +00:00
|
|
|
# PPP on serial device
|
2010-05-01 17:54:37 +00:00
|
|
|
|
2012-03-20 13:09:27 +00:00
|
|
|
proto_ppp_init_config() {
|
|
|
|
proto_config_add_string "device"
|
|
|
|
ppp_generic_init_config
|
|
|
|
no_device=1
|
|
|
|
available=1
|
2015-04-09 10:32:54 +00:00
|
|
|
lasterror=1
|
2012-03-20 13:09:27 +00:00
|
|
|
}
|
2006-10-26 01:33:36 +00:00
|
|
|
|
2012-03-20 13:09:27 +00:00
|
|
|
proto_ppp_setup() {
|
|
|
|
local config="$1"
|
2006-10-24 23:59:08 +00:00
|
|
|
|
2012-03-20 13:09:27 +00:00
|
|
|
json_get_var device device
|
|
|
|
ppp_generic_setup "$config" "$device"
|
|
|
|
}
|
2007-12-13 05:50:24 +00:00
|
|
|
|
2012-03-20 13:09:27 +00:00
|
|
|
proto_ppp_teardown() {
|
|
|
|
ppp_generic_teardown "$@"
|
|
|
|
}
|
2010-05-01 11:08:03 +00:00
|
|
|
|
2012-03-20 13:09:27 +00:00
|
|
|
proto_pppoe_init_config() {
|
|
|
|
ppp_generic_init_config
|
|
|
|
proto_config_add_string "ac"
|
|
|
|
proto_config_add_string "service"
|
2015-01-24 11:30:45 +00:00
|
|
|
proto_config_add_string "host_uniq"
|
2019-05-29 16:51:20 +00:00
|
|
|
proto_config_add_int "padi_attempts"
|
|
|
|
proto_config_add_int "padi_timeout"
|
|
|
|
|
2015-04-09 10:32:54 +00:00
|
|
|
lasterror=1
|
2012-03-20 13:09:27 +00:00
|
|
|
}
|
2010-05-01 11:08:03 +00:00
|
|
|
|
2012-03-20 13:09:27 +00:00
|
|
|
proto_pppoe_setup() {
|
|
|
|
local config="$1"
|
|
|
|
local iface="$2"
|
2010-05-01 11:08:03 +00:00
|
|
|
|
2012-03-20 13:09:27 +00:00
|
|
|
for module in slhc ppp_generic pppox pppoe; do
|
|
|
|
/sbin/insmod $module 2>&- >&-
|
|
|
|
done
|
2007-05-01 21:53:32 +00:00
|
|
|
|
2012-03-20 13:09:27 +00:00
|
|
|
json_get_var mtu mtu
|
|
|
|
mtu="${mtu:-1492}"
|
2010-05-01 11:08:03 +00:00
|
|
|
|
2012-03-20 13:09:27 +00:00
|
|
|
json_get_var ac ac
|
|
|
|
json_get_var service service
|
2014-11-14 16:39:59 +00:00
|
|
|
json_get_var host_uniq host_uniq
|
2019-05-29 16:51:20 +00:00
|
|
|
json_get_var padi_attempts padi_attempts
|
|
|
|
json_get_var padi_timeout padi_timeout
|
2010-05-01 11:08:03 +00:00
|
|
|
|
2012-03-20 13:09:27 +00:00
|
|
|
ppp_generic_setup "$config" \
|
|
|
|
plugin rp-pppoe.so \
|
|
|
|
${ac:+rp_pppoe_ac "$ac"} \
|
|
|
|
${service:+rp_pppoe_service "$service"} \
|
2015-01-24 11:30:45 +00:00
|
|
|
${host_uniq:+host-uniq "$host_uniq"} \
|
2019-05-29 16:51:20 +00:00
|
|
|
${padi_attempts:+pppoe-padi-attempts $padi_attempts} \
|
|
|
|
${padi_timeout:+pppoe-padi-timeout $padi_timeout} \
|
2015-01-24 11:30:45 +00:00
|
|
|
"nic-$iface"
|
2012-03-20 13:09:27 +00:00
|
|
|
}
|
2010-05-01 11:08:03 +00:00
|
|
|
|
2012-03-20 13:09:27 +00:00
|
|
|
proto_pppoe_teardown() {
|
|
|
|
ppp_generic_teardown "$@"
|
|
|
|
}
|
2007-05-01 21:53:32 +00:00
|
|
|
|
2012-03-20 13:09:27 +00:00
|
|
|
proto_pppoa_init_config() {
|
|
|
|
ppp_generic_init_config
|
|
|
|
proto_config_add_int "atmdev"
|
|
|
|
proto_config_add_int "vci"
|
|
|
|
proto_config_add_int "vpi"
|
|
|
|
proto_config_add_string "encaps"
|
2012-06-09 23:16:26 +00:00
|
|
|
no_device=1
|
|
|
|
available=1
|
2015-04-09 10:32:54 +00:00
|
|
|
lasterror=1
|
2012-03-20 13:09:27 +00:00
|
|
|
}
|
2008-03-07 11:18:54 +00:00
|
|
|
|
2012-03-20 13:09:27 +00:00
|
|
|
proto_pppoa_setup() {
|
|
|
|
local config="$1"
|
|
|
|
local iface="$2"
|
2006-10-26 01:33:36 +00:00
|
|
|
|
2012-03-20 13:09:27 +00:00
|
|
|
for module in slhc ppp_generic pppox pppoatm; do
|
|
|
|
/sbin/insmod $module 2>&- >&-
|
|
|
|
done
|
2007-05-01 21:53:32 +00:00
|
|
|
|
2012-05-14 20:58:24 +00:00
|
|
|
json_get_vars atmdev vci vpi encaps
|
2007-05-01 21:53:32 +00:00
|
|
|
|
2012-03-20 13:09:27 +00:00
|
|
|
case "$encaps" in
|
|
|
|
1|vc) encaps="vc-encaps" ;;
|
|
|
|
*) encaps="llc-encaps" ;;
|
|
|
|
esac
|
|
|
|
|
|
|
|
ppp_generic_setup "$config" \
|
|
|
|
plugin pppoatm.so \
|
|
|
|
${atmdev:+$atmdev.}${vpi:-8}.${vci:-35} \
|
|
|
|
${encaps}
|
|
|
|
}
|
2007-05-01 21:53:32 +00:00
|
|
|
|
2012-03-20 13:09:27 +00:00
|
|
|
proto_pppoa_teardown() {
|
|
|
|
ppp_generic_teardown "$@"
|
|
|
|
}
|
2010-05-01 11:08:03 +00:00
|
|
|
|
2012-06-11 20:07:46 +00:00
|
|
|
proto_pptp_init_config() {
|
|
|
|
ppp_generic_init_config
|
|
|
|
proto_config_add_string "server"
|
2015-02-22 08:29:34 +00:00
|
|
|
proto_config_add_string "interface"
|
2012-06-11 20:07:46 +00:00
|
|
|
available=1
|
|
|
|
no_device=1
|
2015-04-09 10:32:54 +00:00
|
|
|
lasterror=1
|
2012-06-11 20:07:46 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
proto_pptp_setup() {
|
|
|
|
local config="$1"
|
|
|
|
local iface="$2"
|
|
|
|
|
2015-02-22 08:29:34 +00:00
|
|
|
local ip serv_addr server interface
|
|
|
|
json_get_vars interface server
|
|
|
|
[ -n "$server" ] && {
|
2012-06-11 20:07:46 +00:00
|
|
|
for ip in $(resolveip -t 5 "$server"); do
|
2015-02-22 08:29:34 +00:00
|
|
|
( proto_add_host_dependency "$config" "$ip" $interface )
|
2012-06-11 20:07:46 +00:00
|
|
|
serv_addr=1
|
|
|
|
done
|
|
|
|
}
|
|
|
|
[ -n "$serv_addr" ] || {
|
|
|
|
echo "Could not resolve server address"
|
|
|
|
sleep 5
|
|
|
|
proto_setup_failed "$config"
|
|
|
|
exit 1
|
|
|
|
}
|
|
|
|
|
|
|
|
local load
|
|
|
|
for module in slhc ppp_generic ppp_async ppp_mppe ip_gre gre pptp; do
|
ppp: correct module loaded check in proto_pptp_setup
proto_pptp_setup is responsible for loading the required modules to establish
a pptp connection to a foreign peer. The function checks whether all required
modules are already loaded, before actually loading them.
It seems that the filter being used to accomplish this, is not restrictive
enough in some cases. For instance when pptp nat helper modules are present on
a system, and already loaded before a pptp connection is enabled. Then the
search filter (possibly) returns the following for module=pptp, where actually
no matches are expected, resulting in the pptp.ko module not being loaded,
thereby failing to establish the pptp connection.
# module="pptp" ; grep "$module" /proc/modules
nf_nat_pptp 1312 0 - Live 0x86ce7000
nf_conntrack_pptp 3072 1 nf_nat_pptp, Live 0x86cb9000
nf_nat_proto_gre 784 1 nf_nat_pptp, Live 0x86cba000
nf_conntrack_proto_gre 2368 1 nf_conntrack_pptp, Live 0x86cbf000
nf_nat 9792 13 nf_nat_rtsp,nf_nat_tftp,nf_nat_sip,nf_nat_pptp,nf_nat_h323,nf_nat_proto_gre,nf_nat_amanda,nf_nat_irc,nf_nat_ftp,ipt_REDIRECT,ipt_NETMAP,ipt_MASQUERADE,iptable_nat, Live 0x86ca8000
nf_conntrack 37264 31 nf_nat_rtsp,nf_conntrack_rtsp,nf_nat_tftp,nf_conntrack_tftp,nf_nat_snmp_basic,nf_conntrack_snmp,nf_nat_sip,nf_conntrack_sip,nf_nat_pptp,nf_conntrack_pptp,nf_nat_h323,nf_conntrack_h323,nf_conntrack_proto_gre,nf_nat_amanda,nf_conntrack_amanda,nf_conntrack_broadcast,nf_nat_irc,nf_conntrack_irc,nf_nat_ftp,nf_conntrack_ftp,ipt_MASQUERADE,iptable_nat,nf_nat,xt_helper,xt_connmark,xt_connbytes,xt_conntrack,xt_CT,xt_NOTRACK,xt_state,nf_conntrack_ipv4, Live 0x86c90000
The search filter can be made more accurate/restrictive, by requiring the
occurance of the exact name of the module at the beginning of a line in
/proc/modules.
# module="pptp" ; grep "^$module " /proc/modules
pptp 13296 2 - Live 0x86e80000
Signed-off-by: Tijs Van Buggenhout <tvb@able.be>
SVN-Revision: 38358
2013-10-10 14:58:12 +00:00
|
|
|
grep -q "^$module " /proc/modules && continue
|
2012-06-11 20:07:46 +00:00
|
|
|
/sbin/insmod $module 2>&- >&-
|
|
|
|
load=1
|
|
|
|
done
|
|
|
|
[ "$load" = "1" ] && sleep 1
|
|
|
|
|
|
|
|
ppp_generic_setup "$config" \
|
|
|
|
plugin pptp.so \
|
|
|
|
pptp_server $server \
|
|
|
|
file /etc/ppp/options.pptp
|
|
|
|
}
|
|
|
|
|
|
|
|
proto_pptp_teardown() {
|
|
|
|
ppp_generic_teardown "$@"
|
|
|
|
}
|
|
|
|
|
2012-03-20 13:09:27 +00:00
|
|
|
[ -n "$INCLUDE_ONLY" ] || {
|
|
|
|
add_protocol ppp
|
|
|
|
[ -f /usr/lib/pppd/*/rp-pppoe.so ] && add_protocol pppoe
|
|
|
|
[ -f /usr/lib/pppd/*/pppoatm.so ] && add_protocol pppoa
|
2012-06-11 20:07:46 +00:00
|
|
|
[ -f /usr/lib/pppd/*/pptp.so ] && add_protocol pptp
|
2007-05-01 21:53:32 +00:00
|
|
|
}
|
|
|
|
|