162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* net/atm/signaling.c - ATM signaling */ 362306a36Sopenharmony_ci 462306a36Sopenharmony_ci/* Written 1995-2000 by Werner Almesberger, EPFL LRC/ICA */ 562306a36Sopenharmony_ci 662306a36Sopenharmony_ci#define pr_fmt(fmt) KBUILD_MODNAME ":%s: " fmt, __func__ 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci#include <linux/errno.h> /* error codes */ 962306a36Sopenharmony_ci#include <linux/kernel.h> /* printk */ 1062306a36Sopenharmony_ci#include <linux/skbuff.h> 1162306a36Sopenharmony_ci#include <linux/wait.h> 1262306a36Sopenharmony_ci#include <linux/sched.h> /* jiffies and HZ */ 1362306a36Sopenharmony_ci#include <linux/atm.h> /* ATM stuff */ 1462306a36Sopenharmony_ci#include <linux/atmsap.h> 1562306a36Sopenharmony_ci#include <linux/atmsvc.h> 1662306a36Sopenharmony_ci#include <linux/atmdev.h> 1762306a36Sopenharmony_ci#include <linux/bitops.h> 1862306a36Sopenharmony_ci#include <linux/slab.h> 1962306a36Sopenharmony_ci 2062306a36Sopenharmony_ci#include "resources.h" 2162306a36Sopenharmony_ci#include "signaling.h" 2262306a36Sopenharmony_ci 2362306a36Sopenharmony_cistruct atm_vcc *sigd = NULL; 2462306a36Sopenharmony_ci 2562306a36Sopenharmony_cistatic void sigd_put_skb(struct sk_buff *skb) 2662306a36Sopenharmony_ci{ 2762306a36Sopenharmony_ci if (!sigd) { 2862306a36Sopenharmony_ci pr_debug("atmsvc: no signaling daemon\n"); 2962306a36Sopenharmony_ci kfree_skb(skb); 3062306a36Sopenharmony_ci return; 3162306a36Sopenharmony_ci } 3262306a36Sopenharmony_ci atm_force_charge(sigd, skb->truesize); 3362306a36Sopenharmony_ci skb_queue_tail(&sk_atm(sigd)->sk_receive_queue, skb); 3462306a36Sopenharmony_ci sk_atm(sigd)->sk_data_ready(sk_atm(sigd)); 3562306a36Sopenharmony_ci} 3662306a36Sopenharmony_ci 3762306a36Sopenharmony_cistatic void modify_qos(struct atm_vcc *vcc, struct atmsvc_msg *msg) 3862306a36Sopenharmony_ci{ 3962306a36Sopenharmony_ci struct sk_buff *skb; 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_ci if (test_bit(ATM_VF_RELEASED, &vcc->flags) || 4262306a36Sopenharmony_ci !test_bit(ATM_VF_READY, &vcc->flags)) 4362306a36Sopenharmony_ci return; 4462306a36Sopenharmony_ci msg->type = as_error; 4562306a36Sopenharmony_ci if (!vcc->dev->ops->change_qos) 4662306a36Sopenharmony_ci msg->reply = -EOPNOTSUPP; 4762306a36Sopenharmony_ci else { 4862306a36Sopenharmony_ci /* should lock VCC */ 4962306a36Sopenharmony_ci msg->reply = vcc->dev->ops->change_qos(vcc, &msg->qos, 5062306a36Sopenharmony_ci msg->reply); 5162306a36Sopenharmony_ci if (!msg->reply) 5262306a36Sopenharmony_ci msg->type = as_okay; 5362306a36Sopenharmony_ci } 5462306a36Sopenharmony_ci /* 5562306a36Sopenharmony_ci * Should probably just turn around the old skb. But then, the buffer 5662306a36Sopenharmony_ci * space accounting needs to follow the change too. Maybe later. 5762306a36Sopenharmony_ci */ 5862306a36Sopenharmony_ci while (!(skb = alloc_skb(sizeof(struct atmsvc_msg), GFP_KERNEL))) 5962306a36Sopenharmony_ci schedule(); 6062306a36Sopenharmony_ci *(struct atmsvc_msg *)skb_put(skb, sizeof(struct atmsvc_msg)) = *msg; 6162306a36Sopenharmony_ci sigd_put_skb(skb); 6262306a36Sopenharmony_ci} 6362306a36Sopenharmony_ci 6462306a36Sopenharmony_cistatic int sigd_send(struct atm_vcc *vcc, struct sk_buff *skb) 6562306a36Sopenharmony_ci{ 6662306a36Sopenharmony_ci struct atmsvc_msg *msg; 6762306a36Sopenharmony_ci struct atm_vcc *session_vcc; 6862306a36Sopenharmony_ci struct sock *sk; 6962306a36Sopenharmony_ci 7062306a36Sopenharmony_ci msg = (struct atmsvc_msg *) skb->data; 7162306a36Sopenharmony_ci WARN_ON(refcount_sub_and_test(skb->truesize, &sk_atm(vcc)->sk_wmem_alloc)); 7262306a36Sopenharmony_ci vcc = *(struct atm_vcc **) &msg->vcc; 7362306a36Sopenharmony_ci pr_debug("%d (0x%lx)\n", (int)msg->type, (unsigned long)vcc); 7462306a36Sopenharmony_ci sk = sk_atm(vcc); 7562306a36Sopenharmony_ci 7662306a36Sopenharmony_ci switch (msg->type) { 7762306a36Sopenharmony_ci case as_okay: 7862306a36Sopenharmony_ci sk->sk_err = -msg->reply; 7962306a36Sopenharmony_ci clear_bit(ATM_VF_WAITING, &vcc->flags); 8062306a36Sopenharmony_ci if (!*vcc->local.sas_addr.prv && !*vcc->local.sas_addr.pub) { 8162306a36Sopenharmony_ci vcc->local.sas_family = AF_ATMSVC; 8262306a36Sopenharmony_ci memcpy(vcc->local.sas_addr.prv, 8362306a36Sopenharmony_ci msg->local.sas_addr.prv, ATM_ESA_LEN); 8462306a36Sopenharmony_ci memcpy(vcc->local.sas_addr.pub, 8562306a36Sopenharmony_ci msg->local.sas_addr.pub, ATM_E164_LEN + 1); 8662306a36Sopenharmony_ci } 8762306a36Sopenharmony_ci session_vcc = vcc->session ? vcc->session : vcc; 8862306a36Sopenharmony_ci if (session_vcc->vpi || session_vcc->vci) 8962306a36Sopenharmony_ci break; 9062306a36Sopenharmony_ci session_vcc->itf = msg->pvc.sap_addr.itf; 9162306a36Sopenharmony_ci session_vcc->vpi = msg->pvc.sap_addr.vpi; 9262306a36Sopenharmony_ci session_vcc->vci = msg->pvc.sap_addr.vci; 9362306a36Sopenharmony_ci if (session_vcc->vpi || session_vcc->vci) 9462306a36Sopenharmony_ci session_vcc->qos = msg->qos; 9562306a36Sopenharmony_ci break; 9662306a36Sopenharmony_ci case as_error: 9762306a36Sopenharmony_ci clear_bit(ATM_VF_REGIS, &vcc->flags); 9862306a36Sopenharmony_ci clear_bit(ATM_VF_READY, &vcc->flags); 9962306a36Sopenharmony_ci sk->sk_err = -msg->reply; 10062306a36Sopenharmony_ci clear_bit(ATM_VF_WAITING, &vcc->flags); 10162306a36Sopenharmony_ci break; 10262306a36Sopenharmony_ci case as_indicate: 10362306a36Sopenharmony_ci vcc = *(struct atm_vcc **)&msg->listen_vcc; 10462306a36Sopenharmony_ci sk = sk_atm(vcc); 10562306a36Sopenharmony_ci pr_debug("as_indicate!!!\n"); 10662306a36Sopenharmony_ci lock_sock(sk); 10762306a36Sopenharmony_ci if (sk_acceptq_is_full(sk)) { 10862306a36Sopenharmony_ci sigd_enq(NULL, as_reject, vcc, NULL, NULL); 10962306a36Sopenharmony_ci dev_kfree_skb(skb); 11062306a36Sopenharmony_ci goto as_indicate_complete; 11162306a36Sopenharmony_ci } 11262306a36Sopenharmony_ci sk_acceptq_added(sk); 11362306a36Sopenharmony_ci skb_queue_tail(&sk->sk_receive_queue, skb); 11462306a36Sopenharmony_ci pr_debug("waking sk_sleep(sk) 0x%p\n", sk_sleep(sk)); 11562306a36Sopenharmony_ci sk->sk_state_change(sk); 11662306a36Sopenharmony_cias_indicate_complete: 11762306a36Sopenharmony_ci release_sock(sk); 11862306a36Sopenharmony_ci return 0; 11962306a36Sopenharmony_ci case as_close: 12062306a36Sopenharmony_ci set_bit(ATM_VF_RELEASED, &vcc->flags); 12162306a36Sopenharmony_ci vcc_release_async(vcc, msg->reply); 12262306a36Sopenharmony_ci goto out; 12362306a36Sopenharmony_ci case as_modify: 12462306a36Sopenharmony_ci modify_qos(vcc, msg); 12562306a36Sopenharmony_ci break; 12662306a36Sopenharmony_ci case as_addparty: 12762306a36Sopenharmony_ci case as_dropparty: 12862306a36Sopenharmony_ci WRITE_ONCE(sk->sk_err_soft, -msg->reply); 12962306a36Sopenharmony_ci /* < 0 failure, otherwise ep_ref */ 13062306a36Sopenharmony_ci clear_bit(ATM_VF_WAITING, &vcc->flags); 13162306a36Sopenharmony_ci break; 13262306a36Sopenharmony_ci default: 13362306a36Sopenharmony_ci pr_alert("bad message type %d\n", (int)msg->type); 13462306a36Sopenharmony_ci return -EINVAL; 13562306a36Sopenharmony_ci } 13662306a36Sopenharmony_ci sk->sk_state_change(sk); 13762306a36Sopenharmony_ciout: 13862306a36Sopenharmony_ci dev_kfree_skb(skb); 13962306a36Sopenharmony_ci return 0; 14062306a36Sopenharmony_ci} 14162306a36Sopenharmony_ci 14262306a36Sopenharmony_civoid sigd_enq2(struct atm_vcc *vcc, enum atmsvc_msg_type type, 14362306a36Sopenharmony_ci struct atm_vcc *listen_vcc, const struct sockaddr_atmpvc *pvc, 14462306a36Sopenharmony_ci const struct sockaddr_atmsvc *svc, const struct atm_qos *qos, 14562306a36Sopenharmony_ci int reply) 14662306a36Sopenharmony_ci{ 14762306a36Sopenharmony_ci struct sk_buff *skb; 14862306a36Sopenharmony_ci struct atmsvc_msg *msg; 14962306a36Sopenharmony_ci static unsigned int session = 0; 15062306a36Sopenharmony_ci 15162306a36Sopenharmony_ci pr_debug("%d (0x%p)\n", (int)type, vcc); 15262306a36Sopenharmony_ci while (!(skb = alloc_skb(sizeof(struct atmsvc_msg), GFP_KERNEL))) 15362306a36Sopenharmony_ci schedule(); 15462306a36Sopenharmony_ci msg = skb_put_zero(skb, sizeof(struct atmsvc_msg)); 15562306a36Sopenharmony_ci msg->type = type; 15662306a36Sopenharmony_ci *(struct atm_vcc **) &msg->vcc = vcc; 15762306a36Sopenharmony_ci *(struct atm_vcc **) &msg->listen_vcc = listen_vcc; 15862306a36Sopenharmony_ci msg->reply = reply; 15962306a36Sopenharmony_ci if (qos) 16062306a36Sopenharmony_ci msg->qos = *qos; 16162306a36Sopenharmony_ci if (vcc) 16262306a36Sopenharmony_ci msg->sap = vcc->sap; 16362306a36Sopenharmony_ci if (svc) 16462306a36Sopenharmony_ci msg->svc = *svc; 16562306a36Sopenharmony_ci if (vcc) 16662306a36Sopenharmony_ci msg->local = vcc->local; 16762306a36Sopenharmony_ci if (pvc) 16862306a36Sopenharmony_ci msg->pvc = *pvc; 16962306a36Sopenharmony_ci if (vcc) { 17062306a36Sopenharmony_ci if (type == as_connect && test_bit(ATM_VF_SESSION, &vcc->flags)) 17162306a36Sopenharmony_ci msg->session = ++session; 17262306a36Sopenharmony_ci /* every new pmp connect gets the next session number */ 17362306a36Sopenharmony_ci } 17462306a36Sopenharmony_ci sigd_put_skb(skb); 17562306a36Sopenharmony_ci if (vcc) 17662306a36Sopenharmony_ci set_bit(ATM_VF_REGIS, &vcc->flags); 17762306a36Sopenharmony_ci} 17862306a36Sopenharmony_ci 17962306a36Sopenharmony_civoid sigd_enq(struct atm_vcc *vcc, enum atmsvc_msg_type type, 18062306a36Sopenharmony_ci struct atm_vcc *listen_vcc, const struct sockaddr_atmpvc *pvc, 18162306a36Sopenharmony_ci const struct sockaddr_atmsvc *svc) 18262306a36Sopenharmony_ci{ 18362306a36Sopenharmony_ci sigd_enq2(vcc, type, listen_vcc, pvc, svc, vcc ? &vcc->qos : NULL, 0); 18462306a36Sopenharmony_ci /* other ISP applications may use "reply" */ 18562306a36Sopenharmony_ci} 18662306a36Sopenharmony_ci 18762306a36Sopenharmony_cistatic void purge_vcc(struct atm_vcc *vcc) 18862306a36Sopenharmony_ci{ 18962306a36Sopenharmony_ci if (sk_atm(vcc)->sk_family == PF_ATMSVC && 19062306a36Sopenharmony_ci !test_bit(ATM_VF_META, &vcc->flags)) { 19162306a36Sopenharmony_ci set_bit(ATM_VF_RELEASED, &vcc->flags); 19262306a36Sopenharmony_ci clear_bit(ATM_VF_REGIS, &vcc->flags); 19362306a36Sopenharmony_ci vcc_release_async(vcc, -EUNATCH); 19462306a36Sopenharmony_ci } 19562306a36Sopenharmony_ci} 19662306a36Sopenharmony_ci 19762306a36Sopenharmony_cistatic void sigd_close(struct atm_vcc *vcc) 19862306a36Sopenharmony_ci{ 19962306a36Sopenharmony_ci struct sock *s; 20062306a36Sopenharmony_ci int i; 20162306a36Sopenharmony_ci 20262306a36Sopenharmony_ci pr_debug("\n"); 20362306a36Sopenharmony_ci sigd = NULL; 20462306a36Sopenharmony_ci if (skb_peek(&sk_atm(vcc)->sk_receive_queue)) 20562306a36Sopenharmony_ci pr_err("closing with requests pending\n"); 20662306a36Sopenharmony_ci skb_queue_purge(&sk_atm(vcc)->sk_receive_queue); 20762306a36Sopenharmony_ci 20862306a36Sopenharmony_ci read_lock(&vcc_sklist_lock); 20962306a36Sopenharmony_ci for (i = 0; i < VCC_HTABLE_SIZE; ++i) { 21062306a36Sopenharmony_ci struct hlist_head *head = &vcc_hash[i]; 21162306a36Sopenharmony_ci 21262306a36Sopenharmony_ci sk_for_each(s, head) { 21362306a36Sopenharmony_ci vcc = atm_sk(s); 21462306a36Sopenharmony_ci 21562306a36Sopenharmony_ci purge_vcc(vcc); 21662306a36Sopenharmony_ci } 21762306a36Sopenharmony_ci } 21862306a36Sopenharmony_ci read_unlock(&vcc_sklist_lock); 21962306a36Sopenharmony_ci} 22062306a36Sopenharmony_ci 22162306a36Sopenharmony_cistatic const struct atmdev_ops sigd_dev_ops = { 22262306a36Sopenharmony_ci .close = sigd_close, 22362306a36Sopenharmony_ci .send = sigd_send 22462306a36Sopenharmony_ci}; 22562306a36Sopenharmony_ci 22662306a36Sopenharmony_cistatic struct atm_dev sigd_dev = { 22762306a36Sopenharmony_ci .ops = &sigd_dev_ops, 22862306a36Sopenharmony_ci .type = "sig", 22962306a36Sopenharmony_ci .number = 999, 23062306a36Sopenharmony_ci .lock = __SPIN_LOCK_UNLOCKED(sigd_dev.lock) 23162306a36Sopenharmony_ci}; 23262306a36Sopenharmony_ci 23362306a36Sopenharmony_ciint sigd_attach(struct atm_vcc *vcc) 23462306a36Sopenharmony_ci{ 23562306a36Sopenharmony_ci if (sigd) 23662306a36Sopenharmony_ci return -EADDRINUSE; 23762306a36Sopenharmony_ci pr_debug("\n"); 23862306a36Sopenharmony_ci sigd = vcc; 23962306a36Sopenharmony_ci vcc->dev = &sigd_dev; 24062306a36Sopenharmony_ci vcc_insert_socket(sk_atm(vcc)); 24162306a36Sopenharmony_ci set_bit(ATM_VF_META, &vcc->flags); 24262306a36Sopenharmony_ci set_bit(ATM_VF_READY, &vcc->flags); 24362306a36Sopenharmony_ci return 0; 24462306a36Sopenharmony_ci} 245