summaryrefslogtreecommitdiffstats
path: root/net/atm/pvc.c
blob: 2493f04aa6bfbf6526cfdc73dbaaaa4a191bfd4b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
/* net/atm/pvc.c - ATM PVC sockets */

/* Written 1995-2000 by Werner Almesberger, EPFL LRC/ICA */


#include <linux/config.h>
#include <linux/net.h>		/* struct socket, struct net_proto,
				   struct proto_ops */
#include <linux/atm.h>		/* ATM stuff */
#include <linux/atmdev.h>	/* ATM devices */
#include <linux/atmclip.h>	/* Classical IP over ATM */
#include <linux/errno.h>	/* error codes */
#include <linux/kernel.h>	/* printk */
#include <linux/init.h>
#include <linux/skbuff.h>
#include <linux/bitops.h>
#include <net/sock.h>		/* for sock_no_* */
#ifdef CONFIG_ATM_CLIP
#include <net/atmclip.h>
#endif

#include "resources.h"		/* devs and vccs */
#include "common.h"		/* common for PVCs and SVCs */

#ifndef NULL
#define NULL 0
#endif


static int pvc_shutdown(struct socket *sock,int how)
{
	return 0;
}


static int pvc_bind(struct socket *sock,struct sockaddr *sockaddr,
    int sockaddr_len)
{
	struct sockaddr_atmpvc *addr;
	struct atm_vcc *vcc;

	if (sockaddr_len != sizeof(struct sockaddr_atmpvc)) return -EINVAL;
	addr = (struct sockaddr_atmpvc *) sockaddr;
	if (addr->sap_family != AF_ATMPVC) return -EAFNOSUPPORT;
	vcc = ATM_SD(sock);
	if (!test_bit(ATM_VF_HASQOS,&vcc->flags)) return -EBADFD;
	if (test_bit(ATM_VF_PARTIAL,&vcc->flags)) {
		if (vcc->vpi != ATM_VPI_UNSPEC) addr->sap_addr.vpi = vcc->vpi;
		if (vcc->vci != ATM_VCI_UNSPEC) addr->sap_addr.vci = vcc->vci;
	}
	return atm_connect(sock,addr->sap_addr.itf,addr->sap_addr.vpi,
	    addr->sap_addr.vci);
}


static int pvc_connect(struct socket *sock,struct sockaddr *sockaddr,
    int sockaddr_len,int flags)
{
	return pvc_bind(sock,sockaddr,sockaddr_len);
}


static int pvc_getname(struct socket *sock,struct sockaddr *sockaddr,
    int *sockaddr_len,int peer)
{
	struct sockaddr_atmpvc *addr;
	struct atm_vcc *vcc = ATM_SD(sock);

	if (!vcc->dev || !test_bit(ATM_VF_ADDR,&vcc->flags)) return -ENOTCONN;
        *sockaddr_len = sizeof(struct sockaddr_atmpvc);
	addr = (struct sockaddr_atmpvc *) sockaddr;
	addr->sap_family = AF_ATMPVC;
	addr->sap_addr.itf = vcc->dev->number;
	addr->sap_addr.vpi = vcc->vpi;
	addr->sap_addr.vci = vcc->vci;
	return 0;
}


static struct proto_ops SOCKOPS_WRAPPED(pvc_proto_ops) = {
	PF_ATMPVC,
	atm_release,
	pvc_bind,
	pvc_connect,
	sock_no_socketpair,
	sock_no_accept,
	pvc_getname,
	atm_poll,
	atm_ioctl,
	sock_no_listen,
	pvc_shutdown,
	atm_setsockopt,
	atm_getsockopt,
	sock_no_fcntl,
	atm_sendmsg,
	atm_recvmsg,
	sock_no_mmap
};


#include <linux/smp_lock.h>
SOCKOPS_WRAP(pvc_proto, PF_ATMPVC);


static int pvc_create(struct socket *sock,int protocol)
{
	sock->ops = &pvc_proto_ops;
	return atm_create(sock,protocol,PF_ATMPVC);
}


static struct net_proto_family pvc_family_ops = {
	PF_ATMPVC,
	pvc_create,
	0,			/* no authentication */
	0,			/* no encryption */
	0			/* no encrypt_net */
};


/*
 *	Initialize the ATM PVC protocol family
 */


void __init atmpvc_proto_init(struct net_proto *pro)
{
	int error;

	error = sock_register(&pvc_family_ops);
	if (error < 0) {
		printk(KERN_ERR "ATMPVC: can't register (%d)",error);
		return;
	}
#ifdef CONFIG_ATM_CLIP
	atm_clip_init();
#endif
#ifdef CONFIG_PROC_FS
	error = atm_proc_init();
	if (error) printk("atm_proc_init fails with %d\n",error);
#endif
}