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
|
/* net/atm/atm_misc.c - Various functions for use by ATM drivers */
/* Written 1995-1999 by Werner Almesberger, EPFL ICA */
#include <linux/module.h>
#include <linux/atm.h>
#include <linux/atmdev.h>
#include <linux/skbuff.h>
#include <asm/atomic.h>
#include <asm/errno.h>
int atm_charge(struct atm_vcc *vcc,int truesize)
{
atm_force_charge(vcc,truesize);
if (atomic_read(&vcc->rx_inuse) <= vcc->sk->rcvbuf) return 1;
atm_return(vcc,truesize);
vcc->stats->rx_drop++;
return 0;
}
struct sk_buff *atm_alloc_charge(struct atm_vcc *vcc,int pdu_size,
int gfp_flags)
{
int guess = atm_guess_pdu2truesize(pdu_size);
atm_force_charge(vcc,guess);
if (atomic_read(&vcc->rx_inuse) <= vcc->sk->rcvbuf) {
struct sk_buff *skb = alloc_skb(pdu_size,gfp_flags);
if (skb) {
atomic_add(skb->truesize-guess,&vcc->rx_inuse);
return skb;
}
}
atm_return(vcc,guess);
vcc->stats->rx_drop++;
return NULL;
}
static int check_ci(struct atm_vcc *vcc,short vpi,int vci)
{
struct atm_vcc *walk;
for (walk = vcc->dev->vccs; walk; walk = walk->next)
if ((walk->flags & ATM_VF_ADDR) && walk->vpi == vpi &&
walk->vci == vci && ((walk->qos.txtp.traffic_class !=
ATM_NONE && vcc->qos.txtp.traffic_class != ATM_NONE) ||
(walk->qos.rxtp.traffic_class != ATM_NONE &&
vcc->qos.rxtp.traffic_class != ATM_NONE)))
return -EADDRINUSE;
/* allow VCCs with same VPI/VCI iff they don't collide on
TX/RX (but we may refuse such sharing for other reasons,
e.g. if protocol requires to have both channels) */
return 0;
}
int atm_find_ci(struct atm_vcc *vcc,short *vpi,int *vci)
{
static short p = 0; /* poor man's per-device cache */
static int c = 0;
short old_p;
int old_c;
if (*vpi != ATM_VPI_ANY && *vci != ATM_VCI_ANY)
return check_ci(vcc,*vpi,*vci);
/* last scan may have left values out of bounds for current device */
if (*vpi != ATM_VPI_ANY) p = *vpi;
else if (p >= 1 << vcc->dev->ci_range.vpi_bits) p = 0;
if (*vci != ATM_VCI_ANY) c = *vci;
else if (c < ATM_NOT_RSV_VCI || c >= 1 << vcc->dev->ci_range.vci_bits)
c = ATM_NOT_RSV_VCI;
old_p = p;
old_c = c;
do {
if (!check_ci(vcc,p,c)) {
*vpi = p;
*vci = c;
return 0;
}
if (*vci == ATM_VCI_ANY) {
c++;
if (c >= 1 << vcc->dev->ci_range.vci_bits)
c = ATM_NOT_RSV_VCI;
}
if ((c == ATM_NOT_RSV_VCI || *vci != ATM_VCI_ANY) &&
*vpi == ATM_VPI_ANY) {
p++;
if (p >= 1 << vcc->dev->ci_range.vpi_bits) p = 0;
}
}
while (old_p != p || old_c != c);
return -EADDRINUSE;
}
/*
* atm_pcr_goal returns the positive PCR if it should be rounded up, the
* negative PCR if it should be rounded down, and zero if the maximum available
* bandwidth should be used.
*
* The rules are as follows (* = maximum, - = absent (0), x = value "x",
* (x+ = x or next value above x, x- = x or next value below):
*
* min max pcr result min max pcr result
* - - - * (UBR only) x - - x+
* - - * * x - * *
* - - z z- x - z z-
* - * - * x * - x+
* - * * * x * * *
* - * z z- x * z z-
* - y - y- x y - x+
* - y * y- x y * y-
* - y z z- x y z z-
*
* All non-error cases can be converted with the following simple set of rules:
*
* if pcr == z then z-
* else if min == x && pcr == - then x+
* else if max == y then y-
* else *
*/
int atm_pcr_goal(struct atm_trafprm *tp)
{
if (tp->pcr && tp->pcr != ATM_MAX_PCR) return -tp->pcr;
if (tp->min_pcr && !tp->pcr) return tp->min_pcr;
if (tp->max_pcr != ATM_MAX_PCR) return -tp->max_pcr;
return 0;
}
EXPORT_SYMBOL(atm_charge);
EXPORT_SYMBOL(atm_alloc_charge);
EXPORT_SYMBOL(atm_find_ci);
EXPORT_SYMBOL(atm_pcr_goal);
|