Merge branch 'atm-remove-more-dead-code'

Jakub Kicinski says:

====================
atm: remove more dead code

Commit 6deb535950 ("net: remove unused ATM protocols and legacy
ATM device drivers") removed a good chunk of old ATM drivers.
Our goal going forward is to limit the ATM support to PPPoATM
used in ADSL deployments.

A recent burst of AI generated fixes for net/atm/signaling.c and
net/atm/svc.c made me look closer at the remaining code. PPPoATM runs
over permanent virtual circuits (PF_ATMPVC) with a statically
configured VPI/VCI. We can drop switched virtual circuits (SVCs)
and user-space signaling (atmsigd) support. While digging around
I noticed a few more obviously dead pieces of code.

Annoyingly, I have applied one "fix" to QoS config which will
now make net conflict with this series :/
====================

Link: https://patch.msgid.link/20260615194416.752559-1-kuba@kernel.org
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
Jakub Kicinski 2026-06-16 08:53:56 -07:00
commit e1f544466b
31 changed files with 15 additions and 2189 deletions

View File

@ -1180,10 +1180,6 @@ static const struct atmdev_ops fpga_ops = {
.close = pclose,
.ioctl = NULL,
.send = psend,
.send_oam = NULL,
.phy_put = NULL,
.phy_get = NULL,
.change_qos = NULL,
.proc_read = NULL,
.owner = THIS_MODULE
};

View File

@ -1,24 +0,0 @@
/* SPDX-License-Identifier: GPL-2.0 */
/* atm_tcp.h - Driver-specific declarations of the ATMTCP driver (for use by
driver-specific utilities) */
/* Written 1997-2000 by Werner Almesberger, EPFL LRC/ICA */
#ifndef LINUX_ATM_TCP_H
#define LINUX_ATM_TCP_H
#include <uapi/linux/atm_tcp.h>
struct atm_vcc;
struct module;
struct atm_tcp_ops {
int (*attach)(struct atm_vcc *vcc,int itf);
int (*create_persistent)(int itf);
int (*remove_persistent)(int itf);
struct module *owner;
};
extern struct atm_tcp_ops atm_tcp_ops;
#endif

View File

@ -51,33 +51,11 @@ enum {
driver, cleared by anybody. */
ATM_VF_PARTIAL, /* resources are bound to PVC (partial PVC
setup), controlled by socket layer */
ATM_VF_REGIS, /* registered with demon, controlled by SVC
socket layer */
ATM_VF_BOUND, /* local SAP is set, controlled by SVC socket
layer */
ATM_VF_RELEASED, /* demon has indicated/requested release,
controlled by SVC socket layer */
ATM_VF_HASQOS, /* QOS parameters have been set */
ATM_VF_LISTEN, /* socket is used for listening */
ATM_VF_META, /* SVC socket isn't used for normal data
traffic and doesn't depend on signaling
to be available */
ATM_VF_SESSION, /* VCC is p2mp session control descriptor */
ATM_VF_HASSAP, /* SAP has been set */
ATM_VF_CLOSE, /* asynchronous close - treat like VF_RELEASED*/
ATM_VF_WAITING, /* waiting for reply from sigd */
ATM_VF_IS_CLIP, /* in use by CLIP protocol */
ATM_VF_CLOSE, /* asynchronous close - VC is being torn down */
};
#define ATM_VF2VS(flags) \
(test_bit(ATM_VF_READY,&(flags)) ? ATM_VS_CONNECTED : \
test_bit(ATM_VF_RELEASED,&(flags)) ? ATM_VS_CLOSING : \
test_bit(ATM_VF_LISTEN,&(flags)) ? ATM_VS_LISTEN : \
test_bit(ATM_VF_REGIS,&(flags)) ? ATM_VS_INUSE : \
test_bit(ATM_VF_BOUND,&(flags)) ? ATM_VS_BOUND : ATM_VS_IDLE)
enum {
ATM_DF_REMOVED, /* device was removed from atm_devs list */
};
@ -100,26 +78,16 @@ struct atm_vcc {
unsigned long atm_options; /* ATM layer options */
struct atm_dev *dev; /* device back pointer */
struct atm_qos qos; /* QOS */
struct atm_sap sap; /* SAP */
void (*release_cb)(struct atm_vcc *vcc); /* release_sock callback */
void (*push)(struct atm_vcc *vcc,struct sk_buff *skb);
void (*pop)(struct atm_vcc *vcc,struct sk_buff *skb); /* optional */
int (*push_oam)(struct atm_vcc *vcc,void *cell);
int (*send)(struct atm_vcc *vcc,struct sk_buff *skb);
void *dev_data; /* per-device data */
void *proto_data; /* per-protocol data */
struct k_atm_aal_stats *stats; /* pointer to AAL stats group */
struct module *owner; /* owner of ->push function */
/* SVC part --- may move later ------------------------------------- */
short itf; /* interface number */
struct sockaddr_atmsvc local;
struct sockaddr_atmsvc remote;
/* Multipoint part ------------------------------------------------- */
struct atm_vcc *session; /* session VCC descriptor */
/* Other stuff ----------------------------------------------------- */
void *user_back; /* user backlink - not touched by */
/* native ATM stack. Currently used */
/* by CLIP and sch_atm. */
void *user_back; /* user backlink - not touched by the */
/* native ATM stack, used by sch_atm */
};
static inline struct atm_vcc *atm_sk(struct sock *sk)
@ -137,31 +105,19 @@ static inline struct sock *sk_atm(struct atm_vcc *vcc)
return (struct sock *)vcc;
}
struct atm_dev_addr {
struct sockaddr_atmsvc addr; /* ATM address */
struct list_head entry; /* next address */
};
enum atm_addr_type_t { ATM_ADDR_LOCAL, ATM_ADDR_LECS };
struct atm_dev {
const struct atmdev_ops *ops; /* device operations; NULL if unused */
const struct atmphy_ops *phy; /* PHY operations, may be undefined */
/* (NULL) */
const char *type; /* device type name */
int number; /* device index */
void *dev_data; /* per-device data */
void *phy_data; /* private PHY data */
unsigned long flags; /* device flags (ATM_DF_*) */
struct list_head local; /* local ATM addresses */
struct list_head lecs; /* LECS ATM addresses learned via ILMI */
unsigned char esi[ESI_LEN]; /* ESI ("MAC" addr) */
struct atm_cirange ci_range; /* VPI/VCI range */
struct k_atm_dev_stats stats; /* statistics */
char signal; /* signal status (ATM_PHY_SIG_*) */
int link_rate; /* link rate (default: OC3) */
refcount_t refcnt; /* reference count */
spinlock_t lock; /* protect internal members */
#ifdef CONFIG_PROC_FS
struct proc_dir_entry *proc_entry; /* proc entry */
char *proc_name; /* proc entry name */
@ -170,12 +126,6 @@ struct atm_dev {
struct list_head dev_list; /* linkage */
};
/* OF: send_Oam Flags */
#define ATM_OF_IMMED 1 /* Attempt immediate delivery */
#define ATM_OF_INRATE 2 /* Attempt in-rate delivery */
struct atmdev_ops { /* only send is required */
void (*dev_close)(struct atm_dev *dev);
int (*open)(struct atm_vcc *vcc);
@ -185,25 +135,11 @@ struct atmdev_ops { /* only send is required */
int (*compat_ioctl)(struct atm_dev *dev,unsigned int cmd,
void __user *arg);
#endif
int (*pre_send)(struct atm_vcc *vcc, struct sk_buff *skb);
int (*send)(struct atm_vcc *vcc,struct sk_buff *skb);
int (*send_bh)(struct atm_vcc *vcc, struct sk_buff *skb);
int (*send_oam)(struct atm_vcc *vcc,void *cell,int flags);
void (*phy_put)(struct atm_dev *dev,unsigned char value,
unsigned long addr);
unsigned char (*phy_get)(struct atm_dev *dev,unsigned long addr);
int (*change_qos)(struct atm_vcc *vcc,struct atm_qos *qos,int flags);
int (*proc_read)(struct atm_dev *dev,loff_t *pos,char *page);
struct module *owner;
};
struct atmphy_ops {
int (*start)(struct atm_dev *dev);
int (*ioctl)(struct atm_dev *dev,unsigned int cmd,void __user *arg);
void (*interrupt)(struct atm_dev *dev);
int (*stop)(struct atm_dev *dev);
};
struct atm_skb_data {
struct atm_vcc *vcc; /* ATM VCC */
unsigned long atm_options; /* ATM layer options */

View File

@ -1,24 +0,0 @@
/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
/* atm_eni.h - Driver-specific declarations of the ENI driver (for use by
driver-specific utilities) */
/* Written 1995-2000 by Werner Almesberger, EPFL LRC/ICA */
#ifndef LINUX_ATM_ENI_H
#define LINUX_ATM_ENI_H
#include <linux/atmioc.h>
struct eni_multipliers {
int tx,rx; /* values are in percent and must be > 100 */
};
#define ENI_MEMDUMP _IOW('a',ATMIOC_SARPRV,struct atmif_sioc)
/* printk memory map */
#define ENI_SETMULT _IOW('a',ATMIOC_SARPRV+7,struct atmif_sioc)
/* set buffer multipliers */
#endif

View File

@ -1,21 +0,0 @@
/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
/* atm_he.h */
#ifndef LINUX_ATM_HE_H
#define LINUX_ATM_HE_H
#include <linux/atmioc.h>
#define HE_GET_REG _IOW('a', ATMIOC_SARPRV, struct atmif_sioc)
#define HE_REGTYPE_PCI 1
#define HE_REGTYPE_RCM 2
#define HE_REGTYPE_TCM 3
#define HE_REGTYPE_MBOX 4
struct he_ioctl_reg {
unsigned addr, val;
char type;
};
#endif /* LINUX_ATM_HE_H */

View File

@ -1,29 +0,0 @@
/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
/* atm_idt77105.h - Driver-specific declarations of the IDT77105 driver (for
* use by driver-specific utilities) */
/* Written 1999 by Greg Banks <gnb@linuxfan.com>. Copied from atm_suni.h. */
#ifndef LINUX_ATM_IDT77105_H
#define LINUX_ATM_IDT77105_H
#include <linux/types.h>
#include <linux/atmioc.h>
#include <linux/atmdev.h>
/*
* Structure for IDT77105_GETSTAT and IDT77105_GETSTATZ ioctls.
* Pointed to by `arg' in atmif_sioc.
*/
struct idt77105_stats {
__u32 symbol_errors; /* wire symbol errors */
__u32 tx_cells; /* cells transmitted */
__u32 rx_cells; /* cells received */
__u32 rx_hec_errors; /* Header Error Check errors on receive */
};
#define IDT77105_GETSTAT _IOW('a',ATMIOC_PHYPRV+2,struct atmif_sioc) /* get stats */
#define IDT77105_GETSTATZ _IOW('a',ATMIOC_PHYPRV+3,struct atmif_sioc) /* get stats and zero */
#endif

View File

@ -1,54 +0,0 @@
/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
/******************************************************************************
*
* atm_nicstar.h
*
* Driver-specific declarations for use by NICSTAR driver specific utils.
*
* Author: Rui Prior
*
* (C) INESC 1998
*
******************************************************************************/
#ifndef LINUX_ATM_NICSTAR_H
#define LINUX_ATM_NICSTAR_H
/* Note: non-kernel programs including this file must also include
* sys/types.h for struct timeval
*/
#include <linux/atmapi.h>
#include <linux/atmioc.h>
#define NS_GETPSTAT _IOWR('a',ATMIOC_SARPRV+1,struct atmif_sioc)
/* get pool statistics */
#define NS_SETBUFLEV _IOW('a',ATMIOC_SARPRV+2,struct atmif_sioc)
/* set buffer level markers */
#define NS_ADJBUFLEV _IO('a',ATMIOC_SARPRV+3)
/* adjust buffer level */
typedef struct buf_nr
{
unsigned min;
unsigned init;
unsigned max;
}buf_nr;
typedef struct pool_levels
{
int buftype;
int count; /* (At least for now) only used in NS_GETPSTAT */
buf_nr level;
} pool_levels;
/* type must be one of the following: */
#define NS_BUFTYPE_SMALL 1
#define NS_BUFTYPE_LARGE 2
#define NS_BUFTYPE_HUGE 3
#define NS_BUFTYPE_IOVEC 4
#endif /* LINUX_ATM_NICSTAR_H */

View File

@ -1,62 +0,0 @@
/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
/* atm_tcp.h - Driver-specific declarations of the ATMTCP driver (for use by
driver-specific utilities) */
/* Written 1997-2000 by Werner Almesberger, EPFL LRC/ICA */
#ifndef _UAPILINUX_ATM_TCP_H
#define _UAPILINUX_ATM_TCP_H
#include <linux/atmapi.h>
#include <linux/atm.h>
#include <linux/atmioc.h>
#include <linux/types.h>
/*
* All values in struct atmtcp_hdr are in network byte order
*/
struct atmtcp_hdr {
__u16 vpi;
__u16 vci;
__u32 length; /* ... of data part */
};
/*
* All values in struct atmtcp_command are in host byte order
*/
#define ATMTCP_HDR_MAGIC (~0) /* this length indicates a command */
#define ATMTCP_CTRL_OPEN 1 /* request/reply */
#define ATMTCP_CTRL_CLOSE 2 /* request/reply */
struct atmtcp_control {
struct atmtcp_hdr hdr; /* must be first */
int type; /* message type; both directions */
atm_kptr_t vcc; /* both directions */
struct sockaddr_atmpvc addr; /* suggested value from kernel */
struct atm_qos qos; /* both directions */
int result; /* to kernel only */
} __ATM_API_ALIGN;
/*
* Field usage:
* Messge type dir. hdr.v?i type addr qos vcc result
* ----------- ---- ------- ---- ---- --- --- ------
* OPEN K->D Y Y Y Y Y 0
* OPEN D->K - Y Y Y Y Y
* CLOSE K->D - - Y - Y 0
* CLOSE D->K - - - - Y Y
*/
#define SIOCSIFATMTCP _IO('a',ATMIOC_ITF) /* set ATMTCP mode */
#define ATMTCP_CREATE _IO('a',ATMIOC_ITF+14) /* create persistent ATMTCP
interface */
#define ATMTCP_REMOVE _IO('a',ATMIOC_ITF+15) /* destroy persistent ATMTCP
interface */
#endif /* _UAPILINUX_ATM_TCP_H */

View File

@ -1,47 +0,0 @@
/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
/* atm_zatm.h - Driver-specific declarations of the ZATM driver (for use by
driver-specific utilities) */
/* Written 1995-1999 by Werner Almesberger, EPFL LRC/ICA */
#ifndef LINUX_ATM_ZATM_H
#define LINUX_ATM_ZATM_H
/*
* Note: non-kernel programs including this file must also include
* sys/types.h for struct timeval
*/
#include <linux/atmapi.h>
#include <linux/atmioc.h>
#define ZATM_GETPOOL _IOW('a',ATMIOC_SARPRV+1,struct atmif_sioc)
/* get pool statistics */
#define ZATM_GETPOOLZ _IOW('a',ATMIOC_SARPRV+2,struct atmif_sioc)
/* get statistics and zero */
#define ZATM_SETPOOL _IOW('a',ATMIOC_SARPRV+3,struct atmif_sioc)
/* set pool parameters */
struct zatm_pool_info {
int ref_count; /* free buffer pool usage counters */
int low_water,high_water; /* refill parameters */
int rqa_count,rqu_count; /* queue condition counters */
int offset,next_off; /* alignment optimizations: offset */
int next_cnt,next_thres; /* repetition counter and threshold */
};
struct zatm_pool_req {
int pool_num; /* pool number */
struct zatm_pool_info info; /* actual information */
};
#define ZATM_OAM_POOL 0 /* free buffer pool for OAM cells */
#define ZATM_AAL0_POOL 1 /* free buffer pool for AAL0 cells */
#define ZATM_AAL5_POOL_BASE 2 /* first AAL5 free buffer pool */
#define ZATM_LAST_POOL ZATM_AAL5_POOL_BASE+10 /* max. 64 kB */
#define ZATM_TIMER_HISTORY_SIZE 16 /* number of timer adjustments to
record; must be 2^n */
#endif

View File

@ -1,42 +0,0 @@
/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
/* atmarp.h - ATM ARP protocol and kernel-demon interface definitions */
/* Written 1995-1999 by Werner Almesberger, EPFL LRC/ICA */
#ifndef _LINUX_ATMARP_H
#define _LINUX_ATMARP_H
#include <linux/types.h>
#include <linux/atmapi.h>
#include <linux/atmioc.h>
#define ATMARP_RETRY_DELAY 30 /* request next resolution or forget
NAK after 30 sec - should go into
atmclip.h */
#define ATMARP_MAX_UNRES_PACKETS 5 /* queue that many packets while
waiting for the resolver */
#define ATMARPD_CTRL _IO('a',ATMIOC_CLIP+1) /* become atmarpd ctrl sock */
#define ATMARP_MKIP _IO('a',ATMIOC_CLIP+2) /* attach socket to IP */
#define ATMARP_SETENTRY _IO('a',ATMIOC_CLIP+3) /* fill or hide ARP entry */
#define ATMARP_ENCAP _IO('a',ATMIOC_CLIP+5) /* change encapsulation */
enum atmarp_ctrl_type {
act_invalid, /* catch uninitialized structures */
act_need, /* need address resolution */
act_up, /* interface is coming up */
act_down, /* interface is going down */
act_change /* interface configuration has changed */
};
struct atmarp_ctrl {
enum atmarp_ctrl_type type; /* message type */
int itf_num;/* interface number (if present) */
__be32 ip; /* IP address (act_need only) */
};
#endif

View File

@ -1,22 +0,0 @@
/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
/* atmclip.h - Classical IP over ATM */
/* Written 1995-1998 by Werner Almesberger, EPFL LRC/ICA */
#ifndef LINUX_ATMCLIP_H
#define LINUX_ATMCLIP_H
#include <linux/sockios.h>
#include <linux/atmioc.h>
#define RFC1483LLC_LEN 8 /* LLC+OUI+PID = 8 */
#define RFC1626_MTU 9180 /* RFC1626 default MTU */
#define CLIP_DEFAULT_IDLETIMER 1200 /* 20 minutes, see RFC1755 */
#define CLIP_CHECK_INTERVAL 10 /* check every ten seconds */
#define SIOCMKCLIP _IO('a',ATMIOC_CLIP) /* create IP interface */
#endif

View File

@ -60,14 +60,6 @@ struct atm_dev_stats {
/* get interface type name */
#define ATM_GETESI _IOW('a',ATMIOC_ITF+5,struct atmif_sioc)
/* get interface ESI */
#define ATM_GETADDR _IOW('a',ATMIOC_ITF+6,struct atmif_sioc)
/* get itf's local ATM addr. list */
#define ATM_RSTADDR _IOW('a',ATMIOC_ITF+7,struct atmif_sioc)
/* reset itf's ATM address list */
#define ATM_ADDADDR _IOW('a',ATMIOC_ITF+8,struct atmif_sioc)
/* add a local ATM address */
#define ATM_DELADDR _IOW('a',ATMIOC_ITF+9,struct atmif_sioc)
/* remove a local ATM address */
#define ATM_GETCIRANGE _IOW('a',ATMIOC_ITF+10,struct atmif_sioc)
/* get connection identifier range */
#define ATM_SETCIRANGE _IOW('a',ATMIOC_ITF+11,struct atmif_sioc)
@ -76,12 +68,6 @@ struct atm_dev_stats {
/* set interface ESI */
#define ATM_SETESIF _IOW('a',ATMIOC_ITF+13,struct atmif_sioc)
/* force interface ESI */
#define ATM_ADDLECSADDR _IOW('a', ATMIOC_ITF+14, struct atmif_sioc)
/* register a LECS address */
#define ATM_DELLECSADDR _IOW('a', ATMIOC_ITF+15, struct atmif_sioc)
/* unregister a LECS address */
#define ATM_GETLECSADDR _IOW('a', ATMIOC_ITF+16, struct atmif_sioc)
/* retrieve LECS address(es) */
#define ATM_GETSTAT _IOW('a',ATMIOC_SARCOM+0,struct atmif_sioc)
/* get AAL layer statistics */
@ -99,10 +85,6 @@ struct atm_dev_stats {
/* set backend handler */
#define ATM_NEWBACKENDIF _IOW('a',ATMIOC_SPECIAL+3,atm_backend_t)
/* use backend to make new if */
#define ATM_ADDPARTY _IOW('a', ATMIOC_SPECIAL+4,struct atm_iobuf)
/* add party to p2mp call */
#define ATM_DROPPARTY _IOW('a', ATMIOC_SPECIAL+5,int)
/* drop party from p2mp call */
/*
* These are backend handkers that can be set via the ATM_SETBACKEND call

View File

@ -1,92 +0,0 @@
/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
/*
* ATM Lan Emulation Daemon driver interface
*
* Marko Kiiskila <mkiiskila@yahoo.com>
*/
#ifndef _ATMLEC_H_
#define _ATMLEC_H_
#include <linux/atmapi.h>
#include <linux/atmioc.h>
#include <linux/atm.h>
#include <linux/if_ether.h>
#include <linux/types.h>
/* ATM lec daemon control socket */
#define ATMLEC_CTRL _IO('a', ATMIOC_LANE)
#define ATMLEC_DATA _IO('a', ATMIOC_LANE+1)
#define ATMLEC_MCAST _IO('a', ATMIOC_LANE+2)
/* Maximum number of LEC interfaces (tweakable) */
#define MAX_LEC_ITF 48
typedef enum {
l_set_mac_addr,
l_del_mac_addr,
l_svc_setup,
l_addr_delete,
l_topology_change,
l_flush_complete,
l_arp_update,
l_narp_req, /* LANE2 mandates the use of this */
l_config,
l_flush_tran_id,
l_set_lecid,
l_arp_xmt,
l_rdesc_arp_xmt,
l_associate_req,
l_should_bridge /* should we bridge this MAC? */
} atmlec_msg_type;
#define ATMLEC_MSG_TYPE_MAX l_should_bridge
struct atmlec_config_msg {
unsigned int maximum_unknown_frame_count;
unsigned int max_unknown_frame_time;
unsigned short max_retry_count;
unsigned int aging_time;
unsigned int forward_delay_time;
unsigned int arp_response_time;
unsigned int flush_timeout;
unsigned int path_switching_delay;
unsigned int lane_version; /* LANE2: 1 for LANEv1, 2 for LANEv2 */
int mtu;
int is_proxy;
};
struct atmlec_msg {
atmlec_msg_type type;
int sizeoftlvs; /* LANE2: if != 0, tlvs follow */
union {
struct {
unsigned char mac_addr[ETH_ALEN];
unsigned char atm_addr[ATM_ESA_LEN];
unsigned int flag; /*
* Topology_change flag,
* remoteflag, permanent flag,
* lecid, transaction id
*/
unsigned int targetless_le_arp; /* LANE2 */
unsigned int no_source_le_narp; /* LANE2 */
} normal;
struct atmlec_config_msg config;
struct {
__u16 lec_id; /* requestor lec_id */
__u32 tran_id; /* transaction id */
unsigned char mac_addr[ETH_ALEN]; /* dst mac addr */
unsigned char atm_addr[ATM_ESA_LEN]; /* reqestor ATM addr */
} proxy; /*
* For mapping LE_ARP requests to responses. Filled by
* zeppelin, returned by kernel. Used only when proxying
*/
} content;
} __ATM_API_ALIGN;
struct atmlec_ioc {
int dev_num;
unsigned char atm_addr[ATM_ESA_LEN];
unsigned char receive; /* 1= receive vcc, 0 = send vcc */
};
#endif /* _ATMLEC_H_ */

View File

@ -1,127 +0,0 @@
/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
#ifndef _ATMMPC_H_
#define _ATMMPC_H_
#include <linux/atmapi.h>
#include <linux/atmioc.h>
#include <linux/atm.h>
#include <linux/types.h>
#define ATMMPC_CTRL _IO('a', ATMIOC_MPOA)
#define ATMMPC_DATA _IO('a', ATMIOC_MPOA+1)
#define MPC_SOCKET_INGRESS 1
#define MPC_SOCKET_EGRESS 2
struct atmmpc_ioc {
int dev_num;
__be32 ipaddr; /* the IP address of the shortcut */
int type; /* ingress or egress */
};
typedef struct in_ctrl_info {
__u8 Last_NHRP_CIE_code;
__u8 Last_Q2931_cause_value;
__u8 eg_MPC_ATM_addr[ATM_ESA_LEN];
__be32 tag;
__be32 in_dst_ip; /* IP address this ingress MPC sends packets to */
__u16 holding_time;
__u32 request_id;
} in_ctrl_info;
typedef struct eg_ctrl_info {
__u8 DLL_header[256];
__u8 DH_length;
__be32 cache_id;
__be32 tag;
__be32 mps_ip;
__be32 eg_dst_ip; /* IP address to which ingress MPC sends packets */
__u8 in_MPC_data_ATM_addr[ATM_ESA_LEN];
__u16 holding_time;
} eg_ctrl_info;
struct mpc_parameters {
__u16 mpc_p1; /* Shortcut-Setup Frame Count */
__u16 mpc_p2; /* Shortcut-Setup Frame Time */
__u8 mpc_p3[8]; /* Flow-detection Protocols */
__u16 mpc_p4; /* MPC Initial Retry Time */
__u16 mpc_p5; /* MPC Retry Time Maximum */
__u16 mpc_p6; /* Hold Down Time */
} ;
struct k_message {
__u16 type;
__be32 ip_mask;
__u8 MPS_ctrl[ATM_ESA_LEN];
union {
in_ctrl_info in_info;
eg_ctrl_info eg_info;
struct mpc_parameters params;
} content;
struct atm_qos qos;
} __ATM_API_ALIGN;
struct llc_snap_hdr {
/* RFC 1483 LLC/SNAP encapsulation for routed IP PDUs */
__u8 dsap; /* Destination Service Access Point (0xAA) */
__u8 ssap; /* Source Service Access Point (0xAA) */
__u8 ui; /* Unnumbered Information (0x03) */
__u8 org[3]; /* Organizational identification (0x000000) */
__u8 type[2]; /* Ether type (for IP) (0x0800) */
};
/* TLVs this MPC recognizes */
#define TLV_MPOA_DEVICE_TYPE 0x00a03e2a
/* MPOA device types in MPOA Device Type TLV */
#define NON_MPOA 0
#define MPS 1
#define MPC 2
#define MPS_AND_MPC 3
/* MPC parameter defaults */
#define MPC_P1 10 /* Shortcut-Setup Frame Count */
#define MPC_P2 1 /* Shortcut-Setup Frame Time */
#define MPC_P3 0 /* Flow-detection Protocols */
#define MPC_P4 5 /* MPC Initial Retry Time */
#define MPC_P5 40 /* MPC Retry Time Maximum */
#define MPC_P6 160 /* Hold Down Time */
#define HOLDING_TIME_DEFAULT 1200 /* same as MPS-p7 */
/* MPC constants */
#define MPC_C1 2 /* Retry Time Multiplier */
#define MPC_C2 60 /* Initial Keep-Alive Lifetime */
/* Message types - to MPOA daemon */
#define SND_MPOA_RES_RQST 201
#define SET_MPS_CTRL_ADDR 202
#define SND_MPOA_RES_RTRY 203 /* Different type in a retry due to req id */
#define STOP_KEEP_ALIVE_SM 204
#define EGRESS_ENTRY_REMOVED 205
#define SND_EGRESS_PURGE 206
#define DIE 207 /* tell the daemon to exit() */
#define DATA_PLANE_PURGE 208 /* Data plane purge because of egress cache hit miss or dead MPS */
#define OPEN_INGRESS_SVC 209
/* Message types - from MPOA daemon */
#define MPOA_TRIGGER_RCVD 101
#define MPOA_RES_REPLY_RCVD 102
#define INGRESS_PURGE_RCVD 103
#define EGRESS_PURGE_RCVD 104
#define MPS_DEATH 105
#define CACHE_IMPOS_RCVD 106
#define SET_MPC_CTRL_ADDR 107 /* Our MPC's control ATM address */
#define SET_MPS_MAC_ADDR 108
#define CLEAN_UP_AND_EXIT 109
#define SET_MPC_PARAMS 110 /* MPC configuration parameters */
/* Message types - bidirectional */
#define RELOAD 301 /* kill -HUP the daemon for reload */
#endif /* _ATMMPC_H_ */

View File

@ -1,56 +0,0 @@
/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
/* atmsvc.h - ATM signaling kernel-demon interface definitions */
/* Written 1995-2000 by Werner Almesberger, EPFL LRC/ICA */
#ifndef _LINUX_ATMSVC_H
#define _LINUX_ATMSVC_H
#include <linux/atmapi.h>
#include <linux/atm.h>
#include <linux/atmioc.h>
#define ATMSIGD_CTRL _IO('a',ATMIOC_SPECIAL)
/* become ATM signaling demon control socket */
enum atmsvc_msg_type { as_catch_null, as_bind, as_connect, as_accept, as_reject,
as_listen, as_okay, as_error, as_indicate, as_close,
as_itf_notify, as_modify, as_identify, as_terminate,
as_addparty, as_dropparty };
struct atmsvc_msg {
enum atmsvc_msg_type type;
atm_kptr_t vcc;
atm_kptr_t listen_vcc; /* indicate */
int reply; /* for okay and close: */
/* < 0: error before active */
/* (sigd has discarded ctx) */
/* ==0: success */
/* > 0: error when active (still */
/* need to close) */
struct sockaddr_atmpvc pvc; /* indicate, okay (connect) */
struct sockaddr_atmsvc local; /* local SVC address */
struct atm_qos qos; /* QOS parameters */
struct atm_sap sap; /* SAP */
unsigned int session; /* for p2pm */
struct sockaddr_atmsvc svc; /* SVC address */
} __ATM_API_ALIGN;
/*
* Message contents: see ftp://icaftp.epfl.ch/pub/linux/atm/docs/isp-*.tar.gz
*/
/*
* Some policy stuff for atmsigd and for net/atm/svc.c. Both have to agree on
* what PCR is used to request bandwidth from the device driver. net/atm/svc.c
* tries to do better than that, but only if there's no routing decision (i.e.
* if signaling only uses one ATM interface).
*/
#define SELECT_TOP_PCR(tp) ((tp).pcr ? (tp).pcr : \
(tp).max_pcr && (tp).max_pcr != ATM_MAX_PCR ? (tp).max_pcr : \
(tp).min_pcr ? (tp).min_pcr : ATM_MAX_PCR)
#endif

View File

@ -3,7 +3,7 @@
# Makefile for the ATM Protocol Families.
#
atm-y := addr.o pvc.o signaling.o svc.o ioctl.o common.o atm_misc.o raw.o resources.o atm_sysfs.o
atm-y := pvc.o ioctl.o common.o atm_misc.o raw.o resources.o atm_sysfs.o
obj-$(CONFIG_ATM) += atm.o
obj-$(CONFIG_ATM_BR2684) += br2684.o

View File

@ -1,162 +0,0 @@
// SPDX-License-Identifier: GPL-2.0
/* net/atm/addr.c - Local ATM address registry */
/* Written 1995-2000 by Werner Almesberger, EPFL LRC/ICA */
#include <linux/atm.h>
#include <linux/atmdev.h>
#include <linux/slab.h>
#include <linux/uaccess.h>
#include "signaling.h"
#include "addr.h"
static int check_addr(const struct sockaddr_atmsvc *addr)
{
int i;
if (addr->sas_family != AF_ATMSVC)
return -EAFNOSUPPORT;
if (!*addr->sas_addr.pub)
return *addr->sas_addr.prv ? 0 : -EINVAL;
for (i = 1; i < ATM_E164_LEN + 1; i++) /* make sure it's \0-terminated */
if (!addr->sas_addr.pub[i])
return 0;
return -EINVAL;
}
static int identical(const struct sockaddr_atmsvc *a, const struct sockaddr_atmsvc *b)
{
if (*a->sas_addr.prv)
if (memcmp(a->sas_addr.prv, b->sas_addr.prv, ATM_ESA_LEN))
return 0;
if (!*a->sas_addr.pub)
return !*b->sas_addr.pub;
if (!*b->sas_addr.pub)
return 0;
return !strcmp(a->sas_addr.pub, b->sas_addr.pub);
}
static void notify_sigd(const struct atm_dev *dev)
{
struct sockaddr_atmpvc pvc;
pvc.sap_addr.itf = dev->number;
sigd_enq(NULL, as_itf_notify, NULL, &pvc, NULL);
}
void atm_reset_addr(struct atm_dev *dev, enum atm_addr_type_t atype)
{
unsigned long flags;
struct atm_dev_addr *this, *p;
struct list_head *head;
spin_lock_irqsave(&dev->lock, flags);
if (atype == ATM_ADDR_LECS)
head = &dev->lecs;
else
head = &dev->local;
list_for_each_entry_safe(this, p, head, entry) {
list_del(&this->entry);
kfree(this);
}
spin_unlock_irqrestore(&dev->lock, flags);
if (head == &dev->local)
notify_sigd(dev);
}
int atm_add_addr(struct atm_dev *dev, const struct sockaddr_atmsvc *addr,
enum atm_addr_type_t atype)
{
unsigned long flags;
struct atm_dev_addr *this;
struct list_head *head;
int error;
error = check_addr(addr);
if (error)
return error;
spin_lock_irqsave(&dev->lock, flags);
if (atype == ATM_ADDR_LECS)
head = &dev->lecs;
else
head = &dev->local;
list_for_each_entry(this, head, entry) {
if (identical(&this->addr, addr)) {
spin_unlock_irqrestore(&dev->lock, flags);
return -EEXIST;
}
}
this = kmalloc_obj(struct atm_dev_addr, GFP_ATOMIC);
if (!this) {
spin_unlock_irqrestore(&dev->lock, flags);
return -ENOMEM;
}
this->addr = *addr;
list_add(&this->entry, head);
spin_unlock_irqrestore(&dev->lock, flags);
if (head == &dev->local)
notify_sigd(dev);
return 0;
}
int atm_del_addr(struct atm_dev *dev, const struct sockaddr_atmsvc *addr,
enum atm_addr_type_t atype)
{
unsigned long flags;
struct atm_dev_addr *this;
struct list_head *head;
int error;
error = check_addr(addr);
if (error)
return error;
spin_lock_irqsave(&dev->lock, flags);
if (atype == ATM_ADDR_LECS)
head = &dev->lecs;
else
head = &dev->local;
list_for_each_entry(this, head, entry) {
if (identical(&this->addr, addr)) {
list_del(&this->entry);
spin_unlock_irqrestore(&dev->lock, flags);
kfree(this);
if (head == &dev->local)
notify_sigd(dev);
return 0;
}
}
spin_unlock_irqrestore(&dev->lock, flags);
return -ENOENT;
}
int atm_get_addr(struct atm_dev *dev, struct sockaddr_atmsvc __user * buf,
size_t size, enum atm_addr_type_t atype)
{
unsigned long flags;
struct atm_dev_addr *this;
struct list_head *head;
int total = 0, error;
struct sockaddr_atmsvc *tmp_buf, *tmp_bufp;
spin_lock_irqsave(&dev->lock, flags);
if (atype == ATM_ADDR_LECS)
head = &dev->lecs;
else
head = &dev->local;
list_for_each_entry(this, head, entry)
total += sizeof(struct sockaddr_atmsvc);
tmp_buf = tmp_bufp = kmalloc(total, GFP_ATOMIC);
if (!tmp_buf) {
spin_unlock_irqrestore(&dev->lock, flags);
return -ENOMEM;
}
list_for_each_entry(this, head, entry)
memcpy(tmp_bufp++, &this->addr, sizeof(struct sockaddr_atmsvc));
spin_unlock_irqrestore(&dev->lock, flags);
error = total > size ? -E2BIG : total;
if (copy_to_user(buf, tmp_buf, total < size ? total : size))
error = -EFAULT;
kfree(tmp_buf);
return error;
}

View File

@ -1,21 +0,0 @@
/* SPDX-License-Identifier: GPL-2.0 */
/* net/atm/addr.h - Local ATM address registry */
/* Written 1995-2000 by Werner Almesberger, EPFL LRC/ICA */
#ifndef NET_ATM_ADDR_H
#define NET_ATM_ADDR_H
#include <linux/atm.h>
#include <linux/atmdev.h>
void atm_reset_addr(struct atm_dev *dev, enum atm_addr_type_t type);
int atm_add_addr(struct atm_dev *dev, const struct sockaddr_atmsvc *addr,
enum atm_addr_type_t type);
int atm_del_addr(struct atm_dev *dev, const struct sockaddr_atmsvc *addr,
enum atm_addr_type_t type);
int atm_get_addr(struct atm_dev *dev, struct sockaddr_atmsvc __user *buf,
size_t size, enum atm_addr_type_t type);
#endif

View File

@ -27,29 +27,6 @@ static ssize_t address_show(struct device *cdev,
return scnprintf(buf, PAGE_SIZE, "%pM\n", adev->esi);
}
static ssize_t atmaddress_show(struct device *cdev,
struct device_attribute *attr, char *buf)
{
unsigned long flags;
struct atm_dev *adev = to_atm_dev(cdev);
struct atm_dev_addr *aaddr;
int count = 0;
spin_lock_irqsave(&adev->lock, flags);
list_for_each_entry(aaddr, &adev->local, entry) {
count += scnprintf(buf + count, PAGE_SIZE - count,
"%1phN.%2phN.%10phN.%6phN.%1phN\n",
&aaddr->addr.sas_addr.prv[0],
&aaddr->addr.sas_addr.prv[1],
&aaddr->addr.sas_addr.prv[3],
&aaddr->addr.sas_addr.prv[13],
&aaddr->addr.sas_addr.prv[19]);
}
spin_unlock_irqrestore(&adev->lock, flags);
return count;
}
static ssize_t atmindex_show(struct device *cdev,
struct device_attribute *attr, char *buf)
{
@ -91,14 +68,12 @@ static ssize_t link_rate_show(struct device *cdev,
}
static DEVICE_ATTR_RO(address);
static DEVICE_ATTR_RO(atmaddress);
static DEVICE_ATTR_RO(atmindex);
static DEVICE_ATTR_RO(carrier);
static DEVICE_ATTR_RO(type);
static DEVICE_ATTR_RO(link_rate);
static struct device_attribute *atm_attrs[] = {
&dev_attr_atmaddress,
&dev_attr_address,
&dev_attr_atmindex,
&dev_attr_carrier,

View File

@ -311,8 +311,7 @@ static netdev_tx_t br2684_start_xmit(struct sk_buff *skb,
bh_lock_sock(sk_atm(atmvcc));
if (test_bit(ATM_VF_RELEASED, &atmvcc->flags) ||
test_bit(ATM_VF_CLOSE, &atmvcc->flags) ||
if (test_bit(ATM_VF_CLOSE, &atmvcc->flags) ||
!test_bit(ATM_VF_READY, &atmvcc->flags)) {
dev->stats.tx_dropped++;
dev_kfree_skb(skb);

View File

@ -30,8 +30,6 @@
#include "resources.h" /* atm_find_dev */
#include "common.h" /* prototypes */
#include "protocols.h" /* atm_init_<transport> */
#include "addr.h" /* address registry */
#include "signaling.h" /* for WAITING and sigd_attach */
struct hlist_head vcc_hash[VCC_HTABLE_SIZE];
EXPORT_SYMBOL(vcc_hash);
@ -155,15 +153,12 @@ int vcc_create(struct net *net, struct socket *sock, int protocol, int family, i
vcc = atm_sk(sk);
vcc->dev = NULL;
memset(&vcc->local, 0, sizeof(struct sockaddr_atmsvc));
memset(&vcc->remote, 0, sizeof(struct sockaddr_atmsvc));
vcc->qos.txtp.max_sdu = 1 << 16; /* for meta VCs */
refcount_set(&sk->sk_wmem_alloc, SK_WMEM_ALLOC_BIAS);
atomic_set(&sk->sk_rmem_alloc, 0);
vcc->push = NULL;
vcc->pop = NULL;
vcc->owner = NULL;
vcc->push_oam = NULL;
vcc->release_cb = NULL;
vcc->vpi = vcc->vci = 0; /* no VCI/VPI yet */
vcc->atm_options = vcc->aal_options = 0;
@ -218,7 +213,6 @@ void vcc_release_async(struct atm_vcc *vcc, int reply)
set_bit(ATM_VF_CLOSE, &vcc->flags);
sk->sk_shutdown |= RCV_SHUTDOWN;
sk->sk_err = -reply;
clear_bit(ATM_VF_WAITING, &vcc->flags);
sk->sk_state_change(sk);
}
EXPORT_SYMBOL(vcc_release_async);
@ -293,9 +287,6 @@ static int adjust_tp(struct atm_trafprm *tp, unsigned char aal)
case ATM_AAL0:
max_sdu = ATM_CELL_SIZE-1;
break;
case ATM_AAL34:
max_sdu = ATM_MAX_AAL34_PDU;
break;
default:
pr_warn("AAL problems ... (%d)\n", aal);
fallthrough;
@ -411,10 +402,6 @@ static int __vcc_connect(struct atm_vcc *vcc, struct atm_dev *dev, short vpi,
error = atm_init_aal0(vcc);
vcc->stats = &dev->stats.aal0;
break;
case ATM_AAL34:
error = atm_init_aal34(vcc);
vcc->stats = &dev->stats.aal34;
break;
case ATM_NO_AAL:
/* ATM_AAL5 is also used in the "0 for default" case */
vcc->qos.aal = ATM_AAL5;
@ -536,8 +523,7 @@ int vcc_recvmsg(struct socket *sock, struct msghdr *msg, size_t size,
return -EOPNOTSUPP;
vcc = ATM_SD(sock);
if (test_bit(ATM_VF_RELEASED, &vcc->flags) ||
test_bit(ATM_VF_CLOSE, &vcc->flags) ||
if (test_bit(ATM_VF_CLOSE, &vcc->flags) ||
!test_bit(ATM_VF_READY, &vcc->flags))
return 0;
@ -584,8 +570,7 @@ int vcc_sendmsg(struct socket *sock, struct msghdr *m, size_t size)
goto out;
}
vcc = ATM_SD(sock);
if (test_bit(ATM_VF_RELEASED, &vcc->flags) ||
test_bit(ATM_VF_CLOSE, &vcc->flags) ||
if (test_bit(ATM_VF_CLOSE, &vcc->flags) ||
!test_bit(ATM_VF_READY, &vcc->flags)) {
error = -EPIPE;
send_sig(SIGPIPE, current, 0);
@ -613,8 +598,7 @@ int vcc_sendmsg(struct socket *sock, struct msghdr *m, size_t size)
error = -ERESTARTSYS;
break;
}
if (test_bit(ATM_VF_RELEASED, &vcc->flags) ||
test_bit(ATM_VF_CLOSE, &vcc->flags) ||
if (test_bit(ATM_VF_CLOSE, &vcc->flags) ||
!test_bit(ATM_VF_READY, &vcc->flags)) {
error = -EPIPE;
send_sig(SIGPIPE, current, 0);
@ -642,12 +626,6 @@ int vcc_sendmsg(struct socket *sock, struct msghdr *m, size_t size)
if (eff != size)
memset(skb->data + size, 0, eff-size);
if (vcc->dev->ops->pre_send) {
error = vcc->dev->ops->pre_send(vcc, skb);
if (error)
goto free_skb;
}
error = vcc->dev->ops->send(vcc, skb);
error = error ? error : size;
out:
@ -674,8 +652,7 @@ __poll_t vcc_poll(struct file *file, struct socket *sock, poll_table *wait)
if (sk->sk_err)
mask = EPOLLERR;
if (test_bit(ATM_VF_RELEASED, &vcc->flags) ||
test_bit(ATM_VF_CLOSE, &vcc->flags))
if (test_bit(ATM_VF_CLOSE, &vcc->flags))
mask |= EPOLLHUP;
/* readable? */
@ -683,10 +660,6 @@ __poll_t vcc_poll(struct file *file, struct socket *sock, poll_table *wait)
mask |= EPOLLIN | EPOLLRDNORM;
/* writable? */
if (sock->state == SS_CONNECTING &&
test_bit(ATM_VF_WAITING, &vcc->flags))
return mask;
if (vcc->qos.txtp.traffic_class != ATM_NONE &&
vcc_writable(sk))
mask |= EPOLLOUT | EPOLLWRNORM | EPOLLWRBAND;
@ -694,30 +667,6 @@ __poll_t vcc_poll(struct file *file, struct socket *sock, poll_table *wait)
return mask;
}
static int atm_change_qos(struct atm_vcc *vcc, struct atm_qos *qos)
{
int error;
/*
* Don't let the QoS change the already connected AAL type nor the
* traffic class.
*/
if (qos->aal != vcc->qos.aal ||
qos->rxtp.traffic_class != vcc->qos.rxtp.traffic_class ||
qos->txtp.traffic_class != vcc->qos.txtp.traffic_class)
return -EINVAL;
error = adjust_tp(&qos->txtp, qos->aal);
if (!error)
error = adjust_tp(&qos->rxtp, qos->aal);
if (error)
return error;
if (!vcc->dev->ops->change_qos)
return -EOPNOTSUPP;
if (sk_atm(vcc)->sk_family == AF_ATMPVC)
return vcc->dev->ops->change_qos(vcc, qos, ATM_MF_SET);
return svc_change_qos(vcc, qos);
}
static int check_tp(const struct atm_trafprm *tp)
{
/* @@@ Should be merged with adjust_tp */
@ -776,8 +725,9 @@ int vcc_setsockopt(struct socket *sock, int level, int optname,
error = check_qos(&qos);
if (error)
return error;
/* QoS cannot be renegotiated on an already connected VCC. */
if (sock->state == SS_CONNECTED)
return atm_change_qos(vcc, &qos);
return -EOPNOTSUPP;
if (sock->state != SS_UNCONNECTED)
return -EBADFD;
vcc->qos = qos;
@ -863,15 +813,10 @@ static int __init atm_init(void)
pr_err("atmpvc_init() failed with %d\n", error);
goto out_unregister_vcc_proto;
}
error = atmsvc_init();
if (error < 0) {
pr_err("atmsvc_init() failed with %d\n", error);
goto out_atmpvc_exit;
}
error = atm_proc_init();
if (error < 0) {
pr_err("atm_proc_init() failed with %d\n", error);
goto out_atmsvc_exit;
goto out_atmpvc_exit;
}
error = atm_sysfs_init();
if (error < 0) {
@ -882,8 +827,6 @@ static int __init atm_init(void)
return error;
out_atmproc_exit:
atm_proc_exit();
out_atmsvc_exit:
atmsvc_exit();
out_atmpvc_exit:
atmpvc_exit();
out_unregister_vcc_proto:
@ -895,7 +838,6 @@ static void __exit atm_exit(void)
{
atm_proc_exit();
atm_sysfs_exit();
atmsvc_exit();
atmpvc_exit();
proto_unregister(&vcc_proto);
}
@ -907,4 +849,3 @@ module_exit(atm_exit);
MODULE_DESCRIPTION("Asynchronous Transfer Mode (ATM) networking core");
MODULE_LICENSE("GPL");
MODULE_ALIAS_NETPROTO(PF_ATMPVC);
MODULE_ALIAS_NETPROTO(PF_ATMSVC);

View File

@ -28,8 +28,6 @@ void vcc_process_recv_queue(struct atm_vcc *vcc);
int atmpvc_init(void);
void atmpvc_exit(void);
int atmsvc_init(void);
void atmsvc_exit(void);
int atm_sysfs_init(void);
void atm_sysfs_exit(void);
@ -48,9 +46,6 @@ static inline void atm_proc_exit(void)
}
#endif /* CONFIG_PROC_FS */
/* SVC */
int svc_change_qos(struct atm_vcc *vcc,struct atm_qos *qos);
void atm_dev_release_vccs(struct atm_dev *dev);
#endif

View File

@ -11,16 +11,12 @@
#include <linux/net.h> /* struct socket, struct proto_ops */
#include <linux/atm.h> /* ATM stuff */
#include <linux/atmdev.h>
#include <linux/atmarp.h> /* manifest constants */
#include <linux/capability.h>
#include <linux/sonet.h> /* for ioctls */
#include <linux/atmsvc.h>
#include <linux/mutex.h>
#include <asm/ioctls.h>
#include <net/compat.h>
#include "resources.h"
#include "signaling.h" /* for WAITING and sigd_attach */
#include "common.h"
@ -87,36 +83,6 @@ static int do_vcc_ioctl(struct socket *sock, unsigned int cmd,
current->comm, task_pid_nr(current));
error = 0;
goto done;
case ATMSIGD_CTRL:
if (!capable(CAP_NET_ADMIN)) {
error = -EPERM;
goto done;
}
/*
* The user/kernel protocol for exchanging signalling
* info uses kernel pointers as opaque references,
* so the holder of the file descriptor can scribble
* on the kernel... so we should make sure that we
* have the same privileges that /proc/kcore needs
*/
if (!capable(CAP_SYS_RAWIO)) {
error = -EPERM;
goto done;
}
#ifdef CONFIG_COMPAT
/* WTF? I don't even want to _think_ about making this
work for 32-bit userspace. TBH I don't really want
to think about it at all. dwmw2. */
if (compat) {
net_warn_ratelimited("32-bit task cannot be atmsigd\n");
error = -EINVAL;
goto done;
}
#endif
error = sigd_attach(vcc);
if (!error)
sock->state = SS_CONNECTED;
goto done;
case ATM_SETBACKEND:
case ATM_NEWBACKENDIF:
{
@ -221,10 +187,6 @@ int vcc_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
#define ATM_GETNAMES32 _IOW('a', ATMIOC_ITF+3, struct compat_atm_iobuf)
#define ATM_GETTYPE32 _IOW('a', ATMIOC_ITF+4, struct compat_atmif_sioc)
#define ATM_GETESI32 _IOW('a', ATMIOC_ITF+5, struct compat_atmif_sioc)
#define ATM_GETADDR32 _IOW('a', ATMIOC_ITF+6, struct compat_atmif_sioc)
#define ATM_RSTADDR32 _IOW('a', ATMIOC_ITF+7, struct compat_atmif_sioc)
#define ATM_ADDADDR32 _IOW('a', ATMIOC_ITF+8, struct compat_atmif_sioc)
#define ATM_DELADDR32 _IOW('a', ATMIOC_ITF+9, struct compat_atmif_sioc)
#define ATM_GETCIRANGE32 _IOW('a', ATMIOC_ITF+10, struct compat_atmif_sioc)
#define ATM_SETCIRANGE32 _IOW('a', ATMIOC_ITF+11, struct compat_atmif_sioc)
#define ATM_SETESI32 _IOW('a', ATMIOC_ITF+12, struct compat_atmif_sioc)
@ -243,10 +205,6 @@ static struct {
{ ATM_GETNAMES32, ATM_GETNAMES },
{ ATM_GETTYPE32, ATM_GETTYPE },
{ ATM_GETESI32, ATM_GETESI },
{ ATM_GETADDR32, ATM_GETADDR },
{ ATM_RSTADDR32, ATM_RSTADDR },
{ ATM_ADDADDR32, ATM_ADDADDR },
{ ATM_DELADDR32, ATM_DELADDR },
{ ATM_GETCIRANGE32, ATM_GETCIRANGE },
{ ATM_SETCIRANGE32, ATM_SETCIRANGE },
{ ATM_SETESI32, ATM_SETESI },
@ -290,18 +248,6 @@ static int do_atm_ioctl(struct socket *sock, unsigned int cmd32,
int i;
unsigned int cmd = 0;
switch (cmd32) {
case SONET_GETSTAT:
case SONET_GETSTATZ:
case SONET_GETDIAG:
case SONET_SETDIAG:
case SONET_CLRDIAG:
case SONET_SETFRAMING:
case SONET_GETFRAMING:
case SONET_GETFRSENSE:
return do_atmif_sioc(sock, cmd32, arg);
}
for (i = 0; i < NR_ATM_IOCTL; i++) {
if (cmd32 == atm_ioctl_map[i].cmd32) {
cmd = atm_ioctl_map[i].cmd;
@ -318,10 +264,6 @@ static int do_atm_ioctl(struct socket *sock, unsigned int cmd32,
case ATM_GETLINKRATE:
case ATM_GETTYPE:
case ATM_GETESI:
case ATM_GETADDR:
case ATM_RSTADDR:
case ATM_ADDADDR:
case ATM_DELADDR:
case ATM_GETCIRANGE:
case ATM_SETCIRANGE:
case ATM_SETESI:

View File

@ -308,8 +308,7 @@ static int pppoatm_send(struct ppp_channel *chan, struct sk_buff *skb)
test_and_set_bit(BLOCKED, &pvcc->blocked);
goto nospace;
}
if (test_bit(ATM_VF_RELEASED, &vcc->flags) ||
test_bit(ATM_VF_CLOSE, &vcc->flags) ||
if (test_bit(ATM_VF_CLOSE, &vcc->flags) ||
!test_bit(ATM_VF_READY, &vcc->flags)) {
bh_unlock_sock(sk_atm(vcc));
kfree_skb(skb);

View File

@ -29,7 +29,6 @@
#include <linux/atomic.h>
#include "resources.h"
#include "common.h" /* atm_proc_init prototype */
#include "signaling.h" /* to get sigd - ugly too */
static ssize_t proc_dev_atm_read(struct file *file, char __user *buf,
size_t count, loff_t *pos);
@ -156,13 +155,6 @@ static void pvc_info(struct seq_file *seq, struct atm_vcc *vcc)
seq_putc(seq, '\n');
}
static const char *vcc_state(struct atm_vcc *vcc)
{
static const char *const map[] = { ATM_VS2TXT_MAP };
return map[ATM_VF2VS(vcc->flags)];
}
static void vcc_info(struct seq_file *seq, struct atm_vcc *vcc)
{
struct sock *sk = sk_atm(vcc);
@ -177,9 +169,6 @@ static void vcc_info(struct seq_file *seq, struct atm_vcc *vcc)
case AF_ATMPVC:
seq_printf(seq, "PVC");
break;
case AF_ATMSVC:
seq_printf(seq, "SVC");
break;
default:
seq_printf(seq, "%3d", sk->sk_family);
}
@ -190,26 +179,6 @@ static void vcc_info(struct seq_file *seq, struct atm_vcc *vcc)
refcount_read(&sk->sk_refcnt));
}
static void svc_info(struct seq_file *seq, struct atm_vcc *vcc)
{
if (!vcc->dev)
seq_printf(seq, sizeof(void *) == 4 ?
"N/A@%pK%10s" : "N/A@%pK%2s", vcc, "");
else
seq_printf(seq, "%3d %3d %5d ",
vcc->dev->number, vcc->vpi, vcc->vci);
seq_printf(seq, "%-10s ", vcc_state(vcc));
seq_printf(seq, "%s%s", vcc->remote.sas_addr.pub,
*vcc->remote.sas_addr.pub && *vcc->remote.sas_addr.prv ? "+" : "");
if (*vcc->remote.sas_addr.prv) {
int i;
for (i = 0; i < ATM_ESA_LEN; i++)
seq_printf(seq, "%02x", vcc->remote.sas_addr.prv[i]);
}
seq_putc(seq, '\n');
}
static int atm_dev_seq_show(struct seq_file *seq, void *v)
{
static char atm_dev_banner[] =
@ -278,29 +247,6 @@ static const struct seq_operations vcc_seq_ops = {
.show = vcc_seq_show,
};
static int svc_seq_show(struct seq_file *seq, void *v)
{
static const char atm_svc_banner[] =
"Itf VPI VCI State Remote\n";
if (v == SEQ_START_TOKEN)
seq_puts(seq, atm_svc_banner);
else {
struct vcc_state *state = seq->private;
struct atm_vcc *vcc = atm_sk(state->sk);
svc_info(seq, vcc);
}
return 0;
}
static const struct seq_operations svc_seq_ops = {
.start = vcc_seq_start,
.next = vcc_seq_next,
.stop = vcc_seq_stop,
.show = svc_seq_show,
};
static ssize_t proc_dev_atm_read(struct file *file, char __user *buf,
size_t count, loff_t *pos)
{
@ -376,8 +322,6 @@ int __init atm_proc_init(void)
proc_create_seq("devices", 0444, atm_proc_root, &atm_dev_seq_ops);
proc_create_seq_private("pvc", 0444, atm_proc_root, &pvc_seq_ops,
sizeof(struct vcc_state), (void *)(uintptr_t)PF_ATMPVC);
proc_create_seq_private("svc", 0444, atm_proc_root, &svc_seq_ops,
sizeof(struct vcc_state), (void *)(uintptr_t)PF_ATMSVC);
proc_create_seq_private("vc", 0444, atm_proc_root, &vcc_seq_ops,
sizeof(struct vcc_state), NULL);
return 0;

View File

@ -8,7 +8,6 @@
#define NET_ATM_PROTOCOLS_H
int atm_init_aal0(struct atm_vcc *vcc); /* "raw" AAL0 */
int atm_init_aal34(struct atm_vcc *vcc);/* "raw" AAL3/4 transport */
int atm_init_aal5(struct atm_vcc *vcc); /* "raw" AAL5 transport */
#endif

View File

@ -54,8 +54,6 @@ static int atm_send_aal0(struct atm_vcc *vcc, struct sk_buff *skb)
kfree_skb(skb);
return -EADDRNOTAVAIL;
}
if (vcc->dev->ops->send_bh)
return vcc->dev->ops->send_bh(vcc, skb);
return vcc->dev->ops->send(vcc, skb);
}
@ -63,32 +61,15 @@ int atm_init_aal0(struct atm_vcc *vcc)
{
vcc->push = atm_push_raw;
vcc->pop = atm_pop_raw;
vcc->push_oam = NULL;
vcc->send = atm_send_aal0;
return 0;
}
int atm_init_aal34(struct atm_vcc *vcc)
{
vcc->push = atm_push_raw;
vcc->pop = atm_pop_raw;
vcc->push_oam = NULL;
if (vcc->dev->ops->send_bh)
vcc->send = vcc->dev->ops->send_bh;
else
vcc->send = vcc->dev->ops->send;
return 0;
}
int atm_init_aal5(struct atm_vcc *vcc)
{
vcc->push = atm_push_raw;
vcc->pop = atm_pop_raw;
vcc->push_oam = NULL;
if (vcc->dev->ops->send_bh)
vcc->send = vcc->dev->ops->send_bh;
else
vcc->send = vcc->dev->ops->send;
vcc->send = vcc->dev->ops->send;
return 0;
}
EXPORT_SYMBOL(atm_init_aal5);

View File

@ -13,7 +13,6 @@
#include <linux/ctype.h>
#include <linux/string.h>
#include <linux/atmdev.h>
#include <linux/sonet.h>
#include <linux/kernel.h> /* for barrier */
#include <linux/module.h>
#include <linux/bitops.h>
@ -26,7 +25,6 @@
#include "common.h"
#include "resources.h"
#include "addr.h"
LIST_HEAD(atm_devs);
@ -42,9 +40,6 @@ static struct atm_dev *__alloc_atm_dev(const char *type)
dev->type = type;
dev->signal = ATM_PHY_SIG_UNKNOWN;
dev->link_rate = ATM_OC3_PCR;
spin_lock_init(&dev->lock);
INIT_LIST_HEAD(&dev->local);
INIT_LIST_HEAD(&dev->lecs);
return dev;
}
@ -228,11 +223,8 @@ int atm_getnames(void __user *buf, int __user *iobuf_len)
int atm_dev_ioctl(unsigned int cmd, void __user *buf, int __user *sioc_len,
int number, int compat)
{
int error, len, size = 0;
struct atm_dev *dev;
if (get_user(len, sioc_len))
return -EFAULT;
int error, size = 0;
dev = try_then_request_module(atm_dev_lookup(number), "atm-device-%d",
number);
@ -307,51 +299,6 @@ int atm_dev_ioctl(unsigned int cmd, void __user *buf, int __user *sioc_len,
goto done;
}
break;
case ATM_RSTADDR:
if (!capable(CAP_NET_ADMIN)) {
error = -EPERM;
goto done;
}
atm_reset_addr(dev, ATM_ADDR_LOCAL);
break;
case ATM_ADDADDR:
case ATM_DELADDR:
case ATM_ADDLECSADDR:
case ATM_DELLECSADDR:
{
struct sockaddr_atmsvc addr;
if (!capable(CAP_NET_ADMIN)) {
error = -EPERM;
goto done;
}
if (copy_from_user(&addr, buf, sizeof(addr))) {
error = -EFAULT;
goto done;
}
if (cmd == ATM_ADDADDR || cmd == ATM_ADDLECSADDR)
error = atm_add_addr(dev, &addr,
(cmd == ATM_ADDADDR ?
ATM_ADDR_LOCAL : ATM_ADDR_LECS));
else
error = atm_del_addr(dev, &addr,
(cmd == ATM_DELADDR ?
ATM_ADDR_LOCAL : ATM_ADDR_LECS));
goto done;
}
case ATM_GETADDR:
case ATM_GETLECSADDR:
error = atm_get_addr(dev, buf, len,
(cmd == ATM_GETADDR ?
ATM_ADDR_LOCAL : ATM_ADDR_LECS));
if (error < 0)
goto done;
size = error;
/* may return 0, but later on size == 0 means "don't
write the length" */
error = put_user(size, sioc_len) ? -EFAULT : 0;
goto done;
case ATM_SETLOOP:
if (__ATM_LM_XTRMT((int) (unsigned long) buf) &&
__ATM_LM_XTLOC((int) (unsigned long) buf) >
@ -361,10 +308,6 @@ int atm_dev_ioctl(unsigned int cmd, void __user *buf, int __user *sioc_len,
}
fallthrough;
case ATM_SETCIRANGE:
case SONET_GETSTATZ:
case SONET_SETDIAG:
case SONET_CLRDIAG:
case SONET_SETFRAMING:
if (!capable(CAP_NET_ADMIN)) {
error = -EPERM;
goto done;

View File

@ -1,297 +0,0 @@
// SPDX-License-Identifier: GPL-2.0
/* net/atm/signaling.c - ATM signaling */
/* Written 1995-2000 by Werner Almesberger, EPFL LRC/ICA */
#define pr_fmt(fmt) KBUILD_MODNAME ":%s: " fmt, __func__
#include <linux/errno.h> /* error codes */
#include <linux/kernel.h> /* printk */
#include <linux/skbuff.h>
#include <linux/wait.h>
#include <linux/sched.h> /* jiffies and HZ */
#include <linux/atm.h> /* ATM stuff */
#include <linux/atmsap.h>
#include <linux/atmsvc.h>
#include <linux/atmdev.h>
#include <linux/bitops.h>
#include <linux/slab.h>
#include "resources.h"
#include "signaling.h"
struct atm_vcc *sigd = NULL;
/*
* find_get_vcc - validate and get a reference to a vcc pointer
* @vcc: the vcc pointer to validate
*
* This function validates that @vcc points to a registered VCC in vcc_hash.
* If found, it increments the socket reference count and returns the vcc.
* The caller must call sock_put(sk_atm(vcc)) when done.
*
* Returns the vcc pointer if valid, NULL otherwise.
*/
static struct atm_vcc *find_get_vcc(struct atm_vcc *vcc)
{
int i;
read_lock(&vcc_sklist_lock);
for (i = 0; i < VCC_HTABLE_SIZE; i++) {
struct sock *s;
sk_for_each(s, &vcc_hash[i]) {
if (atm_sk(s) == vcc) {
sock_hold(s);
read_unlock(&vcc_sklist_lock);
return vcc;
}
}
}
read_unlock(&vcc_sklist_lock);
return NULL;
}
static void sigd_put_skb(struct sk_buff *skb)
{
if (!sigd) {
pr_debug("atmsvc: no signaling daemon\n");
kfree_skb(skb);
return;
}
atm_force_charge(sigd, skb->truesize);
skb_queue_tail(&sk_atm(sigd)->sk_receive_queue, skb);
sk_atm(sigd)->sk_data_ready(sk_atm(sigd));
}
static void modify_qos(struct atm_vcc *vcc, struct atmsvc_msg *msg)
{
struct sk_buff *skb;
if (test_bit(ATM_VF_RELEASED, &vcc->flags) ||
!test_bit(ATM_VF_READY, &vcc->flags))
return;
msg->type = as_error;
if (!vcc->dev->ops->change_qos)
msg->reply = -EOPNOTSUPP;
else {
/* should lock VCC */
msg->reply = vcc->dev->ops->change_qos(vcc, &msg->qos,
msg->reply);
if (!msg->reply)
msg->type = as_okay;
}
/*
* Should probably just turn around the old skb. But then, the buffer
* space accounting needs to follow the change too. Maybe later.
*/
while (!(skb = alloc_skb(sizeof(struct atmsvc_msg), GFP_KERNEL)))
schedule();
*(struct atmsvc_msg *)skb_put(skb, sizeof(struct atmsvc_msg)) = *msg;
sigd_put_skb(skb);
}
static int sigd_send(struct atm_vcc *vcc, struct sk_buff *skb)
{
struct atmsvc_msg *msg;
struct atm_vcc *session_vcc;
struct sock *sk;
msg = (struct atmsvc_msg *) skb->data;
WARN_ON(refcount_sub_and_test(skb->truesize, &sk_atm(vcc)->sk_wmem_alloc));
vcc = find_get_vcc(*(struct atm_vcc **)&msg->vcc);
if (!vcc) {
pr_debug("invalid vcc pointer in msg\n");
dev_kfree_skb(skb);
return -EINVAL;
}
pr_debug("%d (0x%lx)\n", (int)msg->type, (unsigned long)vcc);
sk = sk_atm(vcc);
switch (msg->type) {
case as_okay:
sk->sk_err = -msg->reply;
clear_bit(ATM_VF_WAITING, &vcc->flags);
if (!*vcc->local.sas_addr.prv && !*vcc->local.sas_addr.pub) {
vcc->local.sas_family = AF_ATMSVC;
memcpy(vcc->local.sas_addr.prv,
msg->local.sas_addr.prv, ATM_ESA_LEN);
memcpy(vcc->local.sas_addr.pub,
msg->local.sas_addr.pub, ATM_E164_LEN + 1);
}
session_vcc = vcc->session ? vcc->session : vcc;
if (session_vcc->vpi || session_vcc->vci)
break;
session_vcc->itf = msg->pvc.sap_addr.itf;
session_vcc->vpi = msg->pvc.sap_addr.vpi;
session_vcc->vci = msg->pvc.sap_addr.vci;
if (session_vcc->vpi || session_vcc->vci)
session_vcc->qos = msg->qos;
break;
case as_error:
clear_bit(ATM_VF_REGIS, &vcc->flags);
clear_bit(ATM_VF_READY, &vcc->flags);
sk->sk_err = -msg->reply;
clear_bit(ATM_VF_WAITING, &vcc->flags);
break;
case as_indicate:
/* Release the reference from msg->vcc, we'll use msg->listen_vcc instead */
sock_put(sk);
vcc = find_get_vcc(*(struct atm_vcc **)&msg->listen_vcc);
if (!vcc) {
pr_debug("invalid listen_vcc pointer in msg\n");
dev_kfree_skb(skb);
return -EINVAL;
}
sk = sk_atm(vcc);
pr_debug("as_indicate!!!\n");
lock_sock(sk);
if (sk_acceptq_is_full(sk)) {
sigd_enq(NULL, as_reject, vcc, NULL, NULL);
dev_kfree_skb(skb);
goto as_indicate_complete;
}
sk_acceptq_added(sk);
skb_queue_tail(&sk->sk_receive_queue, skb);
pr_debug("waking sk_sleep(sk) 0x%p\n", sk_sleep(sk));
sk->sk_state_change(sk);
as_indicate_complete:
release_sock(sk);
/* Paired with find_get_vcc(msg->listen_vcc) above */
sock_put(sk);
return 0;
case as_close:
set_bit(ATM_VF_RELEASED, &vcc->flags);
vcc_release_async(vcc, msg->reply);
goto out;
case as_modify:
modify_qos(vcc, msg);
break;
case as_addparty:
case as_dropparty:
WRITE_ONCE(sk->sk_err_soft, -msg->reply);
/* < 0 failure, otherwise ep_ref */
clear_bit(ATM_VF_WAITING, &vcc->flags);
break;
default:
pr_alert("bad message type %d\n", (int)msg->type);
dev_kfree_skb(skb);
/* Paired with find_get_vcc(msg->vcc) above */
sock_put(sk);
return -EINVAL;
}
sk->sk_state_change(sk);
out:
dev_kfree_skb(skb);
/* Paired with find_get_vcc(msg->vcc) above */
sock_put(sk);
return 0;
}
void sigd_enq2(struct atm_vcc *vcc, enum atmsvc_msg_type type,
struct atm_vcc *listen_vcc, const struct sockaddr_atmpvc *pvc,
const struct sockaddr_atmsvc *svc, const struct atm_qos *qos,
int reply)
{
struct sk_buff *skb;
struct atmsvc_msg *msg;
static unsigned int session = 0;
pr_debug("%d (0x%p)\n", (int)type, vcc);
while (!(skb = alloc_skb(sizeof(struct atmsvc_msg), GFP_KERNEL)))
schedule();
msg = skb_put_zero(skb, sizeof(struct atmsvc_msg));
msg->type = type;
*(struct atm_vcc **) &msg->vcc = vcc;
*(struct atm_vcc **) &msg->listen_vcc = listen_vcc;
msg->reply = reply;
if (qos)
msg->qos = *qos;
if (vcc)
msg->sap = vcc->sap;
if (svc)
msg->svc = *svc;
if (vcc)
msg->local = vcc->local;
if (pvc)
msg->pvc = *pvc;
if (vcc) {
if (type == as_connect && test_bit(ATM_VF_SESSION, &vcc->flags))
msg->session = ++session;
/* every new pmp connect gets the next session number */
}
sigd_put_skb(skb);
if (vcc)
set_bit(ATM_VF_REGIS, &vcc->flags);
}
void sigd_enq(struct atm_vcc *vcc, enum atmsvc_msg_type type,
struct atm_vcc *listen_vcc, const struct sockaddr_atmpvc *pvc,
const struct sockaddr_atmsvc *svc)
{
sigd_enq2(vcc, type, listen_vcc, pvc, svc, vcc ? &vcc->qos : NULL, 0);
/* other ISP applications may use "reply" */
}
static void purge_vcc(struct atm_vcc *vcc)
{
if (sk_atm(vcc)->sk_family == PF_ATMSVC &&
!test_bit(ATM_VF_META, &vcc->flags)) {
set_bit(ATM_VF_RELEASED, &vcc->flags);
clear_bit(ATM_VF_REGIS, &vcc->flags);
vcc_release_async(vcc, -EUNATCH);
}
}
static void sigd_close(struct atm_vcc *vcc)
{
struct sock *s;
int i;
pr_debug("\n");
sigd = NULL;
if (skb_peek(&sk_atm(vcc)->sk_receive_queue))
pr_err("closing with requests pending\n");
skb_queue_purge(&sk_atm(vcc)->sk_receive_queue);
read_lock(&vcc_sklist_lock);
for (i = 0; i < VCC_HTABLE_SIZE; ++i) {
struct hlist_head *head = &vcc_hash[i];
sk_for_each(s, head) {
vcc = atm_sk(s);
purge_vcc(vcc);
}
}
read_unlock(&vcc_sklist_lock);
}
static const struct atmdev_ops sigd_dev_ops = {
.close = sigd_close,
.send = sigd_send
};
static struct atm_dev sigd_dev = {
.ops = &sigd_dev_ops,
.type = "sig",
.number = 999,
.lock = __SPIN_LOCK_UNLOCKED(sigd_dev.lock)
};
int sigd_attach(struct atm_vcc *vcc)
{
if (sigd)
return -EADDRINUSE;
pr_debug("\n");
sigd = vcc;
vcc->dev = &sigd_dev;
vcc_insert_socket(sk_atm(vcc));
set_bit(ATM_VF_META, &vcc->flags);
set_bit(ATM_VF_READY, &vcc->flags);
return 0;
}

View File

@ -1,31 +0,0 @@
/* SPDX-License-Identifier: GPL-2.0 */
/* net/atm/signaling.h - ATM signaling */
/* Written 1995-2000 by Werner Almesberger, EPFL LRC/ICA */
#ifndef NET_ATM_SIGNALING_H
#define NET_ATM_SIGNALING_H
#include <linux/atm.h>
#include <linux/atmdev.h>
#include <linux/atmsvc.h>
extern struct atm_vcc *sigd; /* needed in svc_release */
/*
* sigd_enq is a wrapper for sigd_enq2, covering the more common cases, and
* avoiding huge lists of null values.
*/
void sigd_enq2(struct atm_vcc *vcc,enum atmsvc_msg_type type,
struct atm_vcc *listen_vcc,const struct sockaddr_atmpvc *pvc,
const struct sockaddr_atmsvc *svc,const struct atm_qos *qos,int reply);
void sigd_enq(struct atm_vcc *vcc,enum atmsvc_msg_type type,
struct atm_vcc *listen_vcc,const struct sockaddr_atmpvc *pvc,
const struct sockaddr_atmsvc *svc);
int sigd_attach(struct atm_vcc *vcc);
#endif

View File

@ -1,695 +0,0 @@
// SPDX-License-Identifier: GPL-2.0
/* net/atm/svc.c - ATM SVC sockets */
/* Written 1995-2000 by Werner Almesberger, EPFL LRC/ICA */
#define pr_fmt(fmt) KBUILD_MODNAME ":%s: " fmt, __func__
#include <linux/string.h>
#include <linux/net.h> /* struct socket, struct proto_ops */
#include <linux/errno.h> /* error codes */
#include <linux/kernel.h> /* printk */
#include <linux/skbuff.h>
#include <linux/wait.h>
#include <linux/sched/signal.h>
#include <linux/fcntl.h> /* O_NONBLOCK */
#include <linux/init.h>
#include <linux/atm.h> /* ATM stuff */
#include <linux/atmsap.h>
#include <linux/atmsvc.h>
#include <linux/atmdev.h>
#include <linux/bitops.h>
#include <net/sock.h> /* for sock_no_* */
#include <linux/uaccess.h>
#include <linux/uio.h>
#include <linux/export.h>
#include "resources.h"
#include "common.h" /* common for PVCs and SVCs */
#include "signaling.h"
#include "addr.h"
#ifdef CONFIG_COMPAT
/* It actually takes struct sockaddr_atmsvc, not struct atm_iobuf */
#define COMPAT_ATM_ADDPARTY _IOW('a', ATMIOC_SPECIAL + 4, struct compat_atm_iobuf)
#endif
static int svc_create(struct net *net, struct socket *sock, int protocol,
int kern);
/*
* Note: since all this is still nicely synchronized with the signaling demon,
* there's no need to protect sleep loops with clis. If signaling is
* moved into the kernel, that would change.
*/
static int svc_shutdown(struct socket *sock, int how)
{
return 0;
}
static void svc_disconnect(struct atm_vcc *vcc)
{
DEFINE_WAIT(wait);
struct sk_buff *skb;
struct sock *sk = sk_atm(vcc);
pr_debug("%p\n", vcc);
if (test_bit(ATM_VF_REGIS, &vcc->flags)) {
sigd_enq(vcc, as_close, NULL, NULL, NULL);
for (;;) {
prepare_to_wait(sk_sleep(sk), &wait, TASK_UNINTERRUPTIBLE);
if (test_bit(ATM_VF_RELEASED, &vcc->flags) || !sigd)
break;
schedule();
}
finish_wait(sk_sleep(sk), &wait);
}
/* beware - socket is still in use by atmsigd until the last
as_indicate has been answered */
while ((skb = skb_dequeue(&sk->sk_receive_queue)) != NULL) {
atm_return(vcc, skb->truesize);
pr_debug("LISTEN REL\n");
sigd_enq2(NULL, as_reject, vcc, NULL, NULL, &vcc->qos, 0);
dev_kfree_skb(skb);
}
clear_bit(ATM_VF_REGIS, &vcc->flags);
/* ... may retry later */
}
static int svc_release(struct socket *sock)
{
struct sock *sk = sock->sk;
struct atm_vcc *vcc;
if (sk) {
vcc = ATM_SD(sock);
pr_debug("%p\n", vcc);
clear_bit(ATM_VF_READY, &vcc->flags);
/*
* VCC pointer is used as a reference,
* so we must not free it (thereby subjecting it to re-use)
* before all pending connections are closed
*/
svc_disconnect(vcc);
vcc_release(sock);
}
return 0;
}
static int svc_bind(struct socket *sock, struct sockaddr_unsized *sockaddr,
int sockaddr_len)
{
DEFINE_WAIT(wait);
struct sock *sk = sock->sk;
struct sockaddr_atmsvc *addr;
struct atm_vcc *vcc;
int error;
if (sockaddr_len != sizeof(struct sockaddr_atmsvc))
return -EINVAL;
lock_sock(sk);
if (sock->state == SS_CONNECTED) {
error = -EISCONN;
goto out;
}
if (sock->state != SS_UNCONNECTED) {
error = -EINVAL;
goto out;
}
vcc = ATM_SD(sock);
addr = (struct sockaddr_atmsvc *) sockaddr;
if (addr->sas_family != AF_ATMSVC) {
error = -EAFNOSUPPORT;
goto out;
}
clear_bit(ATM_VF_BOUND, &vcc->flags);
/* failing rebind will kill old binding */
/* @@@ check memory (de)allocation on rebind */
if (!test_bit(ATM_VF_HASQOS, &vcc->flags)) {
error = -EBADFD;
goto out;
}
vcc->local = *addr;
set_bit(ATM_VF_WAITING, &vcc->flags);
sigd_enq(vcc, as_bind, NULL, NULL, &vcc->local);
for (;;) {
prepare_to_wait(sk_sleep(sk), &wait, TASK_UNINTERRUPTIBLE);
if (!test_bit(ATM_VF_WAITING, &vcc->flags) || !sigd)
break;
schedule();
}
finish_wait(sk_sleep(sk), &wait);
clear_bit(ATM_VF_REGIS, &vcc->flags); /* doesn't count */
if (!sigd) {
error = -EUNATCH;
goto out;
}
if (!sk->sk_err)
set_bit(ATM_VF_BOUND, &vcc->flags);
error = -sk->sk_err;
out:
release_sock(sk);
return error;
}
static int svc_connect(struct socket *sock, struct sockaddr_unsized *sockaddr,
int sockaddr_len, int flags)
{
DEFINE_WAIT(wait);
struct sock *sk = sock->sk;
struct sockaddr_atmsvc *addr;
struct atm_vcc *vcc = ATM_SD(sock);
int error;
pr_debug("%p\n", vcc);
lock_sock(sk);
if (sockaddr_len != sizeof(struct sockaddr_atmsvc)) {
error = -EINVAL;
goto out;
}
switch (sock->state) {
default:
error = -EINVAL;
goto out;
case SS_CONNECTED:
error = -EISCONN;
goto out;
case SS_CONNECTING:
if (test_bit(ATM_VF_WAITING, &vcc->flags)) {
error = -EALREADY;
goto out;
}
sock->state = SS_UNCONNECTED;
if (sk->sk_err) {
error = -sk->sk_err;
goto out;
}
break;
case SS_UNCONNECTED:
addr = (struct sockaddr_atmsvc *) sockaddr;
if (addr->sas_family != AF_ATMSVC) {
error = -EAFNOSUPPORT;
goto out;
}
if (!test_bit(ATM_VF_HASQOS, &vcc->flags)) {
error = -EBADFD;
goto out;
}
if (vcc->qos.txtp.traffic_class == ATM_ANYCLASS ||
vcc->qos.rxtp.traffic_class == ATM_ANYCLASS) {
error = -EINVAL;
goto out;
}
if (!vcc->qos.txtp.traffic_class &&
!vcc->qos.rxtp.traffic_class) {
error = -EINVAL;
goto out;
}
vcc->remote = *addr;
set_bit(ATM_VF_WAITING, &vcc->flags);
sigd_enq(vcc, as_connect, NULL, NULL, &vcc->remote);
if (flags & O_NONBLOCK) {
sock->state = SS_CONNECTING;
error = -EINPROGRESS;
goto out;
}
error = 0;
prepare_to_wait(sk_sleep(sk), &wait, TASK_INTERRUPTIBLE);
while (test_bit(ATM_VF_WAITING, &vcc->flags) && sigd) {
schedule();
if (!signal_pending(current)) {
prepare_to_wait(sk_sleep(sk), &wait,
TASK_INTERRUPTIBLE);
continue;
}
pr_debug("*ABORT*\n");
/*
* This is tricky:
* Kernel ---close--> Demon
* Kernel <--close--- Demon
* or
* Kernel ---close--> Demon
* Kernel <--error--- Demon
* or
* Kernel ---close--> Demon
* Kernel <--okay---- Demon
* Kernel <--close--- Demon
*/
sigd_enq(vcc, as_close, NULL, NULL, NULL);
while (test_bit(ATM_VF_WAITING, &vcc->flags) && sigd) {
prepare_to_wait(sk_sleep(sk), &wait,
TASK_INTERRUPTIBLE);
schedule();
}
if (!sk->sk_err)
while (!test_bit(ATM_VF_RELEASED, &vcc->flags) &&
sigd) {
prepare_to_wait(sk_sleep(sk), &wait,
TASK_INTERRUPTIBLE);
schedule();
}
clear_bit(ATM_VF_REGIS, &vcc->flags);
clear_bit(ATM_VF_RELEASED, &vcc->flags);
clear_bit(ATM_VF_CLOSE, &vcc->flags);
/* we're gone now but may connect later */
error = -EINTR;
break;
}
finish_wait(sk_sleep(sk), &wait);
if (error)
goto out;
if (!sigd) {
error = -EUNATCH;
goto out;
}
if (sk->sk_err) {
error = -sk->sk_err;
goto out;
}
}
vcc->qos.txtp.max_pcr = SELECT_TOP_PCR(vcc->qos.txtp);
vcc->qos.txtp.pcr = 0;
vcc->qos.txtp.min_pcr = 0;
error = vcc_connect(sock, vcc->itf, vcc->vpi, vcc->vci);
if (!error)
sock->state = SS_CONNECTED;
else
(void)svc_disconnect(vcc);
out:
release_sock(sk);
return error;
}
static int svc_listen(struct socket *sock, int backlog)
{
DEFINE_WAIT(wait);
struct sock *sk = sock->sk;
struct atm_vcc *vcc = ATM_SD(sock);
int error;
pr_debug("%p\n", vcc);
lock_sock(sk);
/* let server handle listen on unbound sockets */
if (test_bit(ATM_VF_SESSION, &vcc->flags)) {
error = -EINVAL;
goto out;
}
if (test_bit(ATM_VF_LISTEN, &vcc->flags)) {
error = -EADDRINUSE;
goto out;
}
set_bit(ATM_VF_WAITING, &vcc->flags);
sigd_enq(vcc, as_listen, NULL, NULL, &vcc->local);
for (;;) {
prepare_to_wait(sk_sleep(sk), &wait, TASK_UNINTERRUPTIBLE);
if (!test_bit(ATM_VF_WAITING, &vcc->flags) || !sigd)
break;
schedule();
}
finish_wait(sk_sleep(sk), &wait);
if (!sigd) {
error = -EUNATCH;
goto out;
}
set_bit(ATM_VF_LISTEN, &vcc->flags);
vcc_insert_socket(sk);
sk->sk_max_ack_backlog = backlog > 0 ? backlog : ATM_BACKLOG_DEFAULT;
error = -sk->sk_err;
out:
release_sock(sk);
return error;
}
static int svc_accept(struct socket *sock, struct socket *newsock,
struct proto_accept_arg *arg)
{
struct sock *sk = sock->sk;
struct sk_buff *skb;
struct atmsvc_msg *msg;
struct atm_vcc *old_vcc = ATM_SD(sock);
struct atm_vcc *new_vcc;
int error;
lock_sock(sk);
error = svc_create(sock_net(sk), newsock, 0, arg->kern);
if (error)
goto out;
new_vcc = ATM_SD(newsock);
pr_debug("%p -> %p\n", old_vcc, new_vcc);
while (1) {
DEFINE_WAIT(wait);
prepare_to_wait(sk_sleep(sk), &wait, TASK_INTERRUPTIBLE);
while (!(skb = skb_dequeue(&sk->sk_receive_queue)) &&
sigd) {
if (test_bit(ATM_VF_RELEASED, &old_vcc->flags))
break;
if (test_bit(ATM_VF_CLOSE, &old_vcc->flags)) {
error = -sk->sk_err;
break;
}
if (arg->flags & O_NONBLOCK) {
error = -EAGAIN;
break;
}
release_sock(sk);
schedule();
lock_sock(sk);
if (signal_pending(current)) {
error = -ERESTARTSYS;
break;
}
prepare_to_wait(sk_sleep(sk), &wait,
TASK_INTERRUPTIBLE);
}
finish_wait(sk_sleep(sk), &wait);
if (error)
goto out;
if (!skb) {
error = -EUNATCH;
goto out;
}
msg = (struct atmsvc_msg *)skb->data;
new_vcc->qos = msg->qos;
set_bit(ATM_VF_HASQOS, &new_vcc->flags);
new_vcc->remote = msg->svc;
new_vcc->local = msg->local;
new_vcc->sap = msg->sap;
error = vcc_connect(newsock, msg->pvc.sap_addr.itf,
msg->pvc.sap_addr.vpi,
msg->pvc.sap_addr.vci);
dev_kfree_skb(skb);
sk_acceptq_removed(sk);
if (error) {
sigd_enq2(NULL, as_reject, old_vcc, NULL, NULL,
&old_vcc->qos, error);
error = error == -EAGAIN ? -EBUSY : error;
goto out;
}
/* wait should be short, so we ignore the non-blocking flag */
set_bit(ATM_VF_WAITING, &new_vcc->flags);
sigd_enq(new_vcc, as_accept, old_vcc, NULL, NULL);
for (;;) {
prepare_to_wait(sk_sleep(sk_atm(new_vcc)), &wait,
TASK_UNINTERRUPTIBLE);
if (!test_bit(ATM_VF_WAITING, &new_vcc->flags) || !sigd)
break;
release_sock(sk);
schedule();
lock_sock(sk);
}
finish_wait(sk_sleep(sk_atm(new_vcc)), &wait);
if (!sigd) {
error = -EUNATCH;
goto out;
}
if (!sk_atm(new_vcc)->sk_err)
break;
if (sk_atm(new_vcc)->sk_err != ERESTARTSYS) {
error = -sk_atm(new_vcc)->sk_err;
goto out;
}
}
newsock->state = SS_CONNECTED;
out:
release_sock(sk);
return error;
}
static int svc_getname(struct socket *sock, struct sockaddr *sockaddr,
int peer)
{
struct sockaddr_atmsvc *addr;
addr = (struct sockaddr_atmsvc *) sockaddr;
memcpy(addr, peer ? &ATM_SD(sock)->remote : &ATM_SD(sock)->local,
sizeof(struct sockaddr_atmsvc));
return sizeof(struct sockaddr_atmsvc);
}
int svc_change_qos(struct atm_vcc *vcc, struct atm_qos *qos)
{
struct sock *sk = sk_atm(vcc);
DEFINE_WAIT(wait);
set_bit(ATM_VF_WAITING, &vcc->flags);
sigd_enq2(vcc, as_modify, NULL, NULL, &vcc->local, qos, 0);
for (;;) {
prepare_to_wait(sk_sleep(sk), &wait, TASK_UNINTERRUPTIBLE);
if (!test_bit(ATM_VF_WAITING, &vcc->flags) ||
test_bit(ATM_VF_RELEASED, &vcc->flags) || !sigd) {
break;
}
schedule();
}
finish_wait(sk_sleep(sk), &wait);
if (!sigd)
return -EUNATCH;
return -sk->sk_err;
}
static int svc_setsockopt(struct socket *sock, int level, int optname,
sockptr_t optval, unsigned int optlen)
{
struct sock *sk = sock->sk;
struct atm_vcc *vcc = ATM_SD(sock);
int value, error = 0;
lock_sock(sk);
switch (optname) {
case SO_ATMSAP:
if (level != SOL_ATM || optlen != sizeof(struct atm_sap)) {
error = -EINVAL;
goto out;
}
if (copy_from_sockptr(&vcc->sap, optval, optlen)) {
error = -EFAULT;
goto out;
}
set_bit(ATM_VF_HASSAP, &vcc->flags);
break;
case SO_MULTIPOINT:
if (level != SOL_ATM || optlen != sizeof(int)) {
error = -EINVAL;
goto out;
}
if (copy_from_sockptr(&value, optval, sizeof(int))) {
error = -EFAULT;
goto out;
}
if (value == 1)
set_bit(ATM_VF_SESSION, &vcc->flags);
else if (value == 0)
clear_bit(ATM_VF_SESSION, &vcc->flags);
else
error = -EINVAL;
break;
default:
error = vcc_setsockopt(sock, level, optname, optval, optlen);
}
out:
release_sock(sk);
return error;
}
static int svc_getsockopt(struct socket *sock, int level, int optname,
sockopt_t *opt)
{
struct sock *sk = sock->sk;
int error = 0, len;
lock_sock(sk);
if (!__SO_LEVEL_MATCH(optname, level) || optname != SO_ATMSAP) {
error = vcc_getsockopt(sock, level, optname, opt);
goto out;
}
len = opt->optlen;
if (len != sizeof(struct atm_sap)) {
error = -EINVAL;
goto out;
}
if (copy_to_iter(&ATM_SD(sock)->sap, sizeof(struct atm_sap),
&opt->iter_out) != sizeof(struct atm_sap)) {
error = -EFAULT;
goto out;
}
out:
release_sock(sk);
return error;
}
static int svc_addparty(struct socket *sock, struct sockaddr *sockaddr,
int sockaddr_len, int flags)
{
DEFINE_WAIT(wait);
struct sock *sk = sock->sk;
struct atm_vcc *vcc = ATM_SD(sock);
int error;
lock_sock(sk);
set_bit(ATM_VF_WAITING, &vcc->flags);
sigd_enq(vcc, as_addparty, NULL, NULL,
(struct sockaddr_atmsvc *) sockaddr);
if (flags & O_NONBLOCK) {
error = -EINPROGRESS;
goto out;
}
pr_debug("added wait queue\n");
for (;;) {
prepare_to_wait(sk_sleep(sk), &wait, TASK_INTERRUPTIBLE);
if (!test_bit(ATM_VF_WAITING, &vcc->flags) || !sigd)
break;
schedule();
}
finish_wait(sk_sleep(sk), &wait);
error = -xchg(&sk->sk_err_soft, 0);
out:
release_sock(sk);
return error;
}
static int svc_dropparty(struct socket *sock, int ep_ref)
{
DEFINE_WAIT(wait);
struct sock *sk = sock->sk;
struct atm_vcc *vcc = ATM_SD(sock);
int error;
lock_sock(sk);
set_bit(ATM_VF_WAITING, &vcc->flags);
sigd_enq2(vcc, as_dropparty, NULL, NULL, NULL, NULL, ep_ref);
for (;;) {
prepare_to_wait(sk_sleep(sk), &wait, TASK_INTERRUPTIBLE);
if (!test_bit(ATM_VF_WAITING, &vcc->flags) || !sigd)
break;
schedule();
}
finish_wait(sk_sleep(sk), &wait);
if (!sigd) {
error = -EUNATCH;
goto out;
}
error = -xchg(&sk->sk_err_soft, 0);
out:
release_sock(sk);
return error;
}
static int svc_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
{
int error, ep_ref;
struct sockaddr_atmsvc sa;
struct atm_vcc *vcc = ATM_SD(sock);
switch (cmd) {
case ATM_ADDPARTY:
if (!test_bit(ATM_VF_SESSION, &vcc->flags))
return -EINVAL;
if (copy_from_user(&sa, (void __user *) arg, sizeof(sa)))
return -EFAULT;
error = svc_addparty(sock, (struct sockaddr *)&sa, sizeof(sa),
0);
break;
case ATM_DROPPARTY:
if (!test_bit(ATM_VF_SESSION, &vcc->flags))
return -EINVAL;
if (copy_from_user(&ep_ref, (void __user *) arg, sizeof(int)))
return -EFAULT;
error = svc_dropparty(sock, ep_ref);
break;
default:
error = vcc_ioctl(sock, cmd, arg);
}
return error;
}
#ifdef CONFIG_COMPAT
static int svc_compat_ioctl(struct socket *sock, unsigned int cmd,
unsigned long arg)
{
/* The definition of ATM_ADDPARTY uses the size of struct atm_iobuf.
But actually it takes a struct sockaddr_atmsvc, which doesn't need
compat handling. So all we have to do is fix up cmd... */
if (cmd == COMPAT_ATM_ADDPARTY)
cmd = ATM_ADDPARTY;
if (cmd == ATM_ADDPARTY || cmd == ATM_DROPPARTY)
return svc_ioctl(sock, cmd, arg);
else
return vcc_compat_ioctl(sock, cmd, arg);
}
#endif /* CONFIG_COMPAT */
static const struct proto_ops svc_proto_ops = {
.family = PF_ATMSVC,
.owner = THIS_MODULE,
.release = svc_release,
.bind = svc_bind,
.connect = svc_connect,
.socketpair = sock_no_socketpair,
.accept = svc_accept,
.getname = svc_getname,
.poll = vcc_poll,
.ioctl = svc_ioctl,
#ifdef CONFIG_COMPAT
.compat_ioctl = svc_compat_ioctl,
#endif
.gettstamp = sock_gettstamp,
.listen = svc_listen,
.shutdown = svc_shutdown,
.setsockopt = svc_setsockopt,
.getsockopt_iter = svc_getsockopt,
.sendmsg = vcc_sendmsg,
.recvmsg = vcc_recvmsg,
.mmap = sock_no_mmap,
};
static int svc_create(struct net *net, struct socket *sock, int protocol,
int kern)
{
int error;
if (!net_eq(net, &init_net))
return -EAFNOSUPPORT;
sock->ops = &svc_proto_ops;
error = vcc_create(net, sock, protocol, AF_ATMSVC, kern);
if (error)
return error;
ATM_SD(sock)->local.sas_family = AF_ATMSVC;
ATM_SD(sock)->remote.sas_family = AF_ATMSVC;
return 0;
}
static const struct net_proto_family svc_family_ops = {
.family = PF_ATMSVC,
.create = svc_create,
.owner = THIS_MODULE,
};
/*
* Initialize the ATM SVC protocol family
*/
int __init atmsvc_init(void)
{
return sock_register(&svc_family_ops);
}
void atmsvc_exit(void)
{
sock_unregister(PF_ATMSVC);
}