[PATCH] cryptoloop
[linux-2.6/history.git] / net / atm / atm_misc.c
blob76823d010f07f65821f66441d8efea61b72deb31
1 /* net/atm/atm_misc.c - Various functions for use by ATM drivers */
3 /* Written 1995-2000 by Werner Almesberger, EPFL ICA */
6 #include <linux/module.h>
7 #include <linux/atm.h>
8 #include <linux/atmdev.h>
9 #include <linux/skbuff.h>
10 #include <linux/sonet.h>
11 #include <linux/bitops.h>
12 #include <asm/atomic.h>
13 #include <asm/errno.h>
16 int atm_charge(struct atm_vcc *vcc,int truesize)
18 atm_force_charge(vcc,truesize);
19 if (atomic_read(&vcc->sk->sk_rmem_alloc) <= vcc->sk->sk_rcvbuf)
20 return 1;
21 atm_return(vcc,truesize);
22 atomic_inc(&vcc->stats->rx_drop);
23 return 0;
27 struct sk_buff *atm_alloc_charge(struct atm_vcc *vcc,int pdu_size,
28 int gfp_flags)
30 int guess = atm_guess_pdu2truesize(pdu_size);
32 atm_force_charge(vcc,guess);
33 if (atomic_read(&vcc->sk->sk_rmem_alloc) <= vcc->sk->sk_rcvbuf) {
34 struct sk_buff *skb = alloc_skb(pdu_size,gfp_flags);
36 if (skb) {
37 atomic_add(skb->truesize-guess,
38 &vcc->sk->sk_rmem_alloc);
39 return skb;
42 atm_return(vcc,guess);
43 atomic_inc(&vcc->stats->rx_drop);
44 return NULL;
48 static int check_ci(struct atm_vcc *vcc,short vpi,int vci)
50 struct hlist_node *node;
51 struct sock *s;
52 struct atm_vcc *walk;
54 sk_for_each(s, node, &vcc_sklist) {
55 walk = atm_sk(s);
56 if (walk->dev != vcc->dev)
57 continue;
58 if (test_bit(ATM_VF_ADDR,&walk->flags) && walk->vpi == vpi &&
59 walk->vci == vci && ((walk->qos.txtp.traffic_class !=
60 ATM_NONE && vcc->qos.txtp.traffic_class != ATM_NONE) ||
61 (walk->qos.rxtp.traffic_class != ATM_NONE &&
62 vcc->qos.rxtp.traffic_class != ATM_NONE)))
63 return -EADDRINUSE;
65 /* allow VCCs with same VPI/VCI iff they don't collide on
66 TX/RX (but we may refuse such sharing for other reasons,
67 e.g. if protocol requires to have both channels) */
68 return 0;
72 int atm_find_ci(struct atm_vcc *vcc,short *vpi,int *vci)
74 static short p = 0; /* poor man's per-device cache */
75 static int c = 0;
76 short old_p;
77 int old_c;
78 int err;
80 read_lock(&vcc_sklist_lock);
81 if (*vpi != ATM_VPI_ANY && *vci != ATM_VCI_ANY) {
82 err = check_ci(vcc,*vpi,*vci);
83 read_unlock(&vcc_sklist_lock);
84 return err;
86 /* last scan may have left values out of bounds for current device */
87 if (*vpi != ATM_VPI_ANY) p = *vpi;
88 else if (p >= 1 << vcc->dev->ci_range.vpi_bits) p = 0;
89 if (*vci != ATM_VCI_ANY) c = *vci;
90 else if (c < ATM_NOT_RSV_VCI || c >= 1 << vcc->dev->ci_range.vci_bits)
91 c = ATM_NOT_RSV_VCI;
92 old_p = p;
93 old_c = c;
94 do {
95 if (!check_ci(vcc,p,c)) {
96 *vpi = p;
97 *vci = c;
98 read_unlock(&vcc_sklist_lock);
99 return 0;
101 if (*vci == ATM_VCI_ANY) {
102 c++;
103 if (c >= 1 << vcc->dev->ci_range.vci_bits)
104 c = ATM_NOT_RSV_VCI;
106 if ((c == ATM_NOT_RSV_VCI || *vci != ATM_VCI_ANY) &&
107 *vpi == ATM_VPI_ANY) {
108 p++;
109 if (p >= 1 << vcc->dev->ci_range.vpi_bits) p = 0;
112 while (old_p != p || old_c != c);
113 read_unlock(&vcc_sklist_lock);
114 return -EADDRINUSE;
119 * atm_pcr_goal returns the positive PCR if it should be rounded up, the
120 * negative PCR if it should be rounded down, and zero if the maximum available
121 * bandwidth should be used.
123 * The rules are as follows (* = maximum, - = absent (0), x = value "x",
124 * (x+ = x or next value above x, x- = x or next value below):
126 * min max pcr result min max pcr result
127 * - - - * (UBR only) x - - x+
128 * - - * * x - * *
129 * - - z z- x - z z-
130 * - * - * x * - x+
131 * - * * * x * * *
132 * - * z z- x * z z-
133 * - y - y- x y - x+
134 * - y * y- x y * y-
135 * - y z z- x y z z-
137 * All non-error cases can be converted with the following simple set of rules:
139 * if pcr == z then z-
140 * else if min == x && pcr == - then x+
141 * else if max == y then y-
142 * else *
146 int atm_pcr_goal(struct atm_trafprm *tp)
148 if (tp->pcr && tp->pcr != ATM_MAX_PCR) return -tp->pcr;
149 if (tp->min_pcr && !tp->pcr) return tp->min_pcr;
150 if (tp->max_pcr != ATM_MAX_PCR) return -tp->max_pcr;
151 return 0;
155 void sonet_copy_stats(struct k_sonet_stats *from,struct sonet_stats *to)
157 #define __HANDLE_ITEM(i) to->i = atomic_read(&from->i)
158 __SONET_ITEMS
159 #undef __HANDLE_ITEM
163 void sonet_subtract_stats(struct k_sonet_stats *from,struct sonet_stats *to)
165 #define __HANDLE_ITEM(i) atomic_sub(to->i,&from->i)
166 __SONET_ITEMS
167 #undef __HANDLE_ITEM
171 EXPORT_SYMBOL(atm_charge);
172 EXPORT_SYMBOL(atm_alloc_charge);
173 EXPORT_SYMBOL(atm_find_ci);
174 EXPORT_SYMBOL(atm_pcr_goal);
175 EXPORT_SYMBOL(sonet_copy_stats);
176 EXPORT_SYMBOL(sonet_subtract_stats);