diff options
author | James Bottomley <jejb@sparkweed.localdomain> | 2006-09-23 22:03:52 -0400 |
---|---|---|
committer | James Bottomley <jejb@sparkweed.localdomain> | 2006-09-23 22:03:52 -0400 |
commit | 1aedf2ccc60fade26c46fae12e28664d0da3f199 (patch) | |
tree | d91083e3079f1ddb942a382ac2b5a7525570ad59 | |
parent | dfdc58ba354adb80d67c99f7be84f95a8e02e466 (diff) | |
parent | 1ab9dd0902df4f4ff56fbf672220549090ab28ba (diff) |
Merge mulgrave-w:git/linux-2.6
Conflicts:
include/linux/blkdev.h
Trivial merge to incorporate tag prototypes.
628 files changed, 33028 insertions, 15465 deletions
@@ -2384,6 +2384,13 @@ N: Thomas Molina | |||
2384 | E: tmolina@cablespeed.com | 2384 | E: tmolina@cablespeed.com |
2385 | D: bug fixes, documentation, minor hackery | 2385 | D: bug fixes, documentation, minor hackery |
2386 | 2386 | ||
2387 | N: Paul Moore | ||
2388 | E: paul.moore@hp.com | ||
2389 | D: NetLabel author | ||
2390 | S: Hewlett-Packard | ||
2391 | S: 110 Spit Brook Road | ||
2392 | S: Nashua, NH 03062 | ||
2393 | |||
2387 | N: James Morris | 2394 | N: James Morris |
2388 | E: jmorris@namei.org | 2395 | E: jmorris@namei.org |
2389 | W: http://namei.org/ | 2396 | W: http://namei.org/ |
diff --git a/Documentation/00-INDEX b/Documentation/00-INDEX index 5f7f7d7f77d2..02457ec9c94f 100644 --- a/Documentation/00-INDEX +++ b/Documentation/00-INDEX | |||
@@ -184,6 +184,8 @@ mtrr.txt | |||
184 | - how to use PPro Memory Type Range Registers to increase performance. | 184 | - how to use PPro Memory Type Range Registers to increase performance. |
185 | nbd.txt | 185 | nbd.txt |
186 | - info on a TCP implementation of a network block device. | 186 | - info on a TCP implementation of a network block device. |
187 | netlabel/ | ||
188 | - directory with information on the NetLabel subsystem. | ||
187 | networking/ | 189 | networking/ |
188 | - directory with info on various aspects of networking with Linux. | 190 | - directory with info on various aspects of networking with Linux. |
189 | nfsroot.txt | 191 | nfsroot.txt |
diff --git a/Documentation/netlabel/00-INDEX b/Documentation/netlabel/00-INDEX new file mode 100644 index 000000000000..837bf35990e2 --- /dev/null +++ b/Documentation/netlabel/00-INDEX | |||
@@ -0,0 +1,10 @@ | |||
1 | 00-INDEX | ||
2 | - this file. | ||
3 | cipso_ipv4.txt | ||
4 | - documentation on the IPv4 CIPSO protocol engine. | ||
5 | draft-ietf-cipso-ipsecurity-01.txt | ||
6 | - IETF draft of the CIPSO protocol, dated 16 July 1992. | ||
7 | introduction.txt | ||
8 | - NetLabel introduction, READ THIS FIRST. | ||
9 | lsm_interface.txt | ||
10 | - documentation on the NetLabel kernel security module API. | ||
diff --git a/Documentation/netlabel/cipso_ipv4.txt b/Documentation/netlabel/cipso_ipv4.txt new file mode 100644 index 000000000000..93dacb132c3c --- /dev/null +++ b/Documentation/netlabel/cipso_ipv4.txt | |||
@@ -0,0 +1,48 @@ | |||
1 | NetLabel CIPSO/IPv4 Protocol Engine | ||
2 | ============================================================================== | ||
3 | Paul Moore, paul.moore@hp.com | ||
4 | |||
5 | May 17, 2006 | ||
6 | |||
7 | * Overview | ||
8 | |||
9 | The NetLabel CIPSO/IPv4 protocol engine is based on the IETF Commercial IP | ||
10 | Security Option (CIPSO) draft from July 16, 1992. A copy of this draft can be | ||
11 | found in this directory, consult '00-INDEX' for the filename. While the IETF | ||
12 | draft never made it to an RFC standard it has become a de-facto standard for | ||
13 | labeled networking and is used in many trusted operating systems. | ||
14 | |||
15 | * Outbound Packet Processing | ||
16 | |||
17 | The CIPSO/IPv4 protocol engine applies the CIPSO IP option to packets by | ||
18 | adding the CIPSO label to the socket. This causes all packets leaving the | ||
19 | system through the socket to have the CIPSO IP option applied. The socket's | ||
20 | CIPSO label can be changed at any point in time, however, it is recommended | ||
21 | that it is set upon the socket's creation. The LSM can set the socket's CIPSO | ||
22 | label by using the NetLabel security module API; if the NetLabel "domain" is | ||
23 | configured to use CIPSO for packet labeling then a CIPSO IP option will be | ||
24 | generated and attached to the socket. | ||
25 | |||
26 | * Inbound Packet Processing | ||
27 | |||
28 | The CIPSO/IPv4 protocol engine validates every CIPSO IP option it finds at the | ||
29 | IP layer without any special handling required by the LSM. However, in order | ||
30 | to decode and translate the CIPSO label on the packet the LSM must use the | ||
31 | NetLabel security module API to extract the security attributes of the packet. | ||
32 | This is typically done at the socket layer using the 'socket_sock_rcv_skb()' | ||
33 | LSM hook. | ||
34 | |||
35 | * Label Translation | ||
36 | |||
37 | The CIPSO/IPv4 protocol engine contains a mechanism to translate CIPSO security | ||
38 | attributes such as sensitivity level and category to values which are | ||
39 | appropriate for the host. These mappings are defined as part of a CIPSO | ||
40 | Domain Of Interpretation (DOI) definition and are configured through the | ||
41 | NetLabel user space communication layer. Each DOI definition can have a | ||
42 | different security attribute mapping table. | ||
43 | |||
44 | * Label Translation Cache | ||
45 | |||
46 | The NetLabel system provides a framework for caching security attribute | ||
47 | mappings from the network labels to the corresponding LSM identifiers. The | ||
48 | CIPSO/IPv4 protocol engine supports this caching mechanism. | ||
diff --git a/Documentation/netlabel/draft-ietf-cipso-ipsecurity-01.txt b/Documentation/netlabel/draft-ietf-cipso-ipsecurity-01.txt new file mode 100644 index 000000000000..256c2c9d4f50 --- /dev/null +++ b/Documentation/netlabel/draft-ietf-cipso-ipsecurity-01.txt | |||
@@ -0,0 +1,791 @@ | |||
1 | IETF CIPSO Working Group | ||
2 | 16 July, 1992 | ||
3 | |||
4 | |||
5 | |||
6 | COMMERCIAL IP SECURITY OPTION (CIPSO 2.2) | ||
7 | |||
8 | |||
9 | |||
10 | 1. Status | ||
11 | |||
12 | This Internet Draft provides the high level specification for a Commercial | ||
13 | IP Security Option (CIPSO). This draft reflects the version as approved by | ||
14 | the CIPSO IETF Working Group. Distribution of this memo is unlimited. | ||
15 | |||
16 | This document is an Internet Draft. Internet Drafts are working documents | ||
17 | of the Internet Engineering Task Force (IETF), its Areas, and its Working | ||
18 | Groups. Note that other groups may also distribute working documents as | ||
19 | Internet Drafts. | ||
20 | |||
21 | Internet Drafts are draft documents valid for a maximum of six months. | ||
22 | Internet Drafts may be updated, replaced, or obsoleted by other documents | ||
23 | at any time. It is not appropriate to use Internet Drafts as reference | ||
24 | material or to cite them other than as a "working draft" or "work in | ||
25 | progress." | ||
26 | |||
27 | Please check the I-D abstract listing contained in each Internet Draft | ||
28 | directory to learn the current status of this or any other Internet Draft. | ||
29 | |||
30 | |||
31 | |||
32 | |||
33 | 2. Background | ||
34 | |||
35 | Currently the Internet Protocol includes two security options. One of | ||
36 | these options is the DoD Basic Security Option (BSO) (Type 130) which allows | ||
37 | IP datagrams to be labeled with security classifications. This option | ||
38 | provides sixteen security classifications and a variable number of handling | ||
39 | restrictions. To handle additional security information, such as security | ||
40 | categories or compartments, another security option (Type 133) exists and | ||
41 | is referred to as the DoD Extended Security Option (ESO). The values for | ||
42 | the fixed fields within these two options are administered by the Defense | ||
43 | Information Systems Agency (DISA). | ||
44 | |||
45 | Computer vendors are now building commercial operating systems with | ||
46 | mandatory access controls and multi-level security. These systems are | ||
47 | no longer built specifically for a particular group in the defense or | ||
48 | intelligence communities. They are generally available commercial systems | ||
49 | for use in a variety of government and civil sector environments. | ||
50 | |||
51 | The small number of ESO format codes can not support all the possible | ||
52 | applications of a commercial security option. The BSO and ESO were | ||
53 | designed to only support the United States DoD. CIPSO has been designed | ||
54 | to support multiple security policies. This Internet Draft provides the | ||
55 | format and procedures required to support a Mandatory Access Control | ||
56 | security policy. Support for additional security policies shall be | ||
57 | defined in future RFCs. | ||
58 | |||
59 | |||
60 | |||
61 | |||
62 | Internet Draft, Expires 15 Jan 93 [PAGE 1] | ||
63 | |||
64 | |||
65 | |||
66 | CIPSO INTERNET DRAFT 16 July, 1992 | ||
67 | |||
68 | |||
69 | |||
70 | |||
71 | 3. CIPSO Format | ||
72 | |||
73 | Option type: 134 (Class 0, Number 6, Copy on Fragmentation) | ||
74 | Option length: Variable | ||
75 | |||
76 | This option permits security related information to be passed between | ||
77 | systems within a single Domain of Interpretation (DOI). A DOI is a | ||
78 | collection of systems which agree on the meaning of particular values | ||
79 | in the security option. An authority that has been assigned a DOI | ||
80 | identifier will define a mapping between appropriate CIPSO field values | ||
81 | and their human readable equivalent. This authority will distribute that | ||
82 | mapping to hosts within the authority's domain. These mappings may be | ||
83 | sensitive, therefore a DOI authority is not required to make these | ||
84 | mappings available to anyone other than the systems that are included in | ||
85 | the DOI. | ||
86 | |||
87 | This option MUST be copied on fragmentation. This option appears at most | ||
88 | once in a datagram. All multi-octet fields in the option are defined to be | ||
89 | transmitted in network byte order. The format of this option is as follows: | ||
90 | |||
91 | +----------+----------+------//------+-----------//---------+ | ||
92 | | 10000110 | LLLLLLLL | DDDDDDDDDDDD | TTTTTTTTTTTTTTTTTTTT | | ||
93 | +----------+----------+------//------+-----------//---------+ | ||
94 | |||
95 | TYPE=134 OPTION DOMAIN OF TAGS | ||
96 | LENGTH INTERPRETATION | ||
97 | |||
98 | |||
99 | Figure 1. CIPSO Format | ||
100 | |||
101 | |||
102 | 3.1 Type | ||
103 | |||
104 | This field is 1 octet in length. Its value is 134. | ||
105 | |||
106 | |||
107 | 3.2 Length | ||
108 | |||
109 | This field is 1 octet in length. It is the total length of the option | ||
110 | including the type and length fields. With the current IP header length | ||
111 | restriction of 40 octets the value of this field MUST not exceed 40. | ||
112 | |||
113 | |||
114 | 3.3 Domain of Interpretation Identifier | ||
115 | |||
116 | This field is an unsigned 32 bit integer. The value 0 is reserved and MUST | ||
117 | not appear as the DOI identifier in any CIPSO option. Implementations | ||
118 | should assume that the DOI identifier field is not aligned on any particular | ||
119 | byte boundary. | ||
120 | |||
121 | To conserve space in the protocol, security levels and categories are | ||
122 | represented by numbers rather than their ASCII equivalent. This requires | ||
123 | a mapping table within CIPSO hosts to map these numbers to their | ||
124 | corresponding ASCII representations. Non-related groups of systems may | ||
125 | |||
126 | |||
127 | |||
128 | Internet Draft, Expires 15 Jan 93 [PAGE 2] | ||
129 | |||
130 | |||
131 | |||
132 | CIPSO INTERNET DRAFT 16 July, 1992 | ||
133 | |||
134 | |||
135 | |||
136 | have their own unique mappings. For example, one group of systems may | ||
137 | use the number 5 to represent Unclassified while another group may use the | ||
138 | number 1 to represent that same security level. The DOI identifier is used | ||
139 | to identify which mapping was used for the values within the option. | ||
140 | |||
141 | |||
142 | 3.4 Tag Types | ||
143 | |||
144 | A common format for passing security related information is necessary | ||
145 | for interoperability. CIPSO uses sets of "tags" to contain the security | ||
146 | information relevant to the data in the IP packet. Each tag begins with | ||
147 | a tag type identifier followed by the length of the tag and ends with the | ||
148 | actual security information to be passed. All multi-octet fields in a tag | ||
149 | are defined to be transmitted in network byte order. Like the DOI | ||
150 | identifier field in the CIPSO header, implementations should assume that | ||
151 | all tags, as well as fields within a tag, are not aligned on any particular | ||
152 | octet boundary. The tag types defined in this document contain alignment | ||
153 | bytes to assist alignment of some information, however alignment can not | ||
154 | be guaranteed if CIPSO is not the first IP option. | ||
155 | |||
156 | CIPSO tag types 0 through 127 are reserved for defining standard tag | ||
157 | formats. Their definitions will be published in RFCs. Tag types whose | ||
158 | identifiers are greater than 127 are defined by the DOI authority and may | ||
159 | only be meaningful in certain Domains of Interpretation. For these tag | ||
160 | types, implementations will require the DOI identifier as well as the tag | ||
161 | number to determine the security policy and the format associated with the | ||
162 | tag. Use of tag types above 127 are restricted to closed networks where | ||
163 | interoperability with other networks will not be an issue. Implementations | ||
164 | that support a tag type greater than 127 MUST support at least one DOI that | ||
165 | requires only tag types 1 to 127. | ||
166 | |||
167 | Tag type 0 is reserved. Tag types 1, 2, and 5 are defined in this | ||
168 | Internet Draft. Types 3 and 4 are reserved for work in progress. | ||
169 | The standard format for all current and future CIPSO tags is shown below: | ||
170 | |||
171 | +----------+----------+--------//--------+ | ||
172 | | TTTTTTTT | LLLLLLLL | IIIIIIIIIIIIIIII | | ||
173 | +----------+----------+--------//--------+ | ||
174 | TAG TAG TAG | ||
175 | TYPE LENGTH INFORMATION | ||
176 | |||
177 | Figure 2: Standard Tag Format | ||
178 | |||
179 | In the three tag types described in this document, the length and count | ||
180 | restrictions are based on the current IP limitation of 40 octets for all | ||
181 | IP options. If the IP header is later expanded, then the length and count | ||
182 | restrictions specified in this document may increase to use the full area | ||
183 | provided for IP options. | ||
184 | |||
185 | |||
186 | 3.4.1 Tag Type Classes | ||
187 | |||
188 | Tag classes consist of tag types that have common processing requirements | ||
189 | and support the same security policy. The three tags defined in this | ||
190 | Internet Draft belong to the Mandatory Access Control (MAC) Sensitivity | ||
191 | |||
192 | |||
193 | |||
194 | Internet Draft, Expires 15 Jan 93 [PAGE 3] | ||
195 | |||
196 | |||
197 | |||
198 | CIPSO INTERNET DRAFT 16 July, 1992 | ||
199 | |||
200 | |||
201 | |||
202 | class and support the MAC Sensitivity security policy. | ||
203 | |||
204 | |||
205 | 3.4.2 Tag Type 1 | ||
206 | |||
207 | This is referred to as the "bit-mapped" tag type. Tag type 1 is included | ||
208 | in the MAC Sensitivity tag type class. The format of this tag type is as | ||
209 | follows: | ||
210 | |||
211 | +----------+----------+----------+----------+--------//---------+ | ||
212 | | 00000001 | LLLLLLLL | 00000000 | LLLLLLLL | CCCCCCCCCCCCCCCCC | | ||
213 | +----------+----------+----------+----------+--------//---------+ | ||
214 | |||
215 | TAG TAG ALIGNMENT SENSITIVITY BIT MAP OF | ||
216 | TYPE LENGTH OCTET LEVEL CATEGORIES | ||
217 | |||
218 | Figure 3. Tag Type 1 Format | ||
219 | |||
220 | |||
221 | 3.4.2.1 Tag Type | ||
222 | |||
223 | This field is 1 octet in length and has a value of 1. | ||
224 | |||
225 | |||
226 | 3.4.2.2 Tag Length | ||
227 | |||
228 | This field is 1 octet in length. It is the total length of the tag type | ||
229 | including the type and length fields. With the current IP header length | ||
230 | restriction of 40 bytes the value within this field is between 4 and 34. | ||
231 | |||
232 | |||
233 | 3.4.2.3 Alignment Octet | ||
234 | |||
235 | This field is 1 octet in length and always has the value of 0. Its purpose | ||
236 | is to align the category bitmap field on an even octet boundary. This will | ||
237 | speed many implementations including router implementations. | ||
238 | |||
239 | |||
240 | 3.4.2.4 Sensitivity Level | ||
241 | |||
242 | This field is 1 octet in length. Its value is from 0 to 255. The values | ||
243 | are ordered with 0 being the minimum value and 255 representing the maximum | ||
244 | value. | ||
245 | |||
246 | |||
247 | 3.4.2.5 Bit Map of Categories | ||
248 | |||
249 | The length of this field is variable and ranges from 0 to 30 octets. This | ||
250 | provides representation of categories 0 to 239. The ordering of the bits | ||
251 | is left to right or MSB to LSB. For example category 0 is represented by | ||
252 | the most significant bit of the first byte and category 15 is represented | ||
253 | by the least significant bit of the second byte. Figure 4 graphically | ||
254 | shows this ordering. Bit N is binary 1 if category N is part of the label | ||
255 | for the datagram, and bit N is binary 0 if category N is not part of the | ||
256 | label. Except for the optimized tag 1 format described in the next section, | ||
257 | |||
258 | |||
259 | |||
260 | Internet Draft, Expires 15 Jan 93 [PAGE 4] | ||
261 | |||
262 | |||
263 | |||
264 | CIPSO INTERNET DRAFT 16 July, 1992 | ||
265 | |||
266 | |||
267 | |||
268 | minimal encoding SHOULD be used resulting in no trailing zero octets in the | ||
269 | category bitmap. | ||
270 | |||
271 | octet 0 octet 1 octet 2 octet 3 octet 4 octet 5 | ||
272 | XXXXXXXX XXXXXXXX XXXXXXXX XXXXXXXX XXXXXXXX XXXXXXXX . . . | ||
273 | bit 01234567 89111111 11112222 22222233 33333333 44444444 | ||
274 | number 012345 67890123 45678901 23456789 01234567 | ||
275 | |||
276 | Figure 4. Ordering of Bits in Tag 1 Bit Map | ||
277 | |||
278 | |||
279 | 3.4.2.6 Optimized Tag 1 Format | ||
280 | |||
281 | Routers work most efficiently when processing fixed length fields. To | ||
282 | support these routers there is an optimized form of tag type 1. The format | ||
283 | does not change. The only change is to the category bitmap which is set to | ||
284 | a constant length of 10 octets. Trailing octets required to fill out the 10 | ||
285 | octets are zero filled. Ten octets, allowing for 80 categories, was chosen | ||
286 | because it makes the total length of the CIPSO option 20 octets. If CIPSO | ||
287 | is the only option then the option will be full word aligned and additional | ||
288 | filler octets will not be required. | ||
289 | |||
290 | |||
291 | 3.4.3 Tag Type 2 | ||
292 | |||
293 | This is referred to as the "enumerated" tag type. It is used to describe | ||
294 | large but sparsely populated sets of categories. Tag type 2 is in the MAC | ||
295 | Sensitivity tag type class. The format of this tag type is as follows: | ||
296 | |||
297 | +----------+----------+----------+----------+-------------//-------------+ | ||
298 | | 00000010 | LLLLLLLL | 00000000 | LLLLLLLL | CCCCCCCCCCCCCCCCCCCCCCCCCC | | ||
299 | +----------+----------+----------+----------+-------------//-------------+ | ||
300 | |||
301 | TAG TAG ALIGNMENT SENSITIVITY ENUMERATED | ||
302 | TYPE LENGTH OCTET LEVEL CATEGORIES | ||
303 | |||
304 | Figure 5. Tag Type 2 Format | ||
305 | |||
306 | |||
307 | 3.4.3.1 Tag Type | ||
308 | |||
309 | This field is one octet in length and has a value of 2. | ||
310 | |||
311 | |||
312 | 3.4.3.2 Tag Length | ||
313 | |||
314 | This field is 1 octet in length. It is the total length of the tag type | ||
315 | including the type and length fields. With the current IP header length | ||
316 | restriction of 40 bytes the value within this field is between 4 and 34. | ||
317 | |||
318 | |||
319 | 3.4.3.3 Alignment Octet | ||
320 | |||
321 | This field is 1 octet in length and always has the value of 0. Its purpose | ||
322 | is to align the category field on an even octet boundary. This will | ||
323 | |||
324 | |||
325 | |||
326 | Internet Draft, Expires 15 Jan 93 [PAGE 5] | ||
327 | |||
328 | |||
329 | |||
330 | CIPSO INTERNET DRAFT 16 July, 1992 | ||
331 | |||
332 | |||
333 | |||
334 | speed many implementations including router implementations. | ||
335 | |||
336 | |||
337 | 3.4.3.4 Sensitivity Level | ||
338 | |||
339 | This field is 1 octet in length. Its value is from 0 to 255. The values | ||
340 | are ordered with 0 being the minimum value and 255 representing the | ||
341 | maximum value. | ||
342 | |||
343 | |||
344 | 3.4.3.5 Enumerated Categories | ||
345 | |||
346 | In this tag, categories are represented by their actual value rather than | ||
347 | by their position within a bit field. The length of each category is 2 | ||
348 | octets. Up to 15 categories may be represented by this tag. Valid values | ||
349 | for categories are 0 to 65534. Category 65535 is not a valid category | ||
350 | value. The categories MUST be listed in ascending order within the tag. | ||
351 | |||
352 | |||
353 | 3.4.4 Tag Type 5 | ||
354 | |||
355 | This is referred to as the "range" tag type. It is used to represent | ||
356 | labels where all categories in a range, or set of ranges, are included | ||
357 | in the sensitivity label. Tag type 5 is in the MAC Sensitivity tag type | ||
358 | class. The format of this tag type is as follows: | ||
359 | |||
360 | +----------+----------+----------+----------+------------//-------------+ | ||
361 | | 00000101 | LLLLLLLL | 00000000 | LLLLLLLL | Top/Bottom | Top/Bottom | | ||
362 | +----------+----------+----------+----------+------------//-------------+ | ||
363 | |||
364 | TAG TAG ALIGNMENT SENSITIVITY CATEGORY RANGES | ||
365 | TYPE LENGTH OCTET LEVEL | ||
366 | |||
367 | Figure 6. Tag Type 5 Format | ||
368 | |||
369 | |||
370 | 3.4.4.1 Tag Type | ||
371 | |||
372 | This field is one octet in length and has a value of 5. | ||
373 | |||
374 | |||
375 | 3.4.4.2 Tag Length | ||
376 | |||
377 | This field is 1 octet in length. It is the total length of the tag type | ||
378 | including the type and length fields. With the current IP header length | ||
379 | restriction of 40 bytes the value within this field is between 4 and 34. | ||
380 | |||
381 | |||
382 | 3.4.4.3 Alignment Octet | ||
383 | |||
384 | This field is 1 octet in length and always has the value of 0. Its purpose | ||
385 | is to align the category range field on an even octet boundary. This will | ||
386 | speed many implementations including router implementations. | ||
387 | |||
388 | |||
389 | |||
390 | |||
391 | |||
392 | Internet Draft, Expires 15 Jan 93 [PAGE 6] | ||
393 | |||
394 | |||
395 | |||
396 | CIPSO INTERNET DRAFT 16 July, 1992 | ||
397 | |||
398 | |||
399 | |||
400 | 3.4.4.4 Sensitivity Level | ||
401 | |||
402 | This field is 1 octet in length. Its value is from 0 to 255. The values | ||
403 | are ordered with 0 being the minimum value and 255 representing the maximum | ||
404 | value. | ||
405 | |||
406 | |||
407 | 3.4.4.5 Category Ranges | ||
408 | |||
409 | A category range is a 4 octet field comprised of the 2 octet index of the | ||
410 | highest numbered category followed by the 2 octet index of the lowest | ||
411 | numbered category. These range endpoints are inclusive within the range of | ||
412 | categories. All categories within a range are included in the sensitivity | ||
413 | label. This tag may contain a maximum of 7 category pairs. The bottom | ||
414 | category endpoint for the last pair in the tag MAY be omitted and SHOULD be | ||
415 | assumed to be 0. The ranges MUST be non-overlapping and be listed in | ||
416 | descending order. Valid values for categories are 0 to 65534. Category | ||
417 | 65535 is not a valid category value. | ||
418 | |||
419 | |||
420 | 3.4.5 Minimum Requirements | ||
421 | |||
422 | A CIPSO implementation MUST be capable of generating at least tag type 1 in | ||
423 | the non-optimized form. In addition, a CIPSO implementation MUST be able | ||
424 | to receive any valid tag type 1 even those using the optimized tag type 1 | ||
425 | format. | ||
426 | |||
427 | |||
428 | 4. Configuration Parameters | ||
429 | |||
430 | The configuration parameters defined below are required for all CIPSO hosts, | ||
431 | gateways, and routers that support multiple sensitivity labels. A CIPSO | ||
432 | host is defined to be the origination or destination system for an IP | ||
433 | datagram. A CIPSO gateway provides IP routing services between two or more | ||
434 | IP networks and may be required to perform label translations between | ||
435 | networks. A CIPSO gateway may be an enhanced CIPSO host or it may just | ||
436 | provide gateway services with no end system CIPSO capabilities. A CIPSO | ||
437 | router is a dedicated IP router that routes IP datagrams between two or more | ||
438 | IP networks. | ||
439 | |||
440 | An implementation of CIPSO on a host MUST have the capability to reject a | ||
441 | datagram for reasons that the information contained can not be adequately | ||
442 | protected by the receiving host or if acceptance may result in violation of | ||
443 | the host or network security policy. In addition, a CIPSO gateway or router | ||
444 | MUST be able to reject datagrams going to networks that can not provide | ||
445 | adequate protection or may violate the network's security policy. To | ||
446 | provide this capability the following minimal set of configuration | ||
447 | parameters are required for CIPSO implementations: | ||
448 | |||
449 | HOST_LABEL_MAX - This parameter contains the maximum sensitivity label that | ||
450 | a CIPSO host is authorized to handle. All datagrams that have a label | ||
451 | greater than this maximum MUST be rejected by the CIPSO host. This | ||
452 | parameter does not apply to CIPSO gateways or routers. This parameter need | ||
453 | not be defined explicitly as it can be implicitly derived from the | ||
454 | PORT_LABEL_MAX parameters for the associated interfaces. | ||
455 | |||
456 | |||
457 | |||
458 | Internet Draft, Expires 15 Jan 93 [PAGE 7] | ||
459 | |||
460 | |||
461 | |||
462 | CIPSO INTERNET DRAFT 16 July, 1992 | ||
463 | |||
464 | |||
465 | |||
466 | |||
467 | HOST_LABEL_MIN - This parameter contains the minimum sensitivity label that | ||
468 | a CIPSO host is authorized to handle. All datagrams that have a label less | ||
469 | than this minimum MUST be rejected by the CIPSO host. This parameter does | ||
470 | not apply to CIPSO gateways or routers. This parameter need not be defined | ||
471 | explicitly as it can be implicitly derived from the PORT_LABEL_MIN | ||
472 | parameters for the associated interfaces. | ||
473 | |||
474 | PORT_LABEL_MAX - This parameter contains the maximum sensitivity label for | ||
475 | all datagrams that may exit a particular network interface port. All | ||
476 | outgoing datagrams that have a label greater than this maximum MUST be | ||
477 | rejected by the CIPSO system. The label within this parameter MUST be | ||
478 | less than or equal to the label within the HOST_LABEL_MAX parameter. This | ||
479 | parameter does not apply to CIPSO hosts that support only one network port. | ||
480 | |||
481 | PORT_LABEL_MIN - This parameter contains the minimum sensitivity label for | ||
482 | all datagrams that may exit a particular network interface port. All | ||
483 | outgoing datagrams that have a label less than this minimum MUST be | ||
484 | rejected by the CIPSO system. The label within this parameter MUST be | ||
485 | greater than or equal to the label within the HOST_LABEL_MIN parameter. | ||
486 | This parameter does not apply to CIPSO hosts that support only one network | ||
487 | port. | ||
488 | |||
489 | PORT_DOI - This parameter is used to assign a DOI identifier value to a | ||
490 | particular network interface port. All CIPSO labels within datagrams | ||
491 | going out this port MUST use the specified DOI identifier. All CIPSO | ||
492 | hosts and gateways MUST support either this parameter, the NET_DOI | ||
493 | parameter, or the HOST_DOI parameter. | ||
494 | |||
495 | NET_DOI - This parameter is used to assign a DOI identifier value to a | ||
496 | particular IP network address. All CIPSO labels within datagrams destined | ||
497 | for the particular IP network MUST use the specified DOI identifier. All | ||
498 | CIPSO hosts and gateways MUST support either this parameter, the PORT_DOI | ||
499 | parameter, or the HOST_DOI parameter. | ||
500 | |||
501 | HOST_DOI - This parameter is used to assign a DOI identifier value to a | ||
502 | particular IP host address. All CIPSO labels within datagrams destined for | ||
503 | the particular IP host will use the specified DOI identifier. All CIPSO | ||
504 | hosts and gateways MUST support either this parameter, the PORT_DOI | ||
505 | parameter, or the NET_DOI parameter. | ||
506 | |||
507 | This list represents the minimal set of configuration parameters required | ||
508 | to be compliant. Implementors are encouraged to add to this list to | ||
509 | provide enhanced functionality and control. For example, many security | ||
510 | policies may require both incoming and outgoing datagrams be checked against | ||
511 | the port and host label ranges. | ||
512 | |||
513 | |||
514 | 4.1 Port Range Parameters | ||
515 | |||
516 | The labels represented by the PORT_LABEL_MAX and PORT_LABEL_MIN parameters | ||
517 | MAY be in CIPSO or local format. Some CIPSO systems, such as routers, may | ||
518 | want to have the range parameters expressed in CIPSO format so that incoming | ||
519 | labels do not have to be converted to a local format before being compared | ||
520 | against the range. If multiple DOIs are supported by one of these CIPSO | ||
521 | |||
522 | |||
523 | |||
524 | Internet Draft, Expires 15 Jan 93 [PAGE 8] | ||
525 | |||
526 | |||
527 | |||
528 | CIPSO INTERNET DRAFT 16 July, 1992 | ||
529 | |||
530 | |||
531 | |||
532 | systems then multiple port range parameters would be needed, one set for | ||
533 | each DOI supported on a particular port. | ||
534 | |||
535 | The port range will usually represent the total set of labels that may | ||
536 | exist on the logical network accessed through the corresponding network | ||
537 | interface. It may, however, represent a subset of these labels that are | ||
538 | allowed to enter the CIPSO system. | ||
539 | |||
540 | |||
541 | 4.2 Single Label CIPSO Hosts | ||
542 | |||
543 | CIPSO implementations that support only one label are not required to | ||
544 | support the parameters described above. These limited implementations are | ||
545 | only required to support a NET_LABEL parameter. This parameter contains | ||
546 | the CIPSO label that may be inserted in datagrams that exit the host. In | ||
547 | addition, the host MUST reject any incoming datagram that has a label which | ||
548 | is not equivalent to the NET_LABEL parameter. | ||
549 | |||
550 | |||
551 | 5. Handling Procedures | ||
552 | |||
553 | This section describes the processing requirements for incoming and | ||
554 | outgoing IP datagrams. Just providing the correct CIPSO label format | ||
555 | is not enough. Assumptions will be made by one system on how a | ||
556 | receiving system will handle the CIPSO label. Wrong assumptions may | ||
557 | lead to non-interoperability or even a security incident. The | ||
558 | requirements described below represent the minimal set needed for | ||
559 | interoperability and that provide users some level of confidence. | ||
560 | Many other requirements could be added to increase user confidence, | ||
561 | however at the risk of restricting creativity and limiting vendor | ||
562 | participation. | ||
563 | |||
564 | |||
565 | 5.1 Input Procedures | ||
566 | |||
567 | All datagrams received through a network port MUST have a security label | ||
568 | associated with them, either contained in the datagram or assigned to the | ||
569 | receiving port. Without this label the host, gateway, or router will not | ||
570 | have the information it needs to make security decisions. This security | ||
571 | label will be obtained from the CIPSO if the option is present in the | ||
572 | datagram. See section 4.1.2 for handling procedures for unlabeled | ||
573 | datagrams. This label will be compared against the PORT (if appropriate) | ||
574 | and HOST configuration parameters defined in section 3. | ||
575 | |||
576 | If any field within the CIPSO option, such as the DOI identifier, is not | ||
577 | recognized the IP datagram is discarded and an ICMP "parameter problem" | ||
578 | (type 12) is generated and returned. The ICMP code field is set to "bad | ||
579 | parameter" (code 0) and the pointer is set to the start of the CIPSO field | ||
580 | that is unrecognized. | ||
581 | |||
582 | If the contents of the CIPSO are valid but the security label is | ||
583 | outside of the configured host or port label range, the datagram is | ||
584 | discarded and an ICMP "destination unreachable" (type 3) is generated | ||
585 | and returned. The code field of the ICMP is set to "communication with | ||
586 | destination network administratively prohibited" (code 9) or to | ||
587 | |||
588 | |||
589 | |||
590 | Internet Draft, Expires 15 Jan 93 [PAGE 9] | ||
591 | |||
592 | |||
593 | |||
594 | CIPSO INTERNET DRAFT 16 July, 1992 | ||
595 | |||
596 | |||
597 | |||
598 | "communication with destination host administratively prohibited" | ||
599 | (code 10). The value of the code field used is dependent upon whether | ||
600 | the originator of the ICMP message is acting as a CIPSO host or a CIPSO | ||
601 | gateway. The recipient of the ICMP message MUST be able to handle either | ||
602 | value. The same procedure is performed if a CIPSO can not be added to an | ||
603 | IP packet because it is too large to fit in the IP options area. | ||
604 | |||
605 | If the error is triggered by receipt of an ICMP message, the message | ||
606 | is discarded and no response is permitted (consistent with general ICMP | ||
607 | processing rules). | ||
608 | |||
609 | |||
610 | 5.1.1 Unrecognized tag types | ||
611 | |||
612 | The default condition for any CIPSO implementation is that an | ||
613 | unrecognized tag type MUST be treated as a "parameter problem" and | ||
614 | handled as described in section 4.1. A CIPSO implementation MAY allow | ||
615 | the system administrator to identify tag types that may safely be | ||
616 | ignored. This capability is an allowable enhancement, not a | ||
617 | requirement. | ||
618 | |||
619 | |||
620 | 5.1.2 Unlabeled Packets | ||
621 | |||
622 | A network port may be configured to not require a CIPSO label for all | ||
623 | incoming datagrams. For this configuration a CIPSO label must be | ||
624 | assigned to that network port and associated with all unlabeled IP | ||
625 | datagrams. This capability might be used for single level networks or | ||
626 | networks that have CIPSO and non-CIPSO hosts and the non-CIPSO hosts | ||
627 | all operate at the same label. | ||
628 | |||
629 | If a CIPSO option is required and none is found, the datagram is | ||
630 | discarded and an ICMP "parameter problem" (type 12) is generated and | ||
631 | returned to the originator of the datagram. The code field of the ICMP | ||
632 | is set to "option missing" (code 1) and the ICMP pointer is set to 134 | ||
633 | (the value of the option type for the missing CIPSO option). | ||
634 | |||
635 | |||
636 | 5.2 Output Procedures | ||
637 | |||
638 | A CIPSO option MUST appear only once in a datagram. Only one tag type | ||
639 | from the MAC Sensitivity class MAY be included in a CIPSO option. Given | ||
640 | the current set of defined tag types, this means that CIPSO labels at | ||
641 | first will contain only one tag. | ||
642 | |||
643 | All datagrams leaving a CIPSO system MUST meet the following condition: | ||
644 | |||
645 | PORT_LABEL_MIN <= CIPSO label <= PORT_LABEL_MAX | ||
646 | |||
647 | If this condition is not satisfied the datagram MUST be discarded. | ||
648 | If the CIPSO system only supports one port, the HOST_LABEL_MIN and the | ||
649 | HOST_LABEL_MAX parameters MAY be substituted for the PORT parameters in | ||
650 | the above condition. | ||
651 | |||
652 | The DOI identifier to be used for all outgoing datagrams is configured by | ||
653 | |||
654 | |||
655 | |||
656 | Internet Draft, Expires 15 Jan 93 [PAGE 10] | ||
657 | |||
658 | |||
659 | |||
660 | CIPSO INTERNET DRAFT 16 July, 1992 | ||
661 | |||
662 | |||
663 | |||
664 | the administrator. If port level DOI identifier assignment is used, then | ||
665 | the PORT_DOI configuration parameter MUST contain the DOI identifier to | ||
666 | use. If network level DOI assignment is used, then the NET_DOI parameter | ||
667 | MUST contain the DOI identifier to use. And if host level DOI assignment | ||
668 | is employed, then the HOST_DOI parameter MUST contain the DOI identifier | ||
669 | to use. A CIPSO implementation need only support one level of DOI | ||
670 | assignment. | ||
671 | |||
672 | |||
673 | 5.3 DOI Processing Requirements | ||
674 | |||
675 | A CIPSO implementation MUST support at least one DOI and SHOULD support | ||
676 | multiple DOIs. System and network administrators are cautioned to | ||
677 | ensure that at least one DOI is common within an IP network to allow for | ||
678 | broadcasting of IP datagrams. | ||
679 | |||
680 | CIPSO gateways MUST be capable of translating a CIPSO option from one | ||
681 | DOI to another when forwarding datagrams between networks. For | ||
682 | efficiency purposes this capability is only a desired feature for CIPSO | ||
683 | routers. | ||
684 | |||
685 | |||
686 | 5.4 Label of ICMP Messages | ||
687 | |||
688 | The CIPSO label to be used on all outgoing ICMP messages MUST be equivalent | ||
689 | to the label of the datagram that caused the ICMP message. If the ICMP was | ||
690 | generated due to a problem associated with the original CIPSO label then the | ||
691 | following responses are allowed: | ||
692 | |||
693 | a. Use the CIPSO label of the original IP datagram | ||
694 | b. Drop the original datagram with no return message generated | ||
695 | |||
696 | In most cases these options will have the same effect. If you can not | ||
697 | interpret the label or if it is outside the label range of your host or | ||
698 | interface then an ICMP message with the same label will probably not be | ||
699 | able to exit the system. | ||
700 | |||
701 | |||
702 | 6. Assignment of DOI Identifier Numbers = | ||
703 | |||
704 | Requests for assignment of a DOI identifier number should be addressed to | ||
705 | the Internet Assigned Numbers Authority (IANA). | ||
706 | |||
707 | |||
708 | 7. Acknowledgements | ||
709 | |||
710 | Much of the material in this RFC is based on (and copied from) work | ||
711 | done by Gary Winiger of Sun Microsystems and published as Commercial | ||
712 | IP Security Option at the INTEROP 89, Commercial IPSO Workshop. | ||
713 | |||
714 | |||
715 | 8. Author's Address | ||
716 | |||
717 | To submit mail for distribution to members of the IETF CIPSO Working | ||
718 | Group, send mail to: cipso@wdl1.wdl.loral.com. | ||
719 | |||
720 | |||
721 | |||
722 | Internet Draft, Expires 15 Jan 93 [PAGE 11] | ||
723 | |||
724 | |||
725 | |||
726 | CIPSO INTERNET DRAFT 16 July, 1992 | ||
727 | |||
728 | |||
729 | |||
730 | |||
731 | To be added to or deleted from this distribution, send mail to: | ||
732 | cipso-request@wdl1.wdl.loral.com. | ||
733 | |||
734 | |||
735 | 9. References | ||
736 | |||
737 | RFC 1038, "Draft Revised IP Security Option", M. St. Johns, IETF, January | ||
738 | 1988. | ||
739 | |||
740 | RFC 1108, "U.S. Department of Defense Security Options | ||
741 | for the Internet Protocol", Stephen Kent, IAB, 1 March, 1991. | ||
742 | |||
743 | |||
744 | |||
745 | |||
746 | |||
747 | |||
748 | |||
749 | |||
750 | |||
751 | |||
752 | |||
753 | |||
754 | |||
755 | |||
756 | |||
757 | |||
758 | |||
759 | |||
760 | |||
761 | |||
762 | |||
763 | |||
764 | |||
765 | |||
766 | |||
767 | |||
768 | |||
769 | |||
770 | |||
771 | |||
772 | |||
773 | |||
774 | |||
775 | |||
776 | |||
777 | |||
778 | |||
779 | |||
780 | |||
781 | |||
782 | |||
783 | |||
784 | |||
785 | |||
786 | |||
787 | |||
788 | Internet Draft, Expires 15 Jan 93 [PAGE 12] | ||
789 | |||
790 | |||
791 | |||
diff --git a/Documentation/netlabel/introduction.txt b/Documentation/netlabel/introduction.txt new file mode 100644 index 000000000000..a4ffba1694c8 --- /dev/null +++ b/Documentation/netlabel/introduction.txt | |||
@@ -0,0 +1,46 @@ | |||
1 | NetLabel Introduction | ||
2 | ============================================================================== | ||
3 | Paul Moore, paul.moore@hp.com | ||
4 | |||
5 | August 2, 2006 | ||
6 | |||
7 | * Overview | ||
8 | |||
9 | NetLabel is a mechanism which can be used by kernel security modules to attach | ||
10 | security attributes to outgoing network packets generated from user space | ||
11 | applications and read security attributes from incoming network packets. It | ||
12 | is composed of three main components, the protocol engines, the communication | ||
13 | layer, and the kernel security module API. | ||
14 | |||
15 | * Protocol Engines | ||
16 | |||
17 | The protocol engines are responsible for both applying and retrieving the | ||
18 | network packet's security attributes. If any translation between the network | ||
19 | security attributes and those on the host are required then the protocol | ||
20 | engine will handle those tasks as well. Other kernel subsystems should | ||
21 | refrain from calling the protocol engines directly, instead they should use | ||
22 | the NetLabel kernel security module API described below. | ||
23 | |||
24 | Detailed information about each NetLabel protocol engine can be found in this | ||
25 | directory, consult '00-INDEX' for filenames. | ||
26 | |||
27 | * Communication Layer | ||
28 | |||
29 | The communication layer exists to allow NetLabel configuration and monitoring | ||
30 | from user space. The NetLabel communication layer uses a message based | ||
31 | protocol built on top of the Generic NETLINK transport mechanism. The exact | ||
32 | formatting of these NetLabel messages as well as the Generic NETLINK family | ||
33 | names can be found in the the 'net/netlabel/' directory as comments in the | ||
34 | header files as well as in 'include/net/netlabel.h'. | ||
35 | |||
36 | * Security Module API | ||
37 | |||
38 | The purpose of the NetLabel security module API is to provide a protocol | ||
39 | independent interface to the underlying NetLabel protocol engines. In addition | ||
40 | to protocol independence, the security module API is designed to be completely | ||
41 | LSM independent which should allow multiple LSMs to leverage the same code | ||
42 | base. | ||
43 | |||
44 | Detailed information about the NetLabel security module API can be found in the | ||
45 | 'include/net/netlabel.h' header file as well as the 'lsm_interface.txt' file | ||
46 | found in this directory. | ||
diff --git a/Documentation/netlabel/lsm_interface.txt b/Documentation/netlabel/lsm_interface.txt new file mode 100644 index 000000000000..98dd9f7430f2 --- /dev/null +++ b/Documentation/netlabel/lsm_interface.txt | |||
@@ -0,0 +1,47 @@ | |||
1 | NetLabel Linux Security Module Interface | ||
2 | ============================================================================== | ||
3 | Paul Moore, paul.moore@hp.com | ||
4 | |||
5 | May 17, 2006 | ||
6 | |||
7 | * Overview | ||
8 | |||
9 | NetLabel is a mechanism which can set and retrieve security attributes from | ||
10 | network packets. It is intended to be used by LSM developers who want to make | ||
11 | use of a common code base for several different packet labeling protocols. | ||
12 | The NetLabel security module API is defined in 'include/net/netlabel.h' but a | ||
13 | brief overview is given below. | ||
14 | |||
15 | * NetLabel Security Attributes | ||
16 | |||
17 | Since NetLabel supports multiple different packet labeling protocols and LSMs | ||
18 | it uses the concept of security attributes to refer to the packet's security | ||
19 | labels. The NetLabel security attributes are defined by the | ||
20 | 'netlbl_lsm_secattr' structure in the NetLabel header file. Internally the | ||
21 | NetLabel subsystem converts the security attributes to and from the correct | ||
22 | low-level packet label depending on the NetLabel build time and run time | ||
23 | configuration. It is up to the LSM developer to translate the NetLabel | ||
24 | security attributes into whatever security identifiers are in use for their | ||
25 | particular LSM. | ||
26 | |||
27 | * NetLabel LSM Protocol Operations | ||
28 | |||
29 | These are the functions which allow the LSM developer to manipulate the labels | ||
30 | on outgoing packets as well as read the labels on incoming packets. Functions | ||
31 | exist to operate both on sockets as well as the sk_buffs directly. These high | ||
32 | level functions are translated into low level protocol operations based on how | ||
33 | the administrator has configured the NetLabel subsystem. | ||
34 | |||
35 | * NetLabel Label Mapping Cache Operations | ||
36 | |||
37 | Depending on the exact configuration, translation between the network packet | ||
38 | label and the internal LSM security identifier can be time consuming. The | ||
39 | NetLabel label mapping cache is a caching mechanism which can be used to | ||
40 | sidestep much of this overhead once a mapping has been established. Once the | ||
41 | LSM has received a packet, used NetLabel to decode it's security attributes, | ||
42 | and translated the security attributes into a LSM internal identifier the LSM | ||
43 | can use the NetLabel caching functions to associate the LSM internal | ||
44 | identifier with the network packet's label. This means that in the future | ||
45 | when a incoming packet matches a cached value not only are the internal | ||
46 | NetLabel translation mechanisms bypassed but the LSM translation mechanisms are | ||
47 | bypassed as well which should result in a significant reduction in overhead. | ||
diff --git a/Documentation/networking/ip-sysctl.txt b/Documentation/networking/ip-sysctl.txt index 90ed78110fd4..935e298f674a 100644 --- a/Documentation/networking/ip-sysctl.txt +++ b/Documentation/networking/ip-sysctl.txt | |||
@@ -375,6 +375,41 @@ tcp_slow_start_after_idle - BOOLEAN | |||
375 | be timed out after an idle period. | 375 | be timed out after an idle period. |
376 | Default: 1 | 376 | Default: 1 |
377 | 377 | ||
378 | CIPSOv4 Variables: | ||
379 | |||
380 | cipso_cache_enable - BOOLEAN | ||
381 | If set, enable additions to and lookups from the CIPSO label mapping | ||
382 | cache. If unset, additions are ignored and lookups always result in a | ||
383 | miss. However, regardless of the setting the cache is still | ||
384 | invalidated when required when means you can safely toggle this on and | ||
385 | off and the cache will always be "safe". | ||
386 | Default: 1 | ||
387 | |||
388 | cipso_cache_bucket_size - INTEGER | ||
389 | The CIPSO label cache consists of a fixed size hash table with each | ||
390 | hash bucket containing a number of cache entries. This variable limits | ||
391 | the number of entries in each hash bucket; the larger the value the | ||
392 | more CIPSO label mappings that can be cached. When the number of | ||
393 | entries in a given hash bucket reaches this limit adding new entries | ||
394 | causes the oldest entry in the bucket to be removed to make room. | ||
395 | Default: 10 | ||
396 | |||
397 | cipso_rbm_optfmt - BOOLEAN | ||
398 | Enable the "Optimized Tag 1 Format" as defined in section 3.4.2.6 of | ||
399 | the CIPSO draft specification (see Documentation/netlabel for details). | ||
400 | This means that when set the CIPSO tag will be padded with empty | ||
401 | categories in order to make the packet data 32-bit aligned. | ||
402 | Default: 0 | ||
403 | |||
404 | cipso_rbm_structvalid - BOOLEAN | ||
405 | If set, do a very strict check of the CIPSO option when | ||
406 | ip_options_compile() is called. If unset, relax the checks done during | ||
407 | ip_options_compile(). Either way is "safe" as errors are caught else | ||
408 | where in the CIPSO processing code but setting this to 0 (False) should | ||
409 | result in less work (i.e. it should be faster) but could cause problems | ||
410 | with other implementations that require strict checking. | ||
411 | Default: 0 | ||
412 | |||
378 | IP Variables: | 413 | IP Variables: |
379 | 414 | ||
380 | ip_local_port_range - 2 INTEGERS | 415 | ip_local_port_range - 2 INTEGERS |
@@ -730,6 +765,9 @@ conf/all/forwarding - BOOLEAN | |||
730 | 765 | ||
731 | This referred to as global forwarding. | 766 | This referred to as global forwarding. |
732 | 767 | ||
768 | proxy_ndp - BOOLEAN | ||
769 | Do proxy ndp. | ||
770 | |||
733 | conf/interface/*: | 771 | conf/interface/*: |
734 | Change special settings per interface. | 772 | Change special settings per interface. |
735 | 773 | ||
diff --git a/Documentation/networking/secid.txt b/Documentation/networking/secid.txt new file mode 100644 index 000000000000..95ea06784333 --- /dev/null +++ b/Documentation/networking/secid.txt | |||
@@ -0,0 +1,14 @@ | |||
1 | flowi structure: | ||
2 | |||
3 | The secid member in the flow structure is used in LSMs (e.g. SELinux) to indicate | ||
4 | the label of the flow. This label of the flow is currently used in selecting | ||
5 | matching labeled xfrm(s). | ||
6 | |||
7 | If this is an outbound flow, the label is derived from the socket, if any, or | ||
8 | the incoming packet this flow is being generated as a response to (e.g. tcp | ||
9 | resets, timewait ack, etc.). It is also conceivable that the label could be | ||
10 | derived from other sources such as process context, device, etc., in special | ||
11 | cases, as may be appropriate. | ||
12 | |||
13 | If this is an inbound flow, the label is derived from the IPSec security | ||
14 | associations, if any, used by the packet. | ||
diff --git a/Documentation/sound/alsa/ALSA-Configuration.txt b/Documentation/sound/alsa/ALSA-Configuration.txt index f61af23dd85d..e6b57dd46a4f 100644 --- a/Documentation/sound/alsa/ALSA-Configuration.txt +++ b/Documentation/sound/alsa/ALSA-Configuration.txt | |||
@@ -758,6 +758,7 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed. | |||
758 | position_fix - Fix DMA pointer (0 = auto, 1 = none, 2 = POSBUF, 3 = FIFO size) | 758 | position_fix - Fix DMA pointer (0 = auto, 1 = none, 2 = POSBUF, 3 = FIFO size) |
759 | single_cmd - Use single immediate commands to communicate with | 759 | single_cmd - Use single immediate commands to communicate with |
760 | codecs (for debugging only) | 760 | codecs (for debugging only) |
761 | disable_msi - Disable Message Signaled Interrupt (MSI) | ||
761 | 762 | ||
762 | This module supports one card and autoprobe. | 763 | This module supports one card and autoprobe. |
763 | 764 | ||
@@ -778,11 +779,16 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed. | |||
778 | 6stack-digout 6-jack with a SPDIF out | 779 | 6stack-digout 6-jack with a SPDIF out |
779 | w810 3-jack | 780 | w810 3-jack |
780 | z71v 3-jack (HP shared SPDIF) | 781 | z71v 3-jack (HP shared SPDIF) |
781 | asus 3-jack | 782 | asus 3-jack (ASUS Mobo) |
783 | asus-w1v ASUS W1V | ||
784 | asus-dig ASUS with SPDIF out | ||
785 | asus-dig2 ASUS with SPDIF out (using GPIO2) | ||
782 | uniwill 3-jack | 786 | uniwill 3-jack |
783 | F1734 2-jack | 787 | F1734 2-jack |
784 | lg LG laptop (m1 express dual) | 788 | lg LG laptop (m1 express dual) |
785 | lg-lw LG LW20 laptop | 789 | lg-lw LG LW20/LW25 laptop |
790 | tcl TCL S700 | ||
791 | clevo Clevo laptops (m520G, m665n) | ||
786 | test for testing/debugging purpose, almost all controls can be | 792 | test for testing/debugging purpose, almost all controls can be |
787 | adjusted. Appearing only when compiled with | 793 | adjusted. Appearing only when compiled with |
788 | $CONFIG_SND_DEBUG=y | 794 | $CONFIG_SND_DEBUG=y |
@@ -790,6 +796,7 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed. | |||
790 | 796 | ||
791 | ALC260 | 797 | ALC260 |
792 | hp HP machines | 798 | hp HP machines |
799 | hp-3013 HP machines (3013-variant) | ||
793 | fujitsu Fujitsu S7020 | 800 | fujitsu Fujitsu S7020 |
794 | acer Acer TravelMate | 801 | acer Acer TravelMate |
795 | basic fixed pin assignment (old default model) | 802 | basic fixed pin assignment (old default model) |
@@ -797,24 +804,32 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed. | |||
797 | 804 | ||
798 | ALC262 | 805 | ALC262 |
799 | fujitsu Fujitsu Laptop | 806 | fujitsu Fujitsu Laptop |
807 | hp-bpc HP xw4400/6400/8400/9400 laptops | ||
808 | benq Benq ED8 | ||
800 | basic fixed pin assignment w/o SPDIF | 809 | basic fixed pin assignment w/o SPDIF |
801 | auto auto-config reading BIOS (default) | 810 | auto auto-config reading BIOS (default) |
802 | 811 | ||
803 | ALC882/885 | 812 | ALC882/885 |
804 | 3stack-dig 3-jack with SPDIF I/O | 813 | 3stack-dig 3-jack with SPDIF I/O |
805 | 6stck-dig 6-jack digital with SPDIF I/O | 814 | 6stck-dig 6-jack digital with SPDIF I/O |
815 | arima Arima W820Di1 | ||
806 | auto auto-config reading BIOS (default) | 816 | auto auto-config reading BIOS (default) |
807 | 817 | ||
808 | ALC883/888 | 818 | ALC883/888 |
809 | 3stack-dig 3-jack with SPDIF I/O | 819 | 3stack-dig 3-jack with SPDIF I/O |
810 | 6stack-dig 6-jack digital with SPDIF I/O | 820 | 6stack-dig 6-jack digital with SPDIF I/O |
811 | 6stack-dig-demo 6-stack digital for Intel demo board | 821 | 3stack-6ch 3-jack 6-channel |
822 | 3stack-6ch-dig 3-jack 6-channel with SPDIF I/O | ||
823 | 6stack-dig-demo 6-jack digital for Intel demo board | ||
824 | acer Acer laptops (Travelmate 3012WTMi, Aspire 5600, etc) | ||
812 | auto auto-config reading BIOS (default) | 825 | auto auto-config reading BIOS (default) |
813 | 826 | ||
814 | ALC861/660 | 827 | ALC861/660 |
815 | 3stack 3-jack | 828 | 3stack 3-jack |
816 | 3stack-dig 3-jack with SPDIF I/O | 829 | 3stack-dig 3-jack with SPDIF I/O |
817 | 6stack-dig 6-jack with SPDIF I/O | 830 | 6stack-dig 6-jack with SPDIF I/O |
831 | 3stack-660 3-jack (for ALC660) | ||
832 | uniwill-m31 Uniwill M31 laptop | ||
818 | auto auto-config reading BIOS (default) | 833 | auto auto-config reading BIOS (default) |
819 | 834 | ||
820 | CMI9880 | 835 | CMI9880 |
@@ -843,10 +858,21 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed. | |||
843 | 3stack-dig ditto with SPDIF | 858 | 3stack-dig ditto with SPDIF |
844 | laptop 3-jack with hp-jack automute | 859 | laptop 3-jack with hp-jack automute |
845 | laptop-dig ditto with SPDIF | 860 | laptop-dig ditto with SPDIF |
846 | auto auto-confgi reading BIOS (default) | 861 | auto auto-config reading BIOS (default) |
862 | |||
863 | STAC9200/9205/9220/9221/9254 | ||
864 | ref Reference board | ||
865 | 3stack D945 3stack | ||
866 | 5stack D945 5stack + SPDIF | ||
847 | 867 | ||
848 | STAC7661(?) | 868 | STAC9227/9228/9229/927x |
869 | ref Reference board | ||
870 | 3stack D965 3stack | ||
871 | 5stack D965 5stack + SPDIF | ||
872 | |||
873 | STAC9872 | ||
849 | vaio Setup for VAIO FE550G/SZ110 | 874 | vaio Setup for VAIO FE550G/SZ110 |
875 | vaio-ar Setup for VAIO AR | ||
850 | 876 | ||
851 | If the default configuration doesn't work and one of the above | 877 | If the default configuration doesn't work and one of the above |
852 | matches with your device, report it together with the PCI | 878 | matches with your device, report it together with the PCI |
@@ -1213,6 +1239,14 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed. | |||
1213 | 1239 | ||
1214 | Module supports only 1 card. This module has no enable option. | 1240 | Module supports only 1 card. This module has no enable option. |
1215 | 1241 | ||
1242 | Module snd-mts64 | ||
1243 | ---------------- | ||
1244 | |||
1245 | Module for Ego Systems (ESI) Miditerminal 4140 | ||
1246 | |||
1247 | This module supports multiple devices. | ||
1248 | Requires parport (CONFIG_PARPORT). | ||
1249 | |||
1216 | Module snd-nm256 | 1250 | Module snd-nm256 |
1217 | ---------------- | 1251 | ---------------- |
1218 | 1252 | ||
diff --git a/Documentation/sound/alsa/DocBook/writing-an-alsa-driver.tmpl b/Documentation/sound/alsa/DocBook/writing-an-alsa-driver.tmpl index b8dc51ca776c..4807ef79a94d 100644 --- a/Documentation/sound/alsa/DocBook/writing-an-alsa-driver.tmpl +++ b/Documentation/sound/alsa/DocBook/writing-an-alsa-driver.tmpl | |||
@@ -1054,9 +1054,8 @@ | |||
1054 | 1054 | ||
1055 | <para> | 1055 | <para> |
1056 | For a device which allows hotplugging, you can use | 1056 | For a device which allows hotplugging, you can use |
1057 | <function>snd_card_free_in_thread</function>. This one will | 1057 | <function>snd_card_free_when_closed</function>. This one will |
1058 | postpone the destruction and wait in a kernel-thread until all | 1058 | postpone the destruction until all devices are closed. |
1059 | devices are closed. | ||
1060 | </para> | 1059 | </para> |
1061 | 1060 | ||
1062 | </section> | 1061 | </section> |
diff --git a/arch/powerpc/platforms/powermac/feature.c b/arch/powerpc/platforms/powermac/feature.c index 13fcaf5b1796..e49621be6640 100644 --- a/arch/powerpc/platforms/powermac/feature.c +++ b/arch/powerpc/platforms/powermac/feature.c | |||
@@ -1058,8 +1058,8 @@ core99_reset_cpu(struct device_node *node, long param, long value) | |||
1058 | if (np == NULL) | 1058 | if (np == NULL) |
1059 | return -ENODEV; | 1059 | return -ENODEV; |
1060 | for (np = np->child; np != NULL; np = np->sibling) { | 1060 | for (np = np->child; np != NULL; np = np->sibling) { |
1061 | u32 *num = get_property(np, "reg", NULL); | 1061 | const u32 *num = get_property(np, "reg", NULL); |
1062 | u32 *rst = get_property(np, "soft-reset", NULL); | 1062 | const u32 *rst = get_property(np, "soft-reset", NULL); |
1063 | if (num == NULL || rst == NULL) | 1063 | if (num == NULL || rst == NULL) |
1064 | continue; | 1064 | continue; |
1065 | if (param == *num) { | 1065 | if (param == *num) { |
diff --git a/arch/powerpc/platforms/powermac/smp.c b/arch/powerpc/platforms/powermac/smp.c index 653eeb64d1e2..1949b657b092 100644 --- a/arch/powerpc/platforms/powermac/smp.c +++ b/arch/powerpc/platforms/powermac/smp.c | |||
@@ -702,7 +702,7 @@ static void __init smp_core99_setup(int ncpus) | |||
702 | /* GPIO based HW sync on ppc32 Core99 */ | 702 | /* GPIO based HW sync on ppc32 Core99 */ |
703 | if (pmac_tb_freeze == NULL && !machine_is_compatible("MacRISC4")) { | 703 | if (pmac_tb_freeze == NULL && !machine_is_compatible("MacRISC4")) { |
704 | struct device_node *cpu; | 704 | struct device_node *cpu; |
705 | u32 *tbprop = NULL; | 705 | const u32 *tbprop = NULL; |
706 | 706 | ||
707 | core99_tb_gpio = KL_GPIO_TB_ENABLE; /* default value */ | 707 | core99_tb_gpio = KL_GPIO_TB_ENABLE; /* default value */ |
708 | cpu = of_find_node_by_type(NULL, "cpu"); | 708 | cpu = of_find_node_by_type(NULL, "cpu"); |
diff --git a/block/ll_rw_blk.c b/block/ll_rw_blk.c index 556a3d354eab..9c3a06bcb7ba 100644 --- a/block/ll_rw_blk.c +++ b/block/ll_rw_blk.c | |||
@@ -2801,6 +2801,18 @@ long blk_congestion_wait(int rw, long timeout) | |||
2801 | 2801 | ||
2802 | EXPORT_SYMBOL(blk_congestion_wait); | 2802 | EXPORT_SYMBOL(blk_congestion_wait); |
2803 | 2803 | ||
2804 | /** | ||
2805 | * blk_congestion_end - wake up sleepers on a congestion queue | ||
2806 | * @rw: READ or WRITE | ||
2807 | */ | ||
2808 | void blk_congestion_end(int rw) | ||
2809 | { | ||
2810 | wait_queue_head_t *wqh = &congestion_wqh[rw]; | ||
2811 | |||
2812 | if (waitqueue_active(wqh)) | ||
2813 | wake_up(wqh); | ||
2814 | } | ||
2815 | |||
2804 | /* | 2816 | /* |
2805 | * Has to be called with the request spinlock acquired | 2817 | * Has to be called with the request spinlock acquired |
2806 | */ | 2818 | */ |
diff --git a/crypto/hmac.c b/crypto/hmac.c index f403b6946047..b521bcd2b2c6 100644 --- a/crypto/hmac.c +++ b/crypto/hmac.c | |||
@@ -92,13 +92,17 @@ static int hmac_init(struct hash_desc *pdesc) | |||
92 | struct hmac_ctx *ctx = align_ptr(ipad + bs * 2 + ds, sizeof(void *)); | 92 | struct hmac_ctx *ctx = align_ptr(ipad + bs * 2 + ds, sizeof(void *)); |
93 | struct hash_desc desc; | 93 | struct hash_desc desc; |
94 | struct scatterlist tmp; | 94 | struct scatterlist tmp; |
95 | int err; | ||
95 | 96 | ||
96 | desc.tfm = ctx->child; | 97 | desc.tfm = ctx->child; |
97 | desc.flags = pdesc->flags & CRYPTO_TFM_REQ_MAY_SLEEP; | 98 | desc.flags = pdesc->flags & CRYPTO_TFM_REQ_MAY_SLEEP; |
98 | sg_set_buf(&tmp, ipad, bs); | 99 | sg_set_buf(&tmp, ipad, bs); |
99 | 100 | ||
100 | return unlikely(crypto_hash_init(&desc)) ?: | 101 | err = crypto_hash_init(&desc); |
101 | crypto_hash_update(&desc, &tmp, 1); | 102 | if (unlikely(err)) |
103 | return err; | ||
104 | |||
105 | return crypto_hash_update(&desc, &tmp, bs); | ||
102 | } | 106 | } |
103 | 107 | ||
104 | static int hmac_update(struct hash_desc *pdesc, | 108 | static int hmac_update(struct hash_desc *pdesc, |
@@ -123,13 +127,17 @@ static int hmac_final(struct hash_desc *pdesc, u8 *out) | |||
123 | struct hmac_ctx *ctx = align_ptr(digest + ds, sizeof(void *)); | 127 | struct hmac_ctx *ctx = align_ptr(digest + ds, sizeof(void *)); |
124 | struct hash_desc desc; | 128 | struct hash_desc desc; |
125 | struct scatterlist tmp; | 129 | struct scatterlist tmp; |
130 | int err; | ||
126 | 131 | ||
127 | desc.tfm = ctx->child; | 132 | desc.tfm = ctx->child; |
128 | desc.flags = pdesc->flags & CRYPTO_TFM_REQ_MAY_SLEEP; | 133 | desc.flags = pdesc->flags & CRYPTO_TFM_REQ_MAY_SLEEP; |
129 | sg_set_buf(&tmp, opad, bs + ds); | 134 | sg_set_buf(&tmp, opad, bs + ds); |
130 | 135 | ||
131 | return unlikely(crypto_hash_final(&desc, digest)) ?: | 136 | err = crypto_hash_final(&desc, digest); |
132 | crypto_hash_digest(&desc, &tmp, bs + ds, out); | 137 | if (unlikely(err)) |
138 | return err; | ||
139 | |||
140 | return crypto_hash_digest(&desc, &tmp, bs + ds, out); | ||
133 | } | 141 | } |
134 | 142 | ||
135 | static int hmac_digest(struct hash_desc *pdesc, struct scatterlist *sg, | 143 | static int hmac_digest(struct hash_desc *pdesc, struct scatterlist *sg, |
@@ -145,6 +153,7 @@ static int hmac_digest(struct hash_desc *pdesc, struct scatterlist *sg, | |||
145 | struct hash_desc desc; | 153 | struct hash_desc desc; |
146 | struct scatterlist sg1[2]; | 154 | struct scatterlist sg1[2]; |
147 | struct scatterlist sg2[1]; | 155 | struct scatterlist sg2[1]; |
156 | int err; | ||
148 | 157 | ||
149 | desc.tfm = ctx->child; | 158 | desc.tfm = ctx->child; |
150 | desc.flags = pdesc->flags & CRYPTO_TFM_REQ_MAY_SLEEP; | 159 | desc.flags = pdesc->flags & CRYPTO_TFM_REQ_MAY_SLEEP; |
@@ -154,8 +163,11 @@ static int hmac_digest(struct hash_desc *pdesc, struct scatterlist *sg, | |||
154 | sg1[1].length = 0; | 163 | sg1[1].length = 0; |
155 | sg_set_buf(sg2, opad, bs + ds); | 164 | sg_set_buf(sg2, opad, bs + ds); |
156 | 165 | ||
157 | return unlikely(crypto_hash_digest(&desc, sg1, nbytes + bs, digest)) ?: | 166 | err = crypto_hash_digest(&desc, sg1, nbytes + bs, digest); |
158 | crypto_hash_digest(&desc, sg2, bs + ds, out); | 167 | if (unlikely(err)) |
168 | return err; | ||
169 | |||
170 | return crypto_hash_digest(&desc, sg2, bs + ds, out); | ||
159 | } | 171 | } |
160 | 172 | ||
161 | static int hmac_init_tfm(struct crypto_tfm *tfm) | 173 | static int hmac_init_tfm(struct crypto_tfm *tfm) |
diff --git a/drivers/atm/he.c b/drivers/atm/he.c index ffcb9fd31c38..41e052fecd7f 100644 --- a/drivers/atm/he.c +++ b/drivers/atm/he.c | |||
@@ -1912,7 +1912,7 @@ he_service_rbrq(struct he_dev *he_dev, int group) | |||
1912 | skb->tail = skb->data + skb->len; | 1912 | skb->tail = skb->data + skb->len; |
1913 | #ifdef USE_CHECKSUM_HW | 1913 | #ifdef USE_CHECKSUM_HW |
1914 | if (vcc->vpi == 0 && vcc->vci >= ATM_NOT_RSV_VCI) { | 1914 | if (vcc->vpi == 0 && vcc->vci >= ATM_NOT_RSV_VCI) { |
1915 | skb->ip_summed = CHECKSUM_HW; | 1915 | skb->ip_summed = CHECKSUM_COMPLETE; |
1916 | skb->csum = TCP_CKSUM(skb->data, | 1916 | skb->csum = TCP_CKSUM(skb->data, |
1917 | he_vcc->pdu_len); | 1917 | he_vcc->pdu_len); |
1918 | } | 1918 | } |
diff --git a/drivers/char/briq_panel.c b/drivers/char/briq_panel.c index a0e5eac5f33a..b8c22255f6ad 100644 --- a/drivers/char/briq_panel.c +++ b/drivers/char/briq_panel.c | |||
@@ -87,7 +87,7 @@ static int briq_panel_release(struct inode *ino, struct file *filep) | |||
87 | return 0; | 87 | return 0; |
88 | } | 88 | } |
89 | 89 | ||
90 | static ssize_t briq_panel_read(struct file *file, char *buf, size_t count, | 90 | static ssize_t briq_panel_read(struct file *file, char __user *buf, size_t count, |
91 | loff_t *ppos) | 91 | loff_t *ppos) |
92 | { | 92 | { |
93 | unsigned short c; | 93 | unsigned short c; |
@@ -135,7 +135,7 @@ static void scroll_vfd( void ) | |||
135 | vfd_cursor = 20; | 135 | vfd_cursor = 20; |
136 | } | 136 | } |
137 | 137 | ||
138 | static ssize_t briq_panel_write(struct file *file, const char *buf, size_t len, | 138 | static ssize_t briq_panel_write(struct file *file, const char __user *buf, size_t len, |
139 | loff_t *ppos) | 139 | loff_t *ppos) |
140 | { | 140 | { |
141 | size_t indx = len; | 141 | size_t indx = len; |
@@ -150,19 +150,22 @@ static ssize_t briq_panel_write(struct file *file, const char *buf, size_t len, | |||
150 | return -EBUSY; | 150 | return -EBUSY; |
151 | 151 | ||
152 | for (;;) { | 152 | for (;;) { |
153 | char c; | ||
153 | if (!indx) | 154 | if (!indx) |
154 | break; | 155 | break; |
156 | if (get_user(c, buf)) | ||
157 | return -EFAULT; | ||
155 | if (esc) { | 158 | if (esc) { |
156 | set_led(*buf); | 159 | set_led(c); |
157 | esc = 0; | 160 | esc = 0; |
158 | } else if (*buf == 27) { | 161 | } else if (c == 27) { |
159 | esc = 1; | 162 | esc = 1; |
160 | } else if (*buf == 12) { | 163 | } else if (c == 12) { |
161 | /* do a form feed */ | 164 | /* do a form feed */ |
162 | for (i=0; i<40; i++) | 165 | for (i=0; i<40; i++) |
163 | vfd[i] = ' '; | 166 | vfd[i] = ' '; |
164 | vfd_cursor = 0; | 167 | vfd_cursor = 0; |
165 | } else if (*buf == 10) { | 168 | } else if (c == 10) { |
166 | if (vfd_cursor < 20) | 169 | if (vfd_cursor < 20) |
167 | vfd_cursor = 20; | 170 | vfd_cursor = 20; |
168 | else if (vfd_cursor < 40) | 171 | else if (vfd_cursor < 40) |
@@ -175,7 +178,7 @@ static ssize_t briq_panel_write(struct file *file, const char *buf, size_t len, | |||
175 | /* just a character */ | 178 | /* just a character */ |
176 | if (vfd_cursor > 39) | 179 | if (vfd_cursor > 39) |
177 | scroll_vfd(); | 180 | scroll_vfd(); |
178 | vfd[vfd_cursor++] = *buf; | 181 | vfd[vfd_cursor++] = c; |
179 | } | 182 | } |
180 | indx--; | 183 | indx--; |
181 | buf++; | 184 | buf++; |
@@ -202,7 +205,7 @@ static struct miscdevice briq_panel_miscdev = { | |||
202 | static int __init briq_panel_init(void) | 205 | static int __init briq_panel_init(void) |
203 | { | 206 | { |
204 | struct device_node *root = find_path_device("/"); | 207 | struct device_node *root = find_path_device("/"); |
205 | char *machine; | 208 | const char *machine; |
206 | int i; | 209 | int i; |
207 | 210 | ||
208 | machine = get_property(root, "model", NULL); | 211 | machine = get_property(root, "model", NULL); |
diff --git a/drivers/infiniband/core/mad_priv.h b/drivers/infiniband/core/mad_priv.h index 1da9adbccaec..d06b59083f6e 100644 --- a/drivers/infiniband/core/mad_priv.h +++ b/drivers/infiniband/core/mad_priv.h | |||
@@ -38,6 +38,7 @@ | |||
38 | #define __IB_MAD_PRIV_H__ | 38 | #define __IB_MAD_PRIV_H__ |
39 | 39 | ||
40 | #include <linux/completion.h> | 40 | #include <linux/completion.h> |
41 | #include <linux/err.h> | ||
41 | #include <linux/pci.h> | 42 | #include <linux/pci.h> |
42 | #include <linux/workqueue.h> | 43 | #include <linux/workqueue.h> |
43 | #include <rdma/ib_mad.h> | 44 | #include <rdma/ib_mad.h> |
diff --git a/drivers/infiniband/hw/amso1100/c2_provider.c b/drivers/infiniband/hw/amso1100/c2_provider.c index 8fddc8cccdf3..dd6af551108b 100644 --- a/drivers/infiniband/hw/amso1100/c2_provider.c +++ b/drivers/infiniband/hw/amso1100/c2_provider.c | |||
@@ -49,6 +49,7 @@ | |||
49 | #include <linux/init.h> | 49 | #include <linux/init.h> |
50 | #include <linux/dma-mapping.h> | 50 | #include <linux/dma-mapping.h> |
51 | #include <linux/if_arp.h> | 51 | #include <linux/if_arp.h> |
52 | #include <linux/vmalloc.h> | ||
52 | 53 | ||
53 | #include <asm/io.h> | 54 | #include <asm/io.h> |
54 | #include <asm/irq.h> | 55 | #include <asm/irq.h> |
diff --git a/drivers/infiniband/hw/amso1100/c2_rnic.c b/drivers/infiniband/hw/amso1100/c2_rnic.c index 1c3c9d65ecea..f49a32b7a8f6 100644 --- a/drivers/infiniband/hw/amso1100/c2_rnic.c +++ b/drivers/infiniband/hw/amso1100/c2_rnic.c | |||
@@ -50,6 +50,7 @@ | |||
50 | #include <linux/dma-mapping.h> | 50 | #include <linux/dma-mapping.h> |
51 | #include <linux/mm.h> | 51 | #include <linux/mm.h> |
52 | #include <linux/inet.h> | 52 | #include <linux/inet.h> |
53 | #include <linux/vmalloc.h> | ||
53 | 54 | ||
54 | #include <linux/route.h> | 55 | #include <linux/route.h> |
55 | 56 | ||
diff --git a/drivers/infiniband/hw/ipath/ipath_diag.c b/drivers/infiniband/hw/ipath/ipath_diag.c index 28b6b46c106a..29958b6e0214 100644 --- a/drivers/infiniband/hw/ipath/ipath_diag.c +++ b/drivers/infiniband/hw/ipath/ipath_diag.c | |||
@@ -43,6 +43,7 @@ | |||
43 | 43 | ||
44 | #include <linux/io.h> | 44 | #include <linux/io.h> |
45 | #include <linux/pci.h> | 45 | #include <linux/pci.h> |
46 | #include <linux/vmalloc.h> | ||
46 | #include <asm/uaccess.h> | 47 | #include <asm/uaccess.h> |
47 | 48 | ||
48 | #include "ipath_kernel.h" | 49 | #include "ipath_kernel.h" |
diff --git a/drivers/mtd/Kconfig b/drivers/mtd/Kconfig index 717e90448fc6..a03e862851db 100644 --- a/drivers/mtd/Kconfig +++ b/drivers/mtd/Kconfig | |||
@@ -101,7 +101,7 @@ config MTD_REDBOOT_PARTS_READONLY | |||
101 | 101 | ||
102 | config MTD_CMDLINE_PARTS | 102 | config MTD_CMDLINE_PARTS |
103 | bool "Command line partition table parsing" | 103 | bool "Command line partition table parsing" |
104 | depends on MTD_PARTITIONS = "y" | 104 | depends on MTD_PARTITIONS = "y" && MTD = "y" |
105 | ---help--- | 105 | ---help--- |
106 | Allow generic configuration of the MTD partition tables via the kernel | 106 | Allow generic configuration of the MTD partition tables via the kernel |
107 | command line. Multiple flash resources are supported for hardware where | 107 | command line. Multiple flash resources are supported for hardware where |
@@ -264,7 +264,7 @@ config RFD_FTL | |||
264 | http://www.gensw.com/pages/prod/bios/rfd.htm | 264 | http://www.gensw.com/pages/prod/bios/rfd.htm |
265 | 265 | ||
266 | config SSFDC | 266 | config SSFDC |
267 | bool "NAND SSFDC (SmartMedia) read only translation layer" | 267 | tristate "NAND SSFDC (SmartMedia) read only translation layer" |
268 | depends on MTD | 268 | depends on MTD |
269 | default n | 269 | default n |
270 | help | 270 | help |
diff --git a/drivers/mtd/ssfdc.c b/drivers/mtd/ssfdc.c index ddbf015f4119..79d3bb659bfe 100644 --- a/drivers/mtd/ssfdc.c +++ b/drivers/mtd/ssfdc.c | |||
@@ -10,7 +10,6 @@ | |||
10 | * published by the Free Software Foundation. | 10 | * published by the Free Software Foundation. |
11 | */ | 11 | */ |
12 | 12 | ||
13 | #include <linux/config.h> | ||
14 | #include <linux/kernel.h> | 13 | #include <linux/kernel.h> |
15 | #include <linux/module.h> | 14 | #include <linux/module.h> |
16 | #include <linux/init.h> | 15 | #include <linux/init.h> |
@@ -29,7 +28,7 @@ struct ssfdcr_record { | |||
29 | int cis_block; /* block n. containing CIS/IDI */ | 28 | int cis_block; /* block n. containing CIS/IDI */ |
30 | int erase_size; /* phys_block_size */ | 29 | int erase_size; /* phys_block_size */ |
31 | unsigned short *logic_block_map; /* all zones (max 8192 phys blocks on | 30 | unsigned short *logic_block_map; /* all zones (max 8192 phys blocks on |
32 | the 128MB) */ | 31 | the 128MiB) */ |
33 | int map_len; /* n. phys_blocks on the card */ | 32 | int map_len; /* n. phys_blocks on the card */ |
34 | }; | 33 | }; |
35 | 34 | ||
@@ -43,11 +42,11 @@ struct ssfdcr_record { | |||
43 | #define MAX_LOGIC_BLK_PER_ZONE 1000 | 42 | #define MAX_LOGIC_BLK_PER_ZONE 1000 |
44 | #define MAX_PHYS_BLK_PER_ZONE 1024 | 43 | #define MAX_PHYS_BLK_PER_ZONE 1024 |
45 | 44 | ||
46 | #define KB(x) ( (x) * 1024L ) | 45 | #define KiB(x) ( (x) * 1024L ) |
47 | #define MB(x) ( KB(x) * 1024L ) | 46 | #define MiB(x) ( KiB(x) * 1024L ) |
48 | 47 | ||
49 | /** CHS Table | 48 | /** CHS Table |
50 | 1MB 2MB 4MB 8MB 16MB 32MB 64MB 128MB | 49 | 1MiB 2MiB 4MiB 8MiB 16MiB 32MiB 64MiB 128MiB |
51 | NCylinder 125 125 250 250 500 500 500 500 | 50 | NCylinder 125 125 250 250 500 500 500 500 |
52 | NHead 4 4 4 4 4 8 8 16 | 51 | NHead 4 4 4 4 4 8 8 16 |
53 | NSector 4 8 8 16 16 16 32 32 | 52 | NSector 4 8 8 16 16 16 32 32 |
@@ -64,14 +63,14 @@ typedef struct { | |||
64 | 63 | ||
65 | /* Must be ordered by size */ | 64 | /* Must be ordered by size */ |
66 | static const chs_entry_t chs_table[] = { | 65 | static const chs_entry_t chs_table[] = { |
67 | { MB( 1), 125, 4, 4 }, | 66 | { MiB( 1), 125, 4, 4 }, |
68 | { MB( 2), 125, 4, 8 }, | 67 | { MiB( 2), 125, 4, 8 }, |
69 | { MB( 4), 250, 4, 8 }, | 68 | { MiB( 4), 250, 4, 8 }, |
70 | { MB( 8), 250, 4, 16 }, | 69 | { MiB( 8), 250, 4, 16 }, |
71 | { MB( 16), 500, 4, 16 }, | 70 | { MiB( 16), 500, 4, 16 }, |
72 | { MB( 32), 500, 8, 16 }, | 71 | { MiB( 32), 500, 8, 16 }, |
73 | { MB( 64), 500, 8, 32 }, | 72 | { MiB( 64), 500, 8, 32 }, |
74 | { MB(128), 500, 16, 32 }, | 73 | { MiB(128), 500, 16, 32 }, |
75 | { 0 }, | 74 | { 0 }, |
76 | }; | 75 | }; |
77 | 76 | ||
@@ -109,25 +108,30 @@ static int get_valid_cis_sector(struct mtd_info *mtd) | |||
109 | int ret, k, cis_sector; | 108 | int ret, k, cis_sector; |
110 | size_t retlen; | 109 | size_t retlen; |
111 | loff_t offset; | 110 | loff_t offset; |
112 | uint8_t sect_buf[SECTOR_SIZE]; | 111 | uint8_t *sect_buf; |
112 | |||
113 | cis_sector = -1; | ||
114 | |||
115 | sect_buf = kmalloc(SECTOR_SIZE, GFP_KERNEL); | ||
116 | if (!sect_buf) | ||
117 | goto out; | ||
113 | 118 | ||
114 | /* | 119 | /* |
115 | * Look for CIS/IDI sector on the first GOOD block (give up after 4 bad | 120 | * Look for CIS/IDI sector on the first GOOD block (give up after 4 bad |
116 | * blocks). If the first good block doesn't contain CIS number the flash | 121 | * blocks). If the first good block doesn't contain CIS number the flash |
117 | * is not SSFDC formatted | 122 | * is not SSFDC formatted |
118 | */ | 123 | */ |
119 | cis_sector = -1; | ||
120 | for (k = 0, offset = 0; k < 4; k++, offset += mtd->erasesize) { | 124 | for (k = 0, offset = 0; k < 4; k++, offset += mtd->erasesize) { |
121 | if (!mtd->block_isbad(mtd, offset)) { | 125 | if (!mtd->block_isbad(mtd, offset)) { |
122 | ret = mtd->read(mtd, offset, SECTOR_SIZE, &retlen, | 126 | ret = mtd->read(mtd, offset, SECTOR_SIZE, &retlen, |
123 | sect_buf); | 127 | sect_buf); |
124 | 128 | ||
125 | /* CIS pattern match on the sector buffer */ | 129 | /* CIS pattern match on the sector buffer */ |
126 | if ( ret < 0 || retlen != SECTOR_SIZE ) { | 130 | if (ret < 0 || retlen != SECTOR_SIZE) { |
127 | printk(KERN_WARNING | 131 | printk(KERN_WARNING |
128 | "SSFDC_RO:can't read CIS/IDI sector\n"); | 132 | "SSFDC_RO:can't read CIS/IDI sector\n"); |
129 | } else if ( !memcmp(sect_buf, cis_numbers, | 133 | } else if (!memcmp(sect_buf, cis_numbers, |
130 | sizeof(cis_numbers)) ) { | 134 | sizeof(cis_numbers))) { |
131 | /* Found */ | 135 | /* Found */ |
132 | cis_sector = (int)(offset >> SECTOR_SHIFT); | 136 | cis_sector = (int)(offset >> SECTOR_SHIFT); |
133 | } else { | 137 | } else { |
@@ -140,6 +144,8 @@ static int get_valid_cis_sector(struct mtd_info *mtd) | |||
140 | } | 144 | } |
141 | } | 145 | } |
142 | 146 | ||
147 | kfree(sect_buf); | ||
148 | out: | ||
143 | return cis_sector; | 149 | return cis_sector; |
144 | } | 150 | } |
145 | 151 | ||
@@ -227,7 +233,7 @@ static int get_logical_address(uint8_t *oob_buf) | |||
227 | } | 233 | } |
228 | } | 234 | } |
229 | 235 | ||
230 | if ( !ok ) | 236 | if (!ok) |
231 | block_address = -2; | 237 | block_address = -2; |
232 | 238 | ||
233 | DEBUG(MTD_DEBUG_LEVEL3, "SSFDC_RO: get_logical_address() %d\n", | 239 | DEBUG(MTD_DEBUG_LEVEL3, "SSFDC_RO: get_logical_address() %d\n", |
@@ -245,8 +251,8 @@ static int build_logical_block_map(struct ssfdcr_record *ssfdc) | |||
245 | struct mtd_info *mtd = ssfdc->mbd.mtd; | 251 | struct mtd_info *mtd = ssfdc->mbd.mtd; |
246 | 252 | ||
247 | DEBUG(MTD_DEBUG_LEVEL1, "SSFDC_RO: build_block_map() nblks=%d (%luK)\n", | 253 | DEBUG(MTD_DEBUG_LEVEL1, "SSFDC_RO: build_block_map() nblks=%d (%luK)\n", |
248 | ssfdc->map_len, (unsigned long)ssfdc->map_len * | 254 | ssfdc->map_len, |
249 | ssfdc->erase_size / 1024 ); | 255 | (unsigned long)ssfdc->map_len * ssfdc->erase_size / 1024); |
250 | 256 | ||
251 | /* Scan every physical block, skip CIS block */ | 257 | /* Scan every physical block, skip CIS block */ |
252 | for (phys_block = ssfdc->cis_block + 1; phys_block < ssfdc->map_len; | 258 | for (phys_block = ssfdc->cis_block + 1; phys_block < ssfdc->map_len; |
@@ -323,21 +329,21 @@ static void ssfdcr_add_mtd(struct mtd_blktrans_ops *tr, struct mtd_info *mtd) | |||
323 | /* Set geometry */ | 329 | /* Set geometry */ |
324 | ssfdc->heads = 16; | 330 | ssfdc->heads = 16; |
325 | ssfdc->sectors = 32; | 331 | ssfdc->sectors = 32; |
326 | get_chs( mtd->size, NULL, &ssfdc->heads, &ssfdc->sectors); | 332 | get_chs(mtd->size, NULL, &ssfdc->heads, &ssfdc->sectors); |
327 | ssfdc->cylinders = (unsigned short)((mtd->size >> SECTOR_SHIFT) / | 333 | ssfdc->cylinders = (unsigned short)((mtd->size >> SECTOR_SHIFT) / |
328 | ((long)ssfdc->sectors * (long)ssfdc->heads)); | 334 | ((long)ssfdc->sectors * (long)ssfdc->heads)); |
329 | 335 | ||
330 | DEBUG(MTD_DEBUG_LEVEL1, "SSFDC_RO: using C:%d H:%d S:%d == %ld sects\n", | 336 | DEBUG(MTD_DEBUG_LEVEL1, "SSFDC_RO: using C:%d H:%d S:%d == %ld sects\n", |
331 | ssfdc->cylinders, ssfdc->heads , ssfdc->sectors, | 337 | ssfdc->cylinders, ssfdc->heads , ssfdc->sectors, |
332 | (long)ssfdc->cylinders * (long)ssfdc->heads * | 338 | (long)ssfdc->cylinders * (long)ssfdc->heads * |
333 | (long)ssfdc->sectors ); | 339 | (long)ssfdc->sectors); |
334 | 340 | ||
335 | ssfdc->mbd.size = (long)ssfdc->heads * (long)ssfdc->cylinders * | 341 | ssfdc->mbd.size = (long)ssfdc->heads * (long)ssfdc->cylinders * |
336 | (long)ssfdc->sectors; | 342 | (long)ssfdc->sectors; |
337 | 343 | ||
338 | /* Allocate logical block map */ | 344 | /* Allocate logical block map */ |
339 | ssfdc->logic_block_map = kmalloc( sizeof(ssfdc->logic_block_map[0]) * | 345 | ssfdc->logic_block_map = kmalloc(sizeof(ssfdc->logic_block_map[0]) * |
340 | ssfdc->map_len, GFP_KERNEL); | 346 | ssfdc->map_len, GFP_KERNEL); |
341 | if (!ssfdc->logic_block_map) { | 347 | if (!ssfdc->logic_block_map) { |
342 | printk(KERN_WARNING | 348 | printk(KERN_WARNING |
343 | "SSFDC_RO: out of memory for data structures\n"); | 349 | "SSFDC_RO: out of memory for data structures\n"); |
@@ -408,7 +414,7 @@ static int ssfdcr_readsect(struct mtd_blktrans_dev *dev, | |||
408 | "SSFDC_RO: ssfdcr_readsect() phys_sect_no=%lu\n", | 414 | "SSFDC_RO: ssfdcr_readsect() phys_sect_no=%lu\n", |
409 | sect_no); | 415 | sect_no); |
410 | 416 | ||
411 | if (read_physical_sector( ssfdc->mbd.mtd, buf, sect_no ) < 0) | 417 | if (read_physical_sector(ssfdc->mbd.mtd, buf, sect_no) < 0) |
412 | return -EIO; | 418 | return -EIO; |
413 | } else { | 419 | } else { |
414 | memset(buf, 0xff, SECTOR_SIZE); | 420 | memset(buf, 0xff, SECTOR_SIZE); |
diff --git a/drivers/net/3c59x.c b/drivers/net/3c59x.c index 80e8ca013e44..29dede2eaa85 100644 --- a/drivers/net/3c59x.c +++ b/drivers/net/3c59x.c | |||
@@ -2077,7 +2077,7 @@ boomerang_start_xmit(struct sk_buff *skb, struct net_device *dev) | |||
2077 | 2077 | ||
2078 | vp->tx_ring[entry].next = 0; | 2078 | vp->tx_ring[entry].next = 0; |
2079 | #if DO_ZEROCOPY | 2079 | #if DO_ZEROCOPY |
2080 | if (skb->ip_summed != CHECKSUM_HW) | 2080 | if (skb->ip_summed != CHECKSUM_PARTIAL) |
2081 | vp->tx_ring[entry].status = cpu_to_le32(skb->len | TxIntrUploaded); | 2081 | vp->tx_ring[entry].status = cpu_to_le32(skb->len | TxIntrUploaded); |
2082 | else | 2082 | else |
2083 | vp->tx_ring[entry].status = cpu_to_le32(skb->len | TxIntrUploaded | AddTCPChksum | AddUDPChksum); | 2083 | vp->tx_ring[entry].status = cpu_to_le32(skb->len | TxIntrUploaded | AddTCPChksum | AddUDPChksum); |
diff --git a/drivers/net/8139cp.c b/drivers/net/8139cp.c index 1428bb7715af..a48b211c489d 100644 --- a/drivers/net/8139cp.c +++ b/drivers/net/8139cp.c | |||
@@ -813,7 +813,7 @@ static int cp_start_xmit (struct sk_buff *skb, struct net_device *dev) | |||
813 | 813 | ||
814 | if (mss) | 814 | if (mss) |
815 | flags |= LargeSend | ((mss & MSSMask) << MSSShift); | 815 | flags |= LargeSend | ((mss & MSSMask) << MSSShift); |
816 | else if (skb->ip_summed == CHECKSUM_HW) { | 816 | else if (skb->ip_summed == CHECKSUM_PARTIAL) { |
817 | const struct iphdr *ip = skb->nh.iph; | 817 | const struct iphdr *ip = skb->nh.iph; |
818 | if (ip->protocol == IPPROTO_TCP) | 818 | if (ip->protocol == IPPROTO_TCP) |
819 | flags |= IPCS | TCPCS; | 819 | flags |= IPCS | TCPCS; |
@@ -867,7 +867,7 @@ static int cp_start_xmit (struct sk_buff *skb, struct net_device *dev) | |||
867 | if (mss) | 867 | if (mss) |
868 | ctrl |= LargeSend | | 868 | ctrl |= LargeSend | |
869 | ((mss & MSSMask) << MSSShift); | 869 | ((mss & MSSMask) << MSSShift); |
870 | else if (skb->ip_summed == CHECKSUM_HW) { | 870 | else if (skb->ip_summed == CHECKSUM_PARTIAL) { |
871 | if (ip->protocol == IPPROTO_TCP) | 871 | if (ip->protocol == IPPROTO_TCP) |
872 | ctrl |= IPCS | TCPCS; | 872 | ctrl |= IPCS | TCPCS; |
873 | else if (ip->protocol == IPPROTO_UDP) | 873 | else if (ip->protocol == IPPROTO_UDP) |
@@ -898,7 +898,7 @@ static int cp_start_xmit (struct sk_buff *skb, struct net_device *dev) | |||
898 | txd->addr = cpu_to_le64(first_mapping); | 898 | txd->addr = cpu_to_le64(first_mapping); |
899 | wmb(); | 899 | wmb(); |
900 | 900 | ||
901 | if (skb->ip_summed == CHECKSUM_HW) { | 901 | if (skb->ip_summed == CHECKSUM_PARTIAL) { |
902 | if (ip->protocol == IPPROTO_TCP) | 902 | if (ip->protocol == IPPROTO_TCP) |
903 | txd->opts1 = cpu_to_le32(first_eor | first_len | | 903 | txd->opts1 = cpu_to_le32(first_eor | first_len | |
904 | FirstFrag | DescOwn | | 904 | FirstFrag | DescOwn | |
diff --git a/drivers/net/acenic.c b/drivers/net/acenic.c index 1c01e9b3d07c..826548644d7b 100644 --- a/drivers/net/acenic.c +++ b/drivers/net/acenic.c | |||
@@ -2040,7 +2040,7 @@ static void ace_rx_int(struct net_device *dev, u32 rxretprd, u32 rxretcsm) | |||
2040 | */ | 2040 | */ |
2041 | if (bd_flags & BD_FLG_TCP_UDP_SUM) { | 2041 | if (bd_flags & BD_FLG_TCP_UDP_SUM) { |
2042 | skb->csum = htons(csum); | 2042 | skb->csum = htons(csum); |
2043 | skb->ip_summed = CHECKSUM_HW; | 2043 | skb->ip_summed = CHECKSUM_COMPLETE; |
2044 | } else { | 2044 | } else { |
2045 | skb->ip_summed = CHECKSUM_NONE; | 2045 | skb->ip_summed = CHECKSUM_NONE; |
2046 | } | 2046 | } |
@@ -2511,7 +2511,7 @@ restart: | |||
2511 | 2511 | ||
2512 | mapping = ace_map_tx_skb(ap, skb, skb, idx); | 2512 | mapping = ace_map_tx_skb(ap, skb, skb, idx); |
2513 | flagsize = (skb->len << 16) | (BD_FLG_END); | 2513 | flagsize = (skb->len << 16) | (BD_FLG_END); |
2514 | if (skb->ip_summed == CHECKSUM_HW) | 2514 | if (skb->ip_summed == CHECKSUM_PARTIAL) |
2515 | flagsize |= BD_FLG_TCP_UDP_SUM; | 2515 | flagsize |= BD_FLG_TCP_UDP_SUM; |
2516 | #if ACENIC_DO_VLAN | 2516 | #if ACENIC_DO_VLAN |
2517 | if (vlan_tx_tag_present(skb)) { | 2517 | if (vlan_tx_tag_present(skb)) { |
@@ -2534,7 +2534,7 @@ restart: | |||
2534 | 2534 | ||
2535 | mapping = ace_map_tx_skb(ap, skb, NULL, idx); | 2535 | mapping = ace_map_tx_skb(ap, skb, NULL, idx); |
2536 | flagsize = (skb_headlen(skb) << 16); | 2536 | flagsize = (skb_headlen(skb) << 16); |
2537 | if (skb->ip_summed == CHECKSUM_HW) | 2537 | if (skb->ip_summed == CHECKSUM_PARTIAL) |
2538 | flagsize |= BD_FLG_TCP_UDP_SUM; | 2538 | flagsize |= BD_FLG_TCP_UDP_SUM; |
2539 | #if ACENIC_DO_VLAN | 2539 | #if ACENIC_DO_VLAN |
2540 | if (vlan_tx_tag_present(skb)) { | 2540 | if (vlan_tx_tag_present(skb)) { |
@@ -2560,7 +2560,7 @@ restart: | |||
2560 | PCI_DMA_TODEVICE); | 2560 | PCI_DMA_TODEVICE); |
2561 | 2561 | ||
2562 | flagsize = (frag->size << 16); | 2562 | flagsize = (frag->size << 16); |
2563 | if (skb->ip_summed == CHECKSUM_HW) | 2563 | if (skb->ip_summed == CHECKSUM_PARTIAL) |
2564 | flagsize |= BD_FLG_TCP_UDP_SUM; | 2564 | flagsize |= BD_FLG_TCP_UDP_SUM; |
2565 | idx = (idx + 1) % ACE_TX_RING_ENTRIES(ap); | 2565 | idx = (idx + 1) % ACE_TX_RING_ENTRIES(ap); |
2566 | 2566 | ||
diff --git a/drivers/net/arcnet/com20020-pci.c b/drivers/net/arcnet/com20020-pci.c index 979a33df0a8c..96d8a694d433 100644 --- a/drivers/net/arcnet/com20020-pci.c +++ b/drivers/net/arcnet/com20020-pci.c | |||
@@ -161,6 +161,7 @@ static struct pci_device_id com20020pci_id_table[] = { | |||
161 | { 0x1571, 0xa204, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ARC_CAN_10MBIT }, | 161 | { 0x1571, 0xa204, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ARC_CAN_10MBIT }, |
162 | { 0x1571, 0xa205, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ARC_CAN_10MBIT }, | 162 | { 0x1571, 0xa205, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ARC_CAN_10MBIT }, |
163 | { 0x1571, 0xa206, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ARC_CAN_10MBIT }, | 163 | { 0x1571, 0xa206, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ARC_CAN_10MBIT }, |
164 | { 0x10B5, 0x9030, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ARC_CAN_10MBIT }, | ||
164 | { 0x10B5, 0x9050, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ARC_CAN_10MBIT }, | 165 | { 0x10B5, 0x9050, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ARC_CAN_10MBIT }, |
165 | {0,} | 166 | {0,} |
166 | }; | 167 | }; |
diff --git a/drivers/net/bnx2.c b/drivers/net/bnx2.c index 652eb05a6c2d..7857b4630124 100644 --- a/drivers/net/bnx2.c +++ b/drivers/net/bnx2.c | |||
@@ -4423,7 +4423,7 @@ bnx2_start_xmit(struct sk_buff *skb, struct net_device *dev) | |||
4423 | ring_prod = TX_RING_IDX(prod); | 4423 | ring_prod = TX_RING_IDX(prod); |
4424 | 4424 | ||
4425 | vlan_tag_flags = 0; | 4425 | vlan_tag_flags = 0; |
4426 | if (skb->ip_summed == CHECKSUM_HW) { | 4426 | if (skb->ip_summed == CHECKSUM_PARTIAL) { |
4427 | vlan_tag_flags |= TX_BD_FLAGS_TCP_UDP_CKSUM; | 4427 | vlan_tag_flags |= TX_BD_FLAGS_TCP_UDP_CKSUM; |
4428 | } | 4428 | } |
4429 | 4429 | ||
diff --git a/drivers/net/cassini.c b/drivers/net/cassini.c index a31544ccb3c4..558fdb8ad2dc 100644 --- a/drivers/net/cassini.c +++ b/drivers/net/cassini.c | |||
@@ -2167,7 +2167,7 @@ end_copy_pkt: | |||
2167 | cas_page_unmap(addr); | 2167 | cas_page_unmap(addr); |
2168 | } | 2168 | } |
2169 | skb->csum = ntohs(i ^ 0xffff); | 2169 | skb->csum = ntohs(i ^ 0xffff); |
2170 | skb->ip_summed = CHECKSUM_HW; | 2170 | skb->ip_summed = CHECKSUM_COMPLETE; |
2171 | skb->protocol = eth_type_trans(skb, cp->dev); | 2171 | skb->protocol = eth_type_trans(skb, cp->dev); |
2172 | return len; | 2172 | return len; |
2173 | } | 2173 | } |
@@ -2821,7 +2821,7 @@ static inline int cas_xmit_tx_ringN(struct cas *cp, int ring, | |||
2821 | } | 2821 | } |
2822 | 2822 | ||
2823 | ctrl = 0; | 2823 | ctrl = 0; |
2824 | if (skb->ip_summed == CHECKSUM_HW) { | 2824 | if (skb->ip_summed == CHECKSUM_PARTIAL) { |
2825 | u64 csum_start_off, csum_stuff_off; | 2825 | u64 csum_start_off, csum_stuff_off; |
2826 | 2826 | ||
2827 | csum_start_off = (u64) (skb->h.raw - skb->data); | 2827 | csum_start_off = (u64) (skb->h.raw - skb->data); |
diff --git a/drivers/net/chelsio/sge.c b/drivers/net/chelsio/sge.c index 61b3754f50ff..ddd0bdb498f4 100644 --- a/drivers/net/chelsio/sge.c +++ b/drivers/net/chelsio/sge.c | |||
@@ -1470,9 +1470,9 @@ int t1_start_xmit(struct sk_buff *skb, struct net_device *dev) | |||
1470 | } | 1470 | } |
1471 | 1471 | ||
1472 | if (!(adapter->flags & UDP_CSUM_CAPABLE) && | 1472 | if (!(adapter->flags & UDP_CSUM_CAPABLE) && |
1473 | skb->ip_summed == CHECKSUM_HW && | 1473 | skb->ip_summed == CHECKSUM_PARTIAL && |
1474 | skb->nh.iph->protocol == IPPROTO_UDP) | 1474 | skb->nh.iph->protocol == IPPROTO_UDP) |
1475 | if (unlikely(skb_checksum_help(skb, 0))) { | 1475 | if (unlikely(skb_checksum_help(skb))) { |
1476 | dev_kfree_skb_any(skb); | 1476 | dev_kfree_skb_any(skb); |
1477 | return NETDEV_TX_OK; | 1477 | return NETDEV_TX_OK; |
1478 | } | 1478 | } |
@@ -1495,11 +1495,11 @@ int t1_start_xmit(struct sk_buff *skb, struct net_device *dev) | |||
1495 | cpl = (struct cpl_tx_pkt *)__skb_push(skb, sizeof(*cpl)); | 1495 | cpl = (struct cpl_tx_pkt *)__skb_push(skb, sizeof(*cpl)); |
1496 | cpl->opcode = CPL_TX_PKT; | 1496 | cpl->opcode = CPL_TX_PKT; |
1497 | cpl->ip_csum_dis = 1; /* SW calculates IP csum */ | 1497 | cpl->ip_csum_dis = 1; /* SW calculates IP csum */ |
1498 | cpl->l4_csum_dis = skb->ip_summed == CHECKSUM_HW ? 0 : 1; | 1498 | cpl->l4_csum_dis = skb->ip_summed == CHECKSUM_PARTIAL ? 0 : 1; |
1499 | /* the length field isn't used so don't bother setting it */ | 1499 | /* the length field isn't used so don't bother setting it */ |
1500 | 1500 | ||
1501 | st->tx_cso += (skb->ip_summed == CHECKSUM_HW); | 1501 | st->tx_cso += (skb->ip_summed == CHECKSUM_PARTIAL); |
1502 | sge->stats.tx_do_cksum += (skb->ip_summed == CHECKSUM_HW); | 1502 | sge->stats.tx_do_cksum += (skb->ip_summed == CHECKSUM_PARTIAL); |
1503 | sge->stats.tx_reg_pkts++; | 1503 | sge->stats.tx_reg_pkts++; |
1504 | } | 1504 | } |
1505 | cpl->iff = dev->if_port; | 1505 | cpl->iff = dev->if_port; |
diff --git a/drivers/net/dl2k.c b/drivers/net/dl2k.c index 402961e68c89..b74e67654764 100644 --- a/drivers/net/dl2k.c +++ b/drivers/net/dl2k.c | |||
@@ -611,7 +611,7 @@ start_xmit (struct sk_buff *skb, struct net_device *dev) | |||
611 | txdesc = &np->tx_ring[entry]; | 611 | txdesc = &np->tx_ring[entry]; |
612 | 612 | ||
613 | #if 0 | 613 | #if 0 |
614 | if (skb->ip_summed == CHECKSUM_HW) { | 614 | if (skb->ip_summed == CHECKSUM_PARTIAL) { |
615 | txdesc->status |= | 615 | txdesc->status |= |
616 | cpu_to_le64 (TCPChecksumEnable | UDPChecksumEnable | | 616 | cpu_to_le64 (TCPChecksumEnable | UDPChecksumEnable | |
617 | IPChecksumEnable); | 617 | IPChecksumEnable); |
diff --git a/drivers/net/e1000/e1000_main.c b/drivers/net/e1000/e1000_main.c index 98ef9f85482f..2ab9f96f5dab 100644 --- a/drivers/net/e1000/e1000_main.c +++ b/drivers/net/e1000/e1000_main.c | |||
@@ -2600,7 +2600,7 @@ e1000_tx_csum(struct e1000_adapter *adapter, struct e1000_tx_ring *tx_ring, | |||
2600 | unsigned int i; | 2600 | unsigned int i; |
2601 | uint8_t css; | 2601 | uint8_t css; |
2602 | 2602 | ||
2603 | if (likely(skb->ip_summed == CHECKSUM_HW)) { | 2603 | if (likely(skb->ip_summed == CHECKSUM_PARTIAL)) { |
2604 | css = skb->h.raw - skb->data; | 2604 | css = skb->h.raw - skb->data; |
2605 | 2605 | ||
2606 | i = tx_ring->next_to_use; | 2606 | i = tx_ring->next_to_use; |
@@ -2927,11 +2927,11 @@ e1000_xmit_frame(struct sk_buff *skb, struct net_device *netdev) | |||
2927 | } | 2927 | } |
2928 | 2928 | ||
2929 | /* reserve a descriptor for the offload context */ | 2929 | /* reserve a descriptor for the offload context */ |
2930 | if ((mss) || (skb->ip_summed == CHECKSUM_HW)) | 2930 | if ((mss) || (skb->ip_summed == CHECKSUM_PARTIAL)) |
2931 | count++; | 2931 | count++; |
2932 | count++; | 2932 | count++; |
2933 | #else | 2933 | #else |
2934 | if (skb->ip_summed == CHECKSUM_HW) | 2934 | if (skb->ip_summed == CHECKSUM_PARTIAL) |
2935 | count++; | 2935 | count++; |
2936 | #endif | 2936 | #endif |
2937 | 2937 | ||
@@ -3608,7 +3608,7 @@ e1000_rx_checksum(struct e1000_adapter *adapter, | |||
3608 | */ | 3608 | */ |
3609 | csum = ntohl(csum ^ 0xFFFF); | 3609 | csum = ntohl(csum ^ 0xFFFF); |
3610 | skb->csum = csum; | 3610 | skb->csum = csum; |
3611 | skb->ip_summed = CHECKSUM_HW; | 3611 | skb->ip_summed = CHECKSUM_COMPLETE; |
3612 | } | 3612 | } |
3613 | adapter->hw_csum_good++; | 3613 | adapter->hw_csum_good++; |
3614 | } | 3614 | } |
diff --git a/drivers/net/forcedeth.c b/drivers/net/forcedeth.c index 11b8f1b43dd5..32cacf115f75 100644 --- a/drivers/net/forcedeth.c +++ b/drivers/net/forcedeth.c | |||
@@ -1503,7 +1503,8 @@ static int nv_start_xmit(struct sk_buff *skb, struct net_device *dev) | |||
1503 | tx_flags_extra = NV_TX2_TSO | (skb_shinfo(skb)->gso_size << NV_TX2_TSO_SHIFT); | 1503 | tx_flags_extra = NV_TX2_TSO | (skb_shinfo(skb)->gso_size << NV_TX2_TSO_SHIFT); |
1504 | else | 1504 | else |
1505 | #endif | 1505 | #endif |
1506 | tx_flags_extra = (skb->ip_summed == CHECKSUM_HW ? (NV_TX2_CHECKSUM_L3|NV_TX2_CHECKSUM_L4) : 0); | 1506 | tx_flags_extra = skb->ip_summed == CHECKSUM_PARTIAL ? |
1507 | NV_TX2_CHECKSUM_L3 | NV_TX2_CHECKSUM_L4 : 0; | ||
1507 | 1508 | ||
1508 | /* vlan tag */ | 1509 | /* vlan tag */ |
1509 | if (np->vlangrp && vlan_tx_tag_present(skb)) { | 1510 | if (np->vlangrp && vlan_tx_tag_present(skb)) { |
diff --git a/drivers/net/gianfar.c b/drivers/net/gianfar.c index ebbbd6ca6204..ba960913c034 100644 --- a/drivers/net/gianfar.c +++ b/drivers/net/gianfar.c | |||
@@ -947,7 +947,7 @@ static int gfar_start_xmit(struct sk_buff *skb, struct net_device *dev) | |||
947 | 947 | ||
948 | /* Set up checksumming */ | 948 | /* Set up checksumming */ |
949 | if (likely((dev->features & NETIF_F_IP_CSUM) | 949 | if (likely((dev->features & NETIF_F_IP_CSUM) |
950 | && (CHECKSUM_HW == skb->ip_summed))) { | 950 | && (CHECKSUM_PARTIAL == skb->ip_summed))) { |
951 | fcb = gfar_add_fcb(skb, txbdp); | 951 | fcb = gfar_add_fcb(skb, txbdp); |
952 | status |= TXBD_TOE; | 952 | status |= TXBD_TOE; |
953 | gfar_tx_checksum(skb, fcb); | 953 | gfar_tx_checksum(skb, fcb); |
diff --git a/drivers/net/hamachi.c b/drivers/net/hamachi.c index 409c6aab0411..763373ae9666 100644 --- a/drivers/net/hamachi.c +++ b/drivers/net/hamachi.c | |||
@@ -1648,7 +1648,7 @@ static int hamachi_rx(struct net_device *dev) | |||
1648 | * could do the pseudo myself and return | 1648 | * could do the pseudo myself and return |
1649 | * CHECKSUM_UNNECESSARY | 1649 | * CHECKSUM_UNNECESSARY |
1650 | */ | 1650 | */ |
1651 | skb->ip_summed = CHECKSUM_HW; | 1651 | skb->ip_summed = CHECKSUM_COMPLETE; |
1652 | } | 1652 | } |
1653 | } | 1653 | } |
1654 | } | 1654 | } |
diff --git a/drivers/net/ibm_emac/ibm_emac_core.c b/drivers/net/ibm_emac/ibm_emac_core.c index 82468e2dc799..57e214d85e9a 100644 --- a/drivers/net/ibm_emac/ibm_emac_core.c +++ b/drivers/net/ibm_emac/ibm_emac_core.c | |||
@@ -1036,7 +1036,7 @@ static inline u16 emac_tx_csum(struct ocp_enet_private *dev, | |||
1036 | struct sk_buff *skb) | 1036 | struct sk_buff *skb) |
1037 | { | 1037 | { |
1038 | #if defined(CONFIG_IBM_EMAC_TAH) | 1038 | #if defined(CONFIG_IBM_EMAC_TAH) |
1039 | if (skb->ip_summed == CHECKSUM_HW) { | 1039 | if (skb->ip_summed == CHECKSUM_PARTIAL) { |
1040 | ++dev->stats.tx_packets_csum; | 1040 | ++dev->stats.tx_packets_csum; |
1041 | return EMAC_TX_CTRL_TAH_CSUM; | 1041 | return EMAC_TX_CTRL_TAH_CSUM; |
1042 | } | 1042 | } |
diff --git a/drivers/net/ioc3-eth.c b/drivers/net/ioc3-eth.c index 68d8af7df08e..65f897ddb920 100644 --- a/drivers/net/ioc3-eth.c +++ b/drivers/net/ioc3-eth.c | |||
@@ -1387,7 +1387,7 @@ static int ioc3_start_xmit(struct sk_buff *skb, struct net_device *dev) | |||
1387 | * MAC header which should not be summed and the TCP/UDP pseudo headers | 1387 | * MAC header which should not be summed and the TCP/UDP pseudo headers |
1388 | * manually. | 1388 | * manually. |
1389 | */ | 1389 | */ |
1390 | if (skb->ip_summed == CHECKSUM_HW) { | 1390 | if (skb->ip_summed == CHECKSUM_PARTIAL) { |
1391 | int proto = ntohs(skb->nh.iph->protocol); | 1391 | int proto = ntohs(skb->nh.iph->protocol); |
1392 | unsigned int csoff; | 1392 | unsigned int csoff; |
1393 | struct iphdr *ih = skb->nh.iph; | 1393 | struct iphdr *ih = skb->nh.iph; |
diff --git a/drivers/net/irda/ali-ircc.c b/drivers/net/irda/ali-ircc.c index e3c8cd5eca67..68d4c418cb98 100644 --- a/drivers/net/irda/ali-ircc.c +++ b/drivers/net/irda/ali-ircc.c | |||
@@ -249,7 +249,7 @@ static void __exit ali_ircc_cleanup(void) | |||
249 | 249 | ||
250 | IRDA_DEBUG(2, "%s(), ---------------- Start ----------------\n", __FUNCTION__); | 250 | IRDA_DEBUG(2, "%s(), ---------------- Start ----------------\n", __FUNCTION__); |
251 | 251 | ||
252 | for (i=0; i < 4; i++) { | 252 | for (i=0; i < ARRAY_SIZE(dev_self); i++) { |
253 | if (dev_self[i]) | 253 | if (dev_self[i]) |
254 | ali_ircc_close(dev_self[i]); | 254 | ali_ircc_close(dev_self[i]); |
255 | } | 255 | } |
@@ -273,6 +273,12 @@ static int ali_ircc_open(int i, chipio_t *info) | |||
273 | int err; | 273 | int err; |
274 | 274 | ||
275 | IRDA_DEBUG(2, "%s(), ---------------- Start ----------------\n", __FUNCTION__); | 275 | IRDA_DEBUG(2, "%s(), ---------------- Start ----------------\n", __FUNCTION__); |
276 | |||
277 | if (i >= ARRAY_SIZE(dev_self)) { | ||
278 | IRDA_ERROR("%s(), maximum number of supported chips reached!\n", | ||
279 | __FUNCTION__); | ||
280 | return -ENOMEM; | ||
281 | } | ||
276 | 282 | ||
277 | /* Set FIR FIFO and DMA Threshold */ | 283 | /* Set FIR FIFO and DMA Threshold */ |
278 | if ((ali_ircc_setup(info)) == -1) | 284 | if ((ali_ircc_setup(info)) == -1) |
diff --git a/drivers/net/irda/irport.c b/drivers/net/irda/irport.c index 44efd49bf4a9..ba4f3eb988b3 100644 --- a/drivers/net/irda/irport.c +++ b/drivers/net/irda/irport.c | |||
@@ -1090,7 +1090,7 @@ static int __init irport_init(void) | |||
1090 | { | 1090 | { |
1091 | int i; | 1091 | int i; |
1092 | 1092 | ||
1093 | for (i=0; (io[i] < 2000) && (i < 4); i++) { | 1093 | for (i=0; (io[i] < 2000) && (i < ARRAY_SIZE(dev_self)); i++) { |
1094 | if (irport_open(i, io[i], irq[i]) != NULL) | 1094 | if (irport_open(i, io[i], irq[i]) != NULL) |
1095 | return 0; | 1095 | return 0; |
1096 | } | 1096 | } |
@@ -1112,7 +1112,7 @@ static void __exit irport_cleanup(void) | |||
1112 | 1112 | ||
1113 | IRDA_DEBUG( 4, "%s()\n", __FUNCTION__); | 1113 | IRDA_DEBUG( 4, "%s()\n", __FUNCTION__); |
1114 | 1114 | ||
1115 | for (i=0; i < 4; i++) { | 1115 | for (i=0; i < ARRAY_SIZE(dev_self); i++) { |
1116 | if (dev_self[i]) | 1116 | if (dev_self[i]) |
1117 | irport_close(dev_self[i]); | 1117 | irport_close(dev_self[i]); |
1118 | } | 1118 | } |
diff --git a/drivers/net/irda/via-ircc.c b/drivers/net/irda/via-ircc.c index 8bafb455c102..79b85f327500 100644 --- a/drivers/net/irda/via-ircc.c +++ b/drivers/net/irda/via-ircc.c | |||
@@ -279,7 +279,7 @@ static void via_ircc_clean(void) | |||
279 | 279 | ||
280 | IRDA_DEBUG(3, "%s()\n", __FUNCTION__); | 280 | IRDA_DEBUG(3, "%s()\n", __FUNCTION__); |
281 | 281 | ||
282 | for (i=0; i < 4; i++) { | 282 | for (i=0; i < ARRAY_SIZE(dev_self); i++) { |
283 | if (dev_self[i]) | 283 | if (dev_self[i]) |
284 | via_ircc_close(dev_self[i]); | 284 | via_ircc_close(dev_self[i]); |
285 | } | 285 | } |
@@ -327,6 +327,9 @@ static __devinit int via_ircc_open(int i, chipio_t * info, unsigned int id) | |||
327 | 327 | ||
328 | IRDA_DEBUG(3, "%s()\n", __FUNCTION__); | 328 | IRDA_DEBUG(3, "%s()\n", __FUNCTION__); |
329 | 329 | ||
330 | if (i >= ARRAY_SIZE(dev_self)) | ||
331 | return -ENOMEM; | ||
332 | |||
330 | /* Allocate new instance of the driver */ | 333 | /* Allocate new instance of the driver */ |
331 | dev = alloc_irdadev(sizeof(struct via_ircc_cb)); | 334 | dev = alloc_irdadev(sizeof(struct via_ircc_cb)); |
332 | if (dev == NULL) | 335 | if (dev == NULL) |
diff --git a/drivers/net/irda/w83977af_ir.c b/drivers/net/irda/w83977af_ir.c index 0ea65c4c6f85..8421597072a7 100644 --- a/drivers/net/irda/w83977af_ir.c +++ b/drivers/net/irda/w83977af_ir.c | |||
@@ -117,7 +117,7 @@ static int __init w83977af_init(void) | |||
117 | 117 | ||
118 | IRDA_DEBUG(0, "%s()\n", __FUNCTION__ ); | 118 | IRDA_DEBUG(0, "%s()\n", __FUNCTION__ ); |
119 | 119 | ||
120 | for (i=0; (io[i] < 2000) && (i < 4); i++) { | 120 | for (i=0; (io[i] < 2000) && (i < ARRAY_SIZE(dev_self)); i++) { |
121 | if (w83977af_open(i, io[i], irq[i], dma[i]) == 0) | 121 | if (w83977af_open(i, io[i], irq[i], dma[i]) == 0) |
122 | return 0; | 122 | return 0; |
123 | } | 123 | } |
@@ -136,7 +136,7 @@ static void __exit w83977af_cleanup(void) | |||
136 | 136 | ||
137 | IRDA_DEBUG(4, "%s()\n", __FUNCTION__ ); | 137 | IRDA_DEBUG(4, "%s()\n", __FUNCTION__ ); |
138 | 138 | ||
139 | for (i=0; i < 4; i++) { | 139 | for (i=0; i < ARRAY_SIZE(dev_self); i++) { |
140 | if (dev_self[i]) | 140 | if (dev_self[i]) |
141 | w83977af_close(dev_self[i]); | 141 | w83977af_close(dev_self[i]); |
142 | } | 142 | } |
diff --git a/drivers/net/ixgb/ixgb_main.c b/drivers/net/ixgb/ixgb_main.c index 7bbd447289b5..9405b44f3214 100644 --- a/drivers/net/ixgb/ixgb_main.c +++ b/drivers/net/ixgb/ixgb_main.c | |||
@@ -1232,7 +1232,7 @@ ixgb_tx_csum(struct ixgb_adapter *adapter, struct sk_buff *skb) | |||
1232 | unsigned int i; | 1232 | unsigned int i; |
1233 | uint8_t css, cso; | 1233 | uint8_t css, cso; |
1234 | 1234 | ||
1235 | if(likely(skb->ip_summed == CHECKSUM_HW)) { | 1235 | if(likely(skb->ip_summed == CHECKSUM_PARTIAL)) { |
1236 | css = skb->h.raw - skb->data; | 1236 | css = skb->h.raw - skb->data; |
1237 | cso = (skb->h.raw + skb->csum) - skb->data; | 1237 | cso = (skb->h.raw + skb->csum) - skb->data; |
1238 | 1238 | ||
diff --git a/drivers/net/mv643xx_eth.c b/drivers/net/mv643xx_eth.c index 59de3e74d2d7..d4dcc856b3cd 100644 --- a/drivers/net/mv643xx_eth.c +++ b/drivers/net/mv643xx_eth.c | |||
@@ -1147,7 +1147,7 @@ static void eth_tx_submit_descs_for_skb(struct mv643xx_private *mp, | |||
1147 | desc->byte_cnt = length; | 1147 | desc->byte_cnt = length; |
1148 | desc->buf_ptr = dma_map_single(NULL, skb->data, length, DMA_TO_DEVICE); | 1148 | desc->buf_ptr = dma_map_single(NULL, skb->data, length, DMA_TO_DEVICE); |
1149 | 1149 | ||
1150 | if (skb->ip_summed == CHECKSUM_HW) { | 1150 | if (skb->ip_summed == CHECKSUM_PARTIAL) { |
1151 | BUG_ON(skb->protocol != ETH_P_IP); | 1151 | BUG_ON(skb->protocol != ETH_P_IP); |
1152 | 1152 | ||
1153 | cmd_sts |= ETH_GEN_TCP_UDP_CHECKSUM | | 1153 | cmd_sts |= ETH_GEN_TCP_UDP_CHECKSUM | |
diff --git a/drivers/net/myri10ge/myri10ge.c b/drivers/net/myri10ge/myri10ge.c index 9bdd43ab3573..9f16681d0e7e 100644 --- a/drivers/net/myri10ge/myri10ge.c +++ b/drivers/net/myri10ge/myri10ge.c | |||
@@ -930,7 +930,7 @@ static inline void myri10ge_vlan_ip_csum(struct sk_buff *skb, u16 hw_csum) | |||
930 | (vh->h_vlan_encapsulated_proto == htons(ETH_P_IP) || | 930 | (vh->h_vlan_encapsulated_proto == htons(ETH_P_IP) || |
931 | vh->h_vlan_encapsulated_proto == htons(ETH_P_IPV6))) { | 931 | vh->h_vlan_encapsulated_proto == htons(ETH_P_IPV6))) { |
932 | skb->csum = hw_csum; | 932 | skb->csum = hw_csum; |
933 | skb->ip_summed = CHECKSUM_HW; | 933 | skb->ip_summed = CHECKSUM_COMPLETE; |
934 | } | 934 | } |
935 | } | 935 | } |
936 | 936 | ||
@@ -973,7 +973,7 @@ myri10ge_rx_done(struct myri10ge_priv *mgp, struct myri10ge_rx_buf *rx, | |||
973 | if ((skb->protocol == ntohs(ETH_P_IP)) || | 973 | if ((skb->protocol == ntohs(ETH_P_IP)) || |
974 | (skb->protocol == ntohs(ETH_P_IPV6))) { | 974 | (skb->protocol == ntohs(ETH_P_IPV6))) { |
975 | skb->csum = ntohs((u16) csum); | 975 | skb->csum = ntohs((u16) csum); |
976 | skb->ip_summed = CHECKSUM_HW; | 976 | skb->ip_summed = CHECKSUM_COMPLETE; |
977 | } else | 977 | } else |
978 | myri10ge_vlan_ip_csum(skb, ntohs((u16) csum)); | 978 | myri10ge_vlan_ip_csum(skb, ntohs((u16) csum)); |
979 | } | 979 | } |
@@ -1897,13 +1897,13 @@ again: | |||
1897 | pseudo_hdr_offset = 0; | 1897 | pseudo_hdr_offset = 0; |
1898 | odd_flag = 0; | 1898 | odd_flag = 0; |
1899 | flags = (MXGEFW_FLAGS_NO_TSO | MXGEFW_FLAGS_FIRST); | 1899 | flags = (MXGEFW_FLAGS_NO_TSO | MXGEFW_FLAGS_FIRST); |
1900 | if (likely(skb->ip_summed == CHECKSUM_HW)) { | 1900 | if (likely(skb->ip_summed == CHECKSUM_PARTIAL)) { |
1901 | cksum_offset = (skb->h.raw - skb->data); | 1901 | cksum_offset = (skb->h.raw - skb->data); |
1902 | pseudo_hdr_offset = (skb->h.raw + skb->csum) - skb->data; | 1902 | pseudo_hdr_offset = (skb->h.raw + skb->csum) - skb->data; |
1903 | /* If the headers are excessively large, then we must | 1903 | /* If the headers are excessively large, then we must |
1904 | * fall back to a software checksum */ | 1904 | * fall back to a software checksum */ |
1905 | if (unlikely(cksum_offset > 255 || pseudo_hdr_offset > 127)) { | 1905 | if (unlikely(cksum_offset > 255 || pseudo_hdr_offset > 127)) { |
1906 | if (skb_checksum_help(skb, 0)) | 1906 | if (skb_checksum_help(skb)) |
1907 | goto drop; | 1907 | goto drop; |
1908 | cksum_offset = 0; | 1908 | cksum_offset = 0; |
1909 | pseudo_hdr_offset = 0; | 1909 | pseudo_hdr_offset = 0; |
diff --git a/drivers/net/ns83820.c b/drivers/net/ns83820.c index 0e76859c90a2..5143f5dbb2e5 100644 --- a/drivers/net/ns83820.c +++ b/drivers/net/ns83820.c | |||
@@ -1153,7 +1153,7 @@ again: | |||
1153 | if (!nr_frags) | 1153 | if (!nr_frags) |
1154 | frag = NULL; | 1154 | frag = NULL; |
1155 | extsts = 0; | 1155 | extsts = 0; |
1156 | if (skb->ip_summed == CHECKSUM_HW) { | 1156 | if (skb->ip_summed == CHECKSUM_PARTIAL) { |
1157 | extsts |= EXTSTS_IPPKT; | 1157 | extsts |= EXTSTS_IPPKT; |
1158 | if (IPPROTO_TCP == skb->nh.iph->protocol) | 1158 | if (IPPROTO_TCP == skb->nh.iph->protocol) |
1159 | extsts |= EXTSTS_TCPPKT; | 1159 | extsts |= EXTSTS_TCPPKT; |
diff --git a/drivers/net/r8169.c b/drivers/net/r8169.c index 4c2f575faad7..d9b960aa9b0d 100644 --- a/drivers/net/r8169.c +++ b/drivers/net/r8169.c | |||
@@ -2169,7 +2169,7 @@ static inline u32 rtl8169_tso_csum(struct sk_buff *skb, struct net_device *dev) | |||
2169 | if (mss) | 2169 | if (mss) |
2170 | return LargeSend | ((mss & MSSMask) << MSSShift); | 2170 | return LargeSend | ((mss & MSSMask) << MSSShift); |
2171 | } | 2171 | } |
2172 | if (skb->ip_summed == CHECKSUM_HW) { | 2172 | if (skb->ip_summed == CHECKSUM_PARTIAL) { |
2173 | const struct iphdr *ip = skb->nh.iph; | 2173 | const struct iphdr *ip = skb->nh.iph; |
2174 | 2174 | ||
2175 | if (ip->protocol == IPPROTO_TCP) | 2175 | if (ip->protocol == IPPROTO_TCP) |
diff --git a/drivers/net/s2io.c b/drivers/net/s2io.c index e72e0e099060..5b3713f622d7 100644 --- a/drivers/net/s2io.c +++ b/drivers/net/s2io.c | |||
@@ -3893,7 +3893,7 @@ static int s2io_xmit(struct sk_buff *skb, struct net_device *dev) | |||
3893 | txdp->Control_1 |= TXD_TCP_LSO_MSS(s2io_tcp_mss(skb)); | 3893 | txdp->Control_1 |= TXD_TCP_LSO_MSS(s2io_tcp_mss(skb)); |
3894 | } | 3894 | } |
3895 | #endif | 3895 | #endif |
3896 | if (skb->ip_summed == CHECKSUM_HW) { | 3896 | if (skb->ip_summed == CHECKSUM_PARTIAL) { |
3897 | txdp->Control_2 |= | 3897 | txdp->Control_2 |= |
3898 | (TXD_TX_CKO_IPV4_EN | TXD_TX_CKO_TCP_EN | | 3898 | (TXD_TX_CKO_IPV4_EN | TXD_TX_CKO_TCP_EN | |
3899 | TXD_TX_CKO_UDP_EN); | 3899 | TXD_TX_CKO_UDP_EN); |
diff --git a/drivers/net/sk98lin/skge.c b/drivers/net/sk98lin/skge.c index ee62845d3ac9..eb3b35180c2f 100644 --- a/drivers/net/sk98lin/skge.c +++ b/drivers/net/sk98lin/skge.c | |||
@@ -1559,7 +1559,7 @@ struct sk_buff *pMessage) /* pointer to send-message */ | |||
1559 | pTxd->VDataHigh = (SK_U32) (PhysAddr >> 32); | 1559 | pTxd->VDataHigh = (SK_U32) (PhysAddr >> 32); |
1560 | pTxd->pMBuf = pMessage; | 1560 | pTxd->pMBuf = pMessage; |
1561 | 1561 | ||
1562 | if (pMessage->ip_summed == CHECKSUM_HW) { | 1562 | if (pMessage->ip_summed == CHECKSUM_PARTIAL) { |
1563 | u16 hdrlen = pMessage->h.raw - pMessage->data; | 1563 | u16 hdrlen = pMessage->h.raw - pMessage->data; |
1564 | u16 offset = hdrlen + pMessage->csum; | 1564 | u16 offset = hdrlen + pMessage->csum; |
1565 | 1565 | ||
@@ -1678,7 +1678,7 @@ struct sk_buff *pMessage) /* pointer to send-message */ | |||
1678 | /* | 1678 | /* |
1679 | ** Does the HW need to evaluate checksum for TCP or UDP packets? | 1679 | ** Does the HW need to evaluate checksum for TCP or UDP packets? |
1680 | */ | 1680 | */ |
1681 | if (pMessage->ip_summed == CHECKSUM_HW) { | 1681 | if (pMessage->ip_summed == CHECKSUM_PARTIAL) { |
1682 | u16 hdrlen = pMessage->h.raw - pMessage->data; | 1682 | u16 hdrlen = pMessage->h.raw - pMessage->data; |
1683 | u16 offset = hdrlen + pMessage->csum; | 1683 | u16 offset = hdrlen + pMessage->csum; |
1684 | 1684 | ||
@@ -2158,7 +2158,7 @@ rx_start: | |||
2158 | 2158 | ||
2159 | #ifdef USE_SK_RX_CHECKSUM | 2159 | #ifdef USE_SK_RX_CHECKSUM |
2160 | pMsg->csum = pRxd->TcpSums & 0xffff; | 2160 | pMsg->csum = pRxd->TcpSums & 0xffff; |
2161 | pMsg->ip_summed = CHECKSUM_HW; | 2161 | pMsg->ip_summed = CHECKSUM_COMPLETE; |
2162 | #else | 2162 | #else |
2163 | pMsg->ip_summed = CHECKSUM_NONE; | 2163 | pMsg->ip_summed = CHECKSUM_NONE; |
2164 | #endif | 2164 | #endif |
diff --git a/drivers/net/skge.c b/drivers/net/skge.c index ad878dfddef4..b3d6fa3d6df4 100644 --- a/drivers/net/skge.c +++ b/drivers/net/skge.c | |||
@@ -2338,7 +2338,7 @@ static int skge_xmit_frame(struct sk_buff *skb, struct net_device *dev) | |||
2338 | td->dma_lo = map; | 2338 | td->dma_lo = map; |
2339 | td->dma_hi = map >> 32; | 2339 | td->dma_hi = map >> 32; |
2340 | 2340 | ||
2341 | if (skb->ip_summed == CHECKSUM_HW) { | 2341 | if (skb->ip_summed == CHECKSUM_PARTIAL) { |
2342 | int offset = skb->h.raw - skb->data; | 2342 | int offset = skb->h.raw - skb->data; |
2343 | 2343 | ||
2344 | /* This seems backwards, but it is what the sk98lin | 2344 | /* This seems backwards, but it is what the sk98lin |
@@ -2642,7 +2642,7 @@ static inline struct sk_buff *skge_rx_get(struct skge_port *skge, | |||
2642 | skb->dev = skge->netdev; | 2642 | skb->dev = skge->netdev; |
2643 | if (skge->rx_csum) { | 2643 | if (skge->rx_csum) { |
2644 | skb->csum = csum; | 2644 | skb->csum = csum; |
2645 | skb->ip_summed = CHECKSUM_HW; | 2645 | skb->ip_summed = CHECKSUM_COMPLETE; |
2646 | } | 2646 | } |
2647 | 2647 | ||
2648 | skb->protocol = eth_type_trans(skb, skge->netdev); | 2648 | skb->protocol = eth_type_trans(skb, skge->netdev); |
diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c index 933e87f1cc68..8e92566b587e 100644 --- a/drivers/net/sky2.c +++ b/drivers/net/sky2.c | |||
@@ -1163,7 +1163,7 @@ static unsigned tx_le_req(const struct sk_buff *skb) | |||
1163 | if (skb_is_gso(skb)) | 1163 | if (skb_is_gso(skb)) |
1164 | ++count; | 1164 | ++count; |
1165 | 1165 | ||
1166 | if (skb->ip_summed == CHECKSUM_HW) | 1166 | if (skb->ip_summed == CHECKSUM_PARTIAL) |
1167 | ++count; | 1167 | ++count; |
1168 | 1168 | ||
1169 | return count; | 1169 | return count; |
@@ -1272,7 +1272,7 @@ static int sky2_xmit_frame(struct sk_buff *skb, struct net_device *dev) | |||
1272 | #endif | 1272 | #endif |
1273 | 1273 | ||
1274 | /* Handle TCP checksum offload */ | 1274 | /* Handle TCP checksum offload */ |
1275 | if (skb->ip_summed == CHECKSUM_HW) { | 1275 | if (skb->ip_summed == CHECKSUM_PARTIAL) { |
1276 | u16 hdr = skb->h.raw - skb->data; | 1276 | u16 hdr = skb->h.raw - skb->data; |
1277 | u16 offset = hdr + skb->csum; | 1277 | u16 offset = hdr + skb->csum; |
1278 | 1278 | ||
@@ -2000,7 +2000,7 @@ static int sky2_status_intr(struct sky2_hw *hw, int to_do) | |||
2000 | #endif | 2000 | #endif |
2001 | case OP_RXCHKS: | 2001 | case OP_RXCHKS: |
2002 | skb = sky2->rx_ring[sky2->rx_next].skb; | 2002 | skb = sky2->rx_ring[sky2->rx_next].skb; |
2003 | skb->ip_summed = CHECKSUM_HW; | 2003 | skb->ip_summed = CHECKSUM_COMPLETE; |
2004 | skb->csum = le16_to_cpu(status); | 2004 | skb->csum = le16_to_cpu(status); |
2005 | break; | 2005 | break; |
2006 | 2006 | ||
diff --git a/drivers/net/starfire.c b/drivers/net/starfire.c index c0a62b00ffc8..2607aa51d8e0 100644 --- a/drivers/net/starfire.c +++ b/drivers/net/starfire.c | |||
@@ -1230,7 +1230,7 @@ static int start_tx(struct sk_buff *skb, struct net_device *dev) | |||
1230 | } | 1230 | } |
1231 | 1231 | ||
1232 | #if defined(ZEROCOPY) && defined(HAS_BROKEN_FIRMWARE) | 1232 | #if defined(ZEROCOPY) && defined(HAS_BROKEN_FIRMWARE) |
1233 | if (skb->ip_summed == CHECKSUM_HW) { | 1233 | if (skb->ip_summed == CHECKSUM_PARTIAL) { |
1234 | if (skb_padto(skb, (skb->len + PADDING_MASK) & ~PADDING_MASK)) | 1234 | if (skb_padto(skb, (skb->len + PADDING_MASK) & ~PADDING_MASK)) |
1235 | return NETDEV_TX_OK; | 1235 | return NETDEV_TX_OK; |
1236 | } | 1236 | } |
@@ -1252,7 +1252,7 @@ static int start_tx(struct sk_buff *skb, struct net_device *dev) | |||
1252 | status |= TxDescIntr; | 1252 | status |= TxDescIntr; |
1253 | np->reap_tx = 0; | 1253 | np->reap_tx = 0; |
1254 | } | 1254 | } |
1255 | if (skb->ip_summed == CHECKSUM_HW) { | 1255 | if (skb->ip_summed == CHECKSUM_PARTIAL) { |
1256 | status |= TxCalTCP; | 1256 | status |= TxCalTCP; |
1257 | np->stats.tx_compressed++; | 1257 | np->stats.tx_compressed++; |
1258 | } | 1258 | } |
@@ -1499,7 +1499,7 @@ static int __netdev_rx(struct net_device *dev, int *quota) | |||
1499 | * Until then, the printk stays. :-) -Ion | 1499 | * Until then, the printk stays. :-) -Ion |
1500 | */ | 1500 | */ |
1501 | else if (le16_to_cpu(desc->status2) & 0x0040) { | 1501 | else if (le16_to_cpu(desc->status2) & 0x0040) { |
1502 | skb->ip_summed = CHECKSUM_HW; | 1502 | skb->ip_summed = CHECKSUM_COMPLETE; |
1503 | skb->csum = le16_to_cpu(desc->csum); | 1503 | skb->csum = le16_to_cpu(desc->csum); |
1504 | printk(KERN_DEBUG "%s: checksum_hw, status2 = %#x\n", dev->name, le16_to_cpu(desc->status2)); | 1504 | printk(KERN_DEBUG "%s: checksum_hw, status2 = %#x\n", dev->name, le16_to_cpu(desc->status2)); |
1505 | } | 1505 | } |
diff --git a/drivers/net/sungem.c b/drivers/net/sungem.c index d7b1d1882cab..b388651b7836 100644 --- a/drivers/net/sungem.c +++ b/drivers/net/sungem.c | |||
@@ -855,7 +855,7 @@ static int gem_rx(struct gem *gp, int work_to_do) | |||
855 | } | 855 | } |
856 | 856 | ||
857 | skb->csum = ntohs((status & RXDCTRL_TCPCSUM) ^ 0xffff); | 857 | skb->csum = ntohs((status & RXDCTRL_TCPCSUM) ^ 0xffff); |
858 | skb->ip_summed = CHECKSUM_HW; | 858 | skb->ip_summed = CHECKSUM_COMPLETE; |
859 | skb->protocol = eth_type_trans(skb, gp->dev); | 859 | skb->protocol = eth_type_trans(skb, gp->dev); |
860 | 860 | ||
861 | netif_receive_skb(skb); | 861 | netif_receive_skb(skb); |
@@ -1026,7 +1026,7 @@ static int gem_start_xmit(struct sk_buff *skb, struct net_device *dev) | |||
1026 | unsigned long flags; | 1026 | unsigned long flags; |
1027 | 1027 | ||
1028 | ctrl = 0; | 1028 | ctrl = 0; |
1029 | if (skb->ip_summed == CHECKSUM_HW) { | 1029 | if (skb->ip_summed == CHECKSUM_PARTIAL) { |
1030 | u64 csum_start_off, csum_stuff_off; | 1030 | u64 csum_start_off, csum_stuff_off; |
1031 | 1031 | ||
1032 | csum_start_off = (u64) (skb->h.raw - skb->data); | 1032 | csum_start_off = (u64) (skb->h.raw - skb->data); |
diff --git a/drivers/net/sunhme.c b/drivers/net/sunhme.c index c6f5bc3c042f..17981da22730 100644 --- a/drivers/net/sunhme.c +++ b/drivers/net/sunhme.c | |||
@@ -1207,7 +1207,7 @@ static void happy_meal_transceiver_check(struct happy_meal *hp, void __iomem *tr | |||
1207 | * flags, thus: | 1207 | * flags, thus: |
1208 | * | 1208 | * |
1209 | * skb->csum = rxd->rx_flags & 0xffff; | 1209 | * skb->csum = rxd->rx_flags & 0xffff; |
1210 | * skb->ip_summed = CHECKSUM_HW; | 1210 | * skb->ip_summed = CHECKSUM_COMPLETE; |
1211 | * | 1211 | * |
1212 | * before sending off the skb to the protocols, and we are good as gold. | 1212 | * before sending off the skb to the protocols, and we are good as gold. |
1213 | */ | 1213 | */ |
@@ -2074,7 +2074,7 @@ static void happy_meal_rx(struct happy_meal *hp, struct net_device *dev) | |||
2074 | 2074 | ||
2075 | /* This card is _fucking_ hot... */ | 2075 | /* This card is _fucking_ hot... */ |
2076 | skb->csum = ntohs(csum ^ 0xffff); | 2076 | skb->csum = ntohs(csum ^ 0xffff); |
2077 | skb->ip_summed = CHECKSUM_HW; | 2077 | skb->ip_summed = CHECKSUM_COMPLETE; |
2078 | 2078 | ||
2079 | RXD(("len=%d csum=%4x]", len, csum)); | 2079 | RXD(("len=%d csum=%4x]", len, csum)); |
2080 | skb->protocol = eth_type_trans(skb, dev); | 2080 | skb->protocol = eth_type_trans(skb, dev); |
@@ -2268,7 +2268,7 @@ static int happy_meal_start_xmit(struct sk_buff *skb, struct net_device *dev) | |||
2268 | u32 tx_flags; | 2268 | u32 tx_flags; |
2269 | 2269 | ||
2270 | tx_flags = TXFLAG_OWN; | 2270 | tx_flags = TXFLAG_OWN; |
2271 | if (skb->ip_summed == CHECKSUM_HW) { | 2271 | if (skb->ip_summed == CHECKSUM_PARTIAL) { |
2272 | u32 csum_start_off, csum_stuff_off; | 2272 | u32 csum_start_off, csum_stuff_off; |
2273 | 2273 | ||
2274 | csum_start_off = (u32) (skb->h.raw - skb->data); | 2274 | csum_start_off = (u32) (skb->h.raw - skb->data); |
diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index eafabb253f08..fb7026153861 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c | |||
@@ -149,122 +149,67 @@ module_param(tg3_debug, int, 0); | |||
149 | MODULE_PARM_DESC(tg3_debug, "Tigon3 bitmapped debugging message enable value"); | 149 | MODULE_PARM_DESC(tg3_debug, "Tigon3 bitmapped debugging message enable value"); |
150 | 150 | ||
151 | static struct pci_device_id tg3_pci_tbl[] = { | 151 | static struct pci_device_id tg3_pci_tbl[] = { |
152 | { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5700, | 152 | {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5700)}, |
153 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL }, | 153 | {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5701)}, |
154 | { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5701, | 154 | {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5702)}, |
155 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL }, | 155 | {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5703)}, |
156 | { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5702, | 156 | {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5704)}, |
157 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL }, | 157 | {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5702FE)}, |
158 | { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5703, | 158 | {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5705)}, |
159 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL }, | 159 | {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5705_2)}, |
160 | { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5704, | 160 | {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5705M)}, |
161 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL }, | 161 | {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5705M_2)}, |
162 | { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5702FE, | 162 | {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5702X)}, |
163 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL }, | 163 | {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5703X)}, |
164 | { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5705, | 164 | {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5704S)}, |
165 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL }, | 165 | {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5702A3)}, |
166 | { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5705_2, | 166 | {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5703A3)}, |
167 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL }, | 167 | {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5782)}, |
168 | { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5705M, | 168 | {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5788)}, |
169 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL }, | 169 | {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5789)}, |
170 | { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5705M_2, | 170 | {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5901)}, |
171 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL }, | 171 | {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5901_2)}, |
172 | { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5702X, | 172 | {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5704S_2)}, |
173 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL }, | 173 | {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5705F)}, |
174 | { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5703X, | 174 | {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5720)}, |
175 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL }, | 175 | {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5721)}, |
176 | { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5704S, | 176 | {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5750)}, |
177 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL }, | 177 | {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5751)}, |
178 | { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5702A3, | 178 | {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5750M)}, |
179 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL }, | 179 | {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5751M)}, |
180 | { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5703A3, | 180 | {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5751F)}, |
181 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL }, | 181 | {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5752)}, |
182 | { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5782, | 182 | {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5752M)}, |
183 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL }, | 183 | {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5753)}, |
184 | { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5788, | 184 | {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5753M)}, |
185 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL }, | 185 | {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5753F)}, |
186 | { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5789, | 186 | {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5754)}, |
187 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL }, | 187 | {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5754M)}, |
188 | { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5901, | 188 | {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5755)}, |
189 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL }, | 189 | {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5755M)}, |
190 | { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5901_2, | 190 | {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5786)}, |
191 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL }, | 191 | {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5787)}, |
192 | { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5704S_2, | 192 | {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5787M)}, |
193 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL }, | 193 | {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5714)}, |
194 | { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5705F, | 194 | {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5714S)}, |
195 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL }, | 195 | {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5715)}, |
196 | { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5720, | 196 | {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5715S)}, |
197 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL }, | 197 | {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5780)}, |
198 | { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5721, | 198 | {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5780S)}, |
199 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL }, | 199 | {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5781)}, |
200 | { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5750, | 200 | {PCI_DEVICE(PCI_VENDOR_ID_SYSKONNECT, PCI_DEVICE_ID_SYSKONNECT_9DXX)}, |
201 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL }, | 201 | {PCI_DEVICE(PCI_VENDOR_ID_SYSKONNECT, PCI_DEVICE_ID_SYSKONNECT_9MXX)}, |
202 | { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5751, | 202 | {PCI_DEVICE(PCI_VENDOR_ID_ALTIMA, PCI_DEVICE_ID_ALTIMA_AC1000)}, |
203 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL }, | 203 | {PCI_DEVICE(PCI_VENDOR_ID_ALTIMA, PCI_DEVICE_ID_ALTIMA_AC1001)}, |
204 | { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5750M, | 204 | {PCI_DEVICE(PCI_VENDOR_ID_ALTIMA, PCI_DEVICE_ID_ALTIMA_AC1003)}, |
205 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL }, | 205 | {PCI_DEVICE(PCI_VENDOR_ID_ALTIMA, PCI_DEVICE_ID_ALTIMA_AC9100)}, |
206 | { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5751M, | 206 | {PCI_DEVICE(PCI_VENDOR_ID_APPLE, PCI_DEVICE_ID_APPLE_TIGON3)}, |
207 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL }, | 207 | {} |
208 | { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5751F, | ||
209 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL }, | ||
210 | { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5752, | ||
211 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL }, | ||
212 | { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5752M, | ||
213 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL }, | ||
214 | { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5753, | ||
215 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL }, | ||
216 | { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5753M, | ||
217 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL }, | ||
218 | { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5753F, | ||
219 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL }, | ||
220 | { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5754, | ||
221 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL }, | ||
222 | { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5754M, | ||
223 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL }, | ||
224 | { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5755, | ||
225 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL }, | ||
226 | { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5755M, | ||
227 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL }, | ||
228 | { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5786, | ||
229 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL }, | ||
230 | { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5787, | ||
231 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL }, | ||
232 | { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5787M, | ||
233 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL }, | ||
234 | { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5714, | ||
235 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL }, | ||
236 | { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5714S, | ||
237 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL }, | ||
238 | { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5715, | ||
239 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL }, | ||
240 | { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5715S, | ||
241 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL }, | ||
242 | { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5780, | ||
243 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL }, | ||
244 | { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5780S, | ||
245 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL }, | ||
246 | { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5781, | ||
247 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL }, | ||
248 | { PCI_VENDOR_ID_SYSKONNECT, PCI_DEVICE_ID_SYSKONNECT_9DXX, | ||
249 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL }, | ||
250 | { PCI_VENDOR_ID_SYSKONNECT, PCI_DEVICE_ID_SYSKONNECT_9MXX, | ||
251 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL }, | ||
252 | { PCI_VENDOR_ID_ALTIMA, PCI_DEVICE_ID_ALTIMA_AC1000, | ||
253 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL }, | ||
254 | { PCI_VENDOR_ID_ALTIMA, PCI_DEVICE_ID_ALTIMA_AC1001, | ||
255 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL }, | ||
256 | { PCI_VENDOR_ID_ALTIMA, PCI_DEVICE_ID_ALTIMA_AC1003, | ||
257 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL }, | ||
258 | { PCI_VENDOR_ID_ALTIMA, PCI_DEVICE_ID_ALTIMA_AC9100, | ||
259 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL }, | ||
260 | { PCI_VENDOR_ID_APPLE, PCI_DEVICE_ID_APPLE_TIGON3, | ||
261 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL }, | ||
262 | { 0, } | ||
263 | }; | 208 | }; |
264 | 209 | ||
265 | MODULE_DEVICE_TABLE(pci, tg3_pci_tbl); | 210 | MODULE_DEVICE_TABLE(pci, tg3_pci_tbl); |
266 | 211 | ||
267 | static struct { | 212 | static const struct { |
268 | const char string[ETH_GSTRING_LEN]; | 213 | const char string[ETH_GSTRING_LEN]; |
269 | } ethtool_stats_keys[TG3_NUM_STATS] = { | 214 | } ethtool_stats_keys[TG3_NUM_STATS] = { |
270 | { "rx_octets" }, | 215 | { "rx_octets" }, |
@@ -345,7 +290,7 @@ static struct { | |||
345 | { "nic_tx_threshold_hit" } | 290 | { "nic_tx_threshold_hit" } |
346 | }; | 291 | }; |
347 | 292 | ||
348 | static struct { | 293 | static const struct { |
349 | const char string[ETH_GSTRING_LEN]; | 294 | const char string[ETH_GSTRING_LEN]; |
350 | } ethtool_test_keys[TG3_NUM_TEST] = { | 295 | } ethtool_test_keys[TG3_NUM_TEST] = { |
351 | { "nvram test (online) " }, | 296 | { "nvram test (online) " }, |
@@ -3851,11 +3796,11 @@ static int tg3_start_xmit(struct sk_buff *skb, struct net_device *dev) | |||
3851 | skb->h.th->check = 0; | 3796 | skb->h.th->check = 0; |
3852 | 3797 | ||
3853 | } | 3798 | } |
3854 | else if (skb->ip_summed == CHECKSUM_HW) | 3799 | else if (skb->ip_summed == CHECKSUM_PARTIAL) |
3855 | base_flags |= TXD_FLAG_TCPUDP_CSUM; | 3800 | base_flags |= TXD_FLAG_TCPUDP_CSUM; |
3856 | #else | 3801 | #else |
3857 | mss = 0; | 3802 | mss = 0; |
3858 | if (skb->ip_summed == CHECKSUM_HW) | 3803 | if (skb->ip_summed == CHECKSUM_PARTIAL) |
3859 | base_flags |= TXD_FLAG_TCPUDP_CSUM; | 3804 | base_flags |= TXD_FLAG_TCPUDP_CSUM; |
3860 | #endif | 3805 | #endif |
3861 | #if TG3_VLAN_TAG_USED | 3806 | #if TG3_VLAN_TAG_USED |
@@ -3981,7 +3926,7 @@ static int tg3_start_xmit_dma_bug(struct sk_buff *skb, struct net_device *dev) | |||
3981 | 3926 | ||
3982 | entry = tp->tx_prod; | 3927 | entry = tp->tx_prod; |
3983 | base_flags = 0; | 3928 | base_flags = 0; |
3984 | if (skb->ip_summed == CHECKSUM_HW) | 3929 | if (skb->ip_summed == CHECKSUM_PARTIAL) |
3985 | base_flags |= TXD_FLAG_TCPUDP_CSUM; | 3930 | base_flags |= TXD_FLAG_TCPUDP_CSUM; |
3986 | #if TG3_TSO_SUPPORT != 0 | 3931 | #if TG3_TSO_SUPPORT != 0 |
3987 | mss = 0; | 3932 | mss = 0; |
@@ -4969,7 +4914,7 @@ static int tg3_halt(struct tg3 *tp, int kind, int silent) | |||
4969 | #define TG3_FW_BSS_ADDR 0x08000a70 | 4914 | #define TG3_FW_BSS_ADDR 0x08000a70 |
4970 | #define TG3_FW_BSS_LEN 0x10 | 4915 | #define TG3_FW_BSS_LEN 0x10 |
4971 | 4916 | ||
4972 | static u32 tg3FwText[(TG3_FW_TEXT_LEN / sizeof(u32)) + 1] = { | 4917 | static const u32 tg3FwText[(TG3_FW_TEXT_LEN / sizeof(u32)) + 1] = { |
4973 | 0x00000000, 0x10000003, 0x00000000, 0x0000000d, 0x0000000d, 0x3c1d0800, | 4918 | 0x00000000, 0x10000003, 0x00000000, 0x0000000d, 0x0000000d, 0x3c1d0800, |
4974 | 0x37bd3ffc, 0x03a0f021, 0x3c100800, 0x26100000, 0x0e000018, 0x00000000, | 4919 | 0x37bd3ffc, 0x03a0f021, 0x3c100800, 0x26100000, 0x0e000018, 0x00000000, |
4975 | 0x0000000d, 0x3c1d0800, 0x37bd3ffc, 0x03a0f021, 0x3c100800, 0x26100034, | 4920 | 0x0000000d, 0x3c1d0800, 0x37bd3ffc, 0x03a0f021, 0x3c100800, 0x26100034, |
@@ -5063,7 +5008,7 @@ static u32 tg3FwText[(TG3_FW_TEXT_LEN / sizeof(u32)) + 1] = { | |||
5063 | 0x27bd0008, 0x03e00008, 0x00000000, 0x00000000, 0x00000000 | 5008 | 0x27bd0008, 0x03e00008, 0x00000000, 0x00000000, 0x00000000 |
5064 | }; | 5009 | }; |
5065 | 5010 | ||
5066 | static u32 tg3FwRodata[(TG3_FW_RODATA_LEN / sizeof(u32)) + 1] = { | 5011 | static const u32 tg3FwRodata[(TG3_FW_RODATA_LEN / sizeof(u32)) + 1] = { |
5067 | 0x35373031, 0x726c7341, 0x00000000, 0x00000000, 0x53774576, 0x656e7430, | 5012 | 0x35373031, 0x726c7341, 0x00000000, 0x00000000, 0x53774576, 0x656e7430, |
5068 | 0x00000000, 0x726c7045, 0x76656e74, 0x31000000, 0x556e6b6e, 0x45766e74, | 5013 | 0x00000000, 0x726c7045, 0x76656e74, 0x31000000, 0x556e6b6e, 0x45766e74, |
5069 | 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x66617461, 0x6c457272, | 5014 | 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x66617461, 0x6c457272, |
@@ -5128,13 +5073,13 @@ static int tg3_halt_cpu(struct tg3 *tp, u32 offset) | |||
5128 | struct fw_info { | 5073 | struct fw_info { |
5129 | unsigned int text_base; | 5074 | unsigned int text_base; |
5130 | unsigned int text_len; | 5075 | unsigned int text_len; |
5131 | u32 *text_data; | 5076 | const u32 *text_data; |
5132 | unsigned int rodata_base; | 5077 | unsigned int rodata_base; |
5133 | unsigned int rodata_len; | 5078 | unsigned int rodata_len; |
5134 | u32 *rodata_data; | 5079 | const u32 *rodata_data; |
5135 | unsigned int data_base; | 5080 | unsigned int data_base; |
5136 | unsigned int data_len; | 5081 | unsigned int data_len; |
5137 | u32 *data_data; | 5082 | const u32 *data_data; |
5138 | }; | 5083 | }; |
5139 | 5084 | ||
5140 | /* tp->lock is held. */ | 5085 | /* tp->lock is held. */ |
@@ -5266,7 +5211,7 @@ static int tg3_load_5701_a0_firmware_fix(struct tg3 *tp) | |||
5266 | #define TG3_TSO_FW_BSS_ADDR 0x08001b80 | 5211 | #define TG3_TSO_FW_BSS_ADDR 0x08001b80 |
5267 | #define TG3_TSO_FW_BSS_LEN 0x894 | 5212 | #define TG3_TSO_FW_BSS_LEN 0x894 |
5268 | 5213 | ||
5269 | static u32 tg3TsoFwText[(TG3_TSO_FW_TEXT_LEN / 4) + 1] = { | 5214 | static const u32 tg3TsoFwText[(TG3_TSO_FW_TEXT_LEN / 4) + 1] = { |
5270 | 0x0e000003, 0x00000000, 0x08001b24, 0x00000000, 0x10000003, 0x00000000, | 5215 | 0x0e000003, 0x00000000, 0x08001b24, 0x00000000, 0x10000003, 0x00000000, |
5271 | 0x0000000d, 0x0000000d, 0x3c1d0800, 0x37bd4000, 0x03a0f021, 0x3c100800, | 5216 | 0x0000000d, 0x0000000d, 0x3c1d0800, 0x37bd4000, 0x03a0f021, 0x3c100800, |
5272 | 0x26100000, 0x0e000010, 0x00000000, 0x0000000d, 0x27bdffe0, 0x3c04fefe, | 5217 | 0x26100000, 0x0e000010, 0x00000000, 0x0000000d, 0x27bdffe0, 0x3c04fefe, |
@@ -5553,7 +5498,7 @@ static u32 tg3TsoFwText[(TG3_TSO_FW_TEXT_LEN / 4) + 1] = { | |||
5553 | 0xac470014, 0xac4a0018, 0x03e00008, 0xac4b001c, 0x00000000, 0x00000000, | 5498 | 0xac470014, 0xac4a0018, 0x03e00008, 0xac4b001c, 0x00000000, 0x00000000, |
5554 | }; | 5499 | }; |
5555 | 5500 | ||
5556 | static u32 tg3TsoFwRodata[] = { | 5501 | static const u32 tg3TsoFwRodata[] = { |
5557 | 0x4d61696e, 0x43707542, 0x00000000, 0x4d61696e, 0x43707541, 0x00000000, | 5502 | 0x4d61696e, 0x43707542, 0x00000000, 0x4d61696e, 0x43707541, 0x00000000, |
5558 | 0x00000000, 0x00000000, 0x73746b6f, 0x66666c64, 0x496e0000, 0x73746b6f, | 5503 | 0x00000000, 0x00000000, 0x73746b6f, 0x66666c64, 0x496e0000, 0x73746b6f, |
5559 | 0x66662a2a, 0x00000000, 0x53774576, 0x656e7430, 0x00000000, 0x00000000, | 5504 | 0x66662a2a, 0x00000000, 0x53774576, 0x656e7430, 0x00000000, 0x00000000, |
@@ -5561,7 +5506,7 @@ static u32 tg3TsoFwRodata[] = { | |||
5561 | 0x00000000, | 5506 | 0x00000000, |
5562 | }; | 5507 | }; |
5563 | 5508 | ||
5564 | static u32 tg3TsoFwData[] = { | 5509 | static const u32 tg3TsoFwData[] = { |
5565 | 0x00000000, 0x73746b6f, 0x66666c64, 0x5f76312e, 0x362e3000, 0x00000000, | 5510 | 0x00000000, 0x73746b6f, 0x66666c64, 0x5f76312e, 0x362e3000, 0x00000000, |
5566 | 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, | 5511 | 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, |
5567 | 0x00000000, | 5512 | 0x00000000, |
@@ -5583,7 +5528,7 @@ static u32 tg3TsoFwData[] = { | |||
5583 | #define TG3_TSO5_FW_BSS_ADDR 0x00010f50 | 5528 | #define TG3_TSO5_FW_BSS_ADDR 0x00010f50 |
5584 | #define TG3_TSO5_FW_BSS_LEN 0x88 | 5529 | #define TG3_TSO5_FW_BSS_LEN 0x88 |
5585 | 5530 | ||
5586 | static u32 tg3Tso5FwText[(TG3_TSO5_FW_TEXT_LEN / 4) + 1] = { | 5531 | static const u32 tg3Tso5FwText[(TG3_TSO5_FW_TEXT_LEN / 4) + 1] = { |
5587 | 0x0c004003, 0x00000000, 0x00010f04, 0x00000000, 0x10000003, 0x00000000, | 5532 | 0x0c004003, 0x00000000, 0x00010f04, 0x00000000, 0x10000003, 0x00000000, |
5588 | 0x0000000d, 0x0000000d, 0x3c1d0001, 0x37bde000, 0x03a0f021, 0x3c100001, | 5533 | 0x0000000d, 0x0000000d, 0x3c1d0001, 0x37bde000, 0x03a0f021, 0x3c100001, |
5589 | 0x26100000, 0x0c004010, 0x00000000, 0x0000000d, 0x27bdffe0, 0x3c04fefe, | 5534 | 0x26100000, 0x0c004010, 0x00000000, 0x0000000d, 0x27bdffe0, 0x3c04fefe, |
@@ -5742,14 +5687,14 @@ static u32 tg3Tso5FwText[(TG3_TSO5_FW_TEXT_LEN / 4) + 1] = { | |||
5742 | 0x00000000, 0x00000000, 0x00000000, | 5687 | 0x00000000, 0x00000000, 0x00000000, |
5743 | }; | 5688 | }; |
5744 | 5689 | ||
5745 | static u32 tg3Tso5FwRodata[(TG3_TSO5_FW_RODATA_LEN / 4) + 1] = { | 5690 | static const u32 tg3Tso5FwRodata[(TG3_TSO5_FW_RODATA_LEN / 4) + 1] = { |
5746 | 0x4d61696e, 0x43707542, 0x00000000, 0x4d61696e, 0x43707541, 0x00000000, | 5691 | 0x4d61696e, 0x43707542, 0x00000000, 0x4d61696e, 0x43707541, 0x00000000, |
5747 | 0x00000000, 0x00000000, 0x73746b6f, 0x66666c64, 0x00000000, 0x00000000, | 5692 | 0x00000000, 0x00000000, 0x73746b6f, 0x66666c64, 0x00000000, 0x00000000, |
5748 | 0x73746b6f, 0x66666c64, 0x00000000, 0x00000000, 0x66617461, 0x6c457272, | 5693 | 0x73746b6f, 0x66666c64, 0x00000000, 0x00000000, 0x66617461, 0x6c457272, |
5749 | 0x00000000, 0x00000000, 0x00000000, | 5694 | 0x00000000, 0x00000000, 0x00000000, |
5750 | }; | 5695 | }; |
5751 | 5696 | ||
5752 | static u32 tg3Tso5FwData[(TG3_TSO5_FW_DATA_LEN / 4) + 1] = { | 5697 | static const u32 tg3Tso5FwData[(TG3_TSO5_FW_DATA_LEN / 4) + 1] = { |
5753 | 0x00000000, 0x73746b6f, 0x66666c64, 0x5f76312e, 0x322e3000, 0x00000000, | 5698 | 0x00000000, 0x73746b6f, 0x66666c64, 0x5f76312e, 0x322e3000, 0x00000000, |
5754 | 0x00000000, 0x00000000, 0x00000000, | 5699 | 0x00000000, 0x00000000, 0x00000000, |
5755 | }; | 5700 | }; |
diff --git a/drivers/net/typhoon.c b/drivers/net/typhoon.c index 4103c37172f9..c6e601dc6bbc 100644 --- a/drivers/net/typhoon.c +++ b/drivers/net/typhoon.c | |||
@@ -830,7 +830,7 @@ typhoon_start_tx(struct sk_buff *skb, struct net_device *dev) | |||
830 | first_txd->addrHi = (u64)((unsigned long) skb) >> 32; | 830 | first_txd->addrHi = (u64)((unsigned long) skb) >> 32; |
831 | first_txd->processFlags = 0; | 831 | first_txd->processFlags = 0; |
832 | 832 | ||
833 | if(skb->ip_summed == CHECKSUM_HW) { | 833 | if(skb->ip_summed == CHECKSUM_PARTIAL) { |
834 | /* The 3XP will figure out if this is UDP/TCP */ | 834 | /* The 3XP will figure out if this is UDP/TCP */ |
835 | first_txd->processFlags |= TYPHOON_TX_PF_TCP_CHKSUM; | 835 | first_txd->processFlags |= TYPHOON_TX_PF_TCP_CHKSUM; |
836 | first_txd->processFlags |= TYPHOON_TX_PF_UDP_CHKSUM; | 836 | first_txd->processFlags |= TYPHOON_TX_PF_UDP_CHKSUM; |
diff --git a/drivers/net/via-rhine.c b/drivers/net/via-rhine.c index ae971080e2e4..66547159bfd9 100644 --- a/drivers/net/via-rhine.c +++ b/drivers/net/via-rhine.c | |||
@@ -1230,7 +1230,7 @@ static int rhine_start_tx(struct sk_buff *skb, struct net_device *dev) | |||
1230 | rp->tx_skbuff[entry] = skb; | 1230 | rp->tx_skbuff[entry] = skb; |
1231 | 1231 | ||
1232 | if ((rp->quirks & rqRhineI) && | 1232 | if ((rp->quirks & rqRhineI) && |
1233 | (((unsigned long)skb->data & 3) || skb_shinfo(skb)->nr_frags != 0 || skb->ip_summed == CHECKSUM_HW)) { | 1233 | (((unsigned long)skb->data & 3) || skb_shinfo(skb)->nr_frags != 0 || skb->ip_summed == CHECKSUM_PARTIAL)) { |
1234 | /* Must use alignment buffer. */ | 1234 | /* Must use alignment buffer. */ |
1235 | if (skb->len > PKT_BUF_SZ) { | 1235 | if (skb->len > PKT_BUF_SZ) { |
1236 | /* packet too long, drop it */ | 1236 | /* packet too long, drop it */ |
diff --git a/drivers/net/via-velocity.c b/drivers/net/via-velocity.c index aa9cd92f46b2..f1e0c746a388 100644 --- a/drivers/net/via-velocity.c +++ b/drivers/net/via-velocity.c | |||
@@ -2002,7 +2002,7 @@ static int velocity_xmit(struct sk_buff *skb, struct net_device *dev) | |||
2002 | * Handle hardware checksum | 2002 | * Handle hardware checksum |
2003 | */ | 2003 | */ |
2004 | if ((vptr->flags & VELOCITY_FLAGS_TX_CSUM) | 2004 | if ((vptr->flags & VELOCITY_FLAGS_TX_CSUM) |
2005 | && (skb->ip_summed == CHECKSUM_HW)) { | 2005 | && (skb->ip_summed == CHECKSUM_PARTIAL)) { |
2006 | struct iphdr *ip = skb->nh.iph; | 2006 | struct iphdr *ip = skb->nh.iph; |
2007 | if (ip->protocol == IPPROTO_TCP) | 2007 | if (ip->protocol == IPPROTO_TCP) |
2008 | td_ptr->tdesc1.TCR |= TCR0_TCPCK; | 2008 | td_ptr->tdesc1.TCR |= TCR0_TCPCK; |
diff --git a/drivers/video/riva/fbdev.c b/drivers/video/riva/fbdev.c index 67d1e1c8813d..4acde4f7dbf8 100644 --- a/drivers/video/riva/fbdev.c +++ b/drivers/video/riva/fbdev.c | |||
@@ -1826,8 +1826,8 @@ static int __devinit riva_get_EDID_OF(struct fb_info *info, struct pci_dev *pd) | |||
1826 | { | 1826 | { |
1827 | struct riva_par *par = info->par; | 1827 | struct riva_par *par = info->par; |
1828 | struct device_node *dp; | 1828 | struct device_node *dp; |
1829 | unsigned char *pedid = NULL; | 1829 | const unsigned char *pedid = NULL; |
1830 | unsigned char *disptype = NULL; | 1830 | const unsigned char *disptype = NULL; |
1831 | static char *propnames[] = { | 1831 | static char *propnames[] = { |
1832 | "DFP,EDID", "LCD,EDID", "EDID", "EDID1", "EDID,B", "EDID,A", NULL }; | 1832 | "DFP,EDID", "LCD,EDID", "EDID", "EDID1", "EDID,B", "EDID,A", NULL }; |
1833 | int i; | 1833 | int i; |
diff --git a/fs/Kconfig b/fs/Kconfig index 530581628311..a27002668bd3 100644 --- a/fs/Kconfig +++ b/fs/Kconfig | |||
@@ -1471,8 +1471,8 @@ config NFS_V4 | |||
1471 | If unsure, say N. | 1471 | If unsure, say N. |
1472 | 1472 | ||
1473 | config NFS_DIRECTIO | 1473 | config NFS_DIRECTIO |
1474 | bool "Allow direct I/O on NFS files (EXPERIMENTAL)" | 1474 | bool "Allow direct I/O on NFS files" |
1475 | depends on NFS_FS && EXPERIMENTAL | 1475 | depends on NFS_FS |
1476 | help | 1476 | help |
1477 | This option enables applications to perform uncached I/O on files | 1477 | This option enables applications to perform uncached I/O on files |
1478 | in NFS file systems using the O_DIRECT open() flag. When O_DIRECT | 1478 | in NFS file systems using the O_DIRECT open() flag. When O_DIRECT |
diff --git a/fs/dcache.c b/fs/dcache.c index 1b4a3a34ec57..17b392a2049e 100644 --- a/fs/dcache.c +++ b/fs/dcache.c | |||
@@ -828,17 +828,19 @@ void d_instantiate(struct dentry *entry, struct inode * inode) | |||
828 | * (or otherwise set) by the caller to indicate that it is now | 828 | * (or otherwise set) by the caller to indicate that it is now |
829 | * in use by the dcache. | 829 | * in use by the dcache. |
830 | */ | 830 | */ |
831 | struct dentry *d_instantiate_unique(struct dentry *entry, struct inode *inode) | 831 | static struct dentry *__d_instantiate_unique(struct dentry *entry, |
832 | struct inode *inode) | ||
832 | { | 833 | { |
833 | struct dentry *alias; | 834 | struct dentry *alias; |
834 | int len = entry->d_name.len; | 835 | int len = entry->d_name.len; |
835 | const char *name = entry->d_name.name; | 836 | const char *name = entry->d_name.name; |
836 | unsigned int hash = entry->d_name.hash; | 837 | unsigned int hash = entry->d_name.hash; |
837 | 838 | ||
838 | BUG_ON(!list_empty(&entry->d_alias)); | 839 | if (!inode) { |
839 | spin_lock(&dcache_lock); | 840 | entry->d_inode = NULL; |
840 | if (!inode) | 841 | return NULL; |
841 | goto do_negative; | 842 | } |
843 | |||
842 | list_for_each_entry(alias, &inode->i_dentry, d_alias) { | 844 | list_for_each_entry(alias, &inode->i_dentry, d_alias) { |
843 | struct qstr *qstr = &alias->d_name; | 845 | struct qstr *qstr = &alias->d_name; |
844 | 846 | ||
@@ -851,19 +853,35 @@ struct dentry *d_instantiate_unique(struct dentry *entry, struct inode *inode) | |||
851 | if (memcmp(qstr->name, name, len)) | 853 | if (memcmp(qstr->name, name, len)) |
852 | continue; | 854 | continue; |
853 | dget_locked(alias); | 855 | dget_locked(alias); |
854 | spin_unlock(&dcache_lock); | ||
855 | BUG_ON(!d_unhashed(alias)); | ||
856 | iput(inode); | ||
857 | return alias; | 856 | return alias; |
858 | } | 857 | } |
858 | |||
859 | list_add(&entry->d_alias, &inode->i_dentry); | 859 | list_add(&entry->d_alias, &inode->i_dentry); |
860 | do_negative: | ||
861 | entry->d_inode = inode; | 860 | entry->d_inode = inode; |
862 | fsnotify_d_instantiate(entry, inode); | 861 | fsnotify_d_instantiate(entry, inode); |
863 | spin_unlock(&dcache_lock); | ||
864 | security_d_instantiate(entry, inode); | ||
865 | return NULL; | 862 | return NULL; |
866 | } | 863 | } |
864 | |||
865 | struct dentry *d_instantiate_unique(struct dentry *entry, struct inode *inode) | ||
866 | { | ||
867 | struct dentry *result; | ||
868 | |||
869 | BUG_ON(!list_empty(&entry->d_alias)); | ||
870 | |||
871 | spin_lock(&dcache_lock); | ||
872 | result = __d_instantiate_unique(entry, inode); | ||
873 | spin_unlock(&dcache_lock); | ||
874 | |||
875 | if (!result) { | ||
876 | security_d_instantiate(entry, inode); | ||
877 | return NULL; | ||
878 | } | ||
879 | |||
880 | BUG_ON(!d_unhashed(result)); | ||
881 | iput(inode); | ||
882 | return result; | ||
883 | } | ||
884 | |||
867 | EXPORT_SYMBOL(d_instantiate_unique); | 885 | EXPORT_SYMBOL(d_instantiate_unique); |
868 | 886 | ||
869 | /** | 887 | /** |
@@ -1235,6 +1253,11 @@ static void __d_rehash(struct dentry * entry, struct hlist_head *list) | |||
1235 | hlist_add_head_rcu(&entry->d_hash, list); | 1253 | hlist_add_head_rcu(&entry->d_hash, list); |
1236 | } | 1254 | } |
1237 | 1255 | ||
1256 | static void _d_rehash(struct dentry * entry) | ||
1257 | { | ||
1258 | __d_rehash(entry, d_hash(entry->d_parent, entry->d_name.hash)); | ||
1259 | } | ||
1260 | |||
1238 | /** | 1261 | /** |
1239 | * d_rehash - add an entry back to the hash | 1262 | * d_rehash - add an entry back to the hash |
1240 | * @entry: dentry to add to the hash | 1263 | * @entry: dentry to add to the hash |
@@ -1244,11 +1267,9 @@ static void __d_rehash(struct dentry * entry, struct hlist_head *list) | |||
1244 | 1267 | ||
1245 | void d_rehash(struct dentry * entry) | 1268 | void d_rehash(struct dentry * entry) |
1246 | { | 1269 | { |
1247 | struct hlist_head *list = d_hash(entry->d_parent, entry->d_name.hash); | ||
1248 | |||
1249 | spin_lock(&dcache_lock); | 1270 | spin_lock(&dcache_lock); |
1250 | spin_lock(&entry->d_lock); | 1271 | spin_lock(&entry->d_lock); |
1251 | __d_rehash(entry, list); | 1272 | _d_rehash(entry); |
1252 | spin_unlock(&entry->d_lock); | 1273 | spin_unlock(&entry->d_lock); |
1253 | spin_unlock(&dcache_lock); | 1274 | spin_unlock(&dcache_lock); |
1254 | } | 1275 | } |
@@ -1386,6 +1407,120 @@ already_unhashed: | |||
1386 | spin_unlock(&dcache_lock); | 1407 | spin_unlock(&dcache_lock); |
1387 | } | 1408 | } |
1388 | 1409 | ||
1410 | /* | ||
1411 | * Prepare an anonymous dentry for life in the superblock's dentry tree as a | ||
1412 | * named dentry in place of the dentry to be replaced. | ||
1413 | */ | ||
1414 | static void __d_materialise_dentry(struct dentry *dentry, struct dentry *anon) | ||
1415 | { | ||
1416 | struct dentry *dparent, *aparent; | ||
1417 | |||
1418 | switch_names(dentry, anon); | ||
1419 | do_switch(dentry->d_name.len, anon->d_name.len); | ||
1420 | do_switch(dentry->d_name.hash, anon->d_name.hash); | ||
1421 | |||
1422 | dparent = dentry->d_parent; | ||
1423 | aparent = anon->d_parent; | ||
1424 | |||
1425 | dentry->d_parent = (aparent == anon) ? dentry : aparent; | ||
1426 | list_del(&dentry->d_u.d_child); | ||
1427 | if (!IS_ROOT(dentry)) | ||
1428 | list_add(&dentry->d_u.d_child, &dentry->d_parent->d_subdirs); | ||
1429 | else | ||
1430 | INIT_LIST_HEAD(&dentry->d_u.d_child); | ||
1431 | |||
1432 | anon->d_parent = (dparent == dentry) ? anon : dparent; | ||
1433 | list_del(&anon->d_u.d_child); | ||
1434 | if (!IS_ROOT(anon)) | ||
1435 | list_add(&anon->d_u.d_child, &anon->d_parent->d_subdirs); | ||
1436 | else | ||
1437 | INIT_LIST_HEAD(&anon->d_u.d_child); | ||
1438 | |||
1439 | anon->d_flags &= ~DCACHE_DISCONNECTED; | ||
1440 | } | ||
1441 | |||
1442 | /** | ||
1443 | * d_materialise_unique - introduce an inode into the tree | ||
1444 | * @dentry: candidate dentry | ||
1445 | * @inode: inode to bind to the dentry, to which aliases may be attached | ||
1446 | * | ||
1447 | * Introduces an dentry into the tree, substituting an extant disconnected | ||
1448 | * root directory alias in its place if there is one | ||
1449 | */ | ||
1450 | struct dentry *d_materialise_unique(struct dentry *dentry, struct inode *inode) | ||
1451 | { | ||
1452 | struct dentry *alias, *actual; | ||
1453 | |||
1454 | BUG_ON(!d_unhashed(dentry)); | ||
1455 | |||
1456 | spin_lock(&dcache_lock); | ||
1457 | |||
1458 | if (!inode) { | ||
1459 | actual = dentry; | ||
1460 | dentry->d_inode = NULL; | ||
1461 | goto found_lock; | ||
1462 | } | ||
1463 | |||
1464 | /* See if a disconnected directory already exists as an anonymous root | ||
1465 | * that we should splice into the tree instead */ | ||
1466 | if (S_ISDIR(inode->i_mode) && (alias = __d_find_alias(inode, 1))) { | ||
1467 | spin_lock(&alias->d_lock); | ||
1468 | |||
1469 | /* Is this a mountpoint that we could splice into our tree? */ | ||
1470 | if (IS_ROOT(alias)) | ||
1471 | goto connect_mountpoint; | ||
1472 | |||
1473 | if (alias->d_name.len == dentry->d_name.len && | ||
1474 | alias->d_parent == dentry->d_parent && | ||
1475 | memcmp(alias->d_name.name, | ||
1476 | dentry->d_name.name, | ||
1477 | dentry->d_name.len) == 0) | ||
1478 | goto replace_with_alias; | ||
1479 | |||
1480 | spin_unlock(&alias->d_lock); | ||
1481 | |||
1482 | /* Doh! Seem to be aliasing directories for some reason... */ | ||
1483 | dput(alias); | ||
1484 | } | ||
1485 | |||
1486 | /* Add a unique reference */ | ||
1487 | actual = __d_instantiate_unique(dentry, inode); | ||
1488 | if (!actual) | ||
1489 | actual = dentry; | ||
1490 | else if (unlikely(!d_unhashed(actual))) | ||
1491 | goto shouldnt_be_hashed; | ||
1492 | |||
1493 | found_lock: | ||
1494 | spin_lock(&actual->d_lock); | ||
1495 | found: | ||
1496 | _d_rehash(actual); | ||
1497 | spin_unlock(&actual->d_lock); | ||
1498 | spin_unlock(&dcache_lock); | ||
1499 | |||
1500 | if (actual == dentry) { | ||
1501 | security_d_instantiate(dentry, inode); | ||
1502 | return NULL; | ||
1503 | } | ||
1504 | |||
1505 | iput(inode); | ||
1506 | return actual; | ||
1507 | |||
1508 | /* Convert the anonymous/root alias into an ordinary dentry */ | ||
1509 | connect_mountpoint: | ||
1510 | __d_materialise_dentry(dentry, alias); | ||
1511 | |||
1512 | /* Replace the candidate dentry with the alias in the tree */ | ||
1513 | replace_with_alias: | ||
1514 | __d_drop(alias); | ||
1515 | actual = alias; | ||
1516 | goto found; | ||
1517 | |||
1518 | shouldnt_be_hashed: | ||
1519 | spin_unlock(&dcache_lock); | ||
1520 | BUG(); | ||
1521 | goto shouldnt_be_hashed; | ||
1522 | } | ||
1523 | |||
1389 | /** | 1524 | /** |
1390 | * d_path - return the path of a dentry | 1525 | * d_path - return the path of a dentry |
1391 | * @dentry: dentry to report | 1526 | * @dentry: dentry to report |
@@ -1784,6 +1919,7 @@ EXPORT_SYMBOL(d_instantiate); | |||
1784 | EXPORT_SYMBOL(d_invalidate); | 1919 | EXPORT_SYMBOL(d_invalidate); |
1785 | EXPORT_SYMBOL(d_lookup); | 1920 | EXPORT_SYMBOL(d_lookup); |
1786 | EXPORT_SYMBOL(d_move); | 1921 | EXPORT_SYMBOL(d_move); |
1922 | EXPORT_SYMBOL_GPL(d_materialise_unique); | ||
1787 | EXPORT_SYMBOL(d_path); | 1923 | EXPORT_SYMBOL(d_path); |
1788 | EXPORT_SYMBOL(d_prune_aliases); | 1924 | EXPORT_SYMBOL(d_prune_aliases); |
1789 | EXPORT_SYMBOL(d_rehash); | 1925 | EXPORT_SYMBOL(d_rehash); |
diff --git a/fs/lockd/clntproc.c b/fs/lockd/clntproc.c index 89ba0df14c22..50dbb67ae0c4 100644 --- a/fs/lockd/clntproc.c +++ b/fs/lockd/clntproc.c | |||
@@ -151,11 +151,13 @@ static void nlmclnt_release_lockargs(struct nlm_rqst *req) | |||
151 | int | 151 | int |
152 | nlmclnt_proc(struct inode *inode, int cmd, struct file_lock *fl) | 152 | nlmclnt_proc(struct inode *inode, int cmd, struct file_lock *fl) |
153 | { | 153 | { |
154 | struct rpc_clnt *client = NFS_CLIENT(inode); | ||
155 | struct sockaddr_in addr; | ||
154 | struct nlm_host *host; | 156 | struct nlm_host *host; |
155 | struct nlm_rqst *call; | 157 | struct nlm_rqst *call; |
156 | sigset_t oldset; | 158 | sigset_t oldset; |
157 | unsigned long flags; | 159 | unsigned long flags; |
158 | int status, proto, vers; | 160 | int status, vers; |
159 | 161 | ||
160 | vers = (NFS_PROTO(inode)->version == 3) ? 4 : 1; | 162 | vers = (NFS_PROTO(inode)->version == 3) ? 4 : 1; |
161 | if (NFS_PROTO(inode)->version > 3) { | 163 | if (NFS_PROTO(inode)->version > 3) { |
@@ -163,10 +165,8 @@ nlmclnt_proc(struct inode *inode, int cmd, struct file_lock *fl) | |||
163 | return -ENOLCK; | 165 | return -ENOLCK; |
164 | } | 166 | } |
165 | 167 | ||
166 | /* Retrieve transport protocol from NFS client */ | 168 | rpc_peeraddr(client, (struct sockaddr *) &addr, sizeof(addr)); |
167 | proto = NFS_CLIENT(inode)->cl_xprt->prot; | 169 | host = nlmclnt_lookup_host(&addr, client->cl_xprt->prot, vers); |
168 | |||
169 | host = nlmclnt_lookup_host(NFS_ADDR(inode), proto, vers); | ||
170 | if (host == NULL) | 170 | if (host == NULL) |
171 | return -ENOLCK; | 171 | return -ENOLCK; |
172 | 172 | ||
diff --git a/fs/lockd/host.c b/fs/lockd/host.c index 38b0e8a1aec0..703fb038c813 100644 --- a/fs/lockd/host.c +++ b/fs/lockd/host.c | |||
@@ -26,7 +26,6 @@ | |||
26 | #define NLM_HOST_REBIND (60 * HZ) | 26 | #define NLM_HOST_REBIND (60 * HZ) |
27 | #define NLM_HOST_EXPIRE ((nrhosts > NLM_HOST_MAX)? 300 * HZ : 120 * HZ) | 27 | #define NLM_HOST_EXPIRE ((nrhosts > NLM_HOST_MAX)? 300 * HZ : 120 * HZ) |
28 | #define NLM_HOST_COLLECT ((nrhosts > NLM_HOST_MAX)? 120 * HZ : 60 * HZ) | 28 | #define NLM_HOST_COLLECT ((nrhosts > NLM_HOST_MAX)? 120 * HZ : 60 * HZ) |
29 | #define NLM_HOST_ADDR(sv) (&(sv)->s_nlmclnt->cl_xprt->addr) | ||
30 | 29 | ||
31 | static struct nlm_host * nlm_hosts[NLM_HOST_NRHASH]; | 30 | static struct nlm_host * nlm_hosts[NLM_HOST_NRHASH]; |
32 | static unsigned long next_gc; | 31 | static unsigned long next_gc; |
@@ -167,7 +166,6 @@ struct rpc_clnt * | |||
167 | nlm_bind_host(struct nlm_host *host) | 166 | nlm_bind_host(struct nlm_host *host) |
168 | { | 167 | { |
169 | struct rpc_clnt *clnt; | 168 | struct rpc_clnt *clnt; |
170 | struct rpc_xprt *xprt; | ||
171 | 169 | ||
172 | dprintk("lockd: nlm_bind_host(%08x)\n", | 170 | dprintk("lockd: nlm_bind_host(%08x)\n", |
173 | (unsigned)ntohl(host->h_addr.sin_addr.s_addr)); | 171 | (unsigned)ntohl(host->h_addr.sin_addr.s_addr)); |
@@ -179,7 +177,6 @@ nlm_bind_host(struct nlm_host *host) | |||
179 | * RPC rebind is required | 177 | * RPC rebind is required |
180 | */ | 178 | */ |
181 | if ((clnt = host->h_rpcclnt) != NULL) { | 179 | if ((clnt = host->h_rpcclnt) != NULL) { |
182 | xprt = clnt->cl_xprt; | ||
183 | if (time_after_eq(jiffies, host->h_nextrebind)) { | 180 | if (time_after_eq(jiffies, host->h_nextrebind)) { |
184 | rpc_force_rebind(clnt); | 181 | rpc_force_rebind(clnt); |
185 | host->h_nextrebind = jiffies + NLM_HOST_REBIND; | 182 | host->h_nextrebind = jiffies + NLM_HOST_REBIND; |
@@ -187,31 +184,37 @@ nlm_bind_host(struct nlm_host *host) | |||
187 | host->h_nextrebind - jiffies); | 184 | host->h_nextrebind - jiffies); |
188 | } | 185 | } |
189 | } else { | 186 | } else { |
190 | xprt = xprt_create_proto(host->h_proto, &host->h_addr, NULL); | 187 | unsigned long increment = nlmsvc_timeout * HZ; |
191 | if (IS_ERR(xprt)) | 188 | struct rpc_timeout timeparms = { |
192 | goto forgetit; | 189 | .to_initval = increment, |
193 | 190 | .to_increment = increment, | |
194 | xprt_set_timeout(&xprt->timeout, 5, nlmsvc_timeout); | 191 | .to_maxval = increment * 6UL, |
195 | xprt->resvport = 1; /* NLM requires a reserved port */ | 192 | .to_retries = 5U, |
196 | 193 | }; | |
197 | /* Existing NLM servers accept AUTH_UNIX only */ | 194 | struct rpc_create_args args = { |
198 | clnt = rpc_new_client(xprt, host->h_name, &nlm_program, | 195 | .protocol = host->h_proto, |
199 | host->h_version, RPC_AUTH_UNIX); | 196 | .address = (struct sockaddr *)&host->h_addr, |
200 | if (IS_ERR(clnt)) | 197 | .addrsize = sizeof(host->h_addr), |
201 | goto forgetit; | 198 | .timeout = &timeparms, |
202 | clnt->cl_autobind = 1; /* turn on pmap queries */ | 199 | .servername = host->h_name, |
203 | clnt->cl_softrtry = 1; /* All queries are soft */ | 200 | .program = &nlm_program, |
204 | 201 | .version = host->h_version, | |
205 | host->h_rpcclnt = clnt; | 202 | .authflavor = RPC_AUTH_UNIX, |
203 | .flags = (RPC_CLNT_CREATE_HARDRTRY | | ||
204 | RPC_CLNT_CREATE_AUTOBIND), | ||
205 | }; | ||
206 | |||
207 | clnt = rpc_create(&args); | ||
208 | if (!IS_ERR(clnt)) | ||
209 | host->h_rpcclnt = clnt; | ||
210 | else { | ||
211 | printk("lockd: couldn't create RPC handle for %s\n", host->h_name); | ||
212 | clnt = NULL; | ||
213 | } | ||
206 | } | 214 | } |
207 | 215 | ||
208 | mutex_unlock(&host->h_mutex); | 216 | mutex_unlock(&host->h_mutex); |
209 | return clnt; | 217 | return clnt; |
210 | |||
211 | forgetit: | ||
212 | printk("lockd: couldn't create RPC handle for %s\n", host->h_name); | ||
213 | mutex_unlock(&host->h_mutex); | ||
214 | return NULL; | ||
215 | } | 218 | } |
216 | 219 | ||
217 | /* | 220 | /* |
diff --git a/fs/lockd/mon.c b/fs/lockd/mon.c index 3fc683f46b3e..5954dcb497e4 100644 --- a/fs/lockd/mon.c +++ b/fs/lockd/mon.c | |||
@@ -109,30 +109,23 @@ nsm_unmonitor(struct nlm_host *host) | |||
109 | static struct rpc_clnt * | 109 | static struct rpc_clnt * |
110 | nsm_create(void) | 110 | nsm_create(void) |
111 | { | 111 | { |
112 | struct rpc_xprt *xprt; | 112 | struct sockaddr_in sin = { |
113 | struct rpc_clnt *clnt; | 113 | .sin_family = AF_INET, |
114 | struct sockaddr_in sin; | 114 | .sin_addr.s_addr = htonl(INADDR_LOOPBACK), |
115 | 115 | .sin_port = 0, | |
116 | sin.sin_family = AF_INET; | 116 | }; |
117 | sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK); | 117 | struct rpc_create_args args = { |
118 | sin.sin_port = 0; | 118 | .protocol = IPPROTO_UDP, |
119 | 119 | .address = (struct sockaddr *)&sin, | |
120 | xprt = xprt_create_proto(IPPROTO_UDP, &sin, NULL); | 120 | .addrsize = sizeof(sin), |
121 | if (IS_ERR(xprt)) | 121 | .servername = "localhost", |
122 | return (struct rpc_clnt *)xprt; | 122 | .program = &nsm_program, |
123 | xprt->resvport = 1; /* NSM requires a reserved port */ | 123 | .version = SM_VERSION, |
124 | 124 | .authflavor = RPC_AUTH_NULL, | |
125 | clnt = rpc_create_client(xprt, "localhost", | 125 | .flags = (RPC_CLNT_CREATE_ONESHOT), |
126 | &nsm_program, SM_VERSION, | 126 | }; |
127 | RPC_AUTH_NULL); | 127 | |
128 | if (IS_ERR(clnt)) | 128 | return rpc_create(&args); |
129 | goto out_err; | ||
130 | clnt->cl_softrtry = 1; | ||
131 | clnt->cl_oneshot = 1; | ||
132 | return clnt; | ||
133 | |||
134 | out_err: | ||
135 | return clnt; | ||
136 | } | 129 | } |
137 | 130 | ||
138 | /* | 131 | /* |
diff --git a/fs/nfs/Makefile b/fs/nfs/Makefile index 0b572a0c1967..f4580b44eef4 100644 --- a/fs/nfs/Makefile +++ b/fs/nfs/Makefile | |||
@@ -4,9 +4,9 @@ | |||
4 | 4 | ||
5 | obj-$(CONFIG_NFS_FS) += nfs.o | 5 | obj-$(CONFIG_NFS_FS) += nfs.o |
6 | 6 | ||
7 | nfs-y := dir.o file.o inode.o super.o nfs2xdr.o pagelist.o \ | 7 | nfs-y := client.o dir.o file.o getroot.o inode.o super.o nfs2xdr.o \ |
8 | proc.o read.o symlink.o unlink.o write.o \ | 8 | pagelist.o proc.o read.o symlink.o unlink.o \ |
9 | namespace.o | 9 | write.o namespace.o |
10 | nfs-$(CONFIG_ROOT_NFS) += nfsroot.o mount_clnt.o | 10 | nfs-$(CONFIG_ROOT_NFS) += nfsroot.o mount_clnt.o |
11 | nfs-$(CONFIG_NFS_V3) += nfs3proc.o nfs3xdr.o | 11 | nfs-$(CONFIG_NFS_V3) += nfs3proc.o nfs3xdr.o |
12 | nfs-$(CONFIG_NFS_V3_ACL) += nfs3acl.o | 12 | nfs-$(CONFIG_NFS_V3_ACL) += nfs3acl.o |
diff --git a/fs/nfs/callback.c b/fs/nfs/callback.c index fe0a6b8ac149..a3ee11364db0 100644 --- a/fs/nfs/callback.c +++ b/fs/nfs/callback.c | |||
@@ -19,6 +19,7 @@ | |||
19 | 19 | ||
20 | #include "nfs4_fs.h" | 20 | #include "nfs4_fs.h" |
21 | #include "callback.h" | 21 | #include "callback.h" |
22 | #include "internal.h" | ||
22 | 23 | ||
23 | #define NFSDBG_FACILITY NFSDBG_CALLBACK | 24 | #define NFSDBG_FACILITY NFSDBG_CALLBACK |
24 | 25 | ||
@@ -36,6 +37,21 @@ static struct svc_program nfs4_callback_program; | |||
36 | 37 | ||
37 | unsigned int nfs_callback_set_tcpport; | 38 | unsigned int nfs_callback_set_tcpport; |
38 | unsigned short nfs_callback_tcpport; | 39 | unsigned short nfs_callback_tcpport; |
40 | static const int nfs_set_port_min = 0; | ||
41 | static const int nfs_set_port_max = 65535; | ||
42 | |||
43 | static int param_set_port(const char *val, struct kernel_param *kp) | ||
44 | { | ||
45 | char *endp; | ||
46 | int num = simple_strtol(val, &endp, 0); | ||
47 | if (endp == val || *endp || num < nfs_set_port_min || num > nfs_set_port_max) | ||
48 | return -EINVAL; | ||
49 | *((int *)kp->arg) = num; | ||
50 | return 0; | ||
51 | } | ||
52 | |||
53 | module_param_call(callback_tcpport, param_set_port, param_get_int, | ||
54 | &nfs_callback_set_tcpport, 0644); | ||
39 | 55 | ||
40 | /* | 56 | /* |
41 | * This is the callback kernel thread. | 57 | * This is the callback kernel thread. |
@@ -134,10 +150,8 @@ out_err: | |||
134 | /* | 150 | /* |
135 | * Kill the server process if it is not already up. | 151 | * Kill the server process if it is not already up. |
136 | */ | 152 | */ |
137 | int nfs_callback_down(void) | 153 | void nfs_callback_down(void) |
138 | { | 154 | { |
139 | int ret = 0; | ||
140 | |||
141 | lock_kernel(); | 155 | lock_kernel(); |
142 | mutex_lock(&nfs_callback_mutex); | 156 | mutex_lock(&nfs_callback_mutex); |
143 | nfs_callback_info.users--; | 157 | nfs_callback_info.users--; |
@@ -149,20 +163,19 @@ int nfs_callback_down(void) | |||
149 | } while (wait_for_completion_timeout(&nfs_callback_info.stopped, 5*HZ) == 0); | 163 | } while (wait_for_completion_timeout(&nfs_callback_info.stopped, 5*HZ) == 0); |
150 | mutex_unlock(&nfs_callback_mutex); | 164 | mutex_unlock(&nfs_callback_mutex); |
151 | unlock_kernel(); | 165 | unlock_kernel(); |
152 | return ret; | ||
153 | } | 166 | } |
154 | 167 | ||
155 | static int nfs_callback_authenticate(struct svc_rqst *rqstp) | 168 | static int nfs_callback_authenticate(struct svc_rqst *rqstp) |
156 | { | 169 | { |
157 | struct in_addr *addr = &rqstp->rq_addr.sin_addr; | 170 | struct sockaddr_in *addr = &rqstp->rq_addr; |
158 | struct nfs4_client *clp; | 171 | struct nfs_client *clp; |
159 | 172 | ||
160 | /* Don't talk to strangers */ | 173 | /* Don't talk to strangers */ |
161 | clp = nfs4_find_client(addr); | 174 | clp = nfs_find_client(addr, 4); |
162 | if (clp == NULL) | 175 | if (clp == NULL) |
163 | return SVC_DROP; | 176 | return SVC_DROP; |
164 | dprintk("%s: %u.%u.%u.%u NFSv4 callback!\n", __FUNCTION__, NIPQUAD(addr)); | 177 | dprintk("%s: %u.%u.%u.%u NFSv4 callback!\n", __FUNCTION__, NIPQUAD(addr->sin_addr)); |
165 | nfs4_put_client(clp); | 178 | nfs_put_client(clp); |
166 | switch (rqstp->rq_authop->flavour) { | 179 | switch (rqstp->rq_authop->flavour) { |
167 | case RPC_AUTH_NULL: | 180 | case RPC_AUTH_NULL: |
168 | if (rqstp->rq_proc != CB_NULL) | 181 | if (rqstp->rq_proc != CB_NULL) |
diff --git a/fs/nfs/callback.h b/fs/nfs/callback.h index b252e7fe53a5..5676163d26e8 100644 --- a/fs/nfs/callback.h +++ b/fs/nfs/callback.h | |||
@@ -62,8 +62,13 @@ struct cb_recallargs { | |||
62 | extern unsigned nfs4_callback_getattr(struct cb_getattrargs *args, struct cb_getattrres *res); | 62 | extern unsigned nfs4_callback_getattr(struct cb_getattrargs *args, struct cb_getattrres *res); |
63 | extern unsigned nfs4_callback_recall(struct cb_recallargs *args, void *dummy); | 63 | extern unsigned nfs4_callback_recall(struct cb_recallargs *args, void *dummy); |
64 | 64 | ||
65 | #ifdef CONFIG_NFS_V4 | ||
65 | extern int nfs_callback_up(void); | 66 | extern int nfs_callback_up(void); |
66 | extern int nfs_callback_down(void); | 67 | extern void nfs_callback_down(void); |
68 | #else | ||
69 | #define nfs_callback_up() (0) | ||
70 | #define nfs_callback_down() do {} while(0) | ||
71 | #endif | ||
67 | 72 | ||
68 | extern unsigned int nfs_callback_set_tcpport; | 73 | extern unsigned int nfs_callback_set_tcpport; |
69 | extern unsigned short nfs_callback_tcpport; | 74 | extern unsigned short nfs_callback_tcpport; |
diff --git a/fs/nfs/callback_proc.c b/fs/nfs/callback_proc.c index 7719483ecdfc..97cf8f71451f 100644 --- a/fs/nfs/callback_proc.c +++ b/fs/nfs/callback_proc.c | |||
@@ -10,19 +10,20 @@ | |||
10 | #include "nfs4_fs.h" | 10 | #include "nfs4_fs.h" |
11 | #include "callback.h" | 11 | #include "callback.h" |
12 | #include "delegation.h" | 12 | #include "delegation.h" |
13 | #include "internal.h" | ||
13 | 14 | ||
14 | #define NFSDBG_FACILITY NFSDBG_CALLBACK | 15 | #define NFSDBG_FACILITY NFSDBG_CALLBACK |
15 | 16 | ||
16 | unsigned nfs4_callback_getattr(struct cb_getattrargs *args, struct cb_getattrres *res) | 17 | unsigned nfs4_callback_getattr(struct cb_getattrargs *args, struct cb_getattrres *res) |
17 | { | 18 | { |
18 | struct nfs4_client *clp; | 19 | struct nfs_client *clp; |
19 | struct nfs_delegation *delegation; | 20 | struct nfs_delegation *delegation; |
20 | struct nfs_inode *nfsi; | 21 | struct nfs_inode *nfsi; |
21 | struct inode *inode; | 22 | struct inode *inode; |
22 | 23 | ||
23 | res->bitmap[0] = res->bitmap[1] = 0; | 24 | res->bitmap[0] = res->bitmap[1] = 0; |
24 | res->status = htonl(NFS4ERR_BADHANDLE); | 25 | res->status = htonl(NFS4ERR_BADHANDLE); |
25 | clp = nfs4_find_client(&args->addr->sin_addr); | 26 | clp = nfs_find_client(args->addr, 4); |
26 | if (clp == NULL) | 27 | if (clp == NULL) |
27 | goto out; | 28 | goto out; |
28 | inode = nfs_delegation_find_inode(clp, &args->fh); | 29 | inode = nfs_delegation_find_inode(clp, &args->fh); |
@@ -48,7 +49,7 @@ out_iput: | |||
48 | up_read(&nfsi->rwsem); | 49 | up_read(&nfsi->rwsem); |
49 | iput(inode); | 50 | iput(inode); |
50 | out_putclient: | 51 | out_putclient: |
51 | nfs4_put_client(clp); | 52 | nfs_put_client(clp); |
52 | out: | 53 | out: |
53 | dprintk("%s: exit with status = %d\n", __FUNCTION__, ntohl(res->status)); | 54 | dprintk("%s: exit with status = %d\n", __FUNCTION__, ntohl(res->status)); |
54 | return res->status; | 55 | return res->status; |
@@ -56,12 +57,12 @@ out: | |||
56 | 57 | ||
57 | unsigned nfs4_callback_recall(struct cb_recallargs *args, void *dummy) | 58 | unsigned nfs4_callback_recall(struct cb_recallargs *args, void *dummy) |
58 | { | 59 | { |
59 | struct nfs4_client *clp; | 60 | struct nfs_client *clp; |
60 | struct inode *inode; | 61 | struct inode *inode; |
61 | unsigned res; | 62 | unsigned res; |
62 | 63 | ||
63 | res = htonl(NFS4ERR_BADHANDLE); | 64 | res = htonl(NFS4ERR_BADHANDLE); |
64 | clp = nfs4_find_client(&args->addr->sin_addr); | 65 | clp = nfs_find_client(args->addr, 4); |
65 | if (clp == NULL) | 66 | if (clp == NULL) |
66 | goto out; | 67 | goto out; |
67 | inode = nfs_delegation_find_inode(clp, &args->fh); | 68 | inode = nfs_delegation_find_inode(clp, &args->fh); |
@@ -80,7 +81,7 @@ unsigned nfs4_callback_recall(struct cb_recallargs *args, void *dummy) | |||
80 | } | 81 | } |
81 | iput(inode); | 82 | iput(inode); |
82 | out_putclient: | 83 | out_putclient: |
83 | nfs4_put_client(clp); | 84 | nfs_put_client(clp); |
84 | out: | 85 | out: |
85 | dprintk("%s: exit with status = %d\n", __FUNCTION__, ntohl(res)); | 86 | dprintk("%s: exit with status = %d\n", __FUNCTION__, ntohl(res)); |
86 | return res; | 87 | return res; |
diff --git a/fs/nfs/client.c b/fs/nfs/client.c new file mode 100644 index 000000000000..ec1938d4b814 --- /dev/null +++ b/fs/nfs/client.c | |||
@@ -0,0 +1,1448 @@ | |||
1 | /* client.c: NFS client sharing and management code | ||
2 | * | ||
3 | * Copyright (C) 2006 Red Hat, Inc. All Rights Reserved. | ||
4 | * Written by David Howells (dhowells@redhat.com) | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or | ||
7 | * modify it under the terms of the GNU General Public License | ||
8 | * as published by the Free Software Foundation; either version | ||
9 | * 2 of the License, or (at your option) any later version. | ||
10 | */ | ||
11 | |||
12 | |||
13 | #include <linux/config.h> | ||
14 | #include <linux/module.h> | ||
15 | #include <linux/init.h> | ||
16 | |||
17 | #include <linux/time.h> | ||
18 | #include <linux/kernel.h> | ||
19 | #include <linux/mm.h> | ||
20 | #include <linux/string.h> | ||
21 | #include <linux/stat.h> | ||
22 | #include <linux/errno.h> | ||
23 | #include <linux/unistd.h> | ||
24 | #include <linux/sunrpc/clnt.h> | ||
25 | #include <linux/sunrpc/stats.h> | ||
26 | #include <linux/sunrpc/metrics.h> | ||
27 | #include <linux/nfs_fs.h> | ||
28 | #include <linux/nfs_mount.h> | ||
29 | #include <linux/nfs4_mount.h> | ||
30 | #include <linux/lockd/bind.h> | ||
31 | #include <linux/smp_lock.h> | ||
32 | #include <linux/seq_file.h> | ||
33 | #include <linux/mount.h> | ||
34 | #include <linux/nfs_idmap.h> | ||
35 | #include <linux/vfs.h> | ||
36 | #include <linux/inet.h> | ||
37 | #include <linux/nfs_xdr.h> | ||
38 | |||
39 | #include <asm/system.h> | ||
40 | |||
41 | #include "nfs4_fs.h" | ||
42 | #include "callback.h" | ||
43 | #include "delegation.h" | ||
44 | #include "iostat.h" | ||
45 | #include "internal.h" | ||
46 | |||
47 | #define NFSDBG_FACILITY NFSDBG_CLIENT | ||
48 | |||
49 | static DEFINE_SPINLOCK(nfs_client_lock); | ||
50 | static LIST_HEAD(nfs_client_list); | ||
51 | static LIST_HEAD(nfs_volume_list); | ||
52 | static DECLARE_WAIT_QUEUE_HEAD(nfs_client_active_wq); | ||
53 | |||
54 | /* | ||
55 | * RPC cruft for NFS | ||
56 | */ | ||
57 | static struct rpc_version *nfs_version[5] = { | ||
58 | [2] = &nfs_version2, | ||
59 | #ifdef CONFIG_NFS_V3 | ||
60 | [3] = &nfs_version3, | ||
61 | #endif | ||
62 | #ifdef CONFIG_NFS_V4 | ||
63 | [4] = &nfs_version4, | ||
64 | #endif | ||
65 | }; | ||
66 | |||
67 | struct rpc_program nfs_program = { | ||
68 | .name = "nfs", | ||
69 | .number = NFS_PROGRAM, | ||
70 | .nrvers = ARRAY_SIZE(nfs_version), | ||
71 | .version = nfs_version, | ||
72 | .stats = &nfs_rpcstat, | ||
73 | .pipe_dir_name = "/nfs", | ||
74 | }; | ||
75 | |||
76 | struct rpc_stat nfs_rpcstat = { | ||
77 | .program = &nfs_program | ||
78 | }; | ||
79 | |||
80 | |||
81 | #ifdef CONFIG_NFS_V3_ACL | ||
82 | static struct rpc_stat nfsacl_rpcstat = { &nfsacl_program }; | ||
83 | static struct rpc_version * nfsacl_version[] = { | ||
84 | [3] = &nfsacl_version3, | ||
85 | }; | ||
86 | |||
87 | struct rpc_program nfsacl_program = { | ||
88 | .name = "nfsacl", | ||
89 | .number = NFS_ACL_PROGRAM, | ||
90 | .nrvers = ARRAY_SIZE(nfsacl_version), | ||
91 | .version = nfsacl_version, | ||
92 | .stats = &nfsacl_rpcstat, | ||
93 | }; | ||
94 | #endif /* CONFIG_NFS_V3_ACL */ | ||
95 | |||
96 | /* | ||
97 | * Allocate a shared client record | ||
98 | * | ||
99 | * Since these are allocated/deallocated very rarely, we don't | ||
100 | * bother putting them in a slab cache... | ||
101 | */ | ||
102 | static struct nfs_client *nfs_alloc_client(const char *hostname, | ||
103 | const struct sockaddr_in *addr, | ||
104 | int nfsversion) | ||
105 | { | ||
106 | struct nfs_client *clp; | ||
107 | int error; | ||
108 | |||
109 | if ((clp = kzalloc(sizeof(*clp), GFP_KERNEL)) == NULL) | ||
110 | goto error_0; | ||
111 | |||
112 | error = rpciod_up(); | ||
113 | if (error < 0) { | ||
114 | dprintk("%s: couldn't start rpciod! Error = %d\n", | ||
115 | __FUNCTION__, error); | ||
116 | goto error_1; | ||
117 | } | ||
118 | __set_bit(NFS_CS_RPCIOD, &clp->cl_res_state); | ||
119 | |||
120 | if (nfsversion == 4) { | ||
121 | if (nfs_callback_up() < 0) | ||
122 | goto error_2; | ||
123 | __set_bit(NFS_CS_CALLBACK, &clp->cl_res_state); | ||
124 | } | ||
125 | |||
126 | atomic_set(&clp->cl_count, 1); | ||
127 | clp->cl_cons_state = NFS_CS_INITING; | ||
128 | |||
129 | clp->cl_nfsversion = nfsversion; | ||
130 | memcpy(&clp->cl_addr, addr, sizeof(clp->cl_addr)); | ||
131 | |||
132 | if (hostname) { | ||
133 | clp->cl_hostname = kstrdup(hostname, GFP_KERNEL); | ||
134 | if (!clp->cl_hostname) | ||
135 | goto error_3; | ||
136 | } | ||
137 | |||
138 | INIT_LIST_HEAD(&clp->cl_superblocks); | ||
139 | clp->cl_rpcclient = ERR_PTR(-EINVAL); | ||
140 | |||
141 | #ifdef CONFIG_NFS_V4 | ||
142 | init_rwsem(&clp->cl_sem); | ||
143 | INIT_LIST_HEAD(&clp->cl_delegations); | ||
144 | INIT_LIST_HEAD(&clp->cl_state_owners); | ||
145 | INIT_LIST_HEAD(&clp->cl_unused); | ||
146 | spin_lock_init(&clp->cl_lock); | ||
147 | INIT_WORK(&clp->cl_renewd, nfs4_renew_state, clp); | ||
148 | rpc_init_wait_queue(&clp->cl_rpcwaitq, "NFS client"); | ||
149 | clp->cl_boot_time = CURRENT_TIME; | ||
150 | clp->cl_state = 1 << NFS4CLNT_LEASE_EXPIRED; | ||
151 | #endif | ||
152 | |||
153 | return clp; | ||
154 | |||
155 | error_3: | ||
156 | if (__test_and_clear_bit(NFS_CS_CALLBACK, &clp->cl_res_state)) | ||
157 | nfs_callback_down(); | ||
158 | error_2: | ||
159 | rpciod_down(); | ||
160 | __clear_bit(NFS_CS_RPCIOD, &clp->cl_res_state); | ||
161 | error_1: | ||
162 | kfree(clp); | ||
163 | error_0: | ||
164 | return NULL; | ||
165 | } | ||
166 | |||
167 | static void nfs4_shutdown_client(struct nfs_client *clp) | ||
168 | { | ||
169 | #ifdef CONFIG_NFS_V4 | ||
170 | if (__test_and_clear_bit(NFS_CS_RENEWD, &clp->cl_res_state)) | ||
171 | nfs4_kill_renewd(clp); | ||
172 | while (!list_empty(&clp->cl_unused)) { | ||
173 | struct nfs4_state_owner *sp; | ||
174 | |||
175 | sp = list_entry(clp->cl_unused.next, | ||
176 | struct nfs4_state_owner, | ||
177 | so_list); | ||
178 | list_del(&sp->so_list); | ||
179 | kfree(sp); | ||
180 | } | ||
181 | BUG_ON(!list_empty(&clp->cl_state_owners)); | ||
182 | if (__test_and_clear_bit(NFS_CS_IDMAP, &clp->cl_res_state)) | ||
183 | nfs_idmap_delete(clp); | ||
184 | #endif | ||
185 | } | ||
186 | |||
187 | /* | ||
188 | * Destroy a shared client record | ||
189 | */ | ||
190 | static void nfs_free_client(struct nfs_client *clp) | ||
191 | { | ||
192 | dprintk("--> nfs_free_client(%d)\n", clp->cl_nfsversion); | ||
193 | |||
194 | nfs4_shutdown_client(clp); | ||
195 | |||
196 | /* -EIO all pending I/O */ | ||
197 | if (!IS_ERR(clp->cl_rpcclient)) | ||
198 | rpc_shutdown_client(clp->cl_rpcclient); | ||
199 | |||
200 | if (__test_and_clear_bit(NFS_CS_CALLBACK, &clp->cl_res_state)) | ||
201 | nfs_callback_down(); | ||
202 | |||
203 | if (__test_and_clear_bit(NFS_CS_RPCIOD, &clp->cl_res_state)) | ||
204 | rpciod_down(); | ||
205 | |||
206 | kfree(clp->cl_hostname); | ||
207 | kfree(clp); | ||
208 | |||
209 | dprintk("<-- nfs_free_client()\n"); | ||
210 | } | ||
211 | |||
212 | /* | ||
213 | * Release a reference to a shared client record | ||
214 | */ | ||
215 | void nfs_put_client(struct nfs_client *clp) | ||
216 | { | ||
217 | if (!clp) | ||
218 | return; | ||
219 | |||
220 | dprintk("--> nfs_put_client({%d})\n", atomic_read(&clp->cl_count)); | ||
221 | |||
222 | if (atomic_dec_and_lock(&clp->cl_count, &nfs_client_lock)) { | ||
223 | list_del(&clp->cl_share_link); | ||
224 | spin_unlock(&nfs_client_lock); | ||
225 | |||
226 | BUG_ON(!list_empty(&clp->cl_superblocks)); | ||
227 | |||
228 | nfs_free_client(clp); | ||
229 | } | ||
230 | } | ||
231 | |||
232 | /* | ||
233 | * Find a client by address | ||
234 | * - caller must hold nfs_client_lock | ||
235 | */ | ||
236 | static struct nfs_client *__nfs_find_client(const struct sockaddr_in *addr, int nfsversion) | ||
237 | { | ||
238 | struct nfs_client *clp; | ||
239 | |||
240 | list_for_each_entry(clp, &nfs_client_list, cl_share_link) { | ||
241 | /* Different NFS versions cannot share the same nfs_client */ | ||
242 | if (clp->cl_nfsversion != nfsversion) | ||
243 | continue; | ||
244 | |||
245 | if (memcmp(&clp->cl_addr.sin_addr, &addr->sin_addr, | ||
246 | sizeof(clp->cl_addr.sin_addr)) != 0) | ||
247 | continue; | ||
248 | |||
249 | if (clp->cl_addr.sin_port == addr->sin_port) | ||
250 | goto found; | ||
251 | } | ||
252 | |||
253 | return NULL; | ||
254 | |||
255 | found: | ||
256 | atomic_inc(&clp->cl_count); | ||
257 | return clp; | ||
258 | } | ||
259 | |||
260 | /* | ||
261 | * Find a client by IP address and protocol version | ||
262 | * - returns NULL if no such client | ||
263 | */ | ||
264 | struct nfs_client *nfs_find_client(const struct sockaddr_in *addr, int nfsversion) | ||
265 | { | ||
266 | struct nfs_client *clp; | ||
267 | |||
268 | spin_lock(&nfs_client_lock); | ||
269 | clp = __nfs_find_client(addr, nfsversion); | ||
270 | spin_unlock(&nfs_client_lock); | ||
271 | |||
272 | BUG_ON(clp && clp->cl_cons_state == 0); | ||
273 | |||
274 | return clp; | ||
275 | } | ||
276 | |||
277 | /* | ||
278 | * Look up a client by IP address and protocol version | ||
279 | * - creates a new record if one doesn't yet exist | ||
280 | */ | ||
281 | static struct nfs_client *nfs_get_client(const char *hostname, | ||
282 | const struct sockaddr_in *addr, | ||
283 | int nfsversion) | ||
284 | { | ||
285 | struct nfs_client *clp, *new = NULL; | ||
286 | int error; | ||
287 | |||
288 | dprintk("--> nfs_get_client(%s,"NIPQUAD_FMT":%d,%d)\n", | ||
289 | hostname ?: "", NIPQUAD(addr->sin_addr), | ||
290 | addr->sin_port, nfsversion); | ||
291 | |||
292 | /* see if the client already exists */ | ||
293 | do { | ||
294 | spin_lock(&nfs_client_lock); | ||
295 | |||
296 | clp = __nfs_find_client(addr, nfsversion); | ||
297 | if (clp) | ||
298 | goto found_client; | ||
299 | if (new) | ||
300 | goto install_client; | ||
301 | |||
302 | spin_unlock(&nfs_client_lock); | ||
303 | |||
304 | new = nfs_alloc_client(hostname, addr, nfsversion); | ||
305 | } while (new); | ||
306 | |||
307 | return ERR_PTR(-ENOMEM); | ||
308 | |||
309 | /* install a new client and return with it unready */ | ||
310 | install_client: | ||
311 | clp = new; | ||
312 | list_add(&clp->cl_share_link, &nfs_client_list); | ||
313 | spin_unlock(&nfs_client_lock); | ||
314 | dprintk("--> nfs_get_client() = %p [new]\n", clp); | ||
315 | return clp; | ||
316 | |||
317 | /* found an existing client | ||
318 | * - make sure it's ready before returning | ||
319 | */ | ||
320 | found_client: | ||
321 | spin_unlock(&nfs_client_lock); | ||
322 | |||
323 | if (new) | ||
324 | nfs_free_client(new); | ||
325 | |||
326 | if (clp->cl_cons_state == NFS_CS_INITING) { | ||
327 | DECLARE_WAITQUEUE(myself, current); | ||
328 | |||
329 | add_wait_queue(&nfs_client_active_wq, &myself); | ||
330 | |||
331 | for (;;) { | ||
332 | set_current_state(TASK_INTERRUPTIBLE); | ||
333 | if (signal_pending(current) || | ||
334 | clp->cl_cons_state > NFS_CS_READY) | ||
335 | break; | ||
336 | schedule(); | ||
337 | } | ||
338 | |||
339 | remove_wait_queue(&nfs_client_active_wq, &myself); | ||
340 | |||
341 | if (signal_pending(current)) { | ||
342 | nfs_put_client(clp); | ||
343 | return ERR_PTR(-ERESTARTSYS); | ||
344 | } | ||
345 | } | ||
346 | |||
347 | if (clp->cl_cons_state < NFS_CS_READY) { | ||
348 | error = clp->cl_cons_state; | ||
349 | nfs_put_client(clp); | ||
350 | return ERR_PTR(error); | ||
351 | } | ||
352 | |||
353 | BUG_ON(clp->cl_cons_state != NFS_CS_READY); | ||
354 | |||
355 | dprintk("--> nfs_get_client() = %p [share]\n", clp); | ||
356 | return clp; | ||
357 | } | ||
358 | |||
359 | /* | ||
360 | * Mark a server as ready or failed | ||
361 | */ | ||
362 | static void nfs_mark_client_ready(struct nfs_client *clp, int state) | ||
363 | { | ||
364 | clp->cl_cons_state = state; | ||
365 | wake_up_all(&nfs_client_active_wq); | ||
366 | } | ||
367 | |||
368 | /* | ||
369 | * Initialise the timeout values for a connection | ||
370 | */ | ||
371 | static void nfs_init_timeout_values(struct rpc_timeout *to, int proto, | ||
372 | unsigned int timeo, unsigned int retrans) | ||
373 | { | ||
374 | to->to_initval = timeo * HZ / 10; | ||
375 | to->to_retries = retrans; | ||
376 | if (!to->to_retries) | ||
377 | to->to_retries = 2; | ||
378 | |||
379 | switch (proto) { | ||
380 | case IPPROTO_TCP: | ||
381 | if (!to->to_initval) | ||
382 | to->to_initval = 60 * HZ; | ||
383 | if (to->to_initval > NFS_MAX_TCP_TIMEOUT) | ||
384 | to->to_initval = NFS_MAX_TCP_TIMEOUT; | ||
385 | to->to_increment = to->to_initval; | ||
386 | to->to_maxval = to->to_initval + (to->to_increment * to->to_retries); | ||
387 | to->to_exponential = 0; | ||
388 | break; | ||
389 | case IPPROTO_UDP: | ||
390 | default: | ||
391 | if (!to->to_initval) | ||
392 | to->to_initval = 11 * HZ / 10; | ||
393 | if (to->to_initval > NFS_MAX_UDP_TIMEOUT) | ||
394 | to->to_initval = NFS_MAX_UDP_TIMEOUT; | ||
395 | to->to_maxval = NFS_MAX_UDP_TIMEOUT; | ||
396 | to->to_exponential = 1; | ||
397 | break; | ||
398 | } | ||
399 | } | ||
400 | |||
401 | /* | ||
402 | * Create an RPC client handle | ||
403 | */ | ||
404 | static int nfs_create_rpc_client(struct nfs_client *clp, int proto, | ||
405 | unsigned int timeo, | ||
406 | unsigned int retrans, | ||
407 | rpc_authflavor_t flavor) | ||
408 | { | ||
409 | struct rpc_timeout timeparms; | ||
410 | struct rpc_clnt *clnt = NULL; | ||
411 | struct rpc_create_args args = { | ||
412 | .protocol = proto, | ||
413 | .address = (struct sockaddr *)&clp->cl_addr, | ||
414 | .addrsize = sizeof(clp->cl_addr), | ||
415 | .timeout = &timeparms, | ||
416 | .servername = clp->cl_hostname, | ||
417 | .program = &nfs_program, | ||
418 | .version = clp->rpc_ops->version, | ||
419 | .authflavor = flavor, | ||
420 | }; | ||
421 | |||
422 | if (!IS_ERR(clp->cl_rpcclient)) | ||
423 | return 0; | ||
424 | |||
425 | nfs_init_timeout_values(&timeparms, proto, timeo, retrans); | ||
426 | clp->retrans_timeo = timeparms.to_initval; | ||
427 | clp->retrans_count = timeparms.to_retries; | ||
428 | |||
429 | clnt = rpc_create(&args); | ||
430 | if (IS_ERR(clnt)) { | ||
431 | dprintk("%s: cannot create RPC client. Error = %ld\n", | ||
432 | __FUNCTION__, PTR_ERR(clnt)); | ||
433 | return PTR_ERR(clnt); | ||
434 | } | ||
435 | |||
436 | clp->cl_rpcclient = clnt; | ||
437 | return 0; | ||
438 | } | ||
439 | |||
440 | /* | ||
441 | * Version 2 or 3 client destruction | ||
442 | */ | ||
443 | static void nfs_destroy_server(struct nfs_server *server) | ||
444 | { | ||
445 | if (!IS_ERR(server->client_acl)) | ||
446 | rpc_shutdown_client(server->client_acl); | ||
447 | |||
448 | if (!(server->flags & NFS_MOUNT_NONLM)) | ||
449 | lockd_down(); /* release rpc.lockd */ | ||
450 | } | ||
451 | |||
452 | /* | ||
453 | * Version 2 or 3 lockd setup | ||
454 | */ | ||
455 | static int nfs_start_lockd(struct nfs_server *server) | ||
456 | { | ||
457 | int error = 0; | ||
458 | |||
459 | if (server->nfs_client->cl_nfsversion > 3) | ||
460 | goto out; | ||
461 | if (server->flags & NFS_MOUNT_NONLM) | ||
462 | goto out; | ||
463 | error = lockd_up(); | ||
464 | if (error < 0) | ||
465 | server->flags |= NFS_MOUNT_NONLM; | ||
466 | else | ||
467 | server->destroy = nfs_destroy_server; | ||
468 | out: | ||
469 | return error; | ||
470 | } | ||
471 | |||
472 | /* | ||
473 | * Initialise an NFSv3 ACL client connection | ||
474 | */ | ||
475 | #ifdef CONFIG_NFS_V3_ACL | ||
476 | static void nfs_init_server_aclclient(struct nfs_server *server) | ||
477 | { | ||
478 | if (server->nfs_client->cl_nfsversion != 3) | ||
479 | goto out_noacl; | ||
480 | if (server->flags & NFS_MOUNT_NOACL) | ||
481 | goto out_noacl; | ||
482 | |||
483 | server->client_acl = rpc_bind_new_program(server->client, &nfsacl_program, 3); | ||
484 | if (IS_ERR(server->client_acl)) | ||
485 | goto out_noacl; | ||
486 | |||
487 | /* No errors! Assume that Sun nfsacls are supported */ | ||
488 | server->caps |= NFS_CAP_ACLS; | ||
489 | return; | ||
490 | |||
491 | out_noacl: | ||
492 | server->caps &= ~NFS_CAP_ACLS; | ||
493 | } | ||
494 | #else | ||
495 | static inline void nfs_init_server_aclclient(struct nfs_server *server) | ||
496 | { | ||
497 | server->flags &= ~NFS_MOUNT_NOACL; | ||
498 | server->caps &= ~NFS_CAP_ACLS; | ||
499 | } | ||
500 | #endif | ||
501 | |||
502 | /* | ||
503 | * Create a general RPC client | ||
504 | */ | ||
505 | static int nfs_init_server_rpcclient(struct nfs_server *server, rpc_authflavor_t pseudoflavour) | ||
506 | { | ||
507 | struct nfs_client *clp = server->nfs_client; | ||
508 | |||
509 | server->client = rpc_clone_client(clp->cl_rpcclient); | ||
510 | if (IS_ERR(server->client)) { | ||
511 | dprintk("%s: couldn't create rpc_client!\n", __FUNCTION__); | ||
512 | return PTR_ERR(server->client); | ||
513 | } | ||
514 | |||
515 | if (pseudoflavour != clp->cl_rpcclient->cl_auth->au_flavor) { | ||
516 | struct rpc_auth *auth; | ||
517 | |||
518 | auth = rpcauth_create(pseudoflavour, server->client); | ||
519 | if (IS_ERR(auth)) { | ||
520 | dprintk("%s: couldn't create credcache!\n", __FUNCTION__); | ||
521 | return PTR_ERR(auth); | ||
522 | } | ||
523 | } | ||
524 | server->client->cl_softrtry = 0; | ||
525 | if (server->flags & NFS_MOUNT_SOFT) | ||
526 | server->client->cl_softrtry = 1; | ||
527 | |||
528 | server->client->cl_intr = 0; | ||
529 | if (server->flags & NFS4_MOUNT_INTR) | ||
530 | server->client->cl_intr = 1; | ||
531 | |||
532 | return 0; | ||
533 | } | ||
534 | |||
535 | /* | ||
536 | * Initialise an NFS2 or NFS3 client | ||
537 | */ | ||
538 | static int nfs_init_client(struct nfs_client *clp, const struct nfs_mount_data *data) | ||
539 | { | ||
540 | int proto = (data->flags & NFS_MOUNT_TCP) ? IPPROTO_TCP : IPPROTO_UDP; | ||
541 | int error; | ||
542 | |||
543 | if (clp->cl_cons_state == NFS_CS_READY) { | ||
544 | /* the client is already initialised */ | ||
545 | dprintk("<-- nfs_init_client() = 0 [already %p]\n", clp); | ||
546 | return 0; | ||
547 | } | ||
548 | |||
549 | /* Check NFS protocol revision and initialize RPC op vector */ | ||
550 | clp->rpc_ops = &nfs_v2_clientops; | ||
551 | #ifdef CONFIG_NFS_V3 | ||
552 | if (clp->cl_nfsversion == 3) | ||
553 | clp->rpc_ops = &nfs_v3_clientops; | ||
554 | #endif | ||
555 | /* | ||
556 | * Create a client RPC handle for doing FSSTAT with UNIX auth only | ||
557 | * - RFC 2623, sec 2.3.2 | ||
558 | */ | ||
559 | error = nfs_create_rpc_client(clp, proto, data->timeo, data->retrans, | ||
560 | RPC_AUTH_UNIX); | ||
561 | if (error < 0) | ||
562 | goto error; | ||
563 | nfs_mark_client_ready(clp, NFS_CS_READY); | ||
564 | return 0; | ||
565 | |||
566 | error: | ||
567 | nfs_mark_client_ready(clp, error); | ||
568 | dprintk("<-- nfs_init_client() = xerror %d\n", error); | ||
569 | return error; | ||
570 | } | ||
571 | |||
572 | /* | ||
573 | * Create a version 2 or 3 client | ||
574 | */ | ||
575 | static int nfs_init_server(struct nfs_server *server, const struct nfs_mount_data *data) | ||
576 | { | ||
577 | struct nfs_client *clp; | ||
578 | int error, nfsvers = 2; | ||
579 | |||
580 | dprintk("--> nfs_init_server()\n"); | ||
581 | |||
582 | #ifdef CONFIG_NFS_V3 | ||
583 | if (data->flags & NFS_MOUNT_VER3) | ||
584 | nfsvers = 3; | ||
585 | #endif | ||
586 | |||
587 | /* Allocate or find a client reference we can use */ | ||
588 | clp = nfs_get_client(data->hostname, &data->addr, nfsvers); | ||
589 | if (IS_ERR(clp)) { | ||
590 | dprintk("<-- nfs_init_server() = error %ld\n", PTR_ERR(clp)); | ||
591 | return PTR_ERR(clp); | ||
592 | } | ||
593 | |||
594 | error = nfs_init_client(clp, data); | ||
595 | if (error < 0) | ||
596 | goto error; | ||
597 | |||
598 | server->nfs_client = clp; | ||
599 | |||
600 | /* Initialise the client representation from the mount data */ | ||
601 | server->flags = data->flags & NFS_MOUNT_FLAGMASK; | ||
602 | |||
603 | if (data->rsize) | ||
604 | server->rsize = nfs_block_size(data->rsize, NULL); | ||
605 | if (data->wsize) | ||
606 | server->wsize = nfs_block_size(data->wsize, NULL); | ||
607 | |||
608 | server->acregmin = data->acregmin * HZ; | ||
609 | server->acregmax = data->acregmax * HZ; | ||
610 | server->acdirmin = data->acdirmin * HZ; | ||
611 | server->acdirmax = data->acdirmax * HZ; | ||
612 | |||
613 | /* Start lockd here, before we might error out */ | ||
614 | error = nfs_start_lockd(server); | ||
615 | if (error < 0) | ||
616 | goto error; | ||
617 | |||
618 | error = nfs_init_server_rpcclient(server, data->pseudoflavor); | ||
619 | if (error < 0) | ||
620 | goto error; | ||
621 | |||
622 | server->namelen = data->namlen; | ||
623 | /* Create a client RPC handle for the NFSv3 ACL management interface */ | ||
624 | nfs_init_server_aclclient(server); | ||
625 | if (clp->cl_nfsversion == 3) { | ||
626 | if (server->namelen == 0 || server->namelen > NFS3_MAXNAMLEN) | ||
627 | server->namelen = NFS3_MAXNAMLEN; | ||
628 | server->caps |= NFS_CAP_READDIRPLUS; | ||
629 | } else { | ||
630 | if (server->namelen == 0 || server->namelen > NFS2_MAXNAMLEN) | ||
631 | server->namelen = NFS2_MAXNAMLEN; | ||
632 | } | ||
633 | |||
634 | dprintk("<-- nfs_init_server() = 0 [new %p]\n", clp); | ||
635 | return 0; | ||
636 | |||
637 | error: | ||
638 | server->nfs_client = NULL; | ||
639 | nfs_put_client(clp); | ||
640 | dprintk("<-- nfs_init_server() = xerror %d\n", error); | ||
641 | return error; | ||
642 | } | ||
643 | |||
644 | /* | ||
645 | * Load up the server record from information gained in an fsinfo record | ||
646 | */ | ||
647 | static void nfs_server_set_fsinfo(struct nfs_server *server, struct nfs_fsinfo *fsinfo) | ||
648 | { | ||
649 | unsigned long max_rpc_payload; | ||
650 | |||
651 | /* Work out a lot of parameters */ | ||
652 | if (server->rsize == 0) | ||
653 | server->rsize = nfs_block_size(fsinfo->rtpref, NULL); | ||
654 | if (server->wsize == 0) | ||
655 | server->wsize = nfs_block_size(fsinfo->wtpref, NULL); | ||
656 | |||
657 | if (fsinfo->rtmax >= 512 && server->rsize > fsinfo->rtmax) | ||
658 | server->rsize = nfs_block_size(fsinfo->rtmax, NULL); | ||
659 | if (fsinfo->wtmax >= 512 && server->wsize > fsinfo->wtmax) | ||
660 | server->wsize = nfs_block_size(fsinfo->wtmax, NULL); | ||
661 | |||
662 | max_rpc_payload = nfs_block_size(rpc_max_payload(server->client), NULL); | ||
663 | if (server->rsize > max_rpc_payload) | ||
664 | server->rsize = max_rpc_payload; | ||
665 | if (server->rsize > NFS_MAX_FILE_IO_SIZE) | ||
666 | server->rsize = NFS_MAX_FILE_IO_SIZE; | ||
667 | server->rpages = (server->rsize + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT; | ||
668 | server->backing_dev_info.ra_pages = server->rpages * NFS_MAX_READAHEAD; | ||
669 | |||
670 | if (server->wsize > max_rpc_payload) | ||
671 | server->wsize = max_rpc_payload; | ||
672 | if (server->wsize > NFS_MAX_FILE_IO_SIZE) | ||
673 | server->wsize = NFS_MAX_FILE_IO_SIZE; | ||
674 | server->wpages = (server->wsize + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT; | ||
675 | server->wtmult = nfs_block_bits(fsinfo->wtmult, NULL); | ||
676 | |||
677 | server->dtsize = nfs_block_size(fsinfo->dtpref, NULL); | ||
678 | if (server->dtsize > PAGE_CACHE_SIZE) | ||
679 | server->dtsize = PAGE_CACHE_SIZE; | ||
680 | if (server->dtsize > server->rsize) | ||
681 | server->dtsize = server->rsize; | ||
682 | |||
683 | if (server->flags & NFS_MOUNT_NOAC) { | ||
684 | server->acregmin = server->acregmax = 0; | ||
685 | server->acdirmin = server->acdirmax = 0; | ||
686 | } | ||
687 | |||
688 | server->maxfilesize = fsinfo->maxfilesize; | ||
689 | |||
690 | /* We're airborne Set socket buffersize */ | ||
691 | rpc_setbufsize(server->client, server->wsize + 100, server->rsize + 100); | ||
692 | } | ||
693 | |||
694 | /* | ||
695 | * Probe filesystem information, including the FSID on v2/v3 | ||
696 | */ | ||
697 | static int nfs_probe_fsinfo(struct nfs_server *server, struct nfs_fh *mntfh, struct nfs_fattr *fattr) | ||
698 | { | ||
699 | struct nfs_fsinfo fsinfo; | ||
700 | struct nfs_client *clp = server->nfs_client; | ||
701 | int error; | ||
702 | |||
703 | dprintk("--> nfs_probe_fsinfo()\n"); | ||
704 | |||
705 | if (clp->rpc_ops->set_capabilities != NULL) { | ||
706 | error = clp->rpc_ops->set_capabilities(server, mntfh); | ||
707 | if (error < 0) | ||
708 | goto out_error; | ||
709 | } | ||
710 | |||
711 | fsinfo.fattr = fattr; | ||
712 | nfs_fattr_init(fattr); | ||
713 | error = clp->rpc_ops->fsinfo(server, mntfh, &fsinfo); | ||
714 | if (error < 0) | ||
715 | goto out_error; | ||
716 | |||
717 | nfs_server_set_fsinfo(server, &fsinfo); | ||
718 | |||
719 | /* Get some general file system info */ | ||
720 | if (server->namelen == 0) { | ||
721 | struct nfs_pathconf pathinfo; | ||
722 | |||
723 | pathinfo.fattr = fattr; | ||
724 | nfs_fattr_init(fattr); | ||
725 | |||
726 | if (clp->rpc_ops->pathconf(server, mntfh, &pathinfo) >= 0) | ||
727 | server->namelen = pathinfo.max_namelen; | ||
728 | } | ||
729 | |||
730 | dprintk("<-- nfs_probe_fsinfo() = 0\n"); | ||
731 | return 0; | ||
732 | |||
733 | out_error: | ||
734 | dprintk("nfs_probe_fsinfo: error = %d\n", -error); | ||
735 | return error; | ||
736 | } | ||
737 | |||
738 | /* | ||
739 | * Copy useful information when duplicating a server record | ||
740 | */ | ||
741 | static void nfs_server_copy_userdata(struct nfs_server *target, struct nfs_server *source) | ||
742 | { | ||
743 | target->flags = source->flags; | ||
744 | target->acregmin = source->acregmin; | ||
745 | target->acregmax = source->acregmax; | ||
746 | target->acdirmin = source->acdirmin; | ||
747 | target->acdirmax = source->acdirmax; | ||
748 | target->caps = source->caps; | ||
749 | } | ||
750 | |||
751 | /* | ||
752 | * Allocate and initialise a server record | ||
753 | */ | ||
754 | static struct nfs_server *nfs_alloc_server(void) | ||
755 | { | ||
756 | struct nfs_server *server; | ||
757 | |||
758 | server = kzalloc(sizeof(struct nfs_server), GFP_KERNEL); | ||
759 | if (!server) | ||
760 | return NULL; | ||
761 | |||
762 | server->client = server->client_acl = ERR_PTR(-EINVAL); | ||
763 | |||
764 | /* Zero out the NFS state stuff */ | ||
765 | INIT_LIST_HEAD(&server->client_link); | ||
766 | INIT_LIST_HEAD(&server->master_link); | ||
767 | |||
768 | server->io_stats = nfs_alloc_iostats(); | ||
769 | if (!server->io_stats) { | ||
770 | kfree(server); | ||
771 | return NULL; | ||
772 | } | ||
773 | |||
774 | return server; | ||
775 | } | ||
776 | |||
777 | /* | ||
778 | * Free up a server record | ||
779 | */ | ||
780 | void nfs_free_server(struct nfs_server *server) | ||
781 | { | ||
782 | dprintk("--> nfs_free_server()\n"); | ||
783 | |||
784 | spin_lock(&nfs_client_lock); | ||
785 | list_del(&server->client_link); | ||
786 | list_del(&server->master_link); | ||
787 | spin_unlock(&nfs_client_lock); | ||
788 | |||
789 | if (server->destroy != NULL) | ||
790 | server->destroy(server); | ||
791 | if (!IS_ERR(server->client)) | ||
792 | rpc_shutdown_client(server->client); | ||
793 | |||
794 | nfs_put_client(server->nfs_client); | ||
795 | |||
796 | nfs_free_iostats(server->io_stats); | ||
797 | kfree(server); | ||
798 | nfs_release_automount_timer(); | ||
799 | dprintk("<-- nfs_free_server()\n"); | ||
800 | } | ||
801 | |||
802 | /* | ||
803 | * Create a version 2 or 3 volume record | ||
804 | * - keyed on server and FSID | ||
805 | */ | ||
806 | struct nfs_server *nfs_create_server(const struct nfs_mount_data *data, | ||
807 | struct nfs_fh *mntfh) | ||
808 | { | ||
809 | struct nfs_server *server; | ||
810 | struct nfs_fattr fattr; | ||
811 | int error; | ||
812 | |||
813 | server = nfs_alloc_server(); | ||
814 | if (!server) | ||
815 | return ERR_PTR(-ENOMEM); | ||
816 | |||
817 | /* Get a client representation */ | ||
818 | error = nfs_init_server(server, data); | ||
819 | if (error < 0) | ||
820 | goto error; | ||
821 | |||
822 | BUG_ON(!server->nfs_client); | ||
823 | BUG_ON(!server->nfs_client->rpc_ops); | ||
824 | BUG_ON(!server->nfs_client->rpc_ops->file_inode_ops); | ||
825 | |||
826 | /* Probe the root fh to retrieve its FSID */ | ||
827 | error = nfs_probe_fsinfo(server, mntfh, &fattr); | ||
828 | if (error < 0) | ||
829 | goto error; | ||
830 | if (!(fattr.valid & NFS_ATTR_FATTR)) { | ||
831 | error = server->nfs_client->rpc_ops->getattr(server, mntfh, &fattr); | ||
832 | if (error < 0) { | ||
833 | dprintk("nfs_create_server: getattr error = %d\n", -error); | ||
834 | goto error; | ||
835 | } | ||
836 | } | ||
837 | memcpy(&server->fsid, &fattr.fsid, sizeof(server->fsid)); | ||
838 | |||
839 | dprintk("Server FSID: %llx:%llx\n", | ||
840 | (unsigned long long) server->fsid.major, | ||
841 | (unsigned long long) server->fsid.minor); | ||
842 | |||
843 | BUG_ON(!server->nfs_client); | ||
844 | BUG_ON(!server->nfs_client->rpc_ops); | ||
845 | BUG_ON(!server->nfs_client->rpc_ops->file_inode_ops); | ||
846 | |||
847 | spin_lock(&nfs_client_lock); | ||
848 | list_add_tail(&server->client_link, &server->nfs_client->cl_superblocks); | ||
849 | list_add_tail(&server->master_link, &nfs_volume_list); | ||
850 | spin_unlock(&nfs_client_lock); | ||
851 | |||
852 | server->mount_time = jiffies; | ||
853 | return server; | ||
854 | |||
855 | error: | ||
856 | nfs_free_server(server); | ||
857 | return ERR_PTR(error); | ||
858 | } | ||
859 | |||
860 | #ifdef CONFIG_NFS_V4 | ||
861 | /* | ||
862 | * Initialise an NFS4 client record | ||
863 | */ | ||
864 | static int nfs4_init_client(struct nfs_client *clp, | ||
865 | int proto, int timeo, int retrans, | ||
866 | rpc_authflavor_t authflavour) | ||
867 | { | ||
868 | int error; | ||
869 | |||
870 | if (clp->cl_cons_state == NFS_CS_READY) { | ||
871 | /* the client is initialised already */ | ||
872 | dprintk("<-- nfs4_init_client() = 0 [already %p]\n", clp); | ||
873 | return 0; | ||
874 | } | ||
875 | |||
876 | /* Check NFS protocol revision and initialize RPC op vector */ | ||
877 | clp->rpc_ops = &nfs_v4_clientops; | ||
878 | |||
879 | error = nfs_create_rpc_client(clp, proto, timeo, retrans, authflavour); | ||
880 | if (error < 0) | ||
881 | goto error; | ||
882 | |||
883 | error = nfs_idmap_new(clp); | ||
884 | if (error < 0) { | ||
885 | dprintk("%s: failed to create idmapper. Error = %d\n", | ||
886 | __FUNCTION__, error); | ||
887 | goto error; | ||
888 | } | ||
889 | __set_bit(NFS_CS_IDMAP, &clp->cl_res_state); | ||
890 | |||
891 | nfs_mark_client_ready(clp, NFS_CS_READY); | ||
892 | return 0; | ||
893 | |||
894 | error: | ||
895 | nfs_mark_client_ready(clp, error); | ||
896 | dprintk("<-- nfs4_init_client() = xerror %d\n", error); | ||
897 | return error; | ||
898 | } | ||
899 | |||
900 | /* | ||
901 | * Set up an NFS4 client | ||
902 | */ | ||
903 | static int nfs4_set_client(struct nfs_server *server, | ||
904 | const char *hostname, const struct sockaddr_in *addr, | ||
905 | rpc_authflavor_t authflavour, | ||
906 | int proto, int timeo, int retrans) | ||
907 | { | ||
908 | struct nfs_client *clp; | ||
909 | int error; | ||
910 | |||
911 | dprintk("--> nfs4_set_client()\n"); | ||
912 | |||
913 | /* Allocate or find a client reference we can use */ | ||
914 | clp = nfs_get_client(hostname, addr, 4); | ||
915 | if (IS_ERR(clp)) { | ||
916 | error = PTR_ERR(clp); | ||
917 | goto error; | ||
918 | } | ||
919 | error = nfs4_init_client(clp, proto, timeo, retrans, authflavour); | ||
920 | if (error < 0) | ||
921 | goto error_put; | ||
922 | |||
923 | server->nfs_client = clp; | ||
924 | dprintk("<-- nfs4_set_client() = 0 [new %p]\n", clp); | ||
925 | return 0; | ||
926 | |||
927 | error_put: | ||
928 | nfs_put_client(clp); | ||
929 | error: | ||
930 | dprintk("<-- nfs4_set_client() = xerror %d\n", error); | ||
931 | return error; | ||
932 | } | ||
933 | |||
934 | /* | ||
935 | * Create a version 4 volume record | ||
936 | */ | ||
937 | static int nfs4_init_server(struct nfs_server *server, | ||
938 | const struct nfs4_mount_data *data, rpc_authflavor_t authflavour) | ||
939 | { | ||
940 | int error; | ||
941 | |||
942 | dprintk("--> nfs4_init_server()\n"); | ||
943 | |||
944 | /* Initialise the client representation from the mount data */ | ||
945 | server->flags = data->flags & NFS_MOUNT_FLAGMASK; | ||
946 | server->caps |= NFS_CAP_ATOMIC_OPEN; | ||
947 | |||
948 | if (data->rsize) | ||
949 | server->rsize = nfs_block_size(data->rsize, NULL); | ||
950 | if (data->wsize) | ||
951 | server->wsize = nfs_block_size(data->wsize, NULL); | ||
952 | |||
953 | server->acregmin = data->acregmin * HZ; | ||
954 | server->acregmax = data->acregmax * HZ; | ||
955 | server->acdirmin = data->acdirmin * HZ; | ||
956 | server->acdirmax = data->acdirmax * HZ; | ||
957 | |||
958 | error = nfs_init_server_rpcclient(server, authflavour); | ||
959 | |||
960 | /* Done */ | ||
961 | dprintk("<-- nfs4_init_server() = %d\n", error); | ||
962 | return error; | ||
963 | } | ||
964 | |||
965 | /* | ||
966 | * Create a version 4 volume record | ||
967 | * - keyed on server and FSID | ||
968 | */ | ||
969 | struct nfs_server *nfs4_create_server(const struct nfs4_mount_data *data, | ||
970 | const char *hostname, | ||
971 | const struct sockaddr_in *addr, | ||
972 | const char *mntpath, | ||
973 | const char *ip_addr, | ||
974 | rpc_authflavor_t authflavour, | ||
975 | struct nfs_fh *mntfh) | ||
976 | { | ||
977 | struct nfs_fattr fattr; | ||
978 | struct nfs_server *server; | ||
979 | int error; | ||
980 | |||
981 | dprintk("--> nfs4_create_server()\n"); | ||
982 | |||
983 | server = nfs_alloc_server(); | ||
984 | if (!server) | ||
985 | return ERR_PTR(-ENOMEM); | ||
986 | |||
987 | /* Get a client record */ | ||
988 | error = nfs4_set_client(server, hostname, addr, authflavour, | ||
989 | data->proto, data->timeo, data->retrans); | ||
990 | if (error < 0) | ||
991 | goto error; | ||
992 | |||
993 | /* set up the general RPC client */ | ||
994 | error = nfs4_init_server(server, data, authflavour); | ||
995 | if (error < 0) | ||
996 | goto error; | ||
997 | |||
998 | BUG_ON(!server->nfs_client); | ||
999 | BUG_ON(!server->nfs_client->rpc_ops); | ||
1000 | BUG_ON(!server->nfs_client->rpc_ops->file_inode_ops); | ||
1001 | |||
1002 | /* Probe the root fh to retrieve its FSID */ | ||
1003 | error = nfs4_path_walk(server, mntfh, mntpath); | ||
1004 | if (error < 0) | ||
1005 | goto error; | ||
1006 | |||
1007 | dprintk("Server FSID: %llx:%llx\n", | ||
1008 | (unsigned long long) server->fsid.major, | ||
1009 | (unsigned long long) server->fsid.minor); | ||
1010 | dprintk("Mount FH: %d\n", mntfh->size); | ||
1011 | |||
1012 | error = nfs_probe_fsinfo(server, mntfh, &fattr); | ||
1013 | if (error < 0) | ||
1014 | goto error; | ||
1015 | |||
1016 | BUG_ON(!server->nfs_client); | ||
1017 | BUG_ON(!server->nfs_client->rpc_ops); | ||
1018 | BUG_ON(!server->nfs_client->rpc_ops->file_inode_ops); | ||
1019 | |||
1020 | spin_lock(&nfs_client_lock); | ||
1021 | list_add_tail(&server->client_link, &server->nfs_client->cl_superblocks); | ||
1022 | list_add_tail(&server->master_link, &nfs_volume_list); | ||
1023 | spin_unlock(&nfs_client_lock); | ||
1024 | |||
1025 | server->mount_time = jiffies; | ||
1026 | dprintk("<-- nfs4_create_server() = %p\n", server); | ||
1027 | return server; | ||
1028 | |||
1029 | error: | ||
1030 | nfs_free_server(server); | ||
1031 | dprintk("<-- nfs4_create_server() = error %d\n", error); | ||
1032 | return ERR_PTR(error); | ||
1033 | } | ||
1034 | |||
1035 | /* | ||
1036 | * Create an NFS4 referral server record | ||
1037 | */ | ||
1038 | struct nfs_server *nfs4_create_referral_server(struct nfs_clone_mount *data, | ||
1039 | struct nfs_fh *fh) | ||
1040 | { | ||
1041 | struct nfs_client *parent_client; | ||
1042 | struct nfs_server *server, *parent_server; | ||
1043 | struct nfs_fattr fattr; | ||
1044 | int error; | ||
1045 | |||
1046 | dprintk("--> nfs4_create_referral_server()\n"); | ||
1047 | |||
1048 | server = nfs_alloc_server(); | ||
1049 | if (!server) | ||
1050 | return ERR_PTR(-ENOMEM); | ||
1051 | |||
1052 | parent_server = NFS_SB(data->sb); | ||
1053 | parent_client = parent_server->nfs_client; | ||
1054 | |||
1055 | /* Get a client representation. | ||
1056 | * Note: NFSv4 always uses TCP, */ | ||
1057 | error = nfs4_set_client(server, data->hostname, data->addr, | ||
1058 | data->authflavor, | ||
1059 | parent_server->client->cl_xprt->prot, | ||
1060 | parent_client->retrans_timeo, | ||
1061 | parent_client->retrans_count); | ||
1062 | if (error < 0) | ||
1063 | goto error; | ||
1064 | |||
1065 | /* Initialise the client representation from the parent server */ | ||
1066 | nfs_server_copy_userdata(server, parent_server); | ||
1067 | server->caps |= NFS_CAP_ATOMIC_OPEN; | ||
1068 | |||
1069 | error = nfs_init_server_rpcclient(server, data->authflavor); | ||
1070 | if (error < 0) | ||
1071 | goto error; | ||
1072 | |||
1073 | BUG_ON(!server->nfs_client); | ||
1074 | BUG_ON(!server->nfs_client->rpc_ops); | ||
1075 | BUG_ON(!server->nfs_client->rpc_ops->file_inode_ops); | ||
1076 | |||
1077 | /* probe the filesystem info for this server filesystem */ | ||
1078 | error = nfs_probe_fsinfo(server, fh, &fattr); | ||
1079 | if (error < 0) | ||
1080 | goto error; | ||
1081 | |||
1082 | dprintk("Referral FSID: %llx:%llx\n", | ||
1083 | (unsigned long long) server->fsid.major, | ||
1084 | (unsigned long long) server->fsid.minor); | ||
1085 | |||
1086 | spin_lock(&nfs_client_lock); | ||
1087 | list_add_tail(&server->client_link, &server->nfs_client->cl_superblocks); | ||
1088 | list_add_tail(&server->master_link, &nfs_volume_list); | ||
1089 | spin_unlock(&nfs_client_lock); | ||
1090 | |||
1091 | server->mount_time = jiffies; | ||
1092 | |||
1093 | dprintk("<-- nfs_create_referral_server() = %p\n", server); | ||
1094 | return server; | ||
1095 | |||
1096 | error: | ||
1097 | nfs_free_server(server); | ||
1098 | dprintk("<-- nfs4_create_referral_server() = error %d\n", error); | ||
1099 | return ERR_PTR(error); | ||
1100 | } | ||
1101 | |||
1102 | #endif /* CONFIG_NFS_V4 */ | ||
1103 | |||
1104 | /* | ||
1105 | * Clone an NFS2, NFS3 or NFS4 server record | ||
1106 | */ | ||
1107 | struct nfs_server *nfs_clone_server(struct nfs_server *source, | ||
1108 | struct nfs_fh *fh, | ||
1109 | struct nfs_fattr *fattr) | ||
1110 | { | ||
1111 | struct nfs_server *server; | ||
1112 | struct nfs_fattr fattr_fsinfo; | ||
1113 | int error; | ||
1114 | |||
1115 | dprintk("--> nfs_clone_server(,%llx:%llx,)\n", | ||
1116 | (unsigned long long) fattr->fsid.major, | ||
1117 | (unsigned long long) fattr->fsid.minor); | ||
1118 | |||
1119 | server = nfs_alloc_server(); | ||
1120 | if (!server) | ||
1121 | return ERR_PTR(-ENOMEM); | ||
1122 | |||
1123 | /* Copy data from the source */ | ||
1124 | server->nfs_client = source->nfs_client; | ||
1125 | atomic_inc(&server->nfs_client->cl_count); | ||
1126 | nfs_server_copy_userdata(server, source); | ||
1127 | |||
1128 | server->fsid = fattr->fsid; | ||
1129 | |||
1130 | error = nfs_init_server_rpcclient(server, source->client->cl_auth->au_flavor); | ||
1131 | if (error < 0) | ||
1132 | goto out_free_server; | ||
1133 | if (!IS_ERR(source->client_acl)) | ||
1134 | nfs_init_server_aclclient(server); | ||
1135 | |||
1136 | /* probe the filesystem info for this server filesystem */ | ||
1137 | error = nfs_probe_fsinfo(server, fh, &fattr_fsinfo); | ||
1138 | if (error < 0) | ||
1139 | goto out_free_server; | ||
1140 | |||
1141 | dprintk("Cloned FSID: %llx:%llx\n", | ||
1142 | (unsigned long long) server->fsid.major, | ||
1143 | (unsigned long long) server->fsid.minor); | ||
1144 | |||
1145 | error = nfs_start_lockd(server); | ||
1146 | if (error < 0) | ||
1147 | goto out_free_server; | ||
1148 | |||
1149 | spin_lock(&nfs_client_lock); | ||
1150 | list_add_tail(&server->client_link, &server->nfs_client->cl_superblocks); | ||
1151 | list_add_tail(&server->master_link, &nfs_volume_list); | ||
1152 | spin_unlock(&nfs_client_lock); | ||
1153 | |||
1154 | server->mount_time = jiffies; | ||
1155 | |||
1156 | dprintk("<-- nfs_clone_server() = %p\n", server); | ||
1157 | return server; | ||
1158 | |||
1159 | out_free_server: | ||
1160 | nfs_free_server(server); | ||
1161 | dprintk("<-- nfs_clone_server() = error %d\n", error); | ||
1162 | return ERR_PTR(error); | ||
1163 | } | ||
1164 | |||
1165 | #ifdef CONFIG_PROC_FS | ||
1166 | static struct proc_dir_entry *proc_fs_nfs; | ||
1167 | |||
1168 | static int nfs_server_list_open(struct inode *inode, struct file *file); | ||
1169 | static void *nfs_server_list_start(struct seq_file *p, loff_t *pos); | ||
1170 | static void *nfs_server_list_next(struct seq_file *p, void *v, loff_t *pos); | ||
1171 | static void nfs_server_list_stop(struct seq_file *p, void *v); | ||
1172 | static int nfs_server_list_show(struct seq_file *m, void *v); | ||
1173 | |||
1174 | static struct seq_operations nfs_server_list_ops = { | ||
1175 | .start = nfs_server_list_start, | ||
1176 | .next = nfs_server_list_next, | ||
1177 | .stop = nfs_server_list_stop, | ||
1178 | .show = nfs_server_list_show, | ||
1179 | }; | ||
1180 | |||
1181 | static struct file_operations nfs_server_list_fops = { | ||
1182 | .open = nfs_server_list_open, | ||
1183 | .read = seq_read, | ||
1184 | .llseek = seq_lseek, | ||
1185 | .release = seq_release, | ||
1186 | }; | ||
1187 | |||
1188 | static int nfs_volume_list_open(struct inode *inode, struct file *file); | ||
1189 | static void *nfs_volume_list_start(struct seq_file *p, loff_t *pos); | ||
1190 | static void *nfs_volume_list_next(struct seq_file *p, void *v, loff_t *pos); | ||
1191 | static void nfs_volume_list_stop(struct seq_file *p, void *v); | ||
1192 | static int nfs_volume_list_show(struct seq_file *m, void *v); | ||
1193 | |||
1194 | static struct seq_operations nfs_volume_list_ops = { | ||
1195 | .start = nfs_volume_list_start, | ||
1196 | .next = nfs_volume_list_next, | ||
1197 | .stop = nfs_volume_list_stop, | ||
1198 | .show = nfs_volume_list_show, | ||
1199 | }; | ||
1200 | |||
1201 | static struct file_operations nfs_volume_list_fops = { | ||
1202 | .open = nfs_volume_list_open, | ||
1203 | .read = seq_read, | ||
1204 | .llseek = seq_lseek, | ||
1205 | .release = seq_release, | ||
1206 | }; | ||
1207 | |||
1208 | /* | ||
1209 | * open "/proc/fs/nfsfs/servers" which provides a summary of servers with which | ||
1210 | * we're dealing | ||
1211 | */ | ||
1212 | static int nfs_server_list_open(struct inode *inode, struct file *file) | ||
1213 | { | ||
1214 | struct seq_file *m; | ||
1215 | int ret; | ||
1216 | |||
1217 | ret = seq_open(file, &nfs_server_list_ops); | ||
1218 | if (ret < 0) | ||
1219 | return ret; | ||
1220 | |||
1221 | m = file->private_data; | ||
1222 | m->private = PDE(inode)->data; | ||
1223 | |||
1224 | return 0; | ||
1225 | } | ||
1226 | |||
1227 | /* | ||
1228 | * set up the iterator to start reading from the server list and return the first item | ||
1229 | */ | ||
1230 | static void *nfs_server_list_start(struct seq_file *m, loff_t *_pos) | ||
1231 | { | ||
1232 | struct list_head *_p; | ||
1233 | loff_t pos = *_pos; | ||
1234 | |||
1235 | /* lock the list against modification */ | ||
1236 | spin_lock(&nfs_client_lock); | ||
1237 | |||
1238 | /* allow for the header line */ | ||
1239 | if (!pos) | ||
1240 | return SEQ_START_TOKEN; | ||
1241 | pos--; | ||
1242 | |||
1243 | /* find the n'th element in the list */ | ||
1244 | list_for_each(_p, &nfs_client_list) | ||
1245 | if (!pos--) | ||
1246 | break; | ||
1247 | |||
1248 | return _p != &nfs_client_list ? _p : NULL; | ||
1249 | } | ||
1250 | |||
1251 | /* | ||
1252 | * move to next server | ||
1253 | */ | ||
1254 | static void *nfs_server_list_next(struct seq_file *p, void *v, loff_t *pos) | ||
1255 | { | ||
1256 | struct list_head *_p; | ||
1257 | |||
1258 | (*pos)++; | ||
1259 | |||
1260 | _p = v; | ||
1261 | _p = (v == SEQ_START_TOKEN) ? nfs_client_list.next : _p->next; | ||
1262 | |||
1263 | return _p != &nfs_client_list ? _p : NULL; | ||
1264 | } | ||
1265 | |||
1266 | /* | ||
1267 | * clean up after reading from the transports list | ||
1268 | */ | ||
1269 | static void nfs_server_list_stop(struct seq_file *p, void *v) | ||
1270 | { | ||
1271 | spin_unlock(&nfs_client_lock); | ||
1272 | } | ||
1273 | |||
1274 | /* | ||
1275 | * display a header line followed by a load of call lines | ||
1276 | */ | ||
1277 | static int nfs_server_list_show(struct seq_file *m, void *v) | ||
1278 | { | ||
1279 | struct nfs_client *clp; | ||
1280 | |||
1281 | /* display header on line 1 */ | ||
1282 | if (v == SEQ_START_TOKEN) { | ||
1283 | seq_puts(m, "NV SERVER PORT USE HOSTNAME\n"); | ||
1284 | return 0; | ||
1285 | } | ||
1286 | |||
1287 | /* display one transport per line on subsequent lines */ | ||
1288 | clp = list_entry(v, struct nfs_client, cl_share_link); | ||
1289 | |||
1290 | seq_printf(m, "v%d %02x%02x%02x%02x %4hx %3d %s\n", | ||
1291 | clp->cl_nfsversion, | ||
1292 | NIPQUAD(clp->cl_addr.sin_addr), | ||
1293 | ntohs(clp->cl_addr.sin_port), | ||
1294 | atomic_read(&clp->cl_count), | ||
1295 | clp->cl_hostname); | ||
1296 | |||
1297 | return 0; | ||
1298 | } | ||
1299 | |||
1300 | /* | ||
1301 | * open "/proc/fs/nfsfs/volumes" which provides a summary of extant volumes | ||
1302 | */ | ||
1303 | static int nfs_volume_list_open(struct inode *inode, struct file *file) | ||
1304 | { | ||
1305 | struct seq_file *m; | ||
1306 | int ret; | ||
1307 | |||
1308 | ret = seq_open(file, &nfs_volume_list_ops); | ||
1309 | if (ret < 0) | ||
1310 | return ret; | ||
1311 | |||
1312 | m = file->private_data; | ||
1313 | m->private = PDE(inode)->data; | ||
1314 | |||
1315 | return 0; | ||
1316 | } | ||
1317 | |||
1318 | /* | ||
1319 | * set up the iterator to start reading from the volume list and return the first item | ||
1320 | */ | ||
1321 | static void *nfs_volume_list_start(struct seq_file *m, loff_t *_pos) | ||
1322 | { | ||
1323 | struct list_head *_p; | ||
1324 | loff_t pos = *_pos; | ||
1325 | |||
1326 | /* lock the list against modification */ | ||
1327 | spin_lock(&nfs_client_lock); | ||
1328 | |||
1329 | /* allow for the header line */ | ||
1330 | if (!pos) | ||
1331 | return SEQ_START_TOKEN; | ||
1332 | pos--; | ||
1333 | |||
1334 | /* find the n'th element in the list */ | ||
1335 | list_for_each(_p, &nfs_volume_list) | ||
1336 | if (!pos--) | ||
1337 | break; | ||
1338 | |||
1339 | return _p != &nfs_volume_list ? _p : NULL; | ||
1340 | } | ||
1341 | |||
1342 | /* | ||
1343 | * move to next volume | ||
1344 | */ | ||
1345 | static void *nfs_volume_list_next(struct seq_file *p, void *v, loff_t *pos) | ||
1346 | { | ||
1347 | struct list_head *_p; | ||
1348 | |||
1349 | (*pos)++; | ||
1350 | |||
1351 | _p = v; | ||
1352 | _p = (v == SEQ_START_TOKEN) ? nfs_volume_list.next : _p->next; | ||
1353 | |||
1354 | return _p != &nfs_volume_list ? _p : NULL; | ||
1355 | } | ||
1356 | |||
1357 | /* | ||
1358 | * clean up after reading from the transports list | ||
1359 | */ | ||
1360 | static void nfs_volume_list_stop(struct seq_file *p, void *v) | ||
1361 | { | ||
1362 | spin_unlock(&nfs_client_lock); | ||
1363 | } | ||
1364 | |||
1365 | /* | ||
1366 | * display a header line followed by a load of call lines | ||
1367 | */ | ||
1368 | static int nfs_volume_list_show(struct seq_file *m, void *v) | ||
1369 | { | ||
1370 | struct nfs_server *server; | ||
1371 | struct nfs_client *clp; | ||
1372 | char dev[8], fsid[17]; | ||
1373 | |||
1374 | /* display header on line 1 */ | ||
1375 | if (v == SEQ_START_TOKEN) { | ||
1376 | seq_puts(m, "NV SERVER PORT DEV FSID\n"); | ||
1377 | return 0; | ||
1378 | } | ||
1379 | /* display one transport per line on subsequent lines */ | ||
1380 | server = list_entry(v, struct nfs_server, master_link); | ||
1381 | clp = server->nfs_client; | ||
1382 | |||
1383 | snprintf(dev, 8, "%u:%u", | ||
1384 | MAJOR(server->s_dev), MINOR(server->s_dev)); | ||
1385 | |||
1386 | snprintf(fsid, 17, "%llx:%llx", | ||
1387 | (unsigned long long) server->fsid.major, | ||
1388 | (unsigned long long) server->fsid.minor); | ||
1389 | |||
1390 | seq_printf(m, "v%d %02x%02x%02x%02x %4hx %-7s %-17s\n", | ||
1391 | clp->cl_nfsversion, | ||
1392 | NIPQUAD(clp->cl_addr.sin_addr), | ||
1393 | ntohs(clp->cl_addr.sin_port), | ||
1394 | dev, | ||
1395 | fsid); | ||
1396 | |||
1397 | return 0; | ||
1398 | } | ||
1399 | |||
1400 | /* | ||
1401 | * initialise the /proc/fs/nfsfs/ directory | ||
1402 | */ | ||
1403 | int __init nfs_fs_proc_init(void) | ||
1404 | { | ||
1405 | struct proc_dir_entry *p; | ||
1406 | |||
1407 | proc_fs_nfs = proc_mkdir("nfsfs", proc_root_fs); | ||
1408 | if (!proc_fs_nfs) | ||
1409 | goto error_0; | ||
1410 | |||
1411 | proc_fs_nfs->owner = THIS_MODULE; | ||
1412 | |||
1413 | /* a file of servers with which we're dealing */ | ||
1414 | p = create_proc_entry("servers", S_IFREG|S_IRUGO, proc_fs_nfs); | ||
1415 | if (!p) | ||
1416 | goto error_1; | ||
1417 | |||
1418 | p->proc_fops = &nfs_server_list_fops; | ||
1419 | p->owner = THIS_MODULE; | ||
1420 | |||
1421 | /* a file of volumes that we have mounted */ | ||
1422 | p = create_proc_entry("volumes", S_IFREG|S_IRUGO, proc_fs_nfs); | ||
1423 | if (!p) | ||
1424 | goto error_2; | ||
1425 | |||
1426 | p->proc_fops = &nfs_volume_list_fops; | ||
1427 | p->owner = THIS_MODULE; | ||
1428 | return 0; | ||
1429 | |||
1430 | error_2: | ||
1431 | remove_proc_entry("servers", proc_fs_nfs); | ||
1432 | error_1: | ||
1433 | remove_proc_entry("nfsfs", proc_root_fs); | ||
1434 | error_0: | ||
1435 | return -ENOMEM; | ||
1436 | } | ||
1437 | |||
1438 | /* | ||
1439 | * clean up the /proc/fs/nfsfs/ directory | ||
1440 | */ | ||
1441 | void nfs_fs_proc_exit(void) | ||
1442 | { | ||
1443 | remove_proc_entry("volumes", proc_fs_nfs); | ||
1444 | remove_proc_entry("servers", proc_fs_nfs); | ||
1445 | remove_proc_entry("nfsfs", proc_root_fs); | ||
1446 | } | ||
1447 | |||
1448 | #endif /* CONFIG_PROC_FS */ | ||
diff --git a/fs/nfs/delegation.c b/fs/nfs/delegation.c index 9540a316c05e..57133678db16 100644 --- a/fs/nfs/delegation.c +++ b/fs/nfs/delegation.c | |||
@@ -18,6 +18,7 @@ | |||
18 | 18 | ||
19 | #include "nfs4_fs.h" | 19 | #include "nfs4_fs.h" |
20 | #include "delegation.h" | 20 | #include "delegation.h" |
21 | #include "internal.h" | ||
21 | 22 | ||
22 | static struct nfs_delegation *nfs_alloc_delegation(void) | 23 | static struct nfs_delegation *nfs_alloc_delegation(void) |
23 | { | 24 | { |
@@ -52,7 +53,7 @@ static int nfs_delegation_claim_locks(struct nfs_open_context *ctx, struct nfs4_ | |||
52 | case -NFS4ERR_EXPIRED: | 53 | case -NFS4ERR_EXPIRED: |
53 | /* kill_proc(fl->fl_pid, SIGLOST, 1); */ | 54 | /* kill_proc(fl->fl_pid, SIGLOST, 1); */ |
54 | case -NFS4ERR_STALE_CLIENTID: | 55 | case -NFS4ERR_STALE_CLIENTID: |
55 | nfs4_schedule_state_recovery(NFS_SERVER(inode)->nfs4_state); | 56 | nfs4_schedule_state_recovery(NFS_SERVER(inode)->nfs_client); |
56 | goto out_err; | 57 | goto out_err; |
57 | } | 58 | } |
58 | } | 59 | } |
@@ -114,7 +115,7 @@ void nfs_inode_reclaim_delegation(struct inode *inode, struct rpc_cred *cred, st | |||
114 | */ | 115 | */ |
115 | int nfs_inode_set_delegation(struct inode *inode, struct rpc_cred *cred, struct nfs_openres *res) | 116 | int nfs_inode_set_delegation(struct inode *inode, struct rpc_cred *cred, struct nfs_openres *res) |
116 | { | 117 | { |
117 | struct nfs4_client *clp = NFS_SERVER(inode)->nfs4_state; | 118 | struct nfs_client *clp = NFS_SERVER(inode)->nfs_client; |
118 | struct nfs_inode *nfsi = NFS_I(inode); | 119 | struct nfs_inode *nfsi = NFS_I(inode); |
119 | struct nfs_delegation *delegation; | 120 | struct nfs_delegation *delegation; |
120 | int status = 0; | 121 | int status = 0; |
@@ -145,7 +146,7 @@ int nfs_inode_set_delegation(struct inode *inode, struct rpc_cred *cred, struct | |||
145 | sizeof(delegation->stateid)) != 0 || | 146 | sizeof(delegation->stateid)) != 0 || |
146 | delegation->type != nfsi->delegation->type) { | 147 | delegation->type != nfsi->delegation->type) { |
147 | printk("%s: server %u.%u.%u.%u, handed out a duplicate delegation!\n", | 148 | printk("%s: server %u.%u.%u.%u, handed out a duplicate delegation!\n", |
148 | __FUNCTION__, NIPQUAD(clp->cl_addr)); | 149 | __FUNCTION__, NIPQUAD(clp->cl_addr.sin_addr)); |
149 | status = -EIO; | 150 | status = -EIO; |
150 | } | 151 | } |
151 | } | 152 | } |
@@ -176,7 +177,7 @@ static void nfs_msync_inode(struct inode *inode) | |||
176 | */ | 177 | */ |
177 | int __nfs_inode_return_delegation(struct inode *inode) | 178 | int __nfs_inode_return_delegation(struct inode *inode) |
178 | { | 179 | { |
179 | struct nfs4_client *clp = NFS_SERVER(inode)->nfs4_state; | 180 | struct nfs_client *clp = NFS_SERVER(inode)->nfs_client; |
180 | struct nfs_inode *nfsi = NFS_I(inode); | 181 | struct nfs_inode *nfsi = NFS_I(inode); |
181 | struct nfs_delegation *delegation; | 182 | struct nfs_delegation *delegation; |
182 | int res = 0; | 183 | int res = 0; |
@@ -208,7 +209,7 @@ int __nfs_inode_return_delegation(struct inode *inode) | |||
208 | */ | 209 | */ |
209 | void nfs_return_all_delegations(struct super_block *sb) | 210 | void nfs_return_all_delegations(struct super_block *sb) |
210 | { | 211 | { |
211 | struct nfs4_client *clp = NFS_SB(sb)->nfs4_state; | 212 | struct nfs_client *clp = NFS_SB(sb)->nfs_client; |
212 | struct nfs_delegation *delegation; | 213 | struct nfs_delegation *delegation; |
213 | struct inode *inode; | 214 | struct inode *inode; |
214 | 215 | ||
@@ -232,7 +233,7 @@ restart: | |||
232 | 233 | ||
233 | int nfs_do_expire_all_delegations(void *ptr) | 234 | int nfs_do_expire_all_delegations(void *ptr) |
234 | { | 235 | { |
235 | struct nfs4_client *clp = ptr; | 236 | struct nfs_client *clp = ptr; |
236 | struct nfs_delegation *delegation; | 237 | struct nfs_delegation *delegation; |
237 | struct inode *inode; | 238 | struct inode *inode; |
238 | 239 | ||
@@ -254,11 +255,11 @@ restart: | |||
254 | } | 255 | } |
255 | out: | 256 | out: |
256 | spin_unlock(&clp->cl_lock); | 257 | spin_unlock(&clp->cl_lock); |
257 | nfs4_put_client(clp); | 258 | nfs_put_client(clp); |
258 | module_put_and_exit(0); | 259 | module_put_and_exit(0); |
259 | } | 260 | } |
260 | 261 | ||
261 | void nfs_expire_all_delegations(struct nfs4_client *clp) | 262 | void nfs_expire_all_delegations(struct nfs_client *clp) |
262 | { | 263 | { |
263 | struct task_struct *task; | 264 | struct task_struct *task; |
264 | 265 | ||
@@ -266,17 +267,17 @@ void nfs_expire_all_delegations(struct nfs4_client *clp) | |||
266 | atomic_inc(&clp->cl_count); | 267 | atomic_inc(&clp->cl_count); |
267 | task = kthread_run(nfs_do_expire_all_delegations, clp, | 268 | task = kthread_run(nfs_do_expire_all_delegations, clp, |
268 | "%u.%u.%u.%u-delegreturn", | 269 | "%u.%u.%u.%u-delegreturn", |
269 | NIPQUAD(clp->cl_addr)); | 270 | NIPQUAD(clp->cl_addr.sin_addr)); |
270 | if (!IS_ERR(task)) | 271 | if (!IS_ERR(task)) |
271 | return; | 272 | return; |
272 | nfs4_put_client(clp); | 273 | nfs_put_client(clp); |
273 | module_put(THIS_MODULE); | 274 | module_put(THIS_MODULE); |
274 | } | 275 | } |
275 | 276 | ||
276 | /* | 277 | /* |
277 | * Return all delegations following an NFS4ERR_CB_PATH_DOWN error. | 278 | * Return all delegations following an NFS4ERR_CB_PATH_DOWN error. |
278 | */ | 279 | */ |
279 | void nfs_handle_cb_pathdown(struct nfs4_client *clp) | 280 | void nfs_handle_cb_pathdown(struct nfs_client *clp) |
280 | { | 281 | { |
281 | struct nfs_delegation *delegation; | 282 | struct nfs_delegation *delegation; |
282 | struct inode *inode; | 283 | struct inode *inode; |
@@ -299,7 +300,7 @@ restart: | |||
299 | 300 | ||
300 | struct recall_threadargs { | 301 | struct recall_threadargs { |
301 | struct inode *inode; | 302 | struct inode *inode; |
302 | struct nfs4_client *clp; | 303 | struct nfs_client *clp; |
303 | const nfs4_stateid *stateid; | 304 | const nfs4_stateid *stateid; |
304 | 305 | ||
305 | struct completion started; | 306 | struct completion started; |
@@ -310,7 +311,7 @@ static int recall_thread(void *data) | |||
310 | { | 311 | { |
311 | struct recall_threadargs *args = (struct recall_threadargs *)data; | 312 | struct recall_threadargs *args = (struct recall_threadargs *)data; |
312 | struct inode *inode = igrab(args->inode); | 313 | struct inode *inode = igrab(args->inode); |
313 | struct nfs4_client *clp = NFS_SERVER(inode)->nfs4_state; | 314 | struct nfs_client *clp = NFS_SERVER(inode)->nfs_client; |
314 | struct nfs_inode *nfsi = NFS_I(inode); | 315 | struct nfs_inode *nfsi = NFS_I(inode); |
315 | struct nfs_delegation *delegation; | 316 | struct nfs_delegation *delegation; |
316 | 317 | ||
@@ -371,7 +372,7 @@ out_module_put: | |||
371 | /* | 372 | /* |
372 | * Retrieve the inode associated with a delegation | 373 | * Retrieve the inode associated with a delegation |
373 | */ | 374 | */ |
374 | struct inode *nfs_delegation_find_inode(struct nfs4_client *clp, const struct nfs_fh *fhandle) | 375 | struct inode *nfs_delegation_find_inode(struct nfs_client *clp, const struct nfs_fh *fhandle) |
375 | { | 376 | { |
376 | struct nfs_delegation *delegation; | 377 | struct nfs_delegation *delegation; |
377 | struct inode *res = NULL; | 378 | struct inode *res = NULL; |
@@ -389,7 +390,7 @@ struct inode *nfs_delegation_find_inode(struct nfs4_client *clp, const struct nf | |||
389 | /* | 390 | /* |
390 | * Mark all delegations as needing to be reclaimed | 391 | * Mark all delegations as needing to be reclaimed |
391 | */ | 392 | */ |
392 | void nfs_delegation_mark_reclaim(struct nfs4_client *clp) | 393 | void nfs_delegation_mark_reclaim(struct nfs_client *clp) |
393 | { | 394 | { |
394 | struct nfs_delegation *delegation; | 395 | struct nfs_delegation *delegation; |
395 | spin_lock(&clp->cl_lock); | 396 | spin_lock(&clp->cl_lock); |
@@ -401,7 +402,7 @@ void nfs_delegation_mark_reclaim(struct nfs4_client *clp) | |||
401 | /* | 402 | /* |
402 | * Reap all unclaimed delegations after reboot recovery is done | 403 | * Reap all unclaimed delegations after reboot recovery is done |
403 | */ | 404 | */ |
404 | void nfs_delegation_reap_unclaimed(struct nfs4_client *clp) | 405 | void nfs_delegation_reap_unclaimed(struct nfs_client *clp) |
405 | { | 406 | { |
406 | struct nfs_delegation *delegation, *n; | 407 | struct nfs_delegation *delegation, *n; |
407 | LIST_HEAD(head); | 408 | LIST_HEAD(head); |
@@ -423,7 +424,7 @@ void nfs_delegation_reap_unclaimed(struct nfs4_client *clp) | |||
423 | 424 | ||
424 | int nfs4_copy_delegation_stateid(nfs4_stateid *dst, struct inode *inode) | 425 | int nfs4_copy_delegation_stateid(nfs4_stateid *dst, struct inode *inode) |
425 | { | 426 | { |
426 | struct nfs4_client *clp = NFS_SERVER(inode)->nfs4_state; | 427 | struct nfs_client *clp = NFS_SERVER(inode)->nfs_client; |
427 | struct nfs_inode *nfsi = NFS_I(inode); | 428 | struct nfs_inode *nfsi = NFS_I(inode); |
428 | struct nfs_delegation *delegation; | 429 | struct nfs_delegation *delegation; |
429 | int res = 0; | 430 | int res = 0; |
diff --git a/fs/nfs/delegation.h b/fs/nfs/delegation.h index 3858694652fa..2cfd4b24c7fe 100644 --- a/fs/nfs/delegation.h +++ b/fs/nfs/delegation.h | |||
@@ -29,13 +29,13 @@ void nfs_inode_reclaim_delegation(struct inode *inode, struct rpc_cred *cred, st | |||
29 | int __nfs_inode_return_delegation(struct inode *inode); | 29 | int __nfs_inode_return_delegation(struct inode *inode); |
30 | int nfs_async_inode_return_delegation(struct inode *inode, const nfs4_stateid *stateid); | 30 | int nfs_async_inode_return_delegation(struct inode *inode, const nfs4_stateid *stateid); |
31 | 31 | ||
32 | struct inode *nfs_delegation_find_inode(struct nfs4_client *clp, const struct nfs_fh *fhandle); | 32 | struct inode *nfs_delegation_find_inode(struct nfs_client *clp, const struct nfs_fh *fhandle); |
33 | void nfs_return_all_delegations(struct super_block *sb); | 33 | void nfs_return_all_delegations(struct super_block *sb); |
34 | void nfs_expire_all_delegations(struct nfs4_client *clp); | 34 | void nfs_expire_all_delegations(struct nfs_client *clp); |
35 | void nfs_handle_cb_pathdown(struct nfs4_client *clp); | 35 | void nfs_handle_cb_pathdown(struct nfs_client *clp); |
36 | 36 | ||
37 | void nfs_delegation_mark_reclaim(struct nfs4_client *clp); | 37 | void nfs_delegation_mark_reclaim(struct nfs_client *clp); |
38 | void nfs_delegation_reap_unclaimed(struct nfs4_client *clp); | 38 | void nfs_delegation_reap_unclaimed(struct nfs_client *clp); |
39 | 39 | ||
40 | /* NFSv4 delegation-related procedures */ | 40 | /* NFSv4 delegation-related procedures */ |
41 | int nfs4_proc_delegreturn(struct inode *inode, struct rpc_cred *cred, const nfs4_stateid *stateid); | 41 | int nfs4_proc_delegreturn(struct inode *inode, struct rpc_cred *cred, const nfs4_stateid *stateid); |
diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c index e7ffb4deb3e5..3419c2da9ba9 100644 --- a/fs/nfs/dir.c +++ b/fs/nfs/dir.c | |||
@@ -30,7 +30,9 @@ | |||
30 | #include <linux/nfs_mount.h> | 30 | #include <linux/nfs_mount.h> |
31 | #include <linux/pagemap.h> | 31 | #include <linux/pagemap.h> |
32 | #include <linux/smp_lock.h> | 32 | #include <linux/smp_lock.h> |
33 | #include <linux/pagevec.h> | ||
33 | #include <linux/namei.h> | 34 | #include <linux/namei.h> |
35 | #include <linux/mount.h> | ||
34 | 36 | ||
35 | #include "nfs4_fs.h" | 37 | #include "nfs4_fs.h" |
36 | #include "delegation.h" | 38 | #include "delegation.h" |
@@ -870,14 +872,14 @@ int nfs_is_exclusive_create(struct inode *dir, struct nameidata *nd) | |||
870 | return (nd->intent.open.flags & O_EXCL) != 0; | 872 | return (nd->intent.open.flags & O_EXCL) != 0; |
871 | } | 873 | } |
872 | 874 | ||
873 | static inline int nfs_reval_fsid(struct inode *dir, | 875 | static inline int nfs_reval_fsid(struct vfsmount *mnt, struct inode *dir, |
874 | struct nfs_fh *fh, struct nfs_fattr *fattr) | 876 | struct nfs_fh *fh, struct nfs_fattr *fattr) |
875 | { | 877 | { |
876 | struct nfs_server *server = NFS_SERVER(dir); | 878 | struct nfs_server *server = NFS_SERVER(dir); |
877 | 879 | ||
878 | if (!nfs_fsid_equal(&server->fsid, &fattr->fsid)) | 880 | if (!nfs_fsid_equal(&server->fsid, &fattr->fsid)) |
879 | /* Revalidate fsid on root dir */ | 881 | /* Revalidate fsid on root dir */ |
880 | return __nfs_revalidate_inode(server, dir->i_sb->s_root->d_inode); | 882 | return __nfs_revalidate_inode(server, mnt->mnt_root->d_inode); |
881 | return 0; | 883 | return 0; |
882 | } | 884 | } |
883 | 885 | ||
@@ -902,9 +904,15 @@ static struct dentry *nfs_lookup(struct inode *dir, struct dentry * dentry, stru | |||
902 | 904 | ||
903 | lock_kernel(); | 905 | lock_kernel(); |
904 | 906 | ||
905 | /* If we're doing an exclusive create, optimize away the lookup */ | 907 | /* |
906 | if (nfs_is_exclusive_create(dir, nd)) | 908 | * If we're doing an exclusive create, optimize away the lookup |
907 | goto no_entry; | 909 | * but don't hash the dentry. |
910 | */ | ||
911 | if (nfs_is_exclusive_create(dir, nd)) { | ||
912 | d_instantiate(dentry, NULL); | ||
913 | res = NULL; | ||
914 | goto out_unlock; | ||
915 | } | ||
908 | 916 | ||
909 | error = NFS_PROTO(dir)->lookup(dir, &dentry->d_name, &fhandle, &fattr); | 917 | error = NFS_PROTO(dir)->lookup(dir, &dentry->d_name, &fhandle, &fattr); |
910 | if (error == -ENOENT) | 918 | if (error == -ENOENT) |
@@ -913,7 +921,7 @@ static struct dentry *nfs_lookup(struct inode *dir, struct dentry * dentry, stru | |||
913 | res = ERR_PTR(error); | 921 | res = ERR_PTR(error); |
914 | goto out_unlock; | 922 | goto out_unlock; |
915 | } | 923 | } |
916 | error = nfs_reval_fsid(dir, &fhandle, &fattr); | 924 | error = nfs_reval_fsid(nd->mnt, dir, &fhandle, &fattr); |
917 | if (error < 0) { | 925 | if (error < 0) { |
918 | res = ERR_PTR(error); | 926 | res = ERR_PTR(error); |
919 | goto out_unlock; | 927 | goto out_unlock; |
@@ -922,8 +930,9 @@ static struct dentry *nfs_lookup(struct inode *dir, struct dentry * dentry, stru | |||
922 | res = (struct dentry *)inode; | 930 | res = (struct dentry *)inode; |
923 | if (IS_ERR(res)) | 931 | if (IS_ERR(res)) |
924 | goto out_unlock; | 932 | goto out_unlock; |
933 | |||
925 | no_entry: | 934 | no_entry: |
926 | res = d_add_unique(dentry, inode); | 935 | res = d_materialise_unique(dentry, inode); |
927 | if (res != NULL) | 936 | if (res != NULL) |
928 | dentry = res; | 937 | dentry = res; |
929 | nfs_renew_times(dentry); | 938 | nfs_renew_times(dentry); |
@@ -1117,11 +1126,13 @@ static struct dentry *nfs_readdir_lookup(nfs_readdir_descriptor_t *desc) | |||
1117 | dput(dentry); | 1126 | dput(dentry); |
1118 | return NULL; | 1127 | return NULL; |
1119 | } | 1128 | } |
1120 | alias = d_add_unique(dentry, inode); | 1129 | |
1130 | alias = d_materialise_unique(dentry, inode); | ||
1121 | if (alias != NULL) { | 1131 | if (alias != NULL) { |
1122 | dput(dentry); | 1132 | dput(dentry); |
1123 | dentry = alias; | 1133 | dentry = alias; |
1124 | } | 1134 | } |
1135 | |||
1125 | nfs_renew_times(dentry); | 1136 | nfs_renew_times(dentry); |
1126 | nfs_set_verifier(dentry, nfs_save_change_attribute(dir)); | 1137 | nfs_set_verifier(dentry, nfs_save_change_attribute(dir)); |
1127 | return dentry; | 1138 | return dentry; |
@@ -1143,23 +1154,22 @@ int nfs_instantiate(struct dentry *dentry, struct nfs_fh *fhandle, | |||
1143 | struct inode *dir = dentry->d_parent->d_inode; | 1154 | struct inode *dir = dentry->d_parent->d_inode; |
1144 | error = NFS_PROTO(dir)->lookup(dir, &dentry->d_name, fhandle, fattr); | 1155 | error = NFS_PROTO(dir)->lookup(dir, &dentry->d_name, fhandle, fattr); |
1145 | if (error) | 1156 | if (error) |
1146 | goto out_err; | 1157 | return error; |
1147 | } | 1158 | } |
1148 | if (!(fattr->valid & NFS_ATTR_FATTR)) { | 1159 | if (!(fattr->valid & NFS_ATTR_FATTR)) { |
1149 | struct nfs_server *server = NFS_SB(dentry->d_sb); | 1160 | struct nfs_server *server = NFS_SB(dentry->d_sb); |
1150 | error = server->rpc_ops->getattr(server, fhandle, fattr); | 1161 | error = server->nfs_client->rpc_ops->getattr(server, fhandle, fattr); |
1151 | if (error < 0) | 1162 | if (error < 0) |
1152 | goto out_err; | 1163 | return error; |
1153 | } | 1164 | } |
1154 | inode = nfs_fhget(dentry->d_sb, fhandle, fattr); | 1165 | inode = nfs_fhget(dentry->d_sb, fhandle, fattr); |
1155 | error = PTR_ERR(inode); | 1166 | error = PTR_ERR(inode); |
1156 | if (IS_ERR(inode)) | 1167 | if (IS_ERR(inode)) |
1157 | goto out_err; | 1168 | return error; |
1158 | d_instantiate(dentry, inode); | 1169 | d_instantiate(dentry, inode); |
1170 | if (d_unhashed(dentry)) | ||
1171 | d_rehash(dentry); | ||
1159 | return 0; | 1172 | return 0; |
1160 | out_err: | ||
1161 | d_drop(dentry); | ||
1162 | return error; | ||
1163 | } | 1173 | } |
1164 | 1174 | ||
1165 | /* | 1175 | /* |
@@ -1440,48 +1450,82 @@ static int nfs_unlink(struct inode *dir, struct dentry *dentry) | |||
1440 | return error; | 1450 | return error; |
1441 | } | 1451 | } |
1442 | 1452 | ||
1443 | static int | 1453 | /* |
1444 | nfs_symlink(struct inode *dir, struct dentry *dentry, const char *symname) | 1454 | * To create a symbolic link, most file systems instantiate a new inode, |
1455 | * add a page to it containing the path, then write it out to the disk | ||
1456 | * using prepare_write/commit_write. | ||
1457 | * | ||
1458 | * Unfortunately the NFS client can't create the in-core inode first | ||
1459 | * because it needs a file handle to create an in-core inode (see | ||
1460 | * fs/nfs/inode.c:nfs_fhget). We only have a file handle *after* the | ||
1461 | * symlink request has completed on the server. | ||
1462 | * | ||
1463 | * So instead we allocate a raw page, copy the symname into it, then do | ||
1464 | * the SYMLINK request with the page as the buffer. If it succeeds, we | ||
1465 | * now have a new file handle and can instantiate an in-core NFS inode | ||
1466 | * and move the raw page into its mapping. | ||
1467 | */ | ||
1468 | static int nfs_symlink(struct inode *dir, struct dentry *dentry, const char *symname) | ||
1445 | { | 1469 | { |
1470 | struct pagevec lru_pvec; | ||
1471 | struct page *page; | ||
1472 | char *kaddr; | ||
1446 | struct iattr attr; | 1473 | struct iattr attr; |
1447 | struct nfs_fattr sym_attr; | 1474 | unsigned int pathlen = strlen(symname); |
1448 | struct nfs_fh sym_fh; | ||
1449 | struct qstr qsymname; | ||
1450 | int error; | 1475 | int error; |
1451 | 1476 | ||
1452 | dfprintk(VFS, "NFS: symlink(%s/%ld, %s, %s)\n", dir->i_sb->s_id, | 1477 | dfprintk(VFS, "NFS: symlink(%s/%ld, %s, %s)\n", dir->i_sb->s_id, |
1453 | dir->i_ino, dentry->d_name.name, symname); | 1478 | dir->i_ino, dentry->d_name.name, symname); |
1454 | 1479 | ||
1455 | #ifdef NFS_PARANOIA | 1480 | if (pathlen > PAGE_SIZE) |
1456 | if (dentry->d_inode) | 1481 | return -ENAMETOOLONG; |
1457 | printk("nfs_proc_symlink: %s/%s not negative!\n", | ||
1458 | dentry->d_parent->d_name.name, dentry->d_name.name); | ||
1459 | #endif | ||
1460 | /* | ||
1461 | * Fill in the sattr for the call. | ||
1462 | * Note: SunOS 4.1.2 crashes if the mode isn't initialized! | ||
1463 | */ | ||
1464 | attr.ia_valid = ATTR_MODE; | ||
1465 | attr.ia_mode = S_IFLNK | S_IRWXUGO; | ||
1466 | 1482 | ||
1467 | qsymname.name = symname; | 1483 | attr.ia_mode = S_IFLNK | S_IRWXUGO; |
1468 | qsymname.len = strlen(symname); | 1484 | attr.ia_valid = ATTR_MODE; |
1469 | 1485 | ||
1470 | lock_kernel(); | 1486 | lock_kernel(); |
1487 | |||
1488 | page = alloc_page(GFP_KERNEL); | ||
1489 | if (!page) { | ||
1490 | unlock_kernel(); | ||
1491 | return -ENOMEM; | ||
1492 | } | ||
1493 | |||
1494 | kaddr = kmap_atomic(page, KM_USER0); | ||
1495 | memcpy(kaddr, symname, pathlen); | ||
1496 | if (pathlen < PAGE_SIZE) | ||
1497 | memset(kaddr + pathlen, 0, PAGE_SIZE - pathlen); | ||
1498 | kunmap_atomic(kaddr, KM_USER0); | ||
1499 | |||
1471 | nfs_begin_data_update(dir); | 1500 | nfs_begin_data_update(dir); |
1472 | error = NFS_PROTO(dir)->symlink(dir, &dentry->d_name, &qsymname, | 1501 | error = NFS_PROTO(dir)->symlink(dir, dentry, page, pathlen, &attr); |
1473 | &attr, &sym_fh, &sym_attr); | ||
1474 | nfs_end_data_update(dir); | 1502 | nfs_end_data_update(dir); |
1475 | if (!error) { | 1503 | if (error != 0) { |
1476 | error = nfs_instantiate(dentry, &sym_fh, &sym_attr); | 1504 | dfprintk(VFS, "NFS: symlink(%s/%ld, %s, %s) error %d\n", |
1477 | } else { | 1505 | dir->i_sb->s_id, dir->i_ino, |
1478 | if (error == -EEXIST) | 1506 | dentry->d_name.name, symname, error); |
1479 | printk("nfs_proc_symlink: %s/%s already exists??\n", | ||
1480 | dentry->d_parent->d_name.name, dentry->d_name.name); | ||
1481 | d_drop(dentry); | 1507 | d_drop(dentry); |
1508 | __free_page(page); | ||
1509 | unlock_kernel(); | ||
1510 | return error; | ||
1482 | } | 1511 | } |
1512 | |||
1513 | /* | ||
1514 | * No big deal if we can't add this page to the page cache here. | ||
1515 | * READLINK will get the missing page from the server if needed. | ||
1516 | */ | ||
1517 | pagevec_init(&lru_pvec, 0); | ||
1518 | if (!add_to_page_cache(page, dentry->d_inode->i_mapping, 0, | ||
1519 | GFP_KERNEL)) { | ||
1520 | if (!pagevec_add(&lru_pvec, page)) | ||
1521 | __pagevec_lru_add(&lru_pvec); | ||
1522 | SetPageUptodate(page); | ||
1523 | unlock_page(page); | ||
1524 | } else | ||
1525 | __free_page(page); | ||
1526 | |||
1483 | unlock_kernel(); | 1527 | unlock_kernel(); |
1484 | return error; | 1528 | return 0; |
1485 | } | 1529 | } |
1486 | 1530 | ||
1487 | static int | 1531 | static int |
@@ -1638,35 +1682,211 @@ out: | |||
1638 | return error; | 1682 | return error; |
1639 | } | 1683 | } |
1640 | 1684 | ||
1685 | static DEFINE_SPINLOCK(nfs_access_lru_lock); | ||
1686 | static LIST_HEAD(nfs_access_lru_list); | ||
1687 | static atomic_long_t nfs_access_nr_entries; | ||
1688 | |||
1689 | static void nfs_access_free_entry(struct nfs_access_entry *entry) | ||
1690 | { | ||
1691 | put_rpccred(entry->cred); | ||
1692 | kfree(entry); | ||
1693 | smp_mb__before_atomic_dec(); | ||
1694 | atomic_long_dec(&nfs_access_nr_entries); | ||
1695 | smp_mb__after_atomic_dec(); | ||
1696 | } | ||
1697 | |||
1698 | int nfs_access_cache_shrinker(int nr_to_scan, gfp_t gfp_mask) | ||
1699 | { | ||
1700 | LIST_HEAD(head); | ||
1701 | struct nfs_inode *nfsi; | ||
1702 | struct nfs_access_entry *cache; | ||
1703 | |||
1704 | spin_lock(&nfs_access_lru_lock); | ||
1705 | restart: | ||
1706 | list_for_each_entry(nfsi, &nfs_access_lru_list, access_cache_inode_lru) { | ||
1707 | struct inode *inode; | ||
1708 | |||
1709 | if (nr_to_scan-- == 0) | ||
1710 | break; | ||
1711 | inode = igrab(&nfsi->vfs_inode); | ||
1712 | if (inode == NULL) | ||
1713 | continue; | ||
1714 | spin_lock(&inode->i_lock); | ||
1715 | if (list_empty(&nfsi->access_cache_entry_lru)) | ||
1716 | goto remove_lru_entry; | ||
1717 | cache = list_entry(nfsi->access_cache_entry_lru.next, | ||
1718 | struct nfs_access_entry, lru); | ||
1719 | list_move(&cache->lru, &head); | ||
1720 | rb_erase(&cache->rb_node, &nfsi->access_cache); | ||
1721 | if (!list_empty(&nfsi->access_cache_entry_lru)) | ||
1722 | list_move_tail(&nfsi->access_cache_inode_lru, | ||
1723 | &nfs_access_lru_list); | ||
1724 | else { | ||
1725 | remove_lru_entry: | ||
1726 | list_del_init(&nfsi->access_cache_inode_lru); | ||
1727 | clear_bit(NFS_INO_ACL_LRU_SET, &nfsi->flags); | ||
1728 | } | ||
1729 | spin_unlock(&inode->i_lock); | ||
1730 | iput(inode); | ||
1731 | goto restart; | ||
1732 | } | ||
1733 | spin_unlock(&nfs_access_lru_lock); | ||
1734 | while (!list_empty(&head)) { | ||
1735 | cache = list_entry(head.next, struct nfs_access_entry, lru); | ||
1736 | list_del(&cache->lru); | ||
1737 | nfs_access_free_entry(cache); | ||
1738 | } | ||
1739 | return (atomic_long_read(&nfs_access_nr_entries) / 100) * sysctl_vfs_cache_pressure; | ||
1740 | } | ||
1741 | |||
1742 | static void __nfs_access_zap_cache(struct inode *inode) | ||
1743 | { | ||
1744 | struct nfs_inode *nfsi = NFS_I(inode); | ||
1745 | struct rb_root *root_node = &nfsi->access_cache; | ||
1746 | struct rb_node *n, *dispose = NULL; | ||
1747 | struct nfs_access_entry *entry; | ||
1748 | |||
1749 | /* Unhook entries from the cache */ | ||
1750 | while ((n = rb_first(root_node)) != NULL) { | ||
1751 | entry = rb_entry(n, struct nfs_access_entry, rb_node); | ||
1752 | rb_erase(n, root_node); | ||
1753 | list_del(&entry->lru); | ||
1754 | n->rb_left = dispose; | ||
1755 | dispose = n; | ||
1756 | } | ||
1757 | nfsi->cache_validity &= ~NFS_INO_INVALID_ACCESS; | ||
1758 | spin_unlock(&inode->i_lock); | ||
1759 | |||
1760 | /* Now kill them all! */ | ||
1761 | while (dispose != NULL) { | ||
1762 | n = dispose; | ||
1763 | dispose = n->rb_left; | ||
1764 | nfs_access_free_entry(rb_entry(n, struct nfs_access_entry, rb_node)); | ||
1765 | } | ||
1766 | } | ||
1767 | |||
1768 | void nfs_access_zap_cache(struct inode *inode) | ||
1769 | { | ||
1770 | /* Remove from global LRU init */ | ||
1771 | if (test_and_clear_bit(NFS_INO_ACL_LRU_SET, &NFS_FLAGS(inode))) { | ||
1772 | spin_lock(&nfs_access_lru_lock); | ||
1773 | list_del_init(&NFS_I(inode)->access_cache_inode_lru); | ||
1774 | spin_unlock(&nfs_access_lru_lock); | ||
1775 | } | ||
1776 | |||
1777 | spin_lock(&inode->i_lock); | ||
1778 | /* This will release the spinlock */ | ||
1779 | __nfs_access_zap_cache(inode); | ||
1780 | } | ||
1781 | |||
1782 | static struct nfs_access_entry *nfs_access_search_rbtree(struct inode *inode, struct rpc_cred *cred) | ||
1783 | { | ||
1784 | struct rb_node *n = NFS_I(inode)->access_cache.rb_node; | ||
1785 | struct nfs_access_entry *entry; | ||
1786 | |||
1787 | while (n != NULL) { | ||
1788 | entry = rb_entry(n, struct nfs_access_entry, rb_node); | ||
1789 | |||
1790 | if (cred < entry->cred) | ||
1791 | n = n->rb_left; | ||
1792 | else if (cred > entry->cred) | ||
1793 | n = n->rb_right; | ||
1794 | else | ||
1795 | return entry; | ||
1796 | } | ||
1797 | return NULL; | ||
1798 | } | ||
1799 | |||
1641 | int nfs_access_get_cached(struct inode *inode, struct rpc_cred *cred, struct nfs_access_entry *res) | 1800 | int nfs_access_get_cached(struct inode *inode, struct rpc_cred *cred, struct nfs_access_entry *res) |
1642 | { | 1801 | { |
1643 | struct nfs_inode *nfsi = NFS_I(inode); | 1802 | struct nfs_inode *nfsi = NFS_I(inode); |
1644 | struct nfs_access_entry *cache = &nfsi->cache_access; | 1803 | struct nfs_access_entry *cache; |
1804 | int err = -ENOENT; | ||
1645 | 1805 | ||
1646 | if (cache->cred != cred | 1806 | spin_lock(&inode->i_lock); |
1647 | || time_after(jiffies, cache->jiffies + NFS_ATTRTIMEO(inode)) | 1807 | if (nfsi->cache_validity & NFS_INO_INVALID_ACCESS) |
1648 | || (nfsi->cache_validity & NFS_INO_INVALID_ACCESS)) | 1808 | goto out_zap; |
1649 | return -ENOENT; | 1809 | cache = nfs_access_search_rbtree(inode, cred); |
1650 | memcpy(res, cache, sizeof(*res)); | 1810 | if (cache == NULL) |
1651 | return 0; | 1811 | goto out; |
1812 | if (time_after(jiffies, cache->jiffies + NFS_ATTRTIMEO(inode))) | ||
1813 | goto out_stale; | ||
1814 | res->jiffies = cache->jiffies; | ||
1815 | res->cred = cache->cred; | ||
1816 | res->mask = cache->mask; | ||
1817 | list_move_tail(&cache->lru, &nfsi->access_cache_entry_lru); | ||
1818 | err = 0; | ||
1819 | out: | ||
1820 | spin_unlock(&inode->i_lock); | ||
1821 | return err; | ||
1822 | out_stale: | ||
1823 | rb_erase(&cache->rb_node, &nfsi->access_cache); | ||
1824 | list_del(&cache->lru); | ||
1825 | spin_unlock(&inode->i_lock); | ||
1826 | nfs_access_free_entry(cache); | ||
1827 | return -ENOENT; | ||
1828 | out_zap: | ||
1829 | /* This will release the spinlock */ | ||
1830 | __nfs_access_zap_cache(inode); | ||
1831 | return -ENOENT; | ||
1652 | } | 1832 | } |
1653 | 1833 | ||
1654 | void nfs_access_add_cache(struct inode *inode, struct nfs_access_entry *set) | 1834 | static void nfs_access_add_rbtree(struct inode *inode, struct nfs_access_entry *set) |
1655 | { | 1835 | { |
1656 | struct nfs_inode *nfsi = NFS_I(inode); | 1836 | struct nfs_inode *nfsi = NFS_I(inode); |
1657 | struct nfs_access_entry *cache = &nfsi->cache_access; | 1837 | struct rb_root *root_node = &nfsi->access_cache; |
1838 | struct rb_node **p = &root_node->rb_node; | ||
1839 | struct rb_node *parent = NULL; | ||
1840 | struct nfs_access_entry *entry; | ||
1658 | 1841 | ||
1659 | if (cache->cred != set->cred) { | ||
1660 | if (cache->cred) | ||
1661 | put_rpccred(cache->cred); | ||
1662 | cache->cred = get_rpccred(set->cred); | ||
1663 | } | ||
1664 | /* FIXME: replace current access_cache BKL reliance with inode->i_lock */ | ||
1665 | spin_lock(&inode->i_lock); | 1842 | spin_lock(&inode->i_lock); |
1666 | nfsi->cache_validity &= ~NFS_INO_INVALID_ACCESS; | 1843 | while (*p != NULL) { |
1844 | parent = *p; | ||
1845 | entry = rb_entry(parent, struct nfs_access_entry, rb_node); | ||
1846 | |||
1847 | if (set->cred < entry->cred) | ||
1848 | p = &parent->rb_left; | ||
1849 | else if (set->cred > entry->cred) | ||
1850 | p = &parent->rb_right; | ||
1851 | else | ||
1852 | goto found; | ||
1853 | } | ||
1854 | rb_link_node(&set->rb_node, parent, p); | ||
1855 | rb_insert_color(&set->rb_node, root_node); | ||
1856 | list_add_tail(&set->lru, &nfsi->access_cache_entry_lru); | ||
1667 | spin_unlock(&inode->i_lock); | 1857 | spin_unlock(&inode->i_lock); |
1858 | return; | ||
1859 | found: | ||
1860 | rb_replace_node(parent, &set->rb_node, root_node); | ||
1861 | list_add_tail(&set->lru, &nfsi->access_cache_entry_lru); | ||
1862 | list_del(&entry->lru); | ||
1863 | spin_unlock(&inode->i_lock); | ||
1864 | nfs_access_free_entry(entry); | ||
1865 | } | ||
1866 | |||
1867 | void nfs_access_add_cache(struct inode *inode, struct nfs_access_entry *set) | ||
1868 | { | ||
1869 | struct nfs_access_entry *cache = kmalloc(sizeof(*cache), GFP_KERNEL); | ||
1870 | if (cache == NULL) | ||
1871 | return; | ||
1872 | RB_CLEAR_NODE(&cache->rb_node); | ||
1668 | cache->jiffies = set->jiffies; | 1873 | cache->jiffies = set->jiffies; |
1874 | cache->cred = get_rpccred(set->cred); | ||
1669 | cache->mask = set->mask; | 1875 | cache->mask = set->mask; |
1876 | |||
1877 | nfs_access_add_rbtree(inode, cache); | ||
1878 | |||
1879 | /* Update accounting */ | ||
1880 | smp_mb__before_atomic_inc(); | ||
1881 | atomic_long_inc(&nfs_access_nr_entries); | ||
1882 | smp_mb__after_atomic_inc(); | ||
1883 | |||
1884 | /* Add inode to global LRU list */ | ||
1885 | if (!test_and_set_bit(NFS_INO_ACL_LRU_SET, &NFS_FLAGS(inode))) { | ||
1886 | spin_lock(&nfs_access_lru_lock); | ||
1887 | list_add_tail(&NFS_I(inode)->access_cache_inode_lru, &nfs_access_lru_list); | ||
1888 | spin_unlock(&nfs_access_lru_lock); | ||
1889 | } | ||
1670 | } | 1890 | } |
1671 | 1891 | ||
1672 | static int nfs_do_access(struct inode *inode, struct rpc_cred *cred, int mask) | 1892 | static int nfs_do_access(struct inode *inode, struct rpc_cred *cred, int mask) |
diff --git a/fs/nfs/file.c b/fs/nfs/file.c index 48e892880d5b..be997d649127 100644 --- a/fs/nfs/file.c +++ b/fs/nfs/file.c | |||
@@ -111,7 +111,7 @@ nfs_file_open(struct inode *inode, struct file *filp) | |||
111 | 111 | ||
112 | nfs_inc_stats(inode, NFSIOS_VFSOPEN); | 112 | nfs_inc_stats(inode, NFSIOS_VFSOPEN); |
113 | lock_kernel(); | 113 | lock_kernel(); |
114 | res = NFS_SERVER(inode)->rpc_ops->file_open(inode, filp); | 114 | res = NFS_PROTO(inode)->file_open(inode, filp); |
115 | unlock_kernel(); | 115 | unlock_kernel(); |
116 | return res; | 116 | return res; |
117 | } | 117 | } |
@@ -157,7 +157,7 @@ force_reval: | |||
157 | static loff_t nfs_file_llseek(struct file *filp, loff_t offset, int origin) | 157 | static loff_t nfs_file_llseek(struct file *filp, loff_t offset, int origin) |
158 | { | 158 | { |
159 | /* origin == SEEK_END => we must revalidate the cached file length */ | 159 | /* origin == SEEK_END => we must revalidate the cached file length */ |
160 | if (origin == 2) { | 160 | if (origin == SEEK_END) { |
161 | struct inode *inode = filp->f_mapping->host; | 161 | struct inode *inode = filp->f_mapping->host; |
162 | int retval = nfs_revalidate_file_size(inode, filp); | 162 | int retval = nfs_revalidate_file_size(inode, filp); |
163 | if (retval < 0) | 163 | if (retval < 0) |
diff --git a/fs/nfs/getroot.c b/fs/nfs/getroot.c new file mode 100644 index 000000000000..76b08ae9ed82 --- /dev/null +++ b/fs/nfs/getroot.c | |||
@@ -0,0 +1,311 @@ | |||
1 | /* getroot.c: get the root dentry for an NFS mount | ||
2 | * | ||
3 | * Copyright (C) 2006 Red Hat, Inc. All Rights Reserved. | ||
4 | * Written by David Howells (dhowells@redhat.com) | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or | ||
7 | * modify it under the terms of the GNU General Public License | ||
8 | * as published by the Free Software Foundation; either version | ||
9 | * 2 of the License, or (at your option) any later version. | ||
10 | */ | ||
11 | |||
12 | #include <linux/config.h> | ||
13 | #include <linux/module.h> | ||
14 | #include <linux/init.h> | ||
15 | |||
16 | #include <linux/time.h> | ||
17 | #include <linux/kernel.h> | ||
18 | #include <linux/mm.h> | ||
19 | #include <linux/string.h> | ||
20 | #include <linux/stat.h> | ||
21 | #include <linux/errno.h> | ||
22 | #include <linux/unistd.h> | ||
23 | #include <linux/sunrpc/clnt.h> | ||
24 | #include <linux/sunrpc/stats.h> | ||
25 | #include <linux/nfs_fs.h> | ||
26 | #include <linux/nfs_mount.h> | ||
27 | #include <linux/nfs4_mount.h> | ||
28 | #include <linux/lockd/bind.h> | ||
29 | #include <linux/smp_lock.h> | ||
30 | #include <linux/seq_file.h> | ||
31 | #include <linux/mount.h> | ||
32 | #include <linux/nfs_idmap.h> | ||
33 | #include <linux/vfs.h> | ||
34 | #include <linux/namei.h> | ||
35 | #include <linux/namespace.h> | ||
36 | #include <linux/security.h> | ||
37 | |||
38 | #include <asm/system.h> | ||
39 | #include <asm/uaccess.h> | ||
40 | |||
41 | #include "nfs4_fs.h" | ||
42 | #include "delegation.h" | ||
43 | #include "internal.h" | ||
44 | |||
45 | #define NFSDBG_FACILITY NFSDBG_CLIENT | ||
46 | #define NFS_PARANOIA 1 | ||
47 | |||
48 | /* | ||
49 | * get an NFS2/NFS3 root dentry from the root filehandle | ||
50 | */ | ||
51 | struct dentry *nfs_get_root(struct super_block *sb, struct nfs_fh *mntfh) | ||
52 | { | ||
53 | struct nfs_server *server = NFS_SB(sb); | ||
54 | struct nfs_fsinfo fsinfo; | ||
55 | struct nfs_fattr fattr; | ||
56 | struct dentry *mntroot; | ||
57 | struct inode *inode; | ||
58 | int error; | ||
59 | |||
60 | /* create a dummy root dentry with dummy inode for this superblock */ | ||
61 | if (!sb->s_root) { | ||
62 | struct nfs_fh dummyfh; | ||
63 | struct dentry *root; | ||
64 | struct inode *iroot; | ||
65 | |||
66 | memset(&dummyfh, 0, sizeof(dummyfh)); | ||
67 | memset(&fattr, 0, sizeof(fattr)); | ||
68 | nfs_fattr_init(&fattr); | ||
69 | fattr.valid = NFS_ATTR_FATTR; | ||
70 | fattr.type = NFDIR; | ||
71 | fattr.mode = S_IFDIR | S_IRUSR | S_IWUSR; | ||
72 | fattr.nlink = 2; | ||
73 | |||
74 | iroot = nfs_fhget(sb, &dummyfh, &fattr); | ||
75 | if (IS_ERR(iroot)) | ||
76 | return ERR_PTR(PTR_ERR(iroot)); | ||
77 | |||
78 | root = d_alloc_root(iroot); | ||
79 | if (!root) { | ||
80 | iput(iroot); | ||
81 | return ERR_PTR(-ENOMEM); | ||
82 | } | ||
83 | |||
84 | sb->s_root = root; | ||
85 | } | ||
86 | |||
87 | /* get the actual root for this mount */ | ||
88 | fsinfo.fattr = &fattr; | ||
89 | |||
90 | error = server->nfs_client->rpc_ops->getroot(server, mntfh, &fsinfo); | ||
91 | if (error < 0) { | ||
92 | dprintk("nfs_get_root: getattr error = %d\n", -error); | ||
93 | return ERR_PTR(error); | ||
94 | } | ||
95 | |||
96 | inode = nfs_fhget(sb, mntfh, fsinfo.fattr); | ||
97 | if (IS_ERR(inode)) { | ||
98 | dprintk("nfs_get_root: get root inode failed\n"); | ||
99 | return ERR_PTR(PTR_ERR(inode)); | ||
100 | } | ||
101 | |||
102 | /* root dentries normally start off anonymous and get spliced in later | ||
103 | * if the dentry tree reaches them; however if the dentry already | ||
104 | * exists, we'll pick it up at this point and use it as the root | ||
105 | */ | ||
106 | mntroot = d_alloc_anon(inode); | ||
107 | if (!mntroot) { | ||
108 | iput(inode); | ||
109 | dprintk("nfs_get_root: get root dentry failed\n"); | ||
110 | return ERR_PTR(-ENOMEM); | ||
111 | } | ||
112 | |||
113 | security_d_instantiate(mntroot, inode); | ||
114 | |||
115 | if (!mntroot->d_op) | ||
116 | mntroot->d_op = server->nfs_client->rpc_ops->dentry_ops; | ||
117 | |||
118 | return mntroot; | ||
119 | } | ||
120 | |||
121 | #ifdef CONFIG_NFS_V4 | ||
122 | |||
123 | /* | ||
124 | * Do a simple pathwalk from the root FH of the server to the nominated target | ||
125 | * of the mountpoint | ||
126 | * - give error on symlinks | ||
127 | * - give error on ".." occurring in the path | ||
128 | * - follow traversals | ||
129 | */ | ||
130 | int nfs4_path_walk(struct nfs_server *server, | ||
131 | struct nfs_fh *mntfh, | ||
132 | const char *path) | ||
133 | { | ||
134 | struct nfs_fsinfo fsinfo; | ||
135 | struct nfs_fattr fattr; | ||
136 | struct nfs_fh lastfh; | ||
137 | struct qstr name; | ||
138 | int ret; | ||
139 | //int referral_count = 0; | ||
140 | |||
141 | dprintk("--> nfs4_path_walk(,,%s)\n", path); | ||
142 | |||
143 | fsinfo.fattr = &fattr; | ||
144 | nfs_fattr_init(&fattr); | ||
145 | |||
146 | if (*path++ != '/') { | ||
147 | dprintk("nfs4_get_root: Path does not begin with a slash\n"); | ||
148 | return -EINVAL; | ||
149 | } | ||
150 | |||
151 | /* Start by getting the root filehandle from the server */ | ||
152 | ret = server->nfs_client->rpc_ops->getroot(server, mntfh, &fsinfo); | ||
153 | if (ret < 0) { | ||
154 | dprintk("nfs4_get_root: getroot error = %d\n", -ret); | ||
155 | return ret; | ||
156 | } | ||
157 | |||
158 | if (fattr.type != NFDIR) { | ||
159 | printk(KERN_ERR "nfs4_get_root:" | ||
160 | " getroot encountered non-directory\n"); | ||
161 | return -ENOTDIR; | ||
162 | } | ||
163 | |||
164 | if (fattr.valid & NFS_ATTR_FATTR_V4_REFERRAL) { | ||
165 | printk(KERN_ERR "nfs4_get_root:" | ||
166 | " getroot obtained referral\n"); | ||
167 | return -EREMOTE; | ||
168 | } | ||
169 | |||
170 | next_component: | ||
171 | dprintk("Next: %s\n", path); | ||
172 | |||
173 | /* extract the next bit of the path */ | ||
174 | if (!*path) | ||
175 | goto path_walk_complete; | ||
176 | |||
177 | name.name = path; | ||
178 | while (*path && *path != '/') | ||
179 | path++; | ||
180 | name.len = path - (const char *) name.name; | ||
181 | |||
182 | eat_dot_dir: | ||
183 | while (*path == '/') | ||
184 | path++; | ||
185 | |||
186 | if (path[0] == '.' && (path[1] == '/' || !path[1])) { | ||
187 | path += 2; | ||
188 | goto eat_dot_dir; | ||
189 | } | ||
190 | |||
191 | if (path[0] == '.' && path[1] == '.' && (path[2] == '/' || !path[2]) | ||
192 | ) { | ||
193 | printk(KERN_ERR "nfs4_get_root:" | ||
194 | " Mount path contains reference to \"..\"\n"); | ||
195 | return -EINVAL; | ||
196 | } | ||
197 | |||
198 | /* lookup the next FH in the sequence */ | ||
199 | memcpy(&lastfh, mntfh, sizeof(lastfh)); | ||
200 | |||
201 | dprintk("LookupFH: %*.*s [%s]\n", name.len, name.len, name.name, path); | ||
202 | |||
203 | ret = server->nfs_client->rpc_ops->lookupfh(server, &lastfh, &name, | ||
204 | mntfh, &fattr); | ||
205 | if (ret < 0) { | ||
206 | dprintk("nfs4_get_root: getroot error = %d\n", -ret); | ||
207 | return ret; | ||
208 | } | ||
209 | |||
210 | if (fattr.type != NFDIR) { | ||
211 | printk(KERN_ERR "nfs4_get_root:" | ||
212 | " lookupfh encountered non-directory\n"); | ||
213 | return -ENOTDIR; | ||
214 | } | ||
215 | |||
216 | if (fattr.valid & NFS_ATTR_FATTR_V4_REFERRAL) { | ||
217 | printk(KERN_ERR "nfs4_get_root:" | ||
218 | " lookupfh obtained referral\n"); | ||
219 | return -EREMOTE; | ||
220 | } | ||
221 | |||
222 | goto next_component; | ||
223 | |||
224 | path_walk_complete: | ||
225 | memcpy(&server->fsid, &fattr.fsid, sizeof(server->fsid)); | ||
226 | dprintk("<-- nfs4_path_walk() = 0\n"); | ||
227 | return 0; | ||
228 | } | ||
229 | |||
230 | /* | ||
231 | * get an NFS4 root dentry from the root filehandle | ||
232 | */ | ||
233 | struct dentry *nfs4_get_root(struct super_block *sb, struct nfs_fh *mntfh) | ||
234 | { | ||
235 | struct nfs_server *server = NFS_SB(sb); | ||
236 | struct nfs_fattr fattr; | ||
237 | struct dentry *mntroot; | ||
238 | struct inode *inode; | ||
239 | int error; | ||
240 | |||
241 | dprintk("--> nfs4_get_root()\n"); | ||
242 | |||
243 | /* create a dummy root dentry with dummy inode for this superblock */ | ||
244 | if (!sb->s_root) { | ||
245 | struct nfs_fh dummyfh; | ||
246 | struct dentry *root; | ||
247 | struct inode *iroot; | ||
248 | |||
249 | memset(&dummyfh, 0, sizeof(dummyfh)); | ||
250 | memset(&fattr, 0, sizeof(fattr)); | ||
251 | nfs_fattr_init(&fattr); | ||
252 | fattr.valid = NFS_ATTR_FATTR; | ||
253 | fattr.type = NFDIR; | ||
254 | fattr.mode = S_IFDIR | S_IRUSR | S_IWUSR; | ||
255 | fattr.nlink = 2; | ||
256 | |||
257 | iroot = nfs_fhget(sb, &dummyfh, &fattr); | ||
258 | if (IS_ERR(iroot)) | ||
259 | return ERR_PTR(PTR_ERR(iroot)); | ||
260 | |||
261 | root = d_alloc_root(iroot); | ||
262 | if (!root) { | ||
263 | iput(iroot); | ||
264 | return ERR_PTR(-ENOMEM); | ||
265 | } | ||
266 | |||
267 | sb->s_root = root; | ||
268 | } | ||
269 | |||
270 | /* get the info about the server and filesystem */ | ||
271 | error = nfs4_server_capabilities(server, mntfh); | ||
272 | if (error < 0) { | ||
273 | dprintk("nfs_get_root: getcaps error = %d\n", | ||
274 | -error); | ||
275 | return ERR_PTR(error); | ||
276 | } | ||
277 | |||
278 | /* get the actual root for this mount */ | ||
279 | error = server->nfs_client->rpc_ops->getattr(server, mntfh, &fattr); | ||
280 | if (error < 0) { | ||
281 | dprintk("nfs_get_root: getattr error = %d\n", -error); | ||
282 | return ERR_PTR(error); | ||
283 | } | ||
284 | |||
285 | inode = nfs_fhget(sb, mntfh, &fattr); | ||
286 | if (IS_ERR(inode)) { | ||
287 | dprintk("nfs_get_root: get root inode failed\n"); | ||
288 | return ERR_PTR(PTR_ERR(inode)); | ||
289 | } | ||
290 | |||
291 | /* root dentries normally start off anonymous and get spliced in later | ||
292 | * if the dentry tree reaches them; however if the dentry already | ||
293 | * exists, we'll pick it up at this point and use it as the root | ||
294 | */ | ||
295 | mntroot = d_alloc_anon(inode); | ||
296 | if (!mntroot) { | ||
297 | iput(inode); | ||
298 | dprintk("nfs_get_root: get root dentry failed\n"); | ||
299 | return ERR_PTR(-ENOMEM); | ||
300 | } | ||
301 | |||
302 | security_d_instantiate(mntroot, inode); | ||
303 | |||
304 | if (!mntroot->d_op) | ||
305 | mntroot->d_op = server->nfs_client->rpc_ops->dentry_ops; | ||
306 | |||
307 | dprintk("<-- nfs4_get_root()\n"); | ||
308 | return mntroot; | ||
309 | } | ||
310 | |||
311 | #endif /* CONFIG_NFS_V4 */ | ||
diff --git a/fs/nfs/idmap.c b/fs/nfs/idmap.c index 07a5dd57646e..82ad7110a1c0 100644 --- a/fs/nfs/idmap.c +++ b/fs/nfs/idmap.c | |||
@@ -57,6 +57,20 @@ | |||
57 | /* Default cache timeout is 10 minutes */ | 57 | /* Default cache timeout is 10 minutes */ |
58 | unsigned int nfs_idmap_cache_timeout = 600 * HZ; | 58 | unsigned int nfs_idmap_cache_timeout = 600 * HZ; |
59 | 59 | ||
60 | static int param_set_idmap_timeout(const char *val, struct kernel_param *kp) | ||
61 | { | ||
62 | char *endp; | ||
63 | int num = simple_strtol(val, &endp, 0); | ||
64 | int jif = num * HZ; | ||
65 | if (endp == val || *endp || num < 0 || jif < num) | ||
66 | return -EINVAL; | ||
67 | *((int *)kp->arg) = jif; | ||
68 | return 0; | ||
69 | } | ||
70 | |||
71 | module_param_call(idmap_cache_timeout, param_set_idmap_timeout, param_get_int, | ||
72 | &nfs_idmap_cache_timeout, 0644); | ||
73 | |||
60 | struct idmap_hashent { | 74 | struct idmap_hashent { |
61 | unsigned long ih_expires; | 75 | unsigned long ih_expires; |
62 | __u32 ih_id; | 76 | __u32 ih_id; |
@@ -70,7 +84,6 @@ struct idmap_hashtable { | |||
70 | }; | 84 | }; |
71 | 85 | ||
72 | struct idmap { | 86 | struct idmap { |
73 | char idmap_path[48]; | ||
74 | struct dentry *idmap_dentry; | 87 | struct dentry *idmap_dentry; |
75 | wait_queue_head_t idmap_wq; | 88 | wait_queue_head_t idmap_wq; |
76 | struct idmap_msg idmap_im; | 89 | struct idmap_msg idmap_im; |
@@ -94,24 +107,23 @@ static struct rpc_pipe_ops idmap_upcall_ops = { | |||
94 | .destroy_msg = idmap_pipe_destroy_msg, | 107 | .destroy_msg = idmap_pipe_destroy_msg, |
95 | }; | 108 | }; |
96 | 109 | ||
97 | void | 110 | int |
98 | nfs_idmap_new(struct nfs4_client *clp) | 111 | nfs_idmap_new(struct nfs_client *clp) |
99 | { | 112 | { |
100 | struct idmap *idmap; | 113 | struct idmap *idmap; |
114 | int error; | ||
101 | 115 | ||
102 | if (clp->cl_idmap != NULL) | 116 | BUG_ON(clp->cl_idmap != NULL); |
103 | return; | ||
104 | if ((idmap = kzalloc(sizeof(*idmap), GFP_KERNEL)) == NULL) | ||
105 | return; | ||
106 | 117 | ||
107 | snprintf(idmap->idmap_path, sizeof(idmap->idmap_path), | 118 | if ((idmap = kzalloc(sizeof(*idmap), GFP_KERNEL)) == NULL) |
108 | "%s/idmap", clp->cl_rpcclient->cl_pathname); | 119 | return -ENOMEM; |
109 | 120 | ||
110 | idmap->idmap_dentry = rpc_mkpipe(idmap->idmap_path, | 121 | idmap->idmap_dentry = rpc_mkpipe(clp->cl_rpcclient->cl_dentry, "idmap", |
111 | idmap, &idmap_upcall_ops, 0); | 122 | idmap, &idmap_upcall_ops, 0); |
112 | if (IS_ERR(idmap->idmap_dentry)) { | 123 | if (IS_ERR(idmap->idmap_dentry)) { |
124 | error = PTR_ERR(idmap->idmap_dentry); | ||
113 | kfree(idmap); | 125 | kfree(idmap); |
114 | return; | 126 | return error; |
115 | } | 127 | } |
116 | 128 | ||
117 | mutex_init(&idmap->idmap_lock); | 129 | mutex_init(&idmap->idmap_lock); |
@@ -121,10 +133,11 @@ nfs_idmap_new(struct nfs4_client *clp) | |||
121 | idmap->idmap_group_hash.h_type = IDMAP_TYPE_GROUP; | 133 | idmap->idmap_group_hash.h_type = IDMAP_TYPE_GROUP; |
122 | 134 | ||
123 | clp->cl_idmap = idmap; | 135 | clp->cl_idmap = idmap; |
136 | return 0; | ||
124 | } | 137 | } |
125 | 138 | ||
126 | void | 139 | void |
127 | nfs_idmap_delete(struct nfs4_client *clp) | 140 | nfs_idmap_delete(struct nfs_client *clp) |
128 | { | 141 | { |
129 | struct idmap *idmap = clp->cl_idmap; | 142 | struct idmap *idmap = clp->cl_idmap; |
130 | 143 | ||
@@ -477,27 +490,27 @@ static unsigned int fnvhash32(const void *buf, size_t buflen) | |||
477 | return (hash); | 490 | return (hash); |
478 | } | 491 | } |
479 | 492 | ||
480 | int nfs_map_name_to_uid(struct nfs4_client *clp, const char *name, size_t namelen, __u32 *uid) | 493 | int nfs_map_name_to_uid(struct nfs_client *clp, const char *name, size_t namelen, __u32 *uid) |
481 | { | 494 | { |
482 | struct idmap *idmap = clp->cl_idmap; | 495 | struct idmap *idmap = clp->cl_idmap; |
483 | 496 | ||
484 | return nfs_idmap_id(idmap, &idmap->idmap_user_hash, name, namelen, uid); | 497 | return nfs_idmap_id(idmap, &idmap->idmap_user_hash, name, namelen, uid); |
485 | } | 498 | } |
486 | 499 | ||
487 | int nfs_map_group_to_gid(struct nfs4_client *clp, const char *name, size_t namelen, __u32 *uid) | 500 | int nfs_map_group_to_gid(struct nfs_client *clp, const char *name, size_t namelen, __u32 *uid) |
488 | { | 501 | { |
489 | struct idmap *idmap = clp->cl_idmap; | 502 | struct idmap *idmap = clp->cl_idmap; |
490 | 503 | ||
491 | return nfs_idmap_id(idmap, &idmap->idmap_group_hash, name, namelen, uid); | 504 | return nfs_idmap_id(idmap, &idmap->idmap_group_hash, name, namelen, uid); |
492 | } | 505 | } |
493 | 506 | ||
494 | int nfs_map_uid_to_name(struct nfs4_client *clp, __u32 uid, char *buf) | 507 | int nfs_map_uid_to_name(struct nfs_client *clp, __u32 uid, char *buf) |
495 | { | 508 | { |
496 | struct idmap *idmap = clp->cl_idmap; | 509 | struct idmap *idmap = clp->cl_idmap; |
497 | 510 | ||
498 | return nfs_idmap_name(idmap, &idmap->idmap_user_hash, uid, buf); | 511 | return nfs_idmap_name(idmap, &idmap->idmap_user_hash, uid, buf); |
499 | } | 512 | } |
500 | int nfs_map_gid_to_group(struct nfs4_client *clp, __u32 uid, char *buf) | 513 | int nfs_map_gid_to_group(struct nfs_client *clp, __u32 uid, char *buf) |
501 | { | 514 | { |
502 | struct idmap *idmap = clp->cl_idmap; | 515 | struct idmap *idmap = clp->cl_idmap; |
503 | 516 | ||
diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c index d349fb2245da..e8c143d182c4 100644 --- a/fs/nfs/inode.c +++ b/fs/nfs/inode.c | |||
@@ -76,19 +76,14 @@ int nfs_write_inode(struct inode *inode, int sync) | |||
76 | 76 | ||
77 | void nfs_clear_inode(struct inode *inode) | 77 | void nfs_clear_inode(struct inode *inode) |
78 | { | 78 | { |
79 | struct nfs_inode *nfsi = NFS_I(inode); | ||
80 | struct rpc_cred *cred; | ||
81 | |||
82 | /* | 79 | /* |
83 | * The following should never happen... | 80 | * The following should never happen... |
84 | */ | 81 | */ |
85 | BUG_ON(nfs_have_writebacks(inode)); | 82 | BUG_ON(nfs_have_writebacks(inode)); |
86 | BUG_ON (!list_empty(&nfsi->open_files)); | 83 | BUG_ON(!list_empty(&NFS_I(inode)->open_files)); |
84 | BUG_ON(atomic_read(&NFS_I(inode)->data_updates) != 0); | ||
87 | nfs_zap_acl_cache(inode); | 85 | nfs_zap_acl_cache(inode); |
88 | cred = nfsi->cache_access.cred; | 86 | nfs_access_zap_cache(inode); |
89 | if (cred) | ||
90 | put_rpccred(cred); | ||
91 | BUG_ON(atomic_read(&nfsi->data_updates) != 0); | ||
92 | } | 87 | } |
93 | 88 | ||
94 | /** | 89 | /** |
@@ -242,13 +237,13 @@ nfs_fhget(struct super_block *sb, struct nfs_fh *fh, struct nfs_fattr *fattr) | |||
242 | /* Why so? Because we want revalidate for devices/FIFOs, and | 237 | /* Why so? Because we want revalidate for devices/FIFOs, and |
243 | * that's precisely what we have in nfs_file_inode_operations. | 238 | * that's precisely what we have in nfs_file_inode_operations. |
244 | */ | 239 | */ |
245 | inode->i_op = NFS_SB(sb)->rpc_ops->file_inode_ops; | 240 | inode->i_op = NFS_SB(sb)->nfs_client->rpc_ops->file_inode_ops; |
246 | if (S_ISREG(inode->i_mode)) { | 241 | if (S_ISREG(inode->i_mode)) { |
247 | inode->i_fop = &nfs_file_operations; | 242 | inode->i_fop = &nfs_file_operations; |
248 | inode->i_data.a_ops = &nfs_file_aops; | 243 | inode->i_data.a_ops = &nfs_file_aops; |
249 | inode->i_data.backing_dev_info = &NFS_SB(sb)->backing_dev_info; | 244 | inode->i_data.backing_dev_info = &NFS_SB(sb)->backing_dev_info; |
250 | } else if (S_ISDIR(inode->i_mode)) { | 245 | } else if (S_ISDIR(inode->i_mode)) { |
251 | inode->i_op = NFS_SB(sb)->rpc_ops->dir_inode_ops; | 246 | inode->i_op = NFS_SB(sb)->nfs_client->rpc_ops->dir_inode_ops; |
252 | inode->i_fop = &nfs_dir_operations; | 247 | inode->i_fop = &nfs_dir_operations; |
253 | if (nfs_server_capable(inode, NFS_CAP_READDIRPLUS) | 248 | if (nfs_server_capable(inode, NFS_CAP_READDIRPLUS) |
254 | && fattr->size <= NFS_LIMIT_READDIRPLUS) | 249 | && fattr->size <= NFS_LIMIT_READDIRPLUS) |
@@ -290,7 +285,7 @@ nfs_fhget(struct super_block *sb, struct nfs_fh *fh, struct nfs_fattr *fattr) | |||
290 | nfsi->attrtimeo = NFS_MINATTRTIMEO(inode); | 285 | nfsi->attrtimeo = NFS_MINATTRTIMEO(inode); |
291 | nfsi->attrtimeo_timestamp = jiffies; | 286 | nfsi->attrtimeo_timestamp = jiffies; |
292 | memset(nfsi->cookieverf, 0, sizeof(nfsi->cookieverf)); | 287 | memset(nfsi->cookieverf, 0, sizeof(nfsi->cookieverf)); |
293 | nfsi->cache_access.cred = NULL; | 288 | nfsi->access_cache = RB_ROOT; |
294 | 289 | ||
295 | unlock_new_inode(inode); | 290 | unlock_new_inode(inode); |
296 | } else | 291 | } else |
@@ -722,13 +717,11 @@ void nfs_end_data_update(struct inode *inode) | |||
722 | { | 717 | { |
723 | struct nfs_inode *nfsi = NFS_I(inode); | 718 | struct nfs_inode *nfsi = NFS_I(inode); |
724 | 719 | ||
725 | if (!nfs_have_delegation(inode, FMODE_READ)) { | 720 | /* Directories: invalidate page cache */ |
726 | /* Directories and symlinks: invalidate page cache */ | 721 | if (S_ISDIR(inode->i_mode)) { |
727 | if (S_ISDIR(inode->i_mode) || S_ISLNK(inode->i_mode)) { | 722 | spin_lock(&inode->i_lock); |
728 | spin_lock(&inode->i_lock); | 723 | nfsi->cache_validity |= NFS_INO_INVALID_DATA; |
729 | nfsi->cache_validity |= NFS_INO_INVALID_DATA; | 724 | spin_unlock(&inode->i_lock); |
730 | spin_unlock(&inode->i_lock); | ||
731 | } | ||
732 | } | 725 | } |
733 | nfsi->cache_change_attribute = jiffies; | 726 | nfsi->cache_change_attribute = jiffies; |
734 | atomic_dec(&nfsi->data_updates); | 727 | atomic_dec(&nfsi->data_updates); |
@@ -847,6 +840,12 @@ int nfs_refresh_inode(struct inode *inode, struct nfs_fattr *fattr) | |||
847 | * | 840 | * |
848 | * After an operation that has changed the inode metadata, mark the | 841 | * After an operation that has changed the inode metadata, mark the |
849 | * attribute cache as being invalid, then try to update it. | 842 | * attribute cache as being invalid, then try to update it. |
843 | * | ||
844 | * NB: if the server didn't return any post op attributes, this | ||
845 | * function will force the retrieval of attributes before the next | ||
846 | * NFS request. Thus it should be used only for operations that | ||
847 | * are expected to change one or more attributes, to avoid | ||
848 | * unnecessary NFS requests and trips through nfs_update_inode(). | ||
850 | */ | 849 | */ |
851 | int nfs_post_op_update_inode(struct inode *inode, struct nfs_fattr *fattr) | 850 | int nfs_post_op_update_inode(struct inode *inode, struct nfs_fattr *fattr) |
852 | { | 851 | { |
@@ -1025,7 +1024,7 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr) | |||
1025 | out_fileid: | 1024 | out_fileid: |
1026 | printk(KERN_ERR "NFS: server %s error: fileid changed\n" | 1025 | printk(KERN_ERR "NFS: server %s error: fileid changed\n" |
1027 | "fsid %s: expected fileid 0x%Lx, got 0x%Lx\n", | 1026 | "fsid %s: expected fileid 0x%Lx, got 0x%Lx\n", |
1028 | NFS_SERVER(inode)->hostname, inode->i_sb->s_id, | 1027 | NFS_SERVER(inode)->nfs_client->cl_hostname, inode->i_sb->s_id, |
1029 | (long long)nfsi->fileid, (long long)fattr->fileid); | 1028 | (long long)nfsi->fileid, (long long)fattr->fileid); |
1030 | goto out_err; | 1029 | goto out_err; |
1031 | } | 1030 | } |
@@ -1109,6 +1108,8 @@ static void init_once(void * foo, kmem_cache_t * cachep, unsigned long flags) | |||
1109 | INIT_LIST_HEAD(&nfsi->dirty); | 1108 | INIT_LIST_HEAD(&nfsi->dirty); |
1110 | INIT_LIST_HEAD(&nfsi->commit); | 1109 | INIT_LIST_HEAD(&nfsi->commit); |
1111 | INIT_LIST_HEAD(&nfsi->open_files); | 1110 | INIT_LIST_HEAD(&nfsi->open_files); |
1111 | INIT_LIST_HEAD(&nfsi->access_cache_entry_lru); | ||
1112 | INIT_LIST_HEAD(&nfsi->access_cache_inode_lru); | ||
1112 | INIT_RADIX_TREE(&nfsi->nfs_page_tree, GFP_ATOMIC); | 1113 | INIT_RADIX_TREE(&nfsi->nfs_page_tree, GFP_ATOMIC); |
1113 | atomic_set(&nfsi->data_updates, 0); | 1114 | atomic_set(&nfsi->data_updates, 0); |
1114 | nfsi->ndirty = 0; | 1115 | nfsi->ndirty = 0; |
@@ -1144,6 +1145,10 @@ static int __init init_nfs_fs(void) | |||
1144 | { | 1145 | { |
1145 | int err; | 1146 | int err; |
1146 | 1147 | ||
1148 | err = nfs_fs_proc_init(); | ||
1149 | if (err) | ||
1150 | goto out5; | ||
1151 | |||
1147 | err = nfs_init_nfspagecache(); | 1152 | err = nfs_init_nfspagecache(); |
1148 | if (err) | 1153 | if (err) |
1149 | goto out4; | 1154 | goto out4; |
@@ -1184,6 +1189,8 @@ out2: | |||
1184 | out3: | 1189 | out3: |
1185 | nfs_destroy_nfspagecache(); | 1190 | nfs_destroy_nfspagecache(); |
1186 | out4: | 1191 | out4: |
1192 | nfs_fs_proc_exit(); | ||
1193 | out5: | ||
1187 | return err; | 1194 | return err; |
1188 | } | 1195 | } |
1189 | 1196 | ||
@@ -1198,6 +1205,7 @@ static void __exit exit_nfs_fs(void) | |||
1198 | rpc_proc_unregister("nfs"); | 1205 | rpc_proc_unregister("nfs"); |
1199 | #endif | 1206 | #endif |
1200 | unregister_nfs_fs(); | 1207 | unregister_nfs_fs(); |
1208 | nfs_fs_proc_exit(); | ||
1201 | } | 1209 | } |
1202 | 1210 | ||
1203 | /* Not quite true; I just maintain it */ | 1211 | /* Not quite true; I just maintain it */ |
diff --git a/fs/nfs/internal.h b/fs/nfs/internal.h index e4f4e5def0fc..bea0b016bd70 100644 --- a/fs/nfs/internal.h +++ b/fs/nfs/internal.h | |||
@@ -4,6 +4,18 @@ | |||
4 | 4 | ||
5 | #include <linux/mount.h> | 5 | #include <linux/mount.h> |
6 | 6 | ||
7 | struct nfs_string; | ||
8 | struct nfs_mount_data; | ||
9 | struct nfs4_mount_data; | ||
10 | |||
11 | /* Maximum number of readahead requests | ||
12 | * FIXME: this should really be a sysctl so that users may tune it to suit | ||
13 | * their needs. People that do NFS over a slow network, might for | ||
14 | * instance want to reduce it to something closer to 1 for improved | ||
15 | * interactive response. | ||
16 | */ | ||
17 | #define NFS_MAX_READAHEAD (RPC_DEF_SLOT_TABLE - 1) | ||
18 | |||
7 | struct nfs_clone_mount { | 19 | struct nfs_clone_mount { |
8 | const struct super_block *sb; | 20 | const struct super_block *sb; |
9 | const struct dentry *dentry; | 21 | const struct dentry *dentry; |
@@ -15,7 +27,40 @@ struct nfs_clone_mount { | |||
15 | rpc_authflavor_t authflavor; | 27 | rpc_authflavor_t authflavor; |
16 | }; | 28 | }; |
17 | 29 | ||
18 | /* namespace-nfs4.c */ | 30 | /* client.c */ |
31 | extern struct rpc_program nfs_program; | ||
32 | |||
33 | extern void nfs_put_client(struct nfs_client *); | ||
34 | extern struct nfs_client *nfs_find_client(const struct sockaddr_in *, int); | ||
35 | extern struct nfs_server *nfs_create_server(const struct nfs_mount_data *, | ||
36 | struct nfs_fh *); | ||
37 | extern struct nfs_server *nfs4_create_server(const struct nfs4_mount_data *, | ||
38 | const char *, | ||
39 | const struct sockaddr_in *, | ||
40 | const char *, | ||
41 | const char *, | ||
42 | rpc_authflavor_t, | ||
43 | struct nfs_fh *); | ||
44 | extern struct nfs_server *nfs4_create_referral_server(struct nfs_clone_mount *, | ||
45 | struct nfs_fh *); | ||
46 | extern void nfs_free_server(struct nfs_server *server); | ||
47 | extern struct nfs_server *nfs_clone_server(struct nfs_server *, | ||
48 | struct nfs_fh *, | ||
49 | struct nfs_fattr *); | ||
50 | #ifdef CONFIG_PROC_FS | ||
51 | extern int __init nfs_fs_proc_init(void); | ||
52 | extern void nfs_fs_proc_exit(void); | ||
53 | #else | ||
54 | static inline int nfs_fs_proc_init(void) | ||
55 | { | ||
56 | return 0; | ||
57 | } | ||
58 | static inline void nfs_fs_proc_exit(void) | ||
59 | { | ||
60 | } | ||
61 | #endif | ||
62 | |||
63 | /* nfs4namespace.c */ | ||
19 | #ifdef CONFIG_NFS_V4 | 64 | #ifdef CONFIG_NFS_V4 |
20 | extern struct vfsmount *nfs_do_refmount(const struct vfsmount *mnt_parent, struct dentry *dentry); | 65 | extern struct vfsmount *nfs_do_refmount(const struct vfsmount *mnt_parent, struct dentry *dentry); |
21 | #else | 66 | #else |
@@ -46,6 +91,7 @@ extern void nfs_destroy_directcache(void); | |||
46 | #endif | 91 | #endif |
47 | 92 | ||
48 | /* nfs2xdr.c */ | 93 | /* nfs2xdr.c */ |
94 | extern int nfs_stat_to_errno(int); | ||
49 | extern struct rpc_procinfo nfs_procedures[]; | 95 | extern struct rpc_procinfo nfs_procedures[]; |
50 | extern u32 * nfs_decode_dirent(u32 *, struct nfs_entry *, int); | 96 | extern u32 * nfs_decode_dirent(u32 *, struct nfs_entry *, int); |
51 | 97 | ||
@@ -54,8 +100,9 @@ extern struct rpc_procinfo nfs3_procedures[]; | |||
54 | extern u32 *nfs3_decode_dirent(u32 *, struct nfs_entry *, int); | 100 | extern u32 *nfs3_decode_dirent(u32 *, struct nfs_entry *, int); |
55 | 101 | ||
56 | /* nfs4xdr.c */ | 102 | /* nfs4xdr.c */ |
57 | extern int nfs_stat_to_errno(int); | 103 | #ifdef CONFIG_NFS_V4 |
58 | extern u32 *nfs4_decode_dirent(u32 *p, struct nfs_entry *entry, int plus); | 104 | extern u32 *nfs4_decode_dirent(u32 *p, struct nfs_entry *entry, int plus); |
105 | #endif | ||
59 | 106 | ||
60 | /* nfs4proc.c */ | 107 | /* nfs4proc.c */ |
61 | #ifdef CONFIG_NFS_V4 | 108 | #ifdef CONFIG_NFS_V4 |
@@ -66,6 +113,9 @@ extern int nfs4_proc_fs_locations(struct inode *dir, struct dentry *dentry, | |||
66 | struct page *page); | 113 | struct page *page); |
67 | #endif | 114 | #endif |
68 | 115 | ||
116 | /* dir.c */ | ||
117 | extern int nfs_access_cache_shrinker(int nr_to_scan, gfp_t gfp_mask); | ||
118 | |||
69 | /* inode.c */ | 119 | /* inode.c */ |
70 | extern struct inode *nfs_alloc_inode(struct super_block *sb); | 120 | extern struct inode *nfs_alloc_inode(struct super_block *sb); |
71 | extern void nfs_destroy_inode(struct inode *); | 121 | extern void nfs_destroy_inode(struct inode *); |
@@ -76,10 +126,10 @@ extern void nfs4_clear_inode(struct inode *); | |||
76 | #endif | 126 | #endif |
77 | 127 | ||
78 | /* super.c */ | 128 | /* super.c */ |
79 | extern struct file_system_type nfs_referral_nfs4_fs_type; | 129 | extern struct file_system_type nfs_xdev_fs_type; |
80 | extern struct file_system_type clone_nfs_fs_type; | ||
81 | #ifdef CONFIG_NFS_V4 | 130 | #ifdef CONFIG_NFS_V4 |
82 | extern struct file_system_type clone_nfs4_fs_type; | 131 | extern struct file_system_type nfs4_xdev_fs_type; |
132 | extern struct file_system_type nfs4_referral_fs_type; | ||
83 | #endif | 133 | #endif |
84 | 134 | ||
85 | extern struct rpc_stat nfs_rpcstat; | 135 | extern struct rpc_stat nfs_rpcstat; |
@@ -88,30 +138,30 @@ extern int __init register_nfs_fs(void); | |||
88 | extern void __exit unregister_nfs_fs(void); | 138 | extern void __exit unregister_nfs_fs(void); |
89 | 139 | ||
90 | /* namespace.c */ | 140 | /* namespace.c */ |
91 | extern char *nfs_path(const char *base, const struct dentry *dentry, | 141 | extern char *nfs_path(const char *base, |
142 | const struct dentry *droot, | ||
143 | const struct dentry *dentry, | ||
92 | char *buffer, ssize_t buflen); | 144 | char *buffer, ssize_t buflen); |
93 | 145 | ||
94 | /* | 146 | /* getroot.c */ |
95 | * Determine the mount path as a string | 147 | extern struct dentry *nfs_get_root(struct super_block *, struct nfs_fh *); |
96 | */ | ||
97 | static inline char * | ||
98 | nfs4_path(const struct dentry *dentry, char *buffer, ssize_t buflen) | ||
99 | { | ||
100 | #ifdef CONFIG_NFS_V4 | 148 | #ifdef CONFIG_NFS_V4 |
101 | return nfs_path(NFS_SB(dentry->d_sb)->mnt_path, dentry, buffer, buflen); | 149 | extern struct dentry *nfs4_get_root(struct super_block *, struct nfs_fh *); |
102 | #else | 150 | |
103 | return NULL; | 151 | extern int nfs4_path_walk(struct nfs_server *server, |
152 | struct nfs_fh *mntfh, | ||
153 | const char *path); | ||
104 | #endif | 154 | #endif |
105 | } | ||
106 | 155 | ||
107 | /* | 156 | /* |
108 | * Determine the device name as a string | 157 | * Determine the device name as a string |
109 | */ | 158 | */ |
110 | static inline char *nfs_devname(const struct vfsmount *mnt_parent, | 159 | static inline char *nfs_devname(const struct vfsmount *mnt_parent, |
111 | const struct dentry *dentry, | 160 | const struct dentry *dentry, |
112 | char *buffer, ssize_t buflen) | 161 | char *buffer, ssize_t buflen) |
113 | { | 162 | { |
114 | return nfs_path(mnt_parent->mnt_devname, dentry, buffer, buflen); | 163 | return nfs_path(mnt_parent->mnt_devname, mnt_parent->mnt_root, |
164 | dentry, buffer, buflen); | ||
115 | } | 165 | } |
116 | 166 | ||
117 | /* | 167 | /* |
@@ -167,20 +217,3 @@ void nfs_super_set_maxbytes(struct super_block *sb, __u64 maxfilesize) | |||
167 | if (sb->s_maxbytes > MAX_LFS_FILESIZE || sb->s_maxbytes <= 0) | 217 | if (sb->s_maxbytes > MAX_LFS_FILESIZE || sb->s_maxbytes <= 0) |
168 | sb->s_maxbytes = MAX_LFS_FILESIZE; | 218 | sb->s_maxbytes = MAX_LFS_FILESIZE; |
169 | } | 219 | } |
170 | |||
171 | /* | ||
172 | * Check if the string represents a "valid" IPv4 address | ||
173 | */ | ||
174 | static inline int valid_ipaddr4(const char *buf) | ||
175 | { | ||
176 | int rc, count, in[4]; | ||
177 | |||
178 | rc = sscanf(buf, "%d.%d.%d.%d", &in[0], &in[1], &in[2], &in[3]); | ||
179 | if (rc != 4) | ||
180 | return -EINVAL; | ||
181 | for (count = 0; count < 4; count++) { | ||
182 | if (in[count] > 255) | ||
183 | return -EINVAL; | ||
184 | } | ||
185 | return 0; | ||
186 | } | ||
diff --git a/fs/nfs/mount_clnt.c b/fs/nfs/mount_clnt.c index 445abb4d4214..d507b021207f 100644 --- a/fs/nfs/mount_clnt.c +++ b/fs/nfs/mount_clnt.c | |||
@@ -14,7 +14,6 @@ | |||
14 | #include <linux/net.h> | 14 | #include <linux/net.h> |
15 | #include <linux/in.h> | 15 | #include <linux/in.h> |
16 | #include <linux/sunrpc/clnt.h> | 16 | #include <linux/sunrpc/clnt.h> |
17 | #include <linux/sunrpc/xprt.h> | ||
18 | #include <linux/sunrpc/sched.h> | 17 | #include <linux/sunrpc/sched.h> |
19 | #include <linux/nfs_fs.h> | 18 | #include <linux/nfs_fs.h> |
20 | 19 | ||
@@ -77,22 +76,19 @@ static struct rpc_clnt * | |||
77 | mnt_create(char *hostname, struct sockaddr_in *srvaddr, int version, | 76 | mnt_create(char *hostname, struct sockaddr_in *srvaddr, int version, |
78 | int protocol) | 77 | int protocol) |
79 | { | 78 | { |
80 | struct rpc_xprt *xprt; | 79 | struct rpc_create_args args = { |
81 | struct rpc_clnt *clnt; | 80 | .protocol = protocol, |
82 | 81 | .address = (struct sockaddr *)srvaddr, | |
83 | xprt = xprt_create_proto(protocol, srvaddr, NULL); | 82 | .addrsize = sizeof(*srvaddr), |
84 | if (IS_ERR(xprt)) | 83 | .servername = hostname, |
85 | return (struct rpc_clnt *)xprt; | 84 | .program = &mnt_program, |
86 | 85 | .version = version, | |
87 | clnt = rpc_create_client(xprt, hostname, | 86 | .authflavor = RPC_AUTH_UNIX, |
88 | &mnt_program, version, | 87 | .flags = (RPC_CLNT_CREATE_ONESHOT | |
89 | RPC_AUTH_UNIX); | 88 | RPC_CLNT_CREATE_INTR), |
90 | if (!IS_ERR(clnt)) { | 89 | }; |
91 | clnt->cl_softrtry = 1; | 90 | |
92 | clnt->cl_oneshot = 1; | 91 | return rpc_create(&args); |
93 | clnt->cl_intr = 1; | ||
94 | } | ||
95 | return clnt; | ||
96 | } | 92 | } |
97 | 93 | ||
98 | /* | 94 | /* |
diff --git a/fs/nfs/namespace.c b/fs/nfs/namespace.c index 86b3169c8cac..77b00684894d 100644 --- a/fs/nfs/namespace.c +++ b/fs/nfs/namespace.c | |||
@@ -2,6 +2,7 @@ | |||
2 | * linux/fs/nfs/namespace.c | 2 | * linux/fs/nfs/namespace.c |
3 | * | 3 | * |
4 | * Copyright (C) 2005 Trond Myklebust <Trond.Myklebust@netapp.com> | 4 | * Copyright (C) 2005 Trond Myklebust <Trond.Myklebust@netapp.com> |
5 | * - Modified by David Howells <dhowells@redhat.com> | ||
5 | * | 6 | * |
6 | * NFS namespace | 7 | * NFS namespace |
7 | */ | 8 | */ |
@@ -28,6 +29,7 @@ int nfs_mountpoint_expiry_timeout = 500 * HZ; | |||
28 | /* | 29 | /* |
29 | * nfs_path - reconstruct the path given an arbitrary dentry | 30 | * nfs_path - reconstruct the path given an arbitrary dentry |
30 | * @base - arbitrary string to prepend to the path | 31 | * @base - arbitrary string to prepend to the path |
32 | * @droot - pointer to root dentry for mountpoint | ||
31 | * @dentry - pointer to dentry | 33 | * @dentry - pointer to dentry |
32 | * @buffer - result buffer | 34 | * @buffer - result buffer |
33 | * @buflen - length of buffer | 35 | * @buflen - length of buffer |
@@ -38,7 +40,9 @@ int nfs_mountpoint_expiry_timeout = 500 * HZ; | |||
38 | * This is mainly for use in figuring out the path on the | 40 | * This is mainly for use in figuring out the path on the |
39 | * server side when automounting on top of an existing partition. | 41 | * server side when automounting on top of an existing partition. |
40 | */ | 42 | */ |
41 | char *nfs_path(const char *base, const struct dentry *dentry, | 43 | char *nfs_path(const char *base, |
44 | const struct dentry *droot, | ||
45 | const struct dentry *dentry, | ||
42 | char *buffer, ssize_t buflen) | 46 | char *buffer, ssize_t buflen) |
43 | { | 47 | { |
44 | char *end = buffer+buflen; | 48 | char *end = buffer+buflen; |
@@ -47,7 +51,7 @@ char *nfs_path(const char *base, const struct dentry *dentry, | |||
47 | *--end = '\0'; | 51 | *--end = '\0'; |
48 | buflen--; | 52 | buflen--; |
49 | spin_lock(&dcache_lock); | 53 | spin_lock(&dcache_lock); |
50 | while (!IS_ROOT(dentry)) { | 54 | while (!IS_ROOT(dentry) && dentry != droot) { |
51 | namelen = dentry->d_name.len; | 55 | namelen = dentry->d_name.len; |
52 | buflen -= namelen + 1; | 56 | buflen -= namelen + 1; |
53 | if (buflen < 0) | 57 | if (buflen < 0) |
@@ -96,15 +100,18 @@ static void * nfs_follow_mountpoint(struct dentry *dentry, struct nameidata *nd) | |||
96 | struct nfs_fattr fattr; | 100 | struct nfs_fattr fattr; |
97 | int err; | 101 | int err; |
98 | 102 | ||
103 | dprintk("--> nfs_follow_mountpoint()\n"); | ||
104 | |||
99 | BUG_ON(IS_ROOT(dentry)); | 105 | BUG_ON(IS_ROOT(dentry)); |
100 | dprintk("%s: enter\n", __FUNCTION__); | 106 | dprintk("%s: enter\n", __FUNCTION__); |
101 | dput(nd->dentry); | 107 | dput(nd->dentry); |
102 | nd->dentry = dget(dentry); | 108 | nd->dentry = dget(dentry); |
103 | if (d_mountpoint(nd->dentry)) | 109 | |
104 | goto out_follow; | ||
105 | /* Look it up again */ | 110 | /* Look it up again */ |
106 | parent = dget_parent(nd->dentry); | 111 | parent = dget_parent(nd->dentry); |
107 | err = server->rpc_ops->lookup(parent->d_inode, &nd->dentry->d_name, &fh, &fattr); | 112 | err = server->nfs_client->rpc_ops->lookup(parent->d_inode, |
113 | &nd->dentry->d_name, | ||
114 | &fh, &fattr); | ||
108 | dput(parent); | 115 | dput(parent); |
109 | if (err != 0) | 116 | if (err != 0) |
110 | goto out_err; | 117 | goto out_err; |
@@ -132,6 +139,8 @@ static void * nfs_follow_mountpoint(struct dentry *dentry, struct nameidata *nd) | |||
132 | schedule_delayed_work(&nfs_automount_task, nfs_mountpoint_expiry_timeout); | 139 | schedule_delayed_work(&nfs_automount_task, nfs_mountpoint_expiry_timeout); |
133 | out: | 140 | out: |
134 | dprintk("%s: done, returned %d\n", __FUNCTION__, err); | 141 | dprintk("%s: done, returned %d\n", __FUNCTION__, err); |
142 | |||
143 | dprintk("<-- nfs_follow_mountpoint() = %d\n", err); | ||
135 | return ERR_PTR(err); | 144 | return ERR_PTR(err); |
136 | out_err: | 145 | out_err: |
137 | path_release(nd); | 146 | path_release(nd); |
@@ -172,22 +181,23 @@ void nfs_release_automount_timer(void) | |||
172 | /* | 181 | /* |
173 | * Clone a mountpoint of the appropriate type | 182 | * Clone a mountpoint of the appropriate type |
174 | */ | 183 | */ |
175 | static struct vfsmount *nfs_do_clone_mount(struct nfs_server *server, char *devname, | 184 | static struct vfsmount *nfs_do_clone_mount(struct nfs_server *server, |
185 | const char *devname, | ||
176 | struct nfs_clone_mount *mountdata) | 186 | struct nfs_clone_mount *mountdata) |
177 | { | 187 | { |
178 | #ifdef CONFIG_NFS_V4 | 188 | #ifdef CONFIG_NFS_V4 |
179 | struct vfsmount *mnt = NULL; | 189 | struct vfsmount *mnt = NULL; |
180 | switch (server->rpc_ops->version) { | 190 | switch (server->nfs_client->cl_nfsversion) { |
181 | case 2: | 191 | case 2: |
182 | case 3: | 192 | case 3: |
183 | mnt = vfs_kern_mount(&clone_nfs_fs_type, 0, devname, mountdata); | 193 | mnt = vfs_kern_mount(&nfs_xdev_fs_type, 0, devname, mountdata); |
184 | break; | 194 | break; |
185 | case 4: | 195 | case 4: |
186 | mnt = vfs_kern_mount(&clone_nfs4_fs_type, 0, devname, mountdata); | 196 | mnt = vfs_kern_mount(&nfs4_xdev_fs_type, 0, devname, mountdata); |
187 | } | 197 | } |
188 | return mnt; | 198 | return mnt; |
189 | #else | 199 | #else |
190 | return vfs_kern_mount(&clone_nfs_fs_type, 0, devname, mountdata); | 200 | return vfs_kern_mount(&nfs_xdev_fs_type, 0, devname, mountdata); |
191 | #endif | 201 | #endif |
192 | } | 202 | } |
193 | 203 | ||
@@ -213,6 +223,8 @@ struct vfsmount *nfs_do_submount(const struct vfsmount *mnt_parent, | |||
213 | char *page = (char *) __get_free_page(GFP_USER); | 223 | char *page = (char *) __get_free_page(GFP_USER); |
214 | char *devname; | 224 | char *devname; |
215 | 225 | ||
226 | dprintk("--> nfs_do_submount()\n"); | ||
227 | |||
216 | dprintk("%s: submounting on %s/%s\n", __FUNCTION__, | 228 | dprintk("%s: submounting on %s/%s\n", __FUNCTION__, |
217 | dentry->d_parent->d_name.name, | 229 | dentry->d_parent->d_name.name, |
218 | dentry->d_name.name); | 230 | dentry->d_name.name); |
@@ -227,5 +239,7 @@ free_page: | |||
227 | free_page((unsigned long)page); | 239 | free_page((unsigned long)page); |
228 | out: | 240 | out: |
229 | dprintk("%s: done\n", __FUNCTION__); | 241 | dprintk("%s: done\n", __FUNCTION__); |
242 | |||
243 | dprintk("<-- nfs_do_submount() = %p\n", mnt); | ||
230 | return mnt; | 244 | return mnt; |
231 | } | 245 | } |
diff --git a/fs/nfs/nfs2xdr.c b/fs/nfs/nfs2xdr.c index 67391eef6b93..b49501fc0a79 100644 --- a/fs/nfs/nfs2xdr.c +++ b/fs/nfs/nfs2xdr.c | |||
@@ -51,7 +51,7 @@ | |||
51 | #define NFS_createargs_sz (NFS_diropargs_sz+NFS_sattr_sz) | 51 | #define NFS_createargs_sz (NFS_diropargs_sz+NFS_sattr_sz) |
52 | #define NFS_renameargs_sz (NFS_diropargs_sz+NFS_diropargs_sz) | 52 | #define NFS_renameargs_sz (NFS_diropargs_sz+NFS_diropargs_sz) |
53 | #define NFS_linkargs_sz (NFS_fhandle_sz+NFS_diropargs_sz) | 53 | #define NFS_linkargs_sz (NFS_fhandle_sz+NFS_diropargs_sz) |
54 | #define NFS_symlinkargs_sz (NFS_diropargs_sz+NFS_path_sz+NFS_sattr_sz) | 54 | #define NFS_symlinkargs_sz (NFS_diropargs_sz+1+NFS_sattr_sz) |
55 | #define NFS_readdirargs_sz (NFS_fhandle_sz+2) | 55 | #define NFS_readdirargs_sz (NFS_fhandle_sz+2) |
56 | 56 | ||
57 | #define NFS_attrstat_sz (1+NFS_fattr_sz) | 57 | #define NFS_attrstat_sz (1+NFS_fattr_sz) |
@@ -351,11 +351,26 @@ nfs_xdr_linkargs(struct rpc_rqst *req, u32 *p, struct nfs_linkargs *args) | |||
351 | static int | 351 | static int |
352 | nfs_xdr_symlinkargs(struct rpc_rqst *req, u32 *p, struct nfs_symlinkargs *args) | 352 | nfs_xdr_symlinkargs(struct rpc_rqst *req, u32 *p, struct nfs_symlinkargs *args) |
353 | { | 353 | { |
354 | struct xdr_buf *sndbuf = &req->rq_snd_buf; | ||
355 | size_t pad; | ||
356 | |||
354 | p = xdr_encode_fhandle(p, args->fromfh); | 357 | p = xdr_encode_fhandle(p, args->fromfh); |
355 | p = xdr_encode_array(p, args->fromname, args->fromlen); | 358 | p = xdr_encode_array(p, args->fromname, args->fromlen); |
356 | p = xdr_encode_array(p, args->topath, args->tolen); | 359 | *p++ = htonl(args->pathlen); |
360 | sndbuf->len = xdr_adjust_iovec(sndbuf->head, p); | ||
361 | |||
362 | xdr_encode_pages(sndbuf, args->pages, 0, args->pathlen); | ||
363 | |||
364 | /* | ||
365 | * xdr_encode_pages may have added a few bytes to ensure the | ||
366 | * pathname ends on a 4-byte boundary. Start encoding the | ||
367 | * attributes after the pad bytes. | ||
368 | */ | ||
369 | pad = sndbuf->tail->iov_len; | ||
370 | if (pad > 0) | ||
371 | p++; | ||
357 | p = xdr_encode_sattr(p, args->sattr); | 372 | p = xdr_encode_sattr(p, args->sattr); |
358 | req->rq_slen = xdr_adjust_iovec(req->rq_svec, p); | 373 | sndbuf->len += xdr_adjust_iovec(sndbuf->tail, p) - pad; |
359 | return 0; | 374 | return 0; |
360 | } | 375 | } |
361 | 376 | ||
diff --git a/fs/nfs/nfs3proc.c b/fs/nfs/nfs3proc.c index 7143b1f82cea..f8688eaa0001 100644 --- a/fs/nfs/nfs3proc.c +++ b/fs/nfs/nfs3proc.c | |||
@@ -81,7 +81,7 @@ do_proc_get_root(struct rpc_clnt *client, struct nfs_fh *fhandle, | |||
81 | } | 81 | } |
82 | 82 | ||
83 | /* | 83 | /* |
84 | * Bare-bones access to getattr: this is for nfs_read_super. | 84 | * Bare-bones access to getattr: this is for nfs_get_root/nfs_get_sb |
85 | */ | 85 | */ |
86 | static int | 86 | static int |
87 | nfs3_proc_get_root(struct nfs_server *server, struct nfs_fh *fhandle, | 87 | nfs3_proc_get_root(struct nfs_server *server, struct nfs_fh *fhandle, |
@@ -90,8 +90,8 @@ nfs3_proc_get_root(struct nfs_server *server, struct nfs_fh *fhandle, | |||
90 | int status; | 90 | int status; |
91 | 91 | ||
92 | status = do_proc_get_root(server->client, fhandle, info); | 92 | status = do_proc_get_root(server->client, fhandle, info); |
93 | if (status && server->client_sys != server->client) | 93 | if (status && server->nfs_client->cl_rpcclient != server->client) |
94 | status = do_proc_get_root(server->client_sys, fhandle, info); | 94 | status = do_proc_get_root(server->nfs_client->cl_rpcclient, fhandle, info); |
95 | return status; | 95 | return status; |
96 | } | 96 | } |
97 | 97 | ||
@@ -544,23 +544,23 @@ nfs3_proc_link(struct inode *inode, struct inode *dir, struct qstr *name) | |||
544 | } | 544 | } |
545 | 545 | ||
546 | static int | 546 | static int |
547 | nfs3_proc_symlink(struct inode *dir, struct qstr *name, struct qstr *path, | 547 | nfs3_proc_symlink(struct inode *dir, struct dentry *dentry, struct page *page, |
548 | struct iattr *sattr, struct nfs_fh *fhandle, | 548 | unsigned int len, struct iattr *sattr) |
549 | struct nfs_fattr *fattr) | ||
550 | { | 549 | { |
551 | struct nfs_fattr dir_attr; | 550 | struct nfs_fh fhandle; |
551 | struct nfs_fattr fattr, dir_attr; | ||
552 | struct nfs3_symlinkargs arg = { | 552 | struct nfs3_symlinkargs arg = { |
553 | .fromfh = NFS_FH(dir), | 553 | .fromfh = NFS_FH(dir), |
554 | .fromname = name->name, | 554 | .fromname = dentry->d_name.name, |
555 | .fromlen = name->len, | 555 | .fromlen = dentry->d_name.len, |
556 | .topath = path->name, | 556 | .pages = &page, |
557 | .tolen = path->len, | 557 | .pathlen = len, |
558 | .sattr = sattr | 558 | .sattr = sattr |
559 | }; | 559 | }; |
560 | struct nfs3_diropres res = { | 560 | struct nfs3_diropres res = { |
561 | .dir_attr = &dir_attr, | 561 | .dir_attr = &dir_attr, |
562 | .fh = fhandle, | 562 | .fh = &fhandle, |
563 | .fattr = fattr | 563 | .fattr = &fattr |
564 | }; | 564 | }; |
565 | struct rpc_message msg = { | 565 | struct rpc_message msg = { |
566 | .rpc_proc = &nfs3_procedures[NFS3PROC_SYMLINK], | 566 | .rpc_proc = &nfs3_procedures[NFS3PROC_SYMLINK], |
@@ -569,13 +569,19 @@ nfs3_proc_symlink(struct inode *dir, struct qstr *name, struct qstr *path, | |||
569 | }; | 569 | }; |
570 | int status; | 570 | int status; |
571 | 571 | ||
572 | if (path->len > NFS3_MAXPATHLEN) | 572 | if (len > NFS3_MAXPATHLEN) |
573 | return -ENAMETOOLONG; | 573 | return -ENAMETOOLONG; |
574 | dprintk("NFS call symlink %s -> %s\n", name->name, path->name); | 574 | |
575 | dprintk("NFS call symlink %s\n", dentry->d_name.name); | ||
576 | |||
575 | nfs_fattr_init(&dir_attr); | 577 | nfs_fattr_init(&dir_attr); |
576 | nfs_fattr_init(fattr); | 578 | nfs_fattr_init(&fattr); |
577 | status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0); | 579 | status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0); |
578 | nfs_post_op_update_inode(dir, &dir_attr); | 580 | nfs_post_op_update_inode(dir, &dir_attr); |
581 | if (status != 0) | ||
582 | goto out; | ||
583 | status = nfs_instantiate(dentry, &fhandle, &fattr); | ||
584 | out: | ||
579 | dprintk("NFS reply symlink: %d\n", status); | 585 | dprintk("NFS reply symlink: %d\n", status); |
580 | return status; | 586 | return status; |
581 | } | 587 | } |
@@ -785,7 +791,7 @@ nfs3_proc_fsinfo(struct nfs_server *server, struct nfs_fh *fhandle, | |||
785 | 791 | ||
786 | dprintk("NFS call fsinfo\n"); | 792 | dprintk("NFS call fsinfo\n"); |
787 | nfs_fattr_init(info->fattr); | 793 | nfs_fattr_init(info->fattr); |
788 | status = rpc_call_sync(server->client_sys, &msg, 0); | 794 | status = rpc_call_sync(server->nfs_client->cl_rpcclient, &msg, 0); |
789 | dprintk("NFS reply fsinfo: %d\n", status); | 795 | dprintk("NFS reply fsinfo: %d\n", status); |
790 | return status; | 796 | return status; |
791 | } | 797 | } |
@@ -886,7 +892,7 @@ nfs3_proc_lock(struct file *filp, int cmd, struct file_lock *fl) | |||
886 | return nlmclnt_proc(filp->f_dentry->d_inode, cmd, fl); | 892 | return nlmclnt_proc(filp->f_dentry->d_inode, cmd, fl); |
887 | } | 893 | } |
888 | 894 | ||
889 | struct nfs_rpc_ops nfs_v3_clientops = { | 895 | const struct nfs_rpc_ops nfs_v3_clientops = { |
890 | .version = 3, /* protocol version */ | 896 | .version = 3, /* protocol version */ |
891 | .dentry_ops = &nfs_dentry_operations, | 897 | .dentry_ops = &nfs_dentry_operations, |
892 | .dir_inode_ops = &nfs3_dir_inode_operations, | 898 | .dir_inode_ops = &nfs3_dir_inode_operations, |
diff --git a/fs/nfs/nfs3xdr.c b/fs/nfs/nfs3xdr.c index 0250269e9753..16556fa4effb 100644 --- a/fs/nfs/nfs3xdr.c +++ b/fs/nfs/nfs3xdr.c | |||
@@ -56,7 +56,7 @@ | |||
56 | #define NFS3_writeargs_sz (NFS3_fh_sz+5) | 56 | #define NFS3_writeargs_sz (NFS3_fh_sz+5) |
57 | #define NFS3_createargs_sz (NFS3_diropargs_sz+NFS3_sattr_sz) | 57 | #define NFS3_createargs_sz (NFS3_diropargs_sz+NFS3_sattr_sz) |
58 | #define NFS3_mkdirargs_sz (NFS3_diropargs_sz+NFS3_sattr_sz) | 58 | #define NFS3_mkdirargs_sz (NFS3_diropargs_sz+NFS3_sattr_sz) |
59 | #define NFS3_symlinkargs_sz (NFS3_diropargs_sz+NFS3_path_sz+NFS3_sattr_sz) | 59 | #define NFS3_symlinkargs_sz (NFS3_diropargs_sz+1+NFS3_sattr_sz) |
60 | #define NFS3_mknodargs_sz (NFS3_diropargs_sz+2+NFS3_sattr_sz) | 60 | #define NFS3_mknodargs_sz (NFS3_diropargs_sz+2+NFS3_sattr_sz) |
61 | #define NFS3_renameargs_sz (NFS3_diropargs_sz+NFS3_diropargs_sz) | 61 | #define NFS3_renameargs_sz (NFS3_diropargs_sz+NFS3_diropargs_sz) |
62 | #define NFS3_linkargs_sz (NFS3_fh_sz+NFS3_diropargs_sz) | 62 | #define NFS3_linkargs_sz (NFS3_fh_sz+NFS3_diropargs_sz) |
@@ -398,8 +398,11 @@ nfs3_xdr_symlinkargs(struct rpc_rqst *req, u32 *p, struct nfs3_symlinkargs *args | |||
398 | p = xdr_encode_fhandle(p, args->fromfh); | 398 | p = xdr_encode_fhandle(p, args->fromfh); |
399 | p = xdr_encode_array(p, args->fromname, args->fromlen); | 399 | p = xdr_encode_array(p, args->fromname, args->fromlen); |
400 | p = xdr_encode_sattr(p, args->sattr); | 400 | p = xdr_encode_sattr(p, args->sattr); |
401 | p = xdr_encode_array(p, args->topath, args->tolen); | 401 | *p++ = htonl(args->pathlen); |
402 | req->rq_slen = xdr_adjust_iovec(req->rq_svec, p); | 402 | req->rq_slen = xdr_adjust_iovec(req->rq_svec, p); |
403 | |||
404 | /* Copy the page */ | ||
405 | xdr_encode_pages(&req->rq_snd_buf, args->pages, 0, args->pathlen); | ||
403 | return 0; | 406 | return 0; |
404 | } | 407 | } |
405 | 408 | ||
diff --git a/fs/nfs/nfs4_fs.h b/fs/nfs/nfs4_fs.h index 9a102860df37..61095fe4b5ca 100644 --- a/fs/nfs/nfs4_fs.h +++ b/fs/nfs/nfs4_fs.h | |||
@@ -43,55 +43,6 @@ enum nfs4_client_state { | |||
43 | }; | 43 | }; |
44 | 44 | ||
45 | /* | 45 | /* |
46 | * The nfs4_client identifies our client state to the server. | ||
47 | */ | ||
48 | struct nfs4_client { | ||
49 | struct list_head cl_servers; /* Global list of servers */ | ||
50 | struct in_addr cl_addr; /* Server identifier */ | ||
51 | u64 cl_clientid; /* constant */ | ||
52 | nfs4_verifier cl_confirm; | ||
53 | unsigned long cl_state; | ||
54 | |||
55 | u32 cl_lockowner_id; | ||
56 | |||
57 | /* | ||
58 | * The following rwsem ensures exclusive access to the server | ||
59 | * while we recover the state following a lease expiration. | ||
60 | */ | ||
61 | struct rw_semaphore cl_sem; | ||
62 | |||
63 | struct list_head cl_delegations; | ||
64 | struct list_head cl_state_owners; | ||
65 | struct list_head cl_unused; | ||
66 | int cl_nunused; | ||
67 | spinlock_t cl_lock; | ||
68 | atomic_t cl_count; | ||
69 | |||
70 | struct rpc_clnt * cl_rpcclient; | ||
71 | |||
72 | struct list_head cl_superblocks; /* List of nfs_server structs */ | ||
73 | |||
74 | unsigned long cl_lease_time; | ||
75 | unsigned long cl_last_renewal; | ||
76 | struct work_struct cl_renewd; | ||
77 | struct work_struct cl_recoverd; | ||
78 | |||
79 | struct rpc_wait_queue cl_rpcwaitq; | ||
80 | |||
81 | /* used for the setclientid verifier */ | ||
82 | struct timespec cl_boot_time; | ||
83 | |||
84 | /* idmapper */ | ||
85 | struct idmap * cl_idmap; | ||
86 | |||
87 | /* Our own IP address, as a null-terminated string. | ||
88 | * This is used to generate the clientid, and the callback address. | ||
89 | */ | ||
90 | char cl_ipaddr[16]; | ||
91 | unsigned char cl_id_uniquifier; | ||
92 | }; | ||
93 | |||
94 | /* | ||
95 | * struct rpc_sequence ensures that RPC calls are sent in the exact | 46 | * struct rpc_sequence ensures that RPC calls are sent in the exact |
96 | * order that they appear on the list. | 47 | * order that they appear on the list. |
97 | */ | 48 | */ |
@@ -127,7 +78,7 @@ static inline void nfs_confirm_seqid(struct nfs_seqid_counter *seqid, int status | |||
127 | struct nfs4_state_owner { | 78 | struct nfs4_state_owner { |
128 | spinlock_t so_lock; | 79 | spinlock_t so_lock; |
129 | struct list_head so_list; /* per-clientid list of state_owners */ | 80 | struct list_head so_list; /* per-clientid list of state_owners */ |
130 | struct nfs4_client *so_client; | 81 | struct nfs_client *so_client; |
131 | u32 so_id; /* 32-bit identifier, unique */ | 82 | u32 so_id; /* 32-bit identifier, unique */ |
132 | atomic_t so_count; | 83 | atomic_t so_count; |
133 | 84 | ||
@@ -210,10 +161,10 @@ extern ssize_t nfs4_listxattr(struct dentry *, char *, size_t); | |||
210 | 161 | ||
211 | /* nfs4proc.c */ | 162 | /* nfs4proc.c */ |
212 | extern int nfs4_map_errors(int err); | 163 | extern int nfs4_map_errors(int err); |
213 | extern int nfs4_proc_setclientid(struct nfs4_client *, u32, unsigned short, struct rpc_cred *); | 164 | extern int nfs4_proc_setclientid(struct nfs_client *, u32, unsigned short, struct rpc_cred *); |
214 | extern int nfs4_proc_setclientid_confirm(struct nfs4_client *, struct rpc_cred *); | 165 | extern int nfs4_proc_setclientid_confirm(struct nfs_client *, struct rpc_cred *); |
215 | extern int nfs4_proc_async_renew(struct nfs4_client *, struct rpc_cred *); | 166 | extern int nfs4_proc_async_renew(struct nfs_client *, struct rpc_cred *); |
216 | extern int nfs4_proc_renew(struct nfs4_client *, struct rpc_cred *); | 167 | extern int nfs4_proc_renew(struct nfs_client *, struct rpc_cred *); |
217 | extern int nfs4_do_close(struct inode *inode, struct nfs4_state *state); | 168 | extern int nfs4_do_close(struct inode *inode, struct nfs4_state *state); |
218 | extern struct dentry *nfs4_atomic_open(struct inode *, struct dentry *, struct nameidata *); | 169 | extern struct dentry *nfs4_atomic_open(struct inode *, struct dentry *, struct nameidata *); |
219 | extern int nfs4_open_revalidate(struct inode *, struct dentry *, int, struct nameidata *); | 170 | extern int nfs4_open_revalidate(struct inode *, struct dentry *, int, struct nameidata *); |
@@ -231,19 +182,14 @@ extern const u32 nfs4_fsinfo_bitmap[2]; | |||
231 | extern const u32 nfs4_fs_locations_bitmap[2]; | 182 | extern const u32 nfs4_fs_locations_bitmap[2]; |
232 | 183 | ||
233 | /* nfs4renewd.c */ | 184 | /* nfs4renewd.c */ |
234 | extern void nfs4_schedule_state_renewal(struct nfs4_client *); | 185 | extern void nfs4_schedule_state_renewal(struct nfs_client *); |
235 | extern void nfs4_renewd_prepare_shutdown(struct nfs_server *); | 186 | extern void nfs4_renewd_prepare_shutdown(struct nfs_server *); |
236 | extern void nfs4_kill_renewd(struct nfs4_client *); | 187 | extern void nfs4_kill_renewd(struct nfs_client *); |
237 | extern void nfs4_renew_state(void *); | 188 | extern void nfs4_renew_state(void *); |
238 | 189 | ||
239 | /* nfs4state.c */ | 190 | /* nfs4state.c */ |
240 | extern void init_nfsv4_state(struct nfs_server *); | 191 | struct rpc_cred *nfs4_get_renew_cred(struct nfs_client *clp); |
241 | extern void destroy_nfsv4_state(struct nfs_server *); | 192 | extern u32 nfs4_alloc_lockowner_id(struct nfs_client *); |
242 | extern struct nfs4_client *nfs4_get_client(struct in_addr *); | ||
243 | extern void nfs4_put_client(struct nfs4_client *clp); | ||
244 | extern struct nfs4_client *nfs4_find_client(struct in_addr *); | ||
245 | struct rpc_cred *nfs4_get_renew_cred(struct nfs4_client *clp); | ||
246 | extern u32 nfs4_alloc_lockowner_id(struct nfs4_client *); | ||
247 | 193 | ||
248 | extern struct nfs4_state_owner * nfs4_get_state_owner(struct nfs_server *, struct rpc_cred *); | 194 | extern struct nfs4_state_owner * nfs4_get_state_owner(struct nfs_server *, struct rpc_cred *); |
249 | extern void nfs4_put_state_owner(struct nfs4_state_owner *); | 195 | extern void nfs4_put_state_owner(struct nfs4_state_owner *); |
@@ -252,7 +198,7 @@ extern struct nfs4_state * nfs4_get_open_state(struct inode *, struct nfs4_state | |||
252 | extern void nfs4_put_open_state(struct nfs4_state *); | 198 | extern void nfs4_put_open_state(struct nfs4_state *); |
253 | extern void nfs4_close_state(struct nfs4_state *, mode_t); | 199 | extern void nfs4_close_state(struct nfs4_state *, mode_t); |
254 | extern void nfs4_state_set_mode_locked(struct nfs4_state *, mode_t); | 200 | extern void nfs4_state_set_mode_locked(struct nfs4_state *, mode_t); |
255 | extern void nfs4_schedule_state_recovery(struct nfs4_client *); | 201 | extern void nfs4_schedule_state_recovery(struct nfs_client *); |
256 | extern void nfs4_put_lock_state(struct nfs4_lock_state *lsp); | 202 | extern void nfs4_put_lock_state(struct nfs4_lock_state *lsp); |
257 | extern int nfs4_set_lock_state(struct nfs4_state *state, struct file_lock *fl); | 203 | extern int nfs4_set_lock_state(struct nfs4_state *state, struct file_lock *fl); |
258 | extern void nfs4_copy_stateid(nfs4_stateid *, struct nfs4_state *, fl_owner_t); | 204 | extern void nfs4_copy_stateid(nfs4_stateid *, struct nfs4_state *, fl_owner_t); |
@@ -276,10 +222,6 @@ extern struct svc_version nfs4_callback_version1; | |||
276 | 222 | ||
277 | #else | 223 | #else |
278 | 224 | ||
279 | #define init_nfsv4_state(server) do { } while (0) | ||
280 | #define destroy_nfsv4_state(server) do { } while (0) | ||
281 | #define nfs4_put_state_owner(inode, owner) do { } while (0) | ||
282 | #define nfs4_put_open_state(state) do { } while (0) | ||
283 | #define nfs4_close_state(a, b) do { } while (0) | 225 | #define nfs4_close_state(a, b) do { } while (0) |
284 | 226 | ||
285 | #endif /* CONFIG_NFS_V4 */ | 227 | #endif /* CONFIG_NFS_V4 */ |
diff --git a/fs/nfs/nfs4namespace.c b/fs/nfs/nfs4namespace.c index ea38d27b74e6..24e47f3bbd17 100644 --- a/fs/nfs/nfs4namespace.c +++ b/fs/nfs/nfs4namespace.c | |||
@@ -2,6 +2,7 @@ | |||
2 | * linux/fs/nfs/nfs4namespace.c | 2 | * linux/fs/nfs/nfs4namespace.c |
3 | * | 3 | * |
4 | * Copyright (C) 2005 Trond Myklebust <Trond.Myklebust@netapp.com> | 4 | * Copyright (C) 2005 Trond Myklebust <Trond.Myklebust@netapp.com> |
5 | * - Modified by David Howells <dhowells@redhat.com> | ||
5 | * | 6 | * |
6 | * NFSv4 namespace | 7 | * NFSv4 namespace |
7 | */ | 8 | */ |
@@ -23,7 +24,7 @@ | |||
23 | /* | 24 | /* |
24 | * Check if fs_root is valid | 25 | * Check if fs_root is valid |
25 | */ | 26 | */ |
26 | static inline char *nfs4_pathname_string(struct nfs4_pathname *pathname, | 27 | static inline char *nfs4_pathname_string(const struct nfs4_pathname *pathname, |
27 | char *buffer, ssize_t buflen) | 28 | char *buffer, ssize_t buflen) |
28 | { | 29 | { |
29 | char *end = buffer + buflen; | 30 | char *end = buffer + buflen; |
@@ -34,7 +35,7 @@ static inline char *nfs4_pathname_string(struct nfs4_pathname *pathname, | |||
34 | 35 | ||
35 | n = pathname->ncomponents; | 36 | n = pathname->ncomponents; |
36 | while (--n >= 0) { | 37 | while (--n >= 0) { |
37 | struct nfs4_string *component = &pathname->components[n]; | 38 | const struct nfs4_string *component = &pathname->components[n]; |
38 | buflen -= component->len + 1; | 39 | buflen -= component->len + 1; |
39 | if (buflen < 0) | 40 | if (buflen < 0) |
40 | goto Elong; | 41 | goto Elong; |
@@ -47,6 +48,68 @@ Elong: | |||
47 | return ERR_PTR(-ENAMETOOLONG); | 48 | return ERR_PTR(-ENAMETOOLONG); |
48 | } | 49 | } |
49 | 50 | ||
51 | /* | ||
52 | * Determine the mount path as a string | ||
53 | */ | ||
54 | static char *nfs4_path(const struct vfsmount *mnt_parent, | ||
55 | const struct dentry *dentry, | ||
56 | char *buffer, ssize_t buflen) | ||
57 | { | ||
58 | const char *srvpath; | ||
59 | |||
60 | srvpath = strchr(mnt_parent->mnt_devname, ':'); | ||
61 | if (srvpath) | ||
62 | srvpath++; | ||
63 | else | ||
64 | srvpath = mnt_parent->mnt_devname; | ||
65 | |||
66 | return nfs_path(srvpath, mnt_parent->mnt_root, dentry, buffer, buflen); | ||
67 | } | ||
68 | |||
69 | /* | ||
70 | * Check that fs_locations::fs_root [RFC3530 6.3] is a prefix for what we | ||
71 | * believe to be the server path to this dentry | ||
72 | */ | ||
73 | static int nfs4_validate_fspath(const struct vfsmount *mnt_parent, | ||
74 | const struct dentry *dentry, | ||
75 | const struct nfs4_fs_locations *locations, | ||
76 | char *page, char *page2) | ||
77 | { | ||
78 | const char *path, *fs_path; | ||
79 | |||
80 | path = nfs4_path(mnt_parent, dentry, page, PAGE_SIZE); | ||
81 | if (IS_ERR(path)) | ||
82 | return PTR_ERR(path); | ||
83 | |||
84 | fs_path = nfs4_pathname_string(&locations->fs_path, page2, PAGE_SIZE); | ||
85 | if (IS_ERR(fs_path)) | ||
86 | return PTR_ERR(fs_path); | ||
87 | |||
88 | if (strncmp(path, fs_path, strlen(fs_path)) != 0) { | ||
89 | dprintk("%s: path %s does not begin with fsroot %s\n", | ||
90 | __FUNCTION__, path, fs_path); | ||
91 | return -ENOENT; | ||
92 | } | ||
93 | |||
94 | return 0; | ||
95 | } | ||
96 | |||
97 | /* | ||
98 | * Check if the string represents a "valid" IPv4 address | ||
99 | */ | ||
100 | static inline int valid_ipaddr4(const char *buf) | ||
101 | { | ||
102 | int rc, count, in[4]; | ||
103 | |||
104 | rc = sscanf(buf, "%d.%d.%d.%d", &in[0], &in[1], &in[2], &in[3]); | ||
105 | if (rc != 4) | ||
106 | return -EINVAL; | ||
107 | for (count = 0; count < 4; count++) { | ||
108 | if (in[count] > 255) | ||
109 | return -EINVAL; | ||
110 | } | ||
111 | return 0; | ||
112 | } | ||
50 | 113 | ||
51 | /** | 114 | /** |
52 | * nfs_follow_referral - set up mountpoint when hitting a referral on moved error | 115 | * nfs_follow_referral - set up mountpoint when hitting a referral on moved error |
@@ -60,7 +123,7 @@ Elong: | |||
60 | */ | 123 | */ |
61 | static struct vfsmount *nfs_follow_referral(const struct vfsmount *mnt_parent, | 124 | static struct vfsmount *nfs_follow_referral(const struct vfsmount *mnt_parent, |
62 | const struct dentry *dentry, | 125 | const struct dentry *dentry, |
63 | struct nfs4_fs_locations *locations) | 126 | const struct nfs4_fs_locations *locations) |
64 | { | 127 | { |
65 | struct vfsmount *mnt = ERR_PTR(-ENOENT); | 128 | struct vfsmount *mnt = ERR_PTR(-ENOENT); |
66 | struct nfs_clone_mount mountdata = { | 129 | struct nfs_clone_mount mountdata = { |
@@ -68,10 +131,9 @@ static struct vfsmount *nfs_follow_referral(const struct vfsmount *mnt_parent, | |||
68 | .dentry = dentry, | 131 | .dentry = dentry, |
69 | .authflavor = NFS_SB(mnt_parent->mnt_sb)->client->cl_auth->au_flavor, | 132 | .authflavor = NFS_SB(mnt_parent->mnt_sb)->client->cl_auth->au_flavor, |
70 | }; | 133 | }; |
71 | char *page, *page2; | 134 | char *page = NULL, *page2 = NULL; |
72 | char *path, *fs_path; | ||
73 | char *devname; | 135 | char *devname; |
74 | int loc, s; | 136 | int loc, s, error; |
75 | 137 | ||
76 | if (locations == NULL || locations->nlocations <= 0) | 138 | if (locations == NULL || locations->nlocations <= 0) |
77 | goto out; | 139 | goto out; |
@@ -79,36 +141,30 @@ static struct vfsmount *nfs_follow_referral(const struct vfsmount *mnt_parent, | |||
79 | dprintk("%s: referral at %s/%s\n", __FUNCTION__, | 141 | dprintk("%s: referral at %s/%s\n", __FUNCTION__, |
80 | dentry->d_parent->d_name.name, dentry->d_name.name); | 142 | dentry->d_parent->d_name.name, dentry->d_name.name); |
81 | 143 | ||
82 | /* Ensure fs path is a prefix of current dentry path */ | ||
83 | page = (char *) __get_free_page(GFP_USER); | 144 | page = (char *) __get_free_page(GFP_USER); |
84 | if (page == NULL) | 145 | if (!page) |
85 | goto out; | 146 | goto out; |
147 | |||
86 | page2 = (char *) __get_free_page(GFP_USER); | 148 | page2 = (char *) __get_free_page(GFP_USER); |
87 | if (page2 == NULL) | 149 | if (!page2) |
88 | goto out; | 150 | goto out; |
89 | 151 | ||
90 | path = nfs4_path(dentry, page, PAGE_SIZE); | 152 | /* Ensure fs path is a prefix of current dentry path */ |
91 | if (IS_ERR(path)) | 153 | error = nfs4_validate_fspath(mnt_parent, dentry, locations, page, page2); |
92 | goto out_free; | 154 | if (error < 0) { |
93 | 155 | mnt = ERR_PTR(error); | |
94 | fs_path = nfs4_pathname_string(&locations->fs_path, page2, PAGE_SIZE); | 156 | goto out; |
95 | if (IS_ERR(fs_path)) | ||
96 | goto out_free; | ||
97 | |||
98 | if (strncmp(path, fs_path, strlen(fs_path)) != 0) { | ||
99 | dprintk("%s: path %s does not begin with fsroot %s\n", __FUNCTION__, path, fs_path); | ||
100 | goto out_free; | ||
101 | } | 157 | } |
102 | 158 | ||
103 | devname = nfs_devname(mnt_parent, dentry, page, PAGE_SIZE); | 159 | devname = nfs_devname(mnt_parent, dentry, page, PAGE_SIZE); |
104 | if (IS_ERR(devname)) { | 160 | if (IS_ERR(devname)) { |
105 | mnt = (struct vfsmount *)devname; | 161 | mnt = (struct vfsmount *)devname; |
106 | goto out_free; | 162 | goto out; |
107 | } | 163 | } |
108 | 164 | ||
109 | loc = 0; | 165 | loc = 0; |
110 | while (loc < locations->nlocations && IS_ERR(mnt)) { | 166 | while (loc < locations->nlocations && IS_ERR(mnt)) { |
111 | struct nfs4_fs_location *location = &locations->locations[loc]; | 167 | const struct nfs4_fs_location *location = &locations->locations[loc]; |
112 | char *mnt_path; | 168 | char *mnt_path; |
113 | 169 | ||
114 | if (location == NULL || location->nservers <= 0 || | 170 | if (location == NULL || location->nservers <= 0 || |
@@ -140,7 +196,7 @@ static struct vfsmount *nfs_follow_referral(const struct vfsmount *mnt_parent, | |||
140 | addr.sin_port = htons(NFS_PORT); | 196 | addr.sin_port = htons(NFS_PORT); |
141 | mountdata.addr = &addr; | 197 | mountdata.addr = &addr; |
142 | 198 | ||
143 | mnt = vfs_kern_mount(&nfs_referral_nfs4_fs_type, 0, devname, &mountdata); | 199 | mnt = vfs_kern_mount(&nfs4_referral_fs_type, 0, devname, &mountdata); |
144 | if (!IS_ERR(mnt)) { | 200 | if (!IS_ERR(mnt)) { |
145 | break; | 201 | break; |
146 | } | 202 | } |
@@ -149,10 +205,9 @@ static struct vfsmount *nfs_follow_referral(const struct vfsmount *mnt_parent, | |||
149 | loc++; | 205 | loc++; |
150 | } | 206 | } |
151 | 207 | ||
152 | out_free: | ||
153 | free_page((unsigned long)page); | ||
154 | free_page((unsigned long)page2); | ||
155 | out: | 208 | out: |
209 | free_page((unsigned long) page); | ||
210 | free_page((unsigned long) page2); | ||
156 | dprintk("%s: done\n", __FUNCTION__); | 211 | dprintk("%s: done\n", __FUNCTION__); |
157 | return mnt; | 212 | return mnt; |
158 | } | 213 | } |
@@ -165,7 +220,7 @@ out: | |||
165 | */ | 220 | */ |
166 | struct vfsmount *nfs_do_refmount(const struct vfsmount *mnt_parent, struct dentry *dentry) | 221 | struct vfsmount *nfs_do_refmount(const struct vfsmount *mnt_parent, struct dentry *dentry) |
167 | { | 222 | { |
168 | struct vfsmount *mnt = ERR_PTR(-ENOENT); | 223 | struct vfsmount *mnt = ERR_PTR(-ENOMEM); |
169 | struct dentry *parent; | 224 | struct dentry *parent; |
170 | struct nfs4_fs_locations *fs_locations = NULL; | 225 | struct nfs4_fs_locations *fs_locations = NULL; |
171 | struct page *page; | 226 | struct page *page; |
@@ -183,11 +238,16 @@ struct vfsmount *nfs_do_refmount(const struct vfsmount *mnt_parent, struct dentr | |||
183 | goto out_free; | 238 | goto out_free; |
184 | 239 | ||
185 | /* Get locations */ | 240 | /* Get locations */ |
241 | mnt = ERR_PTR(-ENOENT); | ||
242 | |||
186 | parent = dget_parent(dentry); | 243 | parent = dget_parent(dentry); |
187 | dprintk("%s: getting locations for %s/%s\n", __FUNCTION__, parent->d_name.name, dentry->d_name.name); | 244 | dprintk("%s: getting locations for %s/%s\n", |
245 | __FUNCTION__, parent->d_name.name, dentry->d_name.name); | ||
246 | |||
188 | err = nfs4_proc_fs_locations(parent->d_inode, dentry, fs_locations, page); | 247 | err = nfs4_proc_fs_locations(parent->d_inode, dentry, fs_locations, page); |
189 | dput(parent); | 248 | dput(parent); |
190 | if (err != 0 || fs_locations->nlocations <= 0 || | 249 | if (err != 0 || |
250 | fs_locations->nlocations <= 0 || | ||
191 | fs_locations->fs_path.ncomponents <= 0) | 251 | fs_locations->fs_path.ncomponents <= 0) |
192 | goto out_free; | 252 | goto out_free; |
193 | 253 | ||
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index b14145b7b87f..47c7e6e3910d 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c | |||
@@ -55,7 +55,7 @@ | |||
55 | 55 | ||
56 | #define NFSDBG_FACILITY NFSDBG_PROC | 56 | #define NFSDBG_FACILITY NFSDBG_PROC |
57 | 57 | ||
58 | #define NFS4_POLL_RETRY_MIN (1*HZ) | 58 | #define NFS4_POLL_RETRY_MIN (HZ/10) |
59 | #define NFS4_POLL_RETRY_MAX (15*HZ) | 59 | #define NFS4_POLL_RETRY_MAX (15*HZ) |
60 | 60 | ||
61 | struct nfs4_opendata; | 61 | struct nfs4_opendata; |
@@ -64,7 +64,7 @@ static int nfs4_do_fsinfo(struct nfs_server *, struct nfs_fh *, struct nfs_fsinf | |||
64 | static int nfs4_async_handle_error(struct rpc_task *, const struct nfs_server *); | 64 | static int nfs4_async_handle_error(struct rpc_task *, const struct nfs_server *); |
65 | static int _nfs4_proc_access(struct inode *inode, struct nfs_access_entry *entry); | 65 | static int _nfs4_proc_access(struct inode *inode, struct nfs_access_entry *entry); |
66 | static int nfs4_handle_exception(const struct nfs_server *server, int errorcode, struct nfs4_exception *exception); | 66 | static int nfs4_handle_exception(const struct nfs_server *server, int errorcode, struct nfs4_exception *exception); |
67 | static int nfs4_wait_clnt_recover(struct rpc_clnt *clnt, struct nfs4_client *clp); | 67 | static int nfs4_wait_clnt_recover(struct rpc_clnt *clnt, struct nfs_client *clp); |
68 | 68 | ||
69 | /* Prevent leaks of NFSv4 errors into userland */ | 69 | /* Prevent leaks of NFSv4 errors into userland */ |
70 | int nfs4_map_errors(int err) | 70 | int nfs4_map_errors(int err) |
@@ -195,7 +195,7 @@ static void nfs4_setup_readdir(u64 cookie, u32 *verifier, struct dentry *dentry, | |||
195 | 195 | ||
196 | static void renew_lease(const struct nfs_server *server, unsigned long timestamp) | 196 | static void renew_lease(const struct nfs_server *server, unsigned long timestamp) |
197 | { | 197 | { |
198 | struct nfs4_client *clp = server->nfs4_state; | 198 | struct nfs_client *clp = server->nfs_client; |
199 | spin_lock(&clp->cl_lock); | 199 | spin_lock(&clp->cl_lock); |
200 | if (time_before(clp->cl_last_renewal,timestamp)) | 200 | if (time_before(clp->cl_last_renewal,timestamp)) |
201 | clp->cl_last_renewal = timestamp; | 201 | clp->cl_last_renewal = timestamp; |
@@ -252,7 +252,7 @@ static struct nfs4_opendata *nfs4_opendata_alloc(struct dentry *dentry, | |||
252 | atomic_inc(&sp->so_count); | 252 | atomic_inc(&sp->so_count); |
253 | p->o_arg.fh = NFS_FH(dir); | 253 | p->o_arg.fh = NFS_FH(dir); |
254 | p->o_arg.open_flags = flags, | 254 | p->o_arg.open_flags = flags, |
255 | p->o_arg.clientid = server->nfs4_state->cl_clientid; | 255 | p->o_arg.clientid = server->nfs_client->cl_clientid; |
256 | p->o_arg.id = sp->so_id; | 256 | p->o_arg.id = sp->so_id; |
257 | p->o_arg.name = &dentry->d_name; | 257 | p->o_arg.name = &dentry->d_name; |
258 | p->o_arg.server = server; | 258 | p->o_arg.server = server; |
@@ -550,7 +550,7 @@ int nfs4_open_delegation_recall(struct dentry *dentry, struct nfs4_state *state) | |||
550 | case -NFS4ERR_STALE_STATEID: | 550 | case -NFS4ERR_STALE_STATEID: |
551 | case -NFS4ERR_EXPIRED: | 551 | case -NFS4ERR_EXPIRED: |
552 | /* Don't recall a delegation if it was lost */ | 552 | /* Don't recall a delegation if it was lost */ |
553 | nfs4_schedule_state_recovery(server->nfs4_state); | 553 | nfs4_schedule_state_recovery(server->nfs_client); |
554 | return err; | 554 | return err; |
555 | } | 555 | } |
556 | err = nfs4_handle_exception(server, err, &exception); | 556 | err = nfs4_handle_exception(server, err, &exception); |
@@ -758,7 +758,7 @@ static int _nfs4_proc_open(struct nfs4_opendata *data) | |||
758 | } | 758 | } |
759 | nfs_confirm_seqid(&data->owner->so_seqid, 0); | 759 | nfs_confirm_seqid(&data->owner->so_seqid, 0); |
760 | if (!(o_res->f_attr->valid & NFS_ATTR_FATTR)) | 760 | if (!(o_res->f_attr->valid & NFS_ATTR_FATTR)) |
761 | return server->rpc_ops->getattr(server, &o_res->fh, o_res->f_attr); | 761 | return server->nfs_client->rpc_ops->getattr(server, &o_res->fh, o_res->f_attr); |
762 | return 0; | 762 | return 0; |
763 | } | 763 | } |
764 | 764 | ||
@@ -792,11 +792,18 @@ out: | |||
792 | 792 | ||
793 | int nfs4_recover_expired_lease(struct nfs_server *server) | 793 | int nfs4_recover_expired_lease(struct nfs_server *server) |
794 | { | 794 | { |
795 | struct nfs4_client *clp = server->nfs4_state; | 795 | struct nfs_client *clp = server->nfs_client; |
796 | int ret; | ||
796 | 797 | ||
797 | if (test_and_clear_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state)) | 798 | for (;;) { |
799 | ret = nfs4_wait_clnt_recover(server->client, clp); | ||
800 | if (ret != 0) | ||
801 | return ret; | ||
802 | if (!test_and_clear_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state)) | ||
803 | break; | ||
798 | nfs4_schedule_state_recovery(clp); | 804 | nfs4_schedule_state_recovery(clp); |
799 | return nfs4_wait_clnt_recover(server->client, clp); | 805 | } |
806 | return 0; | ||
800 | } | 807 | } |
801 | 808 | ||
802 | /* | 809 | /* |
@@ -867,7 +874,7 @@ static int _nfs4_open_delegated(struct inode *inode, int flags, struct rpc_cred | |||
867 | { | 874 | { |
868 | struct nfs_delegation *delegation; | 875 | struct nfs_delegation *delegation; |
869 | struct nfs_server *server = NFS_SERVER(inode); | 876 | struct nfs_server *server = NFS_SERVER(inode); |
870 | struct nfs4_client *clp = server->nfs4_state; | 877 | struct nfs_client *clp = server->nfs_client; |
871 | struct nfs_inode *nfsi = NFS_I(inode); | 878 | struct nfs_inode *nfsi = NFS_I(inode); |
872 | struct nfs4_state_owner *sp = NULL; | 879 | struct nfs4_state_owner *sp = NULL; |
873 | struct nfs4_state *state = NULL; | 880 | struct nfs4_state *state = NULL; |
@@ -953,7 +960,7 @@ static int _nfs4_do_open(struct inode *dir, struct dentry *dentry, int flags, st | |||
953 | struct nfs4_state_owner *sp; | 960 | struct nfs4_state_owner *sp; |
954 | struct nfs4_state *state = NULL; | 961 | struct nfs4_state *state = NULL; |
955 | struct nfs_server *server = NFS_SERVER(dir); | 962 | struct nfs_server *server = NFS_SERVER(dir); |
956 | struct nfs4_client *clp = server->nfs4_state; | 963 | struct nfs_client *clp = server->nfs_client; |
957 | struct nfs4_opendata *opendata; | 964 | struct nfs4_opendata *opendata; |
958 | int status; | 965 | int status; |
959 | 966 | ||
@@ -1133,7 +1140,7 @@ static void nfs4_close_done(struct rpc_task *task, void *data) | |||
1133 | break; | 1140 | break; |
1134 | case -NFS4ERR_STALE_STATEID: | 1141 | case -NFS4ERR_STALE_STATEID: |
1135 | case -NFS4ERR_EXPIRED: | 1142 | case -NFS4ERR_EXPIRED: |
1136 | nfs4_schedule_state_recovery(server->nfs4_state); | 1143 | nfs4_schedule_state_recovery(server->nfs_client); |
1137 | break; | 1144 | break; |
1138 | default: | 1145 | default: |
1139 | if (nfs4_async_handle_error(task, server) == -EAGAIN) { | 1146 | if (nfs4_async_handle_error(task, server) == -EAGAIN) { |
@@ -1268,7 +1275,7 @@ nfs4_atomic_open(struct inode *dir, struct dentry *dentry, struct nameidata *nd) | |||
1268 | BUG_ON(nd->intent.open.flags & O_CREAT); | 1275 | BUG_ON(nd->intent.open.flags & O_CREAT); |
1269 | } | 1276 | } |
1270 | 1277 | ||
1271 | cred = rpcauth_lookupcred(NFS_SERVER(dir)->client->cl_auth, 0); | 1278 | cred = rpcauth_lookupcred(NFS_CLIENT(dir)->cl_auth, 0); |
1272 | if (IS_ERR(cred)) | 1279 | if (IS_ERR(cred)) |
1273 | return (struct dentry *)cred; | 1280 | return (struct dentry *)cred; |
1274 | state = nfs4_do_open(dir, dentry, nd->intent.open.flags, &attr, cred); | 1281 | state = nfs4_do_open(dir, dentry, nd->intent.open.flags, &attr, cred); |
@@ -1291,7 +1298,7 @@ nfs4_open_revalidate(struct inode *dir, struct dentry *dentry, int openflags, st | |||
1291 | struct rpc_cred *cred; | 1298 | struct rpc_cred *cred; |
1292 | struct nfs4_state *state; | 1299 | struct nfs4_state *state; |
1293 | 1300 | ||
1294 | cred = rpcauth_lookupcred(NFS_SERVER(dir)->client->cl_auth, 0); | 1301 | cred = rpcauth_lookupcred(NFS_CLIENT(dir)->cl_auth, 0); |
1295 | if (IS_ERR(cred)) | 1302 | if (IS_ERR(cred)) |
1296 | return PTR_ERR(cred); | 1303 | return PTR_ERR(cred); |
1297 | state = nfs4_open_delegated(dentry->d_inode, openflags, cred); | 1304 | state = nfs4_open_delegated(dentry->d_inode, openflags, cred); |
@@ -1393,70 +1400,19 @@ static int nfs4_lookup_root(struct nfs_server *server, struct nfs_fh *fhandle, | |||
1393 | return err; | 1400 | return err; |
1394 | } | 1401 | } |
1395 | 1402 | ||
1403 | /* | ||
1404 | * get the file handle for the "/" directory on the server | ||
1405 | */ | ||
1396 | static int nfs4_proc_get_root(struct nfs_server *server, struct nfs_fh *fhandle, | 1406 | static int nfs4_proc_get_root(struct nfs_server *server, struct nfs_fh *fhandle, |
1397 | struct nfs_fsinfo *info) | 1407 | struct nfs_fsinfo *info) |
1398 | { | 1408 | { |
1399 | struct nfs_fattr * fattr = info->fattr; | ||
1400 | unsigned char * p; | ||
1401 | struct qstr q; | ||
1402 | struct nfs4_lookup_arg args = { | ||
1403 | .dir_fh = fhandle, | ||
1404 | .name = &q, | ||
1405 | .bitmask = nfs4_fattr_bitmap, | ||
1406 | }; | ||
1407 | struct nfs4_lookup_res res = { | ||
1408 | .server = server, | ||
1409 | .fattr = fattr, | ||
1410 | .fh = fhandle, | ||
1411 | }; | ||
1412 | struct rpc_message msg = { | ||
1413 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_LOOKUP], | ||
1414 | .rpc_argp = &args, | ||
1415 | .rpc_resp = &res, | ||
1416 | }; | ||
1417 | int status; | 1409 | int status; |
1418 | 1410 | ||
1419 | /* | ||
1420 | * Now we do a separate LOOKUP for each component of the mount path. | ||
1421 | * The LOOKUPs are done separately so that we can conveniently | ||
1422 | * catch an ERR_WRONGSEC if it occurs along the way... | ||
1423 | */ | ||
1424 | status = nfs4_lookup_root(server, fhandle, info); | 1411 | status = nfs4_lookup_root(server, fhandle, info); |
1425 | if (status) | ||
1426 | goto out; | ||
1427 | |||
1428 | p = server->mnt_path; | ||
1429 | for (;;) { | ||
1430 | struct nfs4_exception exception = { }; | ||
1431 | |||
1432 | while (*p == '/') | ||
1433 | p++; | ||
1434 | if (!*p) | ||
1435 | break; | ||
1436 | q.name = p; | ||
1437 | while (*p && (*p != '/')) | ||
1438 | p++; | ||
1439 | q.len = p - q.name; | ||
1440 | |||
1441 | do { | ||
1442 | nfs_fattr_init(fattr); | ||
1443 | status = nfs4_handle_exception(server, | ||
1444 | rpc_call_sync(server->client, &msg, 0), | ||
1445 | &exception); | ||
1446 | } while (exception.retry); | ||
1447 | if (status == 0) | ||
1448 | continue; | ||
1449 | if (status == -ENOENT) { | ||
1450 | printk(KERN_NOTICE "NFS: mount path %s does not exist!\n", server->mnt_path); | ||
1451 | printk(KERN_NOTICE "NFS: suggestion: try mounting '/' instead.\n"); | ||
1452 | } | ||
1453 | break; | ||
1454 | } | ||
1455 | if (status == 0) | 1412 | if (status == 0) |
1456 | status = nfs4_server_capabilities(server, fhandle); | 1413 | status = nfs4_server_capabilities(server, fhandle); |
1457 | if (status == 0) | 1414 | if (status == 0) |
1458 | status = nfs4_do_fsinfo(server, fhandle, info); | 1415 | status = nfs4_do_fsinfo(server, fhandle, info); |
1459 | out: | ||
1460 | return nfs4_map_errors(status); | 1416 | return nfs4_map_errors(status); |
1461 | } | 1417 | } |
1462 | 1418 | ||
@@ -1565,7 +1521,7 @@ nfs4_proc_setattr(struct dentry *dentry, struct nfs_fattr *fattr, | |||
1565 | 1521 | ||
1566 | nfs_fattr_init(fattr); | 1522 | nfs_fattr_init(fattr); |
1567 | 1523 | ||
1568 | cred = rpcauth_lookupcred(NFS_SERVER(inode)->client->cl_auth, 0); | 1524 | cred = rpcauth_lookupcred(NFS_CLIENT(inode)->cl_auth, 0); |
1569 | if (IS_ERR(cred)) | 1525 | if (IS_ERR(cred)) |
1570 | return PTR_ERR(cred); | 1526 | return PTR_ERR(cred); |
1571 | 1527 | ||
@@ -1583,6 +1539,52 @@ nfs4_proc_setattr(struct dentry *dentry, struct nfs_fattr *fattr, | |||
1583 | return status; | 1539 | return status; |
1584 | } | 1540 | } |
1585 | 1541 | ||
1542 | static int _nfs4_proc_lookupfh(struct nfs_server *server, struct nfs_fh *dirfh, | ||
1543 | struct qstr *name, struct nfs_fh *fhandle, | ||
1544 | struct nfs_fattr *fattr) | ||
1545 | { | ||
1546 | int status; | ||
1547 | struct nfs4_lookup_arg args = { | ||
1548 | .bitmask = server->attr_bitmask, | ||
1549 | .dir_fh = dirfh, | ||
1550 | .name = name, | ||
1551 | }; | ||
1552 | struct nfs4_lookup_res res = { | ||
1553 | .server = server, | ||
1554 | .fattr = fattr, | ||
1555 | .fh = fhandle, | ||
1556 | }; | ||
1557 | struct rpc_message msg = { | ||
1558 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_LOOKUP], | ||
1559 | .rpc_argp = &args, | ||
1560 | .rpc_resp = &res, | ||
1561 | }; | ||
1562 | |||
1563 | nfs_fattr_init(fattr); | ||
1564 | |||
1565 | dprintk("NFS call lookupfh %s\n", name->name); | ||
1566 | status = rpc_call_sync(server->client, &msg, 0); | ||
1567 | dprintk("NFS reply lookupfh: %d\n", status); | ||
1568 | if (status == -NFS4ERR_MOVED) | ||
1569 | status = -EREMOTE; | ||
1570 | return status; | ||
1571 | } | ||
1572 | |||
1573 | static int nfs4_proc_lookupfh(struct nfs_server *server, struct nfs_fh *dirfh, | ||
1574 | struct qstr *name, struct nfs_fh *fhandle, | ||
1575 | struct nfs_fattr *fattr) | ||
1576 | { | ||
1577 | struct nfs4_exception exception = { }; | ||
1578 | int err; | ||
1579 | do { | ||
1580 | err = nfs4_handle_exception(server, | ||
1581 | _nfs4_proc_lookupfh(server, dirfh, name, | ||
1582 | fhandle, fattr), | ||
1583 | &exception); | ||
1584 | } while (exception.retry); | ||
1585 | return err; | ||
1586 | } | ||
1587 | |||
1586 | static int _nfs4_proc_lookup(struct inode *dir, struct qstr *name, | 1588 | static int _nfs4_proc_lookup(struct inode *dir, struct qstr *name, |
1587 | struct nfs_fh *fhandle, struct nfs_fattr *fattr) | 1589 | struct nfs_fh *fhandle, struct nfs_fattr *fattr) |
1588 | { | 1590 | { |
@@ -1881,7 +1883,7 @@ nfs4_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr, | |||
1881 | struct rpc_cred *cred; | 1883 | struct rpc_cred *cred; |
1882 | int status = 0; | 1884 | int status = 0; |
1883 | 1885 | ||
1884 | cred = rpcauth_lookupcred(NFS_SERVER(dir)->client->cl_auth, 0); | 1886 | cred = rpcauth_lookupcred(NFS_CLIENT(dir)->cl_auth, 0); |
1885 | if (IS_ERR(cred)) { | 1887 | if (IS_ERR(cred)) { |
1886 | status = PTR_ERR(cred); | 1888 | status = PTR_ERR(cred); |
1887 | goto out; | 1889 | goto out; |
@@ -2089,24 +2091,24 @@ static int nfs4_proc_link(struct inode *inode, struct inode *dir, struct qstr *n | |||
2089 | return err; | 2091 | return err; |
2090 | } | 2092 | } |
2091 | 2093 | ||
2092 | static int _nfs4_proc_symlink(struct inode *dir, struct qstr *name, | 2094 | static int _nfs4_proc_symlink(struct inode *dir, struct dentry *dentry, |
2093 | struct qstr *path, struct iattr *sattr, struct nfs_fh *fhandle, | 2095 | struct page *page, unsigned int len, struct iattr *sattr) |
2094 | struct nfs_fattr *fattr) | ||
2095 | { | 2096 | { |
2096 | struct nfs_server *server = NFS_SERVER(dir); | 2097 | struct nfs_server *server = NFS_SERVER(dir); |
2097 | struct nfs_fattr dir_fattr; | 2098 | struct nfs_fh fhandle; |
2099 | struct nfs_fattr fattr, dir_fattr; | ||
2098 | struct nfs4_create_arg arg = { | 2100 | struct nfs4_create_arg arg = { |
2099 | .dir_fh = NFS_FH(dir), | 2101 | .dir_fh = NFS_FH(dir), |
2100 | .server = server, | 2102 | .server = server, |
2101 | .name = name, | 2103 | .name = &dentry->d_name, |
2102 | .attrs = sattr, | 2104 | .attrs = sattr, |
2103 | .ftype = NF4LNK, | 2105 | .ftype = NF4LNK, |
2104 | .bitmask = server->attr_bitmask, | 2106 | .bitmask = server->attr_bitmask, |
2105 | }; | 2107 | }; |
2106 | struct nfs4_create_res res = { | 2108 | struct nfs4_create_res res = { |
2107 | .server = server, | 2109 | .server = server, |
2108 | .fh = fhandle, | 2110 | .fh = &fhandle, |
2109 | .fattr = fattr, | 2111 | .fattr = &fattr, |
2110 | .dir_fattr = &dir_fattr, | 2112 | .dir_fattr = &dir_fattr, |
2111 | }; | 2113 | }; |
2112 | struct rpc_message msg = { | 2114 | struct rpc_message msg = { |
@@ -2116,29 +2118,32 @@ static int _nfs4_proc_symlink(struct inode *dir, struct qstr *name, | |||
2116 | }; | 2118 | }; |
2117 | int status; | 2119 | int status; |
2118 | 2120 | ||
2119 | if (path->len > NFS4_MAXPATHLEN) | 2121 | if (len > NFS4_MAXPATHLEN) |
2120 | return -ENAMETOOLONG; | 2122 | return -ENAMETOOLONG; |
2121 | arg.u.symlink = path; | 2123 | |
2122 | nfs_fattr_init(fattr); | 2124 | arg.u.symlink.pages = &page; |
2125 | arg.u.symlink.len = len; | ||
2126 | nfs_fattr_init(&fattr); | ||
2123 | nfs_fattr_init(&dir_fattr); | 2127 | nfs_fattr_init(&dir_fattr); |
2124 | 2128 | ||
2125 | status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0); | 2129 | status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0); |
2126 | if (!status) | 2130 | if (!status) { |
2127 | update_changeattr(dir, &res.dir_cinfo); | 2131 | update_changeattr(dir, &res.dir_cinfo); |
2128 | nfs_post_op_update_inode(dir, res.dir_fattr); | 2132 | nfs_post_op_update_inode(dir, res.dir_fattr); |
2133 | status = nfs_instantiate(dentry, &fhandle, &fattr); | ||
2134 | } | ||
2129 | return status; | 2135 | return status; |
2130 | } | 2136 | } |
2131 | 2137 | ||
2132 | static int nfs4_proc_symlink(struct inode *dir, struct qstr *name, | 2138 | static int nfs4_proc_symlink(struct inode *dir, struct dentry *dentry, |
2133 | struct qstr *path, struct iattr *sattr, struct nfs_fh *fhandle, | 2139 | struct page *page, unsigned int len, struct iattr *sattr) |
2134 | struct nfs_fattr *fattr) | ||
2135 | { | 2140 | { |
2136 | struct nfs4_exception exception = { }; | 2141 | struct nfs4_exception exception = { }; |
2137 | int err; | 2142 | int err; |
2138 | do { | 2143 | do { |
2139 | err = nfs4_handle_exception(NFS_SERVER(dir), | 2144 | err = nfs4_handle_exception(NFS_SERVER(dir), |
2140 | _nfs4_proc_symlink(dir, name, path, sattr, | 2145 | _nfs4_proc_symlink(dir, dentry, page, |
2141 | fhandle, fattr), | 2146 | len, sattr), |
2142 | &exception); | 2147 | &exception); |
2143 | } while (exception.retry); | 2148 | } while (exception.retry); |
2144 | return err; | 2149 | return err; |
@@ -2521,7 +2526,7 @@ static void nfs4_proc_commit_setup(struct nfs_write_data *data, int how) | |||
2521 | */ | 2526 | */ |
2522 | static void nfs4_renew_done(struct rpc_task *task, void *data) | 2527 | static void nfs4_renew_done(struct rpc_task *task, void *data) |
2523 | { | 2528 | { |
2524 | struct nfs4_client *clp = (struct nfs4_client *)task->tk_msg.rpc_argp; | 2529 | struct nfs_client *clp = (struct nfs_client *)task->tk_msg.rpc_argp; |
2525 | unsigned long timestamp = (unsigned long)data; | 2530 | unsigned long timestamp = (unsigned long)data; |
2526 | 2531 | ||
2527 | if (task->tk_status < 0) { | 2532 | if (task->tk_status < 0) { |
@@ -2543,7 +2548,7 @@ static const struct rpc_call_ops nfs4_renew_ops = { | |||
2543 | .rpc_call_done = nfs4_renew_done, | 2548 | .rpc_call_done = nfs4_renew_done, |
2544 | }; | 2549 | }; |
2545 | 2550 | ||
2546 | int nfs4_proc_async_renew(struct nfs4_client *clp, struct rpc_cred *cred) | 2551 | int nfs4_proc_async_renew(struct nfs_client *clp, struct rpc_cred *cred) |
2547 | { | 2552 | { |
2548 | struct rpc_message msg = { | 2553 | struct rpc_message msg = { |
2549 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_RENEW], | 2554 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_RENEW], |
@@ -2555,7 +2560,7 @@ int nfs4_proc_async_renew(struct nfs4_client *clp, struct rpc_cred *cred) | |||
2555 | &nfs4_renew_ops, (void *)jiffies); | 2560 | &nfs4_renew_ops, (void *)jiffies); |
2556 | } | 2561 | } |
2557 | 2562 | ||
2558 | int nfs4_proc_renew(struct nfs4_client *clp, struct rpc_cred *cred) | 2563 | int nfs4_proc_renew(struct nfs_client *clp, struct rpc_cred *cred) |
2559 | { | 2564 | { |
2560 | struct rpc_message msg = { | 2565 | struct rpc_message msg = { |
2561 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_RENEW], | 2566 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_RENEW], |
@@ -2770,7 +2775,7 @@ static int __nfs4_proc_set_acl(struct inode *inode, const void *buf, size_t bufl | |||
2770 | return -EOPNOTSUPP; | 2775 | return -EOPNOTSUPP; |
2771 | nfs_inode_return_delegation(inode); | 2776 | nfs_inode_return_delegation(inode); |
2772 | buf_to_pages(buf, buflen, arg.acl_pages, &arg.acl_pgbase); | 2777 | buf_to_pages(buf, buflen, arg.acl_pages, &arg.acl_pgbase); |
2773 | ret = rpc_call_sync(NFS_SERVER(inode)->client, &msg, 0); | 2778 | ret = rpc_call_sync(NFS_CLIENT(inode), &msg, 0); |
2774 | if (ret == 0) | 2779 | if (ret == 0) |
2775 | nfs4_write_cached_acl(inode, buf, buflen); | 2780 | nfs4_write_cached_acl(inode, buf, buflen); |
2776 | return ret; | 2781 | return ret; |
@@ -2791,7 +2796,7 @@ static int nfs4_proc_set_acl(struct inode *inode, const void *buf, size_t buflen | |||
2791 | static int | 2796 | static int |
2792 | nfs4_async_handle_error(struct rpc_task *task, const struct nfs_server *server) | 2797 | nfs4_async_handle_error(struct rpc_task *task, const struct nfs_server *server) |
2793 | { | 2798 | { |
2794 | struct nfs4_client *clp = server->nfs4_state; | 2799 | struct nfs_client *clp = server->nfs_client; |
2795 | 2800 | ||
2796 | if (!clp || task->tk_status >= 0) | 2801 | if (!clp || task->tk_status >= 0) |
2797 | return 0; | 2802 | return 0; |
@@ -2828,7 +2833,7 @@ static int nfs4_wait_bit_interruptible(void *word) | |||
2828 | return 0; | 2833 | return 0; |
2829 | } | 2834 | } |
2830 | 2835 | ||
2831 | static int nfs4_wait_clnt_recover(struct rpc_clnt *clnt, struct nfs4_client *clp) | 2836 | static int nfs4_wait_clnt_recover(struct rpc_clnt *clnt, struct nfs_client *clp) |
2832 | { | 2837 | { |
2833 | sigset_t oldset; | 2838 | sigset_t oldset; |
2834 | int res; | 2839 | int res; |
@@ -2871,7 +2876,7 @@ static int nfs4_delay(struct rpc_clnt *clnt, long *timeout) | |||
2871 | */ | 2876 | */ |
2872 | int nfs4_handle_exception(const struct nfs_server *server, int errorcode, struct nfs4_exception *exception) | 2877 | int nfs4_handle_exception(const struct nfs_server *server, int errorcode, struct nfs4_exception *exception) |
2873 | { | 2878 | { |
2874 | struct nfs4_client *clp = server->nfs4_state; | 2879 | struct nfs_client *clp = server->nfs_client; |
2875 | int ret = errorcode; | 2880 | int ret = errorcode; |
2876 | 2881 | ||
2877 | exception->retry = 0; | 2882 | exception->retry = 0; |
@@ -2886,6 +2891,7 @@ int nfs4_handle_exception(const struct nfs_server *server, int errorcode, struct | |||
2886 | if (ret == 0) | 2891 | if (ret == 0) |
2887 | exception->retry = 1; | 2892 | exception->retry = 1; |
2888 | break; | 2893 | break; |
2894 | case -NFS4ERR_FILE_OPEN: | ||
2889 | case -NFS4ERR_GRACE: | 2895 | case -NFS4ERR_GRACE: |
2890 | case -NFS4ERR_DELAY: | 2896 | case -NFS4ERR_DELAY: |
2891 | ret = nfs4_delay(server->client, &exception->timeout); | 2897 | ret = nfs4_delay(server->client, &exception->timeout); |
@@ -2898,7 +2904,7 @@ int nfs4_handle_exception(const struct nfs_server *server, int errorcode, struct | |||
2898 | return nfs4_map_errors(ret); | 2904 | return nfs4_map_errors(ret); |
2899 | } | 2905 | } |
2900 | 2906 | ||
2901 | int nfs4_proc_setclientid(struct nfs4_client *clp, u32 program, unsigned short port, struct rpc_cred *cred) | 2907 | int nfs4_proc_setclientid(struct nfs_client *clp, u32 program, unsigned short port, struct rpc_cred *cred) |
2902 | { | 2908 | { |
2903 | nfs4_verifier sc_verifier; | 2909 | nfs4_verifier sc_verifier; |
2904 | struct nfs4_setclientid setclientid = { | 2910 | struct nfs4_setclientid setclientid = { |
@@ -2922,7 +2928,7 @@ int nfs4_proc_setclientid(struct nfs4_client *clp, u32 program, unsigned short p | |||
2922 | for(;;) { | 2928 | for(;;) { |
2923 | setclientid.sc_name_len = scnprintf(setclientid.sc_name, | 2929 | setclientid.sc_name_len = scnprintf(setclientid.sc_name, |
2924 | sizeof(setclientid.sc_name), "%s/%u.%u.%u.%u %s %u", | 2930 | sizeof(setclientid.sc_name), "%s/%u.%u.%u.%u %s %u", |
2925 | clp->cl_ipaddr, NIPQUAD(clp->cl_addr.s_addr), | 2931 | clp->cl_ipaddr, NIPQUAD(clp->cl_addr.sin_addr), |
2926 | cred->cr_ops->cr_name, | 2932 | cred->cr_ops->cr_name, |
2927 | clp->cl_id_uniquifier); | 2933 | clp->cl_id_uniquifier); |
2928 | setclientid.sc_netid_len = scnprintf(setclientid.sc_netid, | 2934 | setclientid.sc_netid_len = scnprintf(setclientid.sc_netid, |
@@ -2945,7 +2951,7 @@ int nfs4_proc_setclientid(struct nfs4_client *clp, u32 program, unsigned short p | |||
2945 | return status; | 2951 | return status; |
2946 | } | 2952 | } |
2947 | 2953 | ||
2948 | static int _nfs4_proc_setclientid_confirm(struct nfs4_client *clp, struct rpc_cred *cred) | 2954 | static int _nfs4_proc_setclientid_confirm(struct nfs_client *clp, struct rpc_cred *cred) |
2949 | { | 2955 | { |
2950 | struct nfs_fsinfo fsinfo; | 2956 | struct nfs_fsinfo fsinfo; |
2951 | struct rpc_message msg = { | 2957 | struct rpc_message msg = { |
@@ -2969,7 +2975,7 @@ static int _nfs4_proc_setclientid_confirm(struct nfs4_client *clp, struct rpc_cr | |||
2969 | return status; | 2975 | return status; |
2970 | } | 2976 | } |
2971 | 2977 | ||
2972 | int nfs4_proc_setclientid_confirm(struct nfs4_client *clp, struct rpc_cred *cred) | 2978 | int nfs4_proc_setclientid_confirm(struct nfs_client *clp, struct rpc_cred *cred) |
2973 | { | 2979 | { |
2974 | long timeout; | 2980 | long timeout; |
2975 | int err; | 2981 | int err; |
@@ -3077,7 +3083,7 @@ int nfs4_proc_delegreturn(struct inode *inode, struct rpc_cred *cred, const nfs4 | |||
3077 | switch (err) { | 3083 | switch (err) { |
3078 | case -NFS4ERR_STALE_STATEID: | 3084 | case -NFS4ERR_STALE_STATEID: |
3079 | case -NFS4ERR_EXPIRED: | 3085 | case -NFS4ERR_EXPIRED: |
3080 | nfs4_schedule_state_recovery(server->nfs4_state); | 3086 | nfs4_schedule_state_recovery(server->nfs_client); |
3081 | case 0: | 3087 | case 0: |
3082 | return 0; | 3088 | return 0; |
3083 | } | 3089 | } |
@@ -3106,7 +3112,7 @@ static int _nfs4_proc_getlk(struct nfs4_state *state, int cmd, struct file_lock | |||
3106 | { | 3112 | { |
3107 | struct inode *inode = state->inode; | 3113 | struct inode *inode = state->inode; |
3108 | struct nfs_server *server = NFS_SERVER(inode); | 3114 | struct nfs_server *server = NFS_SERVER(inode); |
3109 | struct nfs4_client *clp = server->nfs4_state; | 3115 | struct nfs_client *clp = server->nfs_client; |
3110 | struct nfs_lockt_args arg = { | 3116 | struct nfs_lockt_args arg = { |
3111 | .fh = NFS_FH(inode), | 3117 | .fh = NFS_FH(inode), |
3112 | .fl = request, | 3118 | .fl = request, |
@@ -3231,7 +3237,7 @@ static void nfs4_locku_done(struct rpc_task *task, void *data) | |||
3231 | break; | 3237 | break; |
3232 | case -NFS4ERR_STALE_STATEID: | 3238 | case -NFS4ERR_STALE_STATEID: |
3233 | case -NFS4ERR_EXPIRED: | 3239 | case -NFS4ERR_EXPIRED: |
3234 | nfs4_schedule_state_recovery(calldata->server->nfs4_state); | 3240 | nfs4_schedule_state_recovery(calldata->server->nfs_client); |
3235 | break; | 3241 | break; |
3236 | default: | 3242 | default: |
3237 | if (nfs4_async_handle_error(task, calldata->server) == -EAGAIN) { | 3243 | if (nfs4_async_handle_error(task, calldata->server) == -EAGAIN) { |
@@ -3343,7 +3349,7 @@ static struct nfs4_lockdata *nfs4_alloc_lockdata(struct file_lock *fl, | |||
3343 | if (p->arg.lock_seqid == NULL) | 3349 | if (p->arg.lock_seqid == NULL) |
3344 | goto out_free; | 3350 | goto out_free; |
3345 | p->arg.lock_stateid = &lsp->ls_stateid; | 3351 | p->arg.lock_stateid = &lsp->ls_stateid; |
3346 | p->arg.lock_owner.clientid = server->nfs4_state->cl_clientid; | 3352 | p->arg.lock_owner.clientid = server->nfs_client->cl_clientid; |
3347 | p->arg.lock_owner.id = lsp->ls_id; | 3353 | p->arg.lock_owner.id = lsp->ls_id; |
3348 | p->lsp = lsp; | 3354 | p->lsp = lsp; |
3349 | atomic_inc(&lsp->ls_count); | 3355 | atomic_inc(&lsp->ls_count); |
@@ -3513,7 +3519,7 @@ static int nfs4_lock_expired(struct nfs4_state *state, struct file_lock *request | |||
3513 | 3519 | ||
3514 | static int _nfs4_proc_setlk(struct nfs4_state *state, int cmd, struct file_lock *request) | 3520 | static int _nfs4_proc_setlk(struct nfs4_state *state, int cmd, struct file_lock *request) |
3515 | { | 3521 | { |
3516 | struct nfs4_client *clp = state->owner->so_client; | 3522 | struct nfs_client *clp = state->owner->so_client; |
3517 | unsigned char fl_flags = request->fl_flags; | 3523 | unsigned char fl_flags = request->fl_flags; |
3518 | int status; | 3524 | int status; |
3519 | 3525 | ||
@@ -3715,7 +3721,7 @@ static struct inode_operations nfs4_file_inode_operations = { | |||
3715 | .listxattr = nfs4_listxattr, | 3721 | .listxattr = nfs4_listxattr, |
3716 | }; | 3722 | }; |
3717 | 3723 | ||
3718 | struct nfs_rpc_ops nfs_v4_clientops = { | 3724 | const struct nfs_rpc_ops nfs_v4_clientops = { |
3719 | .version = 4, /* protocol version */ | 3725 | .version = 4, /* protocol version */ |
3720 | .dentry_ops = &nfs4_dentry_operations, | 3726 | .dentry_ops = &nfs4_dentry_operations, |
3721 | .dir_inode_ops = &nfs4_dir_inode_operations, | 3727 | .dir_inode_ops = &nfs4_dir_inode_operations, |
@@ -3723,6 +3729,7 @@ struct nfs_rpc_ops nfs_v4_clientops = { | |||
3723 | .getroot = nfs4_proc_get_root, | 3729 | .getroot = nfs4_proc_get_root, |
3724 | .getattr = nfs4_proc_getattr, | 3730 | .getattr = nfs4_proc_getattr, |
3725 | .setattr = nfs4_proc_setattr, | 3731 | .setattr = nfs4_proc_setattr, |
3732 | .lookupfh = nfs4_proc_lookupfh, | ||
3726 | .lookup = nfs4_proc_lookup, | 3733 | .lookup = nfs4_proc_lookup, |
3727 | .access = nfs4_proc_access, | 3734 | .access = nfs4_proc_access, |
3728 | .readlink = nfs4_proc_readlink, | 3735 | .readlink = nfs4_proc_readlink, |
@@ -3743,6 +3750,7 @@ struct nfs_rpc_ops nfs_v4_clientops = { | |||
3743 | .statfs = nfs4_proc_statfs, | 3750 | .statfs = nfs4_proc_statfs, |
3744 | .fsinfo = nfs4_proc_fsinfo, | 3751 | .fsinfo = nfs4_proc_fsinfo, |
3745 | .pathconf = nfs4_proc_pathconf, | 3752 | .pathconf = nfs4_proc_pathconf, |
3753 | .set_capabilities = nfs4_server_capabilities, | ||
3746 | .decode_dirent = nfs4_decode_dirent, | 3754 | .decode_dirent = nfs4_decode_dirent, |
3747 | .read_setup = nfs4_proc_read_setup, | 3755 | .read_setup = nfs4_proc_read_setup, |
3748 | .read_done = nfs4_read_done, | 3756 | .read_done = nfs4_read_done, |
diff --git a/fs/nfs/nfs4renewd.c b/fs/nfs/nfs4renewd.c index 5d764d8e6d8a..7b6df1852e75 100644 --- a/fs/nfs/nfs4renewd.c +++ b/fs/nfs/nfs4renewd.c | |||
@@ -61,7 +61,7 @@ | |||
61 | void | 61 | void |
62 | nfs4_renew_state(void *data) | 62 | nfs4_renew_state(void *data) |
63 | { | 63 | { |
64 | struct nfs4_client *clp = (struct nfs4_client *)data; | 64 | struct nfs_client *clp = (struct nfs_client *)data; |
65 | struct rpc_cred *cred; | 65 | struct rpc_cred *cred; |
66 | long lease, timeout; | 66 | long lease, timeout; |
67 | unsigned long last, now; | 67 | unsigned long last, now; |
@@ -108,7 +108,7 @@ out: | |||
108 | 108 | ||
109 | /* Must be called with clp->cl_sem locked for writes */ | 109 | /* Must be called with clp->cl_sem locked for writes */ |
110 | void | 110 | void |
111 | nfs4_schedule_state_renewal(struct nfs4_client *clp) | 111 | nfs4_schedule_state_renewal(struct nfs_client *clp) |
112 | { | 112 | { |
113 | long timeout; | 113 | long timeout; |
114 | 114 | ||
@@ -121,32 +121,20 @@ nfs4_schedule_state_renewal(struct nfs4_client *clp) | |||
121 | __FUNCTION__, (timeout + HZ - 1) / HZ); | 121 | __FUNCTION__, (timeout + HZ - 1) / HZ); |
122 | cancel_delayed_work(&clp->cl_renewd); | 122 | cancel_delayed_work(&clp->cl_renewd); |
123 | schedule_delayed_work(&clp->cl_renewd, timeout); | 123 | schedule_delayed_work(&clp->cl_renewd, timeout); |
124 | set_bit(NFS_CS_RENEWD, &clp->cl_res_state); | ||
124 | spin_unlock(&clp->cl_lock); | 125 | spin_unlock(&clp->cl_lock); |
125 | } | 126 | } |
126 | 127 | ||
127 | void | 128 | void |
128 | nfs4_renewd_prepare_shutdown(struct nfs_server *server) | 129 | nfs4_renewd_prepare_shutdown(struct nfs_server *server) |
129 | { | 130 | { |
130 | struct nfs4_client *clp = server->nfs4_state; | ||
131 | |||
132 | if (!clp) | ||
133 | return; | ||
134 | flush_scheduled_work(); | 131 | flush_scheduled_work(); |
135 | down_write(&clp->cl_sem); | ||
136 | if (!list_empty(&server->nfs4_siblings)) | ||
137 | list_del_init(&server->nfs4_siblings); | ||
138 | up_write(&clp->cl_sem); | ||
139 | } | 132 | } |
140 | 133 | ||
141 | /* Must be called with clp->cl_sem locked for writes */ | ||
142 | void | 134 | void |
143 | nfs4_kill_renewd(struct nfs4_client *clp) | 135 | nfs4_kill_renewd(struct nfs_client *clp) |
144 | { | 136 | { |
145 | down_read(&clp->cl_sem); | 137 | down_read(&clp->cl_sem); |
146 | if (!list_empty(&clp->cl_superblocks)) { | ||
147 | up_read(&clp->cl_sem); | ||
148 | return; | ||
149 | } | ||
150 | cancel_delayed_work(&clp->cl_renewd); | 138 | cancel_delayed_work(&clp->cl_renewd); |
151 | up_read(&clp->cl_sem); | 139 | up_read(&clp->cl_sem); |
152 | flush_scheduled_work(); | 140 | flush_scheduled_work(); |
diff --git a/fs/nfs/nfs4state.c b/fs/nfs/nfs4state.c index 090a36b07a22..5fffbdfa971f 100644 --- a/fs/nfs/nfs4state.c +++ b/fs/nfs/nfs4state.c | |||
@@ -50,149 +50,15 @@ | |||
50 | #include "nfs4_fs.h" | 50 | #include "nfs4_fs.h" |
51 | #include "callback.h" | 51 | #include "callback.h" |
52 | #include "delegation.h" | 52 | #include "delegation.h" |
53 | #include "internal.h" | ||
53 | 54 | ||
54 | #define OPENOWNER_POOL_SIZE 8 | 55 | #define OPENOWNER_POOL_SIZE 8 |
55 | 56 | ||
56 | const nfs4_stateid zero_stateid; | 57 | const nfs4_stateid zero_stateid; |
57 | 58 | ||
58 | static DEFINE_SPINLOCK(state_spinlock); | ||
59 | static LIST_HEAD(nfs4_clientid_list); | 59 | static LIST_HEAD(nfs4_clientid_list); |
60 | 60 | ||
61 | void | 61 | static int nfs4_init_client(struct nfs_client *clp, struct rpc_cred *cred) |
62 | init_nfsv4_state(struct nfs_server *server) | ||
63 | { | ||
64 | server->nfs4_state = NULL; | ||
65 | INIT_LIST_HEAD(&server->nfs4_siblings); | ||
66 | } | ||
67 | |||
68 | void | ||
69 | destroy_nfsv4_state(struct nfs_server *server) | ||
70 | { | ||
71 | kfree(server->mnt_path); | ||
72 | server->mnt_path = NULL; | ||
73 | if (server->nfs4_state) { | ||
74 | nfs4_put_client(server->nfs4_state); | ||
75 | server->nfs4_state = NULL; | ||
76 | } | ||
77 | } | ||
78 | |||
79 | /* | ||
80 | * nfs4_get_client(): returns an empty client structure | ||
81 | * nfs4_put_client(): drops reference to client structure | ||
82 | * | ||
83 | * Since these are allocated/deallocated very rarely, we don't | ||
84 | * bother putting them in a slab cache... | ||
85 | */ | ||
86 | static struct nfs4_client * | ||
87 | nfs4_alloc_client(struct in_addr *addr) | ||
88 | { | ||
89 | struct nfs4_client *clp; | ||
90 | |||
91 | if (nfs_callback_up() < 0) | ||
92 | return NULL; | ||
93 | if ((clp = kzalloc(sizeof(*clp), GFP_KERNEL)) == NULL) { | ||
94 | nfs_callback_down(); | ||
95 | return NULL; | ||
96 | } | ||
97 | memcpy(&clp->cl_addr, addr, sizeof(clp->cl_addr)); | ||
98 | init_rwsem(&clp->cl_sem); | ||
99 | INIT_LIST_HEAD(&clp->cl_delegations); | ||
100 | INIT_LIST_HEAD(&clp->cl_state_owners); | ||
101 | INIT_LIST_HEAD(&clp->cl_unused); | ||
102 | spin_lock_init(&clp->cl_lock); | ||
103 | atomic_set(&clp->cl_count, 1); | ||
104 | INIT_WORK(&clp->cl_renewd, nfs4_renew_state, clp); | ||
105 | INIT_LIST_HEAD(&clp->cl_superblocks); | ||
106 | rpc_init_wait_queue(&clp->cl_rpcwaitq, "NFS4 client"); | ||
107 | clp->cl_rpcclient = ERR_PTR(-EINVAL); | ||
108 | clp->cl_boot_time = CURRENT_TIME; | ||
109 | clp->cl_state = 1 << NFS4CLNT_LEASE_EXPIRED; | ||
110 | return clp; | ||
111 | } | ||
112 | |||
113 | static void | ||
114 | nfs4_free_client(struct nfs4_client *clp) | ||
115 | { | ||
116 | struct nfs4_state_owner *sp; | ||
117 | |||
118 | while (!list_empty(&clp->cl_unused)) { | ||
119 | sp = list_entry(clp->cl_unused.next, | ||
120 | struct nfs4_state_owner, | ||
121 | so_list); | ||
122 | list_del(&sp->so_list); | ||
123 | kfree(sp); | ||
124 | } | ||
125 | BUG_ON(!list_empty(&clp->cl_state_owners)); | ||
126 | nfs_idmap_delete(clp); | ||
127 | if (!IS_ERR(clp->cl_rpcclient)) | ||
128 | rpc_shutdown_client(clp->cl_rpcclient); | ||
129 | kfree(clp); | ||
130 | nfs_callback_down(); | ||
131 | } | ||
132 | |||
133 | static struct nfs4_client *__nfs4_find_client(struct in_addr *addr) | ||
134 | { | ||
135 | struct nfs4_client *clp; | ||
136 | list_for_each_entry(clp, &nfs4_clientid_list, cl_servers) { | ||
137 | if (memcmp(&clp->cl_addr, addr, sizeof(clp->cl_addr)) == 0) { | ||
138 | atomic_inc(&clp->cl_count); | ||
139 | return clp; | ||
140 | } | ||
141 | } | ||
142 | return NULL; | ||
143 | } | ||
144 | |||
145 | struct nfs4_client *nfs4_find_client(struct in_addr *addr) | ||
146 | { | ||
147 | struct nfs4_client *clp; | ||
148 | spin_lock(&state_spinlock); | ||
149 | clp = __nfs4_find_client(addr); | ||
150 | spin_unlock(&state_spinlock); | ||
151 | return clp; | ||
152 | } | ||
153 | |||
154 | struct nfs4_client * | ||
155 | nfs4_get_client(struct in_addr *addr) | ||
156 | { | ||
157 | struct nfs4_client *clp, *new = NULL; | ||
158 | |||
159 | spin_lock(&state_spinlock); | ||
160 | for (;;) { | ||
161 | clp = __nfs4_find_client(addr); | ||
162 | if (clp != NULL) | ||
163 | break; | ||
164 | clp = new; | ||
165 | if (clp != NULL) { | ||
166 | list_add(&clp->cl_servers, &nfs4_clientid_list); | ||
167 | new = NULL; | ||
168 | break; | ||
169 | } | ||
170 | spin_unlock(&state_spinlock); | ||
171 | new = nfs4_alloc_client(addr); | ||
172 | spin_lock(&state_spinlock); | ||
173 | if (new == NULL) | ||
174 | break; | ||
175 | } | ||
176 | spin_unlock(&state_spinlock); | ||
177 | if (new) | ||
178 | nfs4_free_client(new); | ||
179 | return clp; | ||
180 | } | ||
181 | |||
182 | void | ||
183 | nfs4_put_client(struct nfs4_client *clp) | ||
184 | { | ||
185 | if (!atomic_dec_and_lock(&clp->cl_count, &state_spinlock)) | ||
186 | return; | ||
187 | list_del(&clp->cl_servers); | ||
188 | spin_unlock(&state_spinlock); | ||
189 | BUG_ON(!list_empty(&clp->cl_superblocks)); | ||
190 | rpc_wake_up(&clp->cl_rpcwaitq); | ||
191 | nfs4_kill_renewd(clp); | ||
192 | nfs4_free_client(clp); | ||
193 | } | ||
194 | |||
195 | static int nfs4_init_client(struct nfs4_client *clp, struct rpc_cred *cred) | ||
196 | { | 62 | { |
197 | int status = nfs4_proc_setclientid(clp, NFS4_CALLBACK, | 63 | int status = nfs4_proc_setclientid(clp, NFS4_CALLBACK, |
198 | nfs_callback_tcpport, cred); | 64 | nfs_callback_tcpport, cred); |
@@ -204,13 +70,13 @@ static int nfs4_init_client(struct nfs4_client *clp, struct rpc_cred *cred) | |||
204 | } | 70 | } |
205 | 71 | ||
206 | u32 | 72 | u32 |
207 | nfs4_alloc_lockowner_id(struct nfs4_client *clp) | 73 | nfs4_alloc_lockowner_id(struct nfs_client *clp) |
208 | { | 74 | { |
209 | return clp->cl_lockowner_id ++; | 75 | return clp->cl_lockowner_id ++; |
210 | } | 76 | } |
211 | 77 | ||
212 | static struct nfs4_state_owner * | 78 | static struct nfs4_state_owner * |
213 | nfs4_client_grab_unused(struct nfs4_client *clp, struct rpc_cred *cred) | 79 | nfs4_client_grab_unused(struct nfs_client *clp, struct rpc_cred *cred) |
214 | { | 80 | { |
215 | struct nfs4_state_owner *sp = NULL; | 81 | struct nfs4_state_owner *sp = NULL; |
216 | 82 | ||
@@ -224,7 +90,7 @@ nfs4_client_grab_unused(struct nfs4_client *clp, struct rpc_cred *cred) | |||
224 | return sp; | 90 | return sp; |
225 | } | 91 | } |
226 | 92 | ||
227 | struct rpc_cred *nfs4_get_renew_cred(struct nfs4_client *clp) | 93 | struct rpc_cred *nfs4_get_renew_cred(struct nfs_client *clp) |
228 | { | 94 | { |
229 | struct nfs4_state_owner *sp; | 95 | struct nfs4_state_owner *sp; |
230 | struct rpc_cred *cred = NULL; | 96 | struct rpc_cred *cred = NULL; |
@@ -238,7 +104,7 @@ struct rpc_cred *nfs4_get_renew_cred(struct nfs4_client *clp) | |||
238 | return cred; | 104 | return cred; |
239 | } | 105 | } |
240 | 106 | ||
241 | struct rpc_cred *nfs4_get_setclientid_cred(struct nfs4_client *clp) | 107 | struct rpc_cred *nfs4_get_setclientid_cred(struct nfs_client *clp) |
242 | { | 108 | { |
243 | struct nfs4_state_owner *sp; | 109 | struct nfs4_state_owner *sp; |
244 | 110 | ||
@@ -251,7 +117,7 @@ struct rpc_cred *nfs4_get_setclientid_cred(struct nfs4_client *clp) | |||
251 | } | 117 | } |
252 | 118 | ||
253 | static struct nfs4_state_owner * | 119 | static struct nfs4_state_owner * |
254 | nfs4_find_state_owner(struct nfs4_client *clp, struct rpc_cred *cred) | 120 | nfs4_find_state_owner(struct nfs_client *clp, struct rpc_cred *cred) |
255 | { | 121 | { |
256 | struct nfs4_state_owner *sp, *res = NULL; | 122 | struct nfs4_state_owner *sp, *res = NULL; |
257 | 123 | ||
@@ -294,7 +160,7 @@ nfs4_alloc_state_owner(void) | |||
294 | void | 160 | void |
295 | nfs4_drop_state_owner(struct nfs4_state_owner *sp) | 161 | nfs4_drop_state_owner(struct nfs4_state_owner *sp) |
296 | { | 162 | { |
297 | struct nfs4_client *clp = sp->so_client; | 163 | struct nfs_client *clp = sp->so_client; |
298 | spin_lock(&clp->cl_lock); | 164 | spin_lock(&clp->cl_lock); |
299 | list_del_init(&sp->so_list); | 165 | list_del_init(&sp->so_list); |
300 | spin_unlock(&clp->cl_lock); | 166 | spin_unlock(&clp->cl_lock); |
@@ -306,7 +172,7 @@ nfs4_drop_state_owner(struct nfs4_state_owner *sp) | |||
306 | */ | 172 | */ |
307 | struct nfs4_state_owner *nfs4_get_state_owner(struct nfs_server *server, struct rpc_cred *cred) | 173 | struct nfs4_state_owner *nfs4_get_state_owner(struct nfs_server *server, struct rpc_cred *cred) |
308 | { | 174 | { |
309 | struct nfs4_client *clp = server->nfs4_state; | 175 | struct nfs_client *clp = server->nfs_client; |
310 | struct nfs4_state_owner *sp, *new; | 176 | struct nfs4_state_owner *sp, *new; |
311 | 177 | ||
312 | get_rpccred(cred); | 178 | get_rpccred(cred); |
@@ -337,7 +203,7 @@ struct nfs4_state_owner *nfs4_get_state_owner(struct nfs_server *server, struct | |||
337 | */ | 203 | */ |
338 | void nfs4_put_state_owner(struct nfs4_state_owner *sp) | 204 | void nfs4_put_state_owner(struct nfs4_state_owner *sp) |
339 | { | 205 | { |
340 | struct nfs4_client *clp = sp->so_client; | 206 | struct nfs_client *clp = sp->so_client; |
341 | struct rpc_cred *cred = sp->so_cred; | 207 | struct rpc_cred *cred = sp->so_cred; |
342 | 208 | ||
343 | if (!atomic_dec_and_lock(&sp->so_count, &clp->cl_lock)) | 209 | if (!atomic_dec_and_lock(&sp->so_count, &clp->cl_lock)) |
@@ -540,7 +406,7 @@ __nfs4_find_lock_state(struct nfs4_state *state, fl_owner_t fl_owner) | |||
540 | static struct nfs4_lock_state *nfs4_alloc_lock_state(struct nfs4_state *state, fl_owner_t fl_owner) | 406 | static struct nfs4_lock_state *nfs4_alloc_lock_state(struct nfs4_state *state, fl_owner_t fl_owner) |
541 | { | 407 | { |
542 | struct nfs4_lock_state *lsp; | 408 | struct nfs4_lock_state *lsp; |
543 | struct nfs4_client *clp = state->owner->so_client; | 409 | struct nfs_client *clp = state->owner->so_client; |
544 | 410 | ||
545 | lsp = kzalloc(sizeof(*lsp), GFP_KERNEL); | 411 | lsp = kzalloc(sizeof(*lsp), GFP_KERNEL); |
546 | if (lsp == NULL) | 412 | if (lsp == NULL) |
@@ -752,7 +618,7 @@ out: | |||
752 | 618 | ||
753 | static int reclaimer(void *); | 619 | static int reclaimer(void *); |
754 | 620 | ||
755 | static inline void nfs4_clear_recover_bit(struct nfs4_client *clp) | 621 | static inline void nfs4_clear_recover_bit(struct nfs_client *clp) |
756 | { | 622 | { |
757 | smp_mb__before_clear_bit(); | 623 | smp_mb__before_clear_bit(); |
758 | clear_bit(NFS4CLNT_STATE_RECOVER, &clp->cl_state); | 624 | clear_bit(NFS4CLNT_STATE_RECOVER, &clp->cl_state); |
@@ -764,25 +630,25 @@ static inline void nfs4_clear_recover_bit(struct nfs4_client *clp) | |||
764 | /* | 630 | /* |
765 | * State recovery routine | 631 | * State recovery routine |
766 | */ | 632 | */ |
767 | static void nfs4_recover_state(struct nfs4_client *clp) | 633 | static void nfs4_recover_state(struct nfs_client *clp) |
768 | { | 634 | { |
769 | struct task_struct *task; | 635 | struct task_struct *task; |
770 | 636 | ||
771 | __module_get(THIS_MODULE); | 637 | __module_get(THIS_MODULE); |
772 | atomic_inc(&clp->cl_count); | 638 | atomic_inc(&clp->cl_count); |
773 | task = kthread_run(reclaimer, clp, "%u.%u.%u.%u-reclaim", | 639 | task = kthread_run(reclaimer, clp, "%u.%u.%u.%u-reclaim", |
774 | NIPQUAD(clp->cl_addr)); | 640 | NIPQUAD(clp->cl_addr.sin_addr)); |
775 | if (!IS_ERR(task)) | 641 | if (!IS_ERR(task)) |
776 | return; | 642 | return; |
777 | nfs4_clear_recover_bit(clp); | 643 | nfs4_clear_recover_bit(clp); |
778 | nfs4_put_client(clp); | 644 | nfs_put_client(clp); |
779 | module_put(THIS_MODULE); | 645 | module_put(THIS_MODULE); |
780 | } | 646 | } |
781 | 647 | ||
782 | /* | 648 | /* |
783 | * Schedule a state recovery attempt | 649 | * Schedule a state recovery attempt |
784 | */ | 650 | */ |
785 | void nfs4_schedule_state_recovery(struct nfs4_client *clp) | 651 | void nfs4_schedule_state_recovery(struct nfs_client *clp) |
786 | { | 652 | { |
787 | if (!clp) | 653 | if (!clp) |
788 | return; | 654 | return; |
@@ -879,7 +745,7 @@ out_err: | |||
879 | return status; | 745 | return status; |
880 | } | 746 | } |
881 | 747 | ||
882 | static void nfs4_state_mark_reclaim(struct nfs4_client *clp) | 748 | static void nfs4_state_mark_reclaim(struct nfs_client *clp) |
883 | { | 749 | { |
884 | struct nfs4_state_owner *sp; | 750 | struct nfs4_state_owner *sp; |
885 | struct nfs4_state *state; | 751 | struct nfs4_state *state; |
@@ -903,7 +769,7 @@ static void nfs4_state_mark_reclaim(struct nfs4_client *clp) | |||
903 | 769 | ||
904 | static int reclaimer(void *ptr) | 770 | static int reclaimer(void *ptr) |
905 | { | 771 | { |
906 | struct nfs4_client *clp = ptr; | 772 | struct nfs_client *clp = ptr; |
907 | struct nfs4_state_owner *sp; | 773 | struct nfs4_state_owner *sp; |
908 | struct nfs4_state_recovery_ops *ops; | 774 | struct nfs4_state_recovery_ops *ops; |
909 | struct rpc_cred *cred; | 775 | struct rpc_cred *cred; |
@@ -970,12 +836,12 @@ out: | |||
970 | if (status == -NFS4ERR_CB_PATH_DOWN) | 836 | if (status == -NFS4ERR_CB_PATH_DOWN) |
971 | nfs_handle_cb_pathdown(clp); | 837 | nfs_handle_cb_pathdown(clp); |
972 | nfs4_clear_recover_bit(clp); | 838 | nfs4_clear_recover_bit(clp); |
973 | nfs4_put_client(clp); | 839 | nfs_put_client(clp); |
974 | module_put_and_exit(0); | 840 | module_put_and_exit(0); |
975 | return 0; | 841 | return 0; |
976 | out_error: | 842 | out_error: |
977 | printk(KERN_WARNING "Error: state recovery failed on NFSv4 server %u.%u.%u.%u with error %d\n", | 843 | printk(KERN_WARNING "Error: state recovery failed on NFSv4 server %u.%u.%u.%u with error %d\n", |
978 | NIPQUAD(clp->cl_addr.s_addr), -status); | 844 | NIPQUAD(clp->cl_addr.sin_addr), -status); |
979 | set_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state); | 845 | set_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state); |
980 | goto out; | 846 | goto out; |
981 | } | 847 | } |
diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c index 730ec8fb31c6..3dd413f52da1 100644 --- a/fs/nfs/nfs4xdr.c +++ b/fs/nfs/nfs4xdr.c | |||
@@ -58,7 +58,7 @@ | |||
58 | /* Mapping from NFS error code to "errno" error code. */ | 58 | /* Mapping from NFS error code to "errno" error code. */ |
59 | #define errno_NFSERR_IO EIO | 59 | #define errno_NFSERR_IO EIO |
60 | 60 | ||
61 | static int nfs_stat_to_errno(int); | 61 | static int nfs4_stat_to_errno(int); |
62 | 62 | ||
63 | /* NFSv4 COMPOUND tags are only wanted for debugging purposes */ | 63 | /* NFSv4 COMPOUND tags are only wanted for debugging purposes */ |
64 | #ifdef DEBUG | 64 | #ifdef DEBUG |
@@ -128,7 +128,7 @@ static int nfs_stat_to_errno(int); | |||
128 | #define decode_link_maxsz (op_decode_hdr_maxsz + 5) | 128 | #define decode_link_maxsz (op_decode_hdr_maxsz + 5) |
129 | #define encode_symlink_maxsz (op_encode_hdr_maxsz + \ | 129 | #define encode_symlink_maxsz (op_encode_hdr_maxsz + \ |
130 | 1 + nfs4_name_maxsz + \ | 130 | 1 + nfs4_name_maxsz + \ |
131 | nfs4_path_maxsz + \ | 131 | 1 + \ |
132 | nfs4_fattr_maxsz) | 132 | nfs4_fattr_maxsz) |
133 | #define decode_symlink_maxsz (op_decode_hdr_maxsz + 8) | 133 | #define decode_symlink_maxsz (op_decode_hdr_maxsz + 8) |
134 | #define encode_create_maxsz (op_encode_hdr_maxsz + \ | 134 | #define encode_create_maxsz (op_encode_hdr_maxsz + \ |
@@ -529,7 +529,7 @@ static int encode_attrs(struct xdr_stream *xdr, const struct iattr *iap, const s | |||
529 | if (iap->ia_valid & ATTR_MODE) | 529 | if (iap->ia_valid & ATTR_MODE) |
530 | len += 4; | 530 | len += 4; |
531 | if (iap->ia_valid & ATTR_UID) { | 531 | if (iap->ia_valid & ATTR_UID) { |
532 | owner_namelen = nfs_map_uid_to_name(server->nfs4_state, iap->ia_uid, owner_name); | 532 | owner_namelen = nfs_map_uid_to_name(server->nfs_client, iap->ia_uid, owner_name); |
533 | if (owner_namelen < 0) { | 533 | if (owner_namelen < 0) { |
534 | printk(KERN_WARNING "nfs: couldn't resolve uid %d to string\n", | 534 | printk(KERN_WARNING "nfs: couldn't resolve uid %d to string\n", |
535 | iap->ia_uid); | 535 | iap->ia_uid); |
@@ -541,7 +541,7 @@ static int encode_attrs(struct xdr_stream *xdr, const struct iattr *iap, const s | |||
541 | len += 4 + (XDR_QUADLEN(owner_namelen) << 2); | 541 | len += 4 + (XDR_QUADLEN(owner_namelen) << 2); |
542 | } | 542 | } |
543 | if (iap->ia_valid & ATTR_GID) { | 543 | if (iap->ia_valid & ATTR_GID) { |
544 | owner_grouplen = nfs_map_gid_to_group(server->nfs4_state, iap->ia_gid, owner_group); | 544 | owner_grouplen = nfs_map_gid_to_group(server->nfs_client, iap->ia_gid, owner_group); |
545 | if (owner_grouplen < 0) { | 545 | if (owner_grouplen < 0) { |
546 | printk(KERN_WARNING "nfs4: couldn't resolve gid %d to string\n", | 546 | printk(KERN_WARNING "nfs4: couldn't resolve gid %d to string\n", |
547 | iap->ia_gid); | 547 | iap->ia_gid); |
@@ -673,9 +673,9 @@ static int encode_create(struct xdr_stream *xdr, const struct nfs4_create_arg *c | |||
673 | 673 | ||
674 | switch (create->ftype) { | 674 | switch (create->ftype) { |
675 | case NF4LNK: | 675 | case NF4LNK: |
676 | RESERVE_SPACE(4 + create->u.symlink->len); | 676 | RESERVE_SPACE(4); |
677 | WRITE32(create->u.symlink->len); | 677 | WRITE32(create->u.symlink.len); |
678 | WRITEMEM(create->u.symlink->name, create->u.symlink->len); | 678 | xdr_write_pages(xdr, create->u.symlink.pages, 0, create->u.symlink.len); |
679 | break; | 679 | break; |
680 | 680 | ||
681 | case NF4BLK: case NF4CHR: | 681 | case NF4BLK: case NF4CHR: |
@@ -1160,7 +1160,7 @@ static int encode_rename(struct xdr_stream *xdr, const struct qstr *oldname, con | |||
1160 | return 0; | 1160 | return 0; |
1161 | } | 1161 | } |
1162 | 1162 | ||
1163 | static int encode_renew(struct xdr_stream *xdr, const struct nfs4_client *client_stateid) | 1163 | static int encode_renew(struct xdr_stream *xdr, const struct nfs_client *client_stateid) |
1164 | { | 1164 | { |
1165 | uint32_t *p; | 1165 | uint32_t *p; |
1166 | 1166 | ||
@@ -1246,7 +1246,7 @@ static int encode_setclientid(struct xdr_stream *xdr, const struct nfs4_setclien | |||
1246 | return 0; | 1246 | return 0; |
1247 | } | 1247 | } |
1248 | 1248 | ||
1249 | static int encode_setclientid_confirm(struct xdr_stream *xdr, const struct nfs4_client *client_state) | 1249 | static int encode_setclientid_confirm(struct xdr_stream *xdr, const struct nfs_client *client_state) |
1250 | { | 1250 | { |
1251 | uint32_t *p; | 1251 | uint32_t *p; |
1252 | 1252 | ||
@@ -1945,7 +1945,7 @@ static int nfs4_xdr_enc_server_caps(struct rpc_rqst *req, uint32_t *p, const str | |||
1945 | /* | 1945 | /* |
1946 | * a RENEW request | 1946 | * a RENEW request |
1947 | */ | 1947 | */ |
1948 | static int nfs4_xdr_enc_renew(struct rpc_rqst *req, uint32_t *p, struct nfs4_client *clp) | 1948 | static int nfs4_xdr_enc_renew(struct rpc_rqst *req, uint32_t *p, struct nfs_client *clp) |
1949 | { | 1949 | { |
1950 | struct xdr_stream xdr; | 1950 | struct xdr_stream xdr; |
1951 | struct compound_hdr hdr = { | 1951 | struct compound_hdr hdr = { |
@@ -1975,7 +1975,7 @@ static int nfs4_xdr_enc_setclientid(struct rpc_rqst *req, uint32_t *p, struct nf | |||
1975 | /* | 1975 | /* |
1976 | * a SETCLIENTID_CONFIRM request | 1976 | * a SETCLIENTID_CONFIRM request |
1977 | */ | 1977 | */ |
1978 | static int nfs4_xdr_enc_setclientid_confirm(struct rpc_rqst *req, uint32_t *p, struct nfs4_client *clp) | 1978 | static int nfs4_xdr_enc_setclientid_confirm(struct rpc_rqst *req, uint32_t *p, struct nfs_client *clp) |
1979 | { | 1979 | { |
1980 | struct xdr_stream xdr; | 1980 | struct xdr_stream xdr; |
1981 | struct compound_hdr hdr = { | 1981 | struct compound_hdr hdr = { |
@@ -2127,12 +2127,12 @@ static int decode_op_hdr(struct xdr_stream *xdr, enum nfs_opnum4 expected) | |||
2127 | } | 2127 | } |
2128 | READ32(nfserr); | 2128 | READ32(nfserr); |
2129 | if (nfserr != NFS_OK) | 2129 | if (nfserr != NFS_OK) |
2130 | return -nfs_stat_to_errno(nfserr); | 2130 | return -nfs4_stat_to_errno(nfserr); |
2131 | return 0; | 2131 | return 0; |
2132 | } | 2132 | } |
2133 | 2133 | ||
2134 | /* Dummy routine */ | 2134 | /* Dummy routine */ |
2135 | static int decode_ace(struct xdr_stream *xdr, void *ace, struct nfs4_client *clp) | 2135 | static int decode_ace(struct xdr_stream *xdr, void *ace, struct nfs_client *clp) |
2136 | { | 2136 | { |
2137 | uint32_t *p; | 2137 | uint32_t *p; |
2138 | unsigned int strlen; | 2138 | unsigned int strlen; |
@@ -2636,7 +2636,7 @@ static int decode_attr_nlink(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t | |||
2636 | return 0; | 2636 | return 0; |
2637 | } | 2637 | } |
2638 | 2638 | ||
2639 | static int decode_attr_owner(struct xdr_stream *xdr, uint32_t *bitmap, struct nfs4_client *clp, int32_t *uid) | 2639 | static int decode_attr_owner(struct xdr_stream *xdr, uint32_t *bitmap, struct nfs_client *clp, int32_t *uid) |
2640 | { | 2640 | { |
2641 | uint32_t len, *p; | 2641 | uint32_t len, *p; |
2642 | 2642 | ||
@@ -2660,7 +2660,7 @@ static int decode_attr_owner(struct xdr_stream *xdr, uint32_t *bitmap, struct nf | |||
2660 | return 0; | 2660 | return 0; |
2661 | } | 2661 | } |
2662 | 2662 | ||
2663 | static int decode_attr_group(struct xdr_stream *xdr, uint32_t *bitmap, struct nfs4_client *clp, int32_t *gid) | 2663 | static int decode_attr_group(struct xdr_stream *xdr, uint32_t *bitmap, struct nfs_client *clp, int32_t *gid) |
2664 | { | 2664 | { |
2665 | uint32_t len, *p; | 2665 | uint32_t len, *p; |
2666 | 2666 | ||
@@ -3051,9 +3051,9 @@ static int decode_getfattr(struct xdr_stream *xdr, struct nfs_fattr *fattr, cons | |||
3051 | fattr->mode |= fmode; | 3051 | fattr->mode |= fmode; |
3052 | if ((status = decode_attr_nlink(xdr, bitmap, &fattr->nlink)) != 0) | 3052 | if ((status = decode_attr_nlink(xdr, bitmap, &fattr->nlink)) != 0) |
3053 | goto xdr_error; | 3053 | goto xdr_error; |
3054 | if ((status = decode_attr_owner(xdr, bitmap, server->nfs4_state, &fattr->uid)) != 0) | 3054 | if ((status = decode_attr_owner(xdr, bitmap, server->nfs_client, &fattr->uid)) != 0) |
3055 | goto xdr_error; | 3055 | goto xdr_error; |
3056 | if ((status = decode_attr_group(xdr, bitmap, server->nfs4_state, &fattr->gid)) != 0) | 3056 | if ((status = decode_attr_group(xdr, bitmap, server->nfs_client, &fattr->gid)) != 0) |
3057 | goto xdr_error; | 3057 | goto xdr_error; |
3058 | if ((status = decode_attr_rdev(xdr, bitmap, &fattr->rdev)) != 0) | 3058 | if ((status = decode_attr_rdev(xdr, bitmap, &fattr->rdev)) != 0) |
3059 | goto xdr_error; | 3059 | goto xdr_error; |
@@ -3254,7 +3254,7 @@ static int decode_delegation(struct xdr_stream *xdr, struct nfs_openres *res) | |||
3254 | if (decode_space_limit(xdr, &res->maxsize) < 0) | 3254 | if (decode_space_limit(xdr, &res->maxsize) < 0) |
3255 | return -EIO; | 3255 | return -EIO; |
3256 | } | 3256 | } |
3257 | return decode_ace(xdr, NULL, res->server->nfs4_state); | 3257 | return decode_ace(xdr, NULL, res->server->nfs_client); |
3258 | } | 3258 | } |
3259 | 3259 | ||
3260 | static int decode_open(struct xdr_stream *xdr, struct nfs_openres *res) | 3260 | static int decode_open(struct xdr_stream *xdr, struct nfs_openres *res) |
@@ -3565,7 +3565,7 @@ static int decode_setattr(struct xdr_stream *xdr, struct nfs_setattrres *res) | |||
3565 | return 0; | 3565 | return 0; |
3566 | } | 3566 | } |
3567 | 3567 | ||
3568 | static int decode_setclientid(struct xdr_stream *xdr, struct nfs4_client *clp) | 3568 | static int decode_setclientid(struct xdr_stream *xdr, struct nfs_client *clp) |
3569 | { | 3569 | { |
3570 | uint32_t *p; | 3570 | uint32_t *p; |
3571 | uint32_t opnum; | 3571 | uint32_t opnum; |
@@ -3598,7 +3598,7 @@ static int decode_setclientid(struct xdr_stream *xdr, struct nfs4_client *clp) | |||
3598 | READ_BUF(len); | 3598 | READ_BUF(len); |
3599 | return -NFSERR_CLID_INUSE; | 3599 | return -NFSERR_CLID_INUSE; |
3600 | } else | 3600 | } else |
3601 | return -nfs_stat_to_errno(nfserr); | 3601 | return -nfs4_stat_to_errno(nfserr); |
3602 | 3602 | ||
3603 | return 0; | 3603 | return 0; |
3604 | } | 3604 | } |
@@ -4256,7 +4256,7 @@ static int nfs4_xdr_dec_fsinfo(struct rpc_rqst *req, uint32_t *p, struct nfs_fsi | |||
4256 | if (!status) | 4256 | if (!status) |
4257 | status = decode_fsinfo(&xdr, fsinfo); | 4257 | status = decode_fsinfo(&xdr, fsinfo); |
4258 | if (!status) | 4258 | if (!status) |
4259 | status = -nfs_stat_to_errno(hdr.status); | 4259 | status = -nfs4_stat_to_errno(hdr.status); |
4260 | return status; | 4260 | return status; |
4261 | } | 4261 | } |
4262 | 4262 | ||
@@ -4335,7 +4335,7 @@ static int nfs4_xdr_dec_renew(struct rpc_rqst *rqstp, uint32_t *p, void *dummy) | |||
4335 | * a SETCLIENTID request | 4335 | * a SETCLIENTID request |
4336 | */ | 4336 | */ |
4337 | static int nfs4_xdr_dec_setclientid(struct rpc_rqst *req, uint32_t *p, | 4337 | static int nfs4_xdr_dec_setclientid(struct rpc_rqst *req, uint32_t *p, |
4338 | struct nfs4_client *clp) | 4338 | struct nfs_client *clp) |
4339 | { | 4339 | { |
4340 | struct xdr_stream xdr; | 4340 | struct xdr_stream xdr; |
4341 | struct compound_hdr hdr; | 4341 | struct compound_hdr hdr; |
@@ -4346,7 +4346,7 @@ static int nfs4_xdr_dec_setclientid(struct rpc_rqst *req, uint32_t *p, | |||
4346 | if (!status) | 4346 | if (!status) |
4347 | status = decode_setclientid(&xdr, clp); | 4347 | status = decode_setclientid(&xdr, clp); |
4348 | if (!status) | 4348 | if (!status) |
4349 | status = -nfs_stat_to_errno(hdr.status); | 4349 | status = -nfs4_stat_to_errno(hdr.status); |
4350 | return status; | 4350 | return status; |
4351 | } | 4351 | } |
4352 | 4352 | ||
@@ -4368,7 +4368,7 @@ static int nfs4_xdr_dec_setclientid_confirm(struct rpc_rqst *req, uint32_t *p, s | |||
4368 | if (!status) | 4368 | if (!status) |
4369 | status = decode_fsinfo(&xdr, fsinfo); | 4369 | status = decode_fsinfo(&xdr, fsinfo); |
4370 | if (!status) | 4370 | if (!status) |
4371 | status = -nfs_stat_to_errno(hdr.status); | 4371 | status = -nfs4_stat_to_errno(hdr.status); |
4372 | return status; | 4372 | return status; |
4373 | } | 4373 | } |
4374 | 4374 | ||
@@ -4521,7 +4521,7 @@ static struct { | |||
4521 | * This one is used jointly by NFSv2 and NFSv3. | 4521 | * This one is used jointly by NFSv2 and NFSv3. |
4522 | */ | 4522 | */ |
4523 | static int | 4523 | static int |
4524 | nfs_stat_to_errno(int stat) | 4524 | nfs4_stat_to_errno(int stat) |
4525 | { | 4525 | { |
4526 | int i; | 4526 | int i; |
4527 | for (i = 0; nfs_errtbl[i].stat != -1; i++) { | 4527 | for (i = 0; nfs_errtbl[i].stat != -1; i++) { |
diff --git a/fs/nfs/proc.c b/fs/nfs/proc.c index b3899ea3229e..630e50647bbb 100644 --- a/fs/nfs/proc.c +++ b/fs/nfs/proc.c | |||
@@ -66,14 +66,14 @@ nfs_proc_get_root(struct nfs_server *server, struct nfs_fh *fhandle, | |||
66 | 66 | ||
67 | dprintk("%s: call getattr\n", __FUNCTION__); | 67 | dprintk("%s: call getattr\n", __FUNCTION__); |
68 | nfs_fattr_init(fattr); | 68 | nfs_fattr_init(fattr); |
69 | status = rpc_call_sync(server->client_sys, &msg, 0); | 69 | status = rpc_call_sync(server->nfs_client->cl_rpcclient, &msg, 0); |
70 | dprintk("%s: reply getattr: %d\n", __FUNCTION__, status); | 70 | dprintk("%s: reply getattr: %d\n", __FUNCTION__, status); |
71 | if (status) | 71 | if (status) |
72 | return status; | 72 | return status; |
73 | dprintk("%s: call statfs\n", __FUNCTION__); | 73 | dprintk("%s: call statfs\n", __FUNCTION__); |
74 | msg.rpc_proc = &nfs_procedures[NFSPROC_STATFS]; | 74 | msg.rpc_proc = &nfs_procedures[NFSPROC_STATFS]; |
75 | msg.rpc_resp = &fsinfo; | 75 | msg.rpc_resp = &fsinfo; |
76 | status = rpc_call_sync(server->client_sys, &msg, 0); | 76 | status = rpc_call_sync(server->nfs_client->cl_rpcclient, &msg, 0); |
77 | dprintk("%s: reply statfs: %d\n", __FUNCTION__, status); | 77 | dprintk("%s: reply statfs: %d\n", __FUNCTION__, status); |
78 | if (status) | 78 | if (status) |
79 | return status; | 79 | return status; |
@@ -425,16 +425,17 @@ nfs_proc_link(struct inode *inode, struct inode *dir, struct qstr *name) | |||
425 | } | 425 | } |
426 | 426 | ||
427 | static int | 427 | static int |
428 | nfs_proc_symlink(struct inode *dir, struct qstr *name, struct qstr *path, | 428 | nfs_proc_symlink(struct inode *dir, struct dentry *dentry, struct page *page, |
429 | struct iattr *sattr, struct nfs_fh *fhandle, | 429 | unsigned int len, struct iattr *sattr) |
430 | struct nfs_fattr *fattr) | ||
431 | { | 430 | { |
431 | struct nfs_fh fhandle; | ||
432 | struct nfs_fattr fattr; | ||
432 | struct nfs_symlinkargs arg = { | 433 | struct nfs_symlinkargs arg = { |
433 | .fromfh = NFS_FH(dir), | 434 | .fromfh = NFS_FH(dir), |
434 | .fromname = name->name, | 435 | .fromname = dentry->d_name.name, |
435 | .fromlen = name->len, | 436 | .fromlen = dentry->d_name.len, |
436 | .topath = path->name, | 437 | .pages = &page, |
437 | .tolen = path->len, | 438 | .pathlen = len, |
438 | .sattr = sattr | 439 | .sattr = sattr |
439 | }; | 440 | }; |
440 | struct rpc_message msg = { | 441 | struct rpc_message msg = { |
@@ -443,13 +444,25 @@ nfs_proc_symlink(struct inode *dir, struct qstr *name, struct qstr *path, | |||
443 | }; | 444 | }; |
444 | int status; | 445 | int status; |
445 | 446 | ||
446 | if (path->len > NFS2_MAXPATHLEN) | 447 | if (len > NFS2_MAXPATHLEN) |
447 | return -ENAMETOOLONG; | 448 | return -ENAMETOOLONG; |
448 | dprintk("NFS call symlink %s -> %s\n", name->name, path->name); | 449 | |
449 | nfs_fattr_init(fattr); | 450 | dprintk("NFS call symlink %s\n", dentry->d_name.name); |
450 | fhandle->size = 0; | 451 | |
451 | status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0); | 452 | status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0); |
452 | nfs_mark_for_revalidate(dir); | 453 | nfs_mark_for_revalidate(dir); |
454 | |||
455 | /* | ||
456 | * V2 SYMLINK requests don't return any attributes. Setting the | ||
457 | * filehandle size to zero indicates to nfs_instantiate that it | ||
458 | * should fill in the data with a LOOKUP call on the wire. | ||
459 | */ | ||
460 | if (status == 0) { | ||
461 | nfs_fattr_init(&fattr); | ||
462 | fhandle.size = 0; | ||
463 | status = nfs_instantiate(dentry, &fhandle, &fattr); | ||
464 | } | ||
465 | |||
453 | dprintk("NFS reply symlink: %d\n", status); | 466 | dprintk("NFS reply symlink: %d\n", status); |
454 | return status; | 467 | return status; |
455 | } | 468 | } |
@@ -671,7 +684,7 @@ nfs_proc_lock(struct file *filp, int cmd, struct file_lock *fl) | |||
671 | } | 684 | } |
672 | 685 | ||
673 | 686 | ||
674 | struct nfs_rpc_ops nfs_v2_clientops = { | 687 | const struct nfs_rpc_ops nfs_v2_clientops = { |
675 | .version = 2, /* protocol version */ | 688 | .version = 2, /* protocol version */ |
676 | .dentry_ops = &nfs_dentry_operations, | 689 | .dentry_ops = &nfs_dentry_operations, |
677 | .dir_inode_ops = &nfs_dir_inode_operations, | 690 | .dir_inode_ops = &nfs_dir_inode_operations, |
diff --git a/fs/nfs/read.c b/fs/nfs/read.c index f0aff824a291..69f1549da2b9 100644 --- a/fs/nfs/read.c +++ b/fs/nfs/read.c | |||
@@ -171,7 +171,7 @@ static int nfs_readpage_sync(struct nfs_open_context *ctx, struct inode *inode, | |||
171 | rdata->args.offset = page_offset(page) + rdata->args.pgbase; | 171 | rdata->args.offset = page_offset(page) + rdata->args.pgbase; |
172 | 172 | ||
173 | dprintk("NFS: nfs_proc_read(%s, (%s/%Ld), %Lu, %u)\n", | 173 | dprintk("NFS: nfs_proc_read(%s, (%s/%Ld), %Lu, %u)\n", |
174 | NFS_SERVER(inode)->hostname, | 174 | NFS_SERVER(inode)->nfs_client->cl_hostname, |
175 | inode->i_sb->s_id, | 175 | inode->i_sb->s_id, |
176 | (long long)NFS_FILEID(inode), | 176 | (long long)NFS_FILEID(inode), |
177 | (unsigned long long)rdata->args.pgbase, | 177 | (unsigned long long)rdata->args.pgbase, |
@@ -568,8 +568,13 @@ int nfs_readpage_result(struct rpc_task *task, struct nfs_read_data *data) | |||
568 | 568 | ||
569 | nfs_add_stats(data->inode, NFSIOS_SERVERREADBYTES, resp->count); | 569 | nfs_add_stats(data->inode, NFSIOS_SERVERREADBYTES, resp->count); |
570 | 570 | ||
571 | /* Is this a short read? */ | 571 | if (task->tk_status < 0) { |
572 | if (task->tk_status >= 0 && resp->count < argp->count && !resp->eof) { | 572 | if (task->tk_status == -ESTALE) { |
573 | set_bit(NFS_INO_STALE, &NFS_FLAGS(data->inode)); | ||
574 | nfs_mark_for_revalidate(data->inode); | ||
575 | } | ||
576 | } else if (resp->count < argp->count && !resp->eof) { | ||
577 | /* This is a short read! */ | ||
573 | nfs_inc_stats(data->inode, NFSIOS_SHORTREAD); | 578 | nfs_inc_stats(data->inode, NFSIOS_SHORTREAD); |
574 | /* Has the server at least made some progress? */ | 579 | /* Has the server at least made some progress? */ |
575 | if (resp->count != 0) { | 580 | if (resp->count != 0) { |
@@ -616,6 +621,10 @@ int nfs_readpage(struct file *file, struct page *page) | |||
616 | if (error) | 621 | if (error) |
617 | goto out_error; | 622 | goto out_error; |
618 | 623 | ||
624 | error = -ESTALE; | ||
625 | if (NFS_STALE(inode)) | ||
626 | goto out_error; | ||
627 | |||
619 | if (file == NULL) { | 628 | if (file == NULL) { |
620 | ctx = nfs_find_open_context(inode, NULL, FMODE_READ); | 629 | ctx = nfs_find_open_context(inode, NULL, FMODE_READ); |
621 | if (ctx == NULL) | 630 | if (ctx == NULL) |
@@ -678,7 +687,7 @@ int nfs_readpages(struct file *filp, struct address_space *mapping, | |||
678 | }; | 687 | }; |
679 | struct inode *inode = mapping->host; | 688 | struct inode *inode = mapping->host; |
680 | struct nfs_server *server = NFS_SERVER(inode); | 689 | struct nfs_server *server = NFS_SERVER(inode); |
681 | int ret; | 690 | int ret = -ESTALE; |
682 | 691 | ||
683 | dprintk("NFS: nfs_readpages (%s/%Ld %d)\n", | 692 | dprintk("NFS: nfs_readpages (%s/%Ld %d)\n", |
684 | inode->i_sb->s_id, | 693 | inode->i_sb->s_id, |
@@ -686,6 +695,9 @@ int nfs_readpages(struct file *filp, struct address_space *mapping, | |||
686 | nr_pages); | 695 | nr_pages); |
687 | nfs_inc_stats(inode, NFSIOS_VFSREADPAGES); | 696 | nfs_inc_stats(inode, NFSIOS_VFSREADPAGES); |
688 | 697 | ||
698 | if (NFS_STALE(inode)) | ||
699 | goto out; | ||
700 | |||
689 | if (filp == NULL) { | 701 | if (filp == NULL) { |
690 | desc.ctx = nfs_find_open_context(inode, NULL, FMODE_READ); | 702 | desc.ctx = nfs_find_open_context(inode, NULL, FMODE_READ); |
691 | if (desc.ctx == NULL) | 703 | if (desc.ctx == NULL) |
@@ -701,6 +713,7 @@ int nfs_readpages(struct file *filp, struct address_space *mapping, | |||
701 | ret = err; | 713 | ret = err; |
702 | } | 714 | } |
703 | put_nfs_open_context(desc.ctx); | 715 | put_nfs_open_context(desc.ctx); |
716 | out: | ||
704 | return ret; | 717 | return ret; |
705 | } | 718 | } |
706 | 719 | ||
diff --git a/fs/nfs/super.c b/fs/nfs/super.c index e8a9bee74d9d..b99113b0f65f 100644 --- a/fs/nfs/super.c +++ b/fs/nfs/super.c | |||
@@ -13,6 +13,11 @@ | |||
13 | * | 13 | * |
14 | * Split from inode.c by David Howells <dhowells@redhat.com> | 14 | * Split from inode.c by David Howells <dhowells@redhat.com> |
15 | * | 15 | * |
16 | * - superblocks are indexed on server only - all inodes, dentries, etc. associated with a | ||
17 | * particular server are held in the same superblock | ||
18 | * - NFS superblocks can have several effective roots to the dentry tree | ||
19 | * - directory type roots are spliced into the tree when a path from one root reaches the root | ||
20 | * of another (see nfs_lookup()) | ||
16 | */ | 21 | */ |
17 | 22 | ||
18 | #include <linux/config.h> | 23 | #include <linux/config.h> |
@@ -52,66 +57,12 @@ | |||
52 | 57 | ||
53 | #define NFSDBG_FACILITY NFSDBG_VFS | 58 | #define NFSDBG_FACILITY NFSDBG_VFS |
54 | 59 | ||
55 | /* Maximum number of readahead requests | ||
56 | * FIXME: this should really be a sysctl so that users may tune it to suit | ||
57 | * their needs. People that do NFS over a slow network, might for | ||
58 | * instance want to reduce it to something closer to 1 for improved | ||
59 | * interactive response. | ||
60 | */ | ||
61 | #define NFS_MAX_READAHEAD (RPC_DEF_SLOT_TABLE - 1) | ||
62 | |||
63 | /* | ||
64 | * RPC cruft for NFS | ||
65 | */ | ||
66 | static struct rpc_version * nfs_version[] = { | ||
67 | NULL, | ||
68 | NULL, | ||
69 | &nfs_version2, | ||
70 | #if defined(CONFIG_NFS_V3) | ||
71 | &nfs_version3, | ||
72 | #elif defined(CONFIG_NFS_V4) | ||
73 | NULL, | ||
74 | #endif | ||
75 | #if defined(CONFIG_NFS_V4) | ||
76 | &nfs_version4, | ||
77 | #endif | ||
78 | }; | ||
79 | |||
80 | static struct rpc_program nfs_program = { | ||
81 | .name = "nfs", | ||
82 | .number = NFS_PROGRAM, | ||
83 | .nrvers = ARRAY_SIZE(nfs_version), | ||
84 | .version = nfs_version, | ||
85 | .stats = &nfs_rpcstat, | ||
86 | .pipe_dir_name = "/nfs", | ||
87 | }; | ||
88 | |||
89 | struct rpc_stat nfs_rpcstat = { | ||
90 | .program = &nfs_program | ||
91 | }; | ||
92 | |||
93 | |||
94 | #ifdef CONFIG_NFS_V3_ACL | ||
95 | static struct rpc_stat nfsacl_rpcstat = { &nfsacl_program }; | ||
96 | static struct rpc_version * nfsacl_version[] = { | ||
97 | [3] = &nfsacl_version3, | ||
98 | }; | ||
99 | |||
100 | struct rpc_program nfsacl_program = { | ||
101 | .name = "nfsacl", | ||
102 | .number = NFS_ACL_PROGRAM, | ||
103 | .nrvers = ARRAY_SIZE(nfsacl_version), | ||
104 | .version = nfsacl_version, | ||
105 | .stats = &nfsacl_rpcstat, | ||
106 | }; | ||
107 | #endif /* CONFIG_NFS_V3_ACL */ | ||
108 | |||
109 | static void nfs_umount_begin(struct vfsmount *, int); | 60 | static void nfs_umount_begin(struct vfsmount *, int); |
110 | static int nfs_statfs(struct dentry *, struct kstatfs *); | 61 | static int nfs_statfs(struct dentry *, struct kstatfs *); |
111 | static int nfs_show_options(struct seq_file *, struct vfsmount *); | 62 | static int nfs_show_options(struct seq_file *, struct vfsmount *); |
112 | static int nfs_show_stats(struct seq_file *, struct vfsmount *); | 63 | static int nfs_show_stats(struct seq_file *, struct vfsmount *); |
113 | static int nfs_get_sb(struct file_system_type *, int, const char *, void *, struct vfsmount *); | 64 | static int nfs_get_sb(struct file_system_type *, int, const char *, void *, struct vfsmount *); |
114 | static int nfs_clone_nfs_sb(struct file_system_type *fs_type, | 65 | static int nfs_xdev_get_sb(struct file_system_type *fs_type, |
115 | int flags, const char *dev_name, void *raw_data, struct vfsmount *mnt); | 66 | int flags, const char *dev_name, void *raw_data, struct vfsmount *mnt); |
116 | static void nfs_kill_super(struct super_block *); | 67 | static void nfs_kill_super(struct super_block *); |
117 | 68 | ||
@@ -123,10 +74,10 @@ static struct file_system_type nfs_fs_type = { | |||
123 | .fs_flags = FS_ODD_RENAME|FS_REVAL_DOT|FS_BINARY_MOUNTDATA, | 74 | .fs_flags = FS_ODD_RENAME|FS_REVAL_DOT|FS_BINARY_MOUNTDATA, |
124 | }; | 75 | }; |
125 | 76 | ||
126 | struct file_system_type clone_nfs_fs_type = { | 77 | struct file_system_type nfs_xdev_fs_type = { |
127 | .owner = THIS_MODULE, | 78 | .owner = THIS_MODULE, |
128 | .name = "nfs", | 79 | .name = "nfs", |
129 | .get_sb = nfs_clone_nfs_sb, | 80 | .get_sb = nfs_xdev_get_sb, |
130 | .kill_sb = nfs_kill_super, | 81 | .kill_sb = nfs_kill_super, |
131 | .fs_flags = FS_ODD_RENAME|FS_REVAL_DOT|FS_BINARY_MOUNTDATA, | 82 | .fs_flags = FS_ODD_RENAME|FS_REVAL_DOT|FS_BINARY_MOUNTDATA, |
132 | }; | 83 | }; |
@@ -145,10 +96,10 @@ static struct super_operations nfs_sops = { | |||
145 | #ifdef CONFIG_NFS_V4 | 96 | #ifdef CONFIG_NFS_V4 |
146 | static int nfs4_get_sb(struct file_system_type *fs_type, | 97 | static int nfs4_get_sb(struct file_system_type *fs_type, |
147 | int flags, const char *dev_name, void *raw_data, struct vfsmount *mnt); | 98 | int flags, const char *dev_name, void *raw_data, struct vfsmount *mnt); |
148 | static int nfs_clone_nfs4_sb(struct file_system_type *fs_type, | 99 | static int nfs4_xdev_get_sb(struct file_system_type *fs_type, |
149 | int flags, const char *dev_name, void *raw_data, struct vfsmount *mnt); | 100 | int flags, const char *dev_name, void *raw_data, struct vfsmount *mnt); |
150 | static int nfs_referral_nfs4_sb(struct file_system_type *fs_type, | 101 | static int nfs4_referral_get_sb(struct file_system_type *fs_type, |
151 | int flags, const char *dev_name, void *raw_data, struct vfsmount *mnt); | 102 | int flags, const char *dev_name, void *raw_data, struct vfsmount *mnt); |
152 | static void nfs4_kill_super(struct super_block *sb); | 103 | static void nfs4_kill_super(struct super_block *sb); |
153 | 104 | ||
154 | static struct file_system_type nfs4_fs_type = { | 105 | static struct file_system_type nfs4_fs_type = { |
@@ -159,18 +110,18 @@ static struct file_system_type nfs4_fs_type = { | |||
159 | .fs_flags = FS_ODD_RENAME|FS_REVAL_DOT|FS_BINARY_MOUNTDATA, | 110 | .fs_flags = FS_ODD_RENAME|FS_REVAL_DOT|FS_BINARY_MOUNTDATA, |
160 | }; | 111 | }; |
161 | 112 | ||
162 | struct file_system_type clone_nfs4_fs_type = { | 113 | struct file_system_type nfs4_xdev_fs_type = { |
163 | .owner = THIS_MODULE, | 114 | .owner = THIS_MODULE, |
164 | .name = "nfs4", | 115 | .name = "nfs4", |
165 | .get_sb = nfs_clone_nfs4_sb, | 116 | .get_sb = nfs4_xdev_get_sb, |
166 | .kill_sb = nfs4_kill_super, | 117 | .kill_sb = nfs4_kill_super, |
167 | .fs_flags = FS_ODD_RENAME|FS_REVAL_DOT|FS_BINARY_MOUNTDATA, | 118 | .fs_flags = FS_ODD_RENAME|FS_REVAL_DOT|FS_BINARY_MOUNTDATA, |
168 | }; | 119 | }; |
169 | 120 | ||
170 | struct file_system_type nfs_referral_nfs4_fs_type = { | 121 | struct file_system_type nfs4_referral_fs_type = { |
171 | .owner = THIS_MODULE, | 122 | .owner = THIS_MODULE, |
172 | .name = "nfs4", | 123 | .name = "nfs4", |
173 | .get_sb = nfs_referral_nfs4_sb, | 124 | .get_sb = nfs4_referral_get_sb, |
174 | .kill_sb = nfs4_kill_super, | 125 | .kill_sb = nfs4_kill_super, |
175 | .fs_flags = FS_ODD_RENAME|FS_REVAL_DOT|FS_BINARY_MOUNTDATA, | 126 | .fs_flags = FS_ODD_RENAME|FS_REVAL_DOT|FS_BINARY_MOUNTDATA, |
176 | }; | 127 | }; |
@@ -187,39 +138,7 @@ static struct super_operations nfs4_sops = { | |||
187 | }; | 138 | }; |
188 | #endif | 139 | #endif |
189 | 140 | ||
190 | #ifdef CONFIG_NFS_V4 | 141 | static struct shrinker *acl_shrinker; |
191 | static const int nfs_set_port_min = 0; | ||
192 | static const int nfs_set_port_max = 65535; | ||
193 | |||
194 | static int param_set_port(const char *val, struct kernel_param *kp) | ||
195 | { | ||
196 | char *endp; | ||
197 | int num = simple_strtol(val, &endp, 0); | ||
198 | if (endp == val || *endp || num < nfs_set_port_min || num > nfs_set_port_max) | ||
199 | return -EINVAL; | ||
200 | *((int *)kp->arg) = num; | ||
201 | return 0; | ||
202 | } | ||
203 | |||
204 | module_param_call(callback_tcpport, param_set_port, param_get_int, | ||
205 | &nfs_callback_set_tcpport, 0644); | ||
206 | #endif | ||
207 | |||
208 | #ifdef CONFIG_NFS_V4 | ||
209 | static int param_set_idmap_timeout(const char *val, struct kernel_param *kp) | ||
210 | { | ||
211 | char *endp; | ||
212 | int num = simple_strtol(val, &endp, 0); | ||
213 | int jif = num * HZ; | ||
214 | if (endp == val || *endp || num < 0 || jif < num) | ||
215 | return -EINVAL; | ||
216 | *((int *)kp->arg) = jif; | ||
217 | return 0; | ||
218 | } | ||
219 | |||
220 | module_param_call(idmap_cache_timeout, param_set_idmap_timeout, param_get_int, | ||
221 | &nfs_idmap_cache_timeout, 0644); | ||
222 | #endif | ||
223 | 142 | ||
224 | /* | 143 | /* |
225 | * Register the NFS filesystems | 144 | * Register the NFS filesystems |
@@ -240,6 +159,7 @@ int __init register_nfs_fs(void) | |||
240 | if (ret < 0) | 159 | if (ret < 0) |
241 | goto error_2; | 160 | goto error_2; |
242 | #endif | 161 | #endif |
162 | acl_shrinker = set_shrinker(DEFAULT_SEEKS, nfs_access_cache_shrinker); | ||
243 | return 0; | 163 | return 0; |
244 | 164 | ||
245 | #ifdef CONFIG_NFS_V4 | 165 | #ifdef CONFIG_NFS_V4 |
@@ -257,6 +177,8 @@ error_0: | |||
257 | */ | 177 | */ |
258 | void __exit unregister_nfs_fs(void) | 178 | void __exit unregister_nfs_fs(void) |
259 | { | 179 | { |
180 | if (acl_shrinker != NULL) | ||
181 | remove_shrinker(acl_shrinker); | ||
260 | #ifdef CONFIG_NFS_V4 | 182 | #ifdef CONFIG_NFS_V4 |
261 | unregister_filesystem(&nfs4_fs_type); | 183 | unregister_filesystem(&nfs4_fs_type); |
262 | nfs_unregister_sysctl(); | 184 | nfs_unregister_sysctl(); |
@@ -269,11 +191,10 @@ void __exit unregister_nfs_fs(void) | |||
269 | */ | 191 | */ |
270 | static int nfs_statfs(struct dentry *dentry, struct kstatfs *buf) | 192 | static int nfs_statfs(struct dentry *dentry, struct kstatfs *buf) |
271 | { | 193 | { |
272 | struct super_block *sb = dentry->d_sb; | 194 | struct nfs_server *server = NFS_SB(dentry->d_sb); |
273 | struct nfs_server *server = NFS_SB(sb); | ||
274 | unsigned char blockbits; | 195 | unsigned char blockbits; |
275 | unsigned long blockres; | 196 | unsigned long blockres; |
276 | struct nfs_fh *rootfh = NFS_FH(sb->s_root->d_inode); | 197 | struct nfs_fh *fh = NFS_FH(dentry->d_inode); |
277 | struct nfs_fattr fattr; | 198 | struct nfs_fattr fattr; |
278 | struct nfs_fsstat res = { | 199 | struct nfs_fsstat res = { |
279 | .fattr = &fattr, | 200 | .fattr = &fattr, |
@@ -282,7 +203,7 @@ static int nfs_statfs(struct dentry *dentry, struct kstatfs *buf) | |||
282 | 203 | ||
283 | lock_kernel(); | 204 | lock_kernel(); |
284 | 205 | ||
285 | error = server->rpc_ops->statfs(server, rootfh, &res); | 206 | error = server->nfs_client->rpc_ops->statfs(server, fh, &res); |
286 | buf->f_type = NFS_SUPER_MAGIC; | 207 | buf->f_type = NFS_SUPER_MAGIC; |
287 | if (error < 0) | 208 | if (error < 0) |
288 | goto out_err; | 209 | goto out_err; |
@@ -292,7 +213,7 @@ static int nfs_statfs(struct dentry *dentry, struct kstatfs *buf) | |||
292 | * case where f_frsize != f_bsize. Eventually we want to | 213 | * case where f_frsize != f_bsize. Eventually we want to |
293 | * report the value of wtmult in this field. | 214 | * report the value of wtmult in this field. |
294 | */ | 215 | */ |
295 | buf->f_frsize = sb->s_blocksize; | 216 | buf->f_frsize = dentry->d_sb->s_blocksize; |
296 | 217 | ||
297 | /* | 218 | /* |
298 | * On most *nix systems, f_blocks, f_bfree, and f_bavail | 219 | * On most *nix systems, f_blocks, f_bfree, and f_bavail |
@@ -301,8 +222,8 @@ static int nfs_statfs(struct dentry *dentry, struct kstatfs *buf) | |||
301 | * thus historically Linux's sys_statfs reports these | 222 | * thus historically Linux's sys_statfs reports these |
302 | * fields in units of f_bsize. | 223 | * fields in units of f_bsize. |
303 | */ | 224 | */ |
304 | buf->f_bsize = sb->s_blocksize; | 225 | buf->f_bsize = dentry->d_sb->s_blocksize; |
305 | blockbits = sb->s_blocksize_bits; | 226 | blockbits = dentry->d_sb->s_blocksize_bits; |
306 | blockres = (1 << blockbits) - 1; | 227 | blockres = (1 << blockbits) - 1; |
307 | buf->f_blocks = (res.tbytes + blockres) >> blockbits; | 228 | buf->f_blocks = (res.tbytes + blockres) >> blockbits; |
308 | buf->f_bfree = (res.fbytes + blockres) >> blockbits; | 229 | buf->f_bfree = (res.fbytes + blockres) >> blockbits; |
@@ -323,9 +244,12 @@ static int nfs_statfs(struct dentry *dentry, struct kstatfs *buf) | |||
323 | 244 | ||
324 | } | 245 | } |
325 | 246 | ||
247 | /* | ||
248 | * Map the security flavour number to a name | ||
249 | */ | ||
326 | static const char *nfs_pseudoflavour_to_name(rpc_authflavor_t flavour) | 250 | static const char *nfs_pseudoflavour_to_name(rpc_authflavor_t flavour) |
327 | { | 251 | { |
328 | static struct { | 252 | static const struct { |
329 | rpc_authflavor_t flavour; | 253 | rpc_authflavor_t flavour; |
330 | const char *str; | 254 | const char *str; |
331 | } sec_flavours[] = { | 255 | } sec_flavours[] = { |
@@ -356,10 +280,10 @@ static const char *nfs_pseudoflavour_to_name(rpc_authflavor_t flavour) | |||
356 | */ | 280 | */ |
357 | static void nfs_show_mount_options(struct seq_file *m, struct nfs_server *nfss, int showdefaults) | 281 | static void nfs_show_mount_options(struct seq_file *m, struct nfs_server *nfss, int showdefaults) |
358 | { | 282 | { |
359 | static struct proc_nfs_info { | 283 | static const struct proc_nfs_info { |
360 | int flag; | 284 | int flag; |
361 | char *str; | 285 | const char *str; |
362 | char *nostr; | 286 | const char *nostr; |
363 | } nfs_info[] = { | 287 | } nfs_info[] = { |
364 | { NFS_MOUNT_SOFT, ",soft", ",hard" }, | 288 | { NFS_MOUNT_SOFT, ",soft", ",hard" }, |
365 | { NFS_MOUNT_INTR, ",intr", "" }, | 289 | { NFS_MOUNT_INTR, ",intr", "" }, |
@@ -369,11 +293,12 @@ static void nfs_show_mount_options(struct seq_file *m, struct nfs_server *nfss, | |||
369 | { NFS_MOUNT_NOACL, ",noacl", "" }, | 293 | { NFS_MOUNT_NOACL, ",noacl", "" }, |
370 | { 0, NULL, NULL } | 294 | { 0, NULL, NULL } |
371 | }; | 295 | }; |
372 | struct proc_nfs_info *nfs_infop; | 296 | const struct proc_nfs_info *nfs_infop; |
297 | struct nfs_client *clp = nfss->nfs_client; | ||
373 | char buf[12]; | 298 | char buf[12]; |
374 | char *proto; | 299 | const char *proto; |
375 | 300 | ||
376 | seq_printf(m, ",vers=%d", nfss->rpc_ops->version); | 301 | seq_printf(m, ",vers=%d", clp->rpc_ops->version); |
377 | seq_printf(m, ",rsize=%d", nfss->rsize); | 302 | seq_printf(m, ",rsize=%d", nfss->rsize); |
378 | seq_printf(m, ",wsize=%d", nfss->wsize); | 303 | seq_printf(m, ",wsize=%d", nfss->wsize); |
379 | if (nfss->acregmin != 3*HZ || showdefaults) | 304 | if (nfss->acregmin != 3*HZ || showdefaults) |
@@ -402,8 +327,8 @@ static void nfs_show_mount_options(struct seq_file *m, struct nfs_server *nfss, | |||
402 | proto = buf; | 327 | proto = buf; |
403 | } | 328 | } |
404 | seq_printf(m, ",proto=%s", proto); | 329 | seq_printf(m, ",proto=%s", proto); |
405 | seq_printf(m, ",timeo=%lu", 10U * nfss->retrans_timeo / HZ); | 330 | seq_printf(m, ",timeo=%lu", 10U * clp->retrans_timeo / HZ); |
406 | seq_printf(m, ",retrans=%u", nfss->retrans_count); | 331 | seq_printf(m, ",retrans=%u", clp->retrans_count); |
407 | seq_printf(m, ",sec=%s", nfs_pseudoflavour_to_name(nfss->client->cl_auth->au_flavor)); | 332 | seq_printf(m, ",sec=%s", nfs_pseudoflavour_to_name(nfss->client->cl_auth->au_flavor)); |
408 | } | 333 | } |
409 | 334 | ||
@@ -417,7 +342,7 @@ static int nfs_show_options(struct seq_file *m, struct vfsmount *mnt) | |||
417 | nfs_show_mount_options(m, nfss, 0); | 342 | nfs_show_mount_options(m, nfss, 0); |
418 | 343 | ||
419 | seq_puts(m, ",addr="); | 344 | seq_puts(m, ",addr="); |
420 | seq_escape(m, nfss->hostname, " \t\n\\"); | 345 | seq_escape(m, nfss->nfs_client->cl_hostname, " \t\n\\"); |
421 | 346 | ||
422 | return 0; | 347 | return 0; |
423 | } | 348 | } |
@@ -454,7 +379,7 @@ static int nfs_show_stats(struct seq_file *m, struct vfsmount *mnt) | |||
454 | seq_printf(m, ",namelen=%d", nfss->namelen); | 379 | seq_printf(m, ",namelen=%d", nfss->namelen); |
455 | 380 | ||
456 | #ifdef CONFIG_NFS_V4 | 381 | #ifdef CONFIG_NFS_V4 |
457 | if (nfss->rpc_ops->version == 4) { | 382 | if (nfss->nfs_client->cl_nfsversion == 4) { |
458 | seq_printf(m, "\n\tnfsv4:\t"); | 383 | seq_printf(m, "\n\tnfsv4:\t"); |
459 | seq_printf(m, "bm0=0x%x", nfss->attr_bitmask[0]); | 384 | seq_printf(m, "bm0=0x%x", nfss->attr_bitmask[0]); |
460 | seq_printf(m, ",bm1=0x%x", nfss->attr_bitmask[1]); | 385 | seq_printf(m, ",bm1=0x%x", nfss->attr_bitmask[1]); |
@@ -501,782 +426,353 @@ static int nfs_show_stats(struct seq_file *m, struct vfsmount *mnt) | |||
501 | 426 | ||
502 | /* | 427 | /* |
503 | * Begin unmount by attempting to remove all automounted mountpoints we added | 428 | * Begin unmount by attempting to remove all automounted mountpoints we added |
504 | * in response to traversals | 429 | * in response to xdev traversals and referrals |
505 | */ | 430 | */ |
506 | static void nfs_umount_begin(struct vfsmount *vfsmnt, int flags) | 431 | static void nfs_umount_begin(struct vfsmount *vfsmnt, int flags) |
507 | { | 432 | { |
508 | struct nfs_server *server; | ||
509 | struct rpc_clnt *rpc; | ||
510 | |||
511 | shrink_submounts(vfsmnt, &nfs_automount_list); | 433 | shrink_submounts(vfsmnt, &nfs_automount_list); |
512 | if (!(flags & MNT_FORCE)) | ||
513 | return; | ||
514 | /* -EIO all pending I/O */ | ||
515 | server = NFS_SB(vfsmnt->mnt_sb); | ||
516 | rpc = server->client; | ||
517 | if (!IS_ERR(rpc)) | ||
518 | rpc_killall_tasks(rpc); | ||
519 | rpc = server->client_acl; | ||
520 | if (!IS_ERR(rpc)) | ||
521 | rpc_killall_tasks(rpc); | ||
522 | } | 434 | } |
523 | 435 | ||
524 | /* | 436 | /* |
525 | * Obtain the root inode of the file system. | 437 | * Validate the NFS2/NFS3 mount data |
438 | * - fills in the mount root filehandle | ||
526 | */ | 439 | */ |
527 | static struct inode * | 440 | static int nfs_validate_mount_data(struct nfs_mount_data *data, |
528 | nfs_get_root(struct super_block *sb, struct nfs_fh *rootfh, struct nfs_fsinfo *fsinfo) | 441 | struct nfs_fh *mntfh) |
529 | { | 442 | { |
530 | struct nfs_server *server = NFS_SB(sb); | 443 | if (data == NULL) { |
531 | int error; | 444 | dprintk("%s: missing data argument\n", __FUNCTION__); |
532 | 445 | return -EINVAL; | |
533 | error = server->rpc_ops->getroot(server, rootfh, fsinfo); | ||
534 | if (error < 0) { | ||
535 | dprintk("nfs_get_root: getattr error = %d\n", -error); | ||
536 | return ERR_PTR(error); | ||
537 | } | 446 | } |
538 | 447 | ||
539 | server->fsid = fsinfo->fattr->fsid; | 448 | if (data->version <= 0 || data->version > NFS_MOUNT_VERSION) { |
540 | return nfs_fhget(sb, rootfh, fsinfo->fattr); | 449 | dprintk("%s: bad mount version\n", __FUNCTION__); |
541 | } | 450 | return -EINVAL; |
542 | 451 | } | |
543 | /* | ||
544 | * Do NFS version-independent mount processing, and sanity checking | ||
545 | */ | ||
546 | static int | ||
547 | nfs_sb_init(struct super_block *sb, rpc_authflavor_t authflavor) | ||
548 | { | ||
549 | struct nfs_server *server; | ||
550 | struct inode *root_inode; | ||
551 | struct nfs_fattr fattr; | ||
552 | struct nfs_fsinfo fsinfo = { | ||
553 | .fattr = &fattr, | ||
554 | }; | ||
555 | struct nfs_pathconf pathinfo = { | ||
556 | .fattr = &fattr, | ||
557 | }; | ||
558 | int no_root_error = 0; | ||
559 | unsigned long max_rpc_payload; | ||
560 | |||
561 | /* We probably want something more informative here */ | ||
562 | snprintf(sb->s_id, sizeof(sb->s_id), "%x:%x", MAJOR(sb->s_dev), MINOR(sb->s_dev)); | ||
563 | |||
564 | server = NFS_SB(sb); | ||
565 | 452 | ||
566 | sb->s_magic = NFS_SUPER_MAGIC; | 453 | switch (data->version) { |
454 | case 1: | ||
455 | data->namlen = 0; | ||
456 | case 2: | ||
457 | data->bsize = 0; | ||
458 | case 3: | ||
459 | if (data->flags & NFS_MOUNT_VER3) { | ||
460 | dprintk("%s: mount structure version %d does not support NFSv3\n", | ||
461 | __FUNCTION__, | ||
462 | data->version); | ||
463 | return -EINVAL; | ||
464 | } | ||
465 | data->root.size = NFS2_FHSIZE; | ||
466 | memcpy(data->root.data, data->old_root.data, NFS2_FHSIZE); | ||
467 | case 4: | ||
468 | if (data->flags & NFS_MOUNT_SECFLAVOUR) { | ||
469 | dprintk("%s: mount structure version %d does not support strong security\n", | ||
470 | __FUNCTION__, | ||
471 | data->version); | ||
472 | return -EINVAL; | ||
473 | } | ||
474 | case 5: | ||
475 | memset(data->context, 0, sizeof(data->context)); | ||
476 | } | ||
567 | 477 | ||
568 | server->io_stats = nfs_alloc_iostats(); | 478 | /* Set the pseudoflavor */ |
569 | if (server->io_stats == NULL) | 479 | if (!(data->flags & NFS_MOUNT_SECFLAVOUR)) |
570 | return -ENOMEM; | 480 | data->pseudoflavor = RPC_AUTH_UNIX; |
571 | 481 | ||
572 | root_inode = nfs_get_root(sb, &server->fh, &fsinfo); | 482 | #ifndef CONFIG_NFS_V3 |
573 | /* Did getting the root inode fail? */ | 483 | /* If NFSv3 is not compiled in, return -EPROTONOSUPPORT */ |
574 | if (IS_ERR(root_inode)) { | 484 | if (data->flags & NFS_MOUNT_VER3) { |
575 | no_root_error = PTR_ERR(root_inode); | 485 | dprintk("%s: NFSv3 not compiled into kernel\n", __FUNCTION__); |
576 | goto out_no_root; | 486 | return -EPROTONOSUPPORT; |
577 | } | ||
578 | sb->s_root = d_alloc_root(root_inode); | ||
579 | if (!sb->s_root) { | ||
580 | no_root_error = -ENOMEM; | ||
581 | goto out_no_root; | ||
582 | } | 487 | } |
583 | sb->s_root->d_op = server->rpc_ops->dentry_ops; | 488 | #endif /* CONFIG_NFS_V3 */ |
584 | |||
585 | /* mount time stamp, in seconds */ | ||
586 | server->mount_time = jiffies; | ||
587 | |||
588 | /* Get some general file system info */ | ||
589 | if (server->namelen == 0 && | ||
590 | server->rpc_ops->pathconf(server, &server->fh, &pathinfo) >= 0) | ||
591 | server->namelen = pathinfo.max_namelen; | ||
592 | /* Work out a lot of parameters */ | ||
593 | if (server->rsize == 0) | ||
594 | server->rsize = nfs_block_size(fsinfo.rtpref, NULL); | ||
595 | if (server->wsize == 0) | ||
596 | server->wsize = nfs_block_size(fsinfo.wtpref, NULL); | ||
597 | |||
598 | if (fsinfo.rtmax >= 512 && server->rsize > fsinfo.rtmax) | ||
599 | server->rsize = nfs_block_size(fsinfo.rtmax, NULL); | ||
600 | if (fsinfo.wtmax >= 512 && server->wsize > fsinfo.wtmax) | ||
601 | server->wsize = nfs_block_size(fsinfo.wtmax, NULL); | ||
602 | |||
603 | max_rpc_payload = nfs_block_size(rpc_max_payload(server->client), NULL); | ||
604 | if (server->rsize > max_rpc_payload) | ||
605 | server->rsize = max_rpc_payload; | ||
606 | if (server->rsize > NFS_MAX_FILE_IO_SIZE) | ||
607 | server->rsize = NFS_MAX_FILE_IO_SIZE; | ||
608 | server->rpages = (server->rsize + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT; | ||
609 | |||
610 | if (server->wsize > max_rpc_payload) | ||
611 | server->wsize = max_rpc_payload; | ||
612 | if (server->wsize > NFS_MAX_FILE_IO_SIZE) | ||
613 | server->wsize = NFS_MAX_FILE_IO_SIZE; | ||
614 | server->wpages = (server->wsize + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT; | ||
615 | 489 | ||
616 | if (sb->s_blocksize == 0) | 490 | /* We now require that the mount process passes the remote address */ |
617 | sb->s_blocksize = nfs_block_bits(server->wsize, | 491 | if (data->addr.sin_addr.s_addr == INADDR_ANY) { |
618 | &sb->s_blocksize_bits); | 492 | dprintk("%s: mount program didn't pass remote address!\n", |
619 | server->wtmult = nfs_block_bits(fsinfo.wtmult, NULL); | 493 | __FUNCTION__); |
620 | 494 | return -EINVAL; | |
621 | server->dtsize = nfs_block_size(fsinfo.dtpref, NULL); | ||
622 | if (server->dtsize > PAGE_CACHE_SIZE) | ||
623 | server->dtsize = PAGE_CACHE_SIZE; | ||
624 | if (server->dtsize > server->rsize) | ||
625 | server->dtsize = server->rsize; | ||
626 | |||
627 | if (server->flags & NFS_MOUNT_NOAC) { | ||
628 | server->acregmin = server->acregmax = 0; | ||
629 | server->acdirmin = server->acdirmax = 0; | ||
630 | sb->s_flags |= MS_SYNCHRONOUS; | ||
631 | } | 495 | } |
632 | server->backing_dev_info.ra_pages = server->rpages * NFS_MAX_READAHEAD; | ||
633 | 496 | ||
634 | nfs_super_set_maxbytes(sb, fsinfo.maxfilesize); | 497 | /* Prepare the root filehandle */ |
498 | if (data->flags & NFS_MOUNT_VER3) | ||
499 | mntfh->size = data->root.size; | ||
500 | else | ||
501 | mntfh->size = NFS2_FHSIZE; | ||
502 | |||
503 | if (mntfh->size > sizeof(mntfh->data)) { | ||
504 | dprintk("%s: invalid root filehandle\n", __FUNCTION__); | ||
505 | return -EINVAL; | ||
506 | } | ||
635 | 507 | ||
636 | server->client->cl_intr = (server->flags & NFS_MOUNT_INTR) ? 1 : 0; | 508 | memcpy(mntfh->data, data->root.data, mntfh->size); |
637 | server->client->cl_softrtry = (server->flags & NFS_MOUNT_SOFT) ? 1 : 0; | 509 | if (mntfh->size < sizeof(mntfh->data)) |
510 | memset(mntfh->data + mntfh->size, 0, | ||
511 | sizeof(mntfh->data) - mntfh->size); | ||
638 | 512 | ||
639 | /* We're airborne Set socket buffersize */ | ||
640 | rpc_setbufsize(server->client, server->wsize + 100, server->rsize + 100); | ||
641 | return 0; | 513 | return 0; |
642 | /* Yargs. It didn't work out. */ | ||
643 | out_no_root: | ||
644 | dprintk("nfs_sb_init: get root inode failed: errno %d\n", -no_root_error); | ||
645 | if (!IS_ERR(root_inode)) | ||
646 | iput(root_inode); | ||
647 | return no_root_error; | ||
648 | } | 514 | } |
649 | 515 | ||
650 | /* | 516 | /* |
651 | * Initialise the timeout values for a connection | 517 | * Initialise the common bits of the superblock |
652 | */ | 518 | */ |
653 | static void nfs_init_timeout_values(struct rpc_timeout *to, int proto, unsigned int timeo, unsigned int retrans) | 519 | static inline void nfs_initialise_sb(struct super_block *sb) |
654 | { | 520 | { |
655 | to->to_initval = timeo * HZ / 10; | 521 | struct nfs_server *server = NFS_SB(sb); |
656 | to->to_retries = retrans; | ||
657 | if (!to->to_retries) | ||
658 | to->to_retries = 2; | ||
659 | |||
660 | switch (proto) { | ||
661 | case IPPROTO_TCP: | ||
662 | if (!to->to_initval) | ||
663 | to->to_initval = 60 * HZ; | ||
664 | if (to->to_initval > NFS_MAX_TCP_TIMEOUT) | ||
665 | to->to_initval = NFS_MAX_TCP_TIMEOUT; | ||
666 | to->to_increment = to->to_initval; | ||
667 | to->to_maxval = to->to_initval + (to->to_increment * to->to_retries); | ||
668 | to->to_exponential = 0; | ||
669 | break; | ||
670 | case IPPROTO_UDP: | ||
671 | default: | ||
672 | if (!to->to_initval) | ||
673 | to->to_initval = 11 * HZ / 10; | ||
674 | if (to->to_initval > NFS_MAX_UDP_TIMEOUT) | ||
675 | to->to_initval = NFS_MAX_UDP_TIMEOUT; | ||
676 | to->to_maxval = NFS_MAX_UDP_TIMEOUT; | ||
677 | to->to_exponential = 1; | ||
678 | break; | ||
679 | } | ||
680 | } | ||
681 | 522 | ||
682 | /* | 523 | sb->s_magic = NFS_SUPER_MAGIC; |
683 | * Create an RPC client handle. | ||
684 | */ | ||
685 | static struct rpc_clnt * | ||
686 | nfs_create_client(struct nfs_server *server, const struct nfs_mount_data *data) | ||
687 | { | ||
688 | struct rpc_timeout timeparms; | ||
689 | struct rpc_xprt *xprt = NULL; | ||
690 | struct rpc_clnt *clnt = NULL; | ||
691 | int proto = (data->flags & NFS_MOUNT_TCP) ? IPPROTO_TCP : IPPROTO_UDP; | ||
692 | |||
693 | nfs_init_timeout_values(&timeparms, proto, data->timeo, data->retrans); | ||
694 | |||
695 | server->retrans_timeo = timeparms.to_initval; | ||
696 | server->retrans_count = timeparms.to_retries; | ||
697 | |||
698 | /* create transport and client */ | ||
699 | xprt = xprt_create_proto(proto, &server->addr, &timeparms); | ||
700 | if (IS_ERR(xprt)) { | ||
701 | dprintk("%s: cannot create RPC transport. Error = %ld\n", | ||
702 | __FUNCTION__, PTR_ERR(xprt)); | ||
703 | return (struct rpc_clnt *)xprt; | ||
704 | } | ||
705 | clnt = rpc_create_client(xprt, server->hostname, &nfs_program, | ||
706 | server->rpc_ops->version, data->pseudoflavor); | ||
707 | if (IS_ERR(clnt)) { | ||
708 | dprintk("%s: cannot create RPC client. Error = %ld\n", | ||
709 | __FUNCTION__, PTR_ERR(xprt)); | ||
710 | goto out_fail; | ||
711 | } | ||
712 | 524 | ||
713 | clnt->cl_intr = 1; | 525 | /* We probably want something more informative here */ |
714 | clnt->cl_softrtry = 1; | 526 | snprintf(sb->s_id, sizeof(sb->s_id), |
527 | "%x:%x", MAJOR(sb->s_dev), MINOR(sb->s_dev)); | ||
528 | |||
529 | if (sb->s_blocksize == 0) | ||
530 | sb->s_blocksize = nfs_block_bits(server->wsize, | ||
531 | &sb->s_blocksize_bits); | ||
715 | 532 | ||
716 | return clnt; | 533 | if (server->flags & NFS_MOUNT_NOAC) |
534 | sb->s_flags |= MS_SYNCHRONOUS; | ||
717 | 535 | ||
718 | out_fail: | 536 | nfs_super_set_maxbytes(sb, server->maxfilesize); |
719 | return clnt; | ||
720 | } | 537 | } |
721 | 538 | ||
722 | /* | 539 | /* |
723 | * Clone a server record | 540 | * Finish setting up an NFS2/3 superblock |
724 | */ | 541 | */ |
725 | static struct nfs_server *nfs_clone_server(struct super_block *sb, struct nfs_clone_mount *data) | 542 | static void nfs_fill_super(struct super_block *sb, struct nfs_mount_data *data) |
726 | { | 543 | { |
727 | struct nfs_server *server = NFS_SB(sb); | 544 | struct nfs_server *server = NFS_SB(sb); |
728 | struct nfs_server *parent = NFS_SB(data->sb); | ||
729 | struct inode *root_inode; | ||
730 | struct nfs_fsinfo fsinfo; | ||
731 | void *err = ERR_PTR(-ENOMEM); | ||
732 | |||
733 | sb->s_op = data->sb->s_op; | ||
734 | sb->s_blocksize = data->sb->s_blocksize; | ||
735 | sb->s_blocksize_bits = data->sb->s_blocksize_bits; | ||
736 | sb->s_maxbytes = data->sb->s_maxbytes; | ||
737 | |||
738 | server->client_sys = server->client_acl = ERR_PTR(-EINVAL); | ||
739 | server->io_stats = nfs_alloc_iostats(); | ||
740 | if (server->io_stats == NULL) | ||
741 | goto out; | ||
742 | |||
743 | server->client = rpc_clone_client(parent->client); | ||
744 | if (IS_ERR((err = server->client))) | ||
745 | goto out; | ||
746 | |||
747 | if (!IS_ERR(parent->client_sys)) { | ||
748 | server->client_sys = rpc_clone_client(parent->client_sys); | ||
749 | if (IS_ERR((err = server->client_sys))) | ||
750 | goto out; | ||
751 | } | ||
752 | if (!IS_ERR(parent->client_acl)) { | ||
753 | server->client_acl = rpc_clone_client(parent->client_acl); | ||
754 | if (IS_ERR((err = server->client_acl))) | ||
755 | goto out; | ||
756 | } | ||
757 | root_inode = nfs_fhget(sb, data->fh, data->fattr); | ||
758 | if (!root_inode) | ||
759 | goto out; | ||
760 | sb->s_root = d_alloc_root(root_inode); | ||
761 | if (!sb->s_root) | ||
762 | goto out_put_root; | ||
763 | fsinfo.fattr = data->fattr; | ||
764 | if (NFS_PROTO(root_inode)->fsinfo(server, data->fh, &fsinfo) == 0) | ||
765 | nfs_super_set_maxbytes(sb, fsinfo.maxfilesize); | ||
766 | sb->s_root->d_op = server->rpc_ops->dentry_ops; | ||
767 | sb->s_flags |= MS_ACTIVE; | ||
768 | return server; | ||
769 | out_put_root: | ||
770 | iput(root_inode); | ||
771 | out: | ||
772 | return err; | ||
773 | } | ||
774 | 545 | ||
775 | /* | 546 | sb->s_blocksize_bits = 0; |
776 | * Copy an existing superblock and attach revised data | 547 | sb->s_blocksize = 0; |
777 | */ | 548 | if (data->bsize) |
778 | static int nfs_clone_generic_sb(struct nfs_clone_mount *data, | 549 | sb->s_blocksize = nfs_block_size(data->bsize, &sb->s_blocksize_bits); |
779 | struct super_block *(*fill_sb)(struct nfs_server *, struct nfs_clone_mount *), | ||
780 | struct nfs_server *(*fill_server)(struct super_block *, struct nfs_clone_mount *), | ||
781 | struct vfsmount *mnt) | ||
782 | { | ||
783 | struct nfs_server *server; | ||
784 | struct nfs_server *parent = NFS_SB(data->sb); | ||
785 | struct super_block *sb = ERR_PTR(-EINVAL); | ||
786 | char *hostname; | ||
787 | int error = -ENOMEM; | ||
788 | int len; | ||
789 | |||
790 | server = kmalloc(sizeof(struct nfs_server), GFP_KERNEL); | ||
791 | if (server == NULL) | ||
792 | goto out_err; | ||
793 | memcpy(server, parent, sizeof(*server)); | ||
794 | hostname = (data->hostname != NULL) ? data->hostname : parent->hostname; | ||
795 | len = strlen(hostname) + 1; | ||
796 | server->hostname = kmalloc(len, GFP_KERNEL); | ||
797 | if (server->hostname == NULL) | ||
798 | goto free_server; | ||
799 | memcpy(server->hostname, hostname, len); | ||
800 | error = rpciod_up(); | ||
801 | if (error != 0) | ||
802 | goto free_hostname; | ||
803 | |||
804 | sb = fill_sb(server, data); | ||
805 | if (IS_ERR(sb)) { | ||
806 | error = PTR_ERR(sb); | ||
807 | goto kill_rpciod; | ||
808 | } | ||
809 | |||
810 | if (sb->s_root) | ||
811 | goto out_rpciod_down; | ||
812 | 550 | ||
813 | server = fill_server(sb, data); | 551 | if (server->flags & NFS_MOUNT_VER3) { |
814 | if (IS_ERR(server)) { | 552 | /* The VFS shouldn't apply the umask to mode bits. We will do |
815 | error = PTR_ERR(server); | 553 | * so ourselves when necessary. |
816 | goto out_deactivate; | 554 | */ |
555 | sb->s_flags |= MS_POSIXACL; | ||
556 | sb->s_time_gran = 1; | ||
817 | } | 557 | } |
818 | return simple_set_mnt(mnt, sb); | 558 | |
819 | out_deactivate: | 559 | sb->s_op = &nfs_sops; |
820 | up_write(&sb->s_umount); | 560 | nfs_initialise_sb(sb); |
821 | deactivate_super(sb); | ||
822 | return error; | ||
823 | out_rpciod_down: | ||
824 | rpciod_down(); | ||
825 | kfree(server->hostname); | ||
826 | kfree(server); | ||
827 | return simple_set_mnt(mnt, sb); | ||
828 | kill_rpciod: | ||
829 | rpciod_down(); | ||
830 | free_hostname: | ||
831 | kfree(server->hostname); | ||
832 | free_server: | ||
833 | kfree(server); | ||
834 | out_err: | ||
835 | return error; | ||
836 | } | 561 | } |
837 | 562 | ||
838 | /* | 563 | /* |
839 | * Set up an NFS2/3 superblock | 564 | * Finish setting up a cloned NFS2/3 superblock |
840 | * | ||
841 | * The way this works is that the mount process passes a structure | ||
842 | * in the data argument which contains the server's IP address | ||
843 | * and the root file handle obtained from the server's mount | ||
844 | * daemon. We stash these away in the private superblock fields. | ||
845 | */ | 565 | */ |
846 | static int | 566 | static void nfs_clone_super(struct super_block *sb, |
847 | nfs_fill_super(struct super_block *sb, struct nfs_mount_data *data, int silent) | 567 | const struct super_block *old_sb) |
848 | { | 568 | { |
849 | struct nfs_server *server; | 569 | struct nfs_server *server = NFS_SB(sb); |
850 | rpc_authflavor_t authflavor; | ||
851 | 570 | ||
852 | server = NFS_SB(sb); | 571 | sb->s_blocksize_bits = old_sb->s_blocksize_bits; |
853 | sb->s_blocksize_bits = 0; | 572 | sb->s_blocksize = old_sb->s_blocksize; |
854 | sb->s_blocksize = 0; | 573 | sb->s_maxbytes = old_sb->s_maxbytes; |
855 | if (data->bsize) | ||
856 | sb->s_blocksize = nfs_block_size(data->bsize, &sb->s_blocksize_bits); | ||
857 | if (data->rsize) | ||
858 | server->rsize = nfs_block_size(data->rsize, NULL); | ||
859 | if (data->wsize) | ||
860 | server->wsize = nfs_block_size(data->wsize, NULL); | ||
861 | server->flags = data->flags & NFS_MOUNT_FLAGMASK; | ||
862 | |||
863 | server->acregmin = data->acregmin*HZ; | ||
864 | server->acregmax = data->acregmax*HZ; | ||
865 | server->acdirmin = data->acdirmin*HZ; | ||
866 | server->acdirmax = data->acdirmax*HZ; | ||
867 | |||
868 | /* Start lockd here, before we might error out */ | ||
869 | if (!(server->flags & NFS_MOUNT_NONLM)) | ||
870 | lockd_up(); | ||
871 | |||
872 | server->namelen = data->namlen; | ||
873 | server->hostname = kmalloc(strlen(data->hostname) + 1, GFP_KERNEL); | ||
874 | if (!server->hostname) | ||
875 | return -ENOMEM; | ||
876 | strcpy(server->hostname, data->hostname); | ||
877 | |||
878 | /* Check NFS protocol revision and initialize RPC op vector | ||
879 | * and file handle pool. */ | ||
880 | #ifdef CONFIG_NFS_V3 | ||
881 | if (server->flags & NFS_MOUNT_VER3) { | ||
882 | server->rpc_ops = &nfs_v3_clientops; | ||
883 | server->caps |= NFS_CAP_READDIRPLUS; | ||
884 | } else { | ||
885 | server->rpc_ops = &nfs_v2_clientops; | ||
886 | } | ||
887 | #else | ||
888 | server->rpc_ops = &nfs_v2_clientops; | ||
889 | #endif | ||
890 | 574 | ||
891 | /* Fill in pseudoflavor for mount version < 5 */ | ||
892 | if (!(data->flags & NFS_MOUNT_SECFLAVOUR)) | ||
893 | data->pseudoflavor = RPC_AUTH_UNIX; | ||
894 | authflavor = data->pseudoflavor; /* save for sb_init() */ | ||
895 | /* XXX maybe we want to add a server->pseudoflavor field */ | ||
896 | |||
897 | /* Create RPC client handles */ | ||
898 | server->client = nfs_create_client(server, data); | ||
899 | if (IS_ERR(server->client)) | ||
900 | return PTR_ERR(server->client); | ||
901 | /* RFC 2623, sec 2.3.2 */ | ||
902 | if (authflavor != RPC_AUTH_UNIX) { | ||
903 | struct rpc_auth *auth; | ||
904 | |||
905 | server->client_sys = rpc_clone_client(server->client); | ||
906 | if (IS_ERR(server->client_sys)) | ||
907 | return PTR_ERR(server->client_sys); | ||
908 | auth = rpcauth_create(RPC_AUTH_UNIX, server->client_sys); | ||
909 | if (IS_ERR(auth)) | ||
910 | return PTR_ERR(auth); | ||
911 | } else { | ||
912 | atomic_inc(&server->client->cl_count); | ||
913 | server->client_sys = server->client; | ||
914 | } | ||
915 | if (server->flags & NFS_MOUNT_VER3) { | 575 | if (server->flags & NFS_MOUNT_VER3) { |
916 | #ifdef CONFIG_NFS_V3_ACL | 576 | /* The VFS shouldn't apply the umask to mode bits. We will do |
917 | if (!(server->flags & NFS_MOUNT_NOACL)) { | 577 | * so ourselves when necessary. |
918 | server->client_acl = rpc_bind_new_program(server->client, &nfsacl_program, 3); | ||
919 | /* No errors! Assume that Sun nfsacls are supported */ | ||
920 | if (!IS_ERR(server->client_acl)) | ||
921 | server->caps |= NFS_CAP_ACLS; | ||
922 | } | ||
923 | #else | ||
924 | server->flags &= ~NFS_MOUNT_NOACL; | ||
925 | #endif /* CONFIG_NFS_V3_ACL */ | ||
926 | /* | ||
927 | * The VFS shouldn't apply the umask to mode bits. We will | ||
928 | * do so ourselves when necessary. | ||
929 | */ | 578 | */ |
930 | sb->s_flags |= MS_POSIXACL; | 579 | sb->s_flags |= MS_POSIXACL; |
931 | if (server->namelen == 0 || server->namelen > NFS3_MAXNAMLEN) | ||
932 | server->namelen = NFS3_MAXNAMLEN; | ||
933 | sb->s_time_gran = 1; | 580 | sb->s_time_gran = 1; |
934 | } else { | ||
935 | if (server->namelen == 0 || server->namelen > NFS2_MAXNAMLEN) | ||
936 | server->namelen = NFS2_MAXNAMLEN; | ||
937 | } | 581 | } |
938 | 582 | ||
939 | sb->s_op = &nfs_sops; | 583 | sb->s_op = old_sb->s_op; |
940 | return nfs_sb_init(sb, authflavor); | 584 | nfs_initialise_sb(sb); |
941 | } | 585 | } |
942 | 586 | ||
943 | static int nfs_set_super(struct super_block *s, void *data) | 587 | static int nfs_set_super(struct super_block *s, void *_server) |
944 | { | 588 | { |
945 | s->s_fs_info = data; | 589 | struct nfs_server *server = _server; |
946 | return set_anon_super(s, data); | 590 | int ret; |
591 | |||
592 | s->s_fs_info = server; | ||
593 | ret = set_anon_super(s, server); | ||
594 | if (ret == 0) | ||
595 | server->s_dev = s->s_dev; | ||
596 | return ret; | ||
947 | } | 597 | } |
948 | 598 | ||
949 | static int nfs_compare_super(struct super_block *sb, void *data) | 599 | static int nfs_compare_super(struct super_block *sb, void *data) |
950 | { | 600 | { |
951 | struct nfs_server *server = data; | 601 | struct nfs_server *server = data, *old = NFS_SB(sb); |
952 | struct nfs_server *old = NFS_SB(sb); | ||
953 | 602 | ||
954 | if (old->addr.sin_addr.s_addr != server->addr.sin_addr.s_addr) | 603 | if (old->nfs_client != server->nfs_client) |
955 | return 0; | 604 | return 0; |
956 | if (old->addr.sin_port != server->addr.sin_port) | 605 | if (memcmp(&old->fsid, &server->fsid, sizeof(old->fsid)) != 0) |
957 | return 0; | 606 | return 0; |
958 | return !nfs_compare_fh(&old->fh, &server->fh); | 607 | return 1; |
959 | } | 608 | } |
960 | 609 | ||
961 | static int nfs_get_sb(struct file_system_type *fs_type, | 610 | static int nfs_get_sb(struct file_system_type *fs_type, |
962 | int flags, const char *dev_name, void *raw_data, struct vfsmount *mnt) | 611 | int flags, const char *dev_name, void *raw_data, struct vfsmount *mnt) |
963 | { | 612 | { |
964 | int error; | ||
965 | struct nfs_server *server = NULL; | 613 | struct nfs_server *server = NULL; |
966 | struct super_block *s; | 614 | struct super_block *s; |
967 | struct nfs_fh *root; | 615 | struct nfs_fh mntfh; |
968 | struct nfs_mount_data *data = raw_data; | 616 | struct nfs_mount_data *data = raw_data; |
617 | struct dentry *mntroot; | ||
618 | int error; | ||
969 | 619 | ||
970 | error = -EINVAL; | 620 | /* Validate the mount data */ |
971 | if (data == NULL) { | 621 | error = nfs_validate_mount_data(data, &mntfh); |
972 | dprintk("%s: missing data argument\n", __FUNCTION__); | 622 | if (error < 0) |
973 | goto out_err_noserver; | 623 | return error; |
974 | } | ||
975 | if (data->version <= 0 || data->version > NFS_MOUNT_VERSION) { | ||
976 | dprintk("%s: bad mount version\n", __FUNCTION__); | ||
977 | goto out_err_noserver; | ||
978 | } | ||
979 | switch (data->version) { | ||
980 | case 1: | ||
981 | data->namlen = 0; | ||
982 | case 2: | ||
983 | data->bsize = 0; | ||
984 | case 3: | ||
985 | if (data->flags & NFS_MOUNT_VER3) { | ||
986 | dprintk("%s: mount structure version %d does not support NFSv3\n", | ||
987 | __FUNCTION__, | ||
988 | data->version); | ||
989 | goto out_err_noserver; | ||
990 | } | ||
991 | data->root.size = NFS2_FHSIZE; | ||
992 | memcpy(data->root.data, data->old_root.data, NFS2_FHSIZE); | ||
993 | case 4: | ||
994 | if (data->flags & NFS_MOUNT_SECFLAVOUR) { | ||
995 | dprintk("%s: mount structure version %d does not support strong security\n", | ||
996 | __FUNCTION__, | ||
997 | data->version); | ||
998 | goto out_err_noserver; | ||
999 | } | ||
1000 | case 5: | ||
1001 | memset(data->context, 0, sizeof(data->context)); | ||
1002 | } | ||
1003 | #ifndef CONFIG_NFS_V3 | ||
1004 | /* If NFSv3 is not compiled in, return -EPROTONOSUPPORT */ | ||
1005 | error = -EPROTONOSUPPORT; | ||
1006 | if (data->flags & NFS_MOUNT_VER3) { | ||
1007 | dprintk("%s: NFSv3 not compiled into kernel\n", __FUNCTION__); | ||
1008 | goto out_err_noserver; | ||
1009 | } | ||
1010 | #endif /* CONFIG_NFS_V3 */ | ||
1011 | 624 | ||
1012 | error = -ENOMEM; | 625 | /* Get a volume representation */ |
1013 | server = kzalloc(sizeof(struct nfs_server), GFP_KERNEL); | 626 | server = nfs_create_server(data, &mntfh); |
1014 | if (!server) | 627 | if (IS_ERR(server)) { |
628 | error = PTR_ERR(server); | ||
1015 | goto out_err_noserver; | 629 | goto out_err_noserver; |
1016 | /* Zero out the NFS state stuff */ | ||
1017 | init_nfsv4_state(server); | ||
1018 | server->client = server->client_sys = server->client_acl = ERR_PTR(-EINVAL); | ||
1019 | |||
1020 | root = &server->fh; | ||
1021 | if (data->flags & NFS_MOUNT_VER3) | ||
1022 | root->size = data->root.size; | ||
1023 | else | ||
1024 | root->size = NFS2_FHSIZE; | ||
1025 | error = -EINVAL; | ||
1026 | if (root->size > sizeof(root->data)) { | ||
1027 | dprintk("%s: invalid root filehandle\n", __FUNCTION__); | ||
1028 | goto out_err; | ||
1029 | } | ||
1030 | memcpy(root->data, data->root.data, root->size); | ||
1031 | |||
1032 | /* We now require that the mount process passes the remote address */ | ||
1033 | memcpy(&server->addr, &data->addr, sizeof(server->addr)); | ||
1034 | if (server->addr.sin_addr.s_addr == INADDR_ANY) { | ||
1035 | dprintk("%s: mount program didn't pass remote address!\n", | ||
1036 | __FUNCTION__); | ||
1037 | goto out_err; | ||
1038 | } | ||
1039 | |||
1040 | /* Fire up rpciod if not yet running */ | ||
1041 | error = rpciod_up(); | ||
1042 | if (error < 0) { | ||
1043 | dprintk("%s: couldn't start rpciod! Error = %d\n", | ||
1044 | __FUNCTION__, error); | ||
1045 | goto out_err; | ||
1046 | } | 630 | } |
1047 | 631 | ||
632 | /* Get a superblock - note that we may end up sharing one that already exists */ | ||
1048 | s = sget(fs_type, nfs_compare_super, nfs_set_super, server); | 633 | s = sget(fs_type, nfs_compare_super, nfs_set_super, server); |
1049 | if (IS_ERR(s)) { | 634 | if (IS_ERR(s)) { |
1050 | error = PTR_ERR(s); | 635 | error = PTR_ERR(s); |
1051 | goto out_err_rpciod; | 636 | goto out_err_nosb; |
1052 | } | 637 | } |
1053 | 638 | ||
1054 | if (s->s_root) | 639 | if (s->s_fs_info != server) { |
1055 | goto out_rpciod_down; | 640 | nfs_free_server(server); |
641 | server = NULL; | ||
642 | } | ||
1056 | 643 | ||
1057 | s->s_flags = flags; | 644 | if (!s->s_root) { |
645 | /* initial superblock/root creation */ | ||
646 | s->s_flags = flags; | ||
647 | nfs_fill_super(s, data); | ||
648 | } | ||
1058 | 649 | ||
1059 | error = nfs_fill_super(s, data, flags & MS_SILENT ? 1 : 0); | 650 | mntroot = nfs_get_root(s, &mntfh); |
1060 | if (error) { | 651 | if (IS_ERR(mntroot)) { |
1061 | up_write(&s->s_umount); | 652 | error = PTR_ERR(mntroot); |
1062 | deactivate_super(s); | 653 | goto error_splat_super; |
1063 | return error; | ||
1064 | } | 654 | } |
1065 | s->s_flags |= MS_ACTIVE; | ||
1066 | return simple_set_mnt(mnt, s); | ||
1067 | 655 | ||
1068 | out_rpciod_down: | 656 | s->s_flags |= MS_ACTIVE; |
1069 | rpciod_down(); | 657 | mnt->mnt_sb = s; |
1070 | kfree(server); | 658 | mnt->mnt_root = mntroot; |
1071 | return simple_set_mnt(mnt, s); | 659 | return 0; |
1072 | 660 | ||
1073 | out_err_rpciod: | 661 | out_err_nosb: |
1074 | rpciod_down(); | 662 | nfs_free_server(server); |
1075 | out_err: | ||
1076 | kfree(server); | ||
1077 | out_err_noserver: | 663 | out_err_noserver: |
1078 | return error; | 664 | return error; |
665 | |||
666 | error_splat_super: | ||
667 | up_write(&s->s_umount); | ||
668 | deactivate_super(s); | ||
669 | return error; | ||
1079 | } | 670 | } |
1080 | 671 | ||
672 | /* | ||
673 | * Destroy an NFS2/3 superblock | ||
674 | */ | ||
1081 | static void nfs_kill_super(struct super_block *s) | 675 | static void nfs_kill_super(struct super_block *s) |
1082 | { | 676 | { |
1083 | struct nfs_server *server = NFS_SB(s); | 677 | struct nfs_server *server = NFS_SB(s); |
1084 | 678 | ||
1085 | kill_anon_super(s); | 679 | kill_anon_super(s); |
1086 | 680 | nfs_free_server(server); | |
1087 | if (!IS_ERR(server->client)) | ||
1088 | rpc_shutdown_client(server->client); | ||
1089 | if (!IS_ERR(server->client_sys)) | ||
1090 | rpc_shutdown_client(server->client_sys); | ||
1091 | if (!IS_ERR(server->client_acl)) | ||
1092 | rpc_shutdown_client(server->client_acl); | ||
1093 | |||
1094 | if (!(server->flags & NFS_MOUNT_NONLM)) | ||
1095 | lockd_down(); /* release rpc.lockd */ | ||
1096 | |||
1097 | rpciod_down(); /* release rpciod */ | ||
1098 | |||
1099 | nfs_free_iostats(server->io_stats); | ||
1100 | kfree(server->hostname); | ||
1101 | kfree(server); | ||
1102 | nfs_release_automount_timer(); | ||
1103 | } | ||
1104 | |||
1105 | static struct super_block *nfs_clone_sb(struct nfs_server *server, struct nfs_clone_mount *data) | ||
1106 | { | ||
1107 | struct super_block *sb; | ||
1108 | |||
1109 | server->fsid = data->fattr->fsid; | ||
1110 | nfs_copy_fh(&server->fh, data->fh); | ||
1111 | sb = sget(&nfs_fs_type, nfs_compare_super, nfs_set_super, server); | ||
1112 | if (!IS_ERR(sb) && sb->s_root == NULL && !(server->flags & NFS_MOUNT_NONLM)) | ||
1113 | lockd_up(); | ||
1114 | return sb; | ||
1115 | } | 681 | } |
1116 | 682 | ||
1117 | static int nfs_clone_nfs_sb(struct file_system_type *fs_type, | 683 | /* |
1118 | int flags, const char *dev_name, void *raw_data, struct vfsmount *mnt) | 684 | * Clone an NFS2/3 server record on xdev traversal (FSID-change) |
685 | */ | ||
686 | static int nfs_xdev_get_sb(struct file_system_type *fs_type, int flags, | ||
687 | const char *dev_name, void *raw_data, | ||
688 | struct vfsmount *mnt) | ||
1119 | { | 689 | { |
1120 | struct nfs_clone_mount *data = raw_data; | 690 | struct nfs_clone_mount *data = raw_data; |
1121 | return nfs_clone_generic_sb(data, nfs_clone_sb, nfs_clone_server, mnt); | 691 | struct super_block *s; |
1122 | } | 692 | struct nfs_server *server; |
693 | struct dentry *mntroot; | ||
694 | int error; | ||
1123 | 695 | ||
1124 | #ifdef CONFIG_NFS_V4 | 696 | dprintk("--> nfs_xdev_get_sb()\n"); |
1125 | static struct rpc_clnt *nfs4_create_client(struct nfs_server *server, | ||
1126 | struct rpc_timeout *timeparms, int proto, rpc_authflavor_t flavor) | ||
1127 | { | ||
1128 | struct nfs4_client *clp; | ||
1129 | struct rpc_xprt *xprt = NULL; | ||
1130 | struct rpc_clnt *clnt = NULL; | ||
1131 | int err = -EIO; | ||
1132 | |||
1133 | clp = nfs4_get_client(&server->addr.sin_addr); | ||
1134 | if (!clp) { | ||
1135 | dprintk("%s: failed to create NFS4 client.\n", __FUNCTION__); | ||
1136 | return ERR_PTR(err); | ||
1137 | } | ||
1138 | 697 | ||
1139 | /* Now create transport and client */ | 698 | /* create a new volume representation */ |
1140 | down_write(&clp->cl_sem); | 699 | server = nfs_clone_server(NFS_SB(data->sb), data->fh, data->fattr); |
1141 | if (IS_ERR(clp->cl_rpcclient)) { | 700 | if (IS_ERR(server)) { |
1142 | xprt = xprt_create_proto(proto, &server->addr, timeparms); | 701 | error = PTR_ERR(server); |
1143 | if (IS_ERR(xprt)) { | 702 | goto out_err_noserver; |
1144 | up_write(&clp->cl_sem); | ||
1145 | err = PTR_ERR(xprt); | ||
1146 | dprintk("%s: cannot create RPC transport. Error = %d\n", | ||
1147 | __FUNCTION__, err); | ||
1148 | goto out_fail; | ||
1149 | } | ||
1150 | /* Bind to a reserved port! */ | ||
1151 | xprt->resvport = 1; | ||
1152 | clnt = rpc_create_client(xprt, server->hostname, &nfs_program, | ||
1153 | server->rpc_ops->version, flavor); | ||
1154 | if (IS_ERR(clnt)) { | ||
1155 | up_write(&clp->cl_sem); | ||
1156 | err = PTR_ERR(clnt); | ||
1157 | dprintk("%s: cannot create RPC client. Error = %d\n", | ||
1158 | __FUNCTION__, err); | ||
1159 | goto out_fail; | ||
1160 | } | ||
1161 | clnt->cl_intr = 1; | ||
1162 | clnt->cl_softrtry = 1; | ||
1163 | clp->cl_rpcclient = clnt; | ||
1164 | memcpy(clp->cl_ipaddr, server->ip_addr, sizeof(clp->cl_ipaddr)); | ||
1165 | nfs_idmap_new(clp); | ||
1166 | } | ||
1167 | list_add_tail(&server->nfs4_siblings, &clp->cl_superblocks); | ||
1168 | clnt = rpc_clone_client(clp->cl_rpcclient); | ||
1169 | if (!IS_ERR(clnt)) | ||
1170 | server->nfs4_state = clp; | ||
1171 | up_write(&clp->cl_sem); | ||
1172 | clp = NULL; | ||
1173 | |||
1174 | if (IS_ERR(clnt)) { | ||
1175 | dprintk("%s: cannot create RPC client. Error = %d\n", | ||
1176 | __FUNCTION__, err); | ||
1177 | return clnt; | ||
1178 | } | 703 | } |
1179 | 704 | ||
1180 | if (server->nfs4_state->cl_idmap == NULL) { | 705 | /* Get a superblock - note that we may end up sharing one that already exists */ |
1181 | dprintk("%s: failed to create idmapper.\n", __FUNCTION__); | 706 | s = sget(&nfs_fs_type, nfs_compare_super, nfs_set_super, server); |
1182 | return ERR_PTR(-ENOMEM); | 707 | if (IS_ERR(s)) { |
708 | error = PTR_ERR(s); | ||
709 | goto out_err_nosb; | ||
1183 | } | 710 | } |
1184 | 711 | ||
1185 | if (clnt->cl_auth->au_flavor != flavor) { | 712 | if (s->s_fs_info != server) { |
1186 | struct rpc_auth *auth; | 713 | nfs_free_server(server); |
1187 | 714 | server = NULL; | |
1188 | auth = rpcauth_create(flavor, clnt); | ||
1189 | if (IS_ERR(auth)) { | ||
1190 | dprintk("%s: couldn't create credcache!\n", __FUNCTION__); | ||
1191 | return (struct rpc_clnt *)auth; | ||
1192 | } | ||
1193 | } | 715 | } |
1194 | return clnt; | ||
1195 | |||
1196 | out_fail: | ||
1197 | if (clp) | ||
1198 | nfs4_put_client(clp); | ||
1199 | return ERR_PTR(err); | ||
1200 | } | ||
1201 | |||
1202 | /* | ||
1203 | * Set up an NFS4 superblock | ||
1204 | */ | ||
1205 | static int nfs4_fill_super(struct super_block *sb, struct nfs4_mount_data *data, int silent) | ||
1206 | { | ||
1207 | struct nfs_server *server; | ||
1208 | struct rpc_timeout timeparms; | ||
1209 | rpc_authflavor_t authflavour; | ||
1210 | int err = -EIO; | ||
1211 | 716 | ||
1212 | sb->s_blocksize_bits = 0; | 717 | if (!s->s_root) { |
1213 | sb->s_blocksize = 0; | 718 | /* initial superblock/root creation */ |
1214 | server = NFS_SB(sb); | 719 | s->s_flags = flags; |
1215 | if (data->rsize != 0) | 720 | nfs_clone_super(s, data->sb); |
1216 | server->rsize = nfs_block_size(data->rsize, NULL); | 721 | } |
1217 | if (data->wsize != 0) | ||
1218 | server->wsize = nfs_block_size(data->wsize, NULL); | ||
1219 | server->flags = data->flags & NFS_MOUNT_FLAGMASK; | ||
1220 | server->caps = NFS_CAP_ATOMIC_OPEN; | ||
1221 | 722 | ||
1222 | server->acregmin = data->acregmin*HZ; | 723 | mntroot = nfs_get_root(s, data->fh); |
1223 | server->acregmax = data->acregmax*HZ; | 724 | if (IS_ERR(mntroot)) { |
1224 | server->acdirmin = data->acdirmin*HZ; | 725 | error = PTR_ERR(mntroot); |
1225 | server->acdirmax = data->acdirmax*HZ; | 726 | goto error_splat_super; |
727 | } | ||
1226 | 728 | ||
1227 | server->rpc_ops = &nfs_v4_clientops; | 729 | s->s_flags |= MS_ACTIVE; |
730 | mnt->mnt_sb = s; | ||
731 | mnt->mnt_root = mntroot; | ||
1228 | 732 | ||
1229 | nfs_init_timeout_values(&timeparms, data->proto, data->timeo, data->retrans); | 733 | dprintk("<-- nfs_xdev_get_sb() = 0\n"); |
734 | return 0; | ||
1230 | 735 | ||
1231 | server->retrans_timeo = timeparms.to_initval; | 736 | out_err_nosb: |
1232 | server->retrans_count = timeparms.to_retries; | 737 | nfs_free_server(server); |
738 | out_err_noserver: | ||
739 | dprintk("<-- nfs_xdev_get_sb() = %d [error]\n", error); | ||
740 | return error; | ||
1233 | 741 | ||
1234 | /* Now create transport and client */ | 742 | error_splat_super: |
1235 | authflavour = RPC_AUTH_UNIX; | 743 | up_write(&s->s_umount); |
1236 | if (data->auth_flavourlen != 0) { | 744 | deactivate_super(s); |
1237 | if (data->auth_flavourlen != 1) { | 745 | dprintk("<-- nfs_xdev_get_sb() = %d [splat]\n", error); |
1238 | dprintk("%s: Invalid number of RPC auth flavours %d.\n", | 746 | return error; |
1239 | __FUNCTION__, data->auth_flavourlen); | 747 | } |
1240 | err = -EINVAL; | ||
1241 | goto out_fail; | ||
1242 | } | ||
1243 | if (copy_from_user(&authflavour, data->auth_flavours, sizeof(authflavour))) { | ||
1244 | err = -EFAULT; | ||
1245 | goto out_fail; | ||
1246 | } | ||
1247 | } | ||
1248 | 748 | ||
1249 | server->client = nfs4_create_client(server, &timeparms, data->proto, authflavour); | 749 | #ifdef CONFIG_NFS_V4 |
1250 | if (IS_ERR(server->client)) { | ||
1251 | err = PTR_ERR(server->client); | ||
1252 | dprintk("%s: cannot create RPC client. Error = %d\n", | ||
1253 | __FUNCTION__, err); | ||
1254 | goto out_fail; | ||
1255 | } | ||
1256 | 750 | ||
751 | /* | ||
752 | * Finish setting up a cloned NFS4 superblock | ||
753 | */ | ||
754 | static void nfs4_clone_super(struct super_block *sb, | ||
755 | const struct super_block *old_sb) | ||
756 | { | ||
757 | sb->s_blocksize_bits = old_sb->s_blocksize_bits; | ||
758 | sb->s_blocksize = old_sb->s_blocksize; | ||
759 | sb->s_maxbytes = old_sb->s_maxbytes; | ||
1257 | sb->s_time_gran = 1; | 760 | sb->s_time_gran = 1; |
1258 | 761 | sb->s_op = old_sb->s_op; | |
1259 | sb->s_op = &nfs4_sops; | 762 | nfs_initialise_sb(sb); |
1260 | err = nfs_sb_init(sb, authflavour); | ||
1261 | |||
1262 | out_fail: | ||
1263 | return err; | ||
1264 | } | 763 | } |
1265 | 764 | ||
1266 | static int nfs4_compare_super(struct super_block *sb, void *data) | 765 | /* |
766 | * Set up an NFS4 superblock | ||
767 | */ | ||
768 | static void nfs4_fill_super(struct super_block *sb) | ||
1267 | { | 769 | { |
1268 | struct nfs_server *server = data; | 770 | sb->s_time_gran = 1; |
1269 | struct nfs_server *old = NFS_SB(sb); | 771 | sb->s_op = &nfs4_sops; |
1270 | 772 | nfs_initialise_sb(sb); | |
1271 | if (strcmp(server->hostname, old->hostname) != 0) | ||
1272 | return 0; | ||
1273 | if (strcmp(server->mnt_path, old->mnt_path) != 0) | ||
1274 | return 0; | ||
1275 | return 1; | ||
1276 | } | 773 | } |
1277 | 774 | ||
1278 | static void * | 775 | static void *nfs_copy_user_string(char *dst, struct nfs_string *src, int maxlen) |
1279 | nfs_copy_user_string(char *dst, struct nfs_string *src, int maxlen) | ||
1280 | { | 776 | { |
1281 | void *p = NULL; | 777 | void *p = NULL; |
1282 | 778 | ||
@@ -1297,14 +793,22 @@ nfs_copy_user_string(char *dst, struct nfs_string *src, int maxlen) | |||
1297 | return dst; | 793 | return dst; |
1298 | } | 794 | } |
1299 | 795 | ||
796 | /* | ||
797 | * Get the superblock for an NFS4 mountpoint | ||
798 | */ | ||
1300 | static int nfs4_get_sb(struct file_system_type *fs_type, | 799 | static int nfs4_get_sb(struct file_system_type *fs_type, |
1301 | int flags, const char *dev_name, void *raw_data, struct vfsmount *mnt) | 800 | int flags, const char *dev_name, void *raw_data, struct vfsmount *mnt) |
1302 | { | 801 | { |
1303 | int error; | ||
1304 | struct nfs_server *server; | ||
1305 | struct super_block *s; | ||
1306 | struct nfs4_mount_data *data = raw_data; | 802 | struct nfs4_mount_data *data = raw_data; |
803 | struct super_block *s; | ||
804 | struct nfs_server *server; | ||
805 | struct sockaddr_in addr; | ||
806 | rpc_authflavor_t authflavour; | ||
807 | struct nfs_fh mntfh; | ||
808 | struct dentry *mntroot; | ||
809 | char *mntpath = NULL, *hostname = NULL, ip_addr[16]; | ||
1307 | void *p; | 810 | void *p; |
811 | int error; | ||
1308 | 812 | ||
1309 | if (data == NULL) { | 813 | if (data == NULL) { |
1310 | dprintk("%s: missing data argument\n", __FUNCTION__); | 814 | dprintk("%s: missing data argument\n", __FUNCTION__); |
@@ -1315,84 +819,112 @@ static int nfs4_get_sb(struct file_system_type *fs_type, | |||
1315 | return -EINVAL; | 819 | return -EINVAL; |
1316 | } | 820 | } |
1317 | 821 | ||
1318 | server = kzalloc(sizeof(struct nfs_server), GFP_KERNEL); | 822 | /* We now require that the mount process passes the remote address */ |
1319 | if (!server) | 823 | if (data->host_addrlen != sizeof(addr)) |
1320 | return -ENOMEM; | 824 | return -EINVAL; |
1321 | /* Zero out the NFS state stuff */ | 825 | |
1322 | init_nfsv4_state(server); | 826 | if (copy_from_user(&addr, data->host_addr, sizeof(addr))) |
1323 | server->client = server->client_sys = server->client_acl = ERR_PTR(-EINVAL); | 827 | return -EFAULT; |
828 | |||
829 | if (addr.sin_family != AF_INET || | ||
830 | addr.sin_addr.s_addr == INADDR_ANY | ||
831 | ) { | ||
832 | dprintk("%s: mount program didn't pass remote IP address!\n", | ||
833 | __FUNCTION__); | ||
834 | return -EINVAL; | ||
835 | } | ||
836 | /* RFC3530: The default port for NFS is 2049 */ | ||
837 | if (addr.sin_port == 0) | ||
838 | addr.sin_port = NFS_PORT; | ||
839 | |||
840 | /* Grab the authentication type */ | ||
841 | authflavour = RPC_AUTH_UNIX; | ||
842 | if (data->auth_flavourlen != 0) { | ||
843 | if (data->auth_flavourlen != 1) { | ||
844 | dprintk("%s: Invalid number of RPC auth flavours %d.\n", | ||
845 | __FUNCTION__, data->auth_flavourlen); | ||
846 | error = -EINVAL; | ||
847 | goto out_err_noserver; | ||
848 | } | ||
849 | |||
850 | if (copy_from_user(&authflavour, data->auth_flavours, | ||
851 | sizeof(authflavour))) { | ||
852 | error = -EFAULT; | ||
853 | goto out_err_noserver; | ||
854 | } | ||
855 | } | ||
1324 | 856 | ||
1325 | p = nfs_copy_user_string(NULL, &data->hostname, 256); | 857 | p = nfs_copy_user_string(NULL, &data->hostname, 256); |
1326 | if (IS_ERR(p)) | 858 | if (IS_ERR(p)) |
1327 | goto out_err; | 859 | goto out_err; |
1328 | server->hostname = p; | 860 | hostname = p; |
1329 | 861 | ||
1330 | p = nfs_copy_user_string(NULL, &data->mnt_path, 1024); | 862 | p = nfs_copy_user_string(NULL, &data->mnt_path, 1024); |
1331 | if (IS_ERR(p)) | 863 | if (IS_ERR(p)) |
1332 | goto out_err; | 864 | goto out_err; |
1333 | server->mnt_path = p; | 865 | mntpath = p; |
866 | |||
867 | dprintk("MNTPATH: %s\n", mntpath); | ||
1334 | 868 | ||
1335 | p = nfs_copy_user_string(server->ip_addr, &data->client_addr, | 869 | p = nfs_copy_user_string(ip_addr, &data->client_addr, |
1336 | sizeof(server->ip_addr) - 1); | 870 | sizeof(ip_addr) - 1); |
1337 | if (IS_ERR(p)) | 871 | if (IS_ERR(p)) |
1338 | goto out_err; | 872 | goto out_err; |
1339 | 873 | ||
1340 | /* We now require that the mount process passes the remote address */ | 874 | /* Get a volume representation */ |
1341 | if (data->host_addrlen != sizeof(server->addr)) { | 875 | server = nfs4_create_server(data, hostname, &addr, mntpath, ip_addr, |
1342 | error = -EINVAL; | 876 | authflavour, &mntfh); |
1343 | goto out_free; | 877 | if (IS_ERR(server)) { |
1344 | } | 878 | error = PTR_ERR(server); |
1345 | if (copy_from_user(&server->addr, data->host_addr, sizeof(server->addr))) { | 879 | goto out_err_noserver; |
1346 | error = -EFAULT; | ||
1347 | goto out_free; | ||
1348 | } | ||
1349 | if (server->addr.sin_family != AF_INET || | ||
1350 | server->addr.sin_addr.s_addr == INADDR_ANY) { | ||
1351 | dprintk("%s: mount program didn't pass remote IP address!\n", | ||
1352 | __FUNCTION__); | ||
1353 | error = -EINVAL; | ||
1354 | goto out_free; | ||
1355 | } | ||
1356 | |||
1357 | /* Fire up rpciod if not yet running */ | ||
1358 | error = rpciod_up(); | ||
1359 | if (error < 0) { | ||
1360 | dprintk("%s: couldn't start rpciod! Error = %d\n", | ||
1361 | __FUNCTION__, error); | ||
1362 | goto out_free; | ||
1363 | } | 880 | } |
1364 | 881 | ||
1365 | s = sget(fs_type, nfs4_compare_super, nfs_set_super, server); | 882 | /* Get a superblock - note that we may end up sharing one that already exists */ |
1366 | 883 | s = sget(fs_type, nfs_compare_super, nfs_set_super, server); | |
1367 | if (IS_ERR(s)) { | 884 | if (IS_ERR(s)) { |
1368 | error = PTR_ERR(s); | 885 | error = PTR_ERR(s); |
1369 | goto out_free; | 886 | goto out_free; |
1370 | } | 887 | } |
1371 | 888 | ||
1372 | if (s->s_root) { | 889 | if (s->s_fs_info != server) { |
1373 | kfree(server->mnt_path); | 890 | nfs_free_server(server); |
1374 | kfree(server->hostname); | 891 | server = NULL; |
1375 | kfree(server); | ||
1376 | return simple_set_mnt(mnt, s); | ||
1377 | } | 892 | } |
1378 | 893 | ||
1379 | s->s_flags = flags; | 894 | if (!s->s_root) { |
895 | /* initial superblock/root creation */ | ||
896 | s->s_flags = flags; | ||
897 | nfs4_fill_super(s); | ||
898 | } | ||
1380 | 899 | ||
1381 | error = nfs4_fill_super(s, data, flags & MS_SILENT ? 1 : 0); | 900 | mntroot = nfs4_get_root(s, &mntfh); |
1382 | if (error) { | 901 | if (IS_ERR(mntroot)) { |
1383 | up_write(&s->s_umount); | 902 | error = PTR_ERR(mntroot); |
1384 | deactivate_super(s); | 903 | goto error_splat_super; |
1385 | return error; | ||
1386 | } | 904 | } |
905 | |||
1387 | s->s_flags |= MS_ACTIVE; | 906 | s->s_flags |= MS_ACTIVE; |
1388 | return simple_set_mnt(mnt, s); | 907 | mnt->mnt_sb = s; |
908 | mnt->mnt_root = mntroot; | ||
909 | kfree(mntpath); | ||
910 | kfree(hostname); | ||
911 | return 0; | ||
912 | |||
1389 | out_err: | 913 | out_err: |
1390 | error = PTR_ERR(p); | 914 | error = PTR_ERR(p); |
915 | goto out_err_noserver; | ||
916 | |||
1391 | out_free: | 917 | out_free: |
1392 | kfree(server->mnt_path); | 918 | nfs_free_server(server); |
1393 | kfree(server->hostname); | 919 | out_err_noserver: |
1394 | kfree(server); | 920 | kfree(mntpath); |
921 | kfree(hostname); | ||
1395 | return error; | 922 | return error; |
923 | |||
924 | error_splat_super: | ||
925 | up_write(&s->s_umount); | ||
926 | deactivate_super(s); | ||
927 | goto out_err_noserver; | ||
1396 | } | 928 | } |
1397 | 929 | ||
1398 | static void nfs4_kill_super(struct super_block *sb) | 930 | static void nfs4_kill_super(struct super_block *sb) |
@@ -1403,135 +935,140 @@ static void nfs4_kill_super(struct super_block *sb) | |||
1403 | kill_anon_super(sb); | 935 | kill_anon_super(sb); |
1404 | 936 | ||
1405 | nfs4_renewd_prepare_shutdown(server); | 937 | nfs4_renewd_prepare_shutdown(server); |
938 | nfs_free_server(server); | ||
939 | } | ||
940 | |||
941 | /* | ||
942 | * Clone an NFS4 server record on xdev traversal (FSID-change) | ||
943 | */ | ||
944 | static int nfs4_xdev_get_sb(struct file_system_type *fs_type, int flags, | ||
945 | const char *dev_name, void *raw_data, | ||
946 | struct vfsmount *mnt) | ||
947 | { | ||
948 | struct nfs_clone_mount *data = raw_data; | ||
949 | struct super_block *s; | ||
950 | struct nfs_server *server; | ||
951 | struct dentry *mntroot; | ||
952 | int error; | ||
953 | |||
954 | dprintk("--> nfs4_xdev_get_sb()\n"); | ||
955 | |||
956 | /* create a new volume representation */ | ||
957 | server = nfs_clone_server(NFS_SB(data->sb), data->fh, data->fattr); | ||
958 | if (IS_ERR(server)) { | ||
959 | error = PTR_ERR(server); | ||
960 | goto out_err_noserver; | ||
961 | } | ||
962 | |||
963 | /* Get a superblock - note that we may end up sharing one that already exists */ | ||
964 | s = sget(&nfs_fs_type, nfs_compare_super, nfs_set_super, server); | ||
965 | if (IS_ERR(s)) { | ||
966 | error = PTR_ERR(s); | ||
967 | goto out_err_nosb; | ||
968 | } | ||
1406 | 969 | ||
1407 | if (server->client != NULL && !IS_ERR(server->client)) | 970 | if (s->s_fs_info != server) { |
1408 | rpc_shutdown_client(server->client); | 971 | nfs_free_server(server); |
972 | server = NULL; | ||
973 | } | ||
1409 | 974 | ||
1410 | destroy_nfsv4_state(server); | 975 | if (!s->s_root) { |
976 | /* initial superblock/root creation */ | ||
977 | s->s_flags = flags; | ||
978 | nfs4_clone_super(s, data->sb); | ||
979 | } | ||
980 | |||
981 | mntroot = nfs4_get_root(s, data->fh); | ||
982 | if (IS_ERR(mntroot)) { | ||
983 | error = PTR_ERR(mntroot); | ||
984 | goto error_splat_super; | ||
985 | } | ||
1411 | 986 | ||
1412 | rpciod_down(); | 987 | s->s_flags |= MS_ACTIVE; |
988 | mnt->mnt_sb = s; | ||
989 | mnt->mnt_root = mntroot; | ||
990 | |||
991 | dprintk("<-- nfs4_xdev_get_sb() = 0\n"); | ||
992 | return 0; | ||
993 | |||
994 | out_err_nosb: | ||
995 | nfs_free_server(server); | ||
996 | out_err_noserver: | ||
997 | dprintk("<-- nfs4_xdev_get_sb() = %d [error]\n", error); | ||
998 | return error; | ||
1413 | 999 | ||
1414 | nfs_free_iostats(server->io_stats); | 1000 | error_splat_super: |
1415 | kfree(server->hostname); | 1001 | up_write(&s->s_umount); |
1416 | kfree(server); | 1002 | deactivate_super(s); |
1417 | nfs_release_automount_timer(); | 1003 | dprintk("<-- nfs4_xdev_get_sb() = %d [splat]\n", error); |
1004 | return error; | ||
1418 | } | 1005 | } |
1419 | 1006 | ||
1420 | /* | 1007 | /* |
1421 | * Constructs the SERVER-side path | 1008 | * Create an NFS4 server record on referral traversal |
1422 | */ | 1009 | */ |
1423 | static inline char *nfs4_dup_path(const struct dentry *dentry) | 1010 | static int nfs4_referral_get_sb(struct file_system_type *fs_type, int flags, |
1011 | const char *dev_name, void *raw_data, | ||
1012 | struct vfsmount *mnt) | ||
1424 | { | 1013 | { |
1425 | char *page = (char *) __get_free_page(GFP_USER); | 1014 | struct nfs_clone_mount *data = raw_data; |
1426 | char *path; | 1015 | struct super_block *s; |
1016 | struct nfs_server *server; | ||
1017 | struct dentry *mntroot; | ||
1018 | struct nfs_fh mntfh; | ||
1019 | int error; | ||
1427 | 1020 | ||
1428 | path = nfs4_path(dentry, page, PAGE_SIZE); | 1021 | dprintk("--> nfs4_referral_get_sb()\n"); |
1429 | if (!IS_ERR(path)) { | ||
1430 | int len = PAGE_SIZE + page - path; | ||
1431 | char *tmp = path; | ||
1432 | 1022 | ||
1433 | path = kmalloc(len, GFP_KERNEL); | 1023 | /* create a new volume representation */ |
1434 | if (path) | 1024 | server = nfs4_create_referral_server(data, &mntfh); |
1435 | memcpy(path, tmp, len); | 1025 | if (IS_ERR(server)) { |
1436 | else | 1026 | error = PTR_ERR(server); |
1437 | path = ERR_PTR(-ENOMEM); | 1027 | goto out_err_noserver; |
1438 | } | 1028 | } |
1439 | free_page((unsigned long)page); | ||
1440 | return path; | ||
1441 | } | ||
1442 | 1029 | ||
1443 | static struct super_block *nfs4_clone_sb(struct nfs_server *server, struct nfs_clone_mount *data) | 1030 | /* Get a superblock - note that we may end up sharing one that already exists */ |
1444 | { | 1031 | s = sget(&nfs_fs_type, nfs_compare_super, nfs_set_super, server); |
1445 | const struct dentry *dentry = data->dentry; | 1032 | if (IS_ERR(s)) { |
1446 | struct nfs4_client *clp = server->nfs4_state; | 1033 | error = PTR_ERR(s); |
1447 | struct super_block *sb; | 1034 | goto out_err_nosb; |
1448 | |||
1449 | server->fsid = data->fattr->fsid; | ||
1450 | nfs_copy_fh(&server->fh, data->fh); | ||
1451 | server->mnt_path = nfs4_dup_path(dentry); | ||
1452 | if (IS_ERR(server->mnt_path)) { | ||
1453 | sb = (struct super_block *)server->mnt_path; | ||
1454 | goto err; | ||
1455 | } | 1035 | } |
1456 | sb = sget(&nfs4_fs_type, nfs4_compare_super, nfs_set_super, server); | ||
1457 | if (IS_ERR(sb) || sb->s_root) | ||
1458 | goto free_path; | ||
1459 | nfs4_server_capabilities(server, &server->fh); | ||
1460 | |||
1461 | down_write(&clp->cl_sem); | ||
1462 | atomic_inc(&clp->cl_count); | ||
1463 | list_add_tail(&server->nfs4_siblings, &clp->cl_superblocks); | ||
1464 | up_write(&clp->cl_sem); | ||
1465 | return sb; | ||
1466 | free_path: | ||
1467 | kfree(server->mnt_path); | ||
1468 | err: | ||
1469 | server->mnt_path = NULL; | ||
1470 | return sb; | ||
1471 | } | ||
1472 | 1036 | ||
1473 | static int nfs_clone_nfs4_sb(struct file_system_type *fs_type, | 1037 | if (s->s_fs_info != server) { |
1474 | int flags, const char *dev_name, void *raw_data, struct vfsmount *mnt) | 1038 | nfs_free_server(server); |
1475 | { | 1039 | server = NULL; |
1476 | struct nfs_clone_mount *data = raw_data; | 1040 | } |
1477 | return nfs_clone_generic_sb(data, nfs4_clone_sb, nfs_clone_server, mnt); | ||
1478 | } | ||
1479 | 1041 | ||
1480 | static struct super_block *nfs4_referral_sb(struct nfs_server *server, struct nfs_clone_mount *data) | 1042 | if (!s->s_root) { |
1481 | { | 1043 | /* initial superblock/root creation */ |
1482 | struct super_block *sb = ERR_PTR(-ENOMEM); | 1044 | s->s_flags = flags; |
1483 | int len; | 1045 | nfs4_fill_super(s); |
1484 | 1046 | } | |
1485 | len = strlen(data->mnt_path) + 1; | ||
1486 | server->mnt_path = kmalloc(len, GFP_KERNEL); | ||
1487 | if (server->mnt_path == NULL) | ||
1488 | goto err; | ||
1489 | memcpy(server->mnt_path, data->mnt_path, len); | ||
1490 | memcpy(&server->addr, data->addr, sizeof(struct sockaddr_in)); | ||
1491 | |||
1492 | sb = sget(&nfs4_fs_type, nfs4_compare_super, nfs_set_super, server); | ||
1493 | if (IS_ERR(sb) || sb->s_root) | ||
1494 | goto free_path; | ||
1495 | return sb; | ||
1496 | free_path: | ||
1497 | kfree(server->mnt_path); | ||
1498 | err: | ||
1499 | server->mnt_path = NULL; | ||
1500 | return sb; | ||
1501 | } | ||
1502 | 1047 | ||
1503 | static struct nfs_server *nfs4_referral_server(struct super_block *sb, struct nfs_clone_mount *data) | 1048 | mntroot = nfs4_get_root(s, data->fh); |
1504 | { | 1049 | if (IS_ERR(mntroot)) { |
1505 | struct nfs_server *server = NFS_SB(sb); | 1050 | error = PTR_ERR(mntroot); |
1506 | struct rpc_timeout timeparms; | 1051 | goto error_splat_super; |
1507 | int proto, timeo, retrans; | 1052 | } |
1508 | void *err; | ||
1509 | |||
1510 | proto = IPPROTO_TCP; | ||
1511 | /* Since we are following a referral and there may be alternatives, | ||
1512 | set the timeouts and retries to low values */ | ||
1513 | timeo = 2; | ||
1514 | retrans = 1; | ||
1515 | nfs_init_timeout_values(&timeparms, proto, timeo, retrans); | ||
1516 | |||
1517 | server->client = nfs4_create_client(server, &timeparms, proto, data->authflavor); | ||
1518 | if (IS_ERR((err = server->client))) | ||
1519 | goto out_err; | ||
1520 | 1053 | ||
1521 | sb->s_time_gran = 1; | 1054 | s->s_flags |= MS_ACTIVE; |
1522 | sb->s_op = &nfs4_sops; | 1055 | mnt->mnt_sb = s; |
1523 | err = ERR_PTR(nfs_sb_init(sb, data->authflavor)); | 1056 | mnt->mnt_root = mntroot; |
1524 | if (!IS_ERR(err)) | ||
1525 | return server; | ||
1526 | out_err: | ||
1527 | return (struct nfs_server *)err; | ||
1528 | } | ||
1529 | 1057 | ||
1530 | static int nfs_referral_nfs4_sb(struct file_system_type *fs_type, | 1058 | dprintk("<-- nfs4_referral_get_sb() = 0\n"); |
1531 | int flags, const char *dev_name, void *raw_data, struct vfsmount *mnt) | 1059 | return 0; |
1532 | { | 1060 | |
1533 | struct nfs_clone_mount *data = raw_data; | 1061 | out_err_nosb: |
1534 | return nfs_clone_generic_sb(data, nfs4_referral_sb, nfs4_referral_server, mnt); | 1062 | nfs_free_server(server); |
1063 | out_err_noserver: | ||
1064 | dprintk("<-- nfs4_referral_get_sb() = %d [error]\n", error); | ||
1065 | return error; | ||
1066 | |||
1067 | error_splat_super: | ||
1068 | up_write(&s->s_umount); | ||
1069 | deactivate_super(s); | ||
1070 | dprintk("<-- nfs4_referral_get_sb() = %d [splat]\n", error); | ||
1071 | return error; | ||
1535 | } | 1072 | } |
1536 | 1073 | ||
1537 | #endif | 1074 | #endif /* CONFIG_NFS_V4 */ |
diff --git a/fs/nfs/write.c b/fs/nfs/write.c index 7084ac9a6455..c12effb46fe5 100644 --- a/fs/nfs/write.c +++ b/fs/nfs/write.c | |||
@@ -396,6 +396,7 @@ int nfs_writepages(struct address_space *mapping, struct writeback_control *wbc) | |||
396 | out: | 396 | out: |
397 | clear_bit(BDI_write_congested, &bdi->state); | 397 | clear_bit(BDI_write_congested, &bdi->state); |
398 | wake_up_all(&nfs_write_congestion); | 398 | wake_up_all(&nfs_write_congestion); |
399 | writeback_congestion_end(); | ||
399 | return err; | 400 | return err; |
400 | } | 401 | } |
401 | 402 | ||
@@ -1252,7 +1253,13 @@ int nfs_writeback_done(struct rpc_task *task, struct nfs_write_data *data) | |||
1252 | dprintk("NFS: %4d nfs_writeback_done (status %d)\n", | 1253 | dprintk("NFS: %4d nfs_writeback_done (status %d)\n", |
1253 | task->tk_pid, task->tk_status); | 1254 | task->tk_pid, task->tk_status); |
1254 | 1255 | ||
1255 | /* Call the NFS version-specific code */ | 1256 | /* |
1257 | * ->write_done will attempt to use post-op attributes to detect | ||
1258 | * conflicting writes by other clients. A strict interpretation | ||
1259 | * of close-to-open would allow us to continue caching even if | ||
1260 | * another writer had changed the file, but some applications | ||
1261 | * depend on tighter cache coherency when writing. | ||
1262 | */ | ||
1256 | status = NFS_PROTO(data->inode)->write_done(task, data); | 1263 | status = NFS_PROTO(data->inode)->write_done(task, data); |
1257 | if (status != 0) | 1264 | if (status != 0) |
1258 | return status; | 1265 | return status; |
@@ -1273,7 +1280,7 @@ int nfs_writeback_done(struct rpc_task *task, struct nfs_write_data *data) | |||
1273 | if (time_before(complain, jiffies)) { | 1280 | if (time_before(complain, jiffies)) { |
1274 | dprintk("NFS: faulty NFS server %s:" | 1281 | dprintk("NFS: faulty NFS server %s:" |
1275 | " (committed = %d) != (stable = %d)\n", | 1282 | " (committed = %d) != (stable = %d)\n", |
1276 | NFS_SERVER(data->inode)->hostname, | 1283 | NFS_SERVER(data->inode)->nfs_client->cl_hostname, |
1277 | resp->verf->committed, argp->stable); | 1284 | resp->verf->committed, argp->stable); |
1278 | complain = jiffies + 300 * HZ; | 1285 | complain = jiffies + 300 * HZ; |
1279 | } | 1286 | } |
diff --git a/fs/nfsd/nfs4callback.c b/fs/nfsd/nfs4callback.c index 54b37b1d2e3a..8583d99ee740 100644 --- a/fs/nfsd/nfs4callback.c +++ b/fs/nfsd/nfs4callback.c | |||
@@ -375,16 +375,28 @@ nfsd4_probe_callback(struct nfs4_client *clp) | |||
375 | { | 375 | { |
376 | struct sockaddr_in addr; | 376 | struct sockaddr_in addr; |
377 | struct nfs4_callback *cb = &clp->cl_callback; | 377 | struct nfs4_callback *cb = &clp->cl_callback; |
378 | struct rpc_timeout timeparms; | 378 | struct rpc_timeout timeparms = { |
379 | struct rpc_xprt * xprt; | 379 | .to_initval = (NFSD_LEASE_TIME/4) * HZ, |
380 | .to_retries = 5, | ||
381 | .to_maxval = (NFSD_LEASE_TIME/2) * HZ, | ||
382 | .to_exponential = 1, | ||
383 | }; | ||
380 | struct rpc_program * program = &cb->cb_program; | 384 | struct rpc_program * program = &cb->cb_program; |
381 | struct rpc_stat * stat = &cb->cb_stat; | 385 | struct rpc_create_args args = { |
382 | struct rpc_clnt * clnt; | 386 | .protocol = IPPROTO_TCP, |
387 | .address = (struct sockaddr *)&addr, | ||
388 | .addrsize = sizeof(addr), | ||
389 | .timeout = &timeparms, | ||
390 | .servername = clp->cl_name.data, | ||
391 | .program = program, | ||
392 | .version = nfs_cb_version[1]->number, | ||
393 | .authflavor = RPC_AUTH_UNIX, /* XXX: need AUTH_GSS... */ | ||
394 | .flags = (RPC_CLNT_CREATE_NOPING), | ||
395 | }; | ||
383 | struct rpc_message msg = { | 396 | struct rpc_message msg = { |
384 | .rpc_proc = &nfs4_cb_procedures[NFSPROC4_CLNT_CB_NULL], | 397 | .rpc_proc = &nfs4_cb_procedures[NFSPROC4_CLNT_CB_NULL], |
385 | .rpc_argp = clp, | 398 | .rpc_argp = clp, |
386 | }; | 399 | }; |
387 | char hostname[32]; | ||
388 | int status; | 400 | int status; |
389 | 401 | ||
390 | if (atomic_read(&cb->cb_set)) | 402 | if (atomic_read(&cb->cb_set)) |
@@ -396,51 +408,27 @@ nfsd4_probe_callback(struct nfs4_client *clp) | |||
396 | addr.sin_port = htons(cb->cb_port); | 408 | addr.sin_port = htons(cb->cb_port); |
397 | addr.sin_addr.s_addr = htonl(cb->cb_addr); | 409 | addr.sin_addr.s_addr = htonl(cb->cb_addr); |
398 | 410 | ||
399 | /* Initialize timeout */ | ||
400 | timeparms.to_initval = (NFSD_LEASE_TIME/4) * HZ; | ||
401 | timeparms.to_retries = 0; | ||
402 | timeparms.to_maxval = (NFSD_LEASE_TIME/2) * HZ; | ||
403 | timeparms.to_exponential = 1; | ||
404 | |||
405 | /* Create RPC transport */ | ||
406 | xprt = xprt_create_proto(IPPROTO_TCP, &addr, &timeparms); | ||
407 | if (IS_ERR(xprt)) { | ||
408 | dprintk("NFSD: couldn't create callback transport!\n"); | ||
409 | goto out_err; | ||
410 | } | ||
411 | |||
412 | /* Initialize rpc_program */ | 411 | /* Initialize rpc_program */ |
413 | program->name = "nfs4_cb"; | 412 | program->name = "nfs4_cb"; |
414 | program->number = cb->cb_prog; | 413 | program->number = cb->cb_prog; |
415 | program->nrvers = ARRAY_SIZE(nfs_cb_version); | 414 | program->nrvers = ARRAY_SIZE(nfs_cb_version); |
416 | program->version = nfs_cb_version; | 415 | program->version = nfs_cb_version; |
417 | program->stats = stat; | 416 | program->stats = &cb->cb_stat; |
418 | 417 | ||
419 | /* Initialize rpc_stat */ | 418 | /* Initialize rpc_stat */ |
420 | memset(stat, 0, sizeof(struct rpc_stat)); | 419 | memset(program->stats, 0, sizeof(cb->cb_stat)); |
421 | stat->program = program; | 420 | program->stats->program = program; |
422 | 421 | ||
423 | /* Create RPC client | 422 | /* Create RPC client */ |
424 | * | 423 | cb->cb_client = rpc_create(&args); |
425 | * XXX AUTH_UNIX only - need AUTH_GSS.... | 424 | if (!cb->cb_client) { |
426 | */ | ||
427 | sprintf(hostname, "%u.%u.%u.%u", NIPQUAD(addr.sin_addr.s_addr)); | ||
428 | clnt = rpc_new_client(xprt, hostname, program, 1, RPC_AUTH_UNIX); | ||
429 | if (IS_ERR(clnt)) { | ||
430 | dprintk("NFSD: couldn't create callback client\n"); | 425 | dprintk("NFSD: couldn't create callback client\n"); |
431 | goto out_err; | 426 | goto out_err; |
432 | } | 427 | } |
433 | clnt->cl_intr = 0; | ||
434 | clnt->cl_softrtry = 1; | ||
435 | 428 | ||
436 | /* Kick rpciod, put the call on the wire. */ | 429 | /* Kick rpciod, put the call on the wire. */ |
437 | 430 | if (rpciod_up() != 0) | |
438 | if (rpciod_up() != 0) { | ||
439 | dprintk("nfsd: couldn't start rpciod for callbacks!\n"); | ||
440 | goto out_clnt; | 431 | goto out_clnt; |
441 | } | ||
442 | |||
443 | cb->cb_client = clnt; | ||
444 | 432 | ||
445 | /* the task holds a reference to the nfs4_client struct */ | 433 | /* the task holds a reference to the nfs4_client struct */ |
446 | atomic_inc(&clp->cl_count); | 434 | atomic_inc(&clp->cl_count); |
@@ -448,7 +436,7 @@ nfsd4_probe_callback(struct nfs4_client *clp) | |||
448 | msg.rpc_cred = nfsd4_lookupcred(clp,0); | 436 | msg.rpc_cred = nfsd4_lookupcred(clp,0); |
449 | if (IS_ERR(msg.rpc_cred)) | 437 | if (IS_ERR(msg.rpc_cred)) |
450 | goto out_rpciod; | 438 | goto out_rpciod; |
451 | status = rpc_call_async(clnt, &msg, RPC_TASK_ASYNC, &nfs4_cb_null_ops, NULL); | 439 | status = rpc_call_async(cb->cb_client, &msg, RPC_TASK_ASYNC, &nfs4_cb_null_ops, NULL); |
452 | put_rpccred(msg.rpc_cred); | 440 | put_rpccred(msg.rpc_cred); |
453 | 441 | ||
454 | if (status != 0) { | 442 | if (status != 0) { |
@@ -462,7 +450,7 @@ out_rpciod: | |||
462 | rpciod_down(); | 450 | rpciod_down(); |
463 | cb->cb_client = NULL; | 451 | cb->cb_client = NULL; |
464 | out_clnt: | 452 | out_clnt: |
465 | rpc_shutdown_client(clnt); | 453 | rpc_shutdown_client(cb->cb_client); |
466 | out_err: | 454 | out_err: |
467 | dprintk("NFSD: warning: no callback path to client %.*s\n", | 455 | dprintk("NFSD: warning: no callback path to client %.*s\n", |
468 | (int)clp->cl_name.len, clp->cl_name.data); | 456 | (int)clp->cl_name.len, clp->cl_name.data); |
diff --git a/include/asm-ppc/ibm4xx.h b/include/asm-ppc/ibm4xx.h index cf62b69cb69a..499c14691c71 100644 --- a/include/asm-ppc/ibm4xx.h +++ b/include/asm-ppc/ibm4xx.h | |||
@@ -86,7 +86,7 @@ void ppc4xx_init(unsigned long r3, unsigned long r4, unsigned long r5, | |||
86 | #define PCI_DRAM_OFFSET 0 | 86 | #define PCI_DRAM_OFFSET 0 |
87 | #endif | 87 | #endif |
88 | 88 | ||
89 | #elif CONFIG_44x | 89 | #elif defined(CONFIG_44x) |
90 | 90 | ||
91 | #if defined(CONFIG_BAMBOO) | 91 | #if defined(CONFIG_BAMBOO) |
92 | #include <platforms/4xx/bamboo.h> | 92 | #include <platforms/4xx/bamboo.h> |
diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h index 427b0d61be6c..c773ee545ebd 100644 --- a/include/linux/blkdev.h +++ b/include/linux/blkdev.h | |||
@@ -748,6 +748,7 @@ extern void blk_queue_invalidate_tags(request_queue_t *); | |||
748 | extern long blk_congestion_wait(int rw, long timeout); | 748 | extern long blk_congestion_wait(int rw, long timeout); |
749 | extern struct blk_queue_tag *blk_init_tags(int); | 749 | extern struct blk_queue_tag *blk_init_tags(int); |
750 | extern void blk_free_tags(struct blk_queue_tag *); | 750 | extern void blk_free_tags(struct blk_queue_tag *); |
751 | extern void blk_congestion_end(int rw); | ||
751 | 752 | ||
752 | extern void blk_rq_bio_prep(request_queue_t *, struct request *, struct bio *); | 753 | extern void blk_rq_bio_prep(request_queue_t *, struct request *, struct bio *); |
753 | extern int blkdev_issue_flush(struct block_device *, sector_t *); | 754 | extern int blkdev_issue_flush(struct block_device *, sector_t *); |
diff --git a/include/linux/bootmem.h b/include/linux/bootmem.h index 1021f508d82c..e319c649e4fd 100644 --- a/include/linux/bootmem.h +++ b/include/linux/bootmem.h | |||
@@ -114,7 +114,7 @@ extern void *__init alloc_large_system_hash(const char *tablename, | |||
114 | #else | 114 | #else |
115 | #define HASHDIST_DEFAULT 0 | 115 | #define HASHDIST_DEFAULT 0 |
116 | #endif | 116 | #endif |
117 | extern int __initdata hashdist; /* Distribute hashes across NUMA nodes? */ | 117 | extern int hashdist; /* Distribute hashes across NUMA nodes? */ |
118 | 118 | ||
119 | 119 | ||
120 | #endif /* _LINUX_BOOTMEM_H */ | 120 | #endif /* _LINUX_BOOTMEM_H */ |
diff --git a/include/linux/dcache.h b/include/linux/dcache.h index 471781ffeab1..44605be59409 100644 --- a/include/linux/dcache.h +++ b/include/linux/dcache.h | |||
@@ -221,6 +221,7 @@ static inline int dname_external(struct dentry *dentry) | |||
221 | */ | 221 | */ |
222 | extern void d_instantiate(struct dentry *, struct inode *); | 222 | extern void d_instantiate(struct dentry *, struct inode *); |
223 | extern struct dentry * d_instantiate_unique(struct dentry *, struct inode *); | 223 | extern struct dentry * d_instantiate_unique(struct dentry *, struct inode *); |
224 | extern struct dentry * d_materialise_unique(struct dentry *, struct inode *); | ||
224 | extern void d_delete(struct dentry *); | 225 | extern void d_delete(struct dentry *); |
225 | 226 | ||
226 | /* allocate/de-allocate */ | 227 | /* allocate/de-allocate */ |
diff --git a/include/linux/dccp.h b/include/linux/dccp.h index 676333b9fad0..2d7671c92c0b 100644 --- a/include/linux/dccp.h +++ b/include/linux/dccp.h | |||
@@ -438,6 +438,7 @@ struct dccp_ackvec; | |||
438 | * @dccps_role - Role of this sock, one of %dccp_role | 438 | * @dccps_role - Role of this sock, one of %dccp_role |
439 | * @dccps_ndp_count - number of Non Data Packets since last data packet | 439 | * @dccps_ndp_count - number of Non Data Packets since last data packet |
440 | * @dccps_hc_rx_ackvec - rx half connection ack vector | 440 | * @dccps_hc_rx_ackvec - rx half connection ack vector |
441 | * @dccps_xmit_timer - timer for when CCID is not ready to send | ||
441 | */ | 442 | */ |
442 | struct dccp_sock { | 443 | struct dccp_sock { |
443 | /* inet_connection_sock has to be the first member of dccp_sock */ | 444 | /* inet_connection_sock has to be the first member of dccp_sock */ |
@@ -470,6 +471,7 @@ struct dccp_sock { | |||
470 | enum dccp_role dccps_role:2; | 471 | enum dccp_role dccps_role:2; |
471 | __u8 dccps_hc_rx_insert_options:1; | 472 | __u8 dccps_hc_rx_insert_options:1; |
472 | __u8 dccps_hc_tx_insert_options:1; | 473 | __u8 dccps_hc_tx_insert_options:1; |
474 | struct timer_list dccps_xmit_timer; | ||
473 | }; | 475 | }; |
474 | 476 | ||
475 | static inline struct dccp_sock *dccp_sk(const struct sock *sk) | 477 | static inline struct dccp_sock *dccp_sk(const struct sock *sk) |
diff --git a/include/linux/fib_rules.h b/include/linux/fib_rules.h new file mode 100644 index 000000000000..4418c8d9d479 --- /dev/null +++ b/include/linux/fib_rules.h | |||
@@ -0,0 +1,65 @@ | |||
1 | #ifndef __LINUX_FIB_RULES_H | ||
2 | #define __LINUX_FIB_RULES_H | ||
3 | |||
4 | #include <linux/types.h> | ||
5 | #include <linux/rtnetlink.h> | ||
6 | |||
7 | /* rule is permanent, and cannot be deleted */ | ||
8 | #define FIB_RULE_PERMANENT 1 | ||
9 | |||
10 | struct fib_rule_hdr | ||
11 | { | ||
12 | __u8 family; | ||
13 | __u8 dst_len; | ||
14 | __u8 src_len; | ||
15 | __u8 tos; | ||
16 | |||
17 | __u8 table; | ||
18 | __u8 res1; /* reserved */ | ||
19 | __u8 res2; /* reserved */ | ||
20 | __u8 action; | ||
21 | |||
22 | __u32 flags; | ||
23 | }; | ||
24 | |||
25 | enum | ||
26 | { | ||
27 | FRA_UNSPEC, | ||
28 | FRA_DST, /* destination address */ | ||
29 | FRA_SRC, /* source address */ | ||
30 | FRA_IFNAME, /* interface name */ | ||
31 | FRA_UNUSED1, | ||
32 | FRA_UNUSED2, | ||
33 | FRA_PRIORITY, /* priority/preference */ | ||
34 | FRA_UNUSED3, | ||
35 | FRA_UNUSED4, | ||
36 | FRA_UNUSED5, | ||
37 | FRA_FWMARK, /* netfilter mark */ | ||
38 | FRA_FLOW, /* flow/class id */ | ||
39 | FRA_UNUSED6, | ||
40 | FRA_UNUSED7, | ||
41 | FRA_UNUSED8, | ||
42 | FRA_TABLE, /* Extended table id */ | ||
43 | FRA_FWMASK, /* mask for netfilter mark */ | ||
44 | __FRA_MAX | ||
45 | }; | ||
46 | |||
47 | #define FRA_MAX (__FRA_MAX - 1) | ||
48 | |||
49 | enum | ||
50 | { | ||
51 | FR_ACT_UNSPEC, | ||
52 | FR_ACT_TO_TBL, /* Pass to fixed table */ | ||
53 | FR_ACT_RES1, | ||
54 | FR_ACT_RES2, | ||
55 | FR_ACT_RES3, | ||
56 | FR_ACT_RES4, | ||
57 | FR_ACT_BLACKHOLE, /* Drop without notification */ | ||
58 | FR_ACT_UNREACHABLE, /* Drop with ENETUNREACH */ | ||
59 | FR_ACT_PROHIBIT, /* Drop with EACCES */ | ||
60 | __FR_ACT_MAX, | ||
61 | }; | ||
62 | |||
63 | #define FR_ACT_MAX (__FR_ACT_MAX - 1) | ||
64 | |||
65 | #endif | ||
diff --git a/include/linux/filter.h b/include/linux/filter.h index c6cb8f095088..91b2e3b9251e 100644 --- a/include/linux/filter.h +++ b/include/linux/filter.h | |||
@@ -25,10 +25,10 @@ | |||
25 | 25 | ||
26 | struct sock_filter /* Filter block */ | 26 | struct sock_filter /* Filter block */ |
27 | { | 27 | { |
28 | __u16 code; /* Actual filter code */ | 28 | __u16 code; /* Actual filter code */ |
29 | __u8 jt; /* Jump true */ | 29 | __u8 jt; /* Jump true */ |
30 | __u8 jf; /* Jump false */ | 30 | __u8 jf; /* Jump false */ |
31 | __u32 k; /* Generic multiuse field */ | 31 | __u32 k; /* Generic multiuse field */ |
32 | }; | 32 | }; |
33 | 33 | ||
34 | struct sock_fprog /* Required for SO_ATTACH_FILTER. */ | 34 | struct sock_fprog /* Required for SO_ATTACH_FILTER. */ |
@@ -41,8 +41,9 @@ struct sock_fprog /* Required for SO_ATTACH_FILTER. */ | |||
41 | struct sk_filter | 41 | struct sk_filter |
42 | { | 42 | { |
43 | atomic_t refcnt; | 43 | atomic_t refcnt; |
44 | unsigned int len; /* Number of filter blocks */ | 44 | unsigned int len; /* Number of filter blocks */ |
45 | struct sock_filter insns[0]; | 45 | struct rcu_head rcu; |
46 | struct sock_filter insns[0]; | ||
46 | }; | 47 | }; |
47 | 48 | ||
48 | static inline unsigned int sk_filter_len(struct sk_filter *fp) | 49 | static inline unsigned int sk_filter_len(struct sk_filter *fp) |
diff --git a/include/linux/genetlink.h b/include/linux/genetlink.h index 84f12a41dc01..9049dc65ae51 100644 --- a/include/linux/genetlink.h +++ b/include/linux/genetlink.h | |||
@@ -16,6 +16,8 @@ struct genlmsghdr { | |||
16 | 16 | ||
17 | #define GENL_HDRLEN NLMSG_ALIGN(sizeof(struct genlmsghdr)) | 17 | #define GENL_HDRLEN NLMSG_ALIGN(sizeof(struct genlmsghdr)) |
18 | 18 | ||
19 | #define GENL_ADMIN_PERM 0x01 | ||
20 | |||
19 | /* | 21 | /* |
20 | * List of reserved static generic netlink identifiers: | 22 | * List of reserved static generic netlink identifiers: |
21 | */ | 23 | */ |
@@ -43,9 +45,25 @@ enum { | |||
43 | CTRL_ATTR_UNSPEC, | 45 | CTRL_ATTR_UNSPEC, |
44 | CTRL_ATTR_FAMILY_ID, | 46 | CTRL_ATTR_FAMILY_ID, |
45 | CTRL_ATTR_FAMILY_NAME, | 47 | CTRL_ATTR_FAMILY_NAME, |
48 | CTRL_ATTR_VERSION, | ||
49 | CTRL_ATTR_HDRSIZE, | ||
50 | CTRL_ATTR_MAXATTR, | ||
51 | CTRL_ATTR_OPS, | ||
46 | __CTRL_ATTR_MAX, | 52 | __CTRL_ATTR_MAX, |
47 | }; | 53 | }; |
48 | 54 | ||
49 | #define CTRL_ATTR_MAX (__CTRL_ATTR_MAX - 1) | 55 | #define CTRL_ATTR_MAX (__CTRL_ATTR_MAX - 1) |
50 | 56 | ||
57 | enum { | ||
58 | CTRL_ATTR_OP_UNSPEC, | ||
59 | CTRL_ATTR_OP_ID, | ||
60 | CTRL_ATTR_OP_FLAGS, | ||
61 | CTRL_ATTR_OP_POLICY, | ||
62 | CTRL_ATTR_OP_DOIT, | ||
63 | CTRL_ATTR_OP_DUMPIT, | ||
64 | __CTRL_ATTR_OP_MAX, | ||
65 | }; | ||
66 | |||
67 | #define CTRL_ATTR_OP_MAX (__CTRL_ATTR_OP_MAX - 1) | ||
68 | |||
51 | #endif /* __LINUX_GENERIC_NETLINK_H */ | 69 | #endif /* __LINUX_GENERIC_NETLINK_H */ |
diff --git a/include/linux/if.h b/include/linux/if.h index 374e20ad8b0d..cd080d765324 100644 --- a/include/linux/if.h +++ b/include/linux/if.h | |||
@@ -212,5 +212,134 @@ struct ifconf | |||
212 | #define ifc_buf ifc_ifcu.ifcu_buf /* buffer address */ | 212 | #define ifc_buf ifc_ifcu.ifcu_buf /* buffer address */ |
213 | #define ifc_req ifc_ifcu.ifcu_req /* array of structures */ | 213 | #define ifc_req ifc_ifcu.ifcu_req /* array of structures */ |
214 | 214 | ||
215 | /* The struct should be in sync with struct net_device_stats */ | ||
216 | struct rtnl_link_stats | ||
217 | { | ||
218 | __u32 rx_packets; /* total packets received */ | ||
219 | __u32 tx_packets; /* total packets transmitted */ | ||
220 | __u32 rx_bytes; /* total bytes received */ | ||
221 | __u32 tx_bytes; /* total bytes transmitted */ | ||
222 | __u32 rx_errors; /* bad packets received */ | ||
223 | __u32 tx_errors; /* packet transmit problems */ | ||
224 | __u32 rx_dropped; /* no space in linux buffers */ | ||
225 | __u32 tx_dropped; /* no space available in linux */ | ||
226 | __u32 multicast; /* multicast packets received */ | ||
227 | __u32 collisions; | ||
228 | |||
229 | /* detailed rx_errors: */ | ||
230 | __u32 rx_length_errors; | ||
231 | __u32 rx_over_errors; /* receiver ring buff overflow */ | ||
232 | __u32 rx_crc_errors; /* recved pkt with crc error */ | ||
233 | __u32 rx_frame_errors; /* recv'd frame alignment error */ | ||
234 | __u32 rx_fifo_errors; /* recv'r fifo overrun */ | ||
235 | __u32 rx_missed_errors; /* receiver missed packet */ | ||
236 | |||
237 | /* detailed tx_errors */ | ||
238 | __u32 tx_aborted_errors; | ||
239 | __u32 tx_carrier_errors; | ||
240 | __u32 tx_fifo_errors; | ||
241 | __u32 tx_heartbeat_errors; | ||
242 | __u32 tx_window_errors; | ||
243 | |||
244 | /* for cslip etc */ | ||
245 | __u32 rx_compressed; | ||
246 | __u32 tx_compressed; | ||
247 | }; | ||
248 | |||
249 | /* The struct should be in sync with struct ifmap */ | ||
250 | struct rtnl_link_ifmap | ||
251 | { | ||
252 | __u64 mem_start; | ||
253 | __u64 mem_end; | ||
254 | __u64 base_addr; | ||
255 | __u16 irq; | ||
256 | __u8 dma; | ||
257 | __u8 port; | ||
258 | }; | ||
259 | |||
260 | enum | ||
261 | { | ||
262 | IFLA_UNSPEC, | ||
263 | IFLA_ADDRESS, | ||
264 | IFLA_BROADCAST, | ||
265 | IFLA_IFNAME, | ||
266 | IFLA_MTU, | ||
267 | IFLA_LINK, | ||
268 | IFLA_QDISC, | ||
269 | IFLA_STATS, | ||
270 | IFLA_COST, | ||
271 | #define IFLA_COST IFLA_COST | ||
272 | IFLA_PRIORITY, | ||
273 | #define IFLA_PRIORITY IFLA_PRIORITY | ||
274 | IFLA_MASTER, | ||
275 | #define IFLA_MASTER IFLA_MASTER | ||
276 | IFLA_WIRELESS, /* Wireless Extension event - see wireless.h */ | ||
277 | #define IFLA_WIRELESS IFLA_WIRELESS | ||
278 | IFLA_PROTINFO, /* Protocol specific information for a link */ | ||
279 | #define IFLA_PROTINFO IFLA_PROTINFO | ||
280 | IFLA_TXQLEN, | ||
281 | #define IFLA_TXQLEN IFLA_TXQLEN | ||
282 | IFLA_MAP, | ||
283 | #define IFLA_MAP IFLA_MAP | ||
284 | IFLA_WEIGHT, | ||
285 | #define IFLA_WEIGHT IFLA_WEIGHT | ||
286 | IFLA_OPERSTATE, | ||
287 | IFLA_LINKMODE, | ||
288 | __IFLA_MAX | ||
289 | }; | ||
290 | |||
291 | |||
292 | #define IFLA_MAX (__IFLA_MAX - 1) | ||
293 | |||
294 | /* ifi_flags. | ||
295 | |||
296 | IFF_* flags. | ||
297 | |||
298 | The only change is: | ||
299 | IFF_LOOPBACK, IFF_BROADCAST and IFF_POINTOPOINT are | ||
300 | more not changeable by user. They describe link media | ||
301 | characteristics and set by device driver. | ||
302 | |||
303 | Comments: | ||
304 | - Combination IFF_BROADCAST|IFF_POINTOPOINT is invalid | ||
305 | - If neither of these three flags are set; | ||
306 | the interface is NBMA. | ||
307 | |||
308 | - IFF_MULTICAST does not mean anything special: | ||
309 | multicasts can be used on all not-NBMA links. | ||
310 | IFF_MULTICAST means that this media uses special encapsulation | ||
311 | for multicast frames. Apparently, all IFF_POINTOPOINT and | ||
312 | IFF_BROADCAST devices are able to use multicasts too. | ||
313 | */ | ||
314 | |||
315 | /* IFLA_LINK. | ||
316 | For usual devices it is equal ifi_index. | ||
317 | If it is a "virtual interface" (f.e. tunnel), ifi_link | ||
318 | can point to real physical interface (f.e. for bandwidth calculations), | ||
319 | or maybe 0, what means, that real media is unknown (usual | ||
320 | for IPIP tunnels, when route to endpoint is allowed to change) | ||
321 | */ | ||
322 | |||
323 | /* Subtype attributes for IFLA_PROTINFO */ | ||
324 | enum | ||
325 | { | ||
326 | IFLA_INET6_UNSPEC, | ||
327 | IFLA_INET6_FLAGS, /* link flags */ | ||
328 | IFLA_INET6_CONF, /* sysctl parameters */ | ||
329 | IFLA_INET6_STATS, /* statistics */ | ||
330 | IFLA_INET6_MCAST, /* MC things. What of them? */ | ||
331 | IFLA_INET6_CACHEINFO, /* time values and max reasm size */ | ||
332 | __IFLA_INET6_MAX | ||
333 | }; | ||
334 | |||
335 | #define IFLA_INET6_MAX (__IFLA_INET6_MAX - 1) | ||
336 | |||
337 | struct ifla_cacheinfo | ||
338 | { | ||
339 | __u32 max_reasm_len; | ||
340 | __u32 tstamp; /* ipv6InterfaceTable updated timestamp */ | ||
341 | __u32 reachable_time; | ||
342 | __u32 retrans_time; | ||
343 | }; | ||
215 | 344 | ||
216 | #endif /* _LINUX_IF_H */ | 345 | #endif /* _LINUX_IF_H */ |
diff --git a/include/linux/if_addr.h b/include/linux/if_addr.h new file mode 100644 index 000000000000..dbe8f6120a40 --- /dev/null +++ b/include/linux/if_addr.h | |||
@@ -0,0 +1,55 @@ | |||
1 | #ifndef __LINUX_IF_ADDR_H | ||
2 | #define __LINUX_IF_ADDR_H | ||
3 | |||
4 | #include <linux/netlink.h> | ||
5 | |||
6 | struct ifaddrmsg | ||
7 | { | ||
8 | __u8 ifa_family; | ||
9 | __u8 ifa_prefixlen; /* The prefix length */ | ||
10 | __u8 ifa_flags; /* Flags */ | ||
11 | __u8 ifa_scope; /* Address scope */ | ||
12 | __u32 ifa_index; /* Link index */ | ||
13 | }; | ||
14 | |||
15 | /* | ||
16 | * Important comment: | ||
17 | * IFA_ADDRESS is prefix address, rather than local interface address. | ||
18 | * It makes no difference for normally configured broadcast interfaces, | ||
19 | * but for point-to-point IFA_ADDRESS is DESTINATION address, | ||
20 | * local address is supplied in IFA_LOCAL attribute. | ||
21 | */ | ||
22 | enum | ||
23 | { | ||
24 | IFA_UNSPEC, | ||
25 | IFA_ADDRESS, | ||
26 | IFA_LOCAL, | ||
27 | IFA_LABEL, | ||
28 | IFA_BROADCAST, | ||
29 | IFA_ANYCAST, | ||
30 | IFA_CACHEINFO, | ||
31 | IFA_MULTICAST, | ||
32 | __IFA_MAX, | ||
33 | }; | ||
34 | |||
35 | #define IFA_MAX (__IFA_MAX - 1) | ||
36 | |||
37 | /* ifa_flags */ | ||
38 | #define IFA_F_SECONDARY 0x01 | ||
39 | #define IFA_F_TEMPORARY IFA_F_SECONDARY | ||
40 | |||
41 | #define IFA_F_NODAD 0x02 | ||
42 | #define IFA_F_HOMEADDRESS 0x10 | ||
43 | #define IFA_F_DEPRECATED 0x20 | ||
44 | #define IFA_F_TENTATIVE 0x40 | ||
45 | #define IFA_F_PERMANENT 0x80 | ||
46 | |||
47 | struct ifa_cacheinfo | ||
48 | { | ||
49 | __u32 ifa_prefered; | ||
50 | __u32 ifa_valid; | ||
51 | __u32 cstamp; /* created timestamp, hundredths of seconds */ | ||
52 | __u32 tstamp; /* updated timestamp, hundredths of seconds */ | ||
53 | }; | ||
54 | |||
55 | #endif | ||
diff --git a/include/linux/in.h b/include/linux/in.h index 94f557fa4636..bcaca8399aed 100644 --- a/include/linux/in.h +++ b/include/linux/in.h | |||
@@ -52,7 +52,7 @@ enum { | |||
52 | 52 | ||
53 | /* Internet address. */ | 53 | /* Internet address. */ |
54 | struct in_addr { | 54 | struct in_addr { |
55 | __u32 s_addr; | 55 | __be32 s_addr; |
56 | }; | 56 | }; |
57 | 57 | ||
58 | #define IP_TOS 1 | 58 | #define IP_TOS 1 |
@@ -177,7 +177,7 @@ struct in_pktinfo | |||
177 | #define __SOCK_SIZE__ 16 /* sizeof(struct sockaddr) */ | 177 | #define __SOCK_SIZE__ 16 /* sizeof(struct sockaddr) */ |
178 | struct sockaddr_in { | 178 | struct sockaddr_in { |
179 | sa_family_t sin_family; /* Address family */ | 179 | sa_family_t sin_family; /* Address family */ |
180 | unsigned short int sin_port; /* Port number */ | 180 | __be16 sin_port; /* Port number */ |
181 | struct in_addr sin_addr; /* Internet address */ | 181 | struct in_addr sin_addr; /* Internet address */ |
182 | 182 | ||
183 | /* Pad to size of `struct sockaddr'. */ | 183 | /* Pad to size of `struct sockaddr'. */ |
diff --git a/include/linux/in6.h b/include/linux/in6.h index 304aaedea305..d776829b443f 100644 --- a/include/linux/in6.h +++ b/include/linux/in6.h | |||
@@ -134,6 +134,7 @@ struct in6_flowlabel_req | |||
134 | #define IPPROTO_ICMPV6 58 /* ICMPv6 */ | 134 | #define IPPROTO_ICMPV6 58 /* ICMPv6 */ |
135 | #define IPPROTO_NONE 59 /* IPv6 no next header */ | 135 | #define IPPROTO_NONE 59 /* IPv6 no next header */ |
136 | #define IPPROTO_DSTOPTS 60 /* IPv6 destination options */ | 136 | #define IPPROTO_DSTOPTS 60 /* IPv6 destination options */ |
137 | #define IPPROTO_MH 135 /* IPv6 mobility header */ | ||
137 | 138 | ||
138 | /* | 139 | /* |
139 | * IPv6 TLV options. | 140 | * IPv6 TLV options. |
@@ -142,6 +143,7 @@ struct in6_flowlabel_req | |||
142 | #define IPV6_TLV_PADN 1 | 143 | #define IPV6_TLV_PADN 1 |
143 | #define IPV6_TLV_ROUTERALERT 5 | 144 | #define IPV6_TLV_ROUTERALERT 5 |
144 | #define IPV6_TLV_JUMBO 194 | 145 | #define IPV6_TLV_JUMBO 194 |
146 | #define IPV6_TLV_HAO 201 /* home address option */ | ||
145 | 147 | ||
146 | /* | 148 | /* |
147 | * IPV6 socket options | 149 | * IPV6 socket options |
diff --git a/include/linux/inet.h b/include/linux/inet.h index 6c5587af118d..b7c6da7d6d32 100644 --- a/include/linux/inet.h +++ b/include/linux/inet.h | |||
@@ -46,5 +46,7 @@ | |||
46 | #include <linux/types.h> | 46 | #include <linux/types.h> |
47 | 47 | ||
48 | extern __be32 in_aton(const char *str); | 48 | extern __be32 in_aton(const char *str); |
49 | extern int in4_pton(const char *src, int srclen, u8 *dst, char delim, const char **end); | ||
50 | extern int in6_pton(const char *src, int srclen, u8 *dst, char delim, const char **end); | ||
49 | #endif | 51 | #endif |
50 | #endif /* _LINUX_INET_H */ | 52 | #endif /* _LINUX_INET_H */ |
diff --git a/include/linux/ip.h b/include/linux/ip.h index 4b55cf1df732..2f4600146f83 100644 --- a/include/linux/ip.h +++ b/include/linux/ip.h | |||
@@ -57,6 +57,7 @@ | |||
57 | #define IPOPT_SEC (2 |IPOPT_CONTROL|IPOPT_COPY) | 57 | #define IPOPT_SEC (2 |IPOPT_CONTROL|IPOPT_COPY) |
58 | #define IPOPT_LSRR (3 |IPOPT_CONTROL|IPOPT_COPY) | 58 | #define IPOPT_LSRR (3 |IPOPT_CONTROL|IPOPT_COPY) |
59 | #define IPOPT_TIMESTAMP (4 |IPOPT_MEASUREMENT) | 59 | #define IPOPT_TIMESTAMP (4 |IPOPT_MEASUREMENT) |
60 | #define IPOPT_CIPSO (6 |IPOPT_CONTROL|IPOPT_COPY) | ||
60 | #define IPOPT_RR (7 |IPOPT_CONTROL) | 61 | #define IPOPT_RR (7 |IPOPT_CONTROL) |
61 | #define IPOPT_SID (8 |IPOPT_CONTROL|IPOPT_COPY) | 62 | #define IPOPT_SID (8 |IPOPT_CONTROL|IPOPT_COPY) |
62 | #define IPOPT_SSRR (9 |IPOPT_CONTROL|IPOPT_COPY) | 63 | #define IPOPT_SSRR (9 |IPOPT_CONTROL|IPOPT_COPY) |
diff --git a/include/linux/ipv6.h b/include/linux/ipv6.h index 297853c841b4..caca57df0d7d 100644 --- a/include/linux/ipv6.h +++ b/include/linux/ipv6.h | |||
@@ -29,6 +29,7 @@ struct in6_ifreq { | |||
29 | 29 | ||
30 | #define IPV6_SRCRT_STRICT 0x01 /* this hop must be a neighbor */ | 30 | #define IPV6_SRCRT_STRICT 0x01 /* this hop must be a neighbor */ |
31 | #define IPV6_SRCRT_TYPE_0 0 /* IPv6 type 0 Routing Header */ | 31 | #define IPV6_SRCRT_TYPE_0 0 /* IPv6 type 0 Routing Header */ |
32 | #define IPV6_SRCRT_TYPE_2 2 /* IPv6 type 2 Routing Header */ | ||
32 | 33 | ||
33 | /* | 34 | /* |
34 | * routing header | 35 | * routing header |
@@ -73,6 +74,28 @@ struct rt0_hdr { | |||
73 | #define rt0_type rt_hdr.type | 74 | #define rt0_type rt_hdr.type |
74 | }; | 75 | }; |
75 | 76 | ||
77 | /* | ||
78 | * routing header type 2 | ||
79 | */ | ||
80 | |||
81 | struct rt2_hdr { | ||
82 | struct ipv6_rt_hdr rt_hdr; | ||
83 | __u32 reserved; | ||
84 | struct in6_addr addr; | ||
85 | |||
86 | #define rt2_type rt_hdr.type | ||
87 | }; | ||
88 | |||
89 | /* | ||
90 | * home address option in destination options header | ||
91 | */ | ||
92 | |||
93 | struct ipv6_destopt_hao { | ||
94 | __u8 type; | ||
95 | __u8 length; | ||
96 | struct in6_addr addr; | ||
97 | } __attribute__ ((__packed__)); | ||
98 | |||
76 | struct ipv6_auth_hdr { | 99 | struct ipv6_auth_hdr { |
77 | __u8 nexthdr; | 100 | __u8 nexthdr; |
78 | __u8 hdrlen; /* This one is measured in 32 bit units! */ | 101 | __u8 hdrlen; /* This one is measured in 32 bit units! */ |
@@ -153,6 +176,7 @@ struct ipv6_devconf { | |||
153 | __s32 accept_ra_rt_info_max_plen; | 176 | __s32 accept_ra_rt_info_max_plen; |
154 | #endif | 177 | #endif |
155 | #endif | 178 | #endif |
179 | __s32 proxy_ndp; | ||
156 | void *sysctl; | 180 | void *sysctl; |
157 | }; | 181 | }; |
158 | 182 | ||
@@ -180,6 +204,7 @@ enum { | |||
180 | DEVCONF_ACCEPT_RA_RTR_PREF, | 204 | DEVCONF_ACCEPT_RA_RTR_PREF, |
181 | DEVCONF_RTR_PROBE_INTERVAL, | 205 | DEVCONF_RTR_PROBE_INTERVAL, |
182 | DEVCONF_ACCEPT_RA_RT_INFO_MAX_PLEN, | 206 | DEVCONF_ACCEPT_RA_RT_INFO_MAX_PLEN, |
207 | DEVCONF_PROXY_NDP, | ||
183 | DEVCONF_MAX | 208 | DEVCONF_MAX |
184 | }; | 209 | }; |
185 | 210 | ||
@@ -206,6 +231,9 @@ struct inet6_skb_parm { | |||
206 | __u16 lastopt; | 231 | __u16 lastopt; |
207 | __u32 nhoff; | 232 | __u32 nhoff; |
208 | __u16 flags; | 233 | __u16 flags; |
234 | #ifdef CONFIG_IPV6_MIP6 | ||
235 | __u16 dsthao; | ||
236 | #endif | ||
209 | 237 | ||
210 | #define IP6SKB_XFRM_TRANSFORMED 1 | 238 | #define IP6SKB_XFRM_TRANSFORMED 1 |
211 | }; | 239 | }; |
@@ -242,6 +270,9 @@ struct ipv6_pinfo { | |||
242 | struct in6_addr rcv_saddr; | 270 | struct in6_addr rcv_saddr; |
243 | struct in6_addr daddr; | 271 | struct in6_addr daddr; |
244 | struct in6_addr *daddr_cache; | 272 | struct in6_addr *daddr_cache; |
273 | #ifdef CONFIG_IPV6_SUBTREES | ||
274 | struct in6_addr *saddr_cache; | ||
275 | #endif | ||
245 | 276 | ||
246 | __u32 flow_label; | 277 | __u32 flow_label; |
247 | __u32 frag_size; | 278 | __u32 frag_size; |
diff --git a/include/linux/kernel.h b/include/linux/kernel.h index 851aa1bcfc1a..2b2ae4fdce8b 100644 --- a/include/linux/kernel.h +++ b/include/linux/kernel.h | |||
@@ -31,7 +31,7 @@ extern const char linux_banner[]; | |||
31 | #define STACK_MAGIC 0xdeadbeef | 31 | #define STACK_MAGIC 0xdeadbeef |
32 | 32 | ||
33 | #define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) | 33 | #define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) |
34 | #define ALIGN(x,a) (((x)+(a)-1)&~((a)-1)) | 34 | #define ALIGN(x,a) (((x)+(a)-1UL)&~((a)-1UL)) |
35 | #define FIELD_SIZEOF(t, f) (sizeof(((t*)0)->f)) | 35 | #define FIELD_SIZEOF(t, f) (sizeof(((t*)0)->f)) |
36 | #define roundup(x, y) ((((x) + ((y) - 1)) / (y)) * (y)) | 36 | #define roundup(x, y) ((((x) + ((y) - 1)) / (y)) * (y)) |
37 | 37 | ||
diff --git a/include/linux/neighbour.h b/include/linux/neighbour.h new file mode 100644 index 000000000000..bd3bbf668cdb --- /dev/null +++ b/include/linux/neighbour.h | |||
@@ -0,0 +1,159 @@ | |||
1 | #ifndef __LINUX_NEIGHBOUR_H | ||
2 | #define __LINUX_NEIGHBOUR_H | ||
3 | |||
4 | #include <linux/netlink.h> | ||
5 | |||
6 | struct ndmsg | ||
7 | { | ||
8 | __u8 ndm_family; | ||
9 | __u8 ndm_pad1; | ||
10 | __u16 ndm_pad2; | ||
11 | __s32 ndm_ifindex; | ||
12 | __u16 ndm_state; | ||
13 | __u8 ndm_flags; | ||
14 | __u8 ndm_type; | ||
15 | }; | ||
16 | |||
17 | enum | ||
18 | { | ||
19 | NDA_UNSPEC, | ||
20 | NDA_DST, | ||
21 | NDA_LLADDR, | ||
22 | NDA_CACHEINFO, | ||
23 | NDA_PROBES, | ||
24 | __NDA_MAX | ||
25 | }; | ||
26 | |||
27 | #define NDA_MAX (__NDA_MAX - 1) | ||
28 | |||
29 | /* | ||
30 | * Neighbor Cache Entry Flags | ||
31 | */ | ||
32 | |||
33 | #define NTF_PROXY 0x08 /* == ATF_PUBL */ | ||
34 | #define NTF_ROUTER 0x80 | ||
35 | |||
36 | /* | ||
37 | * Neighbor Cache Entry States. | ||
38 | */ | ||
39 | |||
40 | #define NUD_INCOMPLETE 0x01 | ||
41 | #define NUD_REACHABLE 0x02 | ||
42 | #define NUD_STALE 0x04 | ||
43 | #define NUD_DELAY 0x08 | ||
44 | #define NUD_PROBE 0x10 | ||
45 | #define NUD_FAILED 0x20 | ||
46 | |||
47 | /* Dummy states */ | ||
48 | #define NUD_NOARP 0x40 | ||
49 | #define NUD_PERMANENT 0x80 | ||
50 | #define NUD_NONE 0x00 | ||
51 | |||
52 | /* NUD_NOARP & NUD_PERMANENT are pseudostates, they never change | ||
53 | and make no address resolution or NUD. | ||
54 | NUD_PERMANENT is also cannot be deleted by garbage collectors. | ||
55 | */ | ||
56 | |||
57 | struct nda_cacheinfo | ||
58 | { | ||
59 | __u32 ndm_confirmed; | ||
60 | __u32 ndm_used; | ||
61 | __u32 ndm_updated; | ||
62 | __u32 ndm_refcnt; | ||
63 | }; | ||
64 | |||
65 | /***************************************************************** | ||
66 | * Neighbour tables specific messages. | ||
67 | * | ||
68 | * To retrieve the neighbour tables send RTM_GETNEIGHTBL with the | ||
69 | * NLM_F_DUMP flag set. Every neighbour table configuration is | ||
70 | * spread over multiple messages to avoid running into message | ||
71 | * size limits on systems with many interfaces. The first message | ||
72 | * in the sequence transports all not device specific data such as | ||
73 | * statistics, configuration, and the default parameter set. | ||
74 | * This message is followed by 0..n messages carrying device | ||
75 | * specific parameter sets. | ||
76 | * Although the ordering should be sufficient, NDTA_NAME can be | ||
77 | * used to identify sequences. The initial message can be identified | ||
78 | * by checking for NDTA_CONFIG. The device specific messages do | ||
79 | * not contain this TLV but have NDTPA_IFINDEX set to the | ||
80 | * corresponding interface index. | ||
81 | * | ||
82 | * To change neighbour table attributes, send RTM_SETNEIGHTBL | ||
83 | * with NDTA_NAME set. Changeable attribute include NDTA_THRESH[1-3], | ||
84 | * NDTA_GC_INTERVAL, and all TLVs in NDTA_PARMS unless marked | ||
85 | * otherwise. Device specific parameter sets can be changed by | ||
86 | * setting NDTPA_IFINDEX to the interface index of the corresponding | ||
87 | * device. | ||
88 | ****/ | ||
89 | |||
90 | struct ndt_stats | ||
91 | { | ||
92 | __u64 ndts_allocs; | ||
93 | __u64 ndts_destroys; | ||
94 | __u64 ndts_hash_grows; | ||
95 | __u64 ndts_res_failed; | ||
96 | __u64 ndts_lookups; | ||
97 | __u64 ndts_hits; | ||
98 | __u64 ndts_rcv_probes_mcast; | ||
99 | __u64 ndts_rcv_probes_ucast; | ||
100 | __u64 ndts_periodic_gc_runs; | ||
101 | __u64 ndts_forced_gc_runs; | ||
102 | }; | ||
103 | |||
104 | enum { | ||
105 | NDTPA_UNSPEC, | ||
106 | NDTPA_IFINDEX, /* u32, unchangeable */ | ||
107 | NDTPA_REFCNT, /* u32, read-only */ | ||
108 | NDTPA_REACHABLE_TIME, /* u64, read-only, msecs */ | ||
109 | NDTPA_BASE_REACHABLE_TIME, /* u64, msecs */ | ||
110 | NDTPA_RETRANS_TIME, /* u64, msecs */ | ||
111 | NDTPA_GC_STALETIME, /* u64, msecs */ | ||
112 | NDTPA_DELAY_PROBE_TIME, /* u64, msecs */ | ||
113 | NDTPA_QUEUE_LEN, /* u32 */ | ||
114 | NDTPA_APP_PROBES, /* u32 */ | ||
115 | NDTPA_UCAST_PROBES, /* u32 */ | ||
116 | NDTPA_MCAST_PROBES, /* u32 */ | ||
117 | NDTPA_ANYCAST_DELAY, /* u64, msecs */ | ||
118 | NDTPA_PROXY_DELAY, /* u64, msecs */ | ||
119 | NDTPA_PROXY_QLEN, /* u32 */ | ||
120 | NDTPA_LOCKTIME, /* u64, msecs */ | ||
121 | __NDTPA_MAX | ||
122 | }; | ||
123 | #define NDTPA_MAX (__NDTPA_MAX - 1) | ||
124 | |||
125 | struct ndtmsg | ||
126 | { | ||
127 | __u8 ndtm_family; | ||
128 | __u8 ndtm_pad1; | ||
129 | __u16 ndtm_pad2; | ||
130 | }; | ||
131 | |||
132 | struct ndt_config | ||
133 | { | ||
134 | __u16 ndtc_key_len; | ||
135 | __u16 ndtc_entry_size; | ||
136 | __u32 ndtc_entries; | ||
137 | __u32 ndtc_last_flush; /* delta to now in msecs */ | ||
138 | __u32 ndtc_last_rand; /* delta to now in msecs */ | ||
139 | __u32 ndtc_hash_rnd; | ||
140 | __u32 ndtc_hash_mask; | ||
141 | __u32 ndtc_hash_chain_gc; | ||
142 | __u32 ndtc_proxy_qlen; | ||
143 | }; | ||
144 | |||
145 | enum { | ||
146 | NDTA_UNSPEC, | ||
147 | NDTA_NAME, /* char *, unchangeable */ | ||
148 | NDTA_THRESH1, /* u32 */ | ||
149 | NDTA_THRESH2, /* u32 */ | ||
150 | NDTA_THRESH3, /* u32 */ | ||
151 | NDTA_CONFIG, /* struct ndt_config, read-only */ | ||
152 | NDTA_PARMS, /* nested TLV NDTPA_* */ | ||
153 | NDTA_STATS, /* struct ndt_stats, read-only */ | ||
154 | NDTA_GC_INTERVAL, /* u64, msecs */ | ||
155 | __NDTA_MAX | ||
156 | }; | ||
157 | #define NDTA_MAX (__NDTA_MAX - 1) | ||
158 | |||
159 | #endif | ||
diff --git a/include/linux/net.h b/include/linux/net.h index b20c53c74413..c257f716e00f 100644 --- a/include/linux/net.h +++ b/include/linux/net.h | |||
@@ -169,11 +169,6 @@ struct proto_ops { | |||
169 | struct net_proto_family { | 169 | struct net_proto_family { |
170 | int family; | 170 | int family; |
171 | int (*create)(struct socket *sock, int protocol); | 171 | int (*create)(struct socket *sock, int protocol); |
172 | /* These are counters for the number of different methods of | ||
173 | each we support */ | ||
174 | short authentication; | ||
175 | short encryption; | ||
176 | short encrypt_net; | ||
177 | struct module *owner; | 172 | struct module *owner; |
178 | }; | 173 | }; |
179 | 174 | ||
@@ -181,8 +176,8 @@ struct iovec; | |||
181 | struct kvec; | 176 | struct kvec; |
182 | 177 | ||
183 | extern int sock_wake_async(struct socket *sk, int how, int band); | 178 | extern int sock_wake_async(struct socket *sk, int how, int band); |
184 | extern int sock_register(struct net_proto_family *fam); | 179 | extern int sock_register(const struct net_proto_family *fam); |
185 | extern int sock_unregister(int family); | 180 | extern void sock_unregister(int family); |
186 | extern int sock_create(int family, int type, int proto, | 181 | extern int sock_create(int family, int type, int proto, |
187 | struct socket **res); | 182 | struct socket **res); |
188 | extern int sock_create_kern(int family, int type, int proto, | 183 | extern int sock_create_kern(int family, int type, int proto, |
@@ -208,6 +203,25 @@ extern int kernel_recvmsg(struct socket *sock, struct msghdr *msg, | |||
208 | struct kvec *vec, size_t num, | 203 | struct kvec *vec, size_t num, |
209 | size_t len, int flags); | 204 | size_t len, int flags); |
210 | 205 | ||
206 | extern int kernel_bind(struct socket *sock, struct sockaddr *addr, | ||
207 | int addrlen); | ||
208 | extern int kernel_listen(struct socket *sock, int backlog); | ||
209 | extern int kernel_accept(struct socket *sock, struct socket **newsock, | ||
210 | int flags); | ||
211 | extern int kernel_connect(struct socket *sock, struct sockaddr *addr, | ||
212 | int addrlen, int flags); | ||
213 | extern int kernel_getsockname(struct socket *sock, struct sockaddr *addr, | ||
214 | int *addrlen); | ||
215 | extern int kernel_getpeername(struct socket *sock, struct sockaddr *addr, | ||
216 | int *addrlen); | ||
217 | extern int kernel_getsockopt(struct socket *sock, int level, int optname, | ||
218 | char *optval, int *optlen); | ||
219 | extern int kernel_setsockopt(struct socket *sock, int level, int optname, | ||
220 | char *optval, int optlen); | ||
221 | extern int kernel_sendpage(struct socket *sock, struct page *page, int offset, | ||
222 | size_t size, int flags); | ||
223 | extern int kernel_sock_ioctl(struct socket *sock, int cmd, unsigned long arg); | ||
224 | |||
211 | #ifndef CONFIG_SMP | 225 | #ifndef CONFIG_SMP |
212 | #define SOCKOPS_WRAPPED(name) name | 226 | #define SOCKOPS_WRAPPED(name) name |
213 | #define SOCKOPS_WRAP(name, fam) | 227 | #define SOCKOPS_WRAP(name, fam) |
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index 50a4719512ed..4f2c2b6beb5e 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h | |||
@@ -976,7 +976,7 @@ extern void dev_mcast_init(void); | |||
976 | extern int netdev_max_backlog; | 976 | extern int netdev_max_backlog; |
977 | extern int weight_p; | 977 | extern int weight_p; |
978 | extern int netdev_set_master(struct net_device *dev, struct net_device *master); | 978 | extern int netdev_set_master(struct net_device *dev, struct net_device *master); |
979 | extern int skb_checksum_help(struct sk_buff *skb, int inward); | 979 | extern int skb_checksum_help(struct sk_buff *skb); |
980 | extern struct sk_buff *skb_gso_segment(struct sk_buff *skb, int features); | 980 | extern struct sk_buff *skb_gso_segment(struct sk_buff *skb, int features); |
981 | #ifdef CONFIG_BUG | 981 | #ifdef CONFIG_BUG |
982 | extern void netdev_rx_csum_fault(struct net_device *dev); | 982 | extern void netdev_rx_csum_fault(struct net_device *dev); |
@@ -1012,7 +1012,7 @@ static inline int netif_needs_gso(struct net_device *dev, struct sk_buff *skb) | |||
1012 | { | 1012 | { |
1013 | return skb_is_gso(skb) && | 1013 | return skb_is_gso(skb) && |
1014 | (!skb_gso_ok(skb, dev->features) || | 1014 | (!skb_gso_ok(skb, dev->features) || |
1015 | unlikely(skb->ip_summed != CHECKSUM_HW)); | 1015 | unlikely(skb->ip_summed != CHECKSUM_PARTIAL)); |
1016 | } | 1016 | } |
1017 | 1017 | ||
1018 | /* On bonding slaves other than the currently active slave, suppress | 1018 | /* On bonding slaves other than the currently active slave, suppress |
diff --git a/include/linux/netfilter.h b/include/linux/netfilter.h index 10168e26a846..b7e67d1d4382 100644 --- a/include/linux/netfilter.h +++ b/include/linux/netfilter.h | |||
@@ -282,6 +282,12 @@ extern void nf_invalidate_cache(int pf); | |||
282 | Returns true or false. */ | 282 | Returns true or false. */ |
283 | extern int skb_make_writable(struct sk_buff **pskb, unsigned int writable_len); | 283 | extern int skb_make_writable(struct sk_buff **pskb, unsigned int writable_len); |
284 | 284 | ||
285 | extern u_int16_t nf_csum_update(u_int32_t oldval, u_int32_t newval, | ||
286 | u_int32_t csum); | ||
287 | extern u_int16_t nf_proto_csum_update(struct sk_buff *skb, | ||
288 | u_int32_t oldval, u_int32_t newval, | ||
289 | u_int16_t csum, int pseudohdr); | ||
290 | |||
285 | struct nf_afinfo { | 291 | struct nf_afinfo { |
286 | unsigned short family; | 292 | unsigned short family; |
287 | unsigned int (*checksum)(struct sk_buff *skb, unsigned int hook, | 293 | unsigned int (*checksum)(struct sk_buff *skb, unsigned int hook, |
diff --git a/include/linux/netfilter/nf_conntrack_common.h b/include/linux/netfilter/nf_conntrack_common.h index d2e4bd7a7a14..9e0dae07861e 100644 --- a/include/linux/netfilter/nf_conntrack_common.h +++ b/include/linux/netfilter/nf_conntrack_common.h | |||
@@ -125,6 +125,10 @@ enum ip_conntrack_events | |||
125 | /* Counter highest bit has been set */ | 125 | /* Counter highest bit has been set */ |
126 | IPCT_COUNTER_FILLING_BIT = 11, | 126 | IPCT_COUNTER_FILLING_BIT = 11, |
127 | IPCT_COUNTER_FILLING = (1 << IPCT_COUNTER_FILLING_BIT), | 127 | IPCT_COUNTER_FILLING = (1 << IPCT_COUNTER_FILLING_BIT), |
128 | |||
129 | /* Mark is set */ | ||
130 | IPCT_MARK_BIT = 12, | ||
131 | IPCT_MARK = (1 << IPCT_MARK_BIT), | ||
128 | }; | 132 | }; |
129 | 133 | ||
130 | enum ip_conntrack_expect_events { | 134 | enum ip_conntrack_expect_events { |
diff --git a/include/linux/netfilter/nf_conntrack_tcp.h b/include/linux/netfilter/nf_conntrack_tcp.h index b2feeffde384..6b01ba297727 100644 --- a/include/linux/netfilter/nf_conntrack_tcp.h +++ b/include/linux/netfilter/nf_conntrack_tcp.h | |||
@@ -49,6 +49,7 @@ struct ip_ct_tcp | |||
49 | u_int32_t last_seq; /* Last sequence number seen in dir */ | 49 | u_int32_t last_seq; /* Last sequence number seen in dir */ |
50 | u_int32_t last_ack; /* Last sequence number seen in opposite dir */ | 50 | u_int32_t last_ack; /* Last sequence number seen in opposite dir */ |
51 | u_int32_t last_end; /* Last seq + len */ | 51 | u_int32_t last_end; /* Last seq + len */ |
52 | u_int16_t last_win; /* Last window advertisement seen in dir */ | ||
52 | }; | 53 | }; |
53 | 54 | ||
54 | #endif /* __KERNEL__ */ | 55 | #endif /* __KERNEL__ */ |
diff --git a/include/linux/netfilter/nfnetlink.h b/include/linux/netfilter/nfnetlink.h index 9f5b12cf489b..6d8e3e5a80e9 100644 --- a/include/linux/netfilter/nfnetlink.h +++ b/include/linux/netfilter/nfnetlink.h | |||
@@ -43,7 +43,7 @@ struct nfattr | |||
43 | u_int16_t nfa_len; | 43 | u_int16_t nfa_len; |
44 | u_int16_t nfa_type; /* we use 15 bits for the type, and the highest | 44 | u_int16_t nfa_type; /* we use 15 bits for the type, and the highest |
45 | * bit to indicate whether the payload is nested */ | 45 | * bit to indicate whether the payload is nested */ |
46 | } __attribute__ ((packed)); | 46 | }; |
47 | 47 | ||
48 | /* FIXME: Apart from NFNL_NFA_NESTED shamelessly copy and pasted from | 48 | /* FIXME: Apart from NFNL_NFA_NESTED shamelessly copy and pasted from |
49 | * rtnetlink.h, it's time to put this in a generic file */ | 49 | * rtnetlink.h, it's time to put this in a generic file */ |
@@ -79,7 +79,7 @@ struct nfgenmsg { | |||
79 | u_int8_t nfgen_family; /* AF_xxx */ | 79 | u_int8_t nfgen_family; /* AF_xxx */ |
80 | u_int8_t version; /* nfnetlink version */ | 80 | u_int8_t version; /* nfnetlink version */ |
81 | u_int16_t res_id; /* resource id */ | 81 | u_int16_t res_id; /* resource id */ |
82 | } __attribute__ ((packed)); | 82 | }; |
83 | 83 | ||
84 | #define NFNETLINK_V0 0 | 84 | #define NFNETLINK_V0 0 |
85 | 85 | ||
diff --git a/include/linux/netfilter/nfnetlink_log.h b/include/linux/netfilter/nfnetlink_log.h index a7497c7436df..87b92f8b988f 100644 --- a/include/linux/netfilter/nfnetlink_log.h +++ b/include/linux/netfilter/nfnetlink_log.h | |||
@@ -19,18 +19,18 @@ struct nfulnl_msg_packet_hdr { | |||
19 | u_int16_t hw_protocol; /* hw protocol (network order) */ | 19 | u_int16_t hw_protocol; /* hw protocol (network order) */ |
20 | u_int8_t hook; /* netfilter hook */ | 20 | u_int8_t hook; /* netfilter hook */ |
21 | u_int8_t _pad; | 21 | u_int8_t _pad; |
22 | } __attribute__ ((packed)); | 22 | }; |
23 | 23 | ||
24 | struct nfulnl_msg_packet_hw { | 24 | struct nfulnl_msg_packet_hw { |
25 | u_int16_t hw_addrlen; | 25 | u_int16_t hw_addrlen; |
26 | u_int16_t _pad; | 26 | u_int16_t _pad; |
27 | u_int8_t hw_addr[8]; | 27 | u_int8_t hw_addr[8]; |
28 | } __attribute__ ((packed)); | 28 | }; |
29 | 29 | ||
30 | struct nfulnl_msg_packet_timestamp { | 30 | struct nfulnl_msg_packet_timestamp { |
31 | aligned_u64 sec; | 31 | aligned_u64 sec; |
32 | aligned_u64 usec; | 32 | aligned_u64 usec; |
33 | } __attribute__ ((packed)); | 33 | }; |
34 | 34 | ||
35 | #define NFULNL_PREFIXLEN 30 /* just like old log target */ | 35 | #define NFULNL_PREFIXLEN 30 /* just like old log target */ |
36 | 36 | ||
diff --git a/include/linux/netfilter/nfnetlink_queue.h b/include/linux/netfilter/nfnetlink_queue.h index 9e774373244c..36af0360b56d 100644 --- a/include/linux/netfilter/nfnetlink_queue.h +++ b/include/linux/netfilter/nfnetlink_queue.h | |||
@@ -22,12 +22,12 @@ struct nfqnl_msg_packet_hw { | |||
22 | u_int16_t hw_addrlen; | 22 | u_int16_t hw_addrlen; |
23 | u_int16_t _pad; | 23 | u_int16_t _pad; |
24 | u_int8_t hw_addr[8]; | 24 | u_int8_t hw_addr[8]; |
25 | } __attribute__ ((packed)); | 25 | }; |
26 | 26 | ||
27 | struct nfqnl_msg_packet_timestamp { | 27 | struct nfqnl_msg_packet_timestamp { |
28 | aligned_u64 sec; | 28 | aligned_u64 sec; |
29 | aligned_u64 usec; | 29 | aligned_u64 usec; |
30 | } __attribute__ ((packed)); | 30 | }; |
31 | 31 | ||
32 | enum nfqnl_attr_type { | 32 | enum nfqnl_attr_type { |
33 | NFQA_UNSPEC, | 33 | NFQA_UNSPEC, |
@@ -49,7 +49,7 @@ enum nfqnl_attr_type { | |||
49 | struct nfqnl_msg_verdict_hdr { | 49 | struct nfqnl_msg_verdict_hdr { |
50 | u_int32_t verdict; | 50 | u_int32_t verdict; |
51 | u_int32_t id; | 51 | u_int32_t id; |
52 | } __attribute__ ((packed)); | 52 | }; |
53 | 53 | ||
54 | 54 | ||
55 | enum nfqnl_msg_config_cmds { | 55 | enum nfqnl_msg_config_cmds { |
@@ -64,7 +64,7 @@ struct nfqnl_msg_config_cmd { | |||
64 | u_int8_t command; /* nfqnl_msg_config_cmds */ | 64 | u_int8_t command; /* nfqnl_msg_config_cmds */ |
65 | u_int8_t _pad; | 65 | u_int8_t _pad; |
66 | u_int16_t pf; /* AF_xxx for PF_[UN]BIND */ | 66 | u_int16_t pf; /* AF_xxx for PF_[UN]BIND */ |
67 | } __attribute__ ((packed)); | 67 | }; |
68 | 68 | ||
69 | enum nfqnl_config_mode { | 69 | enum nfqnl_config_mode { |
70 | NFQNL_COPY_NONE, | 70 | NFQNL_COPY_NONE, |
diff --git a/include/linux/netfilter/x_tables.h b/include/linux/netfilter/x_tables.h index 48cc32d83f77..739a98eebe2c 100644 --- a/include/linux/netfilter/x_tables.h +++ b/include/linux/netfilter/x_tables.h | |||
@@ -138,16 +138,6 @@ struct xt_counters_info | |||
138 | 138 | ||
139 | #include <linux/netdevice.h> | 139 | #include <linux/netdevice.h> |
140 | 140 | ||
141 | #define ASSERT_READ_LOCK(x) | ||
142 | #define ASSERT_WRITE_LOCK(x) | ||
143 | #include <linux/netfilter_ipv4/listhelp.h> | ||
144 | |||
145 | #ifdef CONFIG_COMPAT | ||
146 | #define COMPAT_TO_USER 1 | ||
147 | #define COMPAT_FROM_USER -1 | ||
148 | #define COMPAT_CALC_SIZE 0 | ||
149 | #endif | ||
150 | |||
151 | struct xt_match | 141 | struct xt_match |
152 | { | 142 | { |
153 | struct list_head list; | 143 | struct list_head list; |
@@ -174,21 +164,24 @@ struct xt_match | |||
174 | const void *ip, | 164 | const void *ip, |
175 | const struct xt_match *match, | 165 | const struct xt_match *match, |
176 | void *matchinfo, | 166 | void *matchinfo, |
177 | unsigned int matchinfosize, | ||
178 | unsigned int hook_mask); | 167 | unsigned int hook_mask); |
179 | 168 | ||
180 | /* Called when entry of this type deleted. */ | 169 | /* Called when entry of this type deleted. */ |
181 | void (*destroy)(const struct xt_match *match, void *matchinfo, | 170 | void (*destroy)(const struct xt_match *match, void *matchinfo); |
182 | unsigned int matchinfosize); | ||
183 | 171 | ||
184 | /* Called when userspace align differs from kernel space one */ | 172 | /* Called when userspace align differs from kernel space one */ |
185 | int (*compat)(void *match, void **dstptr, int *size, int convert); | 173 | void (*compat_from_user)(void *dst, void *src); |
174 | int (*compat_to_user)(void __user *dst, void *src); | ||
186 | 175 | ||
187 | /* Set this to THIS_MODULE if you are a module, otherwise NULL */ | 176 | /* Set this to THIS_MODULE if you are a module, otherwise NULL */ |
188 | struct module *me; | 177 | struct module *me; |
189 | 178 | ||
179 | /* Free to use by each match */ | ||
180 | unsigned long data; | ||
181 | |||
190 | char *table; | 182 | char *table; |
191 | unsigned int matchsize; | 183 | unsigned int matchsize; |
184 | unsigned int compatsize; | ||
192 | unsigned int hooks; | 185 | unsigned int hooks; |
193 | unsigned short proto; | 186 | unsigned short proto; |
194 | 187 | ||
@@ -211,8 +204,7 @@ struct xt_target | |||
211 | const struct net_device *out, | 204 | const struct net_device *out, |
212 | unsigned int hooknum, | 205 | unsigned int hooknum, |
213 | const struct xt_target *target, | 206 | const struct xt_target *target, |
214 | const void *targinfo, | 207 | const void *targinfo); |
215 | void *userdata); | ||
216 | 208 | ||
217 | /* Called when user tries to insert an entry of this type: | 209 | /* Called when user tries to insert an entry of this type: |
218 | hook_mask is a bitmask of hooks from which it can be | 210 | hook_mask is a bitmask of hooks from which it can be |
@@ -222,21 +214,21 @@ struct xt_target | |||
222 | const void *entry, | 214 | const void *entry, |
223 | const struct xt_target *target, | 215 | const struct xt_target *target, |
224 | void *targinfo, | 216 | void *targinfo, |
225 | unsigned int targinfosize, | ||
226 | unsigned int hook_mask); | 217 | unsigned int hook_mask); |
227 | 218 | ||
228 | /* Called when entry of this type deleted. */ | 219 | /* Called when entry of this type deleted. */ |
229 | void (*destroy)(const struct xt_target *target, void *targinfo, | 220 | void (*destroy)(const struct xt_target *target, void *targinfo); |
230 | unsigned int targinfosize); | ||
231 | 221 | ||
232 | /* Called when userspace align differs from kernel space one */ | 222 | /* Called when userspace align differs from kernel space one */ |
233 | int (*compat)(void *target, void **dstptr, int *size, int convert); | 223 | void (*compat_from_user)(void *dst, void *src); |
224 | int (*compat_to_user)(void __user *dst, void *src); | ||
234 | 225 | ||
235 | /* Set this to THIS_MODULE if you are a module, otherwise NULL */ | 226 | /* Set this to THIS_MODULE if you are a module, otherwise NULL */ |
236 | struct module *me; | 227 | struct module *me; |
237 | 228 | ||
238 | char *table; | 229 | char *table; |
239 | unsigned int targetsize; | 230 | unsigned int targetsize; |
231 | unsigned int compatsize; | ||
240 | unsigned int hooks; | 232 | unsigned int hooks; |
241 | unsigned short proto; | 233 | unsigned short proto; |
242 | 234 | ||
@@ -290,8 +282,13 @@ struct xt_table_info | |||
290 | 282 | ||
291 | extern int xt_register_target(struct xt_target *target); | 283 | extern int xt_register_target(struct xt_target *target); |
292 | extern void xt_unregister_target(struct xt_target *target); | 284 | extern void xt_unregister_target(struct xt_target *target); |
285 | extern int xt_register_targets(struct xt_target *target, unsigned int n); | ||
286 | extern void xt_unregister_targets(struct xt_target *target, unsigned int n); | ||
287 | |||
293 | extern int xt_register_match(struct xt_match *target); | 288 | extern int xt_register_match(struct xt_match *target); |
294 | extern void xt_unregister_match(struct xt_match *target); | 289 | extern void xt_unregister_match(struct xt_match *target); |
290 | extern int xt_register_matches(struct xt_match *match, unsigned int n); | ||
291 | extern void xt_unregister_matches(struct xt_match *match, unsigned int n); | ||
295 | 292 | ||
296 | extern int xt_check_match(const struct xt_match *match, unsigned short family, | 293 | extern int xt_check_match(const struct xt_match *match, unsigned short family, |
297 | unsigned int size, const char *table, unsigned int hook, | 294 | unsigned int size, const char *table, unsigned int hook, |
@@ -388,9 +385,18 @@ struct compat_xt_counters_info | |||
388 | 385 | ||
389 | extern void xt_compat_lock(int af); | 386 | extern void xt_compat_lock(int af); |
390 | extern void xt_compat_unlock(int af); | 387 | extern void xt_compat_unlock(int af); |
391 | extern int xt_compat_match(void *match, void **dstptr, int *size, int convert); | 388 | |
392 | extern int xt_compat_target(void *target, void **dstptr, int *size, | 389 | extern int xt_compat_match_offset(struct xt_match *match); |
393 | int convert); | 390 | extern void xt_compat_match_from_user(struct xt_entry_match *m, |
391 | void **dstptr, int *size); | ||
392 | extern int xt_compat_match_to_user(struct xt_entry_match *m, | ||
393 | void * __user *dstptr, int *size); | ||
394 | |||
395 | extern int xt_compat_target_offset(struct xt_target *target); | ||
396 | extern void xt_compat_target_from_user(struct xt_entry_target *t, | ||
397 | void **dstptr, int *size); | ||
398 | extern int xt_compat_target_to_user(struct xt_entry_target *t, | ||
399 | void * __user *dstptr, int *size); | ||
394 | 400 | ||
395 | #endif /* CONFIG_COMPAT */ | 401 | #endif /* CONFIG_COMPAT */ |
396 | #endif /* __KERNEL__ */ | 402 | #endif /* __KERNEL__ */ |
diff --git a/include/linux/netfilter/xt_DSCP.h b/include/linux/netfilter/xt_DSCP.h new file mode 100644 index 000000000000..3c7c963997bd --- /dev/null +++ b/include/linux/netfilter/xt_DSCP.h | |||
@@ -0,0 +1,20 @@ | |||
1 | /* x_tables module for setting the IPv4/IPv6 DSCP field | ||
2 | * | ||
3 | * (C) 2002 Harald Welte <laforge@gnumonks.org> | ||
4 | * based on ipt_FTOS.c (C) 2000 by Matthew G. Marsh <mgm@paktronix.com> | ||
5 | * This software is distributed under GNU GPL v2, 1991 | ||
6 | * | ||
7 | * See RFC2474 for a description of the DSCP field within the IP Header. | ||
8 | * | ||
9 | * xt_DSCP.h,v 1.7 2002/03/14 12:03:13 laforge Exp | ||
10 | */ | ||
11 | #ifndef _XT_DSCP_TARGET_H | ||
12 | #define _XT_DSCP_TARGET_H | ||
13 | #include <linux/netfilter/xt_dscp.h> | ||
14 | |||
15 | /* target info */ | ||
16 | struct xt_DSCP_info { | ||
17 | u_int8_t dscp; | ||
18 | }; | ||
19 | |||
20 | #endif /* _XT_DSCP_TARGET_H */ | ||
diff --git a/include/linux/netfilter/xt_dscp.h b/include/linux/netfilter/xt_dscp.h new file mode 100644 index 000000000000..1da61e6acaf7 --- /dev/null +++ b/include/linux/netfilter/xt_dscp.h | |||
@@ -0,0 +1,23 @@ | |||
1 | /* x_tables module for matching the IPv4/IPv6 DSCP field | ||
2 | * | ||
3 | * (C) 2002 Harald Welte <laforge@gnumonks.org> | ||
4 | * This software is distributed under GNU GPL v2, 1991 | ||
5 | * | ||
6 | * See RFC2474 for a description of the DSCP field within the IP Header. | ||
7 | * | ||
8 | * xt_dscp.h,v 1.3 2002/08/05 19:00:21 laforge Exp | ||
9 | */ | ||
10 | #ifndef _XT_DSCP_H | ||
11 | #define _XT_DSCP_H | ||
12 | |||
13 | #define XT_DSCP_MASK 0xfc /* 11111100 */ | ||
14 | #define XT_DSCP_SHIFT 2 | ||
15 | #define XT_DSCP_MAX 0x3f /* 00111111 */ | ||
16 | |||
17 | /* match info */ | ||
18 | struct xt_dscp_info { | ||
19 | u_int8_t dscp; | ||
20 | u_int8_t invert; | ||
21 | }; | ||
22 | |||
23 | #endif /* _XT_DSCP_H */ | ||
diff --git a/include/linux/netfilter_arp/arp_tables.h b/include/linux/netfilter_arp/arp_tables.h index 62cc27daca4e..149e87c9ab13 100644 --- a/include/linux/netfilter_arp/arp_tables.h +++ b/include/linux/netfilter_arp/arp_tables.h | |||
@@ -248,8 +248,7 @@ extern unsigned int arpt_do_table(struct sk_buff **pskb, | |||
248 | unsigned int hook, | 248 | unsigned int hook, |
249 | const struct net_device *in, | 249 | const struct net_device *in, |
250 | const struct net_device *out, | 250 | const struct net_device *out, |
251 | struct arpt_table *table, | 251 | struct arpt_table *table); |
252 | void *userdata); | ||
253 | 252 | ||
254 | #define ARPT_ALIGN(s) (((s) + (__alignof__(struct arpt_entry)-1)) & ~(__alignof__(struct arpt_entry)-1)) | 253 | #define ARPT_ALIGN(s) (((s) + (__alignof__(struct arpt_entry)-1)) & ~(__alignof__(struct arpt_entry)-1)) |
255 | #endif /*__KERNEL__*/ | 254 | #endif /*__KERNEL__*/ |
diff --git a/include/linux/netfilter_bridge.h b/include/linux/netfilter_bridge.h index 427c67ff89e9..9a4dd11af86e 100644 --- a/include/linux/netfilter_bridge.h +++ b/include/linux/netfilter_bridge.h | |||
@@ -5,9 +5,8 @@ | |||
5 | */ | 5 | */ |
6 | 6 | ||
7 | #include <linux/netfilter.h> | 7 | #include <linux/netfilter.h> |
8 | #if defined(__KERNEL__) && defined(CONFIG_BRIDGE_NETFILTER) | ||
9 | #include <linux/if_ether.h> | 8 | #include <linux/if_ether.h> |
10 | #endif | 9 | #include <linux/if_vlan.h> |
11 | 10 | ||
12 | /* Bridge Hooks */ | 11 | /* Bridge Hooks */ |
13 | /* After promisc drops, checksum checks. */ | 12 | /* After promisc drops, checksum checks. */ |
@@ -47,40 +46,20 @@ enum nf_br_hook_priorities { | |||
47 | 46 | ||
48 | 47 | ||
49 | /* Only used in br_forward.c */ | 48 | /* Only used in br_forward.c */ |
50 | static inline | 49 | extern int nf_bridge_copy_header(struct sk_buff *skb); |
51 | int nf_bridge_maybe_copy_header(struct sk_buff *skb) | 50 | static inline int nf_bridge_maybe_copy_header(struct sk_buff *skb) |
52 | { | 51 | { |
53 | int err; | 52 | if (skb->nf_bridge) |
54 | 53 | return nf_bridge_copy_header(skb); | |
55 | if (skb->nf_bridge) { | 54 | return 0; |
56 | if (skb->protocol == __constant_htons(ETH_P_8021Q)) { | ||
57 | err = skb_cow(skb, 18); | ||
58 | if (err) | ||
59 | return err; | ||
60 | memcpy(skb->data - 18, skb->nf_bridge->data, 18); | ||
61 | skb_push(skb, 4); | ||
62 | } else { | ||
63 | err = skb_cow(skb, 16); | ||
64 | if (err) | ||
65 | return err; | ||
66 | memcpy(skb->data - 16, skb->nf_bridge->data, 16); | ||
67 | } | ||
68 | } | ||
69 | return 0; | ||
70 | } | 55 | } |
71 | 56 | ||
72 | /* This is called by the IP fragmenting code and it ensures there is | 57 | /* This is called by the IP fragmenting code and it ensures there is |
73 | * enough room for the encapsulating header (if there is one). */ | 58 | * enough room for the encapsulating header (if there is one). */ |
74 | static inline | 59 | static inline int nf_bridge_pad(const struct sk_buff *skb) |
75 | int nf_bridge_pad(struct sk_buff *skb) | ||
76 | { | 60 | { |
77 | if (skb->protocol == __constant_htons(ETH_P_IP)) | 61 | return (skb->nf_bridge && skb->protocol == htons(ETH_P_8021Q)) |
78 | return 0; | 62 | ? VLAN_HLEN : 0; |
79 | if (skb->nf_bridge) { | ||
80 | if (skb->protocol == __constant_htons(ETH_P_8021Q)) | ||
81 | return 4; | ||
82 | } | ||
83 | return 0; | ||
84 | } | 63 | } |
85 | 64 | ||
86 | struct bridge_skb_cb { | 65 | struct bridge_skb_cb { |
@@ -90,6 +69,9 @@ struct bridge_skb_cb { | |||
90 | }; | 69 | }; |
91 | 70 | ||
92 | extern int brnf_deferred_hooks; | 71 | extern int brnf_deferred_hooks; |
72 | #else | ||
73 | #define nf_bridge_maybe_copy_header(skb) (0) | ||
74 | #define nf_bridge_pad(skb) (0) | ||
93 | #endif /* CONFIG_BRIDGE_NETFILTER */ | 75 | #endif /* CONFIG_BRIDGE_NETFILTER */ |
94 | 76 | ||
95 | #endif /* __KERNEL__ */ | 77 | #endif /* __KERNEL__ */ |
diff --git a/include/linux/netfilter_ipv4/ip_conntrack_helper.h b/include/linux/netfilter_ipv4/ip_conntrack_helper.h index 8d69279ccfe4..77fe868d36ff 100644 --- a/include/linux/netfilter_ipv4/ip_conntrack_helper.h +++ b/include/linux/netfilter_ipv4/ip_conntrack_helper.h | |||
@@ -25,6 +25,8 @@ struct ip_conntrack_helper | |||
25 | struct ip_conntrack *ct, | 25 | struct ip_conntrack *ct, |
26 | enum ip_conntrack_info conntrackinfo); | 26 | enum ip_conntrack_info conntrackinfo); |
27 | 27 | ||
28 | void (*destroy)(struct ip_conntrack *ct); | ||
29 | |||
28 | int (*to_nfattr)(struct sk_buff *skb, const struct ip_conntrack *ct); | 30 | int (*to_nfattr)(struct sk_buff *skb, const struct ip_conntrack *ct); |
29 | }; | 31 | }; |
30 | 32 | ||
diff --git a/include/linux/netfilter_ipv4/ip_conntrack_pptp.h b/include/linux/netfilter_ipv4/ip_conntrack_pptp.h index 816144c75de0..2644b1faddd6 100644 --- a/include/linux/netfilter_ipv4/ip_conntrack_pptp.h +++ b/include/linux/netfilter_ipv4/ip_conntrack_pptp.h | |||
@@ -31,8 +31,8 @@ struct ip_ct_pptp_master { | |||
31 | /* everything below is going to be per-expectation in newnat, | 31 | /* everything below is going to be per-expectation in newnat, |
32 | * since there could be more than one call within one session */ | 32 | * since there could be more than one call within one session */ |
33 | enum pptp_ctrlcall_state cstate; /* call state */ | 33 | enum pptp_ctrlcall_state cstate; /* call state */ |
34 | u_int16_t pac_call_id; /* call id of PAC, host byte order */ | 34 | __be16 pac_call_id; /* call id of PAC, host byte order */ |
35 | u_int16_t pns_call_id; /* call id of PNS, host byte order */ | 35 | __be16 pns_call_id; /* call id of PNS, host byte order */ |
36 | 36 | ||
37 | /* in pre-2.6.11 this used to be per-expect. Now it is per-conntrack | 37 | /* in pre-2.6.11 this used to be per-expect. Now it is per-conntrack |
38 | * and therefore imposes a fixed limit on the number of maps */ | 38 | * and therefore imposes a fixed limit on the number of maps */ |
@@ -42,8 +42,8 @@ struct ip_ct_pptp_master { | |||
42 | /* conntrack_expect private member */ | 42 | /* conntrack_expect private member */ |
43 | struct ip_ct_pptp_expect { | 43 | struct ip_ct_pptp_expect { |
44 | enum pptp_ctrlcall_state cstate; /* call state */ | 44 | enum pptp_ctrlcall_state cstate; /* call state */ |
45 | u_int16_t pac_call_id; /* call id of PAC */ | 45 | __be16 pac_call_id; /* call id of PAC */ |
46 | u_int16_t pns_call_id; /* call id of PNS */ | 46 | __be16 pns_call_id; /* call id of PNS */ |
47 | }; | 47 | }; |
48 | 48 | ||
49 | 49 | ||
@@ -107,8 +107,7 @@ struct PptpControlHeader { | |||
107 | 107 | ||
108 | struct PptpStartSessionRequest { | 108 | struct PptpStartSessionRequest { |
109 | __be16 protocolVersion; | 109 | __be16 protocolVersion; |
110 | __u8 reserved1; | 110 | __u16 reserved1; |
111 | __u8 reserved2; | ||
112 | __be32 framingCapability; | 111 | __be32 framingCapability; |
113 | __be32 bearerCapability; | 112 | __be32 bearerCapability; |
114 | __be16 maxChannels; | 113 | __be16 maxChannels; |
@@ -143,6 +142,8 @@ struct PptpStartSessionReply { | |||
143 | 142 | ||
144 | struct PptpStopSessionRequest { | 143 | struct PptpStopSessionRequest { |
145 | __u8 reason; | 144 | __u8 reason; |
145 | __u8 reserved1; | ||
146 | __u16 reserved2; | ||
146 | }; | 147 | }; |
147 | 148 | ||
148 | /* PptpStopSessionResultCode */ | 149 | /* PptpStopSessionResultCode */ |
@@ -152,6 +153,7 @@ struct PptpStopSessionRequest { | |||
152 | struct PptpStopSessionReply { | 153 | struct PptpStopSessionReply { |
153 | __u8 resultCode; | 154 | __u8 resultCode; |
154 | __u8 generalErrorCode; | 155 | __u8 generalErrorCode; |
156 | __u16 reserved1; | ||
155 | }; | 157 | }; |
156 | 158 | ||
157 | struct PptpEchoRequest { | 159 | struct PptpEchoRequest { |
@@ -188,9 +190,8 @@ struct PptpOutCallRequest { | |||
188 | __be32 framingType; | 190 | __be32 framingType; |
189 | __be16 packetWindow; | 191 | __be16 packetWindow; |
190 | __be16 packetProcDelay; | 192 | __be16 packetProcDelay; |
191 | __u16 reserved1; | ||
192 | __be16 phoneNumberLength; | 193 | __be16 phoneNumberLength; |
193 | __u16 reserved2; | 194 | __u16 reserved1; |
194 | __u8 phoneNumber[64]; | 195 | __u8 phoneNumber[64]; |
195 | __u8 subAddress[64]; | 196 | __u8 subAddress[64]; |
196 | }; | 197 | }; |
@@ -285,19 +286,19 @@ struct PptpSetLinkInfo { | |||
285 | }; | 286 | }; |
286 | 287 | ||
287 | union pptp_ctrl_union { | 288 | union pptp_ctrl_union { |
288 | struct PptpStartSessionRequest sreq; | 289 | struct PptpStartSessionRequest sreq; |
289 | struct PptpStartSessionReply srep; | 290 | struct PptpStartSessionReply srep; |
290 | struct PptpStopSessionRequest streq; | 291 | struct PptpStopSessionRequest streq; |
291 | struct PptpStopSessionReply strep; | 292 | struct PptpStopSessionReply strep; |
292 | struct PptpOutCallRequest ocreq; | 293 | struct PptpOutCallRequest ocreq; |
293 | struct PptpOutCallReply ocack; | 294 | struct PptpOutCallReply ocack; |
294 | struct PptpInCallRequest icreq; | 295 | struct PptpInCallRequest icreq; |
295 | struct PptpInCallReply icack; | 296 | struct PptpInCallReply icack; |
296 | struct PptpInCallConnected iccon; | 297 | struct PptpInCallConnected iccon; |
297 | struct PptpClearCallRequest clrreq; | 298 | struct PptpClearCallRequest clrreq; |
298 | struct PptpCallDisconnectNotify disc; | 299 | struct PptpCallDisconnectNotify disc; |
299 | struct PptpWanErrorNotify wanerr; | 300 | struct PptpWanErrorNotify wanerr; |
300 | struct PptpSetLinkInfo setlink; | 301 | struct PptpSetLinkInfo setlink; |
301 | }; | 302 | }; |
302 | 303 | ||
303 | extern int | 304 | extern int |
@@ -314,7 +315,7 @@ extern int | |||
314 | struct PptpControlHeader *ctlh, | 315 | struct PptpControlHeader *ctlh, |
315 | union pptp_ctrl_union *pptpReq); | 316 | union pptp_ctrl_union *pptpReq); |
316 | 317 | ||
317 | extern int | 318 | extern void |
318 | (*ip_nat_pptp_hook_exp_gre)(struct ip_conntrack_expect *exp_orig, | 319 | (*ip_nat_pptp_hook_exp_gre)(struct ip_conntrack_expect *exp_orig, |
319 | struct ip_conntrack_expect *exp_reply); | 320 | struct ip_conntrack_expect *exp_reply); |
320 | 321 | ||
diff --git a/include/linux/netfilter_ipv4/ip_conntrack_proto_gre.h b/include/linux/netfilter_ipv4/ip_conntrack_proto_gre.h index 8d090ef82f5f..1d853aa873eb 100644 --- a/include/linux/netfilter_ipv4/ip_conntrack_proto_gre.h +++ b/include/linux/netfilter_ipv4/ip_conntrack_proto_gre.h | |||
@@ -49,18 +49,18 @@ struct gre_hdr { | |||
49 | #else | 49 | #else |
50 | #error "Adjust your <asm/byteorder.h> defines" | 50 | #error "Adjust your <asm/byteorder.h> defines" |
51 | #endif | 51 | #endif |
52 | __u16 protocol; | 52 | __be16 protocol; |
53 | }; | 53 | }; |
54 | 54 | ||
55 | /* modified GRE header for PPTP */ | 55 | /* modified GRE header for PPTP */ |
56 | struct gre_hdr_pptp { | 56 | struct gre_hdr_pptp { |
57 | __u8 flags; /* bitfield */ | 57 | __u8 flags; /* bitfield */ |
58 | __u8 version; /* should be GRE_VERSION_PPTP */ | 58 | __u8 version; /* should be GRE_VERSION_PPTP */ |
59 | __u16 protocol; /* should be GRE_PROTOCOL_PPTP */ | 59 | __be16 protocol; /* should be GRE_PROTOCOL_PPTP */ |
60 | __u16 payload_len; /* size of ppp payload, not inc. gre header */ | 60 | __be16 payload_len; /* size of ppp payload, not inc. gre header */ |
61 | __u16 call_id; /* peer's call_id for this session */ | 61 | __be16 call_id; /* peer's call_id for this session */ |
62 | __u32 seq; /* sequence number. Present if S==1 */ | 62 | __be32 seq; /* sequence number. Present if S==1 */ |
63 | __u32 ack; /* seq number of highest packet recieved by */ | 63 | __be32 ack; /* seq number of highest packet recieved by */ |
64 | /* sender in this session */ | 64 | /* sender in this session */ |
65 | }; | 65 | }; |
66 | 66 | ||
@@ -92,13 +92,13 @@ void ip_ct_gre_keymap_destroy(struct ip_conntrack *ct); | |||
92 | 92 | ||
93 | 93 | ||
94 | /* get pointer to gre key, if present */ | 94 | /* get pointer to gre key, if present */ |
95 | static inline u_int32_t *gre_key(struct gre_hdr *greh) | 95 | static inline __be32 *gre_key(struct gre_hdr *greh) |
96 | { | 96 | { |
97 | if (!greh->key) | 97 | if (!greh->key) |
98 | return NULL; | 98 | return NULL; |
99 | if (greh->csum || greh->routing) | 99 | if (greh->csum || greh->routing) |
100 | return (u_int32_t *) (greh+sizeof(*greh)+4); | 100 | return (__be32 *) (greh+sizeof(*greh)+4); |
101 | return (u_int32_t *) (greh+sizeof(*greh)); | 101 | return (__be32 *) (greh+sizeof(*greh)); |
102 | } | 102 | } |
103 | 103 | ||
104 | /* get pointer ot gre csum, if present */ | 104 | /* get pointer ot gre csum, if present */ |
diff --git a/include/linux/netfilter_ipv4/ip_nat.h b/include/linux/netfilter_ipv4/ip_nat.h index e9f5ed1d9f68..98f8407e4cb5 100644 --- a/include/linux/netfilter_ipv4/ip_nat.h +++ b/include/linux/netfilter_ipv4/ip_nat.h | |||
@@ -72,10 +72,6 @@ extern unsigned int ip_nat_setup_info(struct ip_conntrack *conntrack, | |||
72 | extern int ip_nat_used_tuple(const struct ip_conntrack_tuple *tuple, | 72 | extern int ip_nat_used_tuple(const struct ip_conntrack_tuple *tuple, |
73 | const struct ip_conntrack *ignored_conntrack); | 73 | const struct ip_conntrack *ignored_conntrack); |
74 | 74 | ||
75 | /* Calculate relative checksum. */ | ||
76 | extern u_int16_t ip_nat_cheat_check(u_int32_t oldvalinv, | ||
77 | u_int32_t newval, | ||
78 | u_int16_t oldcheck); | ||
79 | #else /* !__KERNEL__: iptables wants this to compile. */ | 75 | #else /* !__KERNEL__: iptables wants this to compile. */ |
80 | #define ip_nat_multi_range ip_nat_multi_range_compat | 76 | #define ip_nat_multi_range ip_nat_multi_range_compat |
81 | #endif /*__KERNEL__*/ | 77 | #endif /*__KERNEL__*/ |
diff --git a/include/linux/netfilter_ipv4/ip_nat_core.h b/include/linux/netfilter_ipv4/ip_nat_core.h index 30db23f06b03..60566f9fd7b3 100644 --- a/include/linux/netfilter_ipv4/ip_nat_core.h +++ b/include/linux/netfilter_ipv4/ip_nat_core.h | |||
@@ -11,8 +11,8 @@ extern unsigned int ip_nat_packet(struct ip_conntrack *ct, | |||
11 | unsigned int hooknum, | 11 | unsigned int hooknum, |
12 | struct sk_buff **pskb); | 12 | struct sk_buff **pskb); |
13 | 13 | ||
14 | extern int ip_nat_icmp_reply_translation(struct sk_buff **pskb, | 14 | extern int ip_nat_icmp_reply_translation(struct ip_conntrack *ct, |
15 | struct ip_conntrack *ct, | 15 | enum ip_conntrack_info ctinfo, |
16 | enum ip_nat_manip_type manip, | 16 | unsigned int hooknum, |
17 | enum ip_conntrack_dir dir); | 17 | struct sk_buff **pskb); |
18 | #endif /* _IP_NAT_CORE_H */ | 18 | #endif /* _IP_NAT_CORE_H */ |
diff --git a/include/linux/netfilter_ipv4/ip_nat_pptp.h b/include/linux/netfilter_ipv4/ip_nat_pptp.h index eaf66c2e8f93..36668bf0f373 100644 --- a/include/linux/netfilter_ipv4/ip_nat_pptp.h +++ b/include/linux/netfilter_ipv4/ip_nat_pptp.h | |||
@@ -4,8 +4,8 @@ | |||
4 | 4 | ||
5 | /* conntrack private data */ | 5 | /* conntrack private data */ |
6 | struct ip_nat_pptp { | 6 | struct ip_nat_pptp { |
7 | u_int16_t pns_call_id; /* NAT'ed PNS call id */ | 7 | __be16 pns_call_id; /* NAT'ed PNS call id */ |
8 | u_int16_t pac_call_id; /* NAT'ed PAC call id */ | 8 | __be16 pac_call_id; /* NAT'ed PAC call id */ |
9 | }; | 9 | }; |
10 | 10 | ||
11 | #endif /* _NAT_PPTP_H */ | 11 | #endif /* _NAT_PPTP_H */ |
diff --git a/include/linux/netfilter_ipv4/ip_tables.h b/include/linux/netfilter_ipv4/ip_tables.h index c0dac16e1902..a536bbdef145 100644 --- a/include/linux/netfilter_ipv4/ip_tables.h +++ b/include/linux/netfilter_ipv4/ip_tables.h | |||
@@ -312,8 +312,7 @@ extern unsigned int ipt_do_table(struct sk_buff **pskb, | |||
312 | unsigned int hook, | 312 | unsigned int hook, |
313 | const struct net_device *in, | 313 | const struct net_device *in, |
314 | const struct net_device *out, | 314 | const struct net_device *out, |
315 | struct ipt_table *table, | 315 | struct ipt_table *table); |
316 | void *userdata); | ||
317 | 316 | ||
318 | #define IPT_ALIGN(s) XT_ALIGN(s) | 317 | #define IPT_ALIGN(s) XT_ALIGN(s) |
319 | 318 | ||
diff --git a/include/linux/netfilter_ipv4/ipt_DSCP.h b/include/linux/netfilter_ipv4/ipt_DSCP.h index b30f510b5bef..3491e524d5ea 100644 --- a/include/linux/netfilter_ipv4/ipt_DSCP.h +++ b/include/linux/netfilter_ipv4/ipt_DSCP.h | |||
@@ -11,10 +11,8 @@ | |||
11 | #ifndef _IPT_DSCP_TARGET_H | 11 | #ifndef _IPT_DSCP_TARGET_H |
12 | #define _IPT_DSCP_TARGET_H | 12 | #define _IPT_DSCP_TARGET_H |
13 | #include <linux/netfilter_ipv4/ipt_dscp.h> | 13 | #include <linux/netfilter_ipv4/ipt_dscp.h> |
14 | #include <linux/netfilter/xt_DSCP.h> | ||
14 | 15 | ||
15 | /* target info */ | 16 | #define ipt_DSCP_info xt_DSCP_info |
16 | struct ipt_DSCP_info { | ||
17 | u_int8_t dscp; | ||
18 | }; | ||
19 | 17 | ||
20 | #endif /* _IPT_DSCP_TARGET_H */ | 18 | #endif /* _IPT_DSCP_TARGET_H */ |
diff --git a/include/linux/netfilter_ipv4/ipt_dscp.h b/include/linux/netfilter_ipv4/ipt_dscp.h index 2fa6dfe92894..4b82ca912b0e 100644 --- a/include/linux/netfilter_ipv4/ipt_dscp.h +++ b/include/linux/netfilter_ipv4/ipt_dscp.h | |||
@@ -10,14 +10,12 @@ | |||
10 | #ifndef _IPT_DSCP_H | 10 | #ifndef _IPT_DSCP_H |
11 | #define _IPT_DSCP_H | 11 | #define _IPT_DSCP_H |
12 | 12 | ||
13 | #define IPT_DSCP_MASK 0xfc /* 11111100 */ | 13 | #include <linux/netfilter/xt_dscp.h> |
14 | #define IPT_DSCP_SHIFT 2 | ||
15 | #define IPT_DSCP_MAX 0x3f /* 00111111 */ | ||
16 | 14 | ||
17 | /* match info */ | 15 | #define IPT_DSCP_MASK XT_DSCP_MASK |
18 | struct ipt_dscp_info { | 16 | #define IPT_DSCP_SHIFT XT_DSCP_SHIFT |
19 | u_int8_t dscp; | 17 | #define IPT_DSCP_MAX XT_DSCP_MAX |
20 | u_int8_t invert; | 18 | |
21 | }; | 19 | #define ipt_dscp_info xt_dscp_info |
22 | 20 | ||
23 | #endif /* _IPT_DSCP_H */ | 21 | #endif /* _IPT_DSCP_H */ |
diff --git a/include/linux/netfilter_ipv4/listhelp.h b/include/linux/netfilter_ipv4/listhelp.h deleted file mode 100644 index 5d92cf044d91..000000000000 --- a/include/linux/netfilter_ipv4/listhelp.h +++ /dev/null | |||
@@ -1,123 +0,0 @@ | |||
1 | #ifndef _LISTHELP_H | ||
2 | #define _LISTHELP_H | ||
3 | #include <linux/list.h> | ||
4 | |||
5 | /* Header to do more comprehensive job than linux/list.h; assume list | ||
6 | is first entry in structure. */ | ||
7 | |||
8 | /* Return pointer to first true entry, if any, or NULL. A macro | ||
9 | required to allow inlining of cmpfn. */ | ||
10 | #define LIST_FIND(head, cmpfn, type, args...) \ | ||
11 | ({ \ | ||
12 | const struct list_head *__i, *__j = NULL; \ | ||
13 | \ | ||
14 | ASSERT_READ_LOCK(head); \ | ||
15 | list_for_each(__i, (head)) \ | ||
16 | if (cmpfn((const type)__i , ## args)) { \ | ||
17 | __j = __i; \ | ||
18 | break; \ | ||
19 | } \ | ||
20 | (type)__j; \ | ||
21 | }) | ||
22 | |||
23 | #define LIST_FIND_W(head, cmpfn, type, args...) \ | ||
24 | ({ \ | ||
25 | const struct list_head *__i, *__j = NULL; \ | ||
26 | \ | ||
27 | ASSERT_WRITE_LOCK(head); \ | ||
28 | list_for_each(__i, (head)) \ | ||
29 | if (cmpfn((type)__i , ## args)) { \ | ||
30 | __j = __i; \ | ||
31 | break; \ | ||
32 | } \ | ||
33 | (type)__j; \ | ||
34 | }) | ||
35 | |||
36 | /* Just like LIST_FIND but we search backwards */ | ||
37 | #define LIST_FIND_B(head, cmpfn, type, args...) \ | ||
38 | ({ \ | ||
39 | const struct list_head *__i, *__j = NULL; \ | ||
40 | \ | ||
41 | ASSERT_READ_LOCK(head); \ | ||
42 | list_for_each_prev(__i, (head)) \ | ||
43 | if (cmpfn((const type)__i , ## args)) { \ | ||
44 | __j = __i; \ | ||
45 | break; \ | ||
46 | } \ | ||
47 | (type)__j; \ | ||
48 | }) | ||
49 | |||
50 | static inline int | ||
51 | __list_cmp_same(const void *p1, const void *p2) { return p1 == p2; } | ||
52 | |||
53 | /* Is this entry in the list? */ | ||
54 | static inline int | ||
55 | list_inlist(struct list_head *head, const void *entry) | ||
56 | { | ||
57 | return LIST_FIND(head, __list_cmp_same, void *, entry) != NULL; | ||
58 | } | ||
59 | |||
60 | /* Delete from list. */ | ||
61 | #ifdef CONFIG_NETFILTER_DEBUG | ||
62 | #define LIST_DELETE(head, oldentry) \ | ||
63 | do { \ | ||
64 | ASSERT_WRITE_LOCK(head); \ | ||
65 | if (!list_inlist(head, oldentry)) \ | ||
66 | printk("LIST_DELETE: %s:%u `%s'(%p) not in %s.\n", \ | ||
67 | __FILE__, __LINE__, #oldentry, oldentry, #head); \ | ||
68 | else list_del((struct list_head *)oldentry); \ | ||
69 | } while(0) | ||
70 | #else | ||
71 | #define LIST_DELETE(head, oldentry) list_del((struct list_head *)oldentry) | ||
72 | #endif | ||
73 | |||
74 | /* Append. */ | ||
75 | static inline void | ||
76 | list_append(struct list_head *head, void *new) | ||
77 | { | ||
78 | ASSERT_WRITE_LOCK(head); | ||
79 | list_add((new), (head)->prev); | ||
80 | } | ||
81 | |||
82 | /* Prepend. */ | ||
83 | static inline void | ||
84 | list_prepend(struct list_head *head, void *new) | ||
85 | { | ||
86 | ASSERT_WRITE_LOCK(head); | ||
87 | list_add(new, head); | ||
88 | } | ||
89 | |||
90 | /* Insert according to ordering function; insert before first true. */ | ||
91 | #define LIST_INSERT(head, new, cmpfn) \ | ||
92 | do { \ | ||
93 | struct list_head *__i; \ | ||
94 | ASSERT_WRITE_LOCK(head); \ | ||
95 | list_for_each(__i, (head)) \ | ||
96 | if ((new), (typeof (new))__i) \ | ||
97 | break; \ | ||
98 | list_add((struct list_head *)(new), __i->prev); \ | ||
99 | } while(0) | ||
100 | |||
101 | /* If the field after the list_head is a nul-terminated string, you | ||
102 | can use these functions. */ | ||
103 | static inline int __list_cmp_name(const void *i, const char *name) | ||
104 | { | ||
105 | return strcmp(name, i+sizeof(struct list_head)) == 0; | ||
106 | } | ||
107 | |||
108 | /* Returns false if same name already in list, otherwise does insert. */ | ||
109 | static inline int | ||
110 | list_named_insert(struct list_head *head, void *new) | ||
111 | { | ||
112 | if (LIST_FIND(head, __list_cmp_name, void *, | ||
113 | new + sizeof(struct list_head))) | ||
114 | return 0; | ||
115 | list_prepend(head, new); | ||
116 | return 1; | ||
117 | } | ||
118 | |||
119 | /* Find this named element in the list. */ | ||
120 | #define list_named_find(head, name) \ | ||
121 | LIST_FIND(head, __list_cmp_name, void *, name) | ||
122 | |||
123 | #endif /*_LISTHELP_H*/ | ||
diff --git a/include/linux/netfilter_ipv6.h b/include/linux/netfilter_ipv6.h index 52a7b9e76428..d97e268cdfe5 100644 --- a/include/linux/netfilter_ipv6.h +++ b/include/linux/netfilter_ipv6.h | |||
@@ -73,6 +73,7 @@ enum nf_ip6_hook_priorities { | |||
73 | }; | 73 | }; |
74 | 74 | ||
75 | #ifdef CONFIG_NETFILTER | 75 | #ifdef CONFIG_NETFILTER |
76 | extern int ip6_route_me_harder(struct sk_buff *skb); | ||
76 | extern unsigned int nf_ip6_checksum(struct sk_buff *skb, unsigned int hook, | 77 | extern unsigned int nf_ip6_checksum(struct sk_buff *skb, unsigned int hook, |
77 | unsigned int dataoff, u_int8_t protocol); | 78 | unsigned int dataoff, u_int8_t protocol); |
78 | 79 | ||
diff --git a/include/linux/netfilter_ipv6/ip6_tables.h b/include/linux/netfilter_ipv6/ip6_tables.h index d0d5d1ee4be3..d7a8e9c0dad0 100644 --- a/include/linux/netfilter_ipv6/ip6_tables.h +++ b/include/linux/netfilter_ipv6/ip6_tables.h | |||
@@ -300,8 +300,7 @@ extern unsigned int ip6t_do_table(struct sk_buff **pskb, | |||
300 | unsigned int hook, | 300 | unsigned int hook, |
301 | const struct net_device *in, | 301 | const struct net_device *in, |
302 | const struct net_device *out, | 302 | const struct net_device *out, |
303 | struct ip6t_table *table, | 303 | struct ip6t_table *table); |
304 | void *userdata); | ||
305 | 304 | ||
306 | /* Check for an extension */ | 305 | /* Check for an extension */ |
307 | extern int ip6t_ext_hdr(u8 nexthdr); | 306 | extern int ip6t_ext_hdr(u8 nexthdr); |
diff --git a/include/linux/netfilter_logging.h b/include/linux/netfilter_logging.h deleted file mode 100644 index 562bb6aad4e1..000000000000 --- a/include/linux/netfilter_logging.h +++ /dev/null | |||
@@ -1,33 +0,0 @@ | |||
1 | /* Internal logging interface, which relies on the real | ||
2 | LOG target modules */ | ||
3 | #ifndef __LINUX_NETFILTER_LOGGING_H | ||
4 | #define __LINUX_NETFILTER_LOGGING_H | ||
5 | |||
6 | #ifdef __KERNEL__ | ||
7 | #include <asm/atomic.h> | ||
8 | |||
9 | struct nf_logging_t { | ||
10 | void (*nf_log_packet)(struct sk_buff **pskb, | ||
11 | unsigned int hooknum, | ||
12 | const struct net_device *in, | ||
13 | const struct net_device *out, | ||
14 | const char *prefix); | ||
15 | void (*nf_log)(char *pfh, size_t len, | ||
16 | const char *prefix); | ||
17 | }; | ||
18 | |||
19 | extern void nf_log_register(int pf, const struct nf_logging_t *logging); | ||
20 | extern void nf_log_unregister(int pf, const struct nf_logging_t *logging); | ||
21 | |||
22 | extern void nf_log_packet(int pf, | ||
23 | struct sk_buff **pskb, | ||
24 | unsigned int hooknum, | ||
25 | const struct net_device *in, | ||
26 | const struct net_device *out, | ||
27 | const char *fmt, ...); | ||
28 | extern void nf_log(int pf, | ||
29 | char *pfh, size_t len, | ||
30 | const char *fmt, ...); | ||
31 | #endif /*__KERNEL__*/ | ||
32 | |||
33 | #endif /*__LINUX_NETFILTER_LOGGING_H*/ | ||
diff --git a/include/linux/nfs_fs.h b/include/linux/nfs_fs.h index 6c2066caeaab..3b5b04193fee 100644 --- a/include/linux/nfs_fs.h +++ b/include/linux/nfs_fs.h | |||
@@ -42,6 +42,7 @@ | |||
42 | #include <linux/in.h> | 42 | #include <linux/in.h> |
43 | #include <linux/mm.h> | 43 | #include <linux/mm.h> |
44 | #include <linux/pagemap.h> | 44 | #include <linux/pagemap.h> |
45 | #include <linux/rbtree.h> | ||
45 | #include <linux/rwsem.h> | 46 | #include <linux/rwsem.h> |
46 | #include <linux/wait.h> | 47 | #include <linux/wait.h> |
47 | 48 | ||
@@ -69,6 +70,8 @@ | |||
69 | * NFSv3/v4 Access mode cache entry | 70 | * NFSv3/v4 Access mode cache entry |
70 | */ | 71 | */ |
71 | struct nfs_access_entry { | 72 | struct nfs_access_entry { |
73 | struct rb_node rb_node; | ||
74 | struct list_head lru; | ||
72 | unsigned long jiffies; | 75 | unsigned long jiffies; |
73 | struct rpc_cred * cred; | 76 | struct rpc_cred * cred; |
74 | int mask; | 77 | int mask; |
@@ -145,7 +148,9 @@ struct nfs_inode { | |||
145 | */ | 148 | */ |
146 | atomic_t data_updates; | 149 | atomic_t data_updates; |
147 | 150 | ||
148 | struct nfs_access_entry cache_access; | 151 | struct rb_root access_cache; |
152 | struct list_head access_cache_entry_lru; | ||
153 | struct list_head access_cache_inode_lru; | ||
149 | #ifdef CONFIG_NFS_V3_ACL | 154 | #ifdef CONFIG_NFS_V3_ACL |
150 | struct posix_acl *acl_access; | 155 | struct posix_acl *acl_access; |
151 | struct posix_acl *acl_default; | 156 | struct posix_acl *acl_default; |
@@ -199,6 +204,7 @@ struct nfs_inode { | |||
199 | #define NFS_INO_REVALIDATING (0) /* revalidating attrs */ | 204 | #define NFS_INO_REVALIDATING (0) /* revalidating attrs */ |
200 | #define NFS_INO_ADVISE_RDPLUS (1) /* advise readdirplus */ | 205 | #define NFS_INO_ADVISE_RDPLUS (1) /* advise readdirplus */ |
201 | #define NFS_INO_STALE (2) /* possible stale inode */ | 206 | #define NFS_INO_STALE (2) /* possible stale inode */ |
207 | #define NFS_INO_ACL_LRU_SET (3) /* Inode is on the LRU list */ | ||
202 | 208 | ||
203 | static inline struct nfs_inode *NFS_I(struct inode *inode) | 209 | static inline struct nfs_inode *NFS_I(struct inode *inode) |
204 | { | 210 | { |
@@ -209,8 +215,7 @@ static inline struct nfs_inode *NFS_I(struct inode *inode) | |||
209 | #define NFS_FH(inode) (&NFS_I(inode)->fh) | 215 | #define NFS_FH(inode) (&NFS_I(inode)->fh) |
210 | #define NFS_SERVER(inode) (NFS_SB(inode->i_sb)) | 216 | #define NFS_SERVER(inode) (NFS_SB(inode->i_sb)) |
211 | #define NFS_CLIENT(inode) (NFS_SERVER(inode)->client) | 217 | #define NFS_CLIENT(inode) (NFS_SERVER(inode)->client) |
212 | #define NFS_PROTO(inode) (NFS_SERVER(inode)->rpc_ops) | 218 | #define NFS_PROTO(inode) (NFS_SERVER(inode)->nfs_client->rpc_ops) |
213 | #define NFS_ADDR(inode) (RPC_PEERADDR(NFS_CLIENT(inode))) | ||
214 | #define NFS_COOKIEVERF(inode) (NFS_I(inode)->cookieverf) | 219 | #define NFS_COOKIEVERF(inode) (NFS_I(inode)->cookieverf) |
215 | #define NFS_READTIME(inode) (NFS_I(inode)->read_cache_jiffies) | 220 | #define NFS_READTIME(inode) (NFS_I(inode)->read_cache_jiffies) |
216 | #define NFS_CHANGE_ATTR(inode) (NFS_I(inode)->change_attr) | 221 | #define NFS_CHANGE_ATTR(inode) (NFS_I(inode)->change_attr) |
@@ -297,6 +302,7 @@ extern int nfs_getattr(struct vfsmount *, struct dentry *, struct kstat *); | |||
297 | extern int nfs_permission(struct inode *, int, struct nameidata *); | 302 | extern int nfs_permission(struct inode *, int, struct nameidata *); |
298 | extern int nfs_access_get_cached(struct inode *, struct rpc_cred *, struct nfs_access_entry *); | 303 | extern int nfs_access_get_cached(struct inode *, struct rpc_cred *, struct nfs_access_entry *); |
299 | extern void nfs_access_add_cache(struct inode *, struct nfs_access_entry *); | 304 | extern void nfs_access_add_cache(struct inode *, struct nfs_access_entry *); |
305 | extern void nfs_access_zap_cache(struct inode *inode); | ||
300 | extern int nfs_open(struct inode *, struct file *); | 306 | extern int nfs_open(struct inode *, struct file *); |
301 | extern int nfs_release(struct inode *, struct file *); | 307 | extern int nfs_release(struct inode *, struct file *); |
302 | extern int nfs_attribute_timeout(struct inode *inode); | 308 | extern int nfs_attribute_timeout(struct inode *inode); |
@@ -579,6 +585,7 @@ extern void * nfs_root_data(void); | |||
579 | #define NFSDBG_FILE 0x0040 | 585 | #define NFSDBG_FILE 0x0040 |
580 | #define NFSDBG_ROOT 0x0080 | 586 | #define NFSDBG_ROOT 0x0080 |
581 | #define NFSDBG_CALLBACK 0x0100 | 587 | #define NFSDBG_CALLBACK 0x0100 |
588 | #define NFSDBG_CLIENT 0x0200 | ||
582 | #define NFSDBG_ALL 0xFFFF | 589 | #define NFSDBG_ALL 0xFFFF |
583 | 590 | ||
584 | #ifdef __KERNEL__ | 591 | #ifdef __KERNEL__ |
diff --git a/include/linux/nfs_fs_sb.h b/include/linux/nfs_fs_sb.h index 6b4a13c79474..7ccfc7ef0a83 100644 --- a/include/linux/nfs_fs_sb.h +++ b/include/linux/nfs_fs_sb.h | |||
@@ -7,13 +7,79 @@ | |||
7 | struct nfs_iostats; | 7 | struct nfs_iostats; |
8 | 8 | ||
9 | /* | 9 | /* |
10 | * The nfs_client identifies our client state to the server. | ||
11 | */ | ||
12 | struct nfs_client { | ||
13 | atomic_t cl_count; | ||
14 | int cl_cons_state; /* current construction state (-ve: init error) */ | ||
15 | #define NFS_CS_READY 0 /* ready to be used */ | ||
16 | #define NFS_CS_INITING 1 /* busy initialising */ | ||
17 | int cl_nfsversion; /* NFS protocol version */ | ||
18 | unsigned long cl_res_state; /* NFS resources state */ | ||
19 | #define NFS_CS_RPCIOD 0 /* - rpciod started */ | ||
20 | #define NFS_CS_CALLBACK 1 /* - callback started */ | ||
21 | #define NFS_CS_IDMAP 2 /* - idmap started */ | ||
22 | #define NFS_CS_RENEWD 3 /* - renewd started */ | ||
23 | struct sockaddr_in cl_addr; /* server identifier */ | ||
24 | char * cl_hostname; /* hostname of server */ | ||
25 | struct list_head cl_share_link; /* link in global client list */ | ||
26 | struct list_head cl_superblocks; /* List of nfs_server structs */ | ||
27 | |||
28 | struct rpc_clnt * cl_rpcclient; | ||
29 | const struct nfs_rpc_ops *rpc_ops; /* NFS protocol vector */ | ||
30 | unsigned long retrans_timeo; /* retransmit timeout */ | ||
31 | unsigned int retrans_count; /* number of retransmit tries */ | ||
32 | |||
33 | #ifdef CONFIG_NFS_V4 | ||
34 | u64 cl_clientid; /* constant */ | ||
35 | nfs4_verifier cl_confirm; | ||
36 | unsigned long cl_state; | ||
37 | |||
38 | u32 cl_lockowner_id; | ||
39 | |||
40 | /* | ||
41 | * The following rwsem ensures exclusive access to the server | ||
42 | * while we recover the state following a lease expiration. | ||
43 | */ | ||
44 | struct rw_semaphore cl_sem; | ||
45 | |||
46 | struct list_head cl_delegations; | ||
47 | struct list_head cl_state_owners; | ||
48 | struct list_head cl_unused; | ||
49 | int cl_nunused; | ||
50 | spinlock_t cl_lock; | ||
51 | |||
52 | unsigned long cl_lease_time; | ||
53 | unsigned long cl_last_renewal; | ||
54 | struct work_struct cl_renewd; | ||
55 | |||
56 | struct rpc_wait_queue cl_rpcwaitq; | ||
57 | |||
58 | /* used for the setclientid verifier */ | ||
59 | struct timespec cl_boot_time; | ||
60 | |||
61 | /* idmapper */ | ||
62 | struct idmap * cl_idmap; | ||
63 | |||
64 | /* Our own IP address, as a null-terminated string. | ||
65 | * This is used to generate the clientid, and the callback address. | ||
66 | */ | ||
67 | char cl_ipaddr[16]; | ||
68 | unsigned char cl_id_uniquifier; | ||
69 | #endif | ||
70 | }; | ||
71 | |||
72 | /* | ||
10 | * NFS client parameters stored in the superblock. | 73 | * NFS client parameters stored in the superblock. |
11 | */ | 74 | */ |
12 | struct nfs_server { | 75 | struct nfs_server { |
76 | struct nfs_client * nfs_client; /* shared client and NFS4 state */ | ||
77 | struct list_head client_link; /* List of other nfs_server structs | ||
78 | * that share the same client | ||
79 | */ | ||
80 | struct list_head master_link; /* link in master servers list */ | ||
13 | struct rpc_clnt * client; /* RPC client handle */ | 81 | struct rpc_clnt * client; /* RPC client handle */ |
14 | struct rpc_clnt * client_sys; /* 2nd handle for FSINFO */ | ||
15 | struct rpc_clnt * client_acl; /* ACL RPC client handle */ | 82 | struct rpc_clnt * client_acl; /* ACL RPC client handle */ |
16 | struct nfs_rpc_ops * rpc_ops; /* NFS protocol vector */ | ||
17 | struct nfs_iostats * io_stats; /* I/O statistics */ | 83 | struct nfs_iostats * io_stats; /* I/O statistics */ |
18 | struct backing_dev_info backing_dev_info; | 84 | struct backing_dev_info backing_dev_info; |
19 | int flags; /* various flags */ | 85 | int flags; /* various flags */ |
@@ -29,24 +95,14 @@ struct nfs_server { | |||
29 | unsigned int acregmax; | 95 | unsigned int acregmax; |
30 | unsigned int acdirmin; | 96 | unsigned int acdirmin; |
31 | unsigned int acdirmax; | 97 | unsigned int acdirmax; |
32 | unsigned long retrans_timeo; /* retransmit timeout */ | ||
33 | unsigned int retrans_count; /* number of retransmit tries */ | ||
34 | unsigned int namelen; | 98 | unsigned int namelen; |
35 | char * hostname; /* remote hostname */ | 99 | |
36 | struct nfs_fh fh; | ||
37 | struct sockaddr_in addr; | ||
38 | struct nfs_fsid fsid; | 100 | struct nfs_fsid fsid; |
101 | __u64 maxfilesize; /* maximum file size */ | ||
39 | unsigned long mount_time; /* when this fs was mounted */ | 102 | unsigned long mount_time; /* when this fs was mounted */ |
103 | dev_t s_dev; /* superblock dev numbers */ | ||
104 | |||
40 | #ifdef CONFIG_NFS_V4 | 105 | #ifdef CONFIG_NFS_V4 |
41 | /* Our own IP address, as a null-terminated string. | ||
42 | * This is used to generate the clientid, and the callback address. | ||
43 | */ | ||
44 | char ip_addr[16]; | ||
45 | char * mnt_path; | ||
46 | struct nfs4_client * nfs4_state; /* all NFSv4 state starts here */ | ||
47 | struct list_head nfs4_siblings; /* List of other nfs_server structs | ||
48 | * that share the same clientid | ||
49 | */ | ||
50 | u32 attr_bitmask[2];/* V4 bitmask representing the set | 106 | u32 attr_bitmask[2];/* V4 bitmask representing the set |
51 | of attributes supported on this | 107 | of attributes supported on this |
52 | filesystem */ | 108 | filesystem */ |
@@ -54,6 +110,7 @@ struct nfs_server { | |||
54 | that are supported on this | 110 | that are supported on this |
55 | filesystem */ | 111 | filesystem */ |
56 | #endif | 112 | #endif |
113 | void (*destroy)(struct nfs_server *); | ||
57 | }; | 114 | }; |
58 | 115 | ||
59 | /* Server capabilities */ | 116 | /* Server capabilities */ |
diff --git a/include/linux/nfs_idmap.h b/include/linux/nfs_idmap.h index 102e56094296..15a9f3b7289a 100644 --- a/include/linux/nfs_idmap.h +++ b/include/linux/nfs_idmap.h | |||
@@ -62,15 +62,15 @@ struct idmap_msg { | |||
62 | #ifdef __KERNEL__ | 62 | #ifdef __KERNEL__ |
63 | 63 | ||
64 | /* Forward declaration to make this header independent of others */ | 64 | /* Forward declaration to make this header independent of others */ |
65 | struct nfs4_client; | 65 | struct nfs_client; |
66 | 66 | ||
67 | void nfs_idmap_new(struct nfs4_client *); | 67 | int nfs_idmap_new(struct nfs_client *); |
68 | void nfs_idmap_delete(struct nfs4_client *); | 68 | void nfs_idmap_delete(struct nfs_client *); |
69 | 69 | ||
70 | int nfs_map_name_to_uid(struct nfs4_client *, const char *, size_t, __u32 *); | 70 | int nfs_map_name_to_uid(struct nfs_client *, const char *, size_t, __u32 *); |
71 | int nfs_map_group_to_gid(struct nfs4_client *, const char *, size_t, __u32 *); | 71 | int nfs_map_group_to_gid(struct nfs_client *, const char *, size_t, __u32 *); |
72 | int nfs_map_uid_to_name(struct nfs4_client *, __u32, char *); | 72 | int nfs_map_uid_to_name(struct nfs_client *, __u32, char *); |
73 | int nfs_map_gid_to_group(struct nfs4_client *, __u32, char *); | 73 | int nfs_map_gid_to_group(struct nfs_client *, __u32, char *); |
74 | 74 | ||
75 | extern unsigned int nfs_idmap_cache_timeout; | 75 | extern unsigned int nfs_idmap_cache_timeout; |
76 | #endif /* __KERNEL__ */ | 76 | #endif /* __KERNEL__ */ |
diff --git a/include/linux/nfs_xdr.h b/include/linux/nfs_xdr.h index 41e5a19199e9..dc5397d9d23c 100644 --- a/include/linux/nfs_xdr.h +++ b/include/linux/nfs_xdr.h | |||
@@ -1,7 +1,6 @@ | |||
1 | #ifndef _LINUX_NFS_XDR_H | 1 | #ifndef _LINUX_NFS_XDR_H |
2 | #define _LINUX_NFS_XDR_H | 2 | #define _LINUX_NFS_XDR_H |
3 | 3 | ||
4 | #include <linux/sunrpc/xprt.h> | ||
5 | #include <linux/nfsacl.h> | 4 | #include <linux/nfsacl.h> |
6 | 5 | ||
7 | /* | 6 | /* |
@@ -359,8 +358,8 @@ struct nfs_symlinkargs { | |||
359 | struct nfs_fh * fromfh; | 358 | struct nfs_fh * fromfh; |
360 | const char * fromname; | 359 | const char * fromname; |
361 | unsigned int fromlen; | 360 | unsigned int fromlen; |
362 | const char * topath; | 361 | struct page ** pages; |
363 | unsigned int tolen; | 362 | unsigned int pathlen; |
364 | struct iattr * sattr; | 363 | struct iattr * sattr; |
365 | }; | 364 | }; |
366 | 365 | ||
@@ -435,8 +434,8 @@ struct nfs3_symlinkargs { | |||
435 | struct nfs_fh * fromfh; | 434 | struct nfs_fh * fromfh; |
436 | const char * fromname; | 435 | const char * fromname; |
437 | unsigned int fromlen; | 436 | unsigned int fromlen; |
438 | const char * topath; | 437 | struct page ** pages; |
439 | unsigned int tolen; | 438 | unsigned int pathlen; |
440 | struct iattr * sattr; | 439 | struct iattr * sattr; |
441 | }; | 440 | }; |
442 | 441 | ||
@@ -534,7 +533,10 @@ struct nfs4_accessres { | |||
534 | struct nfs4_create_arg { | 533 | struct nfs4_create_arg { |
535 | u32 ftype; | 534 | u32 ftype; |
536 | union { | 535 | union { |
537 | struct qstr * symlink; /* NF4LNK */ | 536 | struct { |
537 | struct page ** pages; | ||
538 | unsigned int len; | ||
539 | } symlink; /* NF4LNK */ | ||
538 | struct { | 540 | struct { |
539 | u32 specdata1; | 541 | u32 specdata1; |
540 | u32 specdata2; | 542 | u32 specdata2; |
@@ -770,6 +772,9 @@ struct nfs_rpc_ops { | |||
770 | 772 | ||
771 | int (*getroot) (struct nfs_server *, struct nfs_fh *, | 773 | int (*getroot) (struct nfs_server *, struct nfs_fh *, |
772 | struct nfs_fsinfo *); | 774 | struct nfs_fsinfo *); |
775 | int (*lookupfh)(struct nfs_server *, struct nfs_fh *, | ||
776 | struct qstr *, struct nfs_fh *, | ||
777 | struct nfs_fattr *); | ||
773 | int (*getattr) (struct nfs_server *, struct nfs_fh *, | 778 | int (*getattr) (struct nfs_server *, struct nfs_fh *, |
774 | struct nfs_fattr *); | 779 | struct nfs_fattr *); |
775 | int (*setattr) (struct dentry *, struct nfs_fattr *, | 780 | int (*setattr) (struct dentry *, struct nfs_fattr *, |
@@ -791,9 +796,8 @@ struct nfs_rpc_ops { | |||
791 | int (*rename) (struct inode *, struct qstr *, | 796 | int (*rename) (struct inode *, struct qstr *, |
792 | struct inode *, struct qstr *); | 797 | struct inode *, struct qstr *); |
793 | int (*link) (struct inode *, struct inode *, struct qstr *); | 798 | int (*link) (struct inode *, struct inode *, struct qstr *); |
794 | int (*symlink) (struct inode *, struct qstr *, struct qstr *, | 799 | int (*symlink) (struct inode *, struct dentry *, struct page *, |
795 | struct iattr *, struct nfs_fh *, | 800 | unsigned int, struct iattr *); |
796 | struct nfs_fattr *); | ||
797 | int (*mkdir) (struct inode *, struct dentry *, struct iattr *); | 801 | int (*mkdir) (struct inode *, struct dentry *, struct iattr *); |
798 | int (*rmdir) (struct inode *, struct qstr *); | 802 | int (*rmdir) (struct inode *, struct qstr *); |
799 | int (*readdir) (struct dentry *, struct rpc_cred *, | 803 | int (*readdir) (struct dentry *, struct rpc_cred *, |
@@ -806,6 +810,7 @@ struct nfs_rpc_ops { | |||
806 | struct nfs_fsinfo *); | 810 | struct nfs_fsinfo *); |
807 | int (*pathconf) (struct nfs_server *, struct nfs_fh *, | 811 | int (*pathconf) (struct nfs_server *, struct nfs_fh *, |
808 | struct nfs_pathconf *); | 812 | struct nfs_pathconf *); |
813 | int (*set_capabilities)(struct nfs_server *, struct nfs_fh *); | ||
809 | u32 * (*decode_dirent)(u32 *, struct nfs_entry *, int plus); | 814 | u32 * (*decode_dirent)(u32 *, struct nfs_entry *, int plus); |
810 | void (*read_setup) (struct nfs_read_data *); | 815 | void (*read_setup) (struct nfs_read_data *); |
811 | int (*read_done) (struct rpc_task *, struct nfs_read_data *); | 816 | int (*read_done) (struct rpc_task *, struct nfs_read_data *); |
@@ -829,9 +834,9 @@ struct nfs_rpc_ops { | |||
829 | /* | 834 | /* |
830 | * Function vectors etc. for the NFS client | 835 | * Function vectors etc. for the NFS client |
831 | */ | 836 | */ |
832 | extern struct nfs_rpc_ops nfs_v2_clientops; | 837 | extern const struct nfs_rpc_ops nfs_v2_clientops; |
833 | extern struct nfs_rpc_ops nfs_v3_clientops; | 838 | extern const struct nfs_rpc_ops nfs_v3_clientops; |
834 | extern struct nfs_rpc_ops nfs_v4_clientops; | 839 | extern const struct nfs_rpc_ops nfs_v4_clientops; |
835 | extern struct rpc_version nfs_version2; | 840 | extern struct rpc_version nfs_version2; |
836 | extern struct rpc_version nfs_version3; | 841 | extern struct rpc_version nfs_version3; |
837 | extern struct rpc_version nfs_version4; | 842 | extern struct rpc_version nfs_version4; |
diff --git a/include/linux/pkt_cls.h b/include/linux/pkt_cls.h index bd2c5a2bbbf5..c3f01b3085a4 100644 --- a/include/linux/pkt_cls.h +++ b/include/linux/pkt_cls.h | |||
@@ -305,6 +305,7 @@ enum | |||
305 | TCA_FW_POLICE, | 305 | TCA_FW_POLICE, |
306 | TCA_FW_INDEV, /* used by CONFIG_NET_CLS_IND */ | 306 | TCA_FW_INDEV, /* used by CONFIG_NET_CLS_IND */ |
307 | TCA_FW_ACT, /* used by CONFIG_NET_CLS_ACT */ | 307 | TCA_FW_ACT, /* used by CONFIG_NET_CLS_ACT */ |
308 | TCA_FW_MASK, | ||
308 | __TCA_FW_MAX | 309 | __TCA_FW_MAX |
309 | }; | 310 | }; |
310 | 311 | ||
diff --git a/include/linux/rtnetlink.h b/include/linux/rtnetlink.h index facd9ee37b76..9c92dc8b9a08 100644 --- a/include/linux/rtnetlink.h +++ b/include/linux/rtnetlink.h | |||
@@ -2,6 +2,7 @@ | |||
2 | #define __LINUX_RTNETLINK_H | 2 | #define __LINUX_RTNETLINK_H |
3 | 3 | ||
4 | #include <linux/netlink.h> | 4 | #include <linux/netlink.h> |
5 | #include <linux/if.h> | ||
5 | 6 | ||
6 | /**** | 7 | /**** |
7 | * Routing/neighbour discovery messages. | 8 | * Routing/neighbour discovery messages. |
@@ -238,10 +239,8 @@ enum rt_class_t | |||
238 | RT_TABLE_DEFAULT=253, | 239 | RT_TABLE_DEFAULT=253, |
239 | RT_TABLE_MAIN=254, | 240 | RT_TABLE_MAIN=254, |
240 | RT_TABLE_LOCAL=255, | 241 | RT_TABLE_LOCAL=255, |
241 | __RT_TABLE_MAX | 242 | RT_TABLE_MAX=0xFFFFFFFF |
242 | }; | 243 | }; |
243 | #define RT_TABLE_MAX (__RT_TABLE_MAX - 1) | ||
244 | |||
245 | 244 | ||
246 | 245 | ||
247 | /* Routing message attributes */ | 246 | /* Routing message attributes */ |
@@ -263,6 +262,7 @@ enum rtattr_type_t | |||
263 | RTA_CACHEINFO, | 262 | RTA_CACHEINFO, |
264 | RTA_SESSION, | 263 | RTA_SESSION, |
265 | RTA_MP_ALGO, | 264 | RTA_MP_ALGO, |
265 | RTA_TABLE, | ||
266 | __RTA_MAX | 266 | __RTA_MAX |
267 | }; | 267 | }; |
268 | 268 | ||
@@ -383,226 +383,6 @@ struct rta_session | |||
383 | } u; | 383 | } u; |
384 | }; | 384 | }; |
385 | 385 | ||
386 | |||
387 | /********************************************************* | ||
388 | * Interface address. | ||
389 | ****/ | ||
390 | |||
391 | struct ifaddrmsg | ||
392 | { | ||
393 | unsigned char ifa_family; | ||
394 | unsigned char ifa_prefixlen; /* The prefix length */ | ||
395 | unsigned char ifa_flags; /* Flags */ | ||
396 | unsigned char ifa_scope; /* See above */ | ||
397 | int ifa_index; /* Link index */ | ||
398 | }; | ||
399 | |||
400 | enum | ||
401 | { | ||
402 | IFA_UNSPEC, | ||
403 | IFA_ADDRESS, | ||
404 | IFA_LOCAL, | ||
405 | IFA_LABEL, | ||
406 | IFA_BROADCAST, | ||
407 | IFA_ANYCAST, | ||
408 | IFA_CACHEINFO, | ||
409 | IFA_MULTICAST, | ||
410 | __IFA_MAX | ||
411 | }; | ||
412 | |||
413 | #define IFA_MAX (__IFA_MAX - 1) | ||
414 | |||
415 | /* ifa_flags */ | ||
416 | |||
417 | #define IFA_F_SECONDARY 0x01 | ||
418 | #define IFA_F_TEMPORARY IFA_F_SECONDARY | ||
419 | |||
420 | #define IFA_F_DEPRECATED 0x20 | ||
421 | #define IFA_F_TENTATIVE 0x40 | ||
422 | #define IFA_F_PERMANENT 0x80 | ||
423 | |||
424 | struct ifa_cacheinfo | ||
425 | { | ||
426 | __u32 ifa_prefered; | ||
427 | __u32 ifa_valid; | ||
428 | __u32 cstamp; /* created timestamp, hundredths of seconds */ | ||
429 | __u32 tstamp; /* updated timestamp, hundredths of seconds */ | ||
430 | }; | ||
431 | |||
432 | |||
433 | #define IFA_RTA(r) ((struct rtattr*)(((char*)(r)) + NLMSG_ALIGN(sizeof(struct ifaddrmsg)))) | ||
434 | #define IFA_PAYLOAD(n) NLMSG_PAYLOAD(n,sizeof(struct ifaddrmsg)) | ||
435 | |||
436 | /* | ||
437 | Important comment: | ||
438 | IFA_ADDRESS is prefix address, rather than local interface address. | ||
439 | It makes no difference for normally configured broadcast interfaces, | ||
440 | but for point-to-point IFA_ADDRESS is DESTINATION address, | ||
441 | local address is supplied in IFA_LOCAL attribute. | ||
442 | */ | ||
443 | |||
444 | /************************************************************** | ||
445 | * Neighbour discovery. | ||
446 | ****/ | ||
447 | |||
448 | struct ndmsg | ||
449 | { | ||
450 | unsigned char ndm_family; | ||
451 | unsigned char ndm_pad1; | ||
452 | unsigned short ndm_pad2; | ||
453 | int ndm_ifindex; /* Link index */ | ||
454 | __u16 ndm_state; | ||
455 | __u8 ndm_flags; | ||
456 | __u8 ndm_type; | ||
457 | }; | ||
458 | |||
459 | enum | ||
460 | { | ||
461 | NDA_UNSPEC, | ||
462 | NDA_DST, | ||
463 | NDA_LLADDR, | ||
464 | NDA_CACHEINFO, | ||
465 | NDA_PROBES, | ||
466 | __NDA_MAX | ||
467 | }; | ||
468 | |||
469 | #define NDA_MAX (__NDA_MAX - 1) | ||
470 | |||
471 | #define NDA_RTA(r) ((struct rtattr*)(((char*)(r)) + NLMSG_ALIGN(sizeof(struct ndmsg)))) | ||
472 | #define NDA_PAYLOAD(n) NLMSG_PAYLOAD(n,sizeof(struct ndmsg)) | ||
473 | |||
474 | /* | ||
475 | * Neighbor Cache Entry Flags | ||
476 | */ | ||
477 | |||
478 | #define NTF_PROXY 0x08 /* == ATF_PUBL */ | ||
479 | #define NTF_ROUTER 0x80 | ||
480 | |||
481 | /* | ||
482 | * Neighbor Cache Entry States. | ||
483 | */ | ||
484 | |||
485 | #define NUD_INCOMPLETE 0x01 | ||
486 | #define NUD_REACHABLE 0x02 | ||
487 | #define NUD_STALE 0x04 | ||
488 | #define NUD_DELAY 0x08 | ||
489 | #define NUD_PROBE 0x10 | ||
490 | #define NUD_FAILED 0x20 | ||
491 | |||
492 | /* Dummy states */ | ||
493 | #define NUD_NOARP 0x40 | ||
494 | #define NUD_PERMANENT 0x80 | ||
495 | #define NUD_NONE 0x00 | ||
496 | |||
497 | |||
498 | struct nda_cacheinfo | ||
499 | { | ||
500 | __u32 ndm_confirmed; | ||
501 | __u32 ndm_used; | ||
502 | __u32 ndm_updated; | ||
503 | __u32 ndm_refcnt; | ||
504 | }; | ||
505 | |||
506 | |||
507 | /***************************************************************** | ||
508 | * Neighbour tables specific messages. | ||
509 | * | ||
510 | * To retrieve the neighbour tables send RTM_GETNEIGHTBL with the | ||
511 | * NLM_F_DUMP flag set. Every neighbour table configuration is | ||
512 | * spread over multiple messages to avoid running into message | ||
513 | * size limits on systems with many interfaces. The first message | ||
514 | * in the sequence transports all not device specific data such as | ||
515 | * statistics, configuration, and the default parameter set. | ||
516 | * This message is followed by 0..n messages carrying device | ||
517 | * specific parameter sets. | ||
518 | * Although the ordering should be sufficient, NDTA_NAME can be | ||
519 | * used to identify sequences. The initial message can be identified | ||
520 | * by checking for NDTA_CONFIG. The device specific messages do | ||
521 | * not contain this TLV but have NDTPA_IFINDEX set to the | ||
522 | * corresponding interface index. | ||
523 | * | ||
524 | * To change neighbour table attributes, send RTM_SETNEIGHTBL | ||
525 | * with NDTA_NAME set. Changeable attribute include NDTA_THRESH[1-3], | ||
526 | * NDTA_GC_INTERVAL, and all TLVs in NDTA_PARMS unless marked | ||
527 | * otherwise. Device specific parameter sets can be changed by | ||
528 | * setting NDTPA_IFINDEX to the interface index of the corresponding | ||
529 | * device. | ||
530 | ****/ | ||
531 | |||
532 | struct ndt_stats | ||
533 | { | ||
534 | __u64 ndts_allocs; | ||
535 | __u64 ndts_destroys; | ||
536 | __u64 ndts_hash_grows; | ||
537 | __u64 ndts_res_failed; | ||
538 | __u64 ndts_lookups; | ||
539 | __u64 ndts_hits; | ||
540 | __u64 ndts_rcv_probes_mcast; | ||
541 | __u64 ndts_rcv_probes_ucast; | ||
542 | __u64 ndts_periodic_gc_runs; | ||
543 | __u64 ndts_forced_gc_runs; | ||
544 | }; | ||
545 | |||
546 | enum { | ||
547 | NDTPA_UNSPEC, | ||
548 | NDTPA_IFINDEX, /* u32, unchangeable */ | ||
549 | NDTPA_REFCNT, /* u32, read-only */ | ||
550 | NDTPA_REACHABLE_TIME, /* u64, read-only, msecs */ | ||
551 | NDTPA_BASE_REACHABLE_TIME, /* u64, msecs */ | ||
552 | NDTPA_RETRANS_TIME, /* u64, msecs */ | ||
553 | NDTPA_GC_STALETIME, /* u64, msecs */ | ||
554 | NDTPA_DELAY_PROBE_TIME, /* u64, msecs */ | ||
555 | NDTPA_QUEUE_LEN, /* u32 */ | ||
556 | NDTPA_APP_PROBES, /* u32 */ | ||
557 | NDTPA_UCAST_PROBES, /* u32 */ | ||
558 | NDTPA_MCAST_PROBES, /* u32 */ | ||
559 | NDTPA_ANYCAST_DELAY, /* u64, msecs */ | ||
560 | NDTPA_PROXY_DELAY, /* u64, msecs */ | ||
561 | NDTPA_PROXY_QLEN, /* u32 */ | ||
562 | NDTPA_LOCKTIME, /* u64, msecs */ | ||
563 | __NDTPA_MAX | ||
564 | }; | ||
565 | #define NDTPA_MAX (__NDTPA_MAX - 1) | ||
566 | |||
567 | struct ndtmsg | ||
568 | { | ||
569 | __u8 ndtm_family; | ||
570 | __u8 ndtm_pad1; | ||
571 | __u16 ndtm_pad2; | ||
572 | }; | ||
573 | |||
574 | struct ndt_config | ||
575 | { | ||
576 | __u16 ndtc_key_len; | ||
577 | __u16 ndtc_entry_size; | ||
578 | __u32 ndtc_entries; | ||
579 | __u32 ndtc_last_flush; /* delta to now in msecs */ | ||
580 | __u32 ndtc_last_rand; /* delta to now in msecs */ | ||
581 | __u32 ndtc_hash_rnd; | ||
582 | __u32 ndtc_hash_mask; | ||
583 | __u32 ndtc_hash_chain_gc; | ||
584 | __u32 ndtc_proxy_qlen; | ||
585 | }; | ||
586 | |||
587 | enum { | ||
588 | NDTA_UNSPEC, | ||
589 | NDTA_NAME, /* char *, unchangeable */ | ||
590 | NDTA_THRESH1, /* u32 */ | ||
591 | NDTA_THRESH2, /* u32 */ | ||
592 | NDTA_THRESH3, /* u32 */ | ||
593 | NDTA_CONFIG, /* struct ndt_config, read-only */ | ||
594 | NDTA_PARMS, /* nested TLV NDTPA_* */ | ||
595 | NDTA_STATS, /* struct ndt_stats, read-only */ | ||
596 | NDTA_GC_INTERVAL, /* u64, msecs */ | ||
597 | __NDTA_MAX | ||
598 | }; | ||
599 | #define NDTA_MAX (__NDTA_MAX - 1) | ||
600 | |||
601 | #define NDTA_RTA(r) ((struct rtattr*)(((char*)(r)) + \ | ||
602 | NLMSG_ALIGN(sizeof(struct ndtmsg)))) | ||
603 | #define NDTA_PAYLOAD(n) NLMSG_PAYLOAD(n,sizeof(struct ndtmsg)) | ||
604 | |||
605 | |||
606 | /**** | 386 | /**** |
607 | * General form of address family dependent message. | 387 | * General form of address family dependent message. |
608 | ****/ | 388 | ****/ |
@@ -663,138 +443,6 @@ struct prefix_cacheinfo | |||
663 | __u32 valid_time; | 443 | __u32 valid_time; |
664 | }; | 444 | }; |
665 | 445 | ||
666 | /* The struct should be in sync with struct net_device_stats */ | ||
667 | struct rtnl_link_stats | ||
668 | { | ||
669 | __u32 rx_packets; /* total packets received */ | ||
670 | __u32 tx_packets; /* total packets transmitted */ | ||
671 | __u32 rx_bytes; /* total bytes received */ | ||
672 | __u32 tx_bytes; /* total bytes transmitted */ | ||
673 | __u32 rx_errors; /* bad packets received */ | ||
674 | __u32 tx_errors; /* packet transmit problems */ | ||
675 | __u32 rx_dropped; /* no space in linux buffers */ | ||
676 | __u32 tx_dropped; /* no space available in linux */ | ||
677 | __u32 multicast; /* multicast packets received */ | ||
678 | __u32 collisions; | ||
679 | |||
680 | /* detailed rx_errors: */ | ||
681 | __u32 rx_length_errors; | ||
682 | __u32 rx_over_errors; /* receiver ring buff overflow */ | ||
683 | __u32 rx_crc_errors; /* recved pkt with crc error */ | ||
684 | __u32 rx_frame_errors; /* recv'd frame alignment error */ | ||
685 | __u32 rx_fifo_errors; /* recv'r fifo overrun */ | ||
686 | __u32 rx_missed_errors; /* receiver missed packet */ | ||
687 | |||
688 | /* detailed tx_errors */ | ||
689 | __u32 tx_aborted_errors; | ||
690 | __u32 tx_carrier_errors; | ||
691 | __u32 tx_fifo_errors; | ||
692 | __u32 tx_heartbeat_errors; | ||
693 | __u32 tx_window_errors; | ||
694 | |||
695 | /* for cslip etc */ | ||
696 | __u32 rx_compressed; | ||
697 | __u32 tx_compressed; | ||
698 | }; | ||
699 | |||
700 | /* The struct should be in sync with struct ifmap */ | ||
701 | struct rtnl_link_ifmap | ||
702 | { | ||
703 | __u64 mem_start; | ||
704 | __u64 mem_end; | ||
705 | __u64 base_addr; | ||
706 | __u16 irq; | ||
707 | __u8 dma; | ||
708 | __u8 port; | ||
709 | }; | ||
710 | |||
711 | enum | ||
712 | { | ||
713 | IFLA_UNSPEC, | ||
714 | IFLA_ADDRESS, | ||
715 | IFLA_BROADCAST, | ||
716 | IFLA_IFNAME, | ||
717 | IFLA_MTU, | ||
718 | IFLA_LINK, | ||
719 | IFLA_QDISC, | ||
720 | IFLA_STATS, | ||
721 | IFLA_COST, | ||
722 | #define IFLA_COST IFLA_COST | ||
723 | IFLA_PRIORITY, | ||
724 | #define IFLA_PRIORITY IFLA_PRIORITY | ||
725 | IFLA_MASTER, | ||
726 | #define IFLA_MASTER IFLA_MASTER | ||
727 | IFLA_WIRELESS, /* Wireless Extension event - see wireless.h */ | ||
728 | #define IFLA_WIRELESS IFLA_WIRELESS | ||
729 | IFLA_PROTINFO, /* Protocol specific information for a link */ | ||
730 | #define IFLA_PROTINFO IFLA_PROTINFO | ||
731 | IFLA_TXQLEN, | ||
732 | #define IFLA_TXQLEN IFLA_TXQLEN | ||
733 | IFLA_MAP, | ||
734 | #define IFLA_MAP IFLA_MAP | ||
735 | IFLA_WEIGHT, | ||
736 | #define IFLA_WEIGHT IFLA_WEIGHT | ||
737 | IFLA_OPERSTATE, | ||
738 | IFLA_LINKMODE, | ||
739 | __IFLA_MAX | ||
740 | }; | ||
741 | |||
742 | |||
743 | #define IFLA_MAX (__IFLA_MAX - 1) | ||
744 | |||
745 | #define IFLA_RTA(r) ((struct rtattr*)(((char*)(r)) + NLMSG_ALIGN(sizeof(struct ifinfomsg)))) | ||
746 | #define IFLA_PAYLOAD(n) NLMSG_PAYLOAD(n,sizeof(struct ifinfomsg)) | ||
747 | |||
748 | /* ifi_flags. | ||
749 | |||
750 | IFF_* flags. | ||
751 | |||
752 | The only change is: | ||
753 | IFF_LOOPBACK, IFF_BROADCAST and IFF_POINTOPOINT are | ||
754 | more not changeable by user. They describe link media | ||
755 | characteristics and set by device driver. | ||
756 | |||
757 | Comments: | ||
758 | - Combination IFF_BROADCAST|IFF_POINTOPOINT is invalid | ||
759 | - If neither of these three flags are set; | ||
760 | the interface is NBMA. | ||
761 | |||
762 | - IFF_MULTICAST does not mean anything special: | ||
763 | multicasts can be used on all not-NBMA links. | ||
764 | IFF_MULTICAST means that this media uses special encapsulation | ||
765 | for multicast frames. Apparently, all IFF_POINTOPOINT and | ||
766 | IFF_BROADCAST devices are able to use multicasts too. | ||
767 | */ | ||
768 | |||
769 | /* IFLA_LINK. | ||
770 | For usual devices it is equal ifi_index. | ||
771 | If it is a "virtual interface" (f.e. tunnel), ifi_link | ||
772 | can point to real physical interface (f.e. for bandwidth calculations), | ||
773 | or maybe 0, what means, that real media is unknown (usual | ||
774 | for IPIP tunnels, when route to endpoint is allowed to change) | ||
775 | */ | ||
776 | |||
777 | /* Subtype attributes for IFLA_PROTINFO */ | ||
778 | enum | ||
779 | { | ||
780 | IFLA_INET6_UNSPEC, | ||
781 | IFLA_INET6_FLAGS, /* link flags */ | ||
782 | IFLA_INET6_CONF, /* sysctl parameters */ | ||
783 | IFLA_INET6_STATS, /* statistics */ | ||
784 | IFLA_INET6_MCAST, /* MC things. What of them? */ | ||
785 | IFLA_INET6_CACHEINFO, /* time values and max reasm size */ | ||
786 | __IFLA_INET6_MAX | ||
787 | }; | ||
788 | |||
789 | #define IFLA_INET6_MAX (__IFLA_INET6_MAX - 1) | ||
790 | |||
791 | struct ifla_cacheinfo | ||
792 | { | ||
793 | __u32 max_reasm_len; | ||
794 | __u32 tstamp; /* ipv6InterfaceTable updated timestamp */ | ||
795 | __u32 reachable_time; | ||
796 | __u32 retrans_time; | ||
797 | }; | ||
798 | 446 | ||
799 | /***************************************************************** | 447 | /***************************************************************** |
800 | * Traffic control messages. | 448 | * Traffic control messages. |
@@ -885,10 +533,13 @@ enum rtnetlink_groups { | |||
885 | RTNLGRP_NOP2, | 533 | RTNLGRP_NOP2, |
886 | RTNLGRP_DECnet_ROUTE, | 534 | RTNLGRP_DECnet_ROUTE, |
887 | #define RTNLGRP_DECnet_ROUTE RTNLGRP_DECnet_ROUTE | 535 | #define RTNLGRP_DECnet_ROUTE RTNLGRP_DECnet_ROUTE |
888 | RTNLGRP_NOP3, | 536 | RTNLGRP_DECnet_RULE, |
537 | #define RTNLGRP_DECnet_RULE RTNLGRP_DECnet_RULE | ||
889 | RTNLGRP_NOP4, | 538 | RTNLGRP_NOP4, |
890 | RTNLGRP_IPV6_PREFIX, | 539 | RTNLGRP_IPV6_PREFIX, |
891 | #define RTNLGRP_IPV6_PREFIX RTNLGRP_IPV6_PREFIX | 540 | #define RTNLGRP_IPV6_PREFIX RTNLGRP_IPV6_PREFIX |
541 | RTNLGRP_IPV6_RULE, | ||
542 | #define RTNLGRP_IPV6_RULE RTNLGRP_IPV6_RULE | ||
892 | __RTNLGRP_MAX | 543 | __RTNLGRP_MAX |
893 | }; | 544 | }; |
894 | #define RTNLGRP_MAX (__RTNLGRP_MAX - 1) | 545 | #define RTNLGRP_MAX (__RTNLGRP_MAX - 1) |
@@ -923,8 +574,6 @@ extern int rtattr_parse(struct rtattr *tb[], int maxattr, struct rtattr *rta, in | |||
923 | #define rtattr_parse_nested(tb, max, rta) \ | 574 | #define rtattr_parse_nested(tb, max, rta) \ |
924 | rtattr_parse((tb), (max), RTA_DATA((rta)), RTA_PAYLOAD((rta))) | 575 | rtattr_parse((tb), (max), RTA_DATA((rta)), RTA_PAYLOAD((rta))) |
925 | 576 | ||
926 | extern struct sock *rtnl; | ||
927 | |||
928 | struct rtnetlink_link | 577 | struct rtnetlink_link |
929 | { | 578 | { |
930 | int (*doit)(struct sk_buff *, struct nlmsghdr*, void *attr); | 579 | int (*doit)(struct sk_buff *, struct nlmsghdr*, void *attr); |
@@ -933,6 +582,10 @@ struct rtnetlink_link | |||
933 | 582 | ||
934 | extern struct rtnetlink_link * rtnetlink_links[NPROTO]; | 583 | extern struct rtnetlink_link * rtnetlink_links[NPROTO]; |
935 | extern int rtnetlink_send(struct sk_buff *skb, u32 pid, u32 group, int echo); | 584 | extern int rtnetlink_send(struct sk_buff *skb, u32 pid, u32 group, int echo); |
585 | extern int rtnl_unicast(struct sk_buff *skb, u32 pid); | ||
586 | extern int rtnl_notify(struct sk_buff *skb, u32 pid, u32 group, | ||
587 | struct nlmsghdr *nlh, gfp_t flags); | ||
588 | extern void rtnl_set_sk_err(u32 group, int error); | ||
936 | extern int rtnetlink_put_metrics(struct sk_buff *skb, u32 *metrics); | 589 | extern int rtnetlink_put_metrics(struct sk_buff *skb, u32 *metrics); |
937 | 590 | ||
938 | extern void __rta_fill(struct sk_buff *skb, int attrtype, int attrlen, const void *data); | 591 | extern void __rta_fill(struct sk_buff *skb, int attrtype, int attrlen, const void *data); |
@@ -1065,6 +718,13 @@ extern void __rtnl_unlock(void); | |||
1065 | } \ | 718 | } \ |
1066 | } while(0) | 719 | } while(0) |
1067 | 720 | ||
721 | static inline u32 rtm_get_table(struct rtattr **rta, u8 table) | ||
722 | { | ||
723 | return RTA_GET_U32(rta[RTA_TABLE-1]); | ||
724 | rtattr_failure: | ||
725 | return table; | ||
726 | } | ||
727 | |||
1068 | #endif /* __KERNEL__ */ | 728 | #endif /* __KERNEL__ */ |
1069 | 729 | ||
1070 | 730 | ||
diff --git a/include/linux/security.h b/include/linux/security.h index 6bc2aad494ff..9f56fb8a4a6c 100644 --- a/include/linux/security.h +++ b/include/linux/security.h | |||
@@ -31,6 +31,8 @@ | |||
31 | #include <linux/msg.h> | 31 | #include <linux/msg.h> |
32 | #include <linux/sched.h> | 32 | #include <linux/sched.h> |
33 | #include <linux/key.h> | 33 | #include <linux/key.h> |
34 | #include <linux/xfrm.h> | ||
35 | #include <net/flow.h> | ||
34 | 36 | ||
35 | struct ctl_table; | 37 | struct ctl_table; |
36 | 38 | ||
@@ -88,6 +90,7 @@ extern int cap_netlink_recv(struct sk_buff *skb, int cap); | |||
88 | struct nfsctl_arg; | 90 | struct nfsctl_arg; |
89 | struct sched_param; | 91 | struct sched_param; |
90 | struct swap_info_struct; | 92 | struct swap_info_struct; |
93 | struct request_sock; | ||
91 | 94 | ||
92 | /* bprm_apply_creds unsafe reasons */ | 95 | /* bprm_apply_creds unsafe reasons */ |
93 | #define LSM_UNSAFE_SHARE 1 | 96 | #define LSM_UNSAFE_SHARE 1 |
@@ -812,9 +815,19 @@ struct swap_info_struct; | |||
812 | * which is used to copy security attributes between local stream sockets. | 815 | * which is used to copy security attributes between local stream sockets. |
813 | * @sk_free_security: | 816 | * @sk_free_security: |
814 | * Deallocate security structure. | 817 | * Deallocate security structure. |
815 | * @sk_getsid: | 818 | * @sk_clone_security: |
816 | * Retrieve the LSM-specific sid for the sock to enable caching of network | 819 | * Clone/copy security structure. |
820 | * @sk_getsecid: | ||
821 | * Retrieve the LSM-specific secid for the sock to enable caching of network | ||
817 | * authorizations. | 822 | * authorizations. |
823 | * @sock_graft: | ||
824 | * Sets the socket's isec sid to the sock's sid. | ||
825 | * @inet_conn_request: | ||
826 | * Sets the openreq's sid to socket's sid with MLS portion taken from peer sid. | ||
827 | * @inet_csk_clone: | ||
828 | * Sets the new child socket's sid to the openreq sid. | ||
829 | * @req_classify_flow: | ||
830 | * Sets the flow's sid to the openreq sid. | ||
818 | * | 831 | * |
819 | * Security hooks for XFRM operations. | 832 | * Security hooks for XFRM operations. |
820 | * | 833 | * |
@@ -823,9 +836,10 @@ struct swap_info_struct; | |||
823 | * used by the XFRM system. | 836 | * used by the XFRM system. |
824 | * @sec_ctx contains the security context information being provided by | 837 | * @sec_ctx contains the security context information being provided by |
825 | * the user-level policy update program (e.g., setkey). | 838 | * the user-level policy update program (e.g., setkey). |
826 | * Allocate a security structure to the xp->security field. | 839 | * @sk refers to the sock from which to derive the security context. |
827 | * The security field is initialized to NULL when the xfrm_policy is | 840 | * Allocate a security structure to the xp->security field; the security |
828 | * allocated. | 841 | * field is initialized to NULL when the xfrm_policy is allocated. Only |
842 | * one of sec_ctx or sock can be specified. | ||
829 | * Return 0 if operation was successful (memory to allocate, legal context) | 843 | * Return 0 if operation was successful (memory to allocate, legal context) |
830 | * @xfrm_policy_clone_security: | 844 | * @xfrm_policy_clone_security: |
831 | * @old contains an existing xfrm_policy in the SPD. | 845 | * @old contains an existing xfrm_policy in the SPD. |
@@ -844,9 +858,14 @@ struct swap_info_struct; | |||
844 | * Database by the XFRM system. | 858 | * Database by the XFRM system. |
845 | * @sec_ctx contains the security context information being provided by | 859 | * @sec_ctx contains the security context information being provided by |
846 | * the user-level SA generation program (e.g., setkey or racoon). | 860 | * the user-level SA generation program (e.g., setkey or racoon). |
847 | * Allocate a security structure to the x->security field. The | 861 | * @polsec contains the security context information associated with a xfrm |
848 | * security field is initialized to NULL when the xfrm_state is | 862 | * policy rule from which to take the base context. polsec must be NULL |
849 | * allocated. | 863 | * when sec_ctx is specified. |
864 | * @secid contains the secid from which to take the mls portion of the context. | ||
865 | * Allocate a security structure to the x->security field; the security | ||
866 | * field is initialized to NULL when the xfrm_state is allocated. Set the | ||
867 | * context to correspond to either sec_ctx or polsec, with the mls portion | ||
868 | * taken from secid in the latter case. | ||
850 | * Return 0 if operation was successful (memory to allocate, legal context). | 869 | * Return 0 if operation was successful (memory to allocate, legal context). |
851 | * @xfrm_state_free_security: | 870 | * @xfrm_state_free_security: |
852 | * @x contains the xfrm_state. | 871 | * @x contains the xfrm_state. |
@@ -857,13 +876,27 @@ struct swap_info_struct; | |||
857 | * @xfrm_policy_lookup: | 876 | * @xfrm_policy_lookup: |
858 | * @xp contains the xfrm_policy for which the access control is being | 877 | * @xp contains the xfrm_policy for which the access control is being |
859 | * checked. | 878 | * checked. |
860 | * @sk_sid contains the sock security label that is used to authorize | 879 | * @fl_secid contains the flow security label that is used to authorize |
861 | * access to the policy xp. | 880 | * access to the policy xp. |
862 | * @dir contains the direction of the flow (input or output). | 881 | * @dir contains the direction of the flow (input or output). |
863 | * Check permission when a sock selects a xfrm_policy for processing | 882 | * Check permission when a flow selects a xfrm_policy for processing |
864 | * XFRMs on a packet. The hook is called when selecting either a | 883 | * XFRMs on a packet. The hook is called when selecting either a |
865 | * per-socket policy or a generic xfrm policy. | 884 | * per-socket policy or a generic xfrm policy. |
866 | * Return 0 if permission is granted. | 885 | * Return 0 if permission is granted. |
886 | * @xfrm_state_pol_flow_match: | ||
887 | * @x contains the state to match. | ||
888 | * @xp contains the policy to check for a match. | ||
889 | * @fl contains the flow to check for a match. | ||
890 | * Return 1 if there is a match. | ||
891 | * @xfrm_flow_state_match: | ||
892 | * @fl contains the flow key to match. | ||
893 | * @xfrm points to the xfrm_state to match. | ||
894 | * Return 1 if there is a match. | ||
895 | * @xfrm_decode_session: | ||
896 | * @skb points to skb to decode. | ||
897 | * @secid points to the flow key secid to set. | ||
898 | * @ckall says if all xfrms used should be checked for same secid. | ||
899 | * Return 0 if ckall is zero or all xfrms used have the same secid. | ||
867 | * | 900 | * |
868 | * Security hooks affecting all Key Management operations | 901 | * Security hooks affecting all Key Management operations |
869 | * | 902 | * |
@@ -1308,8 +1341,8 @@ struct security_operations { | |||
1308 | int (*unix_may_send) (struct socket * sock, struct socket * other); | 1341 | int (*unix_may_send) (struct socket * sock, struct socket * other); |
1309 | 1342 | ||
1310 | int (*socket_create) (int family, int type, int protocol, int kern); | 1343 | int (*socket_create) (int family, int type, int protocol, int kern); |
1311 | void (*socket_post_create) (struct socket * sock, int family, | 1344 | int (*socket_post_create) (struct socket * sock, int family, |
1312 | int type, int protocol, int kern); | 1345 | int type, int protocol, int kern); |
1313 | int (*socket_bind) (struct socket * sock, | 1346 | int (*socket_bind) (struct socket * sock, |
1314 | struct sockaddr * address, int addrlen); | 1347 | struct sockaddr * address, int addrlen); |
1315 | int (*socket_connect) (struct socket * sock, | 1348 | int (*socket_connect) (struct socket * sock, |
@@ -1332,18 +1365,31 @@ struct security_operations { | |||
1332 | int (*socket_getpeersec_dgram) (struct socket *sock, struct sk_buff *skb, u32 *secid); | 1365 | int (*socket_getpeersec_dgram) (struct socket *sock, struct sk_buff *skb, u32 *secid); |
1333 | int (*sk_alloc_security) (struct sock *sk, int family, gfp_t priority); | 1366 | int (*sk_alloc_security) (struct sock *sk, int family, gfp_t priority); |
1334 | void (*sk_free_security) (struct sock *sk); | 1367 | void (*sk_free_security) (struct sock *sk); |
1335 | unsigned int (*sk_getsid) (struct sock *sk, struct flowi *fl, u8 dir); | 1368 | void (*sk_clone_security) (const struct sock *sk, struct sock *newsk); |
1369 | void (*sk_getsecid) (struct sock *sk, u32 *secid); | ||
1370 | void (*sock_graft)(struct sock* sk, struct socket *parent); | ||
1371 | int (*inet_conn_request)(struct sock *sk, struct sk_buff *skb, | ||
1372 | struct request_sock *req); | ||
1373 | void (*inet_csk_clone)(struct sock *newsk, const struct request_sock *req); | ||
1374 | void (*req_classify_flow)(const struct request_sock *req, struct flowi *fl); | ||
1336 | #endif /* CONFIG_SECURITY_NETWORK */ | 1375 | #endif /* CONFIG_SECURITY_NETWORK */ |
1337 | 1376 | ||
1338 | #ifdef CONFIG_SECURITY_NETWORK_XFRM | 1377 | #ifdef CONFIG_SECURITY_NETWORK_XFRM |
1339 | int (*xfrm_policy_alloc_security) (struct xfrm_policy *xp, struct xfrm_user_sec_ctx *sec_ctx); | 1378 | int (*xfrm_policy_alloc_security) (struct xfrm_policy *xp, |
1379 | struct xfrm_user_sec_ctx *sec_ctx, struct sock *sk); | ||
1340 | int (*xfrm_policy_clone_security) (struct xfrm_policy *old, struct xfrm_policy *new); | 1380 | int (*xfrm_policy_clone_security) (struct xfrm_policy *old, struct xfrm_policy *new); |
1341 | void (*xfrm_policy_free_security) (struct xfrm_policy *xp); | 1381 | void (*xfrm_policy_free_security) (struct xfrm_policy *xp); |
1342 | int (*xfrm_policy_delete_security) (struct xfrm_policy *xp); | 1382 | int (*xfrm_policy_delete_security) (struct xfrm_policy *xp); |
1343 | int (*xfrm_state_alloc_security) (struct xfrm_state *x, struct xfrm_user_sec_ctx *sec_ctx); | 1383 | int (*xfrm_state_alloc_security) (struct xfrm_state *x, |
1384 | struct xfrm_user_sec_ctx *sec_ctx, struct xfrm_sec_ctx *polsec, | ||
1385 | u32 secid); | ||
1344 | void (*xfrm_state_free_security) (struct xfrm_state *x); | 1386 | void (*xfrm_state_free_security) (struct xfrm_state *x); |
1345 | int (*xfrm_state_delete_security) (struct xfrm_state *x); | 1387 | int (*xfrm_state_delete_security) (struct xfrm_state *x); |
1346 | int (*xfrm_policy_lookup)(struct xfrm_policy *xp, u32 sk_sid, u8 dir); | 1388 | int (*xfrm_policy_lookup)(struct xfrm_policy *xp, u32 fl_secid, u8 dir); |
1389 | int (*xfrm_state_pol_flow_match)(struct xfrm_state *x, | ||
1390 | struct xfrm_policy *xp, struct flowi *fl); | ||
1391 | int (*xfrm_flow_state_match)(struct flowi *fl, struct xfrm_state *xfrm); | ||
1392 | int (*xfrm_decode_session)(struct sk_buff *skb, u32 *secid, int ckall); | ||
1347 | #endif /* CONFIG_SECURITY_NETWORK_XFRM */ | 1393 | #endif /* CONFIG_SECURITY_NETWORK_XFRM */ |
1348 | 1394 | ||
1349 | /* key management security hooks */ | 1395 | /* key management security hooks */ |
@@ -2778,13 +2824,13 @@ static inline int security_socket_create (int family, int type, | |||
2778 | return security_ops->socket_create(family, type, protocol, kern); | 2824 | return security_ops->socket_create(family, type, protocol, kern); |
2779 | } | 2825 | } |
2780 | 2826 | ||
2781 | static inline void security_socket_post_create(struct socket * sock, | 2827 | static inline int security_socket_post_create(struct socket * sock, |
2782 | int family, | 2828 | int family, |
2783 | int type, | 2829 | int type, |
2784 | int protocol, int kern) | 2830 | int protocol, int kern) |
2785 | { | 2831 | { |
2786 | security_ops->socket_post_create(sock, family, type, | 2832 | return security_ops->socket_post_create(sock, family, type, |
2787 | protocol, kern); | 2833 | protocol, kern); |
2788 | } | 2834 | } |
2789 | 2835 | ||
2790 | static inline int security_socket_bind(struct socket * sock, | 2836 | static inline int security_socket_bind(struct socket * sock, |
@@ -2885,9 +2931,36 @@ static inline void security_sk_free(struct sock *sk) | |||
2885 | return security_ops->sk_free_security(sk); | 2931 | return security_ops->sk_free_security(sk); |
2886 | } | 2932 | } |
2887 | 2933 | ||
2888 | static inline unsigned int security_sk_sid(struct sock *sk, struct flowi *fl, u8 dir) | 2934 | static inline void security_sk_clone(const struct sock *sk, struct sock *newsk) |
2935 | { | ||
2936 | return security_ops->sk_clone_security(sk, newsk); | ||
2937 | } | ||
2938 | |||
2939 | static inline void security_sk_classify_flow(struct sock *sk, struct flowi *fl) | ||
2889 | { | 2940 | { |
2890 | return security_ops->sk_getsid(sk, fl, dir); | 2941 | security_ops->sk_getsecid(sk, &fl->secid); |
2942 | } | ||
2943 | |||
2944 | static inline void security_req_classify_flow(const struct request_sock *req, struct flowi *fl) | ||
2945 | { | ||
2946 | security_ops->req_classify_flow(req, fl); | ||
2947 | } | ||
2948 | |||
2949 | static inline void security_sock_graft(struct sock* sk, struct socket *parent) | ||
2950 | { | ||
2951 | security_ops->sock_graft(sk, parent); | ||
2952 | } | ||
2953 | |||
2954 | static inline int security_inet_conn_request(struct sock *sk, | ||
2955 | struct sk_buff *skb, struct request_sock *req) | ||
2956 | { | ||
2957 | return security_ops->inet_conn_request(sk, skb, req); | ||
2958 | } | ||
2959 | |||
2960 | static inline void security_inet_csk_clone(struct sock *newsk, | ||
2961 | const struct request_sock *req) | ||
2962 | { | ||
2963 | security_ops->inet_csk_clone(newsk, req); | ||
2891 | } | 2964 | } |
2892 | #else /* CONFIG_SECURITY_NETWORK */ | 2965 | #else /* CONFIG_SECURITY_NETWORK */ |
2893 | static inline int security_unix_stream_connect(struct socket * sock, | 2966 | static inline int security_unix_stream_connect(struct socket * sock, |
@@ -2909,11 +2982,12 @@ static inline int security_socket_create (int family, int type, | |||
2909 | return 0; | 2982 | return 0; |
2910 | } | 2983 | } |
2911 | 2984 | ||
2912 | static inline void security_socket_post_create(struct socket * sock, | 2985 | static inline int security_socket_post_create(struct socket * sock, |
2913 | int family, | 2986 | int family, |
2914 | int type, | 2987 | int type, |
2915 | int protocol, int kern) | 2988 | int protocol, int kern) |
2916 | { | 2989 | { |
2990 | return 0; | ||
2917 | } | 2991 | } |
2918 | 2992 | ||
2919 | static inline int security_socket_bind(struct socket * sock, | 2993 | static inline int security_socket_bind(struct socket * sock, |
@@ -3011,16 +3085,43 @@ static inline void security_sk_free(struct sock *sk) | |||
3011 | { | 3085 | { |
3012 | } | 3086 | } |
3013 | 3087 | ||
3014 | static inline unsigned int security_sk_sid(struct sock *sk, struct flowi *fl, u8 dir) | 3088 | static inline void security_sk_clone(const struct sock *sk, struct sock *newsk) |
3089 | { | ||
3090 | } | ||
3091 | |||
3092 | static inline void security_sk_classify_flow(struct sock *sk, struct flowi *fl) | ||
3093 | { | ||
3094 | } | ||
3095 | |||
3096 | static inline void security_req_classify_flow(const struct request_sock *req, struct flowi *fl) | ||
3097 | { | ||
3098 | } | ||
3099 | |||
3100 | static inline void security_sock_graft(struct sock* sk, struct socket *parent) | ||
3101 | { | ||
3102 | } | ||
3103 | |||
3104 | static inline int security_inet_conn_request(struct sock *sk, | ||
3105 | struct sk_buff *skb, struct request_sock *req) | ||
3015 | { | 3106 | { |
3016 | return 0; | 3107 | return 0; |
3017 | } | 3108 | } |
3109 | |||
3110 | static inline void security_inet_csk_clone(struct sock *newsk, | ||
3111 | const struct request_sock *req) | ||
3112 | { | ||
3113 | } | ||
3018 | #endif /* CONFIG_SECURITY_NETWORK */ | 3114 | #endif /* CONFIG_SECURITY_NETWORK */ |
3019 | 3115 | ||
3020 | #ifdef CONFIG_SECURITY_NETWORK_XFRM | 3116 | #ifdef CONFIG_SECURITY_NETWORK_XFRM |
3021 | static inline int security_xfrm_policy_alloc(struct xfrm_policy *xp, struct xfrm_user_sec_ctx *sec_ctx) | 3117 | static inline int security_xfrm_policy_alloc(struct xfrm_policy *xp, struct xfrm_user_sec_ctx *sec_ctx) |
3022 | { | 3118 | { |
3023 | return security_ops->xfrm_policy_alloc_security(xp, sec_ctx); | 3119 | return security_ops->xfrm_policy_alloc_security(xp, sec_ctx, NULL); |
3120 | } | ||
3121 | |||
3122 | static inline int security_xfrm_sock_policy_alloc(struct xfrm_policy *xp, struct sock *sk) | ||
3123 | { | ||
3124 | return security_ops->xfrm_policy_alloc_security(xp, NULL, sk); | ||
3024 | } | 3125 | } |
3025 | 3126 | ||
3026 | static inline int security_xfrm_policy_clone(struct xfrm_policy *old, struct xfrm_policy *new) | 3127 | static inline int security_xfrm_policy_clone(struct xfrm_policy *old, struct xfrm_policy *new) |
@@ -3038,9 +3139,18 @@ static inline int security_xfrm_policy_delete(struct xfrm_policy *xp) | |||
3038 | return security_ops->xfrm_policy_delete_security(xp); | 3139 | return security_ops->xfrm_policy_delete_security(xp); |
3039 | } | 3140 | } |
3040 | 3141 | ||
3041 | static inline int security_xfrm_state_alloc(struct xfrm_state *x, struct xfrm_user_sec_ctx *sec_ctx) | 3142 | static inline int security_xfrm_state_alloc(struct xfrm_state *x, |
3143 | struct xfrm_user_sec_ctx *sec_ctx) | ||
3042 | { | 3144 | { |
3043 | return security_ops->xfrm_state_alloc_security(x, sec_ctx); | 3145 | return security_ops->xfrm_state_alloc_security(x, sec_ctx, NULL, 0); |
3146 | } | ||
3147 | |||
3148 | static inline int security_xfrm_state_alloc_acquire(struct xfrm_state *x, | ||
3149 | struct xfrm_sec_ctx *polsec, u32 secid) | ||
3150 | { | ||
3151 | if (!polsec) | ||
3152 | return 0; | ||
3153 | return security_ops->xfrm_state_alloc_security(x, NULL, polsec, secid); | ||
3044 | } | 3154 | } |
3045 | 3155 | ||
3046 | static inline int security_xfrm_state_delete(struct xfrm_state *x) | 3156 | static inline int security_xfrm_state_delete(struct xfrm_state *x) |
@@ -3053,9 +3163,32 @@ static inline void security_xfrm_state_free(struct xfrm_state *x) | |||
3053 | security_ops->xfrm_state_free_security(x); | 3163 | security_ops->xfrm_state_free_security(x); |
3054 | } | 3164 | } |
3055 | 3165 | ||
3056 | static inline int security_xfrm_policy_lookup(struct xfrm_policy *xp, u32 sk_sid, u8 dir) | 3166 | static inline int security_xfrm_policy_lookup(struct xfrm_policy *xp, u32 fl_secid, u8 dir) |
3167 | { | ||
3168 | return security_ops->xfrm_policy_lookup(xp, fl_secid, dir); | ||
3169 | } | ||
3170 | |||
3171 | static inline int security_xfrm_state_pol_flow_match(struct xfrm_state *x, | ||
3172 | struct xfrm_policy *xp, struct flowi *fl) | ||
3057 | { | 3173 | { |
3058 | return security_ops->xfrm_policy_lookup(xp, sk_sid, dir); | 3174 | return security_ops->xfrm_state_pol_flow_match(x, xp, fl); |
3175 | } | ||
3176 | |||
3177 | static inline int security_xfrm_flow_state_match(struct flowi *fl, struct xfrm_state *xfrm) | ||
3178 | { | ||
3179 | return security_ops->xfrm_flow_state_match(fl, xfrm); | ||
3180 | } | ||
3181 | |||
3182 | static inline int security_xfrm_decode_session(struct sk_buff *skb, u32 *secid) | ||
3183 | { | ||
3184 | return security_ops->xfrm_decode_session(skb, secid, 1); | ||
3185 | } | ||
3186 | |||
3187 | static inline void security_skb_classify_flow(struct sk_buff *skb, struct flowi *fl) | ||
3188 | { | ||
3189 | int rc = security_ops->xfrm_decode_session(skb, &fl->secid, 0); | ||
3190 | |||
3191 | BUG_ON(rc); | ||
3059 | } | 3192 | } |
3060 | #else /* CONFIG_SECURITY_NETWORK_XFRM */ | 3193 | #else /* CONFIG_SECURITY_NETWORK_XFRM */ |
3061 | static inline int security_xfrm_policy_alloc(struct xfrm_policy *xp, struct xfrm_user_sec_ctx *sec_ctx) | 3194 | static inline int security_xfrm_policy_alloc(struct xfrm_policy *xp, struct xfrm_user_sec_ctx *sec_ctx) |
@@ -3063,6 +3196,11 @@ static inline int security_xfrm_policy_alloc(struct xfrm_policy *xp, struct xfrm | |||
3063 | return 0; | 3196 | return 0; |
3064 | } | 3197 | } |
3065 | 3198 | ||
3199 | static inline int security_xfrm_sock_policy_alloc(struct xfrm_policy *xp, struct sock *sk) | ||
3200 | { | ||
3201 | return 0; | ||
3202 | } | ||
3203 | |||
3066 | static inline int security_xfrm_policy_clone(struct xfrm_policy *old, struct xfrm_policy *new) | 3204 | static inline int security_xfrm_policy_clone(struct xfrm_policy *old, struct xfrm_policy *new) |
3067 | { | 3205 | { |
3068 | return 0; | 3206 | return 0; |
@@ -3077,7 +3215,14 @@ static inline int security_xfrm_policy_delete(struct xfrm_policy *xp) | |||
3077 | return 0; | 3215 | return 0; |
3078 | } | 3216 | } |
3079 | 3217 | ||
3080 | static inline int security_xfrm_state_alloc(struct xfrm_state *x, struct xfrm_user_sec_ctx *sec_ctx) | 3218 | static inline int security_xfrm_state_alloc(struct xfrm_state *x, |
3219 | struct xfrm_user_sec_ctx *sec_ctx) | ||
3220 | { | ||
3221 | return 0; | ||
3222 | } | ||
3223 | |||
3224 | static inline int security_xfrm_state_alloc_acquire(struct xfrm_state *x, | ||
3225 | struct xfrm_sec_ctx *polsec, u32 secid) | ||
3081 | { | 3226 | { |
3082 | return 0; | 3227 | return 0; |
3083 | } | 3228 | } |
@@ -3091,10 +3236,32 @@ static inline int security_xfrm_state_delete(struct xfrm_state *x) | |||
3091 | return 0; | 3236 | return 0; |
3092 | } | 3237 | } |
3093 | 3238 | ||
3094 | static inline int security_xfrm_policy_lookup(struct xfrm_policy *xp, u32 sk_sid, u8 dir) | 3239 | static inline int security_xfrm_policy_lookup(struct xfrm_policy *xp, u32 fl_secid, u8 dir) |
3240 | { | ||
3241 | return 0; | ||
3242 | } | ||
3243 | |||
3244 | static inline int security_xfrm_state_pol_flow_match(struct xfrm_state *x, | ||
3245 | struct xfrm_policy *xp, struct flowi *fl) | ||
3246 | { | ||
3247 | return 1; | ||
3248 | } | ||
3249 | |||
3250 | static inline int security_xfrm_flow_state_match(struct flowi *fl, | ||
3251 | struct xfrm_state *xfrm) | ||
3252 | { | ||
3253 | return 1; | ||
3254 | } | ||
3255 | |||
3256 | static inline int security_xfrm_decode_session(struct sk_buff *skb, u32 *secid) | ||
3095 | { | 3257 | { |
3096 | return 0; | 3258 | return 0; |
3097 | } | 3259 | } |
3260 | |||
3261 | static inline void security_skb_classify_flow(struct sk_buff *skb, struct flowi *fl) | ||
3262 | { | ||
3263 | } | ||
3264 | |||
3098 | #endif /* CONFIG_SECURITY_NETWORK_XFRM */ | 3265 | #endif /* CONFIG_SECURITY_NETWORK_XFRM */ |
3099 | 3266 | ||
3100 | #ifdef CONFIG_KEYS | 3267 | #ifdef CONFIG_KEYS |
diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h index 755e9cddac47..85577a4ffa61 100644 --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h | |||
@@ -34,8 +34,9 @@ | |||
34 | #define HAVE_ALIGNABLE_SKB /* Ditto 8) */ | 34 | #define HAVE_ALIGNABLE_SKB /* Ditto 8) */ |
35 | 35 | ||
36 | #define CHECKSUM_NONE 0 | 36 | #define CHECKSUM_NONE 0 |
37 | #define CHECKSUM_HW 1 | 37 | #define CHECKSUM_PARTIAL 1 |
38 | #define CHECKSUM_UNNECESSARY 2 | 38 | #define CHECKSUM_UNNECESSARY 2 |
39 | #define CHECKSUM_COMPLETE 3 | ||
39 | 40 | ||
40 | #define SKB_DATA_ALIGN(X) (((X) + (SMP_CACHE_BYTES - 1)) & \ | 41 | #define SKB_DATA_ALIGN(X) (((X) + (SMP_CACHE_BYTES - 1)) & \ |
41 | ~(SMP_CACHE_BYTES - 1)) | 42 | ~(SMP_CACHE_BYTES - 1)) |
@@ -56,17 +57,17 @@ | |||
56 | * Apparently with secret goal to sell you new device, when you | 57 | * Apparently with secret goal to sell you new device, when you |
57 | * will add new protocol to your host. F.e. IPv6. 8) | 58 | * will add new protocol to your host. F.e. IPv6. 8) |
58 | * | 59 | * |
59 | * HW: the most generic way. Device supplied checksum of _all_ | 60 | * COMPLETE: the most generic way. Device supplied checksum of _all_ |
60 | * the packet as seen by netif_rx in skb->csum. | 61 | * the packet as seen by netif_rx in skb->csum. |
61 | * NOTE: Even if device supports only some protocols, but | 62 | * NOTE: Even if device supports only some protocols, but |
62 | * is able to produce some skb->csum, it MUST use HW, | 63 | * is able to produce some skb->csum, it MUST use COMPLETE, |
63 | * not UNNECESSARY. | 64 | * not UNNECESSARY. |
64 | * | 65 | * |
65 | * B. Checksumming on output. | 66 | * B. Checksumming on output. |
66 | * | 67 | * |
67 | * NONE: skb is checksummed by protocol or csum is not required. | 68 | * NONE: skb is checksummed by protocol or csum is not required. |
68 | * | 69 | * |
69 | * HW: device is required to csum packet as seen by hard_start_xmit | 70 | * PARTIAL: device is required to csum packet as seen by hard_start_xmit |
70 | * from skb->h.raw to the end and to record the checksum | 71 | * from skb->h.raw to the end and to record the checksum |
71 | * at skb->h.raw+skb->csum. | 72 | * at skb->h.raw+skb->csum. |
72 | * | 73 | * |
@@ -1261,14 +1262,14 @@ static inline int skb_linearize_cow(struct sk_buff *skb) | |||
1261 | * @len: length of data pulled | 1262 | * @len: length of data pulled |
1262 | * | 1263 | * |
1263 | * After doing a pull on a received packet, you need to call this to | 1264 | * After doing a pull on a received packet, you need to call this to |
1264 | * update the CHECKSUM_HW checksum, or set ip_summed to CHECKSUM_NONE | 1265 | * update the CHECKSUM_COMPLETE checksum, or set ip_summed to |
1265 | * so that it can be recomputed from scratch. | 1266 | * CHECKSUM_NONE so that it can be recomputed from scratch. |
1266 | */ | 1267 | */ |
1267 | 1268 | ||
1268 | static inline void skb_postpull_rcsum(struct sk_buff *skb, | 1269 | static inline void skb_postpull_rcsum(struct sk_buff *skb, |
1269 | const void *start, unsigned int len) | 1270 | const void *start, unsigned int len) |
1270 | { | 1271 | { |
1271 | if (skb->ip_summed == CHECKSUM_HW) | 1272 | if (skb->ip_summed == CHECKSUM_COMPLETE) |
1272 | skb->csum = csum_sub(skb->csum, csum_partial(start, len, 0)); | 1273 | skb->csum = csum_sub(skb->csum, csum_partial(start, len, 0)); |
1273 | } | 1274 | } |
1274 | 1275 | ||
@@ -1287,7 +1288,7 @@ static inline int pskb_trim_rcsum(struct sk_buff *skb, unsigned int len) | |||
1287 | { | 1288 | { |
1288 | if (likely(len >= skb->len)) | 1289 | if (likely(len >= skb->len)) |
1289 | return 0; | 1290 | return 0; |
1290 | if (skb->ip_summed == CHECKSUM_HW) | 1291 | if (skb->ip_summed == CHECKSUM_COMPLETE) |
1291 | skb->ip_summed = CHECKSUM_NONE; | 1292 | skb->ip_summed = CHECKSUM_NONE; |
1292 | return __pskb_trim(skb, len); | 1293 | return __pskb_trim(skb, len); |
1293 | } | 1294 | } |
diff --git a/include/linux/snmp.h b/include/linux/snmp.h index 4db25d5c7cd1..854aa6b543f1 100644 --- a/include/linux/snmp.h +++ b/include/linux/snmp.h | |||
@@ -155,42 +155,11 @@ enum | |||
155 | UDP_MIB_NOPORTS, /* NoPorts */ | 155 | UDP_MIB_NOPORTS, /* NoPorts */ |
156 | UDP_MIB_INERRORS, /* InErrors */ | 156 | UDP_MIB_INERRORS, /* InErrors */ |
157 | UDP_MIB_OUTDATAGRAMS, /* OutDatagrams */ | 157 | UDP_MIB_OUTDATAGRAMS, /* OutDatagrams */ |
158 | UDP_MIB_RCVBUFERRORS, /* RcvbufErrors */ | ||
159 | UDP_MIB_SNDBUFERRORS, /* SndbufErrors */ | ||
158 | __UDP_MIB_MAX | 160 | __UDP_MIB_MAX |
159 | }; | 161 | }; |
160 | 162 | ||
161 | /* sctp mib definitions */ | ||
162 | /* | ||
163 | * draft-ietf-sigtran-sctp-mib-07.txt | ||
164 | */ | ||
165 | enum | ||
166 | { | ||
167 | SCTP_MIB_NUM = 0, | ||
168 | SCTP_MIB_CURRESTAB, /* CurrEstab */ | ||
169 | SCTP_MIB_ACTIVEESTABS, /* ActiveEstabs */ | ||
170 | SCTP_MIB_PASSIVEESTABS, /* PassiveEstabs */ | ||
171 | SCTP_MIB_ABORTEDS, /* Aborteds */ | ||
172 | SCTP_MIB_SHUTDOWNS, /* Shutdowns */ | ||
173 | SCTP_MIB_OUTOFBLUES, /* OutOfBlues */ | ||
174 | SCTP_MIB_CHECKSUMERRORS, /* ChecksumErrors */ | ||
175 | SCTP_MIB_OUTCTRLCHUNKS, /* OutCtrlChunks */ | ||
176 | SCTP_MIB_OUTORDERCHUNKS, /* OutOrderChunks */ | ||
177 | SCTP_MIB_OUTUNORDERCHUNKS, /* OutUnorderChunks */ | ||
178 | SCTP_MIB_INCTRLCHUNKS, /* InCtrlChunks */ | ||
179 | SCTP_MIB_INORDERCHUNKS, /* InOrderChunks */ | ||
180 | SCTP_MIB_INUNORDERCHUNKS, /* InUnorderChunks */ | ||
181 | SCTP_MIB_FRAGUSRMSGS, /* FragUsrMsgs */ | ||
182 | SCTP_MIB_REASMUSRMSGS, /* ReasmUsrMsgs */ | ||
183 | SCTP_MIB_OUTSCTPPACKS, /* OutSCTPPacks */ | ||
184 | SCTP_MIB_INSCTPPACKS, /* InSCTPPacks */ | ||
185 | SCTP_MIB_RTOALGORITHM, /* RtoAlgorithm */ | ||
186 | SCTP_MIB_RTOMIN, /* RtoMin */ | ||
187 | SCTP_MIB_RTOMAX, /* RtoMax */ | ||
188 | SCTP_MIB_RTOINITIAL, /* RtoInitial */ | ||
189 | SCTP_MIB_VALCOOKIELIFE, /* ValCookieLife */ | ||
190 | SCTP_MIB_MAXINITRETR, /* MaxInitRetr */ | ||
191 | __SCTP_MIB_MAX | ||
192 | }; | ||
193 | |||
194 | /* linux mib definitions */ | 163 | /* linux mib definitions */ |
195 | enum | 164 | enum |
196 | { | 165 | { |
diff --git a/include/linux/sunrpc/clnt.h b/include/linux/sunrpc/clnt.h index 8fe9f35eba31..f6d1d646ce05 100644 --- a/include/linux/sunrpc/clnt.h +++ b/include/linux/sunrpc/clnt.h | |||
@@ -18,18 +18,6 @@ | |||
18 | #include <linux/sunrpc/timer.h> | 18 | #include <linux/sunrpc/timer.h> |
19 | #include <asm/signal.h> | 19 | #include <asm/signal.h> |
20 | 20 | ||
21 | /* | ||
22 | * This defines an RPC port mapping | ||
23 | */ | ||
24 | struct rpc_portmap { | ||
25 | __u32 pm_prog; | ||
26 | __u32 pm_vers; | ||
27 | __u32 pm_prot; | ||
28 | __u16 pm_port; | ||
29 | unsigned char pm_binding : 1; /* doing a getport() */ | ||
30 | struct rpc_wait_queue pm_bindwait; /* waiting on getport() */ | ||
31 | }; | ||
32 | |||
33 | struct rpc_inode; | 21 | struct rpc_inode; |
34 | 22 | ||
35 | /* | 23 | /* |
@@ -40,7 +28,9 @@ struct rpc_clnt { | |||
40 | atomic_t cl_users; /* number of references */ | 28 | atomic_t cl_users; /* number of references */ |
41 | struct rpc_xprt * cl_xprt; /* transport */ | 29 | struct rpc_xprt * cl_xprt; /* transport */ |
42 | struct rpc_procinfo * cl_procinfo; /* procedure info */ | 30 | struct rpc_procinfo * cl_procinfo; /* procedure info */ |
43 | u32 cl_maxproc; /* max procedure number */ | 31 | u32 cl_prog, /* RPC program number */ |
32 | cl_vers, /* RPC version number */ | ||
33 | cl_maxproc; /* max procedure number */ | ||
44 | 34 | ||
45 | char * cl_server; /* server machine name */ | 35 | char * cl_server; /* server machine name */ |
46 | char * cl_protname; /* protocol name */ | 36 | char * cl_protname; /* protocol name */ |
@@ -55,7 +45,6 @@ struct rpc_clnt { | |||
55 | cl_dead : 1;/* abandoned */ | 45 | cl_dead : 1;/* abandoned */ |
56 | 46 | ||
57 | struct rpc_rtt * cl_rtt; /* RTO estimator data */ | 47 | struct rpc_rtt * cl_rtt; /* RTO estimator data */ |
58 | struct rpc_portmap * cl_pmap; /* port mapping */ | ||
59 | 48 | ||
60 | int cl_nodelen; /* nodename length */ | 49 | int cl_nodelen; /* nodename length */ |
61 | char cl_nodename[UNX_MAXNODENAME]; | 50 | char cl_nodename[UNX_MAXNODENAME]; |
@@ -64,14 +53,8 @@ struct rpc_clnt { | |||
64 | struct dentry * cl_dentry; /* inode */ | 53 | struct dentry * cl_dentry; /* inode */ |
65 | struct rpc_clnt * cl_parent; /* Points to parent of clones */ | 54 | struct rpc_clnt * cl_parent; /* Points to parent of clones */ |
66 | struct rpc_rtt cl_rtt_default; | 55 | struct rpc_rtt cl_rtt_default; |
67 | struct rpc_portmap cl_pmap_default; | ||
68 | char cl_inline_name[32]; | 56 | char cl_inline_name[32]; |
69 | }; | 57 | }; |
70 | #define cl_timeout cl_xprt->timeout | ||
71 | #define cl_prog cl_pmap->pm_prog | ||
72 | #define cl_vers cl_pmap->pm_vers | ||
73 | #define cl_port cl_pmap->pm_port | ||
74 | #define cl_prot cl_pmap->pm_prot | ||
75 | 58 | ||
76 | /* | 59 | /* |
77 | * General RPC program info | 60 | * General RPC program info |
@@ -106,24 +89,36 @@ struct rpc_procinfo { | |||
106 | char * p_name; /* name of procedure */ | 89 | char * p_name; /* name of procedure */ |
107 | }; | 90 | }; |
108 | 91 | ||
109 | #define RPC_CONGESTED(clnt) (RPCXPRT_CONGESTED((clnt)->cl_xprt)) | ||
110 | #define RPC_PEERADDR(clnt) (&(clnt)->cl_xprt->addr) | ||
111 | |||
112 | #ifdef __KERNEL__ | 92 | #ifdef __KERNEL__ |
113 | 93 | ||
114 | struct rpc_clnt *rpc_create_client(struct rpc_xprt *xprt, char *servname, | 94 | struct rpc_create_args { |
115 | struct rpc_program *info, | 95 | int protocol; |
116 | u32 version, rpc_authflavor_t authflavor); | 96 | struct sockaddr *address; |
117 | struct rpc_clnt *rpc_new_client(struct rpc_xprt *xprt, char *servname, | 97 | size_t addrsize; |
118 | struct rpc_program *info, | 98 | struct rpc_timeout *timeout; |
119 | u32 version, rpc_authflavor_t authflavor); | 99 | char *servername; |
100 | struct rpc_program *program; | ||
101 | u32 version; | ||
102 | rpc_authflavor_t authflavor; | ||
103 | unsigned long flags; | ||
104 | }; | ||
105 | |||
106 | /* Values for "flags" field */ | ||
107 | #define RPC_CLNT_CREATE_HARDRTRY (1UL << 0) | ||
108 | #define RPC_CLNT_CREATE_INTR (1UL << 1) | ||
109 | #define RPC_CLNT_CREATE_AUTOBIND (1UL << 2) | ||
110 | #define RPC_CLNT_CREATE_ONESHOT (1UL << 3) | ||
111 | #define RPC_CLNT_CREATE_NONPRIVPORT (1UL << 4) | ||
112 | #define RPC_CLNT_CREATE_NOPING (1UL << 5) | ||
113 | |||
114 | struct rpc_clnt *rpc_create(struct rpc_create_args *args); | ||
120 | struct rpc_clnt *rpc_bind_new_program(struct rpc_clnt *, | 115 | struct rpc_clnt *rpc_bind_new_program(struct rpc_clnt *, |
121 | struct rpc_program *, int); | 116 | struct rpc_program *, int); |
122 | struct rpc_clnt *rpc_clone_client(struct rpc_clnt *); | 117 | struct rpc_clnt *rpc_clone_client(struct rpc_clnt *); |
123 | int rpc_shutdown_client(struct rpc_clnt *); | 118 | int rpc_shutdown_client(struct rpc_clnt *); |
124 | int rpc_destroy_client(struct rpc_clnt *); | 119 | int rpc_destroy_client(struct rpc_clnt *); |
125 | void rpc_release_client(struct rpc_clnt *); | 120 | void rpc_release_client(struct rpc_clnt *); |
126 | void rpc_getport(struct rpc_task *, struct rpc_clnt *); | 121 | void rpc_getport(struct rpc_task *); |
127 | int rpc_register(u32, u32, int, unsigned short, int *); | 122 | int rpc_register(u32, u32, int, unsigned short, int *); |
128 | 123 | ||
129 | void rpc_call_setup(struct rpc_task *, struct rpc_message *, int); | 124 | void rpc_call_setup(struct rpc_task *, struct rpc_message *, int); |
@@ -140,6 +135,8 @@ void rpc_setbufsize(struct rpc_clnt *, unsigned int, unsigned int); | |||
140 | size_t rpc_max_payload(struct rpc_clnt *); | 135 | size_t rpc_max_payload(struct rpc_clnt *); |
141 | void rpc_force_rebind(struct rpc_clnt *); | 136 | void rpc_force_rebind(struct rpc_clnt *); |
142 | int rpc_ping(struct rpc_clnt *clnt, int flags); | 137 | int rpc_ping(struct rpc_clnt *clnt, int flags); |
138 | size_t rpc_peeraddr(struct rpc_clnt *, struct sockaddr *, size_t); | ||
139 | char * rpc_peeraddr2str(struct rpc_clnt *, enum rpc_display_format_t); | ||
143 | 140 | ||
144 | /* | 141 | /* |
145 | * Helper function for NFSroot support | 142 | * Helper function for NFSroot support |
diff --git a/include/linux/sunrpc/rpc_pipe_fs.h b/include/linux/sunrpc/rpc_pipe_fs.h index a481472c9484..a2eb9b4a9de3 100644 --- a/include/linux/sunrpc/rpc_pipe_fs.h +++ b/include/linux/sunrpc/rpc_pipe_fs.h | |||
@@ -43,7 +43,7 @@ extern int rpc_queue_upcall(struct inode *, struct rpc_pipe_msg *); | |||
43 | 43 | ||
44 | extern struct dentry *rpc_mkdir(char *, struct rpc_clnt *); | 44 | extern struct dentry *rpc_mkdir(char *, struct rpc_clnt *); |
45 | extern int rpc_rmdir(struct dentry *); | 45 | extern int rpc_rmdir(struct dentry *); |
46 | extern struct dentry *rpc_mkpipe(char *, void *, struct rpc_pipe_ops *, int flags); | 46 | extern struct dentry *rpc_mkpipe(struct dentry *, const char *, void *, struct rpc_pipe_ops *, int flags); |
47 | extern int rpc_unlink(struct dentry *); | 47 | extern int rpc_unlink(struct dentry *); |
48 | extern struct vfsmount *rpc_get_mount(void); | 48 | extern struct vfsmount *rpc_get_mount(void); |
49 | extern void rpc_put_mount(void); | 49 | extern void rpc_put_mount(void); |
diff --git a/include/linux/sunrpc/sched.h b/include/linux/sunrpc/sched.h index 82a91bb22362..f399c138f79d 100644 --- a/include/linux/sunrpc/sched.h +++ b/include/linux/sunrpc/sched.h | |||
@@ -127,7 +127,6 @@ struct rpc_call_ops { | |||
127 | */ | 127 | */ |
128 | #define RPC_TASK_ASYNC 0x0001 /* is an async task */ | 128 | #define RPC_TASK_ASYNC 0x0001 /* is an async task */ |
129 | #define RPC_TASK_SWAPPER 0x0002 /* is swapping in/out */ | 129 | #define RPC_TASK_SWAPPER 0x0002 /* is swapping in/out */ |
130 | #define RPC_TASK_CHILD 0x0008 /* is child of other task */ | ||
131 | #define RPC_CALL_MAJORSEEN 0x0020 /* major timeout seen */ | 130 | #define RPC_CALL_MAJORSEEN 0x0020 /* major timeout seen */ |
132 | #define RPC_TASK_ROOTCREDS 0x0040 /* force root creds */ | 131 | #define RPC_TASK_ROOTCREDS 0x0040 /* force root creds */ |
133 | #define RPC_TASK_DYNAMIC 0x0080 /* task was kmalloc'ed */ | 132 | #define RPC_TASK_DYNAMIC 0x0080 /* task was kmalloc'ed */ |
@@ -136,7 +135,6 @@ struct rpc_call_ops { | |||
136 | #define RPC_TASK_NOINTR 0x0400 /* uninterruptible task */ | 135 | #define RPC_TASK_NOINTR 0x0400 /* uninterruptible task */ |
137 | 136 | ||
138 | #define RPC_IS_ASYNC(t) ((t)->tk_flags & RPC_TASK_ASYNC) | 137 | #define RPC_IS_ASYNC(t) ((t)->tk_flags & RPC_TASK_ASYNC) |
139 | #define RPC_IS_CHILD(t) ((t)->tk_flags & RPC_TASK_CHILD) | ||
140 | #define RPC_IS_SWAPPER(t) ((t)->tk_flags & RPC_TASK_SWAPPER) | 138 | #define RPC_IS_SWAPPER(t) ((t)->tk_flags & RPC_TASK_SWAPPER) |
141 | #define RPC_DO_ROOTOVERRIDE(t) ((t)->tk_flags & RPC_TASK_ROOTCREDS) | 139 | #define RPC_DO_ROOTOVERRIDE(t) ((t)->tk_flags & RPC_TASK_ROOTCREDS) |
142 | #define RPC_ASSASSINATED(t) ((t)->tk_flags & RPC_TASK_KILLED) | 140 | #define RPC_ASSASSINATED(t) ((t)->tk_flags & RPC_TASK_KILLED) |
@@ -253,7 +251,6 @@ struct rpc_task *rpc_new_task(struct rpc_clnt *, int flags, | |||
253 | const struct rpc_call_ops *ops, void *data); | 251 | const struct rpc_call_ops *ops, void *data); |
254 | struct rpc_task *rpc_run_task(struct rpc_clnt *clnt, int flags, | 252 | struct rpc_task *rpc_run_task(struct rpc_clnt *clnt, int flags, |
255 | const struct rpc_call_ops *ops, void *data); | 253 | const struct rpc_call_ops *ops, void *data); |
256 | struct rpc_task *rpc_new_child(struct rpc_clnt *, struct rpc_task *parent); | ||
257 | void rpc_init_task(struct rpc_task *task, struct rpc_clnt *clnt, | 254 | void rpc_init_task(struct rpc_task *task, struct rpc_clnt *clnt, |
258 | int flags, const struct rpc_call_ops *ops, | 255 | int flags, const struct rpc_call_ops *ops, |
259 | void *data); | 256 | void *data); |
@@ -261,8 +258,6 @@ void rpc_release_task(struct rpc_task *); | |||
261 | void rpc_exit_task(struct rpc_task *); | 258 | void rpc_exit_task(struct rpc_task *); |
262 | void rpc_killall_tasks(struct rpc_clnt *); | 259 | void rpc_killall_tasks(struct rpc_clnt *); |
263 | int rpc_execute(struct rpc_task *); | 260 | int rpc_execute(struct rpc_task *); |
264 | void rpc_run_child(struct rpc_task *parent, struct rpc_task *child, | ||
265 | rpc_action action); | ||
266 | void rpc_init_priority_wait_queue(struct rpc_wait_queue *, const char *); | 261 | void rpc_init_priority_wait_queue(struct rpc_wait_queue *, const char *); |
267 | void rpc_init_wait_queue(struct rpc_wait_queue *, const char *); | 262 | void rpc_init_wait_queue(struct rpc_wait_queue *, const char *); |
268 | void rpc_sleep_on(struct rpc_wait_queue *, struct rpc_task *, | 263 | void rpc_sleep_on(struct rpc_wait_queue *, struct rpc_task *, |
diff --git a/include/linux/sunrpc/xprt.h b/include/linux/sunrpc/xprt.h index 3a0cca255b76..bdeba8538c71 100644 --- a/include/linux/sunrpc/xprt.h +++ b/include/linux/sunrpc/xprt.h | |||
@@ -12,6 +12,7 @@ | |||
12 | #include <linux/uio.h> | 12 | #include <linux/uio.h> |
13 | #include <linux/socket.h> | 13 | #include <linux/socket.h> |
14 | #include <linux/in.h> | 14 | #include <linux/in.h> |
15 | #include <linux/kref.h> | ||
15 | #include <linux/sunrpc/sched.h> | 16 | #include <linux/sunrpc/sched.h> |
16 | #include <linux/sunrpc/xdr.h> | 17 | #include <linux/sunrpc/xdr.h> |
17 | 18 | ||
@@ -51,6 +52,14 @@ struct rpc_timeout { | |||
51 | unsigned char to_exponential; | 52 | unsigned char to_exponential; |
52 | }; | 53 | }; |
53 | 54 | ||
55 | enum rpc_display_format_t { | ||
56 | RPC_DISPLAY_ADDR = 0, | ||
57 | RPC_DISPLAY_PORT, | ||
58 | RPC_DISPLAY_PROTO, | ||
59 | RPC_DISPLAY_ALL, | ||
60 | RPC_DISPLAY_MAX, | ||
61 | }; | ||
62 | |||
54 | struct rpc_task; | 63 | struct rpc_task; |
55 | struct rpc_xprt; | 64 | struct rpc_xprt; |
56 | struct seq_file; | 65 | struct seq_file; |
@@ -103,8 +112,10 @@ struct rpc_rqst { | |||
103 | 112 | ||
104 | struct rpc_xprt_ops { | 113 | struct rpc_xprt_ops { |
105 | void (*set_buffer_size)(struct rpc_xprt *xprt, size_t sndsize, size_t rcvsize); | 114 | void (*set_buffer_size)(struct rpc_xprt *xprt, size_t sndsize, size_t rcvsize); |
115 | char * (*print_addr)(struct rpc_xprt *xprt, enum rpc_display_format_t format); | ||
106 | int (*reserve_xprt)(struct rpc_task *task); | 116 | int (*reserve_xprt)(struct rpc_task *task); |
107 | void (*release_xprt)(struct rpc_xprt *xprt, struct rpc_task *task); | 117 | void (*release_xprt)(struct rpc_xprt *xprt, struct rpc_task *task); |
118 | void (*rpcbind)(struct rpc_task *task); | ||
108 | void (*set_port)(struct rpc_xprt *xprt, unsigned short port); | 119 | void (*set_port)(struct rpc_xprt *xprt, unsigned short port); |
109 | void (*connect)(struct rpc_task *task); | 120 | void (*connect)(struct rpc_task *task); |
110 | void * (*buf_alloc)(struct rpc_task *task, size_t size); | 121 | void * (*buf_alloc)(struct rpc_task *task, size_t size); |
@@ -119,12 +130,14 @@ struct rpc_xprt_ops { | |||
119 | }; | 130 | }; |
120 | 131 | ||
121 | struct rpc_xprt { | 132 | struct rpc_xprt { |
133 | struct kref kref; /* Reference count */ | ||
122 | struct rpc_xprt_ops * ops; /* transport methods */ | 134 | struct rpc_xprt_ops * ops; /* transport methods */ |
123 | struct socket * sock; /* BSD socket layer */ | 135 | struct socket * sock; /* BSD socket layer */ |
124 | struct sock * inet; /* INET layer */ | 136 | struct sock * inet; /* INET layer */ |
125 | 137 | ||
126 | struct rpc_timeout timeout; /* timeout parms */ | 138 | struct rpc_timeout timeout; /* timeout parms */ |
127 | struct sockaddr_in addr; /* server address */ | 139 | struct sockaddr_storage addr; /* server address */ |
140 | size_t addrlen; /* size of server address */ | ||
128 | int prot; /* IP protocol */ | 141 | int prot; /* IP protocol */ |
129 | 142 | ||
130 | unsigned long cong; /* current congestion */ | 143 | unsigned long cong; /* current congestion */ |
@@ -138,6 +151,7 @@ struct rpc_xprt { | |||
138 | unsigned int tsh_size; /* size of transport specific | 151 | unsigned int tsh_size; /* size of transport specific |
139 | header */ | 152 | header */ |
140 | 153 | ||
154 | struct rpc_wait_queue binding; /* requests waiting on rpcbind */ | ||
141 | struct rpc_wait_queue sending; /* requests waiting to send */ | 155 | struct rpc_wait_queue sending; /* requests waiting to send */ |
142 | struct rpc_wait_queue resend; /* requests waiting to resend */ | 156 | struct rpc_wait_queue resend; /* requests waiting to resend */ |
143 | struct rpc_wait_queue pending; /* requests in flight */ | 157 | struct rpc_wait_queue pending; /* requests in flight */ |
@@ -205,6 +219,8 @@ struct rpc_xprt { | |||
205 | void (*old_data_ready)(struct sock *, int); | 219 | void (*old_data_ready)(struct sock *, int); |
206 | void (*old_state_change)(struct sock *); | 220 | void (*old_state_change)(struct sock *); |
207 | void (*old_write_space)(struct sock *); | 221 | void (*old_write_space)(struct sock *); |
222 | |||
223 | char * address_strings[RPC_DISPLAY_MAX]; | ||
208 | }; | 224 | }; |
209 | 225 | ||
210 | #define XPRT_LAST_FRAG (1 << 0) | 226 | #define XPRT_LAST_FRAG (1 << 0) |
@@ -217,12 +233,12 @@ struct rpc_xprt { | |||
217 | /* | 233 | /* |
218 | * Transport operations used by ULPs | 234 | * Transport operations used by ULPs |
219 | */ | 235 | */ |
220 | struct rpc_xprt * xprt_create_proto(int proto, struct sockaddr_in *addr, struct rpc_timeout *to); | ||
221 | void xprt_set_timeout(struct rpc_timeout *to, unsigned int retr, unsigned long incr); | 236 | void xprt_set_timeout(struct rpc_timeout *to, unsigned int retr, unsigned long incr); |
222 | 237 | ||
223 | /* | 238 | /* |
224 | * Generic internal transport functions | 239 | * Generic internal transport functions |
225 | */ | 240 | */ |
241 | struct rpc_xprt * xprt_create_transport(int proto, struct sockaddr *addr, size_t size, struct rpc_timeout *toparms); | ||
226 | void xprt_connect(struct rpc_task *task); | 242 | void xprt_connect(struct rpc_task *task); |
227 | void xprt_reserve(struct rpc_task *task); | 243 | void xprt_reserve(struct rpc_task *task); |
228 | int xprt_reserve_xprt(struct rpc_task *task); | 244 | int xprt_reserve_xprt(struct rpc_task *task); |
@@ -234,7 +250,8 @@ int xprt_adjust_timeout(struct rpc_rqst *req); | |||
234 | void xprt_release_xprt(struct rpc_xprt *xprt, struct rpc_task *task); | 250 | void xprt_release_xprt(struct rpc_xprt *xprt, struct rpc_task *task); |
235 | void xprt_release_xprt_cong(struct rpc_xprt *xprt, struct rpc_task *task); | 251 | void xprt_release_xprt_cong(struct rpc_xprt *xprt, struct rpc_task *task); |
236 | void xprt_release(struct rpc_task *task); | 252 | void xprt_release(struct rpc_task *task); |
237 | int xprt_destroy(struct rpc_xprt *xprt); | 253 | struct rpc_xprt * xprt_get(struct rpc_xprt *xprt); |
254 | void xprt_put(struct rpc_xprt *xprt); | ||
238 | 255 | ||
239 | static inline u32 *xprt_skip_transport_header(struct rpc_xprt *xprt, u32 *p) | 256 | static inline u32 *xprt_skip_transport_header(struct rpc_xprt *xprt, u32 *p) |
240 | { | 257 | { |
@@ -269,6 +286,8 @@ int xs_setup_tcp(struct rpc_xprt *xprt, struct rpc_timeout *to); | |||
269 | #define XPRT_CONNECTED (1) | 286 | #define XPRT_CONNECTED (1) |
270 | #define XPRT_CONNECTING (2) | 287 | #define XPRT_CONNECTING (2) |
271 | #define XPRT_CLOSE_WAIT (3) | 288 | #define XPRT_CLOSE_WAIT (3) |
289 | #define XPRT_BOUND (4) | ||
290 | #define XPRT_BINDING (5) | ||
272 | 291 | ||
273 | static inline void xprt_set_connected(struct rpc_xprt *xprt) | 292 | static inline void xprt_set_connected(struct rpc_xprt *xprt) |
274 | { | 293 | { |
@@ -312,6 +331,33 @@ static inline int xprt_test_and_set_connecting(struct rpc_xprt *xprt) | |||
312 | return test_and_set_bit(XPRT_CONNECTING, &xprt->state); | 331 | return test_and_set_bit(XPRT_CONNECTING, &xprt->state); |
313 | } | 332 | } |
314 | 333 | ||
334 | static inline void xprt_set_bound(struct rpc_xprt *xprt) | ||
335 | { | ||
336 | test_and_set_bit(XPRT_BOUND, &xprt->state); | ||
337 | } | ||
338 | |||
339 | static inline int xprt_bound(struct rpc_xprt *xprt) | ||
340 | { | ||
341 | return test_bit(XPRT_BOUND, &xprt->state); | ||
342 | } | ||
343 | |||
344 | static inline void xprt_clear_bound(struct rpc_xprt *xprt) | ||
345 | { | ||
346 | clear_bit(XPRT_BOUND, &xprt->state); | ||
347 | } | ||
348 | |||
349 | static inline void xprt_clear_binding(struct rpc_xprt *xprt) | ||
350 | { | ||
351 | smp_mb__before_clear_bit(); | ||
352 | clear_bit(XPRT_BINDING, &xprt->state); | ||
353 | smp_mb__after_clear_bit(); | ||
354 | } | ||
355 | |||
356 | static inline int xprt_test_and_set_binding(struct rpc_xprt *xprt) | ||
357 | { | ||
358 | return test_and_set_bit(XPRT_BINDING, &xprt->state); | ||
359 | } | ||
360 | |||
315 | #endif /* __KERNEL__*/ | 361 | #endif /* __KERNEL__*/ |
316 | 362 | ||
317 | #endif /* _LINUX_SUNRPC_XPRT_H */ | 363 | #endif /* _LINUX_SUNRPC_XPRT_H */ |
diff --git a/include/linux/sysctl.h b/include/linux/sysctl.h index e4b1a4d4dcf3..736ed917a4f8 100644 --- a/include/linux/sysctl.h +++ b/include/linux/sysctl.h | |||
@@ -411,6 +411,10 @@ enum | |||
411 | NET_IPV4_TCP_WORKAROUND_SIGNED_WINDOWS=115, | 411 | NET_IPV4_TCP_WORKAROUND_SIGNED_WINDOWS=115, |
412 | NET_TCP_DMA_COPYBREAK=116, | 412 | NET_TCP_DMA_COPYBREAK=116, |
413 | NET_TCP_SLOW_START_AFTER_IDLE=117, | 413 | NET_TCP_SLOW_START_AFTER_IDLE=117, |
414 | NET_CIPSOV4_CACHE_ENABLE=118, | ||
415 | NET_CIPSOV4_CACHE_BUCKET_SIZE=119, | ||
416 | NET_CIPSOV4_RBM_OPTFMT=120, | ||
417 | NET_CIPSOV4_RBM_STRICTVALID=121, | ||
414 | }; | 418 | }; |
415 | 419 | ||
416 | enum { | 420 | enum { |
@@ -552,6 +556,7 @@ enum { | |||
552 | NET_IPV6_ACCEPT_RA_RTR_PREF=20, | 556 | NET_IPV6_ACCEPT_RA_RTR_PREF=20, |
553 | NET_IPV6_RTR_PROBE_INTERVAL=21, | 557 | NET_IPV6_RTR_PROBE_INTERVAL=21, |
554 | NET_IPV6_ACCEPT_RA_RT_INFO_MAX_PLEN=22, | 558 | NET_IPV6_ACCEPT_RA_RT_INFO_MAX_PLEN=22, |
559 | NET_IPV6_PROXY_NDP=23, | ||
555 | __NET_IPV6_MAX | 560 | __NET_IPV6_MAX |
556 | }; | 561 | }; |
557 | 562 | ||
diff --git a/include/linux/writeback.h b/include/linux/writeback.h index 9e38b566d0e7..0422036af4eb 100644 --- a/include/linux/writeback.h +++ b/include/linux/writeback.h | |||
@@ -85,6 +85,7 @@ int wakeup_pdflush(long nr_pages); | |||
85 | void laptop_io_completion(void); | 85 | void laptop_io_completion(void); |
86 | void laptop_sync_completion(void); | 86 | void laptop_sync_completion(void); |
87 | void throttle_vm_writeout(void); | 87 | void throttle_vm_writeout(void); |
88 | void writeback_congestion_end(void); | ||
88 | 89 | ||
89 | /* These are exported to sysctl. */ | 90 | /* These are exported to sysctl. */ |
90 | extern int dirty_background_ratio; | 91 | extern int dirty_background_ratio; |
diff --git a/include/linux/xfrm.h b/include/linux/xfrm.h index 46a15c7a1a13..14ecd19f4cdc 100644 --- a/include/linux/xfrm.h +++ b/include/linux/xfrm.h | |||
@@ -104,6 +104,13 @@ struct xfrm_stats { | |||
104 | 104 | ||
105 | enum | 105 | enum |
106 | { | 106 | { |
107 | XFRM_POLICY_TYPE_MAIN = 0, | ||
108 | XFRM_POLICY_TYPE_SUB = 1, | ||
109 | XFRM_POLICY_TYPE_MAX = 2 | ||
110 | }; | ||
111 | |||
112 | enum | ||
113 | { | ||
107 | XFRM_POLICY_IN = 0, | 114 | XFRM_POLICY_IN = 0, |
108 | XFRM_POLICY_OUT = 1, | 115 | XFRM_POLICY_OUT = 1, |
109 | XFRM_POLICY_FWD = 2, | 116 | XFRM_POLICY_FWD = 2, |
@@ -120,7 +127,9 @@ enum | |||
120 | 127 | ||
121 | #define XFRM_MODE_TRANSPORT 0 | 128 | #define XFRM_MODE_TRANSPORT 0 |
122 | #define XFRM_MODE_TUNNEL 1 | 129 | #define XFRM_MODE_TUNNEL 1 |
123 | #define XFRM_MODE_MAX 2 | 130 | #define XFRM_MODE_ROUTEOPTIMIZATION 2 |
131 | #define XFRM_MODE_IN_TRIGGER 3 | ||
132 | #define XFRM_MODE_MAX 4 | ||
124 | 133 | ||
125 | /* Netlink configuration messages. */ | 134 | /* Netlink configuration messages. */ |
126 | enum { | 135 | enum { |
@@ -164,6 +173,10 @@ enum { | |||
164 | #define XFRM_MSG_NEWAE XFRM_MSG_NEWAE | 173 | #define XFRM_MSG_NEWAE XFRM_MSG_NEWAE |
165 | XFRM_MSG_GETAE, | 174 | XFRM_MSG_GETAE, |
166 | #define XFRM_MSG_GETAE XFRM_MSG_GETAE | 175 | #define XFRM_MSG_GETAE XFRM_MSG_GETAE |
176 | |||
177 | XFRM_MSG_REPORT, | ||
178 | #define XFRM_MSG_REPORT XFRM_MSG_REPORT | ||
179 | |||
167 | __XFRM_MSG_MAX | 180 | __XFRM_MSG_MAX |
168 | }; | 181 | }; |
169 | #define XFRM_MSG_MAX (__XFRM_MSG_MAX - 1) | 182 | #define XFRM_MSG_MAX (__XFRM_MSG_MAX - 1) |
@@ -217,6 +230,12 @@ enum xfrm_ae_ftype_t { | |||
217 | #define XFRM_AE_MAX (__XFRM_AE_MAX - 1) | 230 | #define XFRM_AE_MAX (__XFRM_AE_MAX - 1) |
218 | }; | 231 | }; |
219 | 232 | ||
233 | struct xfrm_userpolicy_type { | ||
234 | __u8 type; | ||
235 | __u16 reserved1; | ||
236 | __u8 reserved2; | ||
237 | }; | ||
238 | |||
220 | /* Netlink message attributes. */ | 239 | /* Netlink message attributes. */ |
221 | enum xfrm_attr_type_t { | 240 | enum xfrm_attr_type_t { |
222 | XFRMA_UNSPEC, | 241 | XFRMA_UNSPEC, |
@@ -232,6 +251,10 @@ enum xfrm_attr_type_t { | |||
232 | XFRMA_REPLAY_VAL, | 251 | XFRMA_REPLAY_VAL, |
233 | XFRMA_REPLAY_THRESH, | 252 | XFRMA_REPLAY_THRESH, |
234 | XFRMA_ETIMER_THRESH, | 253 | XFRMA_ETIMER_THRESH, |
254 | XFRMA_SRCADDR, /* xfrm_address_t */ | ||
255 | XFRMA_COADDR, /* xfrm_address_t */ | ||
256 | XFRMA_LASTUSED, | ||
257 | XFRMA_POLICY_TYPE, /* struct xfrm_userpolicy_type */ | ||
235 | __XFRMA_MAX | 258 | __XFRMA_MAX |
236 | 259 | ||
237 | #define XFRMA_MAX (__XFRMA_MAX - 1) | 260 | #define XFRMA_MAX (__XFRMA_MAX - 1) |
@@ -247,12 +270,13 @@ struct xfrm_usersa_info { | |||
247 | __u32 seq; | 270 | __u32 seq; |
248 | __u32 reqid; | 271 | __u32 reqid; |
249 | __u16 family; | 272 | __u16 family; |
250 | __u8 mode; /* 0=transport,1=tunnel */ | 273 | __u8 mode; /* XFRM_MODE_xxx */ |
251 | __u8 replay_window; | 274 | __u8 replay_window; |
252 | __u8 flags; | 275 | __u8 flags; |
253 | #define XFRM_STATE_NOECN 1 | 276 | #define XFRM_STATE_NOECN 1 |
254 | #define XFRM_STATE_DECAP_DSCP 2 | 277 | #define XFRM_STATE_DECAP_DSCP 2 |
255 | #define XFRM_STATE_NOPMTUDISC 4 | 278 | #define XFRM_STATE_NOPMTUDISC 4 |
279 | #define XFRM_STATE_WILDRECV 8 | ||
256 | }; | 280 | }; |
257 | 281 | ||
258 | struct xfrm_usersa_id { | 282 | struct xfrm_usersa_id { |
@@ -319,12 +343,18 @@ struct xfrm_usersa_flush { | |||
319 | __u8 proto; | 343 | __u8 proto; |
320 | }; | 344 | }; |
321 | 345 | ||
346 | struct xfrm_user_report { | ||
347 | __u8 proto; | ||
348 | struct xfrm_selector sel; | ||
349 | }; | ||
350 | |||
322 | #ifndef __KERNEL__ | 351 | #ifndef __KERNEL__ |
323 | /* backwards compatibility for userspace */ | 352 | /* backwards compatibility for userspace */ |
324 | #define XFRMGRP_ACQUIRE 1 | 353 | #define XFRMGRP_ACQUIRE 1 |
325 | #define XFRMGRP_EXPIRE 2 | 354 | #define XFRMGRP_EXPIRE 2 |
326 | #define XFRMGRP_SA 4 | 355 | #define XFRMGRP_SA 4 |
327 | #define XFRMGRP_POLICY 8 | 356 | #define XFRMGRP_POLICY 8 |
357 | #define XFRMGRP_REPORT 0x10 | ||
328 | #endif | 358 | #endif |
329 | 359 | ||
330 | enum xfrm_nlgroups { | 360 | enum xfrm_nlgroups { |
@@ -340,6 +370,8 @@ enum xfrm_nlgroups { | |||
340 | #define XFRMNLGRP_POLICY XFRMNLGRP_POLICY | 370 | #define XFRMNLGRP_POLICY XFRMNLGRP_POLICY |
341 | XFRMNLGRP_AEVENTS, | 371 | XFRMNLGRP_AEVENTS, |
342 | #define XFRMNLGRP_AEVENTS XFRMNLGRP_AEVENTS | 372 | #define XFRMNLGRP_AEVENTS XFRMNLGRP_AEVENTS |
373 | XFRMNLGRP_REPORT, | ||
374 | #define XFRMNLGRP_REPORT XFRMNLGRP_REPORT | ||
343 | __XFRMNLGRP_MAX | 375 | __XFRMNLGRP_MAX |
344 | }; | 376 | }; |
345 | #define XFRMNLGRP_MAX (__XFRMNLGRP_MAX - 1) | 377 | #define XFRMNLGRP_MAX (__XFRMNLGRP_MAX - 1) |
diff --git a/include/net/act_api.h b/include/net/act_api.h index 11e9eaf79f5a..8b06c2f3657f 100644 --- a/include/net/act_api.h +++ b/include/net/act_api.h | |||
@@ -8,70 +8,110 @@ | |||
8 | #include <net/sch_generic.h> | 8 | #include <net/sch_generic.h> |
9 | #include <net/pkt_sched.h> | 9 | #include <net/pkt_sched.h> |
10 | 10 | ||
11 | #define tca_gen(name) \ | 11 | struct tcf_common { |
12 | struct tcf_##name *next; \ | 12 | struct tcf_common *tcfc_next; |
13 | u32 index; \ | 13 | u32 tcfc_index; |
14 | int refcnt; \ | 14 | int tcfc_refcnt; |
15 | int bindcnt; \ | 15 | int tcfc_bindcnt; |
16 | u32 capab; \ | 16 | u32 tcfc_capab; |
17 | int action; \ | 17 | int tcfc_action; |
18 | struct tcf_t tm; \ | 18 | struct tcf_t tcfc_tm; |
19 | struct gnet_stats_basic bstats; \ | 19 | struct gnet_stats_basic tcfc_bstats; |
20 | struct gnet_stats_queue qstats; \ | 20 | struct gnet_stats_queue tcfc_qstats; |
21 | struct gnet_stats_rate_est rate_est; \ | 21 | struct gnet_stats_rate_est tcfc_rate_est; |
22 | spinlock_t *stats_lock; \ | 22 | spinlock_t *tcfc_stats_lock; |
23 | spinlock_t lock | 23 | spinlock_t tcfc_lock; |
24 | 24 | }; | |
25 | struct tcf_police | 25 | #define tcf_next common.tcfc_next |
26 | { | 26 | #define tcf_index common.tcfc_index |
27 | tca_gen(police); | 27 | #define tcf_refcnt common.tcfc_refcnt |
28 | int result; | 28 | #define tcf_bindcnt common.tcfc_bindcnt |
29 | u32 ewma_rate; | 29 | #define tcf_capab common.tcfc_capab |
30 | u32 burst; | 30 | #define tcf_action common.tcfc_action |
31 | u32 mtu; | 31 | #define tcf_tm common.tcfc_tm |
32 | u32 toks; | 32 | #define tcf_bstats common.tcfc_bstats |
33 | u32 ptoks; | 33 | #define tcf_qstats common.tcfc_qstats |
34 | psched_time_t t_c; | 34 | #define tcf_rate_est common.tcfc_rate_est |
35 | struct qdisc_rate_table *R_tab; | 35 | #define tcf_stats_lock common.tcfc_stats_lock |
36 | struct qdisc_rate_table *P_tab; | 36 | #define tcf_lock common.tcfc_lock |
37 | |||
38 | struct tcf_police { | ||
39 | struct tcf_common common; | ||
40 | int tcfp_result; | ||
41 | u32 tcfp_ewma_rate; | ||
42 | u32 tcfp_burst; | ||
43 | u32 tcfp_mtu; | ||
44 | u32 tcfp_toks; | ||
45 | u32 tcfp_ptoks; | ||
46 | psched_time_t tcfp_t_c; | ||
47 | struct qdisc_rate_table *tcfp_R_tab; | ||
48 | struct qdisc_rate_table *tcfp_P_tab; | ||
37 | }; | 49 | }; |
50 | #define to_police(pc) \ | ||
51 | container_of(pc, struct tcf_police, common) | ||
52 | |||
53 | struct tcf_hashinfo { | ||
54 | struct tcf_common **htab; | ||
55 | unsigned int hmask; | ||
56 | rwlock_t *lock; | ||
57 | }; | ||
58 | |||
59 | static inline unsigned int tcf_hash(u32 index, unsigned int hmask) | ||
60 | { | ||
61 | return index & hmask; | ||
62 | } | ||
38 | 63 | ||
39 | #ifdef CONFIG_NET_CLS_ACT | 64 | #ifdef CONFIG_NET_CLS_ACT |
40 | 65 | ||
41 | #define ACT_P_CREATED 1 | 66 | #define ACT_P_CREATED 1 |
42 | #define ACT_P_DELETED 1 | 67 | #define ACT_P_DELETED 1 |
43 | 68 | ||
44 | struct tcf_act_hdr | 69 | struct tcf_act_hdr { |
45 | { | 70 | struct tcf_common common; |
46 | tca_gen(act_hdr); | ||
47 | }; | 71 | }; |
48 | 72 | ||
49 | struct tc_action | 73 | struct tc_action { |
50 | { | 74 | void *priv; |
51 | void *priv; | 75 | struct tc_action_ops *ops; |
52 | struct tc_action_ops *ops; | 76 | __u32 type; /* for backward compat(TCA_OLD_COMPAT) */ |
53 | __u32 type; /* for backward compat(TCA_OLD_COMPAT) */ | 77 | __u32 order; |
54 | __u32 order; | 78 | struct tc_action *next; |
55 | struct tc_action *next; | ||
56 | }; | 79 | }; |
57 | 80 | ||
58 | #define TCA_CAP_NONE 0 | 81 | #define TCA_CAP_NONE 0 |
59 | struct tc_action_ops | 82 | struct tc_action_ops { |
60 | { | ||
61 | struct tc_action_ops *next; | 83 | struct tc_action_ops *next; |
84 | struct tcf_hashinfo *hinfo; | ||
62 | char kind[IFNAMSIZ]; | 85 | char kind[IFNAMSIZ]; |
63 | __u32 type; /* TBD to match kind */ | 86 | __u32 type; /* TBD to match kind */ |
64 | __u32 capab; /* capabilities includes 4 bit version */ | 87 | __u32 capab; /* capabilities includes 4 bit version */ |
65 | struct module *owner; | 88 | struct module *owner; |
66 | int (*act)(struct sk_buff *, struct tc_action *, struct tcf_result *); | 89 | int (*act)(struct sk_buff *, struct tc_action *, struct tcf_result *); |
67 | int (*get_stats)(struct sk_buff *, struct tc_action *); | 90 | int (*get_stats)(struct sk_buff *, struct tc_action *); |
68 | int (*dump)(struct sk_buff *, struct tc_action *,int , int); | 91 | int (*dump)(struct sk_buff *, struct tc_action *, int, int); |
69 | int (*cleanup)(struct tc_action *, int bind); | 92 | int (*cleanup)(struct tc_action *, int bind); |
70 | int (*lookup)(struct tc_action *, u32 ); | 93 | int (*lookup)(struct tc_action *, u32); |
71 | int (*init)(struct rtattr *,struct rtattr *,struct tc_action *, int , int ); | 94 | int (*init)(struct rtattr *, struct rtattr *, struct tc_action *, int , int); |
72 | int (*walk)(struct sk_buff *, struct netlink_callback *, int , struct tc_action *); | 95 | int (*walk)(struct sk_buff *, struct netlink_callback *, int, struct tc_action *); |
73 | }; | 96 | }; |
74 | 97 | ||
98 | extern struct tcf_common *tcf_hash_lookup(u32 index, | ||
99 | struct tcf_hashinfo *hinfo); | ||
100 | extern void tcf_hash_destroy(struct tcf_common *p, struct tcf_hashinfo *hinfo); | ||
101 | extern int tcf_hash_release(struct tcf_common *p, int bind, | ||
102 | struct tcf_hashinfo *hinfo); | ||
103 | extern int tcf_generic_walker(struct sk_buff *skb, struct netlink_callback *cb, | ||
104 | int type, struct tc_action *a); | ||
105 | extern u32 tcf_hash_new_index(u32 *idx_gen, struct tcf_hashinfo *hinfo); | ||
106 | extern int tcf_hash_search(struct tc_action *a, u32 index); | ||
107 | extern struct tcf_common *tcf_hash_check(u32 index, struct tc_action *a, | ||
108 | int bind, struct tcf_hashinfo *hinfo); | ||
109 | extern struct tcf_common *tcf_hash_create(u32 index, struct rtattr *est, | ||
110 | struct tc_action *a, int size, | ||
111 | int bind, u32 *idx_gen, | ||
112 | struct tcf_hashinfo *hinfo); | ||
113 | extern void tcf_hash_insert(struct tcf_common *p, struct tcf_hashinfo *hinfo); | ||
114 | |||
75 | extern int tcf_register_action(struct tc_action_ops *a); | 115 | extern int tcf_register_action(struct tc_action_ops *a); |
76 | extern int tcf_unregister_action(struct tc_action_ops *a); | 116 | extern int tcf_unregister_action(struct tc_action_ops *a); |
77 | extern void tcf_action_destroy(struct tc_action *a, int bind); | 117 | extern void tcf_action_destroy(struct tc_action *a, int bind); |
@@ -96,17 +136,17 @@ tcf_police_release(struct tcf_police *p, int bind) | |||
96 | int ret = 0; | 136 | int ret = 0; |
97 | #ifdef CONFIG_NET_CLS_ACT | 137 | #ifdef CONFIG_NET_CLS_ACT |
98 | if (p) { | 138 | if (p) { |
99 | if (bind) { | 139 | if (bind) |
100 | p->bindcnt--; | 140 | p->tcf_bindcnt--; |
101 | } | 141 | |
102 | p->refcnt--; | 142 | p->tcf_refcnt--; |
103 | if (p->refcnt <= 0 && !p->bindcnt) { | 143 | if (p->tcf_refcnt <= 0 && !p->tcf_bindcnt) { |
104 | tcf_police_destroy(p); | 144 | tcf_police_destroy(p); |
105 | ret = 1; | 145 | ret = 1; |
106 | } | 146 | } |
107 | } | 147 | } |
108 | #else | 148 | #else |
109 | if (p && --p->refcnt == 0) | 149 | if (p && --p->tcf_refcnt == 0) |
110 | tcf_police_destroy(p); | 150 | tcf_police_destroy(p); |
111 | 151 | ||
112 | #endif /* CONFIG_NET_CLS_ACT */ | 152 | #endif /* CONFIG_NET_CLS_ACT */ |
diff --git a/include/net/act_generic.h b/include/net/act_generic.h deleted file mode 100644 index c9daa7e52300..000000000000 --- a/include/net/act_generic.h +++ /dev/null | |||
@@ -1,142 +0,0 @@ | |||
1 | /* | ||
2 | * include/net/act_generic.h | ||
3 | * | ||
4 | */ | ||
5 | #ifndef _NET_ACT_GENERIC_H | ||
6 | #define _NET_ACT_GENERIC_H | ||
7 | static inline int tcf_defact_release(struct tcf_defact *p, int bind) | ||
8 | { | ||
9 | int ret = 0; | ||
10 | if (p) { | ||
11 | if (bind) { | ||
12 | p->bindcnt--; | ||
13 | } | ||
14 | p->refcnt--; | ||
15 | if (p->bindcnt <= 0 && p->refcnt <= 0) { | ||
16 | kfree(p->defdata); | ||
17 | tcf_hash_destroy(p); | ||
18 | ret = 1; | ||
19 | } | ||
20 | } | ||
21 | return ret; | ||
22 | } | ||
23 | |||
24 | static inline int | ||
25 | alloc_defdata(struct tcf_defact *p, u32 datalen, void *defdata) | ||
26 | { | ||
27 | p->defdata = kmalloc(datalen, GFP_KERNEL); | ||
28 | if (p->defdata == NULL) | ||
29 | return -ENOMEM; | ||
30 | p->datalen = datalen; | ||
31 | memcpy(p->defdata, defdata, datalen); | ||
32 | return 0; | ||
33 | } | ||
34 | |||
35 | static inline int | ||
36 | realloc_defdata(struct tcf_defact *p, u32 datalen, void *defdata) | ||
37 | { | ||
38 | /* safer to be just brute force for now */ | ||
39 | kfree(p->defdata); | ||
40 | return alloc_defdata(p, datalen, defdata); | ||
41 | } | ||
42 | |||
43 | static inline int | ||
44 | tcf_defact_init(struct rtattr *rta, struct rtattr *est, | ||
45 | struct tc_action *a, int ovr, int bind) | ||
46 | { | ||
47 | struct rtattr *tb[TCA_DEF_MAX]; | ||
48 | struct tc_defact *parm; | ||
49 | struct tcf_defact *p; | ||
50 | void *defdata; | ||
51 | u32 datalen = 0; | ||
52 | int ret = 0; | ||
53 | |||
54 | if (rta == NULL || rtattr_parse_nested(tb, TCA_DEF_MAX, rta) < 0) | ||
55 | return -EINVAL; | ||
56 | |||
57 | if (tb[TCA_DEF_PARMS - 1] == NULL || | ||
58 | RTA_PAYLOAD(tb[TCA_DEF_PARMS - 1]) < sizeof(*parm)) | ||
59 | return -EINVAL; | ||
60 | |||
61 | parm = RTA_DATA(tb[TCA_DEF_PARMS - 1]); | ||
62 | defdata = RTA_DATA(tb[TCA_DEF_DATA - 1]); | ||
63 | if (defdata == NULL) | ||
64 | return -EINVAL; | ||
65 | |||
66 | datalen = RTA_PAYLOAD(tb[TCA_DEF_DATA - 1]); | ||
67 | if (datalen <= 0) | ||
68 | return -EINVAL; | ||
69 | |||
70 | p = tcf_hash_check(parm->index, a, ovr, bind); | ||
71 | if (p == NULL) { | ||
72 | p = tcf_hash_create(parm->index, est, a, sizeof(*p), ovr, bind); | ||
73 | if (p == NULL) | ||
74 | return -ENOMEM; | ||
75 | |||
76 | ret = alloc_defdata(p, datalen, defdata); | ||
77 | if (ret < 0) { | ||
78 | kfree(p); | ||
79 | return ret; | ||
80 | } | ||
81 | ret = ACT_P_CREATED; | ||
82 | } else { | ||
83 | if (!ovr) { | ||
84 | tcf_defact_release(p, bind); | ||
85 | return -EEXIST; | ||
86 | } | ||
87 | realloc_defdata(p, datalen, defdata); | ||
88 | } | ||
89 | |||
90 | spin_lock_bh(&p->lock); | ||
91 | p->action = parm->action; | ||
92 | spin_unlock_bh(&p->lock); | ||
93 | if (ret == ACT_P_CREATED) | ||
94 | tcf_hash_insert(p); | ||
95 | return ret; | ||
96 | } | ||
97 | |||
98 | static inline int tcf_defact_cleanup(struct tc_action *a, int bind) | ||
99 | { | ||
100 | struct tcf_defact *p = PRIV(a, defact); | ||
101 | |||
102 | if (p != NULL) | ||
103 | return tcf_defact_release(p, bind); | ||
104 | return 0; | ||
105 | } | ||
106 | |||
107 | static inline int | ||
108 | tcf_defact_dump(struct sk_buff *skb, struct tc_action *a, int bind, int ref) | ||
109 | { | ||
110 | unsigned char *b = skb->tail; | ||
111 | struct tc_defact opt; | ||
112 | struct tcf_defact *p = PRIV(a, defact); | ||
113 | struct tcf_t t; | ||
114 | |||
115 | opt.index = p->index; | ||
116 | opt.refcnt = p->refcnt - ref; | ||
117 | opt.bindcnt = p->bindcnt - bind; | ||
118 | opt.action = p->action; | ||
119 | RTA_PUT(skb, TCA_DEF_PARMS, sizeof(opt), &opt); | ||
120 | RTA_PUT(skb, TCA_DEF_DATA, p->datalen, p->defdata); | ||
121 | t.install = jiffies_to_clock_t(jiffies - p->tm.install); | ||
122 | t.lastuse = jiffies_to_clock_t(jiffies - p->tm.lastuse); | ||
123 | t.expires = jiffies_to_clock_t(p->tm.expires); | ||
124 | RTA_PUT(skb, TCA_DEF_TM, sizeof(t), &t); | ||
125 | return skb->len; | ||
126 | |||
127 | rtattr_failure: | ||
128 | skb_trim(skb, b - skb->data); | ||
129 | return -1; | ||
130 | } | ||
131 | |||
132 | #define tca_use_default_ops \ | ||
133 | .dump = tcf_defact_dump, \ | ||
134 | .cleanup = tcf_defact_cleanup, \ | ||
135 | .init = tcf_defact_init, \ | ||
136 | .walk = tcf_generic_walker, \ | ||
137 | |||
138 | #define tca_use_default_defines(name) \ | ||
139 | static u32 idx_gen; \ | ||
140 | static struct tcf_defact *tcf_##name_ht[MY_TAB_SIZE]; \ | ||
141 | static DEFINE_RWLOCK(##name_lock); | ||
142 | #endif /* _NET_ACT_GENERIC_H */ | ||
diff --git a/include/net/addrconf.h b/include/net/addrconf.h index 3d71251b3eca..44f1b673f916 100644 --- a/include/net/addrconf.h +++ b/include/net/addrconf.h | |||
@@ -61,6 +61,9 @@ extern int addrconf_set_dstaddr(void __user *arg); | |||
61 | extern int ipv6_chk_addr(struct in6_addr *addr, | 61 | extern int ipv6_chk_addr(struct in6_addr *addr, |
62 | struct net_device *dev, | 62 | struct net_device *dev, |
63 | int strict); | 63 | int strict); |
64 | #ifdef CONFIG_IPV6_MIP6 | ||
65 | extern int ipv6_chk_home_addr(struct in6_addr *addr); | ||
66 | #endif | ||
64 | extern struct inet6_ifaddr * ipv6_get_ifaddr(struct in6_addr *addr, | 67 | extern struct inet6_ifaddr * ipv6_get_ifaddr(struct in6_addr *addr, |
65 | struct net_device *dev, | 68 | struct net_device *dev, |
66 | int strict); | 69 | int strict); |
@@ -126,20 +129,18 @@ extern int unregister_inet6addr_notifier(struct notifier_block *nb); | |||
126 | static inline struct inet6_dev * | 129 | static inline struct inet6_dev * |
127 | __in6_dev_get(struct net_device *dev) | 130 | __in6_dev_get(struct net_device *dev) |
128 | { | 131 | { |
129 | return (struct inet6_dev *)dev->ip6_ptr; | 132 | return rcu_dereference(dev->ip6_ptr); |
130 | } | 133 | } |
131 | 134 | ||
132 | extern rwlock_t addrconf_lock; | ||
133 | |||
134 | static inline struct inet6_dev * | 135 | static inline struct inet6_dev * |
135 | in6_dev_get(struct net_device *dev) | 136 | in6_dev_get(struct net_device *dev) |
136 | { | 137 | { |
137 | struct inet6_dev *idev = NULL; | 138 | struct inet6_dev *idev = NULL; |
138 | read_lock(&addrconf_lock); | 139 | rcu_read_lock(); |
139 | idev = dev->ip6_ptr; | 140 | idev = __in6_dev_get(dev); |
140 | if (idev) | 141 | if (idev) |
141 | atomic_inc(&idev->refcnt); | 142 | atomic_inc(&idev->refcnt); |
142 | read_unlock(&addrconf_lock); | 143 | rcu_read_unlock(); |
143 | return idev; | 144 | return idev; |
144 | } | 145 | } |
145 | 146 | ||
diff --git a/include/net/cipso_ipv4.h b/include/net/cipso_ipv4.h new file mode 100644 index 000000000000..59406e0dc5b2 --- /dev/null +++ b/include/net/cipso_ipv4.h | |||
@@ -0,0 +1,246 @@ | |||
1 | /* | ||
2 | * CIPSO - Commercial IP Security Option | ||
3 | * | ||
4 | * This is an implementation of the CIPSO 2.2 protocol as specified in | ||
5 | * draft-ietf-cipso-ipsecurity-01.txt with additional tag types as found in | ||
6 | * FIPS-188, copies of both documents can be found in the Documentation | ||
7 | * directory. While CIPSO never became a full IETF RFC standard many vendors | ||
8 | * have chosen to adopt the protocol and over the years it has become a | ||
9 | * de-facto standard for labeled networking. | ||
10 | * | ||
11 | * Author: Paul Moore <paul.moore@hp.com> | ||
12 | * | ||
13 | */ | ||
14 | |||
15 | /* | ||
16 | * (c) Copyright Hewlett-Packard Development Company, L.P., 2006 | ||
17 | * | ||
18 | * This program is free software; you can redistribute it and/or modify | ||
19 | * it under the terms of the GNU General Public License as published by | ||
20 | * the Free Software Foundation; either version 2 of the License, or | ||
21 | * (at your option) any later version. | ||
22 | * | ||
23 | * This program is distributed in the hope that it will be useful, | ||
24 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
25 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See | ||
26 | * the GNU General Public License for more details. | ||
27 | * | ||
28 | * You should have received a copy of the GNU General Public License | ||
29 | * along with this program; if not, write to the Free Software | ||
30 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
31 | * | ||
32 | */ | ||
33 | |||
34 | #ifndef _CIPSO_IPV4_H | ||
35 | #define _CIPSO_IPV4_H | ||
36 | |||
37 | #include <linux/types.h> | ||
38 | #include <linux/rcupdate.h> | ||
39 | #include <linux/list.h> | ||
40 | #include <linux/net.h> | ||
41 | #include <linux/skbuff.h> | ||
42 | #include <net/netlabel.h> | ||
43 | |||
44 | /* known doi values */ | ||
45 | #define CIPSO_V4_DOI_UNKNOWN 0x00000000 | ||
46 | |||
47 | /* tag types */ | ||
48 | #define CIPSO_V4_TAG_INVALID 0 | ||
49 | #define CIPSO_V4_TAG_RBITMAP 1 | ||
50 | #define CIPSO_V4_TAG_ENUM 2 | ||
51 | #define CIPSO_V4_TAG_RANGE 5 | ||
52 | #define CIPSO_V4_TAG_PBITMAP 6 | ||
53 | #define CIPSO_V4_TAG_FREEFORM 7 | ||
54 | |||
55 | /* doi mapping types */ | ||
56 | #define CIPSO_V4_MAP_UNKNOWN 0 | ||
57 | #define CIPSO_V4_MAP_STD 1 | ||
58 | #define CIPSO_V4_MAP_PASS 2 | ||
59 | |||
60 | /* limits */ | ||
61 | #define CIPSO_V4_MAX_REM_LVLS 256 | ||
62 | #define CIPSO_V4_INV_LVL 0x80000000 | ||
63 | #define CIPSO_V4_MAX_LOC_LVLS (CIPSO_V4_INV_LVL - 1) | ||
64 | #define CIPSO_V4_MAX_REM_CATS 65536 | ||
65 | #define CIPSO_V4_INV_CAT 0x80000000 | ||
66 | #define CIPSO_V4_MAX_LOC_CATS (CIPSO_V4_INV_CAT - 1) | ||
67 | |||
68 | /* | ||
69 | * CIPSO DOI definitions | ||
70 | */ | ||
71 | |||
72 | /* DOI definition struct */ | ||
73 | #define CIPSO_V4_TAG_MAXCNT 5 | ||
74 | struct cipso_v4_doi { | ||
75 | u32 doi; | ||
76 | u32 type; | ||
77 | union { | ||
78 | struct cipso_v4_std_map_tbl *std; | ||
79 | } map; | ||
80 | u8 tags[CIPSO_V4_TAG_MAXCNT]; | ||
81 | |||
82 | u32 valid; | ||
83 | struct list_head list; | ||
84 | struct rcu_head rcu; | ||
85 | struct list_head dom_list; | ||
86 | }; | ||
87 | |||
88 | /* Standard CIPSO mapping table */ | ||
89 | /* NOTE: the highest order bit (i.e. 0x80000000) is an 'invalid' flag, if the | ||
90 | * bit is set then consider that value as unspecified, meaning the | ||
91 | * mapping for that particular level/category is invalid */ | ||
92 | struct cipso_v4_std_map_tbl { | ||
93 | struct { | ||
94 | u32 *cipso; | ||
95 | u32 *local; | ||
96 | u32 cipso_size; | ||
97 | u32 local_size; | ||
98 | } lvl; | ||
99 | struct { | ||
100 | u32 *cipso; | ||
101 | u32 *local; | ||
102 | u32 cipso_size; | ||
103 | u32 local_size; | ||
104 | } cat; | ||
105 | }; | ||
106 | |||
107 | /* | ||
108 | * Sysctl Variables | ||
109 | */ | ||
110 | |||
111 | #ifdef CONFIG_NETLABEL | ||
112 | extern int cipso_v4_cache_enabled; | ||
113 | extern int cipso_v4_cache_bucketsize; | ||
114 | extern int cipso_v4_rbm_optfmt; | ||
115 | extern int cipso_v4_rbm_strictvalid; | ||
116 | #endif | ||
117 | |||
118 | /* | ||
119 | * Helper Functions | ||
120 | */ | ||
121 | |||
122 | #define CIPSO_V4_OPTEXIST(x) (IPCB(x)->opt.cipso != 0) | ||
123 | #define CIPSO_V4_OPTPTR(x) ((x)->nh.raw + IPCB(x)->opt.cipso) | ||
124 | |||
125 | /* | ||
126 | * DOI List Functions | ||
127 | */ | ||
128 | |||
129 | #ifdef CONFIG_NETLABEL | ||
130 | int cipso_v4_doi_add(struct cipso_v4_doi *doi_def); | ||
131 | int cipso_v4_doi_remove(u32 doi, void (*callback) (struct rcu_head * head)); | ||
132 | struct cipso_v4_doi *cipso_v4_doi_getdef(u32 doi); | ||
133 | struct sk_buff *cipso_v4_doi_dump_all(size_t headroom); | ||
134 | struct sk_buff *cipso_v4_doi_dump(u32 doi, size_t headroom); | ||
135 | int cipso_v4_doi_domhsh_add(struct cipso_v4_doi *doi_def, const char *domain); | ||
136 | int cipso_v4_doi_domhsh_remove(struct cipso_v4_doi *doi_def, | ||
137 | const char *domain); | ||
138 | #else | ||
139 | static inline int cipso_v4_doi_add(struct cipso_v4_doi *doi_def) | ||
140 | { | ||
141 | return -ENOSYS; | ||
142 | } | ||
143 | |||
144 | static inline int cipso_v4_doi_remove(u32 doi, | ||
145 | void (*callback) (struct rcu_head * head)) | ||
146 | { | ||
147 | return 0; | ||
148 | } | ||
149 | |||
150 | static inline struct cipso_v4_doi *cipso_v4_doi_getdef(u32 doi) | ||
151 | { | ||
152 | return NULL; | ||
153 | } | ||
154 | |||
155 | static inline struct sk_buff *cipso_v4_doi_dump_all(size_t headroom) | ||
156 | { | ||
157 | return NULL; | ||
158 | } | ||
159 | |||
160 | static inline struct sk_buff *cipso_v4_doi_dump(u32 doi, size_t headroom) | ||
161 | { | ||
162 | return NULL; | ||
163 | } | ||
164 | |||
165 | static inline int cipso_v4_doi_domhsh_add(struct cipso_v4_doi *doi_def, | ||
166 | const char *domain) | ||
167 | { | ||
168 | return -ENOSYS; | ||
169 | } | ||
170 | |||
171 | static inline int cipso_v4_doi_domhsh_remove(struct cipso_v4_doi *doi_def, | ||
172 | const char *domain) | ||
173 | { | ||
174 | return 0; | ||
175 | } | ||
176 | #endif /* CONFIG_NETLABEL */ | ||
177 | |||
178 | /* | ||
179 | * Label Mapping Cache Functions | ||
180 | */ | ||
181 | |||
182 | #ifdef CONFIG_NETLABEL | ||
183 | void cipso_v4_cache_invalidate(void); | ||
184 | int cipso_v4_cache_add(const struct sk_buff *skb, | ||
185 | const struct netlbl_lsm_secattr *secattr); | ||
186 | #else | ||
187 | static inline void cipso_v4_cache_invalidate(void) | ||
188 | { | ||
189 | return; | ||
190 | } | ||
191 | |||
192 | static inline int cipso_v4_cache_add(const struct sk_buff *skb, | ||
193 | const struct netlbl_lsm_secattr *secattr) | ||
194 | { | ||
195 | return 0; | ||
196 | } | ||
197 | #endif /* CONFIG_NETLABEL */ | ||
198 | |||
199 | /* | ||
200 | * Protocol Handling Functions | ||
201 | */ | ||
202 | |||
203 | #ifdef CONFIG_NETLABEL | ||
204 | void cipso_v4_error(struct sk_buff *skb, int error, u32 gateway); | ||
205 | int cipso_v4_socket_setattr(const struct socket *sock, | ||
206 | const struct cipso_v4_doi *doi_def, | ||
207 | const struct netlbl_lsm_secattr *secattr); | ||
208 | int cipso_v4_socket_getattr(const struct socket *sock, | ||
209 | struct netlbl_lsm_secattr *secattr); | ||
210 | int cipso_v4_skbuff_getattr(const struct sk_buff *skb, | ||
211 | struct netlbl_lsm_secattr *secattr); | ||
212 | int cipso_v4_validate(unsigned char **option); | ||
213 | #else | ||
214 | static inline void cipso_v4_error(struct sk_buff *skb, | ||
215 | int error, | ||
216 | u32 gateway) | ||
217 | { | ||
218 | return; | ||
219 | } | ||
220 | |||
221 | static inline int cipso_v4_socket_setattr(const struct socket *sock, | ||
222 | const struct cipso_v4_doi *doi_def, | ||
223 | const struct netlbl_lsm_secattr *secattr) | ||
224 | { | ||
225 | return -ENOSYS; | ||
226 | } | ||
227 | |||
228 | static inline int cipso_v4_socket_getattr(const struct socket *sock, | ||
229 | struct netlbl_lsm_secattr *secattr) | ||
230 | { | ||
231 | return -ENOSYS; | ||
232 | } | ||
233 | |||
234 | static inline int cipso_v4_skbuff_getattr(const struct sk_buff *skb, | ||
235 | struct netlbl_lsm_secattr *secattr) | ||
236 | { | ||
237 | return -ENOSYS; | ||
238 | } | ||
239 | |||
240 | static inline int cipso_v4_validate(unsigned char **option) | ||
241 | { | ||
242 | return -ENOSYS; | ||
243 | } | ||
244 | #endif /* CONFIG_NETLABEL */ | ||
245 | |||
246 | #endif /* _CIPSO_IPV4_H */ | ||
diff --git a/include/net/dn_fib.h b/include/net/dn_fib.h index a15dcf0d5c1e..f01626cbbed6 100644 --- a/include/net/dn_fib.h +++ b/include/net/dn_fib.h | |||
@@ -22,7 +22,7 @@ struct dn_kern_rta | |||
22 | }; | 22 | }; |
23 | 23 | ||
24 | struct dn_fib_res { | 24 | struct dn_fib_res { |
25 | struct dn_fib_rule *r; | 25 | struct fib_rule *r; |
26 | struct dn_fib_info *fi; | 26 | struct dn_fib_info *fi; |
27 | unsigned char prefixlen; | 27 | unsigned char prefixlen; |
28 | unsigned char nh_sel; | 28 | unsigned char nh_sel; |
@@ -94,7 +94,8 @@ struct dn_fib_node { | |||
94 | 94 | ||
95 | 95 | ||
96 | struct dn_fib_table { | 96 | struct dn_fib_table { |
97 | int n; | 97 | struct hlist_node hlist; |
98 | u32 n; | ||
98 | 99 | ||
99 | int (*insert)(struct dn_fib_table *t, struct rtmsg *r, | 100 | int (*insert)(struct dn_fib_table *t, struct rtmsg *r, |
100 | struct dn_kern_rta *rta, struct nlmsghdr *n, | 101 | struct dn_kern_rta *rta, struct nlmsghdr *n, |
@@ -130,14 +131,11 @@ extern __le16 dn_fib_get_attr16(struct rtattr *attr, int attrlen, int type); | |||
130 | extern void dn_fib_flush(void); | 131 | extern void dn_fib_flush(void); |
131 | extern void dn_fib_select_multipath(const struct flowi *fl, | 132 | extern void dn_fib_select_multipath(const struct flowi *fl, |
132 | struct dn_fib_res *res); | 133 | struct dn_fib_res *res); |
133 | extern int dn_fib_sync_down(__le16 local, struct net_device *dev, | ||
134 | int force); | ||
135 | extern int dn_fib_sync_up(struct net_device *dev); | ||
136 | 134 | ||
137 | /* | 135 | /* |
138 | * dn_tables.c | 136 | * dn_tables.c |
139 | */ | 137 | */ |
140 | extern struct dn_fib_table *dn_fib_get_table(int n, int creat); | 138 | extern struct dn_fib_table *dn_fib_get_table(u32 n, int creat); |
141 | extern struct dn_fib_table *dn_fib_empty_table(void); | 139 | extern struct dn_fib_table *dn_fib_empty_table(void); |
142 | extern void dn_fib_table_init(void); | 140 | extern void dn_fib_table_init(void); |
143 | extern void dn_fib_table_cleanup(void); | 141 | extern void dn_fib_table_cleanup(void); |
@@ -147,10 +145,8 @@ extern void dn_fib_table_cleanup(void); | |||
147 | */ | 145 | */ |
148 | extern void dn_fib_rules_init(void); | 146 | extern void dn_fib_rules_init(void); |
149 | extern void dn_fib_rules_cleanup(void); | 147 | extern void dn_fib_rules_cleanup(void); |
150 | extern void dn_fib_rule_put(struct dn_fib_rule *); | ||
151 | extern __le16 dn_fib_rules_policy(__le16 saddr, struct dn_fib_res *res, unsigned *flags); | ||
152 | extern unsigned dnet_addr_type(__le16 addr); | 148 | extern unsigned dnet_addr_type(__le16 addr); |
153 | extern int dn_fib_lookup(const struct flowi *fl, struct dn_fib_res *res); | 149 | extern int dn_fib_lookup(struct flowi *fl, struct dn_fib_res *res); |
154 | 150 | ||
155 | /* | 151 | /* |
156 | * rtnetlink interface | 152 | * rtnetlink interface |
@@ -176,11 +172,9 @@ static inline void dn_fib_res_put(struct dn_fib_res *res) | |||
176 | if (res->fi) | 172 | if (res->fi) |
177 | dn_fib_info_put(res->fi); | 173 | dn_fib_info_put(res->fi); |
178 | if (res->r) | 174 | if (res->r) |
179 | dn_fib_rule_put(res->r); | 175 | fib_rule_put(res->r); |
180 | } | 176 | } |
181 | 177 | ||
182 | extern struct dn_fib_table *dn_fib_tables[]; | ||
183 | |||
184 | #else /* Endnode */ | 178 | #else /* Endnode */ |
185 | 179 | ||
186 | #define dn_fib_init() do { } while(0) | 180 | #define dn_fib_init() do { } while(0) |
diff --git a/include/net/dst.h b/include/net/dst.h index 36d54fc248b0..a8d825f90305 100644 --- a/include/net/dst.h +++ b/include/net/dst.h | |||
@@ -54,6 +54,7 @@ struct dst_entry | |||
54 | unsigned long expires; | 54 | unsigned long expires; |
55 | 55 | ||
56 | unsigned short header_len; /* more space at head required */ | 56 | unsigned short header_len; /* more space at head required */ |
57 | unsigned short nfheader_len; /* more non-fragment space at head required */ | ||
57 | unsigned short trailer_len; /* space to reserve at tail */ | 58 | unsigned short trailer_len; /* space to reserve at tail */ |
58 | 59 | ||
59 | u32 metrics[RTAX_MAX]; | 60 | u32 metrics[RTAX_MAX]; |
diff --git a/include/net/esp.h b/include/net/esp.h index 064366d66eea..713d039f4af7 100644 --- a/include/net/esp.h +++ b/include/net/esp.h | |||
@@ -15,13 +15,14 @@ struct esp_data | |||
15 | struct { | 15 | struct { |
16 | u8 *key; /* Key */ | 16 | u8 *key; /* Key */ |
17 | int key_len; /* Key length */ | 17 | int key_len; /* Key length */ |
18 | u8 *ivec; /* ivec buffer */ | 18 | int padlen; /* 0..255 */ |
19 | /* ivlen is offset from enc_data, where encrypted data start. | 19 | /* ivlen is offset from enc_data, where encrypted data start. |
20 | * It is logically different of crypto_tfm_alg_ivsize(tfm). | 20 | * It is logically different of crypto_tfm_alg_ivsize(tfm). |
21 | * We assume that it is either zero (no ivec), or | 21 | * We assume that it is either zero (no ivec), or |
22 | * >= crypto_tfm_alg_ivsize(tfm). */ | 22 | * >= crypto_tfm_alg_ivsize(tfm). */ |
23 | int ivlen; | 23 | int ivlen; |
24 | int padlen; /* 0..255 */ | 24 | int ivinitted; |
25 | u8 *ivec; /* ivec buffer */ | ||
25 | struct crypto_blkcipher *tfm; /* crypto handle */ | 26 | struct crypto_blkcipher *tfm; /* crypto handle */ |
26 | } conf; | 27 | } conf; |
27 | 28 | ||
diff --git a/include/net/fib_rules.h b/include/net/fib_rules.h new file mode 100644 index 000000000000..8e2f473d3e82 --- /dev/null +++ b/include/net/fib_rules.h | |||
@@ -0,0 +1,97 @@ | |||
1 | #ifndef __NET_FIB_RULES_H | ||
2 | #define __NET_FIB_RULES_H | ||
3 | |||
4 | #include <linux/types.h> | ||
5 | #include <linux/netdevice.h> | ||
6 | #include <linux/fib_rules.h> | ||
7 | #include <net/flow.h> | ||
8 | #include <net/netlink.h> | ||
9 | |||
10 | struct fib_rule | ||
11 | { | ||
12 | struct list_head list; | ||
13 | atomic_t refcnt; | ||
14 | int ifindex; | ||
15 | char ifname[IFNAMSIZ]; | ||
16 | u32 pref; | ||
17 | u32 flags; | ||
18 | u32 table; | ||
19 | u8 action; | ||
20 | struct rcu_head rcu; | ||
21 | }; | ||
22 | |||
23 | struct fib_lookup_arg | ||
24 | { | ||
25 | void *lookup_ptr; | ||
26 | void *result; | ||
27 | struct fib_rule *rule; | ||
28 | }; | ||
29 | |||
30 | struct fib_rules_ops | ||
31 | { | ||
32 | int family; | ||
33 | struct list_head list; | ||
34 | int rule_size; | ||
35 | |||
36 | int (*action)(struct fib_rule *, | ||
37 | struct flowi *, int, | ||
38 | struct fib_lookup_arg *); | ||
39 | int (*match)(struct fib_rule *, | ||
40 | struct flowi *, int); | ||
41 | int (*configure)(struct fib_rule *, | ||
42 | struct sk_buff *, | ||
43 | struct nlmsghdr *, | ||
44 | struct fib_rule_hdr *, | ||
45 | struct nlattr **); | ||
46 | int (*compare)(struct fib_rule *, | ||
47 | struct fib_rule_hdr *, | ||
48 | struct nlattr **); | ||
49 | int (*fill)(struct fib_rule *, struct sk_buff *, | ||
50 | struct nlmsghdr *, | ||
51 | struct fib_rule_hdr *); | ||
52 | u32 (*default_pref)(void); | ||
53 | |||
54 | int nlgroup; | ||
55 | struct nla_policy *policy; | ||
56 | struct list_head *rules_list; | ||
57 | struct module *owner; | ||
58 | }; | ||
59 | |||
60 | static inline void fib_rule_get(struct fib_rule *rule) | ||
61 | { | ||
62 | atomic_inc(&rule->refcnt); | ||
63 | } | ||
64 | |||
65 | static inline void fib_rule_put_rcu(struct rcu_head *head) | ||
66 | { | ||
67 | struct fib_rule *rule = container_of(head, struct fib_rule, rcu); | ||
68 | kfree(rule); | ||
69 | } | ||
70 | |||
71 | static inline void fib_rule_put(struct fib_rule *rule) | ||
72 | { | ||
73 | if (atomic_dec_and_test(&rule->refcnt)) | ||
74 | call_rcu(&rule->rcu, fib_rule_put_rcu); | ||
75 | } | ||
76 | |||
77 | static inline u32 frh_get_table(struct fib_rule_hdr *frh, struct nlattr **nla) | ||
78 | { | ||
79 | if (nla[FRA_TABLE]) | ||
80 | return nla_get_u32(nla[FRA_TABLE]); | ||
81 | return frh->table; | ||
82 | } | ||
83 | |||
84 | extern int fib_rules_register(struct fib_rules_ops *); | ||
85 | extern int fib_rules_unregister(struct fib_rules_ops *); | ||
86 | |||
87 | extern int fib_rules_lookup(struct fib_rules_ops *, | ||
88 | struct flowi *, int flags, | ||
89 | struct fib_lookup_arg *); | ||
90 | |||
91 | extern int fib_nl_newrule(struct sk_buff *, | ||
92 | struct nlmsghdr *, void *); | ||
93 | extern int fib_nl_delrule(struct sk_buff *, | ||
94 | struct nlmsghdr *, void *); | ||
95 | extern int fib_rules_dump(struct sk_buff *, | ||
96 | struct netlink_callback *, int); | ||
97 | #endif | ||
diff --git a/include/net/flow.h b/include/net/flow.h index 04d89f763451..3ca210ec1379 100644 --- a/include/net/flow.h +++ b/include/net/flow.h | |||
@@ -26,6 +26,7 @@ struct flowi { | |||
26 | struct { | 26 | struct { |
27 | struct in6_addr daddr; | 27 | struct in6_addr daddr; |
28 | struct in6_addr saddr; | 28 | struct in6_addr saddr; |
29 | __u32 fwmark; | ||
29 | __u32 flowlabel; | 30 | __u32 flowlabel; |
30 | } ip6_u; | 31 | } ip6_u; |
31 | 32 | ||
@@ -42,6 +43,7 @@ struct flowi { | |||
42 | #define fld_scope nl_u.dn_u.scope | 43 | #define fld_scope nl_u.dn_u.scope |
43 | #define fl6_dst nl_u.ip6_u.daddr | 44 | #define fl6_dst nl_u.ip6_u.daddr |
44 | #define fl6_src nl_u.ip6_u.saddr | 45 | #define fl6_src nl_u.ip6_u.saddr |
46 | #define fl6_fwmark nl_u.ip6_u.fwmark | ||
45 | #define fl6_flowlabel nl_u.ip6_u.flowlabel | 47 | #define fl6_flowlabel nl_u.ip6_u.flowlabel |
46 | #define fl4_dst nl_u.ip4_u.daddr | 48 | #define fl4_dst nl_u.ip4_u.daddr |
47 | #define fl4_src nl_u.ip4_u.saddr | 49 | #define fl4_src nl_u.ip4_u.saddr |
@@ -72,12 +74,22 @@ struct flowi { | |||
72 | } dnports; | 74 | } dnports; |
73 | 75 | ||
74 | __u32 spi; | 76 | __u32 spi; |
77 | |||
78 | #ifdef CONFIG_IPV6_MIP6 | ||
79 | struct { | ||
80 | __u8 type; | ||
81 | } mht; | ||
82 | #endif | ||
75 | } uli_u; | 83 | } uli_u; |
76 | #define fl_ip_sport uli_u.ports.sport | 84 | #define fl_ip_sport uli_u.ports.sport |
77 | #define fl_ip_dport uli_u.ports.dport | 85 | #define fl_ip_dport uli_u.ports.dport |
78 | #define fl_icmp_type uli_u.icmpt.type | 86 | #define fl_icmp_type uli_u.icmpt.type |
79 | #define fl_icmp_code uli_u.icmpt.code | 87 | #define fl_icmp_code uli_u.icmpt.code |
80 | #define fl_ipsec_spi uli_u.spi | 88 | #define fl_ipsec_spi uli_u.spi |
89 | #ifdef CONFIG_IPV6_MIP6 | ||
90 | #define fl_mh_type uli_u.mht.type | ||
91 | #endif | ||
92 | __u32 secid; /* used by xfrm; see secid.txt */ | ||
81 | } __attribute__((__aligned__(BITS_PER_LONG/8))); | 93 | } __attribute__((__aligned__(BITS_PER_LONG/8))); |
82 | 94 | ||
83 | #define FLOW_DIR_IN 0 | 95 | #define FLOW_DIR_IN 0 |
@@ -85,10 +97,10 @@ struct flowi { | |||
85 | #define FLOW_DIR_FWD 2 | 97 | #define FLOW_DIR_FWD 2 |
86 | 98 | ||
87 | struct sock; | 99 | struct sock; |
88 | typedef void (*flow_resolve_t)(struct flowi *key, u32 sk_sid, u16 family, u8 dir, | 100 | typedef void (*flow_resolve_t)(struct flowi *key, u16 family, u8 dir, |
89 | void **objp, atomic_t **obj_refp); | 101 | void **objp, atomic_t **obj_refp); |
90 | 102 | ||
91 | extern void *flow_cache_lookup(struct flowi *key, u32 sk_sid, u16 family, u8 dir, | 103 | extern void *flow_cache_lookup(struct flowi *key, u16 family, u8 dir, |
92 | flow_resolve_t resolver); | 104 | flow_resolve_t resolver); |
93 | extern void flow_cache_flush(void); | 105 | extern void flow_cache_flush(void); |
94 | extern atomic_t flow_cache_genid; | 106 | extern atomic_t flow_cache_genid; |
diff --git a/include/net/genetlink.h b/include/net/genetlink.h index 8c2287264266..4a38d85e4e25 100644 --- a/include/net/genetlink.h +++ b/include/net/genetlink.h | |||
@@ -27,8 +27,6 @@ struct genl_family | |||
27 | struct list_head family_list; /* private */ | 27 | struct list_head family_list; /* private */ |
28 | }; | 28 | }; |
29 | 29 | ||
30 | #define GENL_ADMIN_PERM 0x01 | ||
31 | |||
32 | /** | 30 | /** |
33 | * struct genl_info - receiving information | 31 | * struct genl_info - receiving information |
34 | * @snd_seq: sending sequence number | 32 | * @snd_seq: sending sequence number |
@@ -133,11 +131,12 @@ static inline int genlmsg_cancel(struct sk_buff *skb, void *hdr) | |||
133 | * @skb: netlink message as socket buffer | 131 | * @skb: netlink message as socket buffer |
134 | * @pid: own netlink pid to avoid sending to yourself | 132 | * @pid: own netlink pid to avoid sending to yourself |
135 | * @group: multicast group id | 133 | * @group: multicast group id |
134 | * @flags: allocation flags | ||
136 | */ | 135 | */ |
137 | static inline int genlmsg_multicast(struct sk_buff *skb, u32 pid, | 136 | static inline int genlmsg_multicast(struct sk_buff *skb, u32 pid, |
138 | unsigned int group) | 137 | unsigned int group, gfp_t flags) |
139 | { | 138 | { |
140 | return nlmsg_multicast(genl_sock, skb, pid, group); | 139 | return nlmsg_multicast(genl_sock, skb, pid, group, flags); |
141 | } | 140 | } |
142 | 141 | ||
143 | /** | 142 | /** |
diff --git a/include/net/if_inet6.h b/include/net/if_inet6.h index e459e1a0ae4a..34489c13c119 100644 --- a/include/net/if_inet6.h +++ b/include/net/if_inet6.h | |||
@@ -189,6 +189,7 @@ struct inet6_dev | |||
189 | struct ipv6_devconf cnf; | 189 | struct ipv6_devconf cnf; |
190 | struct ipv6_devstat stats; | 190 | struct ipv6_devstat stats; |
191 | unsigned long tstamp; /* ipv6InterfaceTable update timestamp */ | 191 | unsigned long tstamp; /* ipv6InterfaceTable update timestamp */ |
192 | struct rcu_head rcu; | ||
192 | }; | 193 | }; |
193 | 194 | ||
194 | extern struct ipv6_devconf ipv6_devconf; | 195 | extern struct ipv6_devconf ipv6_devconf; |
diff --git a/include/net/inet_connection_sock.h b/include/net/inet_connection_sock.h index 9bf73fe50948..de4e83b6da4b 100644 --- a/include/net/inet_connection_sock.h +++ b/include/net/inet_connection_sock.h | |||
@@ -147,7 +147,8 @@ extern struct sock *inet_csk_clone(struct sock *sk, | |||
147 | enum inet_csk_ack_state_t { | 147 | enum inet_csk_ack_state_t { |
148 | ICSK_ACK_SCHED = 1, | 148 | ICSK_ACK_SCHED = 1, |
149 | ICSK_ACK_TIMER = 2, | 149 | ICSK_ACK_TIMER = 2, |
150 | ICSK_ACK_PUSHED = 4 | 150 | ICSK_ACK_PUSHED = 4, |
151 | ICSK_ACK_PUSHED2 = 8 | ||
151 | }; | 152 | }; |
152 | 153 | ||
153 | extern void inet_csk_init_xmit_timers(struct sock *sk, | 154 | extern void inet_csk_init_xmit_timers(struct sock *sk, |
diff --git a/include/net/inet_hashtables.h b/include/net/inet_hashtables.h index 98e0bb3014fe..b4491c9e2a5a 100644 --- a/include/net/inet_hashtables.h +++ b/include/net/inet_hashtables.h | |||
@@ -271,38 +271,15 @@ static inline int inet_iif(const struct sk_buff *skb) | |||
271 | return ((struct rtable *)skb->dst)->rt_iif; | 271 | return ((struct rtable *)skb->dst)->rt_iif; |
272 | } | 272 | } |
273 | 273 | ||
274 | extern struct sock *__inet_lookup_listener(const struct hlist_head *head, | 274 | extern struct sock *__inet_lookup_listener(struct inet_hashinfo *hashinfo, |
275 | const u32 daddr, | 275 | const u32 daddr, |
276 | const unsigned short hnum, | 276 | const unsigned short hnum, |
277 | const int dif); | 277 | const int dif); |
278 | 278 | ||
279 | /* Optimize the common listener case. */ | 279 | static inline struct sock *inet_lookup_listener(struct inet_hashinfo *hashinfo, |
280 | static inline struct sock * | 280 | u32 daddr, u16 dport, int dif) |
281 | inet_lookup_listener(struct inet_hashinfo *hashinfo, | ||
282 | const u32 daddr, | ||
283 | const unsigned short hnum, const int dif) | ||
284 | { | 281 | { |
285 | struct sock *sk = NULL; | 282 | return __inet_lookup_listener(hashinfo, daddr, ntohs(dport), dif); |
286 | const struct hlist_head *head; | ||
287 | |||
288 | read_lock(&hashinfo->lhash_lock); | ||
289 | head = &hashinfo->listening_hash[inet_lhashfn(hnum)]; | ||
290 | if (!hlist_empty(head)) { | ||
291 | const struct inet_sock *inet = inet_sk((sk = __sk_head(head))); | ||
292 | |||
293 | if (inet->num == hnum && !sk->sk_node.next && | ||
294 | (!inet->rcv_saddr || inet->rcv_saddr == daddr) && | ||
295 | (sk->sk_family == PF_INET || !ipv6_only_sock(sk)) && | ||
296 | !sk->sk_bound_dev_if) | ||
297 | goto sherry_cache; | ||
298 | sk = __inet_lookup_listener(head, daddr, hnum, dif); | ||
299 | } | ||
300 | if (sk) { | ||
301 | sherry_cache: | ||
302 | sock_hold(sk); | ||
303 | } | ||
304 | read_unlock(&hashinfo->lhash_lock); | ||
305 | return sk; | ||
306 | } | 283 | } |
307 | 284 | ||
308 | /* Socket demux engine toys. */ | 285 | /* Socket demux engine toys. */ |
@@ -391,14 +368,25 @@ hit: | |||
391 | goto out; | 368 | goto out; |
392 | } | 369 | } |
393 | 370 | ||
371 | static inline struct sock * | ||
372 | inet_lookup_established(struct inet_hashinfo *hashinfo, | ||
373 | const u32 saddr, const u16 sport, | ||
374 | const u32 daddr, const u16 dport, | ||
375 | const int dif) | ||
376 | { | ||
377 | return __inet_lookup_established(hashinfo, saddr, sport, daddr, | ||
378 | ntohs(dport), dif); | ||
379 | } | ||
380 | |||
394 | static inline struct sock *__inet_lookup(struct inet_hashinfo *hashinfo, | 381 | static inline struct sock *__inet_lookup(struct inet_hashinfo *hashinfo, |
395 | const u32 saddr, const u16 sport, | 382 | const u32 saddr, const u16 sport, |
396 | const u32 daddr, const u16 hnum, | 383 | const u32 daddr, const u16 dport, |
397 | const int dif) | 384 | const int dif) |
398 | { | 385 | { |
386 | u16 hnum = ntohs(dport); | ||
399 | struct sock *sk = __inet_lookup_established(hashinfo, saddr, sport, daddr, | 387 | struct sock *sk = __inet_lookup_established(hashinfo, saddr, sport, daddr, |
400 | hnum, dif); | 388 | hnum, dif); |
401 | return sk ? : inet_lookup_listener(hashinfo, daddr, hnum, dif); | 389 | return sk ? : __inet_lookup_listener(hashinfo, daddr, hnum, dif); |
402 | } | 390 | } |
403 | 391 | ||
404 | static inline struct sock *inet_lookup(struct inet_hashinfo *hashinfo, | 392 | static inline struct sock *inet_lookup(struct inet_hashinfo *hashinfo, |
@@ -409,7 +397,7 @@ static inline struct sock *inet_lookup(struct inet_hashinfo *hashinfo, | |||
409 | struct sock *sk; | 397 | struct sock *sk; |
410 | 398 | ||
411 | local_bh_disable(); | 399 | local_bh_disable(); |
412 | sk = __inet_lookup(hashinfo, saddr, sport, daddr, ntohs(dport), dif); | 400 | sk = __inet_lookup(hashinfo, saddr, sport, daddr, dport, dif); |
413 | local_bh_enable(); | 401 | local_bh_enable(); |
414 | 402 | ||
415 | return sk; | 403 | return sk; |
diff --git a/include/net/inet_sock.h b/include/net/inet_sock.h index 1f4a9a60d4cc..f6242710f2ff 100644 --- a/include/net/inet_sock.h +++ b/include/net/inet_sock.h | |||
@@ -27,7 +27,6 @@ | |||
27 | /** struct ip_options - IP Options | 27 | /** struct ip_options - IP Options |
28 | * | 28 | * |
29 | * @faddr - Saved first hop address | 29 | * @faddr - Saved first hop address |
30 | * @is_setbyuser - Set by setsockopt? | ||
31 | * @is_data - Options in __data, rather than skb | 30 | * @is_data - Options in __data, rather than skb |
32 | * @is_strictroute - Strict source route | 31 | * @is_strictroute - Strict source route |
33 | * @srr_is_hit - Packet destination addr was our one | 32 | * @srr_is_hit - Packet destination addr was our one |
@@ -42,8 +41,7 @@ struct ip_options { | |||
42 | unsigned char srr; | 41 | unsigned char srr; |
43 | unsigned char rr; | 42 | unsigned char rr; |
44 | unsigned char ts; | 43 | unsigned char ts; |
45 | unsigned char is_setbyuser:1, | 44 | unsigned char is_data:1, |
46 | is_data:1, | ||
47 | is_strictroute:1, | 45 | is_strictroute:1, |
48 | srr_is_hit:1, | 46 | srr_is_hit:1, |
49 | is_changed:1, | 47 | is_changed:1, |
@@ -51,7 +49,7 @@ struct ip_options { | |||
51 | ts_needtime:1, | 49 | ts_needtime:1, |
52 | ts_needaddr:1; | 50 | ts_needaddr:1; |
53 | unsigned char router_alert; | 51 | unsigned char router_alert; |
54 | unsigned char __pad1; | 52 | unsigned char cipso; |
55 | unsigned char __pad2; | 53 | unsigned char __pad2; |
56 | unsigned char __data[0]; | 54 | unsigned char __data[0]; |
57 | }; | 55 | }; |
diff --git a/include/net/ip6_fib.h b/include/net/ip6_fib.h index a66e9de16a6c..e4438de3bd6b 100644 --- a/include/net/ip6_fib.h +++ b/include/net/ip6_fib.h | |||
@@ -16,14 +16,35 @@ | |||
16 | #ifdef __KERNEL__ | 16 | #ifdef __KERNEL__ |
17 | 17 | ||
18 | #include <linux/ipv6_route.h> | 18 | #include <linux/ipv6_route.h> |
19 | |||
20 | #include <net/dst.h> | ||
21 | #include <net/flow.h> | ||
22 | #include <linux/rtnetlink.h> | 19 | #include <linux/rtnetlink.h> |
23 | #include <linux/spinlock.h> | 20 | #include <linux/spinlock.h> |
21 | #include <net/dst.h> | ||
22 | #include <net/flow.h> | ||
23 | #include <net/netlink.h> | ||
24 | 24 | ||
25 | struct rt6_info; | 25 | struct rt6_info; |
26 | 26 | ||
27 | struct fib6_config | ||
28 | { | ||
29 | u32 fc_table; | ||
30 | u32 fc_metric; | ||
31 | int fc_dst_len; | ||
32 | int fc_src_len; | ||
33 | int fc_ifindex; | ||
34 | u32 fc_flags; | ||
35 | u32 fc_protocol; | ||
36 | |||
37 | struct in6_addr fc_dst; | ||
38 | struct in6_addr fc_src; | ||
39 | struct in6_addr fc_gateway; | ||
40 | |||
41 | unsigned long fc_expires; | ||
42 | struct nlattr *fc_mx; | ||
43 | int fc_mx_len; | ||
44 | |||
45 | struct nl_info fc_nlinfo; | ||
46 | }; | ||
47 | |||
27 | struct fib6_node | 48 | struct fib6_node |
28 | { | 49 | { |
29 | struct fib6_node *parent; | 50 | struct fib6_node *parent; |
@@ -39,6 +60,11 @@ struct fib6_node | |||
39 | __u32 fn_sernum; | 60 | __u32 fn_sernum; |
40 | }; | 61 | }; |
41 | 62 | ||
63 | #ifndef CONFIG_IPV6_SUBTREES | ||
64 | #define FIB6_SUBTREE(fn) NULL | ||
65 | #else | ||
66 | #define FIB6_SUBTREE(fn) ((fn)->subtree) | ||
67 | #endif | ||
42 | 68 | ||
43 | /* | 69 | /* |
44 | * routing information | 70 | * routing information |
@@ -51,6 +77,8 @@ struct rt6key | |||
51 | int plen; | 77 | int plen; |
52 | }; | 78 | }; |
53 | 79 | ||
80 | struct fib6_table; | ||
81 | |||
54 | struct rt6_info | 82 | struct rt6_info |
55 | { | 83 | { |
56 | union { | 84 | union { |
@@ -71,6 +99,7 @@ struct rt6_info | |||
71 | u32 rt6i_flags; | 99 | u32 rt6i_flags; |
72 | u32 rt6i_metric; | 100 | u32 rt6i_metric; |
73 | atomic_t rt6i_ref; | 101 | atomic_t rt6i_ref; |
102 | struct fib6_table *rt6i_table; | ||
74 | 103 | ||
75 | struct rt6key rt6i_dst; | 104 | struct rt6key rt6i_dst; |
76 | struct rt6key rt6i_src; | 105 | struct rt6key rt6i_src; |
@@ -89,28 +118,6 @@ struct fib6_walker_t | |||
89 | void *args; | 118 | void *args; |
90 | }; | 119 | }; |
91 | 120 | ||
92 | extern struct fib6_walker_t fib6_walker_list; | ||
93 | extern rwlock_t fib6_walker_lock; | ||
94 | |||
95 | static inline void fib6_walker_link(struct fib6_walker_t *w) | ||
96 | { | ||
97 | write_lock_bh(&fib6_walker_lock); | ||
98 | w->next = fib6_walker_list.next; | ||
99 | w->prev = &fib6_walker_list; | ||
100 | w->next->prev = w; | ||
101 | w->prev->next = w; | ||
102 | write_unlock_bh(&fib6_walker_lock); | ||
103 | } | ||
104 | |||
105 | static inline void fib6_walker_unlink(struct fib6_walker_t *w) | ||
106 | { | ||
107 | write_lock_bh(&fib6_walker_lock); | ||
108 | w->next->prev = w->prev; | ||
109 | w->prev->next = w->next; | ||
110 | w->prev = w->next = w; | ||
111 | write_unlock_bh(&fib6_walker_lock); | ||
112 | } | ||
113 | |||
114 | struct rt6_statistics { | 121 | struct rt6_statistics { |
115 | __u32 fib_nodes; | 122 | __u32 fib_nodes; |
116 | __u32 fib_route_nodes; | 123 | __u32 fib_route_nodes; |
@@ -143,12 +150,41 @@ struct rt6_statistics { | |||
143 | 150 | ||
144 | typedef void (*f_pnode)(struct fib6_node *fn, void *); | 151 | typedef void (*f_pnode)(struct fib6_node *fn, void *); |
145 | 152 | ||
146 | extern struct fib6_node ip6_routing_table; | 153 | struct fib6_table { |
154 | struct hlist_node tb6_hlist; | ||
155 | u32 tb6_id; | ||
156 | rwlock_t tb6_lock; | ||
157 | struct fib6_node tb6_root; | ||
158 | }; | ||
159 | |||
160 | #define RT6_TABLE_UNSPEC RT_TABLE_UNSPEC | ||
161 | #define RT6_TABLE_MAIN RT_TABLE_MAIN | ||
162 | #define RT6_TABLE_DFLT RT6_TABLE_MAIN | ||
163 | #define RT6_TABLE_INFO RT6_TABLE_MAIN | ||
164 | #define RT6_TABLE_PREFIX RT6_TABLE_MAIN | ||
165 | |||
166 | #ifdef CONFIG_IPV6_MULTIPLE_TABLES | ||
167 | #define FIB6_TABLE_MIN 1 | ||
168 | #define FIB6_TABLE_MAX RT_TABLE_MAX | ||
169 | #define RT6_TABLE_LOCAL RT_TABLE_LOCAL | ||
170 | #else | ||
171 | #define FIB6_TABLE_MIN RT_TABLE_MAIN | ||
172 | #define FIB6_TABLE_MAX FIB6_TABLE_MIN | ||
173 | #define RT6_TABLE_LOCAL RT6_TABLE_MAIN | ||
174 | #endif | ||
175 | |||
176 | typedef struct rt6_info *(*pol_lookup_t)(struct fib6_table *, | ||
177 | struct flowi *, int); | ||
147 | 178 | ||
148 | /* | 179 | /* |
149 | * exported functions | 180 | * exported functions |
150 | */ | 181 | */ |
151 | 182 | ||
183 | extern struct fib6_table * fib6_get_table(u32 id); | ||
184 | extern struct fib6_table * fib6_new_table(u32 id); | ||
185 | extern struct dst_entry * fib6_rule_lookup(struct flowi *fl, int flags, | ||
186 | pol_lookup_t lookup); | ||
187 | |||
152 | extern struct fib6_node *fib6_lookup(struct fib6_node *root, | 188 | extern struct fib6_node *fib6_lookup(struct fib6_node *root, |
153 | struct in6_addr *daddr, | 189 | struct in6_addr *daddr, |
154 | struct in6_addr *saddr); | 190 | struct in6_addr *saddr); |
@@ -157,32 +193,29 @@ struct fib6_node *fib6_locate(struct fib6_node *root, | |||
157 | struct in6_addr *daddr, int dst_len, | 193 | struct in6_addr *daddr, int dst_len, |
158 | struct in6_addr *saddr, int src_len); | 194 | struct in6_addr *saddr, int src_len); |
159 | 195 | ||
160 | extern void fib6_clean_tree(struct fib6_node *root, | 196 | extern void fib6_clean_all(int (*func)(struct rt6_info *, void *arg), |
161 | int (*func)(struct rt6_info *, void *arg), | 197 | int prune, void *arg); |
162 | int prune, void *arg); | ||
163 | |||
164 | extern int fib6_walk(struct fib6_walker_t *w); | ||
165 | extern int fib6_walk_continue(struct fib6_walker_t *w); | ||
166 | 198 | ||
167 | extern int fib6_add(struct fib6_node *root, | 199 | extern int fib6_add(struct fib6_node *root, |
168 | struct rt6_info *rt, | 200 | struct rt6_info *rt, |
169 | struct nlmsghdr *nlh, | 201 | struct nl_info *info); |
170 | void *rtattr, | ||
171 | struct netlink_skb_parms *req); | ||
172 | 202 | ||
173 | extern int fib6_del(struct rt6_info *rt, | 203 | extern int fib6_del(struct rt6_info *rt, |
174 | struct nlmsghdr *nlh, | 204 | struct nl_info *info); |
175 | void *rtattr, | ||
176 | struct netlink_skb_parms *req); | ||
177 | 205 | ||
178 | extern void inet6_rt_notify(int event, struct rt6_info *rt, | 206 | extern void inet6_rt_notify(int event, struct rt6_info *rt, |
179 | struct nlmsghdr *nlh, | 207 | struct nl_info *info); |
180 | struct netlink_skb_parms *req); | ||
181 | 208 | ||
182 | extern void fib6_run_gc(unsigned long dummy); | 209 | extern void fib6_run_gc(unsigned long dummy); |
183 | 210 | ||
184 | extern void fib6_gc_cleanup(void); | 211 | extern void fib6_gc_cleanup(void); |
185 | 212 | ||
186 | extern void fib6_init(void); | 213 | extern void fib6_init(void); |
214 | |||
215 | extern void fib6_rules_init(void); | ||
216 | extern void fib6_rules_cleanup(void); | ||
217 | extern int fib6_rules_dump(struct sk_buff *, | ||
218 | struct netlink_callback *); | ||
219 | |||
187 | #endif | 220 | #endif |
188 | #endif | 221 | #endif |
diff --git a/include/net/ip6_route.h b/include/net/ip6_route.h index 96b0e66406ec..6ca6b71dfe0f 100644 --- a/include/net/ip6_route.h +++ b/include/net/ip6_route.h | |||
@@ -32,6 +32,10 @@ struct route_info { | |||
32 | #include <linux/ip.h> | 32 | #include <linux/ip.h> |
33 | #include <linux/ipv6.h> | 33 | #include <linux/ipv6.h> |
34 | 34 | ||
35 | #define RT6_LOOKUP_F_IFACE 0x1 | ||
36 | #define RT6_LOOKUP_F_REACHABLE 0x2 | ||
37 | #define RT6_LOOKUP_F_HAS_SADDR 0x4 | ||
38 | |||
35 | struct pol_chain { | 39 | struct pol_chain { |
36 | int type; | 40 | int type; |
37 | int priority; | 41 | int priority; |
@@ -41,6 +45,11 @@ struct pol_chain { | |||
41 | 45 | ||
42 | extern struct rt6_info ip6_null_entry; | 46 | extern struct rt6_info ip6_null_entry; |
43 | 47 | ||
48 | #ifdef CONFIG_IPV6_MULTIPLE_TABLES | ||
49 | extern struct rt6_info ip6_prohibit_entry; | ||
50 | extern struct rt6_info ip6_blk_hole_entry; | ||
51 | #endif | ||
52 | |||
44 | extern int ip6_rt_gc_interval; | 53 | extern int ip6_rt_gc_interval; |
45 | 54 | ||
46 | extern void ip6_route_input(struct sk_buff *skb); | 55 | extern void ip6_route_input(struct sk_buff *skb); |
@@ -48,25 +57,14 @@ extern void ip6_route_input(struct sk_buff *skb); | |||
48 | extern struct dst_entry * ip6_route_output(struct sock *sk, | 57 | extern struct dst_entry * ip6_route_output(struct sock *sk, |
49 | struct flowi *fl); | 58 | struct flowi *fl); |
50 | 59 | ||
51 | extern int ip6_route_me_harder(struct sk_buff *skb); | ||
52 | |||
53 | extern void ip6_route_init(void); | 60 | extern void ip6_route_init(void); |
54 | extern void ip6_route_cleanup(void); | 61 | extern void ip6_route_cleanup(void); |
55 | 62 | ||
56 | extern int ipv6_route_ioctl(unsigned int cmd, void __user *arg); | 63 | extern int ipv6_route_ioctl(unsigned int cmd, void __user *arg); |
57 | 64 | ||
58 | extern int ip6_route_add(struct in6_rtmsg *rtmsg, | 65 | extern int ip6_route_add(struct fib6_config *cfg); |
59 | struct nlmsghdr *, | 66 | extern int ip6_ins_rt(struct rt6_info *); |
60 | void *rtattr, | 67 | extern int ip6_del_rt(struct rt6_info *); |
61 | struct netlink_skb_parms *req); | ||
62 | extern int ip6_ins_rt(struct rt6_info *, | ||
63 | struct nlmsghdr *, | ||
64 | void *rtattr, | ||
65 | struct netlink_skb_parms *req); | ||
66 | extern int ip6_del_rt(struct rt6_info *, | ||
67 | struct nlmsghdr *, | ||
68 | void *rtattr, | ||
69 | struct netlink_skb_parms *req); | ||
70 | 68 | ||
71 | extern int ip6_rt_addr_add(struct in6_addr *addr, | 69 | extern int ip6_rt_addr_add(struct in6_addr *addr, |
72 | struct net_device *dev, | 70 | struct net_device *dev, |
@@ -114,6 +112,7 @@ extern int rt6_route_rcv(struct net_device *dev, | |||
114 | struct in6_addr *gwaddr); | 112 | struct in6_addr *gwaddr); |
115 | 113 | ||
116 | extern void rt6_redirect(struct in6_addr *dest, | 114 | extern void rt6_redirect(struct in6_addr *dest, |
115 | struct in6_addr *src, | ||
117 | struct in6_addr *saddr, | 116 | struct in6_addr *saddr, |
118 | struct neighbour *neigh, | 117 | struct neighbour *neigh, |
119 | u8 *lladdr, | 118 | u8 *lladdr, |
@@ -131,6 +130,13 @@ extern int inet6_rtm_newroute(struct sk_buff *skb, struct nlmsghdr* nlh, void *a | |||
131 | extern int inet6_rtm_delroute(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg); | 130 | extern int inet6_rtm_delroute(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg); |
132 | extern int inet6_rtm_getroute(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg); | 131 | extern int inet6_rtm_getroute(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg); |
133 | 132 | ||
133 | struct rt6_rtnl_dump_arg | ||
134 | { | ||
135 | struct sk_buff *skb; | ||
136 | struct netlink_callback *cb; | ||
137 | }; | ||
138 | |||
139 | extern int rt6_dump_route(struct rt6_info *rt, void *p_arg); | ||
134 | extern void rt6_ifdown(struct net_device *dev); | 140 | extern void rt6_ifdown(struct net_device *dev); |
135 | extern void rt6_mtu_change(struct net_device *dev, unsigned mtu); | 141 | extern void rt6_mtu_change(struct net_device *dev, unsigned mtu); |
136 | 142 | ||
@@ -140,21 +146,24 @@ extern rwlock_t rt6_lock; | |||
140 | * Store a destination cache entry in a socket | 146 | * Store a destination cache entry in a socket |
141 | */ | 147 | */ |
142 | static inline void __ip6_dst_store(struct sock *sk, struct dst_entry *dst, | 148 | static inline void __ip6_dst_store(struct sock *sk, struct dst_entry *dst, |
143 | struct in6_addr *daddr) | 149 | struct in6_addr *daddr, struct in6_addr *saddr) |
144 | { | 150 | { |
145 | struct ipv6_pinfo *np = inet6_sk(sk); | 151 | struct ipv6_pinfo *np = inet6_sk(sk); |
146 | struct rt6_info *rt = (struct rt6_info *) dst; | 152 | struct rt6_info *rt = (struct rt6_info *) dst; |
147 | 153 | ||
148 | sk_setup_caps(sk, dst); | 154 | sk_setup_caps(sk, dst); |
149 | np->daddr_cache = daddr; | 155 | np->daddr_cache = daddr; |
156 | #ifdef CONFIG_IPV6_SUBTREES | ||
157 | np->saddr_cache = saddr; | ||
158 | #endif | ||
150 | np->dst_cookie = rt->rt6i_node ? rt->rt6i_node->fn_sernum : 0; | 159 | np->dst_cookie = rt->rt6i_node ? rt->rt6i_node->fn_sernum : 0; |
151 | } | 160 | } |
152 | 161 | ||
153 | static inline void ip6_dst_store(struct sock *sk, struct dst_entry *dst, | 162 | static inline void ip6_dst_store(struct sock *sk, struct dst_entry *dst, |
154 | struct in6_addr *daddr) | 163 | struct in6_addr *daddr, struct in6_addr *saddr) |
155 | { | 164 | { |
156 | write_lock(&sk->sk_dst_lock); | 165 | write_lock(&sk->sk_dst_lock); |
157 | __ip6_dst_store(sk, dst, daddr); | 166 | __ip6_dst_store(sk, dst, daddr, saddr); |
158 | write_unlock(&sk->sk_dst_lock); | 167 | write_unlock(&sk->sk_dst_lock); |
159 | } | 168 | } |
160 | 169 | ||
diff --git a/include/net/ip_fib.h b/include/net/ip_fib.h index a095d1dec7a4..fcc159a4ac17 100644 --- a/include/net/ip_fib.h +++ b/include/net/ip_fib.h | |||
@@ -18,26 +18,34 @@ | |||
18 | 18 | ||
19 | #include <net/flow.h> | 19 | #include <net/flow.h> |
20 | #include <linux/seq_file.h> | 20 | #include <linux/seq_file.h> |
21 | 21 | #include <net/fib_rules.h> | |
22 | /* WARNING: The ordering of these elements must match ordering | 22 | |
23 | * of RTA_* rtnetlink attribute numbers. | 23 | struct fib_config { |
24 | */ | 24 | u8 fc_family; |
25 | struct kern_rta { | 25 | u8 fc_dst_len; |
26 | void *rta_dst; | 26 | u8 fc_src_len; |
27 | void *rta_src; | 27 | u8 fc_tos; |
28 | int *rta_iif; | 28 | u8 fc_protocol; |
29 | int *rta_oif; | 29 | u8 fc_scope; |
30 | void *rta_gw; | 30 | u8 fc_type; |
31 | u32 *rta_priority; | 31 | /* 1 byte unused */ |
32 | void *rta_prefsrc; | 32 | u32 fc_table; |
33 | struct rtattr *rta_mx; | 33 | u32 fc_dst; |
34 | struct rtattr *rta_mp; | 34 | u32 fc_src; |
35 | unsigned char *rta_protoinfo; | 35 | u32 fc_gw; |
36 | u32 *rta_flow; | 36 | int fc_oif; |
37 | struct rta_cacheinfo *rta_ci; | 37 | u32 fc_flags; |
38 | struct rta_session *rta_sess; | 38 | u32 fc_priority; |
39 | u32 *rta_mp_alg; | 39 | u32 fc_prefsrc; |
40 | }; | 40 | struct nlattr *fc_mx; |
41 | struct rtnexthop *fc_mp; | ||
42 | int fc_mx_len; | ||
43 | int fc_mp_len; | ||
44 | u32 fc_flow; | ||
45 | u32 fc_mp_alg; | ||
46 | u32 fc_nlflags; | ||
47 | struct nl_info fc_nlinfo; | ||
48 | }; | ||
41 | 49 | ||
42 | struct fib_info; | 50 | struct fib_info; |
43 | 51 | ||
@@ -149,15 +157,12 @@ struct fib_result_nl { | |||
149 | #endif /* CONFIG_IP_ROUTE_MULTIPATH_WRANDOM */ | 157 | #endif /* CONFIG_IP_ROUTE_MULTIPATH_WRANDOM */ |
150 | 158 | ||
151 | struct fib_table { | 159 | struct fib_table { |
152 | unsigned char tb_id; | 160 | struct hlist_node tb_hlist; |
161 | u32 tb_id; | ||
153 | unsigned tb_stamp; | 162 | unsigned tb_stamp; |
154 | int (*tb_lookup)(struct fib_table *tb, const struct flowi *flp, struct fib_result *res); | 163 | int (*tb_lookup)(struct fib_table *tb, const struct flowi *flp, struct fib_result *res); |
155 | int (*tb_insert)(struct fib_table *table, struct rtmsg *r, | 164 | int (*tb_insert)(struct fib_table *, struct fib_config *); |
156 | struct kern_rta *rta, struct nlmsghdr *n, | 165 | int (*tb_delete)(struct fib_table *, struct fib_config *); |
157 | struct netlink_skb_parms *req); | ||
158 | int (*tb_delete)(struct fib_table *table, struct rtmsg *r, | ||
159 | struct kern_rta *rta, struct nlmsghdr *n, | ||
160 | struct netlink_skb_parms *req); | ||
161 | int (*tb_dump)(struct fib_table *table, struct sk_buff *skb, | 166 | int (*tb_dump)(struct fib_table *table, struct sk_buff *skb, |
162 | struct netlink_callback *cb); | 167 | struct netlink_callback *cb); |
163 | int (*tb_flush)(struct fib_table *table); | 168 | int (*tb_flush)(struct fib_table *table); |
@@ -172,14 +177,14 @@ struct fib_table { | |||
172 | extern struct fib_table *ip_fib_local_table; | 177 | extern struct fib_table *ip_fib_local_table; |
173 | extern struct fib_table *ip_fib_main_table; | 178 | extern struct fib_table *ip_fib_main_table; |
174 | 179 | ||
175 | static inline struct fib_table *fib_get_table(int id) | 180 | static inline struct fib_table *fib_get_table(u32 id) |
176 | { | 181 | { |
177 | if (id != RT_TABLE_LOCAL) | 182 | if (id != RT_TABLE_LOCAL) |
178 | return ip_fib_main_table; | 183 | return ip_fib_main_table; |
179 | return ip_fib_local_table; | 184 | return ip_fib_local_table; |
180 | } | 185 | } |
181 | 186 | ||
182 | static inline struct fib_table *fib_new_table(int id) | 187 | static inline struct fib_table *fib_new_table(u32 id) |
183 | { | 188 | { |
184 | return fib_get_table(id); | 189 | return fib_get_table(id); |
185 | } | 190 | } |
@@ -199,35 +204,19 @@ static inline void fib_select_default(const struct flowi *flp, struct fib_result | |||
199 | } | 204 | } |
200 | 205 | ||
201 | #else /* CONFIG_IP_MULTIPLE_TABLES */ | 206 | #else /* CONFIG_IP_MULTIPLE_TABLES */ |
202 | #define ip_fib_local_table (fib_tables[RT_TABLE_LOCAL]) | 207 | #define ip_fib_local_table fib_get_table(RT_TABLE_LOCAL) |
203 | #define ip_fib_main_table (fib_tables[RT_TABLE_MAIN]) | 208 | #define ip_fib_main_table fib_get_table(RT_TABLE_MAIN) |
204 | |||
205 | extern struct fib_table * fib_tables[RT_TABLE_MAX+1]; | ||
206 | extern int fib_lookup(const struct flowi *flp, struct fib_result *res); | ||
207 | extern struct fib_table *__fib_new_table(int id); | ||
208 | extern void fib_rule_put(struct fib_rule *r); | ||
209 | 209 | ||
210 | static inline struct fib_table *fib_get_table(int id) | 210 | extern int fib_lookup(struct flowi *flp, struct fib_result *res); |
211 | { | ||
212 | if (id == 0) | ||
213 | id = RT_TABLE_MAIN; | ||
214 | |||
215 | return fib_tables[id]; | ||
216 | } | ||
217 | |||
218 | static inline struct fib_table *fib_new_table(int id) | ||
219 | { | ||
220 | if (id == 0) | ||
221 | id = RT_TABLE_MAIN; | ||
222 | |||
223 | return fib_tables[id] ? : __fib_new_table(id); | ||
224 | } | ||
225 | 211 | ||
212 | extern struct fib_table *fib_new_table(u32 id); | ||
213 | extern struct fib_table *fib_get_table(u32 id); | ||
226 | extern void fib_select_default(const struct flowi *flp, struct fib_result *res); | 214 | extern void fib_select_default(const struct flowi *flp, struct fib_result *res); |
227 | 215 | ||
228 | #endif /* CONFIG_IP_MULTIPLE_TABLES */ | 216 | #endif /* CONFIG_IP_MULTIPLE_TABLES */ |
229 | 217 | ||
230 | /* Exported by fib_frontend.c */ | 218 | /* Exported by fib_frontend.c */ |
219 | extern struct nla_policy rtm_ipv4_policy[]; | ||
231 | extern void ip_fib_init(void); | 220 | extern void ip_fib_init(void); |
232 | extern int inet_rtm_delroute(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg); | 221 | extern int inet_rtm_delroute(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg); |
233 | extern int inet_rtm_newroute(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg); | 222 | extern int inet_rtm_newroute(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg); |
@@ -243,23 +232,20 @@ struct rtentry; | |||
243 | extern int ip_fib_check_default(u32 gw, struct net_device *dev); | 232 | extern int ip_fib_check_default(u32 gw, struct net_device *dev); |
244 | extern int fib_sync_down(u32 local, struct net_device *dev, int force); | 233 | extern int fib_sync_down(u32 local, struct net_device *dev, int force); |
245 | extern int fib_sync_up(struct net_device *dev); | 234 | extern int fib_sync_up(struct net_device *dev); |
246 | extern int fib_convert_rtentry(int cmd, struct nlmsghdr *nl, struct rtmsg *rtm, | ||
247 | struct kern_rta *rta, struct rtentry *r); | ||
248 | extern u32 __fib_res_prefsrc(struct fib_result *res); | 235 | extern u32 __fib_res_prefsrc(struct fib_result *res); |
249 | 236 | ||
250 | /* Exported by fib_hash.c */ | 237 | /* Exported by fib_hash.c */ |
251 | extern struct fib_table *fib_hash_init(int id); | 238 | extern struct fib_table *fib_hash_init(u32 id); |
252 | 239 | ||
253 | #ifdef CONFIG_IP_MULTIPLE_TABLES | 240 | #ifdef CONFIG_IP_MULTIPLE_TABLES |
254 | /* Exported by fib_rules.c */ | 241 | extern int fib4_rules_dump(struct sk_buff *skb, struct netlink_callback *cb); |
242 | |||
243 | extern void __init fib4_rules_init(void); | ||
255 | 244 | ||
256 | extern int inet_rtm_delrule(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg); | ||
257 | extern int inet_rtm_newrule(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg); | ||
258 | extern int inet_dump_rules(struct sk_buff *skb, struct netlink_callback *cb); | ||
259 | #ifdef CONFIG_NET_CLS_ROUTE | 245 | #ifdef CONFIG_NET_CLS_ROUTE |
260 | extern u32 fib_rules_tclass(struct fib_result *res); | 246 | extern u32 fib_rules_tclass(struct fib_result *res); |
261 | #endif | 247 | #endif |
262 | extern void fib_rules_init(void); | 248 | |
263 | #endif | 249 | #endif |
264 | 250 | ||
265 | static inline void fib_combine_itag(u32 *itag, struct fib_result *res) | 251 | static inline void fib_combine_itag(u32 *itag, struct fib_result *res) |
diff --git a/include/net/ipv6.h b/include/net/ipv6.h index ece7e8a84ffd..72bf47b2a4e0 100644 --- a/include/net/ipv6.h +++ b/include/net/ipv6.h | |||
@@ -40,6 +40,7 @@ | |||
40 | #define NEXTHDR_ICMP 58 /* ICMP for IPv6. */ | 40 | #define NEXTHDR_ICMP 58 /* ICMP for IPv6. */ |
41 | #define NEXTHDR_NONE 59 /* No next header */ | 41 | #define NEXTHDR_NONE 59 /* No next header */ |
42 | #define NEXTHDR_DEST 60 /* Destination options header. */ | 42 | #define NEXTHDR_DEST 60 /* Destination options header. */ |
43 | #define NEXTHDR_MOBILITY 135 /* Mobility header. */ | ||
43 | 44 | ||
44 | #define NEXTHDR_MAX 255 | 45 | #define NEXTHDR_MAX 255 |
45 | 46 | ||
@@ -229,7 +230,7 @@ extern int ip6_ra_control(struct sock *sk, int sel, | |||
229 | void (*destructor)(struct sock *)); | 230 | void (*destructor)(struct sock *)); |
230 | 231 | ||
231 | 232 | ||
232 | extern int ipv6_parse_hopopts(struct sk_buff *skb); | 233 | extern int ipv6_parse_hopopts(struct sk_buff **skbp); |
233 | 234 | ||
234 | extern struct ipv6_txoptions * ipv6_dup_options(struct sock *sk, struct ipv6_txoptions *opt); | 235 | extern struct ipv6_txoptions * ipv6_dup_options(struct sock *sk, struct ipv6_txoptions *opt); |
235 | extern struct ipv6_txoptions * ipv6_renew_options(struct sock *sk, struct ipv6_txoptions *opt, | 236 | extern struct ipv6_txoptions * ipv6_renew_options(struct sock *sk, struct ipv6_txoptions *opt, |
@@ -506,6 +507,8 @@ extern int ipv6_skip_exthdr(const struct sk_buff *, int start, | |||
506 | 507 | ||
507 | extern int ipv6_ext_hdr(u8 nexthdr); | 508 | extern int ipv6_ext_hdr(u8 nexthdr); |
508 | 509 | ||
510 | extern int ipv6_find_tlv(struct sk_buff *skb, int offset, int type); | ||
511 | |||
509 | extern struct ipv6_txoptions * ipv6_invert_rthdr(struct sock *sk, | 512 | extern struct ipv6_txoptions * ipv6_invert_rthdr(struct sock *sk, |
510 | struct ipv6_rt_hdr *hdr); | 513 | struct ipv6_rt_hdr *hdr); |
511 | 514 | ||
diff --git a/include/net/mip6.h b/include/net/mip6.h new file mode 100644 index 000000000000..68263c6d9996 --- /dev/null +++ b/include/net/mip6.h | |||
@@ -0,0 +1,61 @@ | |||
1 | /* | ||
2 | * Copyright (C)2003-2006 Helsinki University of Technology | ||
3 | * Copyright (C)2003-2006 USAGI/WIDE Project | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or modify | ||
6 | * it under the terms of the GNU General Public License as published by | ||
7 | * the Free Software Foundation; either version 2 of the License, or | ||
8 | * (at your option) any later version. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | * GNU General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License | ||
16 | * along with this program; if not, write to the Free Software | ||
17 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
18 | */ | ||
19 | /* | ||
20 | * Authors: | ||
21 | * Noriaki TAKAMIYA @USAGI | ||
22 | * Masahide NAKAMURA @USAGI | ||
23 | * YOSHIFUJI Hideaki @USAGI | ||
24 | */ | ||
25 | #ifndef _NET_MIP6_H | ||
26 | #define _NET_MIP6_H | ||
27 | |||
28 | #include <linux/skbuff.h> | ||
29 | #include <net/sock.h> | ||
30 | |||
31 | #define MIP6_OPT_PAD_1 0 | ||
32 | #define MIP6_OPT_PAD_N 1 | ||
33 | |||
34 | /* | ||
35 | * Mobility Header | ||
36 | */ | ||
37 | struct ip6_mh { | ||
38 | __u8 ip6mh_proto; | ||
39 | __u8 ip6mh_hdrlen; | ||
40 | __u8 ip6mh_type; | ||
41 | __u8 ip6mh_reserved; | ||
42 | __u16 ip6mh_cksum; | ||
43 | /* Followed by type specific messages */ | ||
44 | __u8 data[0]; | ||
45 | } __attribute__ ((__packed__)); | ||
46 | |||
47 | #define IP6_MH_TYPE_BRR 0 /* Binding Refresh Request */ | ||
48 | #define IP6_MH_TYPE_HOTI 1 /* HOTI Message */ | ||
49 | #define IP6_MH_TYPE_COTI 2 /* COTI Message */ | ||
50 | #define IP6_MH_TYPE_HOT 3 /* HOT Message */ | ||
51 | #define IP6_MH_TYPE_COT 4 /* COT Message */ | ||
52 | #define IP6_MH_TYPE_BU 5 /* Binding Update */ | ||
53 | #define IP6_MH_TYPE_BACK 6 /* Binding ACK */ | ||
54 | #define IP6_MH_TYPE_BERROR 7 /* Binding Error */ | ||
55 | #define IP6_MH_TYPE_MAX IP6_MH_TYPE_BERROR | ||
56 | |||
57 | extern int mip6_init(void); | ||
58 | extern void mip6_fini(void); | ||
59 | extern int mip6_mh_filter(struct sock *sk, struct sk_buff *skb); | ||
60 | |||
61 | #endif | ||
diff --git a/include/net/neighbour.h b/include/net/neighbour.h index 4901ee446879..c8aacbd2e333 100644 --- a/include/net/neighbour.h +++ b/include/net/neighbour.h | |||
@@ -1,6 +1,8 @@ | |||
1 | #ifndef _NET_NEIGHBOUR_H | 1 | #ifndef _NET_NEIGHBOUR_H |
2 | #define _NET_NEIGHBOUR_H | 2 | #define _NET_NEIGHBOUR_H |
3 | 3 | ||
4 | #include <linux/neighbour.h> | ||
5 | |||
4 | /* | 6 | /* |
5 | * Generic neighbour manipulation | 7 | * Generic neighbour manipulation |
6 | * | 8 | * |
@@ -14,40 +16,6 @@ | |||
14 | * - Add neighbour cache statistics like rtstat | 16 | * - Add neighbour cache statistics like rtstat |
15 | */ | 17 | */ |
16 | 18 | ||
17 | /* The following flags & states are exported to user space, | ||
18 | so that they should be moved to include/linux/ directory. | ||
19 | */ | ||
20 | |||
21 | /* | ||
22 | * Neighbor Cache Entry Flags | ||
23 | */ | ||
24 | |||
25 | #define NTF_PROXY 0x08 /* == ATF_PUBL */ | ||
26 | #define NTF_ROUTER 0x80 | ||
27 | |||
28 | /* | ||
29 | * Neighbor Cache Entry States. | ||
30 | */ | ||
31 | |||
32 | #define NUD_INCOMPLETE 0x01 | ||
33 | #define NUD_REACHABLE 0x02 | ||
34 | #define NUD_STALE 0x04 | ||
35 | #define NUD_DELAY 0x08 | ||
36 | #define NUD_PROBE 0x10 | ||
37 | #define NUD_FAILED 0x20 | ||
38 | |||
39 | /* Dummy states */ | ||
40 | #define NUD_NOARP 0x40 | ||
41 | #define NUD_PERMANENT 0x80 | ||
42 | #define NUD_NONE 0x00 | ||
43 | |||
44 | /* NUD_NOARP & NUD_PERMANENT are pseudostates, they never change | ||
45 | and make no address resolution or NUD. | ||
46 | NUD_PERMANENT is also cannot be deleted by garbage collectors. | ||
47 | */ | ||
48 | |||
49 | #ifdef __KERNEL__ | ||
50 | |||
51 | #include <asm/atomic.h> | 19 | #include <asm/atomic.h> |
52 | #include <linux/netdevice.h> | 20 | #include <linux/netdevice.h> |
53 | #include <linux/skbuff.h> | 21 | #include <linux/skbuff.h> |
@@ -133,7 +101,7 @@ struct neighbour | |||
133 | __u8 dead; | 101 | __u8 dead; |
134 | atomic_t probes; | 102 | atomic_t probes; |
135 | rwlock_t lock; | 103 | rwlock_t lock; |
136 | unsigned char ha[(MAX_ADDR_LEN+sizeof(unsigned long)-1)&~(sizeof(unsigned long)-1)]; | 104 | unsigned char ha[ALIGN(MAX_ADDR_LEN, sizeof(unsigned long))]; |
137 | struct hh_cache *hh; | 105 | struct hh_cache *hh; |
138 | atomic_t refcnt; | 106 | atomic_t refcnt; |
139 | int (*output)(struct sk_buff *skb); | 107 | int (*output)(struct sk_buff *skb); |
@@ -158,6 +126,7 @@ struct pneigh_entry | |||
158 | { | 126 | { |
159 | struct pneigh_entry *next; | 127 | struct pneigh_entry *next; |
160 | struct net_device *dev; | 128 | struct net_device *dev; |
129 | u8 flags; | ||
161 | u8 key[0]; | 130 | u8 key[0]; |
162 | }; | 131 | }; |
163 | 132 | ||
@@ -374,6 +343,3 @@ struct neighbour_cb { | |||
374 | #define NEIGH_CB(skb) ((struct neighbour_cb *)(skb)->cb) | 343 | #define NEIGH_CB(skb) ((struct neighbour_cb *)(skb)->cb) |
375 | 344 | ||
376 | #endif | 345 | #endif |
377 | #endif | ||
378 | |||
379 | |||
diff --git a/include/net/netlabel.h b/include/net/netlabel.h new file mode 100644 index 000000000000..fc2b72fc7e07 --- /dev/null +++ b/include/net/netlabel.h | |||
@@ -0,0 +1,292 @@ | |||
1 | /* | ||
2 | * NetLabel System | ||
3 | * | ||
4 | * The NetLabel system manages static and dynamic label mappings for network | ||
5 | * protocols such as CIPSO and RIPSO. | ||
6 | * | ||
7 | * Author: Paul Moore <paul.moore@hp.com> | ||
8 | * | ||
9 | */ | ||
10 | |||
11 | /* | ||
12 | * (c) Copyright Hewlett-Packard Development Company, L.P., 2006 | ||
13 | * | ||
14 | * This program is free software; you can redistribute it and/or modify | ||
15 | * it under the terms of the GNU General Public License as published by | ||
16 | * the Free Software Foundation; either version 2 of the License, or | ||
17 | * (at your option) any later version. | ||
18 | * | ||
19 | * This program is distributed in the hope that it will be useful, | ||
20 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
21 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See | ||
22 | * the GNU General Public License for more details. | ||
23 | * | ||
24 | * You should have received a copy of the GNU General Public License | ||
25 | * along with this program; if not, write to the Free Software | ||
26 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
27 | * | ||
28 | */ | ||
29 | |||
30 | #ifndef _NETLABEL_H | ||
31 | #define _NETLABEL_H | ||
32 | |||
33 | #include <linux/types.h> | ||
34 | #include <linux/net.h> | ||
35 | #include <linux/skbuff.h> | ||
36 | #include <net/netlink.h> | ||
37 | |||
38 | /* | ||
39 | * NetLabel - A management interface for maintaining network packet label | ||
40 | * mapping tables for explicit packet labling protocols. | ||
41 | * | ||
42 | * Network protocols such as CIPSO and RIPSO require a label translation layer | ||
43 | * to convert the label on the packet into something meaningful on the host | ||
44 | * machine. In the current Linux implementation these mapping tables live | ||
45 | * inside the kernel; NetLabel provides a mechanism for user space applications | ||
46 | * to manage these mapping tables. | ||
47 | * | ||
48 | * NetLabel makes use of the Generic NETLINK mechanism as a transport layer to | ||
49 | * send messages between kernel and user space. The general format of a | ||
50 | * NetLabel message is shown below: | ||
51 | * | ||
52 | * +-----------------+-------------------+--------- --- -- - | ||
53 | * | struct nlmsghdr | struct genlmsghdr | payload | ||
54 | * +-----------------+-------------------+--------- --- -- - | ||
55 | * | ||
56 | * The 'nlmsghdr' and 'genlmsghdr' structs should be dealt with like normal. | ||
57 | * The payload is dependent on the subsystem specified in the | ||
58 | * 'nlmsghdr->nlmsg_type' and should be defined below, supporting functions | ||
59 | * should be defined in the corresponding net/netlabel/netlabel_<subsys>.h|c | ||
60 | * file. All of the fields in the NetLabel payload are NETLINK attributes, the | ||
61 | * length of each field is the length of the NETLINK attribute payload, see | ||
62 | * include/net/netlink.h for more information on NETLINK attributes. | ||
63 | * | ||
64 | */ | ||
65 | |||
66 | /* | ||
67 | * NetLabel NETLINK protocol | ||
68 | */ | ||
69 | |||
70 | #define NETLBL_PROTO_VERSION 1 | ||
71 | |||
72 | /* NetLabel NETLINK types/families */ | ||
73 | #define NETLBL_NLTYPE_NONE 0 | ||
74 | #define NETLBL_NLTYPE_MGMT 1 | ||
75 | #define NETLBL_NLTYPE_MGMT_NAME "NLBL_MGMT" | ||
76 | #define NETLBL_NLTYPE_RIPSO 2 | ||
77 | #define NETLBL_NLTYPE_RIPSO_NAME "NLBL_RIPSO" | ||
78 | #define NETLBL_NLTYPE_CIPSOV4 3 | ||
79 | #define NETLBL_NLTYPE_CIPSOV4_NAME "NLBL_CIPSOv4" | ||
80 | #define NETLBL_NLTYPE_CIPSOV6 4 | ||
81 | #define NETLBL_NLTYPE_CIPSOV6_NAME "NLBL_CIPSOv6" | ||
82 | #define NETLBL_NLTYPE_UNLABELED 5 | ||
83 | #define NETLBL_NLTYPE_UNLABELED_NAME "NLBL_UNLBL" | ||
84 | |||
85 | /* NetLabel return codes */ | ||
86 | #define NETLBL_E_OK 0 | ||
87 | |||
88 | /* | ||
89 | * Helper functions | ||
90 | */ | ||
91 | |||
92 | #define NETLBL_LEN_U8 nla_total_size(sizeof(u8)) | ||
93 | #define NETLBL_LEN_U16 nla_total_size(sizeof(u16)) | ||
94 | #define NETLBL_LEN_U32 nla_total_size(sizeof(u32)) | ||
95 | |||
96 | /** | ||
97 | * netlbl_netlink_alloc_skb - Allocate a NETLINK message buffer | ||
98 | * @head: the amount of headroom in bytes | ||
99 | * @body: the desired size (minus headroom) in bytes | ||
100 | * @gfp_flags: the alloc flags to pass to alloc_skb() | ||
101 | * | ||
102 | * Description: | ||
103 | * Allocate a NETLINK message buffer based on the sizes given in @head and | ||
104 | * @body. If @head is greater than zero skb_reserve() is called to reserve | ||
105 | * @head bytes at the start of the buffer. Returns a valid sk_buff pointer on | ||
106 | * success, NULL on failure. | ||
107 | * | ||
108 | */ | ||
109 | static inline struct sk_buff *netlbl_netlink_alloc_skb(size_t head, | ||
110 | size_t body, | ||
111 | int gfp_flags) | ||
112 | { | ||
113 | struct sk_buff *skb; | ||
114 | |||
115 | skb = alloc_skb(NLMSG_ALIGN(head + body), gfp_flags); | ||
116 | if (skb == NULL) | ||
117 | return NULL; | ||
118 | if (head > 0) { | ||
119 | skb_reserve(skb, head); | ||
120 | if (skb_tailroom(skb) < body) { | ||
121 | kfree_skb(skb); | ||
122 | return NULL; | ||
123 | } | ||
124 | } | ||
125 | |||
126 | return skb; | ||
127 | } | ||
128 | |||
129 | /* | ||
130 | * NetLabel - Kernel API for accessing the network packet label mappings. | ||
131 | * | ||
132 | * The following functions are provided for use by other kernel modules, | ||
133 | * specifically kernel LSM modules, to provide a consistent, transparent API | ||
134 | * for dealing with explicit packet labeling protocols such as CIPSO and | ||
135 | * RIPSO. The functions defined here are implemented in the | ||
136 | * net/netlabel/netlabel_kapi.c file. | ||
137 | * | ||
138 | */ | ||
139 | |||
140 | /* Domain mapping definition struct */ | ||
141 | struct netlbl_dom_map; | ||
142 | |||
143 | /* Domain mapping operations */ | ||
144 | int netlbl_domhsh_remove(const char *domain); | ||
145 | |||
146 | /* LSM security attributes */ | ||
147 | struct netlbl_lsm_cache { | ||
148 | void (*free) (const void *data); | ||
149 | void *data; | ||
150 | }; | ||
151 | struct netlbl_lsm_secattr { | ||
152 | char *domain; | ||
153 | |||
154 | u32 mls_lvl; | ||
155 | u32 mls_lvl_vld; | ||
156 | unsigned char *mls_cat; | ||
157 | size_t mls_cat_len; | ||
158 | |||
159 | struct netlbl_lsm_cache cache; | ||
160 | }; | ||
161 | |||
162 | /* | ||
163 | * LSM security attribute operations | ||
164 | */ | ||
165 | |||
166 | |||
167 | /** | ||
168 | * netlbl_secattr_init - Initialize a netlbl_lsm_secattr struct | ||
169 | * @secattr: the struct to initialize | ||
170 | * | ||
171 | * Description: | ||
172 | * Initialize an already allocated netlbl_lsm_secattr struct. Returns zero on | ||
173 | * success, negative values on error. | ||
174 | * | ||
175 | */ | ||
176 | static inline int netlbl_secattr_init(struct netlbl_lsm_secattr *secattr) | ||
177 | { | ||
178 | memset(secattr, 0, sizeof(*secattr)); | ||
179 | return 0; | ||
180 | } | ||
181 | |||
182 | /** | ||
183 | * netlbl_secattr_destroy - Clears a netlbl_lsm_secattr struct | ||
184 | * @secattr: the struct to clear | ||
185 | * @clear_cache: cache clear flag | ||
186 | * | ||
187 | * Description: | ||
188 | * Destroys the @secattr struct, including freeing all of the internal buffers. | ||
189 | * If @clear_cache is true then free the cache fields, otherwise leave them | ||
190 | * intact. The struct must be reset with a call to netlbl_secattr_init() | ||
191 | * before reuse. | ||
192 | * | ||
193 | */ | ||
194 | static inline void netlbl_secattr_destroy(struct netlbl_lsm_secattr *secattr, | ||
195 | u32 clear_cache) | ||
196 | { | ||
197 | if (clear_cache && secattr->cache.data != NULL && secattr->cache.free) | ||
198 | secattr->cache.free(secattr->cache.data); | ||
199 | kfree(secattr->domain); | ||
200 | kfree(secattr->mls_cat); | ||
201 | } | ||
202 | |||
203 | /** | ||
204 | * netlbl_secattr_alloc - Allocate and initialize a netlbl_lsm_secattr struct | ||
205 | * @flags: the memory allocation flags | ||
206 | * | ||
207 | * Description: | ||
208 | * Allocate and initialize a netlbl_lsm_secattr struct. Returns a valid | ||
209 | * pointer on success, or NULL on failure. | ||
210 | * | ||
211 | */ | ||
212 | static inline struct netlbl_lsm_secattr *netlbl_secattr_alloc(int flags) | ||
213 | { | ||
214 | return kzalloc(sizeof(struct netlbl_lsm_secattr), flags); | ||
215 | } | ||
216 | |||
217 | /** | ||
218 | * netlbl_secattr_free - Frees a netlbl_lsm_secattr struct | ||
219 | * @secattr: the struct to free | ||
220 | * @clear_cache: cache clear flag | ||
221 | * | ||
222 | * Description: | ||
223 | * Frees @secattr including all of the internal buffers. If @clear_cache is | ||
224 | * true then free the cache fields, otherwise leave them intact. | ||
225 | * | ||
226 | */ | ||
227 | static inline void netlbl_secattr_free(struct netlbl_lsm_secattr *secattr, | ||
228 | u32 clear_cache) | ||
229 | { | ||
230 | netlbl_secattr_destroy(secattr, clear_cache); | ||
231 | kfree(secattr); | ||
232 | } | ||
233 | |||
234 | /* | ||
235 | * LSM protocol operations | ||
236 | */ | ||
237 | |||
238 | #ifdef CONFIG_NETLABEL | ||
239 | int netlbl_socket_setattr(const struct socket *sock, | ||
240 | const struct netlbl_lsm_secattr *secattr); | ||
241 | int netlbl_socket_getattr(const struct socket *sock, | ||
242 | struct netlbl_lsm_secattr *secattr); | ||
243 | int netlbl_skbuff_getattr(const struct sk_buff *skb, | ||
244 | struct netlbl_lsm_secattr *secattr); | ||
245 | void netlbl_skbuff_err(struct sk_buff *skb, int error); | ||
246 | #else | ||
247 | static inline int netlbl_socket_setattr(const struct socket *sock, | ||
248 | const struct netlbl_lsm_secattr *secattr) | ||
249 | { | ||
250 | return -ENOSYS; | ||
251 | } | ||
252 | |||
253 | static inline int netlbl_socket_getattr(const struct socket *sock, | ||
254 | struct netlbl_lsm_secattr *secattr) | ||
255 | { | ||
256 | return -ENOSYS; | ||
257 | } | ||
258 | |||
259 | static inline int netlbl_skbuff_getattr(const struct sk_buff *skb, | ||
260 | struct netlbl_lsm_secattr *secattr) | ||
261 | { | ||
262 | return -ENOSYS; | ||
263 | } | ||
264 | |||
265 | static inline void netlbl_skbuff_err(struct sk_buff *skb, int error) | ||
266 | { | ||
267 | return; | ||
268 | } | ||
269 | #endif /* CONFIG_NETLABEL */ | ||
270 | |||
271 | /* | ||
272 | * LSM label mapping cache operations | ||
273 | */ | ||
274 | |||
275 | #ifdef CONFIG_NETLABEL | ||
276 | void netlbl_cache_invalidate(void); | ||
277 | int netlbl_cache_add(const struct sk_buff *skb, | ||
278 | const struct netlbl_lsm_secattr *secattr); | ||
279 | #else | ||
280 | static inline void netlbl_cache_invalidate(void) | ||
281 | { | ||
282 | return; | ||
283 | } | ||
284 | |||
285 | static inline int netlbl_cache_add(const struct sk_buff *skb, | ||
286 | const struct netlbl_lsm_secattr *secattr) | ||
287 | { | ||
288 | return 0; | ||
289 | } | ||
290 | #endif /* CONFIG_NETLABEL */ | ||
291 | |||
292 | #endif /* _NETLABEL_H */ | ||
diff --git a/include/net/netlink.h b/include/net/netlink.h index 640c26a90cf1..11dc2e7f679a 100644 --- a/include/net/netlink.h +++ b/include/net/netlink.h | |||
@@ -35,12 +35,15 @@ | |||
35 | * nlmsg_put() add a netlink message to an skb | 35 | * nlmsg_put() add a netlink message to an skb |
36 | * nlmsg_put_answer() callback based nlmsg_put() | 36 | * nlmsg_put_answer() callback based nlmsg_put() |
37 | * nlmsg_end() finanlize netlink message | 37 | * nlmsg_end() finanlize netlink message |
38 | * nlmsg_get_pos() return current position in message | ||
39 | * nlmsg_trim() trim part of message | ||
38 | * nlmsg_cancel() cancel message construction | 40 | * nlmsg_cancel() cancel message construction |
39 | * nlmsg_free() free a netlink message | 41 | * nlmsg_free() free a netlink message |
40 | * | 42 | * |
41 | * Message Sending: | 43 | * Message Sending: |
42 | * nlmsg_multicast() multicast message to several groups | 44 | * nlmsg_multicast() multicast message to several groups |
43 | * nlmsg_unicast() unicast a message to a single socket | 45 | * nlmsg_unicast() unicast a message to a single socket |
46 | * nlmsg_notify() send notification message | ||
44 | * | 47 | * |
45 | * Message Length Calculations: | 48 | * Message Length Calculations: |
46 | * nlmsg_msg_size(payload) length of message w/o padding | 49 | * nlmsg_msg_size(payload) length of message w/o padding |
@@ -62,6 +65,9 @@ | |||
62 | * nlmsg_validate() validate netlink message incl. attrs | 65 | * nlmsg_validate() validate netlink message incl. attrs |
63 | * nlmsg_for_each_attr() loop over all attributes | 66 | * nlmsg_for_each_attr() loop over all attributes |
64 | * | 67 | * |
68 | * Misc: | ||
69 | * nlmsg_report() report back to application? | ||
70 | * | ||
65 | * ------------------------------------------------------------------------ | 71 | * ------------------------------------------------------------------------ |
66 | * Attributes Interface | 72 | * Attributes Interface |
67 | * ------------------------------------------------------------------------ | 73 | * ------------------------------------------------------------------------ |
@@ -80,8 +86,10 @@ | |||
80 | * struct nlattr netlink attribtue header | 86 | * struct nlattr netlink attribtue header |
81 | * | 87 | * |
82 | * Attribute Construction: | 88 | * Attribute Construction: |
83 | * nla_reserve(skb, type, len) reserve skb tailroom for an attribute | 89 | * nla_reserve(skb, type, len) reserve room for an attribute |
90 | * nla_reserve_nohdr(skb, len) reserve room for an attribute w/o hdr | ||
84 | * nla_put(skb, type, len, data) add attribute to skb | 91 | * nla_put(skb, type, len, data) add attribute to skb |
92 | * nla_put_nohdr(skb, len, data) add attribute w/o hdr | ||
85 | * | 93 | * |
86 | * Attribute Construction for Basic Types: | 94 | * Attribute Construction for Basic Types: |
87 | * nla_put_u8(skb, type, value) add u8 attribute to skb | 95 | * nla_put_u8(skb, type, value) add u8 attribute to skb |
@@ -139,6 +147,7 @@ | |||
139 | * nla_next(nla, remaining) get next netlink attribute | 147 | * nla_next(nla, remaining) get next netlink attribute |
140 | * nla_validate() validate a stream of attributes | 148 | * nla_validate() validate a stream of attributes |
141 | * nla_find() find attribute in stream of attributes | 149 | * nla_find() find attribute in stream of attributes |
150 | * nla_find_nested() find attribute in nested attributes | ||
142 | * nla_parse() parse and validate stream of attrs | 151 | * nla_parse() parse and validate stream of attrs |
143 | * nla_parse_nested() parse nested attribuets | 152 | * nla_parse_nested() parse nested attribuets |
144 | * nla_for_each_attr() loop over all attributes | 153 | * nla_for_each_attr() loop over all attributes |
@@ -158,6 +167,7 @@ enum { | |||
158 | NLA_FLAG, | 167 | NLA_FLAG, |
159 | NLA_MSECS, | 168 | NLA_MSECS, |
160 | NLA_NESTED, | 169 | NLA_NESTED, |
170 | NLA_NUL_STRING, | ||
161 | __NLA_TYPE_MAX, | 171 | __NLA_TYPE_MAX, |
162 | }; | 172 | }; |
163 | 173 | ||
@@ -166,21 +176,37 @@ enum { | |||
166 | /** | 176 | /** |
167 | * struct nla_policy - attribute validation policy | 177 | * struct nla_policy - attribute validation policy |
168 | * @type: Type of attribute or NLA_UNSPEC | 178 | * @type: Type of attribute or NLA_UNSPEC |
169 | * @minlen: Minimal length of payload required to be available | 179 | * @len: Type specific length of payload |
170 | * | 180 | * |
171 | * Policies are defined as arrays of this struct, the array must be | 181 | * Policies are defined as arrays of this struct, the array must be |
172 | * accessible by attribute type up to the highest identifier to be expected. | 182 | * accessible by attribute type up to the highest identifier to be expected. |
173 | * | 183 | * |
184 | * Meaning of `len' field: | ||
185 | * NLA_STRING Maximum length of string | ||
186 | * NLA_NUL_STRING Maximum length of string (excluding NUL) | ||
187 | * NLA_FLAG Unused | ||
188 | * All other Exact length of attribute payload | ||
189 | * | ||
174 | * Example: | 190 | * Example: |
175 | * static struct nla_policy my_policy[ATTR_MAX+1] __read_mostly = { | 191 | * static struct nla_policy my_policy[ATTR_MAX+1] __read_mostly = { |
176 | * [ATTR_FOO] = { .type = NLA_U16 }, | 192 | * [ATTR_FOO] = { .type = NLA_U16 }, |
177 | * [ATTR_BAR] = { .type = NLA_STRING }, | 193 | * [ATTR_BAR] = { .type = NLA_STRING, len = BARSIZ }, |
178 | * [ATTR_BAZ] = { .minlen = sizeof(struct mystruct) }, | 194 | * [ATTR_BAZ] = { .len = sizeof(struct mystruct) }, |
179 | * }; | 195 | * }; |
180 | */ | 196 | */ |
181 | struct nla_policy { | 197 | struct nla_policy { |
182 | u16 type; | 198 | u16 type; |
183 | u16 minlen; | 199 | u16 len; |
200 | }; | ||
201 | |||
202 | /** | ||
203 | * struct nl_info - netlink source information | ||
204 | * @nlh: Netlink message header of original request | ||
205 | * @pid: Netlink PID of requesting application | ||
206 | */ | ||
207 | struct nl_info { | ||
208 | struct nlmsghdr *nlh; | ||
209 | u32 pid; | ||
184 | }; | 210 | }; |
185 | 211 | ||
186 | extern void netlink_run_queue(struct sock *sk, unsigned int *qlen, | 212 | extern void netlink_run_queue(struct sock *sk, unsigned int *qlen, |
@@ -188,6 +214,9 @@ extern void netlink_run_queue(struct sock *sk, unsigned int *qlen, | |||
188 | struct nlmsghdr *, int *)); | 214 | struct nlmsghdr *, int *)); |
189 | extern void netlink_queue_skip(struct nlmsghdr *nlh, | 215 | extern void netlink_queue_skip(struct nlmsghdr *nlh, |
190 | struct sk_buff *skb); | 216 | struct sk_buff *skb); |
217 | extern int nlmsg_notify(struct sock *sk, struct sk_buff *skb, | ||
218 | u32 pid, unsigned int group, int report, | ||
219 | gfp_t flags); | ||
191 | 220 | ||
192 | extern int nla_validate(struct nlattr *head, int len, int maxtype, | 221 | extern int nla_validate(struct nlattr *head, int len, int maxtype, |
193 | struct nla_policy *policy); | 222 | struct nla_policy *policy); |
@@ -203,12 +232,18 @@ extern int nla_memcmp(const struct nlattr *nla, const void *data, | |||
203 | extern int nla_strcmp(const struct nlattr *nla, const char *str); | 232 | extern int nla_strcmp(const struct nlattr *nla, const char *str); |
204 | extern struct nlattr * __nla_reserve(struct sk_buff *skb, int attrtype, | 233 | extern struct nlattr * __nla_reserve(struct sk_buff *skb, int attrtype, |
205 | int attrlen); | 234 | int attrlen); |
235 | extern void * __nla_reserve_nohdr(struct sk_buff *skb, int attrlen); | ||
206 | extern struct nlattr * nla_reserve(struct sk_buff *skb, int attrtype, | 236 | extern struct nlattr * nla_reserve(struct sk_buff *skb, int attrtype, |
207 | int attrlen); | 237 | int attrlen); |
238 | extern void * nla_reserve_nohdr(struct sk_buff *skb, int attrlen); | ||
208 | extern void __nla_put(struct sk_buff *skb, int attrtype, | 239 | extern void __nla_put(struct sk_buff *skb, int attrtype, |
209 | int attrlen, const void *data); | 240 | int attrlen, const void *data); |
241 | extern void __nla_put_nohdr(struct sk_buff *skb, int attrlen, | ||
242 | const void *data); | ||
210 | extern int nla_put(struct sk_buff *skb, int attrtype, | 243 | extern int nla_put(struct sk_buff *skb, int attrtype, |
211 | int attrlen, const void *data); | 244 | int attrlen, const void *data); |
245 | extern int nla_put_nohdr(struct sk_buff *skb, int attrlen, | ||
246 | const void *data); | ||
212 | 247 | ||
213 | /************************************************************************** | 248 | /************************************************************************** |
214 | * Netlink Messages | 249 | * Netlink Messages |
@@ -364,6 +399,17 @@ static inline int nlmsg_validate(struct nlmsghdr *nlh, int hdrlen, int maxtype, | |||
364 | } | 399 | } |
365 | 400 | ||
366 | /** | 401 | /** |
402 | * nlmsg_report - need to report back to application? | ||
403 | * @nlh: netlink message header | ||
404 | * | ||
405 | * Returns 1 if a report back to the application is requested. | ||
406 | */ | ||
407 | static inline int nlmsg_report(struct nlmsghdr *nlh) | ||
408 | { | ||
409 | return !!(nlh->nlmsg_flags & NLM_F_ECHO); | ||
410 | } | ||
411 | |||
412 | /** | ||
367 | * nlmsg_for_each_attr - iterate over a stream of attributes | 413 | * nlmsg_for_each_attr - iterate over a stream of attributes |
368 | * @pos: loop counter, set to current attribute | 414 | * @pos: loop counter, set to current attribute |
369 | * @nlh: netlink message header | 415 | * @nlh: netlink message header |
@@ -453,12 +499,13 @@ static inline struct nlmsghdr *nlmsg_put_answer(struct sk_buff *skb, | |||
453 | /** | 499 | /** |
454 | * nlmsg_new - Allocate a new netlink message | 500 | * nlmsg_new - Allocate a new netlink message |
455 | * @size: maximum size of message | 501 | * @size: maximum size of message |
502 | * @flags: the type of memory to allocate. | ||
456 | * | 503 | * |
457 | * Use NLMSG_GOODSIZE if size isn't know and you need a good default size. | 504 | * Use NLMSG_GOODSIZE if size isn't know and you need a good default size. |
458 | */ | 505 | */ |
459 | static inline struct sk_buff *nlmsg_new(int size) | 506 | static inline struct sk_buff *nlmsg_new(int size, gfp_t flags) |
460 | { | 507 | { |
461 | return alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL); | 508 | return alloc_skb(size, flags); |
462 | } | 509 | } |
463 | 510 | ||
464 | /** | 511 | /** |
@@ -480,6 +527,32 @@ static inline int nlmsg_end(struct sk_buff *skb, struct nlmsghdr *nlh) | |||
480 | } | 527 | } |
481 | 528 | ||
482 | /** | 529 | /** |
530 | * nlmsg_get_pos - return current position in netlink message | ||
531 | * @skb: socket buffer the message is stored in | ||
532 | * | ||
533 | * Returns a pointer to the current tail of the message. | ||
534 | */ | ||
535 | static inline void *nlmsg_get_pos(struct sk_buff *skb) | ||
536 | { | ||
537 | return skb->tail; | ||
538 | } | ||
539 | |||
540 | /** | ||
541 | * nlmsg_trim - Trim message to a mark | ||
542 | * @skb: socket buffer the message is stored in | ||
543 | * @mark: mark to trim to | ||
544 | * | ||
545 | * Trims the message to the provided mark. Returns -1. | ||
546 | */ | ||
547 | static inline int nlmsg_trim(struct sk_buff *skb, void *mark) | ||
548 | { | ||
549 | if (mark) | ||
550 | skb_trim(skb, (unsigned char *) mark - skb->data); | ||
551 | |||
552 | return -1; | ||
553 | } | ||
554 | |||
555 | /** | ||
483 | * nlmsg_cancel - Cancel construction of a netlink message | 556 | * nlmsg_cancel - Cancel construction of a netlink message |
484 | * @skb: socket buffer the message is stored in | 557 | * @skb: socket buffer the message is stored in |
485 | * @nlh: netlink message header | 558 | * @nlh: netlink message header |
@@ -489,9 +562,7 @@ static inline int nlmsg_end(struct sk_buff *skb, struct nlmsghdr *nlh) | |||
489 | */ | 562 | */ |
490 | static inline int nlmsg_cancel(struct sk_buff *skb, struct nlmsghdr *nlh) | 563 | static inline int nlmsg_cancel(struct sk_buff *skb, struct nlmsghdr *nlh) |
491 | { | 564 | { |
492 | skb_trim(skb, (unsigned char *) nlh - skb->data); | 565 | return nlmsg_trim(skb, nlh); |
493 | |||
494 | return -1; | ||
495 | } | 566 | } |
496 | 567 | ||
497 | /** | 568 | /** |
@@ -509,15 +580,16 @@ static inline void nlmsg_free(struct sk_buff *skb) | |||
509 | * @skb: netlink message as socket buffer | 580 | * @skb: netlink message as socket buffer |
510 | * @pid: own netlink pid to avoid sending to yourself | 581 | * @pid: own netlink pid to avoid sending to yourself |
511 | * @group: multicast group id | 582 | * @group: multicast group id |
583 | * @flags: allocation flags | ||
512 | */ | 584 | */ |
513 | static inline int nlmsg_multicast(struct sock *sk, struct sk_buff *skb, | 585 | static inline int nlmsg_multicast(struct sock *sk, struct sk_buff *skb, |
514 | u32 pid, unsigned int group) | 586 | u32 pid, unsigned int group, gfp_t flags) |
515 | { | 587 | { |
516 | int err; | 588 | int err; |
517 | 589 | ||
518 | NETLINK_CB(skb).dst_group = group; | 590 | NETLINK_CB(skb).dst_group = group; |
519 | 591 | ||
520 | err = netlink_broadcast(sk, skb, pid, group, GFP_KERNEL); | 592 | err = netlink_broadcast(sk, skb, pid, group, flags); |
521 | if (err > 0) | 593 | if (err > 0) |
522 | err = 0; | 594 | err = 0; |
523 | 595 | ||
@@ -631,6 +703,18 @@ static inline struct nlattr *nla_next(const struct nlattr *nla, int *remaining) | |||
631 | } | 703 | } |
632 | 704 | ||
633 | /** | 705 | /** |
706 | * nla_find_nested - find attribute in a set of nested attributes | ||
707 | * @nla: attribute containing the nested attributes | ||
708 | * @attrtype: type of attribute to look for | ||
709 | * | ||
710 | * Returns the first attribute which matches the specified type. | ||
711 | */ | ||
712 | static inline struct nlattr *nla_find_nested(struct nlattr *nla, int attrtype) | ||
713 | { | ||
714 | return nla_find(nla_data(nla), nla_len(nla), attrtype); | ||
715 | } | ||
716 | |||
717 | /** | ||
634 | * nla_parse_nested - parse nested attributes | 718 | * nla_parse_nested - parse nested attributes |
635 | * @tb: destination array with maxtype+1 elements | 719 | * @tb: destination array with maxtype+1 elements |
636 | * @maxtype: maximum attribute type to be expected | 720 | * @maxtype: maximum attribute type to be expected |
@@ -751,7 +835,7 @@ static inline int nla_put_msecs(struct sk_buff *skb, int attrtype, | |||
751 | #define NLA_PUT_STRING(skb, attrtype, value) \ | 835 | #define NLA_PUT_STRING(skb, attrtype, value) \ |
752 | NLA_PUT(skb, attrtype, strlen(value) + 1, value) | 836 | NLA_PUT(skb, attrtype, strlen(value) + 1, value) |
753 | 837 | ||
754 | #define NLA_PUT_FLAG(skb, attrtype, value) \ | 838 | #define NLA_PUT_FLAG(skb, attrtype) \ |
755 | NLA_PUT(skb, attrtype, 0, NULL) | 839 | NLA_PUT(skb, attrtype, 0, NULL) |
756 | 840 | ||
757 | #define NLA_PUT_MSECS(skb, attrtype, jiffies) \ | 841 | #define NLA_PUT_MSECS(skb, attrtype, jiffies) \ |
@@ -862,10 +946,7 @@ static inline int nla_nest_end(struct sk_buff *skb, struct nlattr *start) | |||
862 | */ | 946 | */ |
863 | static inline int nla_nest_cancel(struct sk_buff *skb, struct nlattr *start) | 947 | static inline int nla_nest_cancel(struct sk_buff *skb, struct nlattr *start) |
864 | { | 948 | { |
865 | if (start) | 949 | return nlmsg_trim(skb, start); |
866 | skb_trim(skb, (unsigned char *) start - skb->data); | ||
867 | |||
868 | return -1; | ||
869 | } | 950 | } |
870 | 951 | ||
871 | /** | 952 | /** |
@@ -880,4 +961,13 @@ static inline int nla_nest_cancel(struct sk_buff *skb, struct nlattr *start) | |||
880 | nla_ok(pos, rem); \ | 961 | nla_ok(pos, rem); \ |
881 | pos = nla_next(pos, &(rem))) | 962 | pos = nla_next(pos, &(rem))) |
882 | 963 | ||
964 | /** | ||
965 | * nla_for_each_nested - iterate over nested attributes | ||
966 | * @pos: loop counter, set to current attribute | ||
967 | * @nla: attribute containing the nested attributes | ||
968 | * @rem: initialized to len, holds bytes currently remaining in stream | ||
969 | */ | ||
970 | #define nla_for_each_nested(pos, nla, rem) \ | ||
971 | nla_for_each_attr(pos, nla_data(nla), nla_len(nla), rem) | ||
972 | |||
883 | #endif | 973 | #endif |
diff --git a/include/net/nexthop.h b/include/net/nexthop.h new file mode 100644 index 000000000000..3334dbfa5aa4 --- /dev/null +++ b/include/net/nexthop.h | |||
@@ -0,0 +1,33 @@ | |||
1 | #ifndef __NET_NEXTHOP_H | ||
2 | #define __NET_NEXTHOP_H | ||
3 | |||
4 | #include <linux/rtnetlink.h> | ||
5 | #include <net/netlink.h> | ||
6 | |||
7 | static inline int rtnh_ok(const struct rtnexthop *rtnh, int remaining) | ||
8 | { | ||
9 | return remaining >= sizeof(*rtnh) && | ||
10 | rtnh->rtnh_len >= sizeof(*rtnh) && | ||
11 | rtnh->rtnh_len <= remaining; | ||
12 | } | ||
13 | |||
14 | static inline struct rtnexthop *rtnh_next(const struct rtnexthop *rtnh, | ||
15 | int *remaining) | ||
16 | { | ||
17 | int totlen = NLA_ALIGN(rtnh->rtnh_len); | ||
18 | |||
19 | *remaining -= totlen; | ||
20 | return (struct rtnexthop *) ((char *) rtnh + totlen); | ||
21 | } | ||
22 | |||
23 | static inline struct nlattr *rtnh_attrs(const struct rtnexthop *rtnh) | ||
24 | { | ||
25 | return (struct nlattr *) ((char *) rtnh + NLA_ALIGN(sizeof(*rtnh))); | ||
26 | } | ||
27 | |||
28 | static inline int rtnh_attrlen(const struct rtnexthop *rtnh) | ||
29 | { | ||
30 | return rtnh->rtnh_len - NLA_ALIGN(sizeof(*rtnh)); | ||
31 | } | ||
32 | |||
33 | #endif | ||
diff --git a/include/net/pkt_act.h b/include/net/pkt_act.h deleted file mode 100644 index cf5e4d2e4c21..000000000000 --- a/include/net/pkt_act.h +++ /dev/null | |||
@@ -1,273 +0,0 @@ | |||
1 | #ifndef __NET_PKT_ACT_H | ||
2 | #define __NET_PKT_ACT_H | ||
3 | |||
4 | #include <asm/uaccess.h> | ||
5 | #include <asm/system.h> | ||
6 | #include <linux/bitops.h> | ||
7 | #include <linux/types.h> | ||
8 | #include <linux/kernel.h> | ||
9 | #include <linux/sched.h> | ||
10 | #include <linux/string.h> | ||
11 | #include <linux/mm.h> | ||
12 | #include <linux/socket.h> | ||
13 | #include <linux/sockios.h> | ||
14 | #include <linux/in.h> | ||
15 | #include <linux/errno.h> | ||
16 | #include <linux/interrupt.h> | ||
17 | #include <linux/skbuff.h> | ||
18 | #include <linux/rtnetlink.h> | ||
19 | #include <linux/module.h> | ||
20 | #include <linux/init.h> | ||
21 | #include <linux/proc_fs.h> | ||
22 | #include <net/sock.h> | ||
23 | #include <net/pkt_sched.h> | ||
24 | |||
25 | #define tca_st(val) (struct tcf_##val *) | ||
26 | #define PRIV(a,name) ( tca_st(name) (a)->priv) | ||
27 | |||
28 | #if 0 /* control */ | ||
29 | #define DPRINTK(format,args...) printk(KERN_DEBUG format,##args) | ||
30 | #else | ||
31 | #define DPRINTK(format,args...) | ||
32 | #endif | ||
33 | |||
34 | #if 0 /* data */ | ||
35 | #define D2PRINTK(format,args...) printk(KERN_DEBUG format,##args) | ||
36 | #else | ||
37 | #define D2PRINTK(format,args...) | ||
38 | #endif | ||
39 | |||
40 | static __inline__ unsigned | ||
41 | tcf_hash(u32 index) | ||
42 | { | ||
43 | return index & MY_TAB_MASK; | ||
44 | } | ||
45 | |||
46 | /* probably move this from being inline | ||
47 | * and put into act_generic | ||
48 | */ | ||
49 | static inline void | ||
50 | tcf_hash_destroy(struct tcf_st *p) | ||
51 | { | ||
52 | unsigned h = tcf_hash(p->index); | ||
53 | struct tcf_st **p1p; | ||
54 | |||
55 | for (p1p = &tcf_ht[h]; *p1p; p1p = &(*p1p)->next) { | ||
56 | if (*p1p == p) { | ||
57 | write_lock_bh(&tcf_t_lock); | ||
58 | *p1p = p->next; | ||
59 | write_unlock_bh(&tcf_t_lock); | ||
60 | #ifdef CONFIG_NET_ESTIMATOR | ||
61 | gen_kill_estimator(&p->bstats, &p->rate_est); | ||
62 | #endif | ||
63 | kfree(p); | ||
64 | return; | ||
65 | } | ||
66 | } | ||
67 | BUG_TRAP(0); | ||
68 | } | ||
69 | |||
70 | static inline int | ||
71 | tcf_hash_release(struct tcf_st *p, int bind ) | ||
72 | { | ||
73 | int ret = 0; | ||
74 | if (p) { | ||
75 | if (bind) { | ||
76 | p->bindcnt--; | ||
77 | } | ||
78 | p->refcnt--; | ||
79 | if(p->bindcnt <=0 && p->refcnt <= 0) { | ||
80 | tcf_hash_destroy(p); | ||
81 | ret = 1; | ||
82 | } | ||
83 | } | ||
84 | return ret; | ||
85 | } | ||
86 | |||
87 | static __inline__ int | ||
88 | tcf_dump_walker(struct sk_buff *skb, struct netlink_callback *cb, | ||
89 | struct tc_action *a) | ||
90 | { | ||
91 | struct tcf_st *p; | ||
92 | int err =0, index = -1,i= 0, s_i = 0, n_i = 0; | ||
93 | struct rtattr *r ; | ||
94 | |||
95 | read_lock(&tcf_t_lock); | ||
96 | |||
97 | s_i = cb->args[0]; | ||
98 | |||
99 | for (i = 0; i < MY_TAB_SIZE; i++) { | ||
100 | p = tcf_ht[tcf_hash(i)]; | ||
101 | |||
102 | for (; p; p = p->next) { | ||
103 | index++; | ||
104 | if (index < s_i) | ||
105 | continue; | ||
106 | a->priv = p; | ||
107 | a->order = n_i; | ||
108 | r = (struct rtattr*) skb->tail; | ||
109 | RTA_PUT(skb, a->order, 0, NULL); | ||
110 | err = tcf_action_dump_1(skb, a, 0, 0); | ||
111 | if (0 > err) { | ||
112 | index--; | ||
113 | skb_trim(skb, (u8*)r - skb->data); | ||
114 | goto done; | ||
115 | } | ||
116 | r->rta_len = skb->tail - (u8*)r; | ||
117 | n_i++; | ||
118 | if (n_i >= TCA_ACT_MAX_PRIO) { | ||
119 | goto done; | ||
120 | } | ||
121 | } | ||
122 | } | ||
123 | done: | ||
124 | read_unlock(&tcf_t_lock); | ||
125 | if (n_i) | ||
126 | cb->args[0] += n_i; | ||
127 | return n_i; | ||
128 | |||
129 | rtattr_failure: | ||
130 | skb_trim(skb, (u8*)r - skb->data); | ||
131 | goto done; | ||
132 | } | ||
133 | |||
134 | static __inline__ int | ||
135 | tcf_del_walker(struct sk_buff *skb, struct tc_action *a) | ||
136 | { | ||
137 | struct tcf_st *p, *s_p; | ||
138 | struct rtattr *r ; | ||
139 | int i= 0, n_i = 0; | ||
140 | |||
141 | r = (struct rtattr*) skb->tail; | ||
142 | RTA_PUT(skb, a->order, 0, NULL); | ||
143 | RTA_PUT(skb, TCA_KIND, IFNAMSIZ, a->ops->kind); | ||
144 | for (i = 0; i < MY_TAB_SIZE; i++) { | ||
145 | p = tcf_ht[tcf_hash(i)]; | ||
146 | |||
147 | while (p != NULL) { | ||
148 | s_p = p->next; | ||
149 | if (ACT_P_DELETED == tcf_hash_release(p, 0)) { | ||
150 | module_put(a->ops->owner); | ||
151 | } | ||
152 | n_i++; | ||
153 | p = s_p; | ||
154 | } | ||
155 | } | ||
156 | RTA_PUT(skb, TCA_FCNT, 4, &n_i); | ||
157 | r->rta_len = skb->tail - (u8*)r; | ||
158 | |||
159 | return n_i; | ||
160 | rtattr_failure: | ||
161 | skb_trim(skb, (u8*)r - skb->data); | ||
162 | return -EINVAL; | ||
163 | } | ||
164 | |||
165 | static __inline__ int | ||
166 | tcf_generic_walker(struct sk_buff *skb, struct netlink_callback *cb, int type, | ||
167 | struct tc_action *a) | ||
168 | { | ||
169 | if (type == RTM_DELACTION) { | ||
170 | return tcf_del_walker(skb,a); | ||
171 | } else if (type == RTM_GETACTION) { | ||
172 | return tcf_dump_walker(skb,cb,a); | ||
173 | } else { | ||
174 | printk("tcf_generic_walker: unknown action %d\n",type); | ||
175 | return -EINVAL; | ||
176 | } | ||
177 | } | ||
178 | |||
179 | static __inline__ struct tcf_st * | ||
180 | tcf_hash_lookup(u32 index) | ||
181 | { | ||
182 | struct tcf_st *p; | ||
183 | |||
184 | read_lock(&tcf_t_lock); | ||
185 | for (p = tcf_ht[tcf_hash(index)]; p; p = p->next) { | ||
186 | if (p->index == index) | ||
187 | break; | ||
188 | } | ||
189 | read_unlock(&tcf_t_lock); | ||
190 | return p; | ||
191 | } | ||
192 | |||
193 | static __inline__ u32 | ||
194 | tcf_hash_new_index(void) | ||
195 | { | ||
196 | do { | ||
197 | if (++idx_gen == 0) | ||
198 | idx_gen = 1; | ||
199 | } while (tcf_hash_lookup(idx_gen)); | ||
200 | |||
201 | return idx_gen; | ||
202 | } | ||
203 | |||
204 | |||
205 | static inline int | ||
206 | tcf_hash_search(struct tc_action *a, u32 index) | ||
207 | { | ||
208 | struct tcf_st *p = tcf_hash_lookup(index); | ||
209 | |||
210 | if (p != NULL) { | ||
211 | a->priv = p; | ||
212 | return 1; | ||
213 | } | ||
214 | return 0; | ||
215 | } | ||
216 | |||
217 | #ifdef CONFIG_NET_ACT_INIT | ||
218 | static inline struct tcf_st * | ||
219 | tcf_hash_check(u32 index, struct tc_action *a, int ovr, int bind) | ||
220 | { | ||
221 | struct tcf_st *p = NULL; | ||
222 | if (index && (p = tcf_hash_lookup(index)) != NULL) { | ||
223 | if (bind) { | ||
224 | p->bindcnt++; | ||
225 | p->refcnt++; | ||
226 | } | ||
227 | a->priv = p; | ||
228 | } | ||
229 | return p; | ||
230 | } | ||
231 | |||
232 | static inline struct tcf_st * | ||
233 | tcf_hash_create(u32 index, struct rtattr *est, struct tc_action *a, int size, int ovr, int bind) | ||
234 | { | ||
235 | struct tcf_st *p = NULL; | ||
236 | |||
237 | p = kmalloc(size, GFP_KERNEL); | ||
238 | if (p == NULL) | ||
239 | return p; | ||
240 | |||
241 | memset(p, 0, size); | ||
242 | p->refcnt = 1; | ||
243 | |||
244 | if (bind) { | ||
245 | p->bindcnt = 1; | ||
246 | } | ||
247 | |||
248 | spin_lock_init(&p->lock); | ||
249 | p->stats_lock = &p->lock; | ||
250 | p->index = index ? : tcf_hash_new_index(); | ||
251 | p->tm.install = jiffies; | ||
252 | p->tm.lastuse = jiffies; | ||
253 | #ifdef CONFIG_NET_ESTIMATOR | ||
254 | if (est) | ||
255 | gen_new_estimator(&p->bstats, &p->rate_est, p->stats_lock, est); | ||
256 | #endif | ||
257 | a->priv = (void *) p; | ||
258 | return p; | ||
259 | } | ||
260 | |||
261 | static inline void tcf_hash_insert(struct tcf_st *p) | ||
262 | { | ||
263 | unsigned h = tcf_hash(p->index); | ||
264 | |||
265 | write_lock_bh(&tcf_t_lock); | ||
266 | p->next = tcf_ht[h]; | ||
267 | tcf_ht[h] = p; | ||
268 | write_unlock_bh(&tcf_t_lock); | ||
269 | } | ||
270 | |||
271 | #endif | ||
272 | |||
273 | #endif | ||
diff --git a/include/net/request_sock.h b/include/net/request_sock.h index c5d7f920c352..8e165ca16bd8 100644 --- a/include/net/request_sock.h +++ b/include/net/request_sock.h | |||
@@ -53,6 +53,7 @@ struct request_sock { | |||
53 | unsigned long expires; | 53 | unsigned long expires; |
54 | struct request_sock_ops *rsk_ops; | 54 | struct request_sock_ops *rsk_ops; |
55 | struct sock *sk; | 55 | struct sock *sk; |
56 | u32 secid; | ||
56 | }; | 57 | }; |
57 | 58 | ||
58 | static inline struct request_sock *reqsk_alloc(struct request_sock_ops *ops) | 59 | static inline struct request_sock *reqsk_alloc(struct request_sock_ops *ops) |
diff --git a/include/net/route.h b/include/net/route.h index c4a068692dcc..7f93ac0e0899 100644 --- a/include/net/route.h +++ b/include/net/route.h | |||
@@ -32,6 +32,7 @@ | |||
32 | #include <linux/route.h> | 32 | #include <linux/route.h> |
33 | #include <linux/ip.h> | 33 | #include <linux/ip.h> |
34 | #include <linux/cache.h> | 34 | #include <linux/cache.h> |
35 | #include <linux/security.h> | ||
35 | 36 | ||
36 | #ifndef __KERNEL__ | 37 | #ifndef __KERNEL__ |
37 | #warning This file is not supposed to be used outside of kernel. | 38 | #warning This file is not supposed to be used outside of kernel. |
@@ -166,6 +167,7 @@ static inline int ip_route_connect(struct rtable **rp, u32 dst, | |||
166 | ip_rt_put(*rp); | 167 | ip_rt_put(*rp); |
167 | *rp = NULL; | 168 | *rp = NULL; |
168 | } | 169 | } |
170 | security_sk_classify_flow(sk, &fl); | ||
169 | return ip_route_output_flow(rp, &fl, sk, 0); | 171 | return ip_route_output_flow(rp, &fl, sk, 0); |
170 | } | 172 | } |
171 | 173 | ||
@@ -182,6 +184,7 @@ static inline int ip_route_newports(struct rtable **rp, u8 protocol, | |||
182 | fl.proto = protocol; | 184 | fl.proto = protocol; |
183 | ip_rt_put(*rp); | 185 | ip_rt_put(*rp); |
184 | *rp = NULL; | 186 | *rp = NULL; |
187 | security_sk_classify_flow(sk, &fl); | ||
185 | return ip_route_output_flow(rp, &fl, sk, 0); | 188 | return ip_route_output_flow(rp, &fl, sk, 0); |
186 | } | 189 | } |
187 | return 0; | 190 | return 0; |
diff --git a/include/net/sctp/constants.h b/include/net/sctp/constants.h index 57166bfdf8eb..6c632e26f72d 100644 --- a/include/net/sctp/constants.h +++ b/include/net/sctp/constants.h | |||
@@ -264,10 +264,10 @@ enum { SCTP_MAX_DUP_TSNS = 16 }; | |||
264 | enum { SCTP_MAX_GABS = 16 }; | 264 | enum { SCTP_MAX_GABS = 16 }; |
265 | 265 | ||
266 | /* Heartbeat interval - 30 secs */ | 266 | /* Heartbeat interval - 30 secs */ |
267 | #define SCTP_DEFAULT_TIMEOUT_HEARTBEAT (30 * HZ) | 267 | #define SCTP_DEFAULT_TIMEOUT_HEARTBEAT (30*1000) |
268 | 268 | ||
269 | /* Delayed sack timer - 200ms */ | 269 | /* Delayed sack timer - 200ms */ |
270 | #define SCTP_DEFAULT_TIMEOUT_SACK ((200 * HZ) / 1000) | 270 | #define SCTP_DEFAULT_TIMEOUT_SACK (200) |
271 | 271 | ||
272 | /* RTO.Initial - 3 seconds | 272 | /* RTO.Initial - 3 seconds |
273 | * RTO.Min - 1 second | 273 | * RTO.Min - 1 second |
@@ -275,9 +275,9 @@ enum { SCTP_MAX_GABS = 16 }; | |||
275 | * RTO.Alpha - 1/8 | 275 | * RTO.Alpha - 1/8 |
276 | * RTO.Beta - 1/4 | 276 | * RTO.Beta - 1/4 |
277 | */ | 277 | */ |
278 | #define SCTP_RTO_INITIAL (3 * HZ) | 278 | #define SCTP_RTO_INITIAL (3 * 1000) |
279 | #define SCTP_RTO_MIN (1 * HZ) | 279 | #define SCTP_RTO_MIN (1 * 1000) |
280 | #define SCTP_RTO_MAX (60 * HZ) | 280 | #define SCTP_RTO_MAX (60 * 1000) |
281 | 281 | ||
282 | #define SCTP_RTO_ALPHA 3 /* 1/8 when converted to right shifts. */ | 282 | #define SCTP_RTO_ALPHA 3 /* 1/8 when converted to right shifts. */ |
283 | #define SCTP_RTO_BETA 2 /* 1/4 when converted to right shifts. */ | 283 | #define SCTP_RTO_BETA 2 /* 1/4 when converted to right shifts. */ |
@@ -290,8 +290,7 @@ enum { SCTP_MAX_GABS = 16 }; | |||
290 | #define SCTP_DEF_MAX_INIT 6 | 290 | #define SCTP_DEF_MAX_INIT 6 |
291 | #define SCTP_DEF_MAX_SEND 10 | 291 | #define SCTP_DEF_MAX_SEND 10 |
292 | 292 | ||
293 | #define SCTP_DEFAULT_COOKIE_LIFE_SEC 60 /* seconds */ | 293 | #define SCTP_DEFAULT_COOKIE_LIFE (60 * 1000) /* 60 seconds */ |
294 | #define SCTP_DEFAULT_COOKIE_LIFE_USEC 0 /* microseconds */ | ||
295 | 294 | ||
296 | #define SCTP_DEFAULT_MINWINDOW 1500 /* default minimum rwnd size */ | 295 | #define SCTP_DEFAULT_MINWINDOW 1500 /* default minimum rwnd size */ |
297 | #define SCTP_DEFAULT_MAXWINDOW 65535 /* default rwnd size */ | 296 | #define SCTP_DEFAULT_MAXWINDOW 65535 /* default rwnd size */ |
diff --git a/include/net/sctp/sctp.h b/include/net/sctp/sctp.h index 1c1abce5f6b6..ee68a3124076 100644 --- a/include/net/sctp/sctp.h +++ b/include/net/sctp/sctp.h | |||
@@ -128,6 +128,8 @@ extern int sctp_copy_local_addr_list(struct sctp_bind_addr *, | |||
128 | int flags); | 128 | int flags); |
129 | extern struct sctp_pf *sctp_get_pf_specific(sa_family_t family); | 129 | extern struct sctp_pf *sctp_get_pf_specific(sa_family_t family); |
130 | extern int sctp_register_pf(struct sctp_pf *, sa_family_t); | 130 | extern int sctp_register_pf(struct sctp_pf *, sa_family_t); |
131 | int sctp_inetaddr_event(struct notifier_block *this, unsigned long ev, | ||
132 | void *ptr); | ||
131 | 133 | ||
132 | /* | 134 | /* |
133 | * sctp/socket.c | 135 | * sctp/socket.c |
@@ -178,6 +180,17 @@ void sctp_backlog_migrate(struct sctp_association *assoc, | |||
178 | struct sock *oldsk, struct sock *newsk); | 180 | struct sock *oldsk, struct sock *newsk); |
179 | 181 | ||
180 | /* | 182 | /* |
183 | * sctp/proc.c | ||
184 | */ | ||
185 | int sctp_snmp_proc_init(void); | ||
186 | void sctp_snmp_proc_exit(void); | ||
187 | int sctp_eps_proc_init(void); | ||
188 | void sctp_eps_proc_exit(void); | ||
189 | int sctp_assocs_proc_init(void); | ||
190 | void sctp_assocs_proc_exit(void); | ||
191 | |||
192 | |||
193 | /* | ||
181 | * Section: Macros, externs, and inlines | 194 | * Section: Macros, externs, and inlines |
182 | */ | 195 | */ |
183 | 196 | ||
@@ -216,6 +229,50 @@ DECLARE_SNMP_STAT(struct sctp_mib, sctp_statistics); | |||
216 | 229 | ||
217 | #endif /* !TEST_FRAME */ | 230 | #endif /* !TEST_FRAME */ |
218 | 231 | ||
232 | /* sctp mib definitions */ | ||
233 | enum | ||
234 | { | ||
235 | SCTP_MIB_NUM = 0, | ||
236 | SCTP_MIB_CURRESTAB, /* CurrEstab */ | ||
237 | SCTP_MIB_ACTIVEESTABS, /* ActiveEstabs */ | ||
238 | SCTP_MIB_PASSIVEESTABS, /* PassiveEstabs */ | ||
239 | SCTP_MIB_ABORTEDS, /* Aborteds */ | ||
240 | SCTP_MIB_SHUTDOWNS, /* Shutdowns */ | ||
241 | SCTP_MIB_OUTOFBLUES, /* OutOfBlues */ | ||
242 | SCTP_MIB_CHECKSUMERRORS, /* ChecksumErrors */ | ||
243 | SCTP_MIB_OUTCTRLCHUNKS, /* OutCtrlChunks */ | ||
244 | SCTP_MIB_OUTORDERCHUNKS, /* OutOrderChunks */ | ||
245 | SCTP_MIB_OUTUNORDERCHUNKS, /* OutUnorderChunks */ | ||
246 | SCTP_MIB_INCTRLCHUNKS, /* InCtrlChunks */ | ||
247 | SCTP_MIB_INORDERCHUNKS, /* InOrderChunks */ | ||
248 | SCTP_MIB_INUNORDERCHUNKS, /* InUnorderChunks */ | ||
249 | SCTP_MIB_FRAGUSRMSGS, /* FragUsrMsgs */ | ||
250 | SCTP_MIB_REASMUSRMSGS, /* ReasmUsrMsgs */ | ||
251 | SCTP_MIB_OUTSCTPPACKS, /* OutSCTPPacks */ | ||
252 | SCTP_MIB_INSCTPPACKS, /* InSCTPPacks */ | ||
253 | SCTP_MIB_T1_INIT_EXPIREDS, | ||
254 | SCTP_MIB_T1_COOKIE_EXPIREDS, | ||
255 | SCTP_MIB_T2_SHUTDOWN_EXPIREDS, | ||
256 | SCTP_MIB_T3_RTX_EXPIREDS, | ||
257 | SCTP_MIB_T4_RTO_EXPIREDS, | ||
258 | SCTP_MIB_T5_SHUTDOWN_GUARD_EXPIREDS, | ||
259 | SCTP_MIB_DELAY_SACK_EXPIREDS, | ||
260 | SCTP_MIB_AUTOCLOSE_EXPIREDS, | ||
261 | SCTP_MIB_T3_RETRANSMITS, | ||
262 | SCTP_MIB_PMTUD_RETRANSMITS, | ||
263 | SCTP_MIB_FAST_RETRANSMITS, | ||
264 | SCTP_MIB_IN_PKT_SOFTIRQ, | ||
265 | SCTP_MIB_IN_PKT_BACKLOG, | ||
266 | SCTP_MIB_IN_PKT_DISCARDS, | ||
267 | SCTP_MIB_IN_DATA_CHUNK_DISCARDS, | ||
268 | __SCTP_MIB_MAX | ||
269 | }; | ||
270 | |||
271 | #define SCTP_MIB_MAX __SCTP_MIB_MAX | ||
272 | struct sctp_mib { | ||
273 | unsigned long mibs[SCTP_MIB_MAX]; | ||
274 | } __SNMP_MIB_ALIGN__; | ||
275 | |||
219 | 276 | ||
220 | /* Print debugging messages. */ | 277 | /* Print debugging messages. */ |
221 | #if SCTP_DEBUG | 278 | #if SCTP_DEBUG |
diff --git a/include/net/sctp/structs.h b/include/net/sctp/structs.h index 0412e730c765..c6d93bb0dcd2 100644 --- a/include/net/sctp/structs.h +++ b/include/net/sctp/structs.h | |||
@@ -128,9 +128,9 @@ extern struct sctp_globals { | |||
128 | * RTO.Alpha - 1/8 (3 when converted to right shifts.) | 128 | * RTO.Alpha - 1/8 (3 when converted to right shifts.) |
129 | * RTO.Beta - 1/4 (2 when converted to right shifts.) | 129 | * RTO.Beta - 1/4 (2 when converted to right shifts.) |
130 | */ | 130 | */ |
131 | unsigned long rto_initial; | 131 | unsigned int rto_initial; |
132 | unsigned long rto_min; | 132 | unsigned int rto_min; |
133 | unsigned long rto_max; | 133 | unsigned int rto_max; |
134 | 134 | ||
135 | /* Note: rto_alpha and rto_beta are really defined as inverse | 135 | /* Note: rto_alpha and rto_beta are really defined as inverse |
136 | * powers of two to facilitate integer operations. | 136 | * powers of two to facilitate integer operations. |
@@ -145,13 +145,13 @@ extern struct sctp_globals { | |||
145 | int cookie_preserve_enable; | 145 | int cookie_preserve_enable; |
146 | 146 | ||
147 | /* Valid.Cookie.Life - 60 seconds */ | 147 | /* Valid.Cookie.Life - 60 seconds */ |
148 | unsigned long valid_cookie_life; | 148 | unsigned int valid_cookie_life; |
149 | 149 | ||
150 | /* Delayed SACK timeout 200ms default*/ | 150 | /* Delayed SACK timeout 200ms default*/ |
151 | unsigned long sack_timeout; | 151 | unsigned int sack_timeout; |
152 | 152 | ||
153 | /* HB.interval - 30 seconds */ | 153 | /* HB.interval - 30 seconds */ |
154 | unsigned long hb_interval; | 154 | unsigned int hb_interval; |
155 | 155 | ||
156 | /* Association.Max.Retrans - 10 attempts | 156 | /* Association.Max.Retrans - 10 attempts |
157 | * Path.Max.Retrans - 5 attempts (per destination address) | 157 | * Path.Max.Retrans - 5 attempts (per destination address) |
diff --git a/include/net/snmp.h b/include/net/snmp.h index a36bed8ea210..464970e39ec0 100644 --- a/include/net/snmp.h +++ b/include/net/snmp.h | |||
@@ -100,12 +100,6 @@ struct udp_mib { | |||
100 | unsigned long mibs[UDP_MIB_MAX]; | 100 | unsigned long mibs[UDP_MIB_MAX]; |
101 | } __SNMP_MIB_ALIGN__; | 101 | } __SNMP_MIB_ALIGN__; |
102 | 102 | ||
103 | /* SCTP */ | ||
104 | #define SCTP_MIB_MAX __SCTP_MIB_MAX | ||
105 | struct sctp_mib { | ||
106 | unsigned long mibs[SCTP_MIB_MAX]; | ||
107 | } __SNMP_MIB_ALIGN__; | ||
108 | |||
109 | /* Linux */ | 103 | /* Linux */ |
110 | #define LINUX_MIB_MAX __LINUX_MIB_MAX | 104 | #define LINUX_MIB_MAX __LINUX_MIB_MAX |
111 | struct linux_mib { | 105 | struct linux_mib { |
diff --git a/include/net/sock.h b/include/net/sock.h index 324b3ea233d6..edd4d73ce7f5 100644 --- a/include/net/sock.h +++ b/include/net/sock.h | |||
@@ -862,30 +862,24 @@ extern void sock_init_data(struct socket *sock, struct sock *sk); | |||
862 | * | 862 | * |
863 | */ | 863 | */ |
864 | 864 | ||
865 | static inline int sk_filter(struct sock *sk, struct sk_buff *skb, int needlock) | 865 | static inline int sk_filter(struct sock *sk, struct sk_buff *skb) |
866 | { | 866 | { |
867 | int err; | 867 | int err; |
868 | struct sk_filter *filter; | ||
868 | 869 | ||
869 | err = security_sock_rcv_skb(sk, skb); | 870 | err = security_sock_rcv_skb(sk, skb); |
870 | if (err) | 871 | if (err) |
871 | return err; | 872 | return err; |
872 | 873 | ||
873 | if (sk->sk_filter) { | 874 | rcu_read_lock_bh(); |
874 | struct sk_filter *filter; | 875 | filter = sk->sk_filter; |
875 | 876 | if (filter) { | |
876 | if (needlock) | 877 | unsigned int pkt_len = sk_run_filter(skb, filter->insns, |
877 | bh_lock_sock(sk); | 878 | filter->len); |
878 | 879 | err = pkt_len ? pskb_trim(skb, pkt_len) : -EPERM; | |
879 | filter = sk->sk_filter; | ||
880 | if (filter) { | ||
881 | unsigned int pkt_len = sk_run_filter(skb, filter->insns, | ||
882 | filter->len); | ||
883 | err = pkt_len ? pskb_trim(skb, pkt_len) : -EPERM; | ||
884 | } | ||
885 | |||
886 | if (needlock) | ||
887 | bh_unlock_sock(sk); | ||
888 | } | 880 | } |
881 | rcu_read_unlock_bh(); | ||
882 | |||
889 | return err; | 883 | return err; |
890 | } | 884 | } |
891 | 885 | ||
@@ -897,6 +891,12 @@ static inline int sk_filter(struct sock *sk, struct sk_buff *skb, int needlock) | |||
897 | * Remove a filter from a socket and release its resources. | 891 | * Remove a filter from a socket and release its resources. |
898 | */ | 892 | */ |
899 | 893 | ||
894 | static inline void sk_filter_rcu_free(struct rcu_head *rcu) | ||
895 | { | ||
896 | struct sk_filter *fp = container_of(rcu, struct sk_filter, rcu); | ||
897 | kfree(fp); | ||
898 | } | ||
899 | |||
900 | static inline void sk_filter_release(struct sock *sk, struct sk_filter *fp) | 900 | static inline void sk_filter_release(struct sock *sk, struct sk_filter *fp) |
901 | { | 901 | { |
902 | unsigned int size = sk_filter_len(fp); | 902 | unsigned int size = sk_filter_len(fp); |
@@ -904,7 +904,7 @@ static inline void sk_filter_release(struct sock *sk, struct sk_filter *fp) | |||
904 | atomic_sub(size, &sk->sk_omem_alloc); | 904 | atomic_sub(size, &sk->sk_omem_alloc); |
905 | 905 | ||
906 | if (atomic_dec_and_test(&fp->refcnt)) | 906 | if (atomic_dec_and_test(&fp->refcnt)) |
907 | kfree(fp); | 907 | call_rcu_bh(&fp->rcu, sk_filter_rcu_free); |
908 | } | 908 | } |
909 | 909 | ||
910 | static inline void sk_filter_charge(struct sock *sk, struct sk_filter *fp) | 910 | static inline void sk_filter_charge(struct sock *sk, struct sk_filter *fp) |
@@ -969,9 +969,23 @@ static inline void sock_graft(struct sock *sk, struct socket *parent) | |||
969 | sk->sk_sleep = &parent->wait; | 969 | sk->sk_sleep = &parent->wait; |
970 | parent->sk = sk; | 970 | parent->sk = sk; |
971 | sk->sk_socket = parent; | 971 | sk->sk_socket = parent; |
972 | security_sock_graft(sk, parent); | ||
972 | write_unlock_bh(&sk->sk_callback_lock); | 973 | write_unlock_bh(&sk->sk_callback_lock); |
973 | } | 974 | } |
974 | 975 | ||
976 | static inline void sock_copy(struct sock *nsk, const struct sock *osk) | ||
977 | { | ||
978 | #ifdef CONFIG_SECURITY_NETWORK | ||
979 | void *sptr = nsk->sk_security; | ||
980 | #endif | ||
981 | |||
982 | memcpy(nsk, osk, osk->sk_prot->obj_size); | ||
983 | #ifdef CONFIG_SECURITY_NETWORK | ||
984 | nsk->sk_security = sptr; | ||
985 | security_sk_clone(osk, nsk); | ||
986 | #endif | ||
987 | } | ||
988 | |||
975 | extern int sock_i_uid(struct sock *sk); | 989 | extern int sock_i_uid(struct sock *sk); |
976 | extern unsigned long sock_i_ino(struct sock *sk); | 990 | extern unsigned long sock_i_ino(struct sock *sk); |
977 | 991 | ||
diff --git a/include/net/tc_act/tc_defact.h b/include/net/tc_act/tc_defact.h index 463aa671f95d..65f024b80958 100644 --- a/include/net/tc_act/tc_defact.h +++ b/include/net/tc_act/tc_defact.h | |||
@@ -3,11 +3,12 @@ | |||
3 | 3 | ||
4 | #include <net/act_api.h> | 4 | #include <net/act_api.h> |
5 | 5 | ||
6 | struct tcf_defact | 6 | struct tcf_defact { |
7 | { | 7 | struct tcf_common common; |
8 | tca_gen(defact); | 8 | u32 tcfd_datalen; |
9 | u32 datalen; | 9 | void *tcfd_defdata; |
10 | void *defdata; | ||
11 | }; | 10 | }; |
11 | #define to_defact(pc) \ | ||
12 | container_of(pc, struct tcf_defact, common) | ||
12 | 13 | ||
13 | #endif | 14 | #endif /* __NET_TC_DEF_H */ |
diff --git a/include/net/tc_act/tc_gact.h b/include/net/tc_act/tc_gact.h index 59f0d9628ad1..9e3f6767b80e 100644 --- a/include/net/tc_act/tc_gact.h +++ b/include/net/tc_act/tc_gact.h | |||
@@ -3,15 +3,15 @@ | |||
3 | 3 | ||
4 | #include <net/act_api.h> | 4 | #include <net/act_api.h> |
5 | 5 | ||
6 | struct tcf_gact | 6 | struct tcf_gact { |
7 | { | 7 | struct tcf_common common; |
8 | tca_gen(gact); | ||
9 | #ifdef CONFIG_GACT_PROB | 8 | #ifdef CONFIG_GACT_PROB |
10 | u16 ptype; | 9 | u16 tcfg_ptype; |
11 | u16 pval; | 10 | u16 tcfg_pval; |
12 | int paction; | 11 | int tcfg_paction; |
13 | #endif | 12 | #endif |
14 | |||
15 | }; | 13 | }; |
16 | 14 | #define to_gact(pc) \ | |
17 | #endif | 15 | container_of(pc, struct tcf_gact, common) |
16 | |||
17 | #endif /* __NET_TC_GACT_H */ | ||
diff --git a/include/net/tc_act/tc_ipt.h b/include/net/tc_act/tc_ipt.h index cb37ad08427f..f7d25dfcc4b7 100644 --- a/include/net/tc_act/tc_ipt.h +++ b/include/net/tc_act/tc_ipt.h | |||
@@ -5,12 +5,13 @@ | |||
5 | 5 | ||
6 | struct xt_entry_target; | 6 | struct xt_entry_target; |
7 | 7 | ||
8 | struct tcf_ipt | 8 | struct tcf_ipt { |
9 | { | 9 | struct tcf_common common; |
10 | tca_gen(ipt); | 10 | u32 tcfi_hook; |
11 | u32 hook; | 11 | char *tcfi_tname; |
12 | char *tname; | 12 | struct xt_entry_target *tcfi_t; |
13 | struct xt_entry_target *t; | ||
14 | }; | 13 | }; |
14 | #define to_ipt(pc) \ | ||
15 | container_of(pc, struct tcf_ipt, common) | ||
15 | 16 | ||
16 | #endif | 17 | #endif /* __NET_TC_IPT_H */ |
diff --git a/include/net/tc_act/tc_mirred.h b/include/net/tc_act/tc_mirred.h index b5c32f65c12c..ceac661cdfd5 100644 --- a/include/net/tc_act/tc_mirred.h +++ b/include/net/tc_act/tc_mirred.h | |||
@@ -3,13 +3,14 @@ | |||
3 | 3 | ||
4 | #include <net/act_api.h> | 4 | #include <net/act_api.h> |
5 | 5 | ||
6 | struct tcf_mirred | 6 | struct tcf_mirred { |
7 | { | 7 | struct tcf_common common; |
8 | tca_gen(mirred); | 8 | int tcfm_eaction; |
9 | int eaction; | 9 | int tcfm_ifindex; |
10 | int ifindex; | 10 | int tcfm_ok_push; |
11 | int ok_push; | 11 | struct net_device *tcfm_dev; |
12 | struct net_device *dev; | ||
13 | }; | 12 | }; |
13 | #define to_mirred(pc) \ | ||
14 | container_of(pc, struct tcf_mirred, common) | ||
14 | 15 | ||
15 | #endif | 16 | #endif /* __NET_TC_MIR_H */ |
diff --git a/include/net/tc_act/tc_pedit.h b/include/net/tc_act/tc_pedit.h index eb21689d759d..e6f6e15956f5 100644 --- a/include/net/tc_act/tc_pedit.h +++ b/include/net/tc_act/tc_pedit.h | |||
@@ -3,12 +3,13 @@ | |||
3 | 3 | ||
4 | #include <net/act_api.h> | 4 | #include <net/act_api.h> |
5 | 5 | ||
6 | struct tcf_pedit | 6 | struct tcf_pedit { |
7 | { | 7 | struct tcf_common common; |
8 | tca_gen(pedit); | 8 | unsigned char tcfp_nkeys; |
9 | unsigned char nkeys; | 9 | unsigned char tcfp_flags; |
10 | unsigned char flags; | 10 | struct tc_pedit_key *tcfp_keys; |
11 | struct tc_pedit_key *keys; | ||
12 | }; | 11 | }; |
12 | #define to_pedit(pc) \ | ||
13 | container_of(pc, struct tcf_pedit, common) | ||
13 | 14 | ||
14 | #endif | 15 | #endif /* __NET_TC_PED_H */ |
diff --git a/include/net/udp.h b/include/net/udp.h index 766fba1369ce..db0c05f67546 100644 --- a/include/net/udp.h +++ b/include/net/udp.h | |||
@@ -30,25 +30,9 @@ | |||
30 | 30 | ||
31 | #define UDP_HTABLE_SIZE 128 | 31 | #define UDP_HTABLE_SIZE 128 |
32 | 32 | ||
33 | /* udp.c: This needs to be shared by v4 and v6 because the lookup | ||
34 | * and hashing code needs to work with different AF's yet | ||
35 | * the port space is shared. | ||
36 | */ | ||
37 | extern struct hlist_head udp_hash[UDP_HTABLE_SIZE]; | 33 | extern struct hlist_head udp_hash[UDP_HTABLE_SIZE]; |
38 | extern rwlock_t udp_hash_lock; | 34 | extern rwlock_t udp_hash_lock; |
39 | 35 | ||
40 | extern int udp_port_rover; | ||
41 | |||
42 | static inline int udp_lport_inuse(u16 num) | ||
43 | { | ||
44 | struct sock *sk; | ||
45 | struct hlist_node *node; | ||
46 | |||
47 | sk_for_each(sk, node, &udp_hash[num & (UDP_HTABLE_SIZE - 1)]) | ||
48 | if (inet_sk(sk)->num == num) | ||
49 | return 1; | ||
50 | return 0; | ||
51 | } | ||
52 | 36 | ||
53 | /* Note: this must match 'valbool' in sock_setsockopt */ | 37 | /* Note: this must match 'valbool' in sock_setsockopt */ |
54 | #define UDP_CSUM_NOXMIT 1 | 38 | #define UDP_CSUM_NOXMIT 1 |
@@ -63,6 +47,8 @@ extern struct proto udp_prot; | |||
63 | 47 | ||
64 | struct sk_buff; | 48 | struct sk_buff; |
65 | 49 | ||
50 | extern int udp_get_port(struct sock *sk, unsigned short snum, | ||
51 | int (*saddr_cmp)(const struct sock *, const struct sock *)); | ||
66 | extern void udp_err(struct sk_buff *, u32); | 52 | extern void udp_err(struct sk_buff *, u32); |
67 | 53 | ||
68 | extern int udp_sendmsg(struct kiocb *iocb, struct sock *sk, | 54 | extern int udp_sendmsg(struct kiocb *iocb, struct sock *sk, |
diff --git a/include/net/xfrm.h b/include/net/xfrm.h index 3ecd9fa1ed4b..11e0b1d6bd47 100644 --- a/include/net/xfrm.h +++ b/include/net/xfrm.h | |||
@@ -9,6 +9,7 @@ | |||
9 | #include <linux/skbuff.h> | 9 | #include <linux/skbuff.h> |
10 | #include <linux/socket.h> | 10 | #include <linux/socket.h> |
11 | #include <linux/pfkeyv2.h> | 11 | #include <linux/pfkeyv2.h> |
12 | #include <linux/ipsec.h> | ||
12 | #include <linux/in6.h> | 13 | #include <linux/in6.h> |
13 | #include <linux/mutex.h> | 14 | #include <linux/mutex.h> |
14 | 15 | ||
@@ -93,8 +94,9 @@ extern struct mutex xfrm_cfg_mutex; | |||
93 | struct xfrm_state | 94 | struct xfrm_state |
94 | { | 95 | { |
95 | /* Note: bydst is re-used during gc */ | 96 | /* Note: bydst is re-used during gc */ |
96 | struct list_head bydst; | 97 | struct hlist_node bydst; |
97 | struct list_head byspi; | 98 | struct hlist_node bysrc; |
99 | struct hlist_node byspi; | ||
98 | 100 | ||
99 | atomic_t refcnt; | 101 | atomic_t refcnt; |
100 | spinlock_t lock; | 102 | spinlock_t lock; |
@@ -102,6 +104,8 @@ struct xfrm_state | |||
102 | struct xfrm_id id; | 104 | struct xfrm_id id; |
103 | struct xfrm_selector sel; | 105 | struct xfrm_selector sel; |
104 | 106 | ||
107 | u32 genid; | ||
108 | |||
105 | /* Key manger bits */ | 109 | /* Key manger bits */ |
106 | struct { | 110 | struct { |
107 | u8 state; | 111 | u8 state; |
@@ -132,6 +136,9 @@ struct xfrm_state | |||
132 | /* Data for encapsulator */ | 136 | /* Data for encapsulator */ |
133 | struct xfrm_encap_tmpl *encap; | 137 | struct xfrm_encap_tmpl *encap; |
134 | 138 | ||
139 | /* Data for care-of address */ | ||
140 | xfrm_address_t *coaddr; | ||
141 | |||
135 | /* IPComp needs an IPIP tunnel for handling uncompressed packets */ | 142 | /* IPComp needs an IPIP tunnel for handling uncompressed packets */ |
136 | struct xfrm_state *tunnel; | 143 | struct xfrm_state *tunnel; |
137 | 144 | ||
@@ -162,6 +169,9 @@ struct xfrm_state | |||
162 | struct xfrm_lifetime_cur curlft; | 169 | struct xfrm_lifetime_cur curlft; |
163 | struct timer_list timer; | 170 | struct timer_list timer; |
164 | 171 | ||
172 | /* Last used time */ | ||
173 | u64 lastused; | ||
174 | |||
165 | /* Reference to data common to all the instances of this | 175 | /* Reference to data common to all the instances of this |
166 | * transformer. */ | 176 | * transformer. */ |
167 | struct xfrm_type *type; | 177 | struct xfrm_type *type; |
@@ -195,6 +205,7 @@ struct km_event | |||
195 | u32 proto; | 205 | u32 proto; |
196 | u32 byid; | 206 | u32 byid; |
197 | u32 aevent; | 207 | u32 aevent; |
208 | u32 type; | ||
198 | } data; | 209 | } data; |
199 | 210 | ||
200 | u32 seq; | 211 | u32 seq; |
@@ -211,6 +222,7 @@ struct xfrm_policy_afinfo { | |||
211 | struct dst_ops *dst_ops; | 222 | struct dst_ops *dst_ops; |
212 | void (*garbage_collect)(void); | 223 | void (*garbage_collect)(void); |
213 | int (*dst_lookup)(struct xfrm_dst **dst, struct flowi *fl); | 224 | int (*dst_lookup)(struct xfrm_dst **dst, struct flowi *fl); |
225 | int (*get_saddr)(xfrm_address_t *saddr, xfrm_address_t *daddr); | ||
214 | struct dst_entry *(*find_bundle)(struct flowi *fl, struct xfrm_policy *policy); | 226 | struct dst_entry *(*find_bundle)(struct flowi *fl, struct xfrm_policy *policy); |
215 | int (*bundle_create)(struct xfrm_policy *policy, | 227 | int (*bundle_create)(struct xfrm_policy *policy, |
216 | struct xfrm_state **xfrm, | 228 | struct xfrm_state **xfrm, |
@@ -234,16 +246,12 @@ extern int __xfrm_state_delete(struct xfrm_state *x); | |||
234 | 246 | ||
235 | struct xfrm_state_afinfo { | 247 | struct xfrm_state_afinfo { |
236 | unsigned short family; | 248 | unsigned short family; |
237 | struct list_head *state_bydst; | ||
238 | struct list_head *state_byspi; | ||
239 | int (*init_flags)(struct xfrm_state *x); | 249 | int (*init_flags)(struct xfrm_state *x); |
240 | void (*init_tempsel)(struct xfrm_state *x, struct flowi *fl, | 250 | void (*init_tempsel)(struct xfrm_state *x, struct flowi *fl, |
241 | struct xfrm_tmpl *tmpl, | 251 | struct xfrm_tmpl *tmpl, |
242 | xfrm_address_t *daddr, xfrm_address_t *saddr); | 252 | xfrm_address_t *daddr, xfrm_address_t *saddr); |
243 | struct xfrm_state *(*state_lookup)(xfrm_address_t *daddr, u32 spi, u8 proto); | 253 | int (*tmpl_sort)(struct xfrm_tmpl **dst, struct xfrm_tmpl **src, int n); |
244 | struct xfrm_state *(*find_acq)(u8 mode, u32 reqid, u8 proto, | 254 | int (*state_sort)(struct xfrm_state **dst, struct xfrm_state **src, int n); |
245 | xfrm_address_t *daddr, xfrm_address_t *saddr, | ||
246 | int create); | ||
247 | }; | 255 | }; |
248 | 256 | ||
249 | extern int xfrm_state_register_afinfo(struct xfrm_state_afinfo *afinfo); | 257 | extern int xfrm_state_register_afinfo(struct xfrm_state_afinfo *afinfo); |
@@ -256,11 +264,17 @@ struct xfrm_type | |||
256 | char *description; | 264 | char *description; |
257 | struct module *owner; | 265 | struct module *owner; |
258 | __u8 proto; | 266 | __u8 proto; |
267 | __u8 flags; | ||
268 | #define XFRM_TYPE_NON_FRAGMENT 1 | ||
259 | 269 | ||
260 | int (*init_state)(struct xfrm_state *x); | 270 | int (*init_state)(struct xfrm_state *x); |
261 | void (*destructor)(struct xfrm_state *); | 271 | void (*destructor)(struct xfrm_state *); |
262 | int (*input)(struct xfrm_state *, struct sk_buff *skb); | 272 | int (*input)(struct xfrm_state *, struct sk_buff *skb); |
263 | int (*output)(struct xfrm_state *, struct sk_buff *pskb); | 273 | int (*output)(struct xfrm_state *, struct sk_buff *pskb); |
274 | int (*reject)(struct xfrm_state *, struct sk_buff *, struct flowi *); | ||
275 | int (*hdr_offset)(struct xfrm_state *, struct sk_buff *, u8 **); | ||
276 | xfrm_address_t *(*local_addr)(struct xfrm_state *, xfrm_address_t *); | ||
277 | xfrm_address_t *(*remote_addr)(struct xfrm_state *, xfrm_address_t *); | ||
264 | /* Estimate maximal size of result of transformation of a dgram */ | 278 | /* Estimate maximal size of result of transformation of a dgram */ |
265 | u32 (*get_max_size)(struct xfrm_state *, int size); | 279 | u32 (*get_max_size)(struct xfrm_state *, int size); |
266 | }; | 280 | }; |
@@ -272,7 +286,7 @@ extern void xfrm_put_type(struct xfrm_type *type); | |||
272 | 286 | ||
273 | struct xfrm_mode { | 287 | struct xfrm_mode { |
274 | int (*input)(struct xfrm_state *x, struct sk_buff *skb); | 288 | int (*input)(struct xfrm_state *x, struct sk_buff *skb); |
275 | int (*output)(struct sk_buff *skb); | 289 | int (*output)(struct xfrm_state *x,struct sk_buff *skb); |
276 | 290 | ||
277 | struct module *owner; | 291 | struct module *owner; |
278 | unsigned int encap; | 292 | unsigned int encap; |
@@ -298,7 +312,7 @@ struct xfrm_tmpl | |||
298 | 312 | ||
299 | __u32 reqid; | 313 | __u32 reqid; |
300 | 314 | ||
301 | /* Mode: transport/tunnel */ | 315 | /* Mode: transport, tunnel etc. */ |
302 | __u8 mode; | 316 | __u8 mode; |
303 | 317 | ||
304 | /* Sharing mode: unique, this session only, this user only etc. */ | 318 | /* Sharing mode: unique, this session only, this user only etc. */ |
@@ -313,18 +327,20 @@ struct xfrm_tmpl | |||
313 | __u32 calgos; | 327 | __u32 calgos; |
314 | }; | 328 | }; |
315 | 329 | ||
316 | #define XFRM_MAX_DEPTH 4 | 330 | #define XFRM_MAX_DEPTH 6 |
317 | 331 | ||
318 | struct xfrm_policy | 332 | struct xfrm_policy |
319 | { | 333 | { |
320 | struct xfrm_policy *next; | 334 | struct xfrm_policy *next; |
321 | struct list_head list; | 335 | struct hlist_node bydst; |
336 | struct hlist_node byidx; | ||
322 | 337 | ||
323 | /* This lock only affects elements except for entry. */ | 338 | /* This lock only affects elements except for entry. */ |
324 | rwlock_t lock; | 339 | rwlock_t lock; |
325 | atomic_t refcnt; | 340 | atomic_t refcnt; |
326 | struct timer_list timer; | 341 | struct timer_list timer; |
327 | 342 | ||
343 | u8 type; | ||
328 | u32 priority; | 344 | u32 priority; |
329 | u32 index; | 345 | u32 index; |
330 | struct xfrm_selector selector; | 346 | struct xfrm_selector selector; |
@@ -362,16 +378,16 @@ struct xfrm_mgr | |||
362 | char *id; | 378 | char *id; |
363 | int (*notify)(struct xfrm_state *x, struct km_event *c); | 379 | int (*notify)(struct xfrm_state *x, struct km_event *c); |
364 | int (*acquire)(struct xfrm_state *x, struct xfrm_tmpl *, struct xfrm_policy *xp, int dir); | 380 | int (*acquire)(struct xfrm_state *x, struct xfrm_tmpl *, struct xfrm_policy *xp, int dir); |
365 | struct xfrm_policy *(*compile_policy)(u16 family, int opt, u8 *data, int len, int *dir); | 381 | struct xfrm_policy *(*compile_policy)(struct sock *sk, int opt, u8 *data, int len, int *dir); |
366 | int (*new_mapping)(struct xfrm_state *x, xfrm_address_t *ipaddr, u16 sport); | 382 | int (*new_mapping)(struct xfrm_state *x, xfrm_address_t *ipaddr, u16 sport); |
367 | int (*notify_policy)(struct xfrm_policy *x, int dir, struct km_event *c); | 383 | int (*notify_policy)(struct xfrm_policy *x, int dir, struct km_event *c); |
384 | int (*report)(u8 proto, struct xfrm_selector *sel, xfrm_address_t *addr); | ||
368 | }; | 385 | }; |
369 | 386 | ||
370 | extern int xfrm_register_km(struct xfrm_mgr *km); | 387 | extern int xfrm_register_km(struct xfrm_mgr *km); |
371 | extern int xfrm_unregister_km(struct xfrm_mgr *km); | 388 | extern int xfrm_unregister_km(struct xfrm_mgr *km); |
372 | 389 | ||
373 | 390 | extern unsigned int xfrm_policy_count[XFRM_POLICY_MAX*2]; | |
374 | extern struct xfrm_policy *xfrm_policy_list[XFRM_POLICY_MAX*2]; | ||
375 | 391 | ||
376 | static inline void xfrm_pol_hold(struct xfrm_policy *policy) | 392 | static inline void xfrm_pol_hold(struct xfrm_policy *policy) |
377 | { | 393 | { |
@@ -387,67 +403,19 @@ static inline void xfrm_pol_put(struct xfrm_policy *policy) | |||
387 | __xfrm_policy_destroy(policy); | 403 | __xfrm_policy_destroy(policy); |
388 | } | 404 | } |
389 | 405 | ||
390 | #define XFRM_DST_HSIZE 1024 | 406 | #ifdef CONFIG_XFRM_SUB_POLICY |
391 | 407 | static inline void xfrm_pols_put(struct xfrm_policy **pols, int npols) | |
392 | static __inline__ | ||
393 | unsigned __xfrm4_dst_hash(xfrm_address_t *addr) | ||
394 | { | ||
395 | unsigned h; | ||
396 | h = ntohl(addr->a4); | ||
397 | h = (h ^ (h>>16)) % XFRM_DST_HSIZE; | ||
398 | return h; | ||
399 | } | ||
400 | |||
401 | static __inline__ | ||
402 | unsigned __xfrm6_dst_hash(xfrm_address_t *addr) | ||
403 | { | ||
404 | unsigned h; | ||
405 | h = ntohl(addr->a6[2]^addr->a6[3]); | ||
406 | h = (h ^ (h>>16)) % XFRM_DST_HSIZE; | ||
407 | return h; | ||
408 | } | ||
409 | |||
410 | static __inline__ | ||
411 | unsigned xfrm_dst_hash(xfrm_address_t *addr, unsigned short family) | ||
412 | { | ||
413 | switch (family) { | ||
414 | case AF_INET: | ||
415 | return __xfrm4_dst_hash(addr); | ||
416 | case AF_INET6: | ||
417 | return __xfrm6_dst_hash(addr); | ||
418 | } | ||
419 | return 0; | ||
420 | } | ||
421 | |||
422 | static __inline__ | ||
423 | unsigned __xfrm4_spi_hash(xfrm_address_t *addr, u32 spi, u8 proto) | ||
424 | { | 408 | { |
425 | unsigned h; | 409 | int i; |
426 | h = ntohl(addr->a4^spi^proto); | 410 | for (i = npols - 1; i >= 0; --i) |
427 | h = (h ^ (h>>10) ^ (h>>20)) % XFRM_DST_HSIZE; | 411 | xfrm_pol_put(pols[i]); |
428 | return h; | ||
429 | } | 412 | } |
430 | 413 | #else | |
431 | static __inline__ | 414 | static inline void xfrm_pols_put(struct xfrm_policy **pols, int npols) |
432 | unsigned __xfrm6_spi_hash(xfrm_address_t *addr, u32 spi, u8 proto) | ||
433 | { | ||
434 | unsigned h; | ||
435 | h = ntohl(addr->a6[2]^addr->a6[3]^spi^proto); | ||
436 | h = (h ^ (h>>10) ^ (h>>20)) % XFRM_DST_HSIZE; | ||
437 | return h; | ||
438 | } | ||
439 | |||
440 | static __inline__ | ||
441 | unsigned xfrm_spi_hash(xfrm_address_t *addr, u32 spi, u8 proto, unsigned short family) | ||
442 | { | 415 | { |
443 | switch (family) { | 416 | xfrm_pol_put(pols[0]); |
444 | case AF_INET: | ||
445 | return __xfrm4_spi_hash(addr, spi, proto); | ||
446 | case AF_INET6: | ||
447 | return __xfrm6_spi_hash(addr, spi, proto); | ||
448 | } | ||
449 | return 0; /*XXX*/ | ||
450 | } | 417 | } |
418 | #endif | ||
451 | 419 | ||
452 | extern void __xfrm_state_destroy(struct xfrm_state *); | 420 | extern void __xfrm_state_destroy(struct xfrm_state *); |
453 | 421 | ||
@@ -507,6 +475,11 @@ u16 xfrm_flowi_sport(struct flowi *fl) | |||
507 | case IPPROTO_ICMPV6: | 475 | case IPPROTO_ICMPV6: |
508 | port = htons(fl->fl_icmp_type); | 476 | port = htons(fl->fl_icmp_type); |
509 | break; | 477 | break; |
478 | #ifdef CONFIG_IPV6_MIP6 | ||
479 | case IPPROTO_MH: | ||
480 | port = htons(fl->fl_mh_type); | ||
481 | break; | ||
482 | #endif | ||
510 | default: | 483 | default: |
511 | port = 0; /*XXX*/ | 484 | port = 0; /*XXX*/ |
512 | } | 485 | } |
@@ -607,6 +580,7 @@ struct xfrm_dst | |||
607 | struct rt6_info rt6; | 580 | struct rt6_info rt6; |
608 | } u; | 581 | } u; |
609 | struct dst_entry *route; | 582 | struct dst_entry *route; |
583 | u32 genid; | ||
610 | u32 route_mtu_cached; | 584 | u32 route_mtu_cached; |
611 | u32 child_mtu_cached; | 585 | u32 child_mtu_cached; |
612 | u32 route_cookie; | 586 | u32 route_cookie; |
@@ -658,6 +632,18 @@ secpath_reset(struct sk_buff *skb) | |||
658 | } | 632 | } |
659 | 633 | ||
660 | static inline int | 634 | static inline int |
635 | xfrm_addr_any(xfrm_address_t *addr, unsigned short family) | ||
636 | { | ||
637 | switch (family) { | ||
638 | case AF_INET: | ||
639 | return addr->a4 == 0; | ||
640 | case AF_INET6: | ||
641 | return ipv6_addr_any((struct in6_addr *)&addr->a6); | ||
642 | } | ||
643 | return 0; | ||
644 | } | ||
645 | |||
646 | static inline int | ||
661 | __xfrm4_state_addr_cmp(struct xfrm_tmpl *tmpl, struct xfrm_state *x) | 647 | __xfrm4_state_addr_cmp(struct xfrm_tmpl *tmpl, struct xfrm_state *x) |
662 | { | 648 | { |
663 | return (tmpl->saddr.a4 && | 649 | return (tmpl->saddr.a4 && |
@@ -691,8 +677,8 @@ static inline int xfrm_policy_check(struct sock *sk, int dir, struct sk_buff *sk | |||
691 | { | 677 | { |
692 | if (sk && sk->sk_policy[XFRM_POLICY_IN]) | 678 | if (sk && sk->sk_policy[XFRM_POLICY_IN]) |
693 | return __xfrm_policy_check(sk, dir, skb, family); | 679 | return __xfrm_policy_check(sk, dir, skb, family); |
694 | 680 | ||
695 | return (!xfrm_policy_list[dir] && !skb->sp) || | 681 | return (!xfrm_policy_count[dir] && !skb->sp) || |
696 | (skb->dst->flags & DST_NOPOLICY) || | 682 | (skb->dst->flags & DST_NOPOLICY) || |
697 | __xfrm_policy_check(sk, dir, skb, family); | 683 | __xfrm_policy_check(sk, dir, skb, family); |
698 | } | 684 | } |
@@ -712,7 +698,7 @@ extern int __xfrm_route_forward(struct sk_buff *skb, unsigned short family); | |||
712 | 698 | ||
713 | static inline int xfrm_route_forward(struct sk_buff *skb, unsigned short family) | 699 | static inline int xfrm_route_forward(struct sk_buff *skb, unsigned short family) |
714 | { | 700 | { |
715 | return !xfrm_policy_list[XFRM_POLICY_OUT] || | 701 | return !xfrm_policy_count[XFRM_POLICY_OUT] || |
716 | (skb->dst->flags & DST_NOXFRM) || | 702 | (skb->dst->flags & DST_NOXFRM) || |
717 | __xfrm_route_forward(skb, family); | 703 | __xfrm_route_forward(skb, family); |
718 | } | 704 | } |
@@ -830,11 +816,36 @@ xfrm_state_addr_check(struct xfrm_state *x, | |||
830 | return 0; | 816 | return 0; |
831 | } | 817 | } |
832 | 818 | ||
819 | static __inline__ int | ||
820 | xfrm_state_addr_flow_check(struct xfrm_state *x, struct flowi *fl, | ||
821 | unsigned short family) | ||
822 | { | ||
823 | switch (family) { | ||
824 | case AF_INET: | ||
825 | return __xfrm4_state_addr_check(x, | ||
826 | (xfrm_address_t *)&fl->fl4_dst, | ||
827 | (xfrm_address_t *)&fl->fl4_src); | ||
828 | case AF_INET6: | ||
829 | return __xfrm6_state_addr_check(x, | ||
830 | (xfrm_address_t *)&fl->fl6_dst, | ||
831 | (xfrm_address_t *)&fl->fl6_src); | ||
832 | } | ||
833 | return 0; | ||
834 | } | ||
835 | |||
833 | static inline int xfrm_state_kern(struct xfrm_state *x) | 836 | static inline int xfrm_state_kern(struct xfrm_state *x) |
834 | { | 837 | { |
835 | return atomic_read(&x->tunnel_users); | 838 | return atomic_read(&x->tunnel_users); |
836 | } | 839 | } |
837 | 840 | ||
841 | static inline int xfrm_id_proto_match(u8 proto, u8 userproto) | ||
842 | { | ||
843 | return (!userproto || proto == userproto || | ||
844 | (userproto == IPSEC_PROTO_ANY && (proto == IPPROTO_AH || | ||
845 | proto == IPPROTO_ESP || | ||
846 | proto == IPPROTO_COMP))); | ||
847 | } | ||
848 | |||
838 | /* | 849 | /* |
839 | * xfrm algorithm information | 850 | * xfrm algorithm information |
840 | */ | 851 | */ |
@@ -902,6 +913,25 @@ extern void xfrm_state_insert(struct xfrm_state *x); | |||
902 | extern int xfrm_state_add(struct xfrm_state *x); | 913 | extern int xfrm_state_add(struct xfrm_state *x); |
903 | extern int xfrm_state_update(struct xfrm_state *x); | 914 | extern int xfrm_state_update(struct xfrm_state *x); |
904 | extern struct xfrm_state *xfrm_state_lookup(xfrm_address_t *daddr, u32 spi, u8 proto, unsigned short family); | 915 | extern struct xfrm_state *xfrm_state_lookup(xfrm_address_t *daddr, u32 spi, u8 proto, unsigned short family); |
916 | extern struct xfrm_state *xfrm_state_lookup_byaddr(xfrm_address_t *daddr, xfrm_address_t *saddr, u8 proto, unsigned short family); | ||
917 | #ifdef CONFIG_XFRM_SUB_POLICY | ||
918 | extern int xfrm_tmpl_sort(struct xfrm_tmpl **dst, struct xfrm_tmpl **src, | ||
919 | int n, unsigned short family); | ||
920 | extern int xfrm_state_sort(struct xfrm_state **dst, struct xfrm_state **src, | ||
921 | int n, unsigned short family); | ||
922 | #else | ||
923 | static inline int xfrm_tmpl_sort(struct xfrm_tmpl **dst, struct xfrm_tmpl **src, | ||
924 | int n, unsigned short family) | ||
925 | { | ||
926 | return -ENOSYS; | ||
927 | } | ||
928 | |||
929 | static inline int xfrm_state_sort(struct xfrm_state **dst, struct xfrm_state **src, | ||
930 | int n, unsigned short family) | ||
931 | { | ||
932 | return -ENOSYS; | ||
933 | } | ||
934 | #endif | ||
905 | extern struct xfrm_state *xfrm_find_acq_byseq(u32 seq); | 935 | extern struct xfrm_state *xfrm_find_acq_byseq(u32 seq); |
906 | extern int xfrm_state_delete(struct xfrm_state *x); | 936 | extern int xfrm_state_delete(struct xfrm_state *x); |
907 | extern void xfrm_state_flush(u8 proto); | 937 | extern void xfrm_state_flush(u8 proto); |
@@ -917,12 +947,16 @@ extern int xfrm4_tunnel_register(struct xfrm_tunnel *handler); | |||
917 | extern int xfrm4_tunnel_deregister(struct xfrm_tunnel *handler); | 947 | extern int xfrm4_tunnel_deregister(struct xfrm_tunnel *handler); |
918 | extern int xfrm6_rcv_spi(struct sk_buff *skb, u32 spi); | 948 | extern int xfrm6_rcv_spi(struct sk_buff *skb, u32 spi); |
919 | extern int xfrm6_rcv(struct sk_buff **pskb); | 949 | extern int xfrm6_rcv(struct sk_buff **pskb); |
950 | extern int xfrm6_input_addr(struct sk_buff *skb, xfrm_address_t *daddr, | ||
951 | xfrm_address_t *saddr, u8 proto); | ||
920 | extern int xfrm6_tunnel_register(struct xfrm6_tunnel *handler); | 952 | extern int xfrm6_tunnel_register(struct xfrm6_tunnel *handler); |
921 | extern int xfrm6_tunnel_deregister(struct xfrm6_tunnel *handler); | 953 | extern int xfrm6_tunnel_deregister(struct xfrm6_tunnel *handler); |
922 | extern u32 xfrm6_tunnel_alloc_spi(xfrm_address_t *saddr); | 954 | extern u32 xfrm6_tunnel_alloc_spi(xfrm_address_t *saddr); |
923 | extern void xfrm6_tunnel_free_spi(xfrm_address_t *saddr); | 955 | extern void xfrm6_tunnel_free_spi(xfrm_address_t *saddr); |
924 | extern u32 xfrm6_tunnel_spi_lookup(xfrm_address_t *saddr); | 956 | extern u32 xfrm6_tunnel_spi_lookup(xfrm_address_t *saddr); |
925 | extern int xfrm6_output(struct sk_buff *skb); | 957 | extern int xfrm6_output(struct sk_buff *skb); |
958 | extern int xfrm6_find_1stfragopt(struct xfrm_state *x, struct sk_buff *skb, | ||
959 | u8 **prevhdr); | ||
926 | 960 | ||
927 | #ifdef CONFIG_XFRM | 961 | #ifdef CONFIG_XFRM |
928 | extern int xfrm4_rcv_encap(struct sk_buff *skb, __u16 encap_type); | 962 | extern int xfrm4_rcv_encap(struct sk_buff *skb, __u16 encap_type); |
@@ -947,27 +981,27 @@ static inline int xfrm_dst_lookup(struct xfrm_dst **dst, struct flowi *fl, unsig | |||
947 | #endif | 981 | #endif |
948 | 982 | ||
949 | struct xfrm_policy *xfrm_policy_alloc(gfp_t gfp); | 983 | struct xfrm_policy *xfrm_policy_alloc(gfp_t gfp); |
950 | extern int xfrm_policy_walk(int (*func)(struct xfrm_policy *, int, int, void*), void *); | 984 | extern int xfrm_policy_walk(u8 type, int (*func)(struct xfrm_policy *, int, int, void*), void *); |
951 | int xfrm_policy_insert(int dir, struct xfrm_policy *policy, int excl); | 985 | int xfrm_policy_insert(int dir, struct xfrm_policy *policy, int excl); |
952 | struct xfrm_policy *xfrm_policy_bysel_ctx(int dir, struct xfrm_selector *sel, | 986 | struct xfrm_policy *xfrm_policy_bysel_ctx(u8 type, int dir, |
987 | struct xfrm_selector *sel, | ||
953 | struct xfrm_sec_ctx *ctx, int delete); | 988 | struct xfrm_sec_ctx *ctx, int delete); |
954 | struct xfrm_policy *xfrm_policy_byid(int dir, u32 id, int delete); | 989 | struct xfrm_policy *xfrm_policy_byid(u8, int dir, u32 id, int delete); |
955 | void xfrm_policy_flush(void); | 990 | void xfrm_policy_flush(u8 type); |
956 | u32 xfrm_get_acqseq(void); | 991 | u32 xfrm_get_acqseq(void); |
957 | void xfrm_alloc_spi(struct xfrm_state *x, u32 minspi, u32 maxspi); | 992 | void xfrm_alloc_spi(struct xfrm_state *x, u32 minspi, u32 maxspi); |
958 | struct xfrm_state * xfrm_find_acq(u8 mode, u32 reqid, u8 proto, | 993 | struct xfrm_state * xfrm_find_acq(u8 mode, u32 reqid, u8 proto, |
959 | xfrm_address_t *daddr, xfrm_address_t *saddr, | 994 | xfrm_address_t *daddr, xfrm_address_t *saddr, |
960 | int create, unsigned short family); | 995 | int create, unsigned short family); |
961 | extern void xfrm_policy_flush(void); | 996 | extern void xfrm_policy_flush(u8 type); |
962 | extern int xfrm_sk_policy_insert(struct sock *sk, int dir, struct xfrm_policy *pol); | 997 | extern int xfrm_sk_policy_insert(struct sock *sk, int dir, struct xfrm_policy *pol); |
963 | extern int xfrm_flush_bundles(void); | 998 | extern int xfrm_bundle_ok(struct xfrm_dst *xdst, struct flowi *fl, int family, int strict); |
964 | extern void xfrm_flush_all_bundles(void); | ||
965 | extern int xfrm_bundle_ok(struct xfrm_dst *xdst, struct flowi *fl, int family); | ||
966 | extern void xfrm_init_pmtu(struct dst_entry *dst); | 999 | extern void xfrm_init_pmtu(struct dst_entry *dst); |
967 | 1000 | ||
968 | extern wait_queue_head_t km_waitq; | 1001 | extern wait_queue_head_t km_waitq; |
969 | extern int km_new_mapping(struct xfrm_state *x, xfrm_address_t *ipaddr, u16 sport); | 1002 | extern int km_new_mapping(struct xfrm_state *x, xfrm_address_t *ipaddr, u16 sport); |
970 | extern void km_policy_expired(struct xfrm_policy *pol, int dir, int hard, u32 pid); | 1003 | extern void km_policy_expired(struct xfrm_policy *pol, int dir, int hard, u32 pid); |
1004 | extern int km_report(u8 proto, struct xfrm_selector *sel, xfrm_address_t *addr); | ||
971 | 1005 | ||
972 | extern void xfrm_input_init(void); | 1006 | extern void xfrm_input_init(void); |
973 | extern int xfrm_parse_spi(struct sk_buff *skb, u8 nexthdr, u32 *spi, u32 *seq); | 1007 | extern int xfrm_parse_spi(struct sk_buff *skb, u8 nexthdr, u32 *spi, u32 *seq); |
diff --git a/include/sound/ac97_codec.h b/include/sound/ac97_codec.h index 758f8bf133c7..4c43521cc493 100644 --- a/include/sound/ac97_codec.h +++ b/include/sound/ac97_codec.h | |||
@@ -27,6 +27,7 @@ | |||
27 | 27 | ||
28 | #include <linux/bitops.h> | 28 | #include <linux/bitops.h> |
29 | #include <linux/device.h> | 29 | #include <linux/device.h> |
30 | #include <linux/workqueue.h> | ||
30 | #include "pcm.h" | 31 | #include "pcm.h" |
31 | #include "control.h" | 32 | #include "control.h" |
32 | #include "info.h" | 33 | #include "info.h" |
@@ -140,6 +141,20 @@ | |||
140 | #define AC97_GP_DRSS_1011 0x0000 /* LR(C) 10+11(+12) */ | 141 | #define AC97_GP_DRSS_1011 0x0000 /* LR(C) 10+11(+12) */ |
141 | #define AC97_GP_DRSS_78 0x0400 /* LR 7+8 */ | 142 | #define AC97_GP_DRSS_78 0x0400 /* LR 7+8 */ |
142 | 143 | ||
144 | /* powerdown bits */ | ||
145 | #define AC97_PD_ADC_STATUS 0x0001 /* ADC status (RO) */ | ||
146 | #define AC97_PD_DAC_STATUS 0x0002 /* DAC status (RO) */ | ||
147 | #define AC97_PD_MIXER_STATUS 0x0004 /* Analog mixer status (RO) */ | ||
148 | #define AC97_PD_VREF_STATUS 0x0008 /* Vref status (RO) */ | ||
149 | #define AC97_PD_PR0 0x0100 /* Power down PCM ADCs and input MUX */ | ||
150 | #define AC97_PD_PR1 0x0200 /* Power down PCM front DAC */ | ||
151 | #define AC97_PD_PR2 0x0400 /* Power down Mixer (Vref still on) */ | ||
152 | #define AC97_PD_PR3 0x0800 /* Power down Mixer (Vref off) */ | ||
153 | #define AC97_PD_PR4 0x1000 /* Power down AC-Link */ | ||
154 | #define AC97_PD_PR5 0x2000 /* Disable internal clock usage */ | ||
155 | #define AC97_PD_PR6 0x4000 /* Headphone amplifier */ | ||
156 | #define AC97_PD_EAPD 0x8000 /* External Amplifer Power Down (EAPD) */ | ||
157 | |||
143 | /* extended audio ID bit defines */ | 158 | /* extended audio ID bit defines */ |
144 | #define AC97_EI_VRA 0x0001 /* Variable bit rate supported */ | 159 | #define AC97_EI_VRA 0x0001 /* Variable bit rate supported */ |
145 | #define AC97_EI_DRA 0x0002 /* Double rate supported */ | 160 | #define AC97_EI_DRA 0x0002 /* Double rate supported */ |
@@ -359,6 +374,7 @@ | |||
359 | #define AC97_SCAP_INV_EAPD (1<<7) /* inverted EAPD */ | 374 | #define AC97_SCAP_INV_EAPD (1<<7) /* inverted EAPD */ |
360 | #define AC97_SCAP_DETECT_BY_VENDOR (1<<8) /* use vendor registers for read tests */ | 375 | #define AC97_SCAP_DETECT_BY_VENDOR (1<<8) /* use vendor registers for read tests */ |
361 | #define AC97_SCAP_NO_SPDIF (1<<9) /* don't build SPDIF controls */ | 376 | #define AC97_SCAP_NO_SPDIF (1<<9) /* don't build SPDIF controls */ |
377 | #define AC97_SCAP_EAPD_LED (1<<10) /* EAPD as mute LED */ | ||
362 | 378 | ||
363 | /* ac97->flags */ | 379 | /* ac97->flags */ |
364 | #define AC97_HAS_PC_BEEP (1<<0) /* force PC Speaker usage */ | 380 | #define AC97_HAS_PC_BEEP (1<<0) /* force PC Speaker usage */ |
@@ -491,6 +507,12 @@ struct snd_ac97 { | |||
491 | /* jack-sharing info */ | 507 | /* jack-sharing info */ |
492 | unsigned char indep_surround; | 508 | unsigned char indep_surround; |
493 | unsigned char channel_mode; | 509 | unsigned char channel_mode; |
510 | |||
511 | #ifdef CONFIG_SND_AC97_POWER_SAVE | ||
512 | unsigned int power_up; /* power states */ | ||
513 | struct workqueue_struct *power_workq; | ||
514 | struct work_struct power_work; | ||
515 | #endif | ||
494 | struct device dev; | 516 | struct device dev; |
495 | }; | 517 | }; |
496 | 518 | ||
@@ -532,6 +554,15 @@ unsigned short snd_ac97_read(struct snd_ac97 *ac97, unsigned short reg); | |||
532 | void snd_ac97_write_cache(struct snd_ac97 *ac97, unsigned short reg, unsigned short value); | 554 | void snd_ac97_write_cache(struct snd_ac97 *ac97, unsigned short reg, unsigned short value); |
533 | int snd_ac97_update(struct snd_ac97 *ac97, unsigned short reg, unsigned short value); | 555 | int snd_ac97_update(struct snd_ac97 *ac97, unsigned short reg, unsigned short value); |
534 | int snd_ac97_update_bits(struct snd_ac97 *ac97, unsigned short reg, unsigned short mask, unsigned short value); | 556 | int snd_ac97_update_bits(struct snd_ac97 *ac97, unsigned short reg, unsigned short mask, unsigned short value); |
557 | #ifdef CONFIG_SND_AC97_POWER_SAVE | ||
558 | int snd_ac97_update_power(struct snd_ac97 *ac97, int reg, int powerup); | ||
559 | #else | ||
560 | static inline int snd_ac97_update_power(struct snd_ac97 *ac97, int reg, | ||
561 | int powerup) | ||
562 | { | ||
563 | return 0; | ||
564 | } | ||
565 | #endif | ||
535 | #ifdef CONFIG_PM | 566 | #ifdef CONFIG_PM |
536 | void snd_ac97_suspend(struct snd_ac97 *ac97); | 567 | void snd_ac97_suspend(struct snd_ac97 *ac97); |
537 | void snd_ac97_resume(struct snd_ac97 *ac97); | 568 | void snd_ac97_resume(struct snd_ac97 *ac97); |
@@ -583,6 +614,7 @@ struct ac97_pcm { | |||
583 | copy_flag: 1, /* lowlevel driver must fill all entries */ | 614 | copy_flag: 1, /* lowlevel driver must fill all entries */ |
584 | spdif: 1; /* spdif pcm */ | 615 | spdif: 1; /* spdif pcm */ |
585 | unsigned short aslots; /* active slots */ | 616 | unsigned short aslots; /* active slots */ |
617 | unsigned short cur_dbl; /* current double-rate state */ | ||
586 | unsigned int rates; /* available rates */ | 618 | unsigned int rates; /* available rates */ |
587 | struct { | 619 | struct { |
588 | unsigned short slots; /* driver input: requested AC97 slot numbers */ | 620 | unsigned short slots; /* driver input: requested AC97 slot numbers */ |
diff --git a/include/sound/ad1848.h b/include/sound/ad1848.h index 57af1fe7b309..c8de6f83338f 100644 --- a/include/sound/ad1848.h +++ b/include/sound/ad1848.h | |||
@@ -179,14 +179,13 @@ enum { AD1848_MIX_SINGLE, AD1848_MIX_DOUBLE, AD1848_MIX_CAPTURE }; | |||
179 | #define AD1848_MIXVAL_DOUBLE(left_reg, right_reg, shift_left, shift_right, mask, invert) \ | 179 | #define AD1848_MIXVAL_DOUBLE(left_reg, right_reg, shift_left, shift_right, mask, invert) \ |
180 | ((left_reg) | ((right_reg) << 8) | ((shift_left) << 16) | ((shift_right) << 19) | ((mask) << 24) | ((invert) << 22)) | 180 | ((left_reg) | ((right_reg) << 8) | ((shift_left) << 16) | ((shift_right) << 19) | ((mask) << 24) | ((invert) << 22)) |
181 | 181 | ||
182 | int snd_ad1848_add_ctl(struct snd_ad1848 *chip, const char *name, int index, int type, unsigned long value); | ||
183 | |||
184 | /* for ease of use */ | 182 | /* for ease of use */ |
185 | struct ad1848_mix_elem { | 183 | struct ad1848_mix_elem { |
186 | const char *name; | 184 | const char *name; |
187 | int index; | 185 | int index; |
188 | int type; | 186 | int type; |
189 | unsigned long private_value; | 187 | unsigned long private_value; |
188 | unsigned int *tlv; | ||
190 | }; | 189 | }; |
191 | 190 | ||
192 | #define AD1848_SINGLE(xname, xindex, reg, shift, mask, invert) \ | 191 | #define AD1848_SINGLE(xname, xindex, reg, shift, mask, invert) \ |
@@ -195,15 +194,26 @@ struct ad1848_mix_elem { | |||
195 | .type = AD1848_MIX_SINGLE, \ | 194 | .type = AD1848_MIX_SINGLE, \ |
196 | .private_value = AD1848_MIXVAL_SINGLE(reg, shift, mask, invert) } | 195 | .private_value = AD1848_MIXVAL_SINGLE(reg, shift, mask, invert) } |
197 | 196 | ||
197 | #define AD1848_SINGLE_TLV(xname, xindex, reg, shift, mask, invert, xtlv) \ | ||
198 | { .name = xname, \ | ||
199 | .index = xindex, \ | ||
200 | .type = AD1848_MIX_SINGLE, \ | ||
201 | .private_value = AD1848_MIXVAL_SINGLE(reg, shift, mask, invert), \ | ||
202 | .tlv = xtlv } | ||
203 | |||
198 | #define AD1848_DOUBLE(xname, xindex, left_reg, right_reg, shift_left, shift_right, mask, invert) \ | 204 | #define AD1848_DOUBLE(xname, xindex, left_reg, right_reg, shift_left, shift_right, mask, invert) \ |
199 | { .name = xname, \ | 205 | { .name = xname, \ |
200 | .index = xindex, \ | 206 | .index = xindex, \ |
201 | .type = AD1848_MIX_DOUBLE, \ | 207 | .type = AD1848_MIX_DOUBLE, \ |
202 | .private_value = AD1848_MIXVAL_DOUBLE(left_reg, right_reg, shift_left, shift_right, mask, invert) } | 208 | .private_value = AD1848_MIXVAL_DOUBLE(left_reg, right_reg, shift_left, shift_right, mask, invert) } |
203 | 209 | ||
204 | static inline int snd_ad1848_add_ctl_elem(struct snd_ad1848 *chip, const struct ad1848_mix_elem *c) | 210 | #define AD1848_DOUBLE_TLV(xname, xindex, left_reg, right_reg, shift_left, shift_right, mask, invert, xtlv) \ |
205 | { | 211 | { .name = xname, \ |
206 | return snd_ad1848_add_ctl(chip, c->name, c->index, c->type, c->private_value); | 212 | .index = xindex, \ |
207 | } | 213 | .type = AD1848_MIX_DOUBLE, \ |
214 | .private_value = AD1848_MIXVAL_DOUBLE(left_reg, right_reg, shift_left, shift_right, mask, invert), \ | ||
215 | .tlv = xtlv } | ||
216 | |||
217 | int snd_ad1848_add_ctl_elem(struct snd_ad1848 *chip, const struct ad1848_mix_elem *c); | ||
208 | 218 | ||
209 | #endif /* __SOUND_AD1848_H */ | 219 | #endif /* __SOUND_AD1848_H */ |
diff --git a/include/sound/ak4xxx-adda.h b/include/sound/ak4xxx-adda.h index 3d9888492026..d0deca669b92 100644 --- a/include/sound/ak4xxx-adda.h +++ b/include/sound/ak4xxx-adda.h | |||
@@ -39,26 +39,39 @@ struct snd_ak4xxx_ops { | |||
39 | 39 | ||
40 | #define AK4XXX_IMAGE_SIZE (AK4XXX_MAX_CHIPS * 16) /* 64 bytes */ | 40 | #define AK4XXX_IMAGE_SIZE (AK4XXX_MAX_CHIPS * 16) /* 64 bytes */ |
41 | 41 | ||
42 | /* DAC label and channels */ | ||
43 | struct snd_akm4xxx_dac_channel { | ||
44 | char *name; /* mixer volume name */ | ||
45 | unsigned int num_channels; | ||
46 | }; | ||
47 | |||
48 | /* ADC labels and channels */ | ||
49 | struct snd_akm4xxx_adc_channel { | ||
50 | char *name; /* capture gain volume label */ | ||
51 | char *switch_name; /* capture switch */ | ||
52 | unsigned int num_channels; | ||
53 | }; | ||
54 | |||
42 | struct snd_akm4xxx { | 55 | struct snd_akm4xxx { |
43 | struct snd_card *card; | 56 | struct snd_card *card; |
44 | unsigned int num_adcs; /* AK4524 or AK4528 ADCs */ | 57 | unsigned int num_adcs; /* AK4524 or AK4528 ADCs */ |
45 | unsigned int num_dacs; /* AK4524 or AK4528 DACs */ | 58 | unsigned int num_dacs; /* AK4524 or AK4528 DACs */ |
46 | unsigned char images[AK4XXX_IMAGE_SIZE]; /* saved register image */ | 59 | unsigned char images[AK4XXX_IMAGE_SIZE]; /* saved register image */ |
47 | unsigned char ipga_gain[AK4XXX_MAX_CHIPS][2]; /* saved register image | 60 | unsigned char volumes[AK4XXX_IMAGE_SIZE]; /* saved volume values */ |
48 | * for IPGA (AK4528) | ||
49 | */ | ||
50 | unsigned long private_value[AK4XXX_MAX_CHIPS]; /* helper for driver */ | 61 | unsigned long private_value[AK4XXX_MAX_CHIPS]; /* helper for driver */ |
51 | void *private_data[AK4XXX_MAX_CHIPS]; /* helper for driver */ | 62 | void *private_data[AK4XXX_MAX_CHIPS]; /* helper for driver */ |
52 | /* template should fill the following fields */ | 63 | /* template should fill the following fields */ |
53 | unsigned int idx_offset; /* control index offset */ | 64 | unsigned int idx_offset; /* control index offset */ |
54 | enum { | 65 | enum { |
55 | SND_AK4524, SND_AK4528, SND_AK4529, | 66 | SND_AK4524, SND_AK4528, SND_AK4529, |
56 | SND_AK4355, SND_AK4358, SND_AK4381 | 67 | SND_AK4355, SND_AK4358, SND_AK4381, |
68 | SND_AK5365 | ||
57 | } type; | 69 | } type; |
58 | unsigned int *num_stereo; /* array of combined counts | 70 | |
59 | * for the mixer | 71 | /* (array) information of combined codecs */ |
60 | */ | 72 | struct snd_akm4xxx_dac_channel *dac_info; |
61 | char **channel_names; /* array of mixer channel names */ | 73 | struct snd_akm4xxx_adc_channel *adc_info; |
74 | |||
62 | struct snd_ak4xxx_ops ops; | 75 | struct snd_ak4xxx_ops ops; |
63 | }; | 76 | }; |
64 | 77 | ||
@@ -72,9 +85,9 @@ int snd_akm4xxx_build_controls(struct snd_akm4xxx *ak); | |||
72 | (ak)->images[(chip) * 16 + (reg)] | 85 | (ak)->images[(chip) * 16 + (reg)] |
73 | #define snd_akm4xxx_set(ak,chip,reg,val) \ | 86 | #define snd_akm4xxx_set(ak,chip,reg,val) \ |
74 | ((ak)->images[(chip) * 16 + (reg)] = (val)) | 87 | ((ak)->images[(chip) * 16 + (reg)] = (val)) |
75 | #define snd_akm4xxx_get_ipga(ak,chip,reg) \ | 88 | #define snd_akm4xxx_get_vol(ak,chip,reg) \ |
76 | (ak)->ipga_gain[chip][(reg)-4] | 89 | (ak)->volumes[(chip) * 16 + (reg)] |
77 | #define snd_akm4xxx_set_ipga(ak,chip,reg,val) \ | 90 | #define snd_akm4xxx_set_vol(ak,chip,reg,val) \ |
78 | ((ak)->ipga_gain[chip][(reg)-4] = (val)) | 91 | ((ak)->volumes[(chip) * 16 + (reg)] = (val)) |
79 | 92 | ||
80 | #endif /* __SOUND_AK4XXX_ADDA_H */ | 93 | #endif /* __SOUND_AK4XXX_ADDA_H */ |
diff --git a/include/sound/asound.h b/include/sound/asound.h index 41885f48ad91..c1621c650a9a 100644 --- a/include/sound/asound.h +++ b/include/sound/asound.h | |||
@@ -688,7 +688,7 @@ struct snd_timer_tread { | |||
688 | * * | 688 | * * |
689 | ****************************************************************************/ | 689 | ****************************************************************************/ |
690 | 690 | ||
691 | #define SNDRV_CTL_VERSION SNDRV_PROTOCOL_VERSION(2, 0, 3) | 691 | #define SNDRV_CTL_VERSION SNDRV_PROTOCOL_VERSION(2, 0, 4) |
692 | 692 | ||
693 | struct snd_ctl_card_info { | 693 | struct snd_ctl_card_info { |
694 | int card; /* card number */ | 694 | int card; /* card number */ |
@@ -727,10 +727,15 @@ typedef int __bitwise snd_ctl_elem_iface_t; | |||
727 | #define SNDRV_CTL_ELEM_ACCESS_WRITE (1<<1) | 727 | #define SNDRV_CTL_ELEM_ACCESS_WRITE (1<<1) |
728 | #define SNDRV_CTL_ELEM_ACCESS_READWRITE (SNDRV_CTL_ELEM_ACCESS_READ|SNDRV_CTL_ELEM_ACCESS_WRITE) | 728 | #define SNDRV_CTL_ELEM_ACCESS_READWRITE (SNDRV_CTL_ELEM_ACCESS_READ|SNDRV_CTL_ELEM_ACCESS_WRITE) |
729 | #define SNDRV_CTL_ELEM_ACCESS_VOLATILE (1<<2) /* control value may be changed without a notification */ | 729 | #define SNDRV_CTL_ELEM_ACCESS_VOLATILE (1<<2) /* control value may be changed without a notification */ |
730 | #define SNDRV_CTL_ELEM_ACCESS_TIMESTAMP (1<<2) /* when was control changed */ | 730 | #define SNDRV_CTL_ELEM_ACCESS_TIMESTAMP (1<<3) /* when was control changed */ |
731 | #define SNDRV_CTL_ELEM_ACCESS_TLV_READ (1<<4) /* TLV read is possible */ | ||
732 | #define SNDRV_CTL_ELEM_ACCESS_TLV_WRITE (1<<5) /* TLV write is possible */ | ||
733 | #define SNDRV_CTL_ELEM_ACCESS_TLV_READWRITE (SNDRV_CTL_ELEM_ACCESS_TLV_READ|SNDRV_CTL_ELEM_ACCESS_TLV_WRITE) | ||
734 | #define SNDRV_CTL_ELEM_ACCESS_TLV_COMMAND (1<<6) /* TLV command is possible */ | ||
731 | #define SNDRV_CTL_ELEM_ACCESS_INACTIVE (1<<8) /* control does actually nothing, but may be updated */ | 735 | #define SNDRV_CTL_ELEM_ACCESS_INACTIVE (1<<8) /* control does actually nothing, but may be updated */ |
732 | #define SNDRV_CTL_ELEM_ACCESS_LOCK (1<<9) /* write lock */ | 736 | #define SNDRV_CTL_ELEM_ACCESS_LOCK (1<<9) /* write lock */ |
733 | #define SNDRV_CTL_ELEM_ACCESS_OWNER (1<<10) /* write lock owner */ | 737 | #define SNDRV_CTL_ELEM_ACCESS_OWNER (1<<10) /* write lock owner */ |
738 | #define SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK (1<<28) /* kernel use a TLV callback */ | ||
734 | #define SNDRV_CTL_ELEM_ACCESS_USER (1<<29) /* user space element */ | 739 | #define SNDRV_CTL_ELEM_ACCESS_USER (1<<29) /* user space element */ |
735 | #define SNDRV_CTL_ELEM_ACCESS_DINDIRECT (1<<30) /* indirect access for matrix dimensions in the info structure */ | 740 | #define SNDRV_CTL_ELEM_ACCESS_DINDIRECT (1<<30) /* indirect access for matrix dimensions in the info structure */ |
736 | #define SNDRV_CTL_ELEM_ACCESS_INDIRECT (1<<31) /* indirect access for element value in the value structure */ | 741 | #define SNDRV_CTL_ELEM_ACCESS_INDIRECT (1<<31) /* indirect access for element value in the value structure */ |
@@ -818,6 +823,12 @@ struct snd_ctl_elem_value { | |||
818 | unsigned char reserved[128-sizeof(struct timespec)]; | 823 | unsigned char reserved[128-sizeof(struct timespec)]; |
819 | }; | 824 | }; |
820 | 825 | ||
826 | struct snd_ctl_tlv { | ||
827 | unsigned int numid; /* control element numeric identification */ | ||
828 | unsigned int length; /* in bytes aligned to 4 */ | ||
829 | unsigned int tlv[0]; /* first TLV */ | ||
830 | }; | ||
831 | |||
821 | enum { | 832 | enum { |
822 | SNDRV_CTL_IOCTL_PVERSION = _IOR('U', 0x00, int), | 833 | SNDRV_CTL_IOCTL_PVERSION = _IOR('U', 0x00, int), |
823 | SNDRV_CTL_IOCTL_CARD_INFO = _IOR('U', 0x01, struct snd_ctl_card_info), | 834 | SNDRV_CTL_IOCTL_CARD_INFO = _IOR('U', 0x01, struct snd_ctl_card_info), |
@@ -831,6 +842,9 @@ enum { | |||
831 | SNDRV_CTL_IOCTL_ELEM_ADD = _IOWR('U', 0x17, struct snd_ctl_elem_info), | 842 | SNDRV_CTL_IOCTL_ELEM_ADD = _IOWR('U', 0x17, struct snd_ctl_elem_info), |
832 | SNDRV_CTL_IOCTL_ELEM_REPLACE = _IOWR('U', 0x18, struct snd_ctl_elem_info), | 843 | SNDRV_CTL_IOCTL_ELEM_REPLACE = _IOWR('U', 0x18, struct snd_ctl_elem_info), |
833 | SNDRV_CTL_IOCTL_ELEM_REMOVE = _IOWR('U', 0x19, struct snd_ctl_elem_id), | 844 | SNDRV_CTL_IOCTL_ELEM_REMOVE = _IOWR('U', 0x19, struct snd_ctl_elem_id), |
845 | SNDRV_CTL_IOCTL_TLV_READ = _IOWR('U', 0x1a, struct snd_ctl_tlv), | ||
846 | SNDRV_CTL_IOCTL_TLV_WRITE = _IOWR('U', 0x1b, struct snd_ctl_tlv), | ||
847 | SNDRV_CTL_IOCTL_TLV_COMMAND = _IOWR('U', 0x1c, struct snd_ctl_tlv), | ||
834 | SNDRV_CTL_IOCTL_HWDEP_NEXT_DEVICE = _IOWR('U', 0x20, int), | 848 | SNDRV_CTL_IOCTL_HWDEP_NEXT_DEVICE = _IOWR('U', 0x20, int), |
835 | SNDRV_CTL_IOCTL_HWDEP_INFO = _IOR('U', 0x21, struct snd_hwdep_info), | 849 | SNDRV_CTL_IOCTL_HWDEP_INFO = _IOR('U', 0x21, struct snd_hwdep_info), |
836 | SNDRV_CTL_IOCTL_PCM_NEXT_DEVICE = _IOR('U', 0x30, int), | 850 | SNDRV_CTL_IOCTL_PCM_NEXT_DEVICE = _IOR('U', 0x30, int), |
@@ -855,6 +869,7 @@ enum sndrv_ctl_event_type { | |||
855 | #define SNDRV_CTL_EVENT_MASK_VALUE (1<<0) /* element value was changed */ | 869 | #define SNDRV_CTL_EVENT_MASK_VALUE (1<<0) /* element value was changed */ |
856 | #define SNDRV_CTL_EVENT_MASK_INFO (1<<1) /* element info was changed */ | 870 | #define SNDRV_CTL_EVENT_MASK_INFO (1<<1) /* element info was changed */ |
857 | #define SNDRV_CTL_EVENT_MASK_ADD (1<<2) /* element was added */ | 871 | #define SNDRV_CTL_EVENT_MASK_ADD (1<<2) /* element was added */ |
872 | #define SNDRV_CTL_EVENT_MASK_TLV (1<<3) /* element TLV tree was changed */ | ||
858 | #define SNDRV_CTL_EVENT_MASK_REMOVE (~0U) /* element was removed */ | 873 | #define SNDRV_CTL_EVENT_MASK_REMOVE (~0U) /* element was removed */ |
859 | 874 | ||
860 | struct snd_ctl_event { | 875 | struct snd_ctl_event { |
diff --git a/include/sound/control.h b/include/sound/control.h index 2489b1eb0110..1de148b0fd94 100644 --- a/include/sound/control.h +++ b/include/sound/control.h | |||
@@ -30,6 +30,11 @@ struct snd_kcontrol; | |||
30 | typedef int (snd_kcontrol_info_t) (struct snd_kcontrol * kcontrol, struct snd_ctl_elem_info * uinfo); | 30 | typedef int (snd_kcontrol_info_t) (struct snd_kcontrol * kcontrol, struct snd_ctl_elem_info * uinfo); |
31 | typedef int (snd_kcontrol_get_t) (struct snd_kcontrol * kcontrol, struct snd_ctl_elem_value * ucontrol); | 31 | typedef int (snd_kcontrol_get_t) (struct snd_kcontrol * kcontrol, struct snd_ctl_elem_value * ucontrol); |
32 | typedef int (snd_kcontrol_put_t) (struct snd_kcontrol * kcontrol, struct snd_ctl_elem_value * ucontrol); | 32 | typedef int (snd_kcontrol_put_t) (struct snd_kcontrol * kcontrol, struct snd_ctl_elem_value * ucontrol); |
33 | typedef int (snd_kcontrol_tlv_rw_t)(struct snd_kcontrol *kcontrol, | ||
34 | int op_flag, /* 0=read,1=write,-1=command */ | ||
35 | unsigned int size, | ||
36 | unsigned int __user *tlv); | ||
37 | |||
33 | 38 | ||
34 | struct snd_kcontrol_new { | 39 | struct snd_kcontrol_new { |
35 | snd_ctl_elem_iface_t iface; /* interface identifier */ | 40 | snd_ctl_elem_iface_t iface; /* interface identifier */ |
@@ -42,6 +47,10 @@ struct snd_kcontrol_new { | |||
42 | snd_kcontrol_info_t *info; | 47 | snd_kcontrol_info_t *info; |
43 | snd_kcontrol_get_t *get; | 48 | snd_kcontrol_get_t *get; |
44 | snd_kcontrol_put_t *put; | 49 | snd_kcontrol_put_t *put; |
50 | union { | ||
51 | snd_kcontrol_tlv_rw_t *c; | ||
52 | unsigned int *p; | ||
53 | } tlv; | ||
45 | unsigned long private_value; | 54 | unsigned long private_value; |
46 | }; | 55 | }; |
47 | 56 | ||
@@ -58,6 +67,10 @@ struct snd_kcontrol { | |||
58 | snd_kcontrol_info_t *info; | 67 | snd_kcontrol_info_t *info; |
59 | snd_kcontrol_get_t *get; | 68 | snd_kcontrol_get_t *get; |
60 | snd_kcontrol_put_t *put; | 69 | snd_kcontrol_put_t *put; |
70 | union { | ||
71 | snd_kcontrol_tlv_rw_t *c; | ||
72 | unsigned int *p; | ||
73 | } tlv; | ||
61 | unsigned long private_value; | 74 | unsigned long private_value; |
62 | void *private_data; | 75 | void *private_data; |
63 | void (*private_free)(struct snd_kcontrol *kcontrol); | 76 | void (*private_free)(struct snd_kcontrol *kcontrol); |
diff --git a/include/sound/core.h b/include/sound/core.h index bab3ff457e40..b056ea925ecf 100644 --- a/include/sound/core.h +++ b/include/sound/core.h | |||
@@ -25,8 +25,8 @@ | |||
25 | #include <linux/sched.h> /* wake_up() */ | 25 | #include <linux/sched.h> /* wake_up() */ |
26 | #include <linux/mutex.h> /* struct mutex */ | 26 | #include <linux/mutex.h> /* struct mutex */ |
27 | #include <linux/rwsem.h> /* struct rw_semaphore */ | 27 | #include <linux/rwsem.h> /* struct rw_semaphore */ |
28 | #include <linux/workqueue.h> /* struct workqueue_struct */ | ||
29 | #include <linux/pm.h> /* pm_message_t */ | 28 | #include <linux/pm.h> /* pm_message_t */ |
29 | #include <linux/device.h> | ||
30 | 30 | ||
31 | /* forward declarations */ | 31 | /* forward declarations */ |
32 | #ifdef CONFIG_PCI | 32 | #ifdef CONFIG_PCI |
@@ -71,7 +71,6 @@ struct snd_device_ops { | |||
71 | int (*dev_free)(struct snd_device *dev); | 71 | int (*dev_free)(struct snd_device *dev); |
72 | int (*dev_register)(struct snd_device *dev); | 72 | int (*dev_register)(struct snd_device *dev); |
73 | int (*dev_disconnect)(struct snd_device *dev); | 73 | int (*dev_disconnect)(struct snd_device *dev); |
74 | int (*dev_unregister)(struct snd_device *dev); | ||
75 | }; | 74 | }; |
76 | 75 | ||
77 | struct snd_device { | 76 | struct snd_device { |
@@ -131,8 +130,8 @@ struct snd_card { | |||
131 | state */ | 130 | state */ |
132 | spinlock_t files_lock; /* lock the files for this card */ | 131 | spinlock_t files_lock; /* lock the files for this card */ |
133 | int shutdown; /* this card is going down */ | 132 | int shutdown; /* this card is going down */ |
133 | int free_on_last_close; /* free in context of file_release */ | ||
134 | wait_queue_head_t shutdown_sleep; | 134 | wait_queue_head_t shutdown_sleep; |
135 | struct work_struct free_workq; /* for free in workqueue */ | ||
136 | struct device *dev; | 135 | struct device *dev; |
137 | 136 | ||
138 | #ifdef CONFIG_PM | 137 | #ifdef CONFIG_PM |
@@ -188,6 +187,7 @@ struct snd_minor { | |||
188 | int device; /* device number */ | 187 | int device; /* device number */ |
189 | const struct file_operations *f_ops; /* file operations */ | 188 | const struct file_operations *f_ops; /* file operations */ |
190 | void *private_data; /* private data for f_ops->open */ | 189 | void *private_data; /* private data for f_ops->open */ |
190 | struct class_device *class_dev; /* class device for sysfs */ | ||
191 | }; | 191 | }; |
192 | 192 | ||
193 | /* sound.c */ | 193 | /* sound.c */ |
@@ -202,6 +202,8 @@ int snd_register_device(int type, struct snd_card *card, int dev, | |||
202 | const char *name); | 202 | const char *name); |
203 | int snd_unregister_device(int type, struct snd_card *card, int dev); | 203 | int snd_unregister_device(int type, struct snd_card *card, int dev); |
204 | void *snd_lookup_minor_data(unsigned int minor, int type); | 204 | void *snd_lookup_minor_data(unsigned int minor, int type); |
205 | int snd_add_device_sysfs_file(int type, struct snd_card *card, int dev, | ||
206 | const struct class_device_attribute *attr); | ||
205 | 207 | ||
206 | #ifdef CONFIG_SND_OSSEMUL | 208 | #ifdef CONFIG_SND_OSSEMUL |
207 | int snd_register_oss_device(int type, struct snd_card *card, int dev, | 209 | int snd_register_oss_device(int type, struct snd_card *card, int dev, |
@@ -244,7 +246,7 @@ struct snd_card *snd_card_new(int idx, const char *id, | |||
244 | struct module *module, int extra_size); | 246 | struct module *module, int extra_size); |
245 | int snd_card_disconnect(struct snd_card *card); | 247 | int snd_card_disconnect(struct snd_card *card); |
246 | int snd_card_free(struct snd_card *card); | 248 | int snd_card_free(struct snd_card *card); |
247 | int snd_card_free_in_thread(struct snd_card *card); | 249 | int snd_card_free_when_closed(struct snd_card *card); |
248 | int snd_card_register(struct snd_card *card); | 250 | int snd_card_register(struct snd_card *card); |
249 | int snd_card_info_init(void); | 251 | int snd_card_info_init(void); |
250 | int snd_card_info_done(void); | 252 | int snd_card_info_done(void); |
diff --git a/include/sound/emu10k1.h b/include/sound/emu10k1.h index 884bbf54cd36..892e310c504d 100644 --- a/include/sound/emu10k1.h +++ b/include/sound/emu10k1.h | |||
@@ -1524,6 +1524,10 @@ struct snd_emu10k1_fx8010_control_gpr { | |||
1524 | unsigned int value[32]; /* initial values */ | 1524 | unsigned int value[32]; /* initial values */ |
1525 | unsigned int min; /* minimum range */ | 1525 | unsigned int min; /* minimum range */ |
1526 | unsigned int max; /* maximum range */ | 1526 | unsigned int max; /* maximum range */ |
1527 | union { | ||
1528 | snd_kcontrol_tlv_rw_t *c; | ||
1529 | unsigned int *p; | ||
1530 | } tlv; | ||
1527 | unsigned int translation; /* translation type (EMU10K1_GPR_TRANSLATION*) */ | 1531 | unsigned int translation; /* translation type (EMU10K1_GPR_TRANSLATION*) */ |
1528 | }; | 1532 | }; |
1529 | 1533 | ||
diff --git a/include/sound/info.h b/include/sound/info.h index 74f6996769c7..97ffc4fb9969 100644 --- a/include/sound/info.h +++ b/include/sound/info.h | |||
@@ -71,7 +71,6 @@ struct snd_info_entry { | |||
71 | mode_t mode; | 71 | mode_t mode; |
72 | long size; | 72 | long size; |
73 | unsigned short content; | 73 | unsigned short content; |
74 | unsigned short disconnected: 1; | ||
75 | union { | 74 | union { |
76 | struct snd_info_entry_text text; | 75 | struct snd_info_entry_text text; |
77 | struct snd_info_entry_ops *ops; | 76 | struct snd_info_entry_ops *ops; |
@@ -83,6 +82,8 @@ struct snd_info_entry { | |||
83 | void (*private_free)(struct snd_info_entry *entry); | 82 | void (*private_free)(struct snd_info_entry *entry); |
84 | struct proc_dir_entry *p; | 83 | struct proc_dir_entry *p; |
85 | struct mutex access; | 84 | struct mutex access; |
85 | struct list_head children; | ||
86 | struct list_head list; | ||
86 | }; | 87 | }; |
87 | 88 | ||
88 | #if defined(CONFIG_SND_OSSEMUL) && defined(CONFIG_PROC_FS) | 89 | #if defined(CONFIG_SND_OSSEMUL) && defined(CONFIG_PROC_FS) |
@@ -122,8 +123,8 @@ int snd_info_restore_text(struct snd_info_entry * entry); | |||
122 | int snd_info_card_create(struct snd_card * card); | 123 | int snd_info_card_create(struct snd_card * card); |
123 | int snd_info_card_register(struct snd_card * card); | 124 | int snd_info_card_register(struct snd_card * card); |
124 | int snd_info_card_free(struct snd_card * card); | 125 | int snd_info_card_free(struct snd_card * card); |
126 | void snd_info_card_disconnect(struct snd_card * card); | ||
125 | int snd_info_register(struct snd_info_entry * entry); | 127 | int snd_info_register(struct snd_info_entry * entry); |
126 | int snd_info_unregister(struct snd_info_entry * entry); | ||
127 | 128 | ||
128 | /* for card drivers */ | 129 | /* for card drivers */ |
129 | int snd_card_proc_new(struct snd_card *card, const char *name, struct snd_info_entry **entryp); | 130 | int snd_card_proc_new(struct snd_card *card, const char *name, struct snd_info_entry **entryp); |
@@ -156,8 +157,8 @@ static inline void snd_info_free_entry(struct snd_info_entry * entry) { ; } | |||
156 | static inline int snd_info_card_create(struct snd_card * card) { return 0; } | 157 | static inline int snd_info_card_create(struct snd_card * card) { return 0; } |
157 | static inline int snd_info_card_register(struct snd_card * card) { return 0; } | 158 | static inline int snd_info_card_register(struct snd_card * card) { return 0; } |
158 | static inline int snd_info_card_free(struct snd_card * card) { return 0; } | 159 | static inline int snd_info_card_free(struct snd_card * card) { return 0; } |
160 | static inline void snd_info_card_disconnect(struct snd_card * card) { } | ||
159 | static inline int snd_info_register(struct snd_info_entry * entry) { return 0; } | 161 | static inline int snd_info_register(struct snd_info_entry * entry) { return 0; } |
160 | static inline int snd_info_unregister(struct snd_info_entry * entry) { return 0; } | ||
161 | 162 | ||
162 | static inline int snd_card_proc_new(struct snd_card *card, const char *name, | 163 | static inline int snd_card_proc_new(struct snd_card *card, const char *name, |
163 | struct snd_info_entry **entryp) { return -EINVAL; } | 164 | struct snd_info_entry **entryp) { return -EINVAL; } |
diff --git a/include/sound/pcm.h b/include/sound/pcm.h index f84d84993a31..60d40b34efc0 100644 --- a/include/sound/pcm.h +++ b/include/sound/pcm.h | |||
@@ -190,7 +190,7 @@ struct snd_pcm_ops { | |||
190 | 190 | ||
191 | struct snd_pcm_file { | 191 | struct snd_pcm_file { |
192 | struct snd_pcm_substream *substream; | 192 | struct snd_pcm_substream *substream; |
193 | struct snd_pcm_file *next; | 193 | int no_compat_mmap; |
194 | }; | 194 | }; |
195 | 195 | ||
196 | struct snd_pcm_hw_rule; | 196 | struct snd_pcm_hw_rule; |
@@ -384,7 +384,6 @@ struct snd_pcm_substream { | |||
384 | struct snd_info_entry *proc_prealloc_entry; | 384 | struct snd_info_entry *proc_prealloc_entry; |
385 | #endif | 385 | #endif |
386 | /* misc flags */ | 386 | /* misc flags */ |
387 | unsigned int no_mmap_ctrl: 1; | ||
388 | unsigned int hw_opened: 1; | 387 | unsigned int hw_opened: 1; |
389 | }; | 388 | }; |
390 | 389 | ||
@@ -402,7 +401,6 @@ struct snd_pcm_str { | |||
402 | /* -- OSS things -- */ | 401 | /* -- OSS things -- */ |
403 | struct snd_pcm_oss_stream oss; | 402 | struct snd_pcm_oss_stream oss; |
404 | #endif | 403 | #endif |
405 | struct snd_pcm_file *files; | ||
406 | #ifdef CONFIG_SND_VERBOSE_PROCFS | 404 | #ifdef CONFIG_SND_VERBOSE_PROCFS |
407 | struct snd_info_entry *proc_root; | 405 | struct snd_info_entry *proc_root; |
408 | struct snd_info_entry *proc_info_entry; | 406 | struct snd_info_entry *proc_info_entry; |
diff --git a/include/sound/timer.h b/include/sound/timer.h index 5ece2bf541dc..d42c083db1da 100644 --- a/include/sound/timer.h +++ b/include/sound/timer.h | |||
@@ -129,7 +129,6 @@ void snd_timer_notify(struct snd_timer *timer, int event, struct timespec *tstam | |||
129 | int snd_timer_global_new(char *id, int device, struct snd_timer **rtimer); | 129 | int snd_timer_global_new(char *id, int device, struct snd_timer **rtimer); |
130 | int snd_timer_global_free(struct snd_timer *timer); | 130 | int snd_timer_global_free(struct snd_timer *timer); |
131 | int snd_timer_global_register(struct snd_timer *timer); | 131 | int snd_timer_global_register(struct snd_timer *timer); |
132 | int snd_timer_global_unregister(struct snd_timer *timer); | ||
133 | 132 | ||
134 | int snd_timer_open(struct snd_timer_instance **ti, char *owner, struct snd_timer_id *tid, unsigned int slave_id); | 133 | int snd_timer_open(struct snd_timer_instance **ti, char *owner, struct snd_timer_id *tid, unsigned int slave_id); |
135 | int snd_timer_close(struct snd_timer_instance *timeri); | 134 | int snd_timer_close(struct snd_timer_instance *timeri); |
diff --git a/include/sound/tlv.h b/include/sound/tlv.h new file mode 100644 index 000000000000..d93a96b91875 --- /dev/null +++ b/include/sound/tlv.h | |||
@@ -0,0 +1,60 @@ | |||
1 | #ifndef __SOUND_TLV_H | ||
2 | #define __SOUND_TLV_H | ||
3 | |||
4 | /* | ||
5 | * Advanced Linux Sound Architecture - ALSA - Driver | ||
6 | * Copyright (c) 2006 by Jaroslav Kysela <perex@suse.cz> | ||
7 | * | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or modify | ||
10 | * it under the terms of the GNU General Public License as published by | ||
11 | * the Free Software Foundation; either version 2 of the License, or | ||
12 | * (at your option) any later version. | ||
13 | * | ||
14 | * This program is distributed in the hope that it will be useful, | ||
15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
17 | * GNU General Public License for more details. | ||
18 | * | ||
19 | * You should have received a copy of the GNU General Public License | ||
20 | * along with this program; if not, write to the Free Software | ||
21 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
22 | * | ||
23 | */ | ||
24 | |||
25 | /* | ||
26 | * TLV structure is right behind the struct snd_ctl_tlv: | ||
27 | * unsigned int type - see SNDRV_CTL_TLVT_* | ||
28 | * unsigned int length | ||
29 | * .... data aligned to sizeof(unsigned int), use | ||
30 | * block_length = (length + (sizeof(unsigned int) - 1)) & | ||
31 | * ~(sizeof(unsigned int) - 1)) .... | ||
32 | */ | ||
33 | |||
34 | #define SNDRV_CTL_TLVT_CONTAINER 0 /* one level down - group of TLVs */ | ||
35 | #define SNDRV_CTL_TLVT_DB_SCALE 1 /* dB scale */ | ||
36 | #define SNDRV_CTL_TLVT_DB_LINEAR 2 /* linear volume */ | ||
37 | #define SNDRV_CTL_TLVT_DB_RANGE 3 /* dB range container */ | ||
38 | |||
39 | #define TLV_DB_SCALE_ITEM(min, step, mute) \ | ||
40 | SNDRV_CTL_TLVT_DB_SCALE, 2 * sizeof(unsigned int), \ | ||
41 | (min), ((step) & 0xffff) | ((mute) ? 0x10000 : 0) | ||
42 | #define DECLARE_TLV_DB_SCALE(name, min, step, mute) \ | ||
43 | unsigned int name[] = { TLV_DB_SCALE_ITEM(min, step, mute) } | ||
44 | |||
45 | /* linear volume between min_dB and max_dB (.01dB unit) */ | ||
46 | #define TLV_DB_LINEAR_ITEM(min_dB, max_dB) \ | ||
47 | SNDRV_CTL_TLVT_DB_LINEAR, 2 * sizeof(unsigned int), \ | ||
48 | (min_dB), (max_dB) | ||
49 | #define DECLARE_TLV_DB_LINEAR(name, min_dB, max_dB) \ | ||
50 | unsigned int name[] = { TLV_DB_LINEAR_ITEM(min_dB, max_dB) } | ||
51 | |||
52 | /* dB range container */ | ||
53 | /* Each item is: <min> <max> <TLV> */ | ||
54 | /* The below assumes that each item TLV is 4 words like DB_SCALE or LINEAR */ | ||
55 | #define TLV_DB_RANGE_HEAD(num) \ | ||
56 | SNDRV_CTL_TLVT_DB_RANGE, 6 * (num) * sizeof(unsigned int) | ||
57 | |||
58 | #define TLV_DB_GAIN_MUTE -9999999 | ||
59 | |||
60 | #endif /* __SOUND_TLV_H */ | ||
diff --git a/include/sound/vx_core.h b/include/sound/vx_core.h index 9821a6194caa..dbca14170615 100644 --- a/include/sound/vx_core.h +++ b/include/sound/vx_core.h | |||
@@ -128,6 +128,7 @@ struct snd_vx_hardware { | |||
128 | unsigned int num_ins; | 128 | unsigned int num_ins; |
129 | unsigned int num_outs; | 129 | unsigned int num_outs; |
130 | unsigned int output_level_max; | 130 | unsigned int output_level_max; |
131 | unsigned int *output_level_db_scale; | ||
131 | }; | 132 | }; |
132 | 133 | ||
133 | /* hwdep id string */ | 134 | /* hwdep id string */ |
diff --git a/kernel/taskstats.c b/kernel/taskstats.c index e78187657330..2ed4040d0dc5 100644 --- a/kernel/taskstats.c +++ b/kernel/taskstats.c | |||
@@ -75,7 +75,7 @@ static int prepare_reply(struct genl_info *info, u8 cmd, struct sk_buff **skbp, | |||
75 | /* | 75 | /* |
76 | * If new attributes are added, please revisit this allocation | 76 | * If new attributes are added, please revisit this allocation |
77 | */ | 77 | */ |
78 | skb = nlmsg_new(size); | 78 | skb = nlmsg_new(size, GFP_KERNEL); |
79 | if (!skb) | 79 | if (!skb) |
80 | return -ENOMEM; | 80 | return -ENOMEM; |
81 | 81 | ||
diff --git a/mm/page-writeback.c b/mm/page-writeback.c index e630188ccc40..77a0bc4e261a 100644 --- a/mm/page-writeback.c +++ b/mm/page-writeback.c | |||
@@ -803,6 +803,15 @@ int test_set_page_writeback(struct page *page) | |||
803 | EXPORT_SYMBOL(test_set_page_writeback); | 803 | EXPORT_SYMBOL(test_set_page_writeback); |
804 | 804 | ||
805 | /* | 805 | /* |
806 | * Wakes up tasks that are being throttled due to writeback congestion | ||
807 | */ | ||
808 | void writeback_congestion_end(void) | ||
809 | { | ||
810 | blk_congestion_end(WRITE); | ||
811 | } | ||
812 | EXPORT_SYMBOL(writeback_congestion_end); | ||
813 | |||
814 | /* | ||
806 | * Return true if any of the pages in the mapping are marged with the | 815 | * Return true if any of the pages in the mapping are marged with the |
807 | * passed tag. | 816 | * passed tag. |
808 | */ | 817 | */ |
diff --git a/mm/page_alloc.c b/mm/page_alloc.c index 54a4f5375bba..3b5358a0561f 100644 --- a/mm/page_alloc.c +++ b/mm/page_alloc.c | |||
@@ -2363,7 +2363,7 @@ int percpu_pagelist_fraction_sysctl_handler(ctl_table *table, int write, | |||
2363 | return 0; | 2363 | return 0; |
2364 | } | 2364 | } |
2365 | 2365 | ||
2366 | __initdata int hashdist = HASHDIST_DEFAULT; | 2366 | int hashdist = HASHDIST_DEFAULT; |
2367 | 2367 | ||
2368 | #ifdef CONFIG_NUMA | 2368 | #ifdef CONFIG_NUMA |
2369 | static int __init set_hashdist(char *str) | 2369 | static int __init set_hashdist(char *str) |
diff --git a/net/Kconfig b/net/Kconfig index 4959a4e1e0fe..6528a935622c 100644 --- a/net/Kconfig +++ b/net/Kconfig | |||
@@ -249,6 +249,11 @@ source "net/ieee80211/Kconfig" | |||
249 | config WIRELESS_EXT | 249 | config WIRELESS_EXT |
250 | bool | 250 | bool |
251 | 251 | ||
252 | source "net/netlabel/Kconfig" | ||
253 | |||
254 | config FIB_RULES | ||
255 | bool | ||
256 | |||
252 | endif # if NET | 257 | endif # if NET |
253 | endmenu # Networking | 258 | endmenu # Networking |
254 | 259 | ||
diff --git a/net/Makefile b/net/Makefile index 065796f5fb17..ad4d14f4bb29 100644 --- a/net/Makefile +++ b/net/Makefile | |||
@@ -46,6 +46,7 @@ obj-$(CONFIG_IP_DCCP) += dccp/ | |||
46 | obj-$(CONFIG_IP_SCTP) += sctp/ | 46 | obj-$(CONFIG_IP_SCTP) += sctp/ |
47 | obj-$(CONFIG_IEEE80211) += ieee80211/ | 47 | obj-$(CONFIG_IEEE80211) += ieee80211/ |
48 | obj-$(CONFIG_TIPC) += tipc/ | 48 | obj-$(CONFIG_TIPC) += tipc/ |
49 | obj-$(CONFIG_NETLABEL) += netlabel/ | ||
49 | 50 | ||
50 | ifeq ($(CONFIG_NET),y) | 51 | ifeq ($(CONFIG_NET),y) |
51 | obj-$(CONFIG_SYSCTL) += sysctl_net.o | 52 | obj-$(CONFIG_SYSCTL) += sysctl_net.o |
diff --git a/net/atm/atm_sysfs.c b/net/atm/atm_sysfs.c index 5df4b9a068bb..c0a4ae28fcfa 100644 --- a/net/atm/atm_sysfs.c +++ b/net/atm/atm_sysfs.c | |||
@@ -1,6 +1,5 @@ | |||
1 | /* ATM driver model support. */ | 1 | /* ATM driver model support. */ |
2 | 2 | ||
3 | #include <linux/config.h> | ||
4 | #include <linux/kernel.h> | 3 | #include <linux/kernel.h> |
5 | #include <linux/init.h> | 4 | #include <linux/init.h> |
6 | #include <linux/kobject.h> | 5 | #include <linux/kobject.h> |
diff --git a/net/atm/mpc.c b/net/atm/mpc.c index 00704661e83f..b87c2a88bdce 100644 --- a/net/atm/mpc.c +++ b/net/atm/mpc.c | |||
@@ -98,11 +98,6 @@ static struct notifier_block mpoa_notifier = { | |||
98 | 0 | 98 | 0 |
99 | }; | 99 | }; |
100 | 100 | ||
101 | #ifdef CONFIG_PROC_FS | ||
102 | extern int mpc_proc_init(void); | ||
103 | extern void mpc_proc_clean(void); | ||
104 | #endif | ||
105 | |||
106 | struct mpoa_client *mpcs = NULL; /* FIXME */ | 101 | struct mpoa_client *mpcs = NULL; /* FIXME */ |
107 | static struct atm_mpoa_qos *qos_head = NULL; | 102 | static struct atm_mpoa_qos *qos_head = NULL; |
108 | static DEFINE_TIMER(mpc_timer, NULL, 0, 0); | 103 | static DEFINE_TIMER(mpc_timer, NULL, 0, 0); |
@@ -1439,12 +1434,8 @@ static __init int atm_mpoa_init(void) | |||
1439 | { | 1434 | { |
1440 | register_atm_ioctl(&atm_ioctl_ops); | 1435 | register_atm_ioctl(&atm_ioctl_ops); |
1441 | 1436 | ||
1442 | #ifdef CONFIG_PROC_FS | ||
1443 | if (mpc_proc_init() != 0) | 1437 | if (mpc_proc_init() != 0) |
1444 | printk(KERN_INFO "mpoa: failed to initialize /proc/mpoa\n"); | 1438 | printk(KERN_INFO "mpoa: failed to initialize /proc/mpoa\n"); |
1445 | else | ||
1446 | printk(KERN_INFO "mpoa: /proc/mpoa initialized\n"); | ||
1447 | #endif | ||
1448 | 1439 | ||
1449 | printk("mpc.c: " __DATE__ " " __TIME__ " initialized\n"); | 1440 | printk("mpc.c: " __DATE__ " " __TIME__ " initialized\n"); |
1450 | 1441 | ||
@@ -1457,9 +1448,7 @@ static void __exit atm_mpoa_cleanup(void) | |||
1457 | struct atm_mpoa_qos *qos, *nextqos; | 1448 | struct atm_mpoa_qos *qos, *nextqos; |
1458 | struct lec_priv *priv; | 1449 | struct lec_priv *priv; |
1459 | 1450 | ||
1460 | #ifdef CONFIG_PROC_FS | ||
1461 | mpc_proc_clean(); | 1451 | mpc_proc_clean(); |
1462 | #endif | ||
1463 | 1452 | ||
1464 | del_timer(&mpc_timer); | 1453 | del_timer(&mpc_timer); |
1465 | unregister_netdevice_notifier(&mpoa_notifier); | 1454 | unregister_netdevice_notifier(&mpoa_notifier); |
diff --git a/net/atm/mpc.h b/net/atm/mpc.h index 863ddf6079e1..3c7981a229e8 100644 --- a/net/atm/mpc.h +++ b/net/atm/mpc.h | |||
@@ -50,4 +50,12 @@ int atm_mpoa_delete_qos(struct atm_mpoa_qos *qos); | |||
50 | struct seq_file; | 50 | struct seq_file; |
51 | void atm_mpoa_disp_qos(struct seq_file *m); | 51 | void atm_mpoa_disp_qos(struct seq_file *m); |
52 | 52 | ||
53 | #ifdef CONFIG_PROC_FS | ||
54 | int mpc_proc_init(void); | ||
55 | void mpc_proc_clean(void); | ||
56 | #else | ||
57 | #define mpc_proc_init() (0) | ||
58 | #define mpc_proc_clean() do { } while(0) | ||
59 | #endif | ||
60 | |||
53 | #endif /* _MPC_H_ */ | 61 | #endif /* _MPC_H_ */ |
diff --git a/net/bridge/br_forward.c b/net/bridge/br_forward.c index 864fbbc7b24d..191b861e5e53 100644 --- a/net/bridge/br_forward.c +++ b/net/bridge/br_forward.c | |||
@@ -38,13 +38,10 @@ int br_dev_queue_push_xmit(struct sk_buff *skb) | |||
38 | if (packet_length(skb) > skb->dev->mtu && !skb_is_gso(skb)) | 38 | if (packet_length(skb) > skb->dev->mtu && !skb_is_gso(skb)) |
39 | kfree_skb(skb); | 39 | kfree_skb(skb); |
40 | else { | 40 | else { |
41 | #ifdef CONFIG_BRIDGE_NETFILTER | ||
42 | /* ip_refrag calls ip_fragment, doesn't copy the MAC header. */ | 41 | /* ip_refrag calls ip_fragment, doesn't copy the MAC header. */ |
43 | if (nf_bridge_maybe_copy_header(skb)) | 42 | if (nf_bridge_maybe_copy_header(skb)) |
44 | kfree_skb(skb); | 43 | kfree_skb(skb); |
45 | else | 44 | else { |
46 | #endif | ||
47 | { | ||
48 | skb_push(skb, ETH_HLEN); | 45 | skb_push(skb, ETH_HLEN); |
49 | 46 | ||
50 | dev_queue_xmit(skb); | 47 | dev_queue_xmit(skb); |
diff --git a/net/bridge/br_netfilter.c b/net/bridge/br_netfilter.c index 05b3de888243..ac181be13d83 100644 --- a/net/bridge/br_netfilter.c +++ b/net/bridge/br_netfilter.c | |||
@@ -53,10 +53,10 @@ | |||
53 | 53 | ||
54 | #ifdef CONFIG_SYSCTL | 54 | #ifdef CONFIG_SYSCTL |
55 | static struct ctl_table_header *brnf_sysctl_header; | 55 | static struct ctl_table_header *brnf_sysctl_header; |
56 | static int brnf_call_iptables = 1; | 56 | static int brnf_call_iptables __read_mostly = 1; |
57 | static int brnf_call_ip6tables = 1; | 57 | static int brnf_call_ip6tables __read_mostly = 1; |
58 | static int brnf_call_arptables = 1; | 58 | static int brnf_call_arptables __read_mostly = 1; |
59 | static int brnf_filter_vlan_tagged = 1; | 59 | static int brnf_filter_vlan_tagged __read_mostly = 1; |
60 | #else | 60 | #else |
61 | #define brnf_filter_vlan_tagged 1 | 61 | #define brnf_filter_vlan_tagged 1 |
62 | #endif | 62 | #endif |
@@ -127,14 +127,37 @@ static inline struct nf_bridge_info *nf_bridge_alloc(struct sk_buff *skb) | |||
127 | 127 | ||
128 | static inline void nf_bridge_save_header(struct sk_buff *skb) | 128 | static inline void nf_bridge_save_header(struct sk_buff *skb) |
129 | { | 129 | { |
130 | int header_size = 16; | 130 | int header_size = ETH_HLEN; |
131 | 131 | ||
132 | if (skb->protocol == htons(ETH_P_8021Q)) | 132 | if (skb->protocol == htons(ETH_P_8021Q)) |
133 | header_size = 18; | 133 | header_size += VLAN_HLEN; |
134 | 134 | ||
135 | memcpy(skb->nf_bridge->data, skb->data - header_size, header_size); | 135 | memcpy(skb->nf_bridge->data, skb->data - header_size, header_size); |
136 | } | 136 | } |
137 | 137 | ||
138 | /* | ||
139 | * When forwarding bridge frames, we save a copy of the original | ||
140 | * header before processing. | ||
141 | */ | ||
142 | int nf_bridge_copy_header(struct sk_buff *skb) | ||
143 | { | ||
144 | int err; | ||
145 | int header_size = ETH_HLEN; | ||
146 | |||
147 | if (skb->protocol == htons(ETH_P_8021Q)) | ||
148 | header_size += VLAN_HLEN; | ||
149 | |||
150 | err = skb_cow(skb, header_size); | ||
151 | if (err) | ||
152 | return err; | ||
153 | |||
154 | memcpy(skb->data - header_size, skb->nf_bridge->data, header_size); | ||
155 | |||
156 | if (skb->protocol == htons(ETH_P_8021Q)) | ||
157 | __skb_push(skb, VLAN_HLEN); | ||
158 | return 0; | ||
159 | } | ||
160 | |||
138 | /* PF_BRIDGE/PRE_ROUTING *********************************************/ | 161 | /* PF_BRIDGE/PRE_ROUTING *********************************************/ |
139 | /* Undo the changes made for ip6tables PREROUTING and continue the | 162 | /* Undo the changes made for ip6tables PREROUTING and continue the |
140 | * bridge PRE_ROUTING hook. */ | 163 | * bridge PRE_ROUTING hook. */ |
@@ -695,16 +718,6 @@ static unsigned int br_nf_local_out(unsigned int hook, struct sk_buff **pskb, | |||
695 | else | 718 | else |
696 | pf = PF_INET6; | 719 | pf = PF_INET6; |
697 | 720 | ||
698 | #ifdef CONFIG_NETFILTER_DEBUG | ||
699 | /* Sometimes we get packets with NULL ->dst here (for example, | ||
700 | * running a dhcp client daemon triggers this). This should now | ||
701 | * be fixed, but let's keep the check around. */ | ||
702 | if (skb->dst == NULL) { | ||
703 | printk(KERN_CRIT "br_netfilter: skb->dst == NULL."); | ||
704 | return NF_ACCEPT; | ||
705 | } | ||
706 | #endif | ||
707 | |||
708 | nf_bridge = skb->nf_bridge; | 721 | nf_bridge = skb->nf_bridge; |
709 | nf_bridge->physoutdev = skb->dev; | 722 | nf_bridge->physoutdev = skb->dev; |
710 | realindev = nf_bridge->physindev; | 723 | realindev = nf_bridge->physindev; |
@@ -786,7 +799,7 @@ static unsigned int br_nf_post_routing(unsigned int hook, struct sk_buff **pskb, | |||
786 | * keep the check just to be sure... */ | 799 | * keep the check just to be sure... */ |
787 | if (skb->mac.raw < skb->head || skb->mac.raw + ETH_HLEN > skb->data) { | 800 | if (skb->mac.raw < skb->head || skb->mac.raw + ETH_HLEN > skb->data) { |
788 | printk(KERN_CRIT "br_netfilter: Argh!! br_nf_post_routing: " | 801 | printk(KERN_CRIT "br_netfilter: Argh!! br_nf_post_routing: " |
789 | "bad mac.raw pointer."); | 802 | "bad mac.raw pointer.\n"); |
790 | goto print_error; | 803 | goto print_error; |
791 | } | 804 | } |
792 | #endif | 805 | #endif |
@@ -804,7 +817,7 @@ static unsigned int br_nf_post_routing(unsigned int hook, struct sk_buff **pskb, | |||
804 | 817 | ||
805 | #ifdef CONFIG_NETFILTER_DEBUG | 818 | #ifdef CONFIG_NETFILTER_DEBUG |
806 | if (skb->dst == NULL) { | 819 | if (skb->dst == NULL) { |
807 | printk(KERN_CRIT "br_netfilter: skb->dst == NULL."); | 820 | printk(KERN_INFO "br_netfilter post_routing: skb->dst == NULL\n"); |
808 | goto print_error; | 821 | goto print_error; |
809 | } | 822 | } |
810 | #endif | 823 | #endif |
@@ -841,6 +854,7 @@ print_error: | |||
841 | } | 854 | } |
842 | printk(" head:%p, raw:%p, data:%p\n", skb->head, skb->mac.raw, | 855 | printk(" head:%p, raw:%p, data:%p\n", skb->head, skb->mac.raw, |
843 | skb->data); | 856 | skb->data); |
857 | dump_stack(); | ||
844 | return NF_ACCEPT; | 858 | return NF_ACCEPT; |
845 | #endif | 859 | #endif |
846 | } | 860 | } |
diff --git a/net/bridge/br_netlink.c b/net/bridge/br_netlink.c index 53086fb75089..8f661195d09d 100644 --- a/net/bridge/br_netlink.c +++ b/net/bridge/br_netlink.c | |||
@@ -12,6 +12,7 @@ | |||
12 | 12 | ||
13 | #include <linux/kernel.h> | 13 | #include <linux/kernel.h> |
14 | #include <linux/rtnetlink.h> | 14 | #include <linux/rtnetlink.h> |
15 | #include <net/netlink.h> | ||
15 | #include "br_private.h" | 16 | #include "br_private.h" |
16 | 17 | ||
17 | /* | 18 | /* |
@@ -76,26 +77,24 @@ rtattr_failure: | |||
76 | void br_ifinfo_notify(int event, struct net_bridge_port *port) | 77 | void br_ifinfo_notify(int event, struct net_bridge_port *port) |
77 | { | 78 | { |
78 | struct sk_buff *skb; | 79 | struct sk_buff *skb; |
79 | int err = -ENOMEM; | 80 | int payload = sizeof(struct ifinfomsg) + 128; |
81 | int err = -ENOBUFS; | ||
80 | 82 | ||
81 | pr_debug("bridge notify event=%d\n", event); | 83 | pr_debug("bridge notify event=%d\n", event); |
82 | skb = alloc_skb(NLMSG_SPACE(sizeof(struct ifinfomsg) + 128), | 84 | skb = nlmsg_new(nlmsg_total_size(payload), GFP_ATOMIC); |
83 | GFP_ATOMIC); | 85 | if (skb == NULL) |
84 | if (!skb) | 86 | goto errout; |
85 | goto err_out; | 87 | |
88 | err = br_fill_ifinfo(skb, port, 0, 0, event, 0); | ||
89 | if (err < 0) { | ||
90 | kfree_skb(skb); | ||
91 | goto errout; | ||
92 | } | ||
86 | 93 | ||
87 | err = br_fill_ifinfo(skb, port, current->pid, 0, event, 0); | 94 | err = rtnl_notify(skb, 0, RTNLGRP_LINK, NULL, GFP_ATOMIC); |
95 | errout: | ||
88 | if (err < 0) | 96 | if (err < 0) |
89 | goto err_kfree; | 97 | rtnl_set_sk_err(RTNLGRP_LINK, err); |
90 | |||
91 | NETLINK_CB(skb).dst_group = RTNLGRP_LINK; | ||
92 | netlink_broadcast(rtnl, skb, 0, RTNLGRP_LINK, GFP_ATOMIC); | ||
93 | return; | ||
94 | |||
95 | err_kfree: | ||
96 | kfree_skb(skb); | ||
97 | err_out: | ||
98 | netlink_set_err(rtnl, 0, RTNLGRP_LINK, err); | ||
99 | } | 98 | } |
100 | 99 | ||
101 | /* | 100 | /* |
diff --git a/net/bridge/netfilter/ebtables.c b/net/bridge/netfilter/ebtables.c index 3a13ed643459..3df55b2bd91d 100644 --- a/net/bridge/netfilter/ebtables.c +++ b/net/bridge/netfilter/ebtables.c | |||
@@ -24,6 +24,7 @@ | |||
24 | #include <linux/vmalloc.h> | 24 | #include <linux/vmalloc.h> |
25 | #include <linux/netfilter_bridge/ebtables.h> | 25 | #include <linux/netfilter_bridge/ebtables.h> |
26 | #include <linux/spinlock.h> | 26 | #include <linux/spinlock.h> |
27 | #include <linux/mutex.h> | ||
27 | #include <asm/uaccess.h> | 28 | #include <asm/uaccess.h> |
28 | #include <linux/smp.h> | 29 | #include <linux/smp.h> |
29 | #include <linux/cpumask.h> | 30 | #include <linux/cpumask.h> |
@@ -31,36 +32,9 @@ | |||
31 | /* needed for logical [in,out]-dev filtering */ | 32 | /* needed for logical [in,out]-dev filtering */ |
32 | #include "../br_private.h" | 33 | #include "../br_private.h" |
33 | 34 | ||
34 | /* list_named_find */ | ||
35 | #define ASSERT_READ_LOCK(x) | ||
36 | #define ASSERT_WRITE_LOCK(x) | ||
37 | #include <linux/netfilter_ipv4/listhelp.h> | ||
38 | #include <linux/mutex.h> | ||
39 | |||
40 | #if 0 | ||
41 | /* use this for remote debugging | ||
42 | * Copyright (C) 1998 by Ori Pomerantz | ||
43 | * Print the string to the appropriate tty, the one | ||
44 | * the current task uses | ||
45 | */ | ||
46 | static void print_string(char *str) | ||
47 | { | ||
48 | struct tty_struct *my_tty; | ||
49 | |||
50 | /* The tty for the current task */ | ||
51 | my_tty = current->signal->tty; | ||
52 | if (my_tty != NULL) { | ||
53 | my_tty->driver->write(my_tty, 0, str, strlen(str)); | ||
54 | my_tty->driver->write(my_tty, 0, "\015\012", 2); | ||
55 | } | ||
56 | } | ||
57 | |||
58 | #define BUGPRINT(args) print_string(args); | ||
59 | #else | ||
60 | #define BUGPRINT(format, args...) printk("kernel msg: ebtables bug: please "\ | 35 | #define BUGPRINT(format, args...) printk("kernel msg: ebtables bug: please "\ |
61 | "report to author: "format, ## args) | 36 | "report to author: "format, ## args) |
62 | /* #define BUGPRINT(format, args...) */ | 37 | /* #define BUGPRINT(format, args...) */ |
63 | #endif | ||
64 | #define MEMPRINT(format, args...) printk("kernel msg: ebtables "\ | 38 | #define MEMPRINT(format, args...) printk("kernel msg: ebtables "\ |
65 | ": out of memory: "format, ## args) | 39 | ": out of memory: "format, ## args) |
66 | /* #define MEMPRINT(format, args...) */ | 40 | /* #define MEMPRINT(format, args...) */ |
@@ -299,18 +273,22 @@ static inline void * | |||
299 | find_inlist_lock_noload(struct list_head *head, const char *name, int *error, | 273 | find_inlist_lock_noload(struct list_head *head, const char *name, int *error, |
300 | struct mutex *mutex) | 274 | struct mutex *mutex) |
301 | { | 275 | { |
302 | void *ret; | 276 | struct { |
277 | struct list_head list; | ||
278 | char name[EBT_FUNCTION_MAXNAMELEN]; | ||
279 | } *e; | ||
303 | 280 | ||
304 | *error = mutex_lock_interruptible(mutex); | 281 | *error = mutex_lock_interruptible(mutex); |
305 | if (*error != 0) | 282 | if (*error != 0) |
306 | return NULL; | 283 | return NULL; |
307 | 284 | ||
308 | ret = list_named_find(head, name); | 285 | list_for_each_entry(e, head, list) { |
309 | if (!ret) { | 286 | if (strcmp(e->name, name) == 0) |
310 | *error = -ENOENT; | 287 | return e; |
311 | mutex_unlock(mutex); | ||
312 | } | 288 | } |
313 | return ret; | 289 | *error = -ENOENT; |
290 | mutex_unlock(mutex); | ||
291 | return NULL; | ||
314 | } | 292 | } |
315 | 293 | ||
316 | #ifndef CONFIG_KMOD | 294 | #ifndef CONFIG_KMOD |
@@ -1064,15 +1042,19 @@ free_newinfo: | |||
1064 | 1042 | ||
1065 | int ebt_register_target(struct ebt_target *target) | 1043 | int ebt_register_target(struct ebt_target *target) |
1066 | { | 1044 | { |
1045 | struct ebt_target *t; | ||
1067 | int ret; | 1046 | int ret; |
1068 | 1047 | ||
1069 | ret = mutex_lock_interruptible(&ebt_mutex); | 1048 | ret = mutex_lock_interruptible(&ebt_mutex); |
1070 | if (ret != 0) | 1049 | if (ret != 0) |
1071 | return ret; | 1050 | return ret; |
1072 | if (!list_named_insert(&ebt_targets, target)) { | 1051 | list_for_each_entry(t, &ebt_targets, list) { |
1073 | mutex_unlock(&ebt_mutex); | 1052 | if (strcmp(t->name, target->name) == 0) { |
1074 | return -EEXIST; | 1053 | mutex_unlock(&ebt_mutex); |
1054 | return -EEXIST; | ||
1055 | } | ||
1075 | } | 1056 | } |
1057 | list_add(&target->list, &ebt_targets); | ||
1076 | mutex_unlock(&ebt_mutex); | 1058 | mutex_unlock(&ebt_mutex); |
1077 | 1059 | ||
1078 | return 0; | 1060 | return 0; |
@@ -1081,21 +1063,25 @@ int ebt_register_target(struct ebt_target *target) | |||
1081 | void ebt_unregister_target(struct ebt_target *target) | 1063 | void ebt_unregister_target(struct ebt_target *target) |
1082 | { | 1064 | { |
1083 | mutex_lock(&ebt_mutex); | 1065 | mutex_lock(&ebt_mutex); |
1084 | LIST_DELETE(&ebt_targets, target); | 1066 | list_del(&target->list); |
1085 | mutex_unlock(&ebt_mutex); | 1067 | mutex_unlock(&ebt_mutex); |
1086 | } | 1068 | } |
1087 | 1069 | ||
1088 | int ebt_register_match(struct ebt_match *match) | 1070 | int ebt_register_match(struct ebt_match *match) |
1089 | { | 1071 | { |
1072 | struct ebt_match *m; | ||
1090 | int ret; | 1073 | int ret; |
1091 | 1074 | ||
1092 | ret = mutex_lock_interruptible(&ebt_mutex); | 1075 | ret = mutex_lock_interruptible(&ebt_mutex); |
1093 | if (ret != 0) | 1076 | if (ret != 0) |
1094 | return ret; | 1077 | return ret; |
1095 | if (!list_named_insert(&ebt_matches, match)) { | 1078 | list_for_each_entry(m, &ebt_matches, list) { |
1096 | mutex_unlock(&ebt_mutex); | 1079 | if (strcmp(m->name, match->name) == 0) { |
1097 | return -EEXIST; | 1080 | mutex_unlock(&ebt_mutex); |
1081 | return -EEXIST; | ||
1082 | } | ||
1098 | } | 1083 | } |
1084 | list_add(&match->list, &ebt_matches); | ||
1099 | mutex_unlock(&ebt_mutex); | 1085 | mutex_unlock(&ebt_mutex); |
1100 | 1086 | ||
1101 | return 0; | 1087 | return 0; |
@@ -1104,21 +1090,25 @@ int ebt_register_match(struct ebt_match *match) | |||
1104 | void ebt_unregister_match(struct ebt_match *match) | 1090 | void ebt_unregister_match(struct ebt_match *match) |
1105 | { | 1091 | { |
1106 | mutex_lock(&ebt_mutex); | 1092 | mutex_lock(&ebt_mutex); |
1107 | LIST_DELETE(&ebt_matches, match); | 1093 | list_del(&match->list); |
1108 | mutex_unlock(&ebt_mutex); | 1094 | mutex_unlock(&ebt_mutex); |
1109 | } | 1095 | } |
1110 | 1096 | ||
1111 | int ebt_register_watcher(struct ebt_watcher *watcher) | 1097 | int ebt_register_watcher(struct ebt_watcher *watcher) |
1112 | { | 1098 | { |
1099 | struct ebt_watcher *w; | ||
1113 | int ret; | 1100 | int ret; |
1114 | 1101 | ||
1115 | ret = mutex_lock_interruptible(&ebt_mutex); | 1102 | ret = mutex_lock_interruptible(&ebt_mutex); |
1116 | if (ret != 0) | 1103 | if (ret != 0) |
1117 | return ret; | 1104 | return ret; |
1118 | if (!list_named_insert(&ebt_watchers, watcher)) { | 1105 | list_for_each_entry(w, &ebt_watchers, list) { |
1119 | mutex_unlock(&ebt_mutex); | 1106 | if (strcmp(w->name, watcher->name) == 0) { |
1120 | return -EEXIST; | 1107 | mutex_unlock(&ebt_mutex); |
1108 | return -EEXIST; | ||
1109 | } | ||
1121 | } | 1110 | } |
1111 | list_add(&watcher->list, &ebt_watchers); | ||
1122 | mutex_unlock(&ebt_mutex); | 1112 | mutex_unlock(&ebt_mutex); |
1123 | 1113 | ||
1124 | return 0; | 1114 | return 0; |
@@ -1127,13 +1117,14 @@ int ebt_register_watcher(struct ebt_watcher *watcher) | |||
1127 | void ebt_unregister_watcher(struct ebt_watcher *watcher) | 1117 | void ebt_unregister_watcher(struct ebt_watcher *watcher) |
1128 | { | 1118 | { |
1129 | mutex_lock(&ebt_mutex); | 1119 | mutex_lock(&ebt_mutex); |
1130 | LIST_DELETE(&ebt_watchers, watcher); | 1120 | list_del(&watcher->list); |
1131 | mutex_unlock(&ebt_mutex); | 1121 | mutex_unlock(&ebt_mutex); |
1132 | } | 1122 | } |
1133 | 1123 | ||
1134 | int ebt_register_table(struct ebt_table *table) | 1124 | int ebt_register_table(struct ebt_table *table) |
1135 | { | 1125 | { |
1136 | struct ebt_table_info *newinfo; | 1126 | struct ebt_table_info *newinfo; |
1127 | struct ebt_table *t; | ||
1137 | int ret, i, countersize; | 1128 | int ret, i, countersize; |
1138 | 1129 | ||
1139 | if (!table || !table->table ||!table->table->entries || | 1130 | if (!table || !table->table ||!table->table->entries || |
@@ -1179,10 +1170,12 @@ int ebt_register_table(struct ebt_table *table) | |||
1179 | if (ret != 0) | 1170 | if (ret != 0) |
1180 | goto free_chainstack; | 1171 | goto free_chainstack; |
1181 | 1172 | ||
1182 | if (list_named_find(&ebt_tables, table->name)) { | 1173 | list_for_each_entry(t, &ebt_tables, list) { |
1183 | ret = -EEXIST; | 1174 | if (strcmp(t->name, table->name) == 0) { |
1184 | BUGPRINT("Table name already exists\n"); | 1175 | ret = -EEXIST; |
1185 | goto free_unlock; | 1176 | BUGPRINT("Table name already exists\n"); |
1177 | goto free_unlock; | ||
1178 | } | ||
1186 | } | 1179 | } |
1187 | 1180 | ||
1188 | /* Hold a reference count if the chains aren't empty */ | 1181 | /* Hold a reference count if the chains aren't empty */ |
@@ -1190,7 +1183,7 @@ int ebt_register_table(struct ebt_table *table) | |||
1190 | ret = -ENOENT; | 1183 | ret = -ENOENT; |
1191 | goto free_unlock; | 1184 | goto free_unlock; |
1192 | } | 1185 | } |
1193 | list_prepend(&ebt_tables, table); | 1186 | list_add(&table->list, &ebt_tables); |
1194 | mutex_unlock(&ebt_mutex); | 1187 | mutex_unlock(&ebt_mutex); |
1195 | return 0; | 1188 | return 0; |
1196 | free_unlock: | 1189 | free_unlock: |
@@ -1216,7 +1209,7 @@ void ebt_unregister_table(struct ebt_table *table) | |||
1216 | return; | 1209 | return; |
1217 | } | 1210 | } |
1218 | mutex_lock(&ebt_mutex); | 1211 | mutex_lock(&ebt_mutex); |
1219 | LIST_DELETE(&ebt_tables, table); | 1212 | list_del(&table->list); |
1220 | mutex_unlock(&ebt_mutex); | 1213 | mutex_unlock(&ebt_mutex); |
1221 | vfree(table->private->entries); | 1214 | vfree(table->private->entries); |
1222 | if (table->private->chainstack) { | 1215 | if (table->private->chainstack) { |
@@ -1486,7 +1479,7 @@ static int __init ebtables_init(void) | |||
1486 | int ret; | 1479 | int ret; |
1487 | 1480 | ||
1488 | mutex_lock(&ebt_mutex); | 1481 | mutex_lock(&ebt_mutex); |
1489 | list_named_insert(&ebt_targets, &ebt_standard_target); | 1482 | list_add(&ebt_standard_target.list, &ebt_targets); |
1490 | mutex_unlock(&ebt_mutex); | 1483 | mutex_unlock(&ebt_mutex); |
1491 | if ((ret = nf_register_sockopt(&ebt_sockopts)) < 0) | 1484 | if ((ret = nf_register_sockopt(&ebt_sockopts)) < 0) |
1492 | return ret; | 1485 | return ret; |
diff --git a/net/core/Makefile b/net/core/Makefile index 2645ba428d48..119568077dab 100644 --- a/net/core/Makefile +++ b/net/core/Makefile | |||
@@ -17,3 +17,4 @@ obj-$(CONFIG_NET_PKTGEN) += pktgen.o | |||
17 | obj-$(CONFIG_WIRELESS_EXT) += wireless.o | 17 | obj-$(CONFIG_WIRELESS_EXT) += wireless.o |
18 | obj-$(CONFIG_NETPOLL) += netpoll.o | 18 | obj-$(CONFIG_NETPOLL) += netpoll.o |
19 | obj-$(CONFIG_NET_DMA) += user_dma.o | 19 | obj-$(CONFIG_NET_DMA) += user_dma.o |
20 | obj-$(CONFIG_FIB_RULES) += fib_rules.o | ||
diff --git a/net/core/datagram.c b/net/core/datagram.c index aecddcc30401..f558c61aecc7 100644 --- a/net/core/datagram.c +++ b/net/core/datagram.c | |||
@@ -417,7 +417,7 @@ unsigned int __skb_checksum_complete(struct sk_buff *skb) | |||
417 | 417 | ||
418 | sum = (u16)csum_fold(skb_checksum(skb, 0, skb->len, skb->csum)); | 418 | sum = (u16)csum_fold(skb_checksum(skb, 0, skb->len, skb->csum)); |
419 | if (likely(!sum)) { | 419 | if (likely(!sum)) { |
420 | if (unlikely(skb->ip_summed == CHECKSUM_HW)) | 420 | if (unlikely(skb->ip_summed == CHECKSUM_COMPLETE)) |
421 | netdev_rx_csum_fault(skb->dev); | 421 | netdev_rx_csum_fault(skb->dev); |
422 | skb->ip_summed = CHECKSUM_UNNECESSARY; | 422 | skb->ip_summed = CHECKSUM_UNNECESSARY; |
423 | } | 423 | } |
@@ -462,7 +462,7 @@ int skb_copy_and_csum_datagram_iovec(struct sk_buff *skb, | |||
462 | goto fault; | 462 | goto fault; |
463 | if ((unsigned short)csum_fold(csum)) | 463 | if ((unsigned short)csum_fold(csum)) |
464 | goto csum_error; | 464 | goto csum_error; |
465 | if (unlikely(skb->ip_summed == CHECKSUM_HW)) | 465 | if (unlikely(skb->ip_summed == CHECKSUM_COMPLETE)) |
466 | netdev_rx_csum_fault(skb->dev); | 466 | netdev_rx_csum_fault(skb->dev); |
467 | iov->iov_len -= chunk; | 467 | iov->iov_len -= chunk; |
468 | iov->iov_base += chunk; | 468 | iov->iov_base += chunk; |
diff --git a/net/core/dev.c b/net/core/dev.c index d4a1ec3bded5..14de297d024d 100644 --- a/net/core/dev.c +++ b/net/core/dev.c | |||
@@ -640,6 +640,8 @@ int dev_valid_name(const char *name) | |||
640 | { | 640 | { |
641 | if (*name == '\0') | 641 | if (*name == '\0') |
642 | return 0; | 642 | return 0; |
643 | if (strlen(name) >= IFNAMSIZ) | ||
644 | return 0; | ||
643 | if (!strcmp(name, ".") || !strcmp(name, "..")) | 645 | if (!strcmp(name, ".") || !strcmp(name, "..")) |
644 | return 0; | 646 | return 0; |
645 | 647 | ||
@@ -1166,12 +1168,12 @@ EXPORT_SYMBOL(netif_device_attach); | |||
1166 | * Invalidate hardware checksum when packet is to be mangled, and | 1168 | * Invalidate hardware checksum when packet is to be mangled, and |
1167 | * complete checksum manually on outgoing path. | 1169 | * complete checksum manually on outgoing path. |
1168 | */ | 1170 | */ |
1169 | int skb_checksum_help(struct sk_buff *skb, int inward) | 1171 | int skb_checksum_help(struct sk_buff *skb) |
1170 | { | 1172 | { |
1171 | unsigned int csum; | 1173 | unsigned int csum; |
1172 | int ret = 0, offset = skb->h.raw - skb->data; | 1174 | int ret = 0, offset = skb->h.raw - skb->data; |
1173 | 1175 | ||
1174 | if (inward) | 1176 | if (skb->ip_summed == CHECKSUM_COMPLETE) |
1175 | goto out_set_summed; | 1177 | goto out_set_summed; |
1176 | 1178 | ||
1177 | if (unlikely(skb_shinfo(skb)->gso_size)) { | 1179 | if (unlikely(skb_shinfo(skb)->gso_size)) { |
@@ -1223,7 +1225,7 @@ struct sk_buff *skb_gso_segment(struct sk_buff *skb, int features) | |||
1223 | skb->mac_len = skb->nh.raw - skb->data; | 1225 | skb->mac_len = skb->nh.raw - skb->data; |
1224 | __skb_pull(skb, skb->mac_len); | 1226 | __skb_pull(skb, skb->mac_len); |
1225 | 1227 | ||
1226 | if (unlikely(skb->ip_summed != CHECKSUM_HW)) { | 1228 | if (unlikely(skb->ip_summed != CHECKSUM_PARTIAL)) { |
1227 | if (skb_header_cloned(skb) && | 1229 | if (skb_header_cloned(skb) && |
1228 | (err = pskb_expand_head(skb, 0, 0, GFP_ATOMIC))) | 1230 | (err = pskb_expand_head(skb, 0, 0, GFP_ATOMIC))) |
1229 | return ERR_PTR(err); | 1231 | return ERR_PTR(err); |
@@ -1232,7 +1234,7 @@ struct sk_buff *skb_gso_segment(struct sk_buff *skb, int features) | |||
1232 | rcu_read_lock(); | 1234 | rcu_read_lock(); |
1233 | list_for_each_entry_rcu(ptype, &ptype_base[ntohs(type) & 15], list) { | 1235 | list_for_each_entry_rcu(ptype, &ptype_base[ntohs(type) & 15], list) { |
1234 | if (ptype->type == type && !ptype->dev && ptype->gso_segment) { | 1236 | if (ptype->type == type && !ptype->dev && ptype->gso_segment) { |
1235 | if (unlikely(skb->ip_summed != CHECKSUM_HW)) { | 1237 | if (unlikely(skb->ip_summed != CHECKSUM_PARTIAL)) { |
1236 | err = ptype->gso_send_check(skb); | 1238 | err = ptype->gso_send_check(skb); |
1237 | segs = ERR_PTR(err); | 1239 | segs = ERR_PTR(err); |
1238 | if (err || skb_gso_ok(skb, features)) | 1240 | if (err || skb_gso_ok(skb, features)) |
@@ -1444,11 +1446,11 @@ int dev_queue_xmit(struct sk_buff *skb) | |||
1444 | /* If packet is not checksummed and device does not support | 1446 | /* If packet is not checksummed and device does not support |
1445 | * checksumming for this protocol, complete checksumming here. | 1447 | * checksumming for this protocol, complete checksumming here. |
1446 | */ | 1448 | */ |
1447 | if (skb->ip_summed == CHECKSUM_HW && | 1449 | if (skb->ip_summed == CHECKSUM_PARTIAL && |
1448 | (!(dev->features & NETIF_F_GEN_CSUM) && | 1450 | (!(dev->features & NETIF_F_GEN_CSUM) && |
1449 | (!(dev->features & NETIF_F_IP_CSUM) || | 1451 | (!(dev->features & NETIF_F_IP_CSUM) || |
1450 | skb->protocol != htons(ETH_P_IP)))) | 1452 | skb->protocol != htons(ETH_P_IP)))) |
1451 | if (skb_checksum_help(skb, 0)) | 1453 | if (skb_checksum_help(skb)) |
1452 | goto out_kfree_skb; | 1454 | goto out_kfree_skb; |
1453 | 1455 | ||
1454 | gso: | 1456 | gso: |
@@ -3191,13 +3193,15 @@ struct net_device *alloc_netdev(int sizeof_priv, const char *name, | |||
3191 | struct net_device *dev; | 3193 | struct net_device *dev; |
3192 | int alloc_size; | 3194 | int alloc_size; |
3193 | 3195 | ||
3196 | BUG_ON(strlen(name) >= sizeof(dev->name)); | ||
3197 | |||
3194 | /* ensure 32-byte alignment of both the device and private area */ | 3198 | /* ensure 32-byte alignment of both the device and private area */ |
3195 | alloc_size = (sizeof(*dev) + NETDEV_ALIGN_CONST) & ~NETDEV_ALIGN_CONST; | 3199 | alloc_size = (sizeof(*dev) + NETDEV_ALIGN_CONST) & ~NETDEV_ALIGN_CONST; |
3196 | alloc_size += sizeof_priv + NETDEV_ALIGN_CONST; | 3200 | alloc_size += sizeof_priv + NETDEV_ALIGN_CONST; |
3197 | 3201 | ||
3198 | p = kzalloc(alloc_size, GFP_KERNEL); | 3202 | p = kzalloc(alloc_size, GFP_KERNEL); |
3199 | if (!p) { | 3203 | if (!p) { |
3200 | printk(KERN_ERR "alloc_dev: Unable to allocate device.\n"); | 3204 | printk(KERN_ERR "alloc_netdev: Unable to allocate device.\n"); |
3201 | return NULL; | 3205 | return NULL; |
3202 | } | 3206 | } |
3203 | 3207 | ||
diff --git a/net/core/dev_mcast.c b/net/core/dev_mcast.c index c57d887da2ef..b22648d04d36 100644 --- a/net/core/dev_mcast.c +++ b/net/core/dev_mcast.c | |||
@@ -21,8 +21,7 @@ | |||
21 | * 2 of the License, or (at your option) any later version. | 21 | * 2 of the License, or (at your option) any later version. |
22 | */ | 22 | */ |
23 | 23 | ||
24 | #include <linux/config.h> | 24 | #include <linux/module.h> |
25 | #include <linux/module.h> | ||
26 | #include <asm/uaccess.h> | 25 | #include <asm/uaccess.h> |
27 | #include <asm/system.h> | 26 | #include <asm/system.h> |
28 | #include <linux/bitops.h> | 27 | #include <linux/bitops.h> |
diff --git a/net/core/fib_rules.c b/net/core/fib_rules.c new file mode 100644 index 000000000000..a99d87d82b7f --- /dev/null +++ b/net/core/fib_rules.c | |||
@@ -0,0 +1,421 @@ | |||
1 | /* | ||
2 | * net/core/fib_rules.c Generic Routing Rules | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or | ||
5 | * modify it under the terms of the GNU General Public License as | ||
6 | * published by the Free Software Foundation, version 2. | ||
7 | * | ||
8 | * Authors: Thomas Graf <tgraf@suug.ch> | ||
9 | */ | ||
10 | |||
11 | #include <linux/config.h> | ||
12 | #include <linux/types.h> | ||
13 | #include <linux/kernel.h> | ||
14 | #include <linux/list.h> | ||
15 | #include <net/fib_rules.h> | ||
16 | |||
17 | static LIST_HEAD(rules_ops); | ||
18 | static DEFINE_SPINLOCK(rules_mod_lock); | ||
19 | |||
20 | static void notify_rule_change(int event, struct fib_rule *rule, | ||
21 | struct fib_rules_ops *ops, struct nlmsghdr *nlh, | ||
22 | u32 pid); | ||
23 | |||
24 | static struct fib_rules_ops *lookup_rules_ops(int family) | ||
25 | { | ||
26 | struct fib_rules_ops *ops; | ||
27 | |||
28 | rcu_read_lock(); | ||
29 | list_for_each_entry_rcu(ops, &rules_ops, list) { | ||
30 | if (ops->family == family) { | ||
31 | if (!try_module_get(ops->owner)) | ||
32 | ops = NULL; | ||
33 | rcu_read_unlock(); | ||
34 | return ops; | ||
35 | } | ||
36 | } | ||
37 | rcu_read_unlock(); | ||
38 | |||
39 | return NULL; | ||
40 | } | ||
41 | |||
42 | static void rules_ops_put(struct fib_rules_ops *ops) | ||
43 | { | ||
44 | if (ops) | ||
45 | module_put(ops->owner); | ||
46 | } | ||
47 | |||
48 | int fib_rules_register(struct fib_rules_ops *ops) | ||
49 | { | ||
50 | int err = -EEXIST; | ||
51 | struct fib_rules_ops *o; | ||
52 | |||
53 | if (ops->rule_size < sizeof(struct fib_rule)) | ||
54 | return -EINVAL; | ||
55 | |||
56 | if (ops->match == NULL || ops->configure == NULL || | ||
57 | ops->compare == NULL || ops->fill == NULL || | ||
58 | ops->action == NULL) | ||
59 | return -EINVAL; | ||
60 | |||
61 | spin_lock(&rules_mod_lock); | ||
62 | list_for_each_entry(o, &rules_ops, list) | ||
63 | if (ops->family == o->family) | ||
64 | goto errout; | ||
65 | |||
66 | list_add_tail_rcu(&ops->list, &rules_ops); | ||
67 | err = 0; | ||
68 | errout: | ||
69 | spin_unlock(&rules_mod_lock); | ||
70 | |||
71 | return err; | ||
72 | } | ||
73 | |||
74 | EXPORT_SYMBOL_GPL(fib_rules_register); | ||
75 | |||
76 | static void cleanup_ops(struct fib_rules_ops *ops) | ||
77 | { | ||
78 | struct fib_rule *rule, *tmp; | ||
79 | |||
80 | list_for_each_entry_safe(rule, tmp, ops->rules_list, list) { | ||
81 | list_del_rcu(&rule->list); | ||
82 | fib_rule_put(rule); | ||
83 | } | ||
84 | } | ||
85 | |||
86 | int fib_rules_unregister(struct fib_rules_ops *ops) | ||
87 | { | ||
88 | int err = 0; | ||
89 | struct fib_rules_ops *o; | ||
90 | |||
91 | spin_lock(&rules_mod_lock); | ||
92 | list_for_each_entry(o, &rules_ops, list) { | ||
93 | if (o == ops) { | ||
94 | list_del_rcu(&o->list); | ||
95 | cleanup_ops(ops); | ||
96 | goto out; | ||
97 | } | ||
98 | } | ||
99 | |||
100 | err = -ENOENT; | ||
101 | out: | ||
102 | spin_unlock(&rules_mod_lock); | ||
103 | |||
104 | synchronize_rcu(); | ||
105 | |||
106 | return err; | ||
107 | } | ||
108 | |||
109 | EXPORT_SYMBOL_GPL(fib_rules_unregister); | ||
110 | |||
111 | int fib_rules_lookup(struct fib_rules_ops *ops, struct flowi *fl, | ||
112 | int flags, struct fib_lookup_arg *arg) | ||
113 | { | ||
114 | struct fib_rule *rule; | ||
115 | int err; | ||
116 | |||
117 | rcu_read_lock(); | ||
118 | |||
119 | list_for_each_entry_rcu(rule, ops->rules_list, list) { | ||
120 | if (rule->ifindex && (rule->ifindex != fl->iif)) | ||
121 | continue; | ||
122 | |||
123 | if (!ops->match(rule, fl, flags)) | ||
124 | continue; | ||
125 | |||
126 | err = ops->action(rule, fl, flags, arg); | ||
127 | if (err != -EAGAIN) { | ||
128 | fib_rule_get(rule); | ||
129 | arg->rule = rule; | ||
130 | goto out; | ||
131 | } | ||
132 | } | ||
133 | |||
134 | err = -ENETUNREACH; | ||
135 | out: | ||
136 | rcu_read_unlock(); | ||
137 | |||
138 | return err; | ||
139 | } | ||
140 | |||
141 | EXPORT_SYMBOL_GPL(fib_rules_lookup); | ||
142 | |||
143 | int fib_nl_newrule(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg) | ||
144 | { | ||
145 | struct fib_rule_hdr *frh = nlmsg_data(nlh); | ||
146 | struct fib_rules_ops *ops = NULL; | ||
147 | struct fib_rule *rule, *r, *last = NULL; | ||
148 | struct nlattr *tb[FRA_MAX+1]; | ||
149 | int err = -EINVAL; | ||
150 | |||
151 | if (nlh->nlmsg_len < nlmsg_msg_size(sizeof(*frh))) | ||
152 | goto errout; | ||
153 | |||
154 | ops = lookup_rules_ops(frh->family); | ||
155 | if (ops == NULL) { | ||
156 | err = EAFNOSUPPORT; | ||
157 | goto errout; | ||
158 | } | ||
159 | |||
160 | err = nlmsg_parse(nlh, sizeof(*frh), tb, FRA_MAX, ops->policy); | ||
161 | if (err < 0) | ||
162 | goto errout; | ||
163 | |||
164 | rule = kzalloc(ops->rule_size, GFP_KERNEL); | ||
165 | if (rule == NULL) { | ||
166 | err = -ENOMEM; | ||
167 | goto errout; | ||
168 | } | ||
169 | |||
170 | if (tb[FRA_PRIORITY]) | ||
171 | rule->pref = nla_get_u32(tb[FRA_PRIORITY]); | ||
172 | |||
173 | if (tb[FRA_IFNAME]) { | ||
174 | struct net_device *dev; | ||
175 | |||
176 | rule->ifindex = -1; | ||
177 | nla_strlcpy(rule->ifname, tb[FRA_IFNAME], IFNAMSIZ); | ||
178 | dev = __dev_get_by_name(rule->ifname); | ||
179 | if (dev) | ||
180 | rule->ifindex = dev->ifindex; | ||
181 | } | ||
182 | |||
183 | rule->action = frh->action; | ||
184 | rule->flags = frh->flags; | ||
185 | rule->table = frh_get_table(frh, tb); | ||
186 | |||
187 | if (!rule->pref && ops->default_pref) | ||
188 | rule->pref = ops->default_pref(); | ||
189 | |||
190 | err = ops->configure(rule, skb, nlh, frh, tb); | ||
191 | if (err < 0) | ||
192 | goto errout_free; | ||
193 | |||
194 | list_for_each_entry(r, ops->rules_list, list) { | ||
195 | if (r->pref > rule->pref) | ||
196 | break; | ||
197 | last = r; | ||
198 | } | ||
199 | |||
200 | fib_rule_get(rule); | ||
201 | |||
202 | if (last) | ||
203 | list_add_rcu(&rule->list, &last->list); | ||
204 | else | ||
205 | list_add_rcu(&rule->list, ops->rules_list); | ||
206 | |||
207 | notify_rule_change(RTM_NEWRULE, rule, ops, nlh, NETLINK_CB(skb).pid); | ||
208 | rules_ops_put(ops); | ||
209 | return 0; | ||
210 | |||
211 | errout_free: | ||
212 | kfree(rule); | ||
213 | errout: | ||
214 | rules_ops_put(ops); | ||
215 | return err; | ||
216 | } | ||
217 | |||
218 | int fib_nl_delrule(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg) | ||
219 | { | ||
220 | struct fib_rule_hdr *frh = nlmsg_data(nlh); | ||
221 | struct fib_rules_ops *ops = NULL; | ||
222 | struct fib_rule *rule; | ||
223 | struct nlattr *tb[FRA_MAX+1]; | ||
224 | int err = -EINVAL; | ||
225 | |||
226 | if (nlh->nlmsg_len < nlmsg_msg_size(sizeof(*frh))) | ||
227 | goto errout; | ||
228 | |||
229 | ops = lookup_rules_ops(frh->family); | ||
230 | if (ops == NULL) { | ||
231 | err = EAFNOSUPPORT; | ||
232 | goto errout; | ||
233 | } | ||
234 | |||
235 | err = nlmsg_parse(nlh, sizeof(*frh), tb, FRA_MAX, ops->policy); | ||
236 | if (err < 0) | ||
237 | goto errout; | ||
238 | |||
239 | list_for_each_entry(rule, ops->rules_list, list) { | ||
240 | if (frh->action && (frh->action != rule->action)) | ||
241 | continue; | ||
242 | |||
243 | if (frh->table && (frh_get_table(frh, tb) != rule->table)) | ||
244 | continue; | ||
245 | |||
246 | if (tb[FRA_PRIORITY] && | ||
247 | (rule->pref != nla_get_u32(tb[FRA_PRIORITY]))) | ||
248 | continue; | ||
249 | |||
250 | if (tb[FRA_IFNAME] && | ||
251 | nla_strcmp(tb[FRA_IFNAME], rule->ifname)) | ||
252 | continue; | ||
253 | |||
254 | if (!ops->compare(rule, frh, tb)) | ||
255 | continue; | ||
256 | |||
257 | if (rule->flags & FIB_RULE_PERMANENT) { | ||
258 | err = -EPERM; | ||
259 | goto errout; | ||
260 | } | ||
261 | |||
262 | list_del_rcu(&rule->list); | ||
263 | synchronize_rcu(); | ||
264 | notify_rule_change(RTM_DELRULE, rule, ops, nlh, | ||
265 | NETLINK_CB(skb).pid); | ||
266 | fib_rule_put(rule); | ||
267 | rules_ops_put(ops); | ||
268 | return 0; | ||
269 | } | ||
270 | |||
271 | err = -ENOENT; | ||
272 | errout: | ||
273 | rules_ops_put(ops); | ||
274 | return err; | ||
275 | } | ||
276 | |||
277 | static int fib_nl_fill_rule(struct sk_buff *skb, struct fib_rule *rule, | ||
278 | u32 pid, u32 seq, int type, int flags, | ||
279 | struct fib_rules_ops *ops) | ||
280 | { | ||
281 | struct nlmsghdr *nlh; | ||
282 | struct fib_rule_hdr *frh; | ||
283 | |||
284 | nlh = nlmsg_put(skb, pid, seq, type, sizeof(*frh), flags); | ||
285 | if (nlh == NULL) | ||
286 | return -1; | ||
287 | |||
288 | frh = nlmsg_data(nlh); | ||
289 | frh->table = rule->table; | ||
290 | NLA_PUT_U32(skb, FRA_TABLE, rule->table); | ||
291 | frh->res1 = 0; | ||
292 | frh->res2 = 0; | ||
293 | frh->action = rule->action; | ||
294 | frh->flags = rule->flags; | ||
295 | |||
296 | if (rule->ifname[0]) | ||
297 | NLA_PUT_STRING(skb, FRA_IFNAME, rule->ifname); | ||
298 | |||
299 | if (rule->pref) | ||
300 | NLA_PUT_U32(skb, FRA_PRIORITY, rule->pref); | ||
301 | |||
302 | if (ops->fill(rule, skb, nlh, frh) < 0) | ||
303 | goto nla_put_failure; | ||
304 | |||
305 | return nlmsg_end(skb, nlh); | ||
306 | |||
307 | nla_put_failure: | ||
308 | return nlmsg_cancel(skb, nlh); | ||
309 | } | ||
310 | |||
311 | int fib_rules_dump(struct sk_buff *skb, struct netlink_callback *cb, int family) | ||
312 | { | ||
313 | int idx = 0; | ||
314 | struct fib_rule *rule; | ||
315 | struct fib_rules_ops *ops; | ||
316 | |||
317 | ops = lookup_rules_ops(family); | ||
318 | if (ops == NULL) | ||
319 | return -EAFNOSUPPORT; | ||
320 | |||
321 | rcu_read_lock(); | ||
322 | list_for_each_entry(rule, ops->rules_list, list) { | ||
323 | if (idx < cb->args[0]) | ||
324 | goto skip; | ||
325 | |||
326 | if (fib_nl_fill_rule(skb, rule, NETLINK_CB(cb->skb).pid, | ||
327 | cb->nlh->nlmsg_seq, RTM_NEWRULE, | ||
328 | NLM_F_MULTI, ops) < 0) | ||
329 | break; | ||
330 | skip: | ||
331 | idx++; | ||
332 | } | ||
333 | rcu_read_unlock(); | ||
334 | cb->args[0] = idx; | ||
335 | rules_ops_put(ops); | ||
336 | |||
337 | return skb->len; | ||
338 | } | ||
339 | |||
340 | EXPORT_SYMBOL_GPL(fib_rules_dump); | ||
341 | |||
342 | static void notify_rule_change(int event, struct fib_rule *rule, | ||
343 | struct fib_rules_ops *ops, struct nlmsghdr *nlh, | ||
344 | u32 pid) | ||
345 | { | ||
346 | struct sk_buff *skb; | ||
347 | int err = -ENOBUFS; | ||
348 | |||
349 | skb = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); | ||
350 | if (skb == NULL) | ||
351 | goto errout; | ||
352 | |||
353 | err = fib_nl_fill_rule(skb, rule, pid, nlh->nlmsg_seq, event, 0, ops); | ||
354 | if (err < 0) { | ||
355 | kfree_skb(skb); | ||
356 | goto errout; | ||
357 | } | ||
358 | |||
359 | err = rtnl_notify(skb, pid, ops->nlgroup, nlh, GFP_KERNEL); | ||
360 | errout: | ||
361 | if (err < 0) | ||
362 | rtnl_set_sk_err(ops->nlgroup, err); | ||
363 | } | ||
364 | |||
365 | static void attach_rules(struct list_head *rules, struct net_device *dev) | ||
366 | { | ||
367 | struct fib_rule *rule; | ||
368 | |||
369 | list_for_each_entry(rule, rules, list) { | ||
370 | if (rule->ifindex == -1 && | ||
371 | strcmp(dev->name, rule->ifname) == 0) | ||
372 | rule->ifindex = dev->ifindex; | ||
373 | } | ||
374 | } | ||
375 | |||
376 | static void detach_rules(struct list_head *rules, struct net_device *dev) | ||
377 | { | ||
378 | struct fib_rule *rule; | ||
379 | |||
380 | list_for_each_entry(rule, rules, list) | ||
381 | if (rule->ifindex == dev->ifindex) | ||
382 | rule->ifindex = -1; | ||
383 | } | ||
384 | |||
385 | |||
386 | static int fib_rules_event(struct notifier_block *this, unsigned long event, | ||
387 | void *ptr) | ||
388 | { | ||
389 | struct net_device *dev = ptr; | ||
390 | struct fib_rules_ops *ops; | ||
391 | |||
392 | ASSERT_RTNL(); | ||
393 | rcu_read_lock(); | ||
394 | |||
395 | switch (event) { | ||
396 | case NETDEV_REGISTER: | ||
397 | list_for_each_entry(ops, &rules_ops, list) | ||
398 | attach_rules(ops->rules_list, dev); | ||
399 | break; | ||
400 | |||
401 | case NETDEV_UNREGISTER: | ||
402 | list_for_each_entry(ops, &rules_ops, list) | ||
403 | detach_rules(ops->rules_list, dev); | ||
404 | break; | ||
405 | } | ||
406 | |||
407 | rcu_read_unlock(); | ||
408 | |||
409 | return NOTIFY_DONE; | ||
410 | } | ||
411 | |||
412 | static struct notifier_block fib_rules_notifier = { | ||
413 | .notifier_call = fib_rules_event, | ||
414 | }; | ||
415 | |||
416 | static int __init fib_rules_init(void) | ||
417 | { | ||
418 | return register_netdevice_notifier(&fib_rules_notifier); | ||
419 | } | ||
420 | |||
421 | subsys_initcall(fib_rules_init); | ||
diff --git a/net/core/filter.c b/net/core/filter.c index 5b4486a60cf6..6732782a5a40 100644 --- a/net/core/filter.c +++ b/net/core/filter.c | |||
@@ -422,10 +422,10 @@ int sk_attach_filter(struct sock_fprog *fprog, struct sock *sk) | |||
422 | if (!err) { | 422 | if (!err) { |
423 | struct sk_filter *old_fp; | 423 | struct sk_filter *old_fp; |
424 | 424 | ||
425 | spin_lock_bh(&sk->sk_lock.slock); | 425 | rcu_read_lock_bh(); |
426 | old_fp = sk->sk_filter; | 426 | old_fp = rcu_dereference(sk->sk_filter); |
427 | sk->sk_filter = fp; | 427 | rcu_assign_pointer(sk->sk_filter, fp); |
428 | spin_unlock_bh(&sk->sk_lock.slock); | 428 | rcu_read_unlock_bh(); |
429 | fp = old_fp; | 429 | fp = old_fp; |
430 | } | 430 | } |
431 | 431 | ||
diff --git a/net/core/flow.c b/net/core/flow.c index 2191af5f26ac..f23e7e386543 100644 --- a/net/core/flow.c +++ b/net/core/flow.c | |||
@@ -32,7 +32,6 @@ struct flow_cache_entry { | |||
32 | u8 dir; | 32 | u8 dir; |
33 | struct flowi key; | 33 | struct flowi key; |
34 | u32 genid; | 34 | u32 genid; |
35 | u32 sk_sid; | ||
36 | void *object; | 35 | void *object; |
37 | atomic_t *object_ref; | 36 | atomic_t *object_ref; |
38 | }; | 37 | }; |
@@ -165,7 +164,7 @@ static int flow_key_compare(struct flowi *key1, struct flowi *key2) | |||
165 | return 0; | 164 | return 0; |
166 | } | 165 | } |
167 | 166 | ||
168 | void *flow_cache_lookup(struct flowi *key, u32 sk_sid, u16 family, u8 dir, | 167 | void *flow_cache_lookup(struct flowi *key, u16 family, u8 dir, |
169 | flow_resolve_t resolver) | 168 | flow_resolve_t resolver) |
170 | { | 169 | { |
171 | struct flow_cache_entry *fle, **head; | 170 | struct flow_cache_entry *fle, **head; |
@@ -189,7 +188,6 @@ void *flow_cache_lookup(struct flowi *key, u32 sk_sid, u16 family, u8 dir, | |||
189 | for (fle = *head; fle; fle = fle->next) { | 188 | for (fle = *head; fle; fle = fle->next) { |
190 | if (fle->family == family && | 189 | if (fle->family == family && |
191 | fle->dir == dir && | 190 | fle->dir == dir && |
192 | fle->sk_sid == sk_sid && | ||
193 | flow_key_compare(key, &fle->key) == 0) { | 191 | flow_key_compare(key, &fle->key) == 0) { |
194 | if (fle->genid == atomic_read(&flow_cache_genid)) { | 192 | if (fle->genid == atomic_read(&flow_cache_genid)) { |
195 | void *ret = fle->object; | 193 | void *ret = fle->object; |
@@ -214,7 +212,6 @@ void *flow_cache_lookup(struct flowi *key, u32 sk_sid, u16 family, u8 dir, | |||
214 | *head = fle; | 212 | *head = fle; |
215 | fle->family = family; | 213 | fle->family = family; |
216 | fle->dir = dir; | 214 | fle->dir = dir; |
217 | fle->sk_sid = sk_sid; | ||
218 | memcpy(&fle->key, key, sizeof(*key)); | 215 | memcpy(&fle->key, key, sizeof(*key)); |
219 | fle->object = NULL; | 216 | fle->object = NULL; |
220 | flow_count(cpu)++; | 217 | flow_count(cpu)++; |
@@ -226,7 +223,7 @@ nocache: | |||
226 | void *obj; | 223 | void *obj; |
227 | atomic_t *obj_ref; | 224 | atomic_t *obj_ref; |
228 | 225 | ||
229 | resolver(key, sk_sid, family, dir, &obj, &obj_ref); | 226 | resolver(key, family, dir, &obj, &obj_ref); |
230 | 227 | ||
231 | if (fle) { | 228 | if (fle) { |
232 | fle->genid = atomic_read(&flow_cache_genid); | 229 | fle->genid = atomic_read(&flow_cache_genid); |
@@ -346,12 +343,8 @@ static int __init flow_cache_init(void) | |||
346 | 343 | ||
347 | flow_cachep = kmem_cache_create("flow_cache", | 344 | flow_cachep = kmem_cache_create("flow_cache", |
348 | sizeof(struct flow_cache_entry), | 345 | sizeof(struct flow_cache_entry), |
349 | 0, SLAB_HWCACHE_ALIGN, | 346 | 0, SLAB_HWCACHE_ALIGN|SLAB_PANIC, |
350 | NULL, NULL); | 347 | NULL, NULL); |
351 | |||
352 | if (!flow_cachep) | ||
353 | panic("NET: failed to allocate flow cache slab\n"); | ||
354 | |||
355 | flow_hash_shift = 10; | 348 | flow_hash_shift = 10; |
356 | flow_lwm = 2 * flow_hash_size; | 349 | flow_lwm = 2 * flow_hash_size; |
357 | flow_hwm = 4 * flow_hash_size; | 350 | flow_hwm = 4 * flow_hash_size; |
diff --git a/net/core/neighbour.c b/net/core/neighbour.c index fe2113f54e2b..b6c69e1463e8 100644 --- a/net/core/neighbour.c +++ b/net/core/neighbour.c | |||
@@ -30,6 +30,7 @@ | |||
30 | #include <net/dst.h> | 30 | #include <net/dst.h> |
31 | #include <net/sock.h> | 31 | #include <net/sock.h> |
32 | #include <net/netevent.h> | 32 | #include <net/netevent.h> |
33 | #include <net/netlink.h> | ||
33 | #include <linux/rtnetlink.h> | 34 | #include <linux/rtnetlink.h> |
34 | #include <linux/random.h> | 35 | #include <linux/random.h> |
35 | #include <linux/string.h> | 36 | #include <linux/string.h> |
@@ -888,7 +889,7 @@ out_unlock_bh: | |||
888 | return rc; | 889 | return rc; |
889 | } | 890 | } |
890 | 891 | ||
891 | static __inline__ void neigh_update_hhs(struct neighbour *neigh) | 892 | static void neigh_update_hhs(struct neighbour *neigh) |
892 | { | 893 | { |
893 | struct hh_cache *hh; | 894 | struct hh_cache *hh; |
894 | void (*update)(struct hh_cache*, struct net_device*, unsigned char *) = | 895 | void (*update)(struct hh_cache*, struct net_device*, unsigned char *) = |
@@ -1338,14 +1339,10 @@ void neigh_table_init_no_netlink(struct neigh_table *tbl) | |||
1338 | neigh_rand_reach_time(tbl->parms.base_reachable_time); | 1339 | neigh_rand_reach_time(tbl->parms.base_reachable_time); |
1339 | 1340 | ||
1340 | if (!tbl->kmem_cachep) | 1341 | if (!tbl->kmem_cachep) |
1341 | tbl->kmem_cachep = kmem_cache_create(tbl->id, | 1342 | tbl->kmem_cachep = |
1342 | tbl->entry_size, | 1343 | kmem_cache_create(tbl->id, tbl->entry_size, 0, |
1343 | 0, SLAB_HWCACHE_ALIGN, | 1344 | SLAB_HWCACHE_ALIGN|SLAB_PANIC, |
1344 | NULL, NULL); | 1345 | NULL, NULL); |
1345 | |||
1346 | if (!tbl->kmem_cachep) | ||
1347 | panic("cannot create neighbour cache"); | ||
1348 | |||
1349 | tbl->stats = alloc_percpu(struct neigh_statistics); | 1346 | tbl->stats = alloc_percpu(struct neigh_statistics); |
1350 | if (!tbl->stats) | 1347 | if (!tbl->stats) |
1351 | panic("cannot create neighbour cache statistics"); | 1348 | panic("cannot create neighbour cache statistics"); |
@@ -1440,48 +1437,62 @@ int neigh_table_clear(struct neigh_table *tbl) | |||
1440 | 1437 | ||
1441 | int neigh_delete(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) | 1438 | int neigh_delete(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) |
1442 | { | 1439 | { |
1443 | struct ndmsg *ndm = NLMSG_DATA(nlh); | 1440 | struct ndmsg *ndm; |
1444 | struct rtattr **nda = arg; | 1441 | struct nlattr *dst_attr; |
1445 | struct neigh_table *tbl; | 1442 | struct neigh_table *tbl; |
1446 | struct net_device *dev = NULL; | 1443 | struct net_device *dev = NULL; |
1447 | int err = -ENODEV; | 1444 | int err = -EINVAL; |
1448 | 1445 | ||
1449 | if (ndm->ndm_ifindex && | 1446 | if (nlmsg_len(nlh) < sizeof(*ndm)) |
1450 | (dev = dev_get_by_index(ndm->ndm_ifindex)) == NULL) | ||
1451 | goto out; | 1447 | goto out; |
1452 | 1448 | ||
1449 | dst_attr = nlmsg_find_attr(nlh, sizeof(*ndm), NDA_DST); | ||
1450 | if (dst_attr == NULL) | ||
1451 | goto out; | ||
1452 | |||
1453 | ndm = nlmsg_data(nlh); | ||
1454 | if (ndm->ndm_ifindex) { | ||
1455 | dev = dev_get_by_index(ndm->ndm_ifindex); | ||
1456 | if (dev == NULL) { | ||
1457 | err = -ENODEV; | ||
1458 | goto out; | ||
1459 | } | ||
1460 | } | ||
1461 | |||
1453 | read_lock(&neigh_tbl_lock); | 1462 | read_lock(&neigh_tbl_lock); |
1454 | for (tbl = neigh_tables; tbl; tbl = tbl->next) { | 1463 | for (tbl = neigh_tables; tbl; tbl = tbl->next) { |
1455 | struct rtattr *dst_attr = nda[NDA_DST - 1]; | 1464 | struct neighbour *neigh; |
1456 | struct neighbour *n; | ||
1457 | 1465 | ||
1458 | if (tbl->family != ndm->ndm_family) | 1466 | if (tbl->family != ndm->ndm_family) |
1459 | continue; | 1467 | continue; |
1460 | read_unlock(&neigh_tbl_lock); | 1468 | read_unlock(&neigh_tbl_lock); |
1461 | 1469 | ||
1462 | err = -EINVAL; | 1470 | if (nla_len(dst_attr) < tbl->key_len) |
1463 | if (!dst_attr || RTA_PAYLOAD(dst_attr) < tbl->key_len) | ||
1464 | goto out_dev_put; | 1471 | goto out_dev_put; |
1465 | 1472 | ||
1466 | if (ndm->ndm_flags & NTF_PROXY) { | 1473 | if (ndm->ndm_flags & NTF_PROXY) { |
1467 | err = pneigh_delete(tbl, RTA_DATA(dst_attr), dev); | 1474 | err = pneigh_delete(tbl, nla_data(dst_attr), dev); |
1468 | goto out_dev_put; | 1475 | goto out_dev_put; |
1469 | } | 1476 | } |
1470 | 1477 | ||
1471 | if (!dev) | 1478 | if (dev == NULL) |
1472 | goto out; | 1479 | goto out_dev_put; |
1473 | 1480 | ||
1474 | n = neigh_lookup(tbl, RTA_DATA(dst_attr), dev); | 1481 | neigh = neigh_lookup(tbl, nla_data(dst_attr), dev); |
1475 | if (n) { | 1482 | if (neigh == NULL) { |
1476 | err = neigh_update(n, NULL, NUD_FAILED, | 1483 | err = -ENOENT; |
1477 | NEIGH_UPDATE_F_OVERRIDE| | 1484 | goto out_dev_put; |
1478 | NEIGH_UPDATE_F_ADMIN); | ||
1479 | neigh_release(n); | ||
1480 | } | 1485 | } |
1486 | |||
1487 | err = neigh_update(neigh, NULL, NUD_FAILED, | ||
1488 | NEIGH_UPDATE_F_OVERRIDE | | ||
1489 | NEIGH_UPDATE_F_ADMIN); | ||
1490 | neigh_release(neigh); | ||
1481 | goto out_dev_put; | 1491 | goto out_dev_put; |
1482 | } | 1492 | } |
1483 | read_unlock(&neigh_tbl_lock); | 1493 | read_unlock(&neigh_tbl_lock); |
1484 | err = -EADDRNOTAVAIL; | 1494 | err = -EAFNOSUPPORT; |
1495 | |||
1485 | out_dev_put: | 1496 | out_dev_put: |
1486 | if (dev) | 1497 | if (dev) |
1487 | dev_put(dev); | 1498 | dev_put(dev); |
@@ -1491,76 +1502,93 @@ out: | |||
1491 | 1502 | ||
1492 | int neigh_add(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) | 1503 | int neigh_add(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) |
1493 | { | 1504 | { |
1494 | struct ndmsg *ndm = NLMSG_DATA(nlh); | 1505 | struct ndmsg *ndm; |
1495 | struct rtattr **nda = arg; | 1506 | struct nlattr *tb[NDA_MAX+1]; |
1496 | struct neigh_table *tbl; | 1507 | struct neigh_table *tbl; |
1497 | struct net_device *dev = NULL; | 1508 | struct net_device *dev = NULL; |
1498 | int err = -ENODEV; | 1509 | int err; |
1499 | 1510 | ||
1500 | if (ndm->ndm_ifindex && | 1511 | err = nlmsg_parse(nlh, sizeof(*ndm), tb, NDA_MAX, NULL); |
1501 | (dev = dev_get_by_index(ndm->ndm_ifindex)) == NULL) | 1512 | if (err < 0) |
1502 | goto out; | 1513 | goto out; |
1503 | 1514 | ||
1515 | err = -EINVAL; | ||
1516 | if (tb[NDA_DST] == NULL) | ||
1517 | goto out; | ||
1518 | |||
1519 | ndm = nlmsg_data(nlh); | ||
1520 | if (ndm->ndm_ifindex) { | ||
1521 | dev = dev_get_by_index(ndm->ndm_ifindex); | ||
1522 | if (dev == NULL) { | ||
1523 | err = -ENODEV; | ||
1524 | goto out; | ||
1525 | } | ||
1526 | |||
1527 | if (tb[NDA_LLADDR] && nla_len(tb[NDA_LLADDR]) < dev->addr_len) | ||
1528 | goto out_dev_put; | ||
1529 | } | ||
1530 | |||
1504 | read_lock(&neigh_tbl_lock); | 1531 | read_lock(&neigh_tbl_lock); |
1505 | for (tbl = neigh_tables; tbl; tbl = tbl->next) { | 1532 | for (tbl = neigh_tables; tbl; tbl = tbl->next) { |
1506 | struct rtattr *lladdr_attr = nda[NDA_LLADDR - 1]; | 1533 | int flags = NEIGH_UPDATE_F_ADMIN | NEIGH_UPDATE_F_OVERRIDE; |
1507 | struct rtattr *dst_attr = nda[NDA_DST - 1]; | 1534 | struct neighbour *neigh; |
1508 | int override = 1; | 1535 | void *dst, *lladdr; |
1509 | struct neighbour *n; | ||
1510 | 1536 | ||
1511 | if (tbl->family != ndm->ndm_family) | 1537 | if (tbl->family != ndm->ndm_family) |
1512 | continue; | 1538 | continue; |
1513 | read_unlock(&neigh_tbl_lock); | 1539 | read_unlock(&neigh_tbl_lock); |
1514 | 1540 | ||
1515 | err = -EINVAL; | 1541 | if (nla_len(tb[NDA_DST]) < tbl->key_len) |
1516 | if (!dst_attr || RTA_PAYLOAD(dst_attr) < tbl->key_len) | ||
1517 | goto out_dev_put; | 1542 | goto out_dev_put; |
1543 | dst = nla_data(tb[NDA_DST]); | ||
1544 | lladdr = tb[NDA_LLADDR] ? nla_data(tb[NDA_LLADDR]) : NULL; | ||
1518 | 1545 | ||
1519 | if (ndm->ndm_flags & NTF_PROXY) { | 1546 | if (ndm->ndm_flags & NTF_PROXY) { |
1547 | struct pneigh_entry *pn; | ||
1548 | |||
1520 | err = -ENOBUFS; | 1549 | err = -ENOBUFS; |
1521 | if (pneigh_lookup(tbl, RTA_DATA(dst_attr), dev, 1)) | 1550 | pn = pneigh_lookup(tbl, dst, dev, 1); |
1551 | if (pn) { | ||
1552 | pn->flags = ndm->ndm_flags; | ||
1522 | err = 0; | 1553 | err = 0; |
1554 | } | ||
1523 | goto out_dev_put; | 1555 | goto out_dev_put; |
1524 | } | 1556 | } |
1525 | 1557 | ||
1526 | err = -EINVAL; | 1558 | if (dev == NULL) |
1527 | if (!dev) | ||
1528 | goto out; | ||
1529 | if (lladdr_attr && RTA_PAYLOAD(lladdr_attr) < dev->addr_len) | ||
1530 | goto out_dev_put; | 1559 | goto out_dev_put; |
1560 | |||
1561 | neigh = neigh_lookup(tbl, dst, dev); | ||
1562 | if (neigh == NULL) { | ||
1563 | if (!(nlh->nlmsg_flags & NLM_F_CREATE)) { | ||
1564 | err = -ENOENT; | ||
1565 | goto out_dev_put; | ||
1566 | } | ||
1531 | 1567 | ||
1532 | n = neigh_lookup(tbl, RTA_DATA(dst_attr), dev); | 1568 | neigh = __neigh_lookup_errno(tbl, dst, dev); |
1533 | if (n) { | 1569 | if (IS_ERR(neigh)) { |
1534 | if (nlh->nlmsg_flags & NLM_F_EXCL) { | 1570 | err = PTR_ERR(neigh); |
1535 | err = -EEXIST; | ||
1536 | neigh_release(n); | ||
1537 | goto out_dev_put; | 1571 | goto out_dev_put; |
1538 | } | 1572 | } |
1539 | |||
1540 | override = nlh->nlmsg_flags & NLM_F_REPLACE; | ||
1541 | } else if (!(nlh->nlmsg_flags & NLM_F_CREATE)) { | ||
1542 | err = -ENOENT; | ||
1543 | goto out_dev_put; | ||
1544 | } else { | 1573 | } else { |
1545 | n = __neigh_lookup_errno(tbl, RTA_DATA(dst_attr), dev); | 1574 | if (nlh->nlmsg_flags & NLM_F_EXCL) { |
1546 | if (IS_ERR(n)) { | 1575 | err = -EEXIST; |
1547 | err = PTR_ERR(n); | 1576 | neigh_release(neigh); |
1548 | goto out_dev_put; | 1577 | goto out_dev_put; |
1549 | } | 1578 | } |
1550 | } | ||
1551 | 1579 | ||
1552 | err = neigh_update(n, | 1580 | if (!(nlh->nlmsg_flags & NLM_F_REPLACE)) |
1553 | lladdr_attr ? RTA_DATA(lladdr_attr) : NULL, | 1581 | flags &= ~NEIGH_UPDATE_F_OVERRIDE; |
1554 | ndm->ndm_state, | 1582 | } |
1555 | (override ? NEIGH_UPDATE_F_OVERRIDE : 0) | | ||
1556 | NEIGH_UPDATE_F_ADMIN); | ||
1557 | 1583 | ||
1558 | neigh_release(n); | 1584 | err = neigh_update(neigh, lladdr, ndm->ndm_state, flags); |
1585 | neigh_release(neigh); | ||
1559 | goto out_dev_put; | 1586 | goto out_dev_put; |
1560 | } | 1587 | } |
1561 | 1588 | ||
1562 | read_unlock(&neigh_tbl_lock); | 1589 | read_unlock(&neigh_tbl_lock); |
1563 | err = -EADDRNOTAVAIL; | 1590 | err = -EAFNOSUPPORT; |
1591 | |||
1564 | out_dev_put: | 1592 | out_dev_put: |
1565 | if (dev) | 1593 | if (dev) |
1566 | dev_put(dev); | 1594 | dev_put(dev); |
@@ -1570,56 +1598,59 @@ out: | |||
1570 | 1598 | ||
1571 | static int neightbl_fill_parms(struct sk_buff *skb, struct neigh_parms *parms) | 1599 | static int neightbl_fill_parms(struct sk_buff *skb, struct neigh_parms *parms) |
1572 | { | 1600 | { |
1573 | struct rtattr *nest = NULL; | 1601 | struct nlattr *nest; |
1574 | 1602 | ||
1575 | nest = RTA_NEST(skb, NDTA_PARMS); | 1603 | nest = nla_nest_start(skb, NDTA_PARMS); |
1604 | if (nest == NULL) | ||
1605 | return -ENOBUFS; | ||
1576 | 1606 | ||
1577 | if (parms->dev) | 1607 | if (parms->dev) |
1578 | RTA_PUT_U32(skb, NDTPA_IFINDEX, parms->dev->ifindex); | 1608 | NLA_PUT_U32(skb, NDTPA_IFINDEX, parms->dev->ifindex); |
1579 | 1609 | ||
1580 | RTA_PUT_U32(skb, NDTPA_REFCNT, atomic_read(&parms->refcnt)); | 1610 | NLA_PUT_U32(skb, NDTPA_REFCNT, atomic_read(&parms->refcnt)); |
1581 | RTA_PUT_U32(skb, NDTPA_QUEUE_LEN, parms->queue_len); | 1611 | NLA_PUT_U32(skb, NDTPA_QUEUE_LEN, parms->queue_len); |
1582 | RTA_PUT_U32(skb, NDTPA_PROXY_QLEN, parms->proxy_qlen); | 1612 | NLA_PUT_U32(skb, NDTPA_PROXY_QLEN, parms->proxy_qlen); |
1583 | RTA_PUT_U32(skb, NDTPA_APP_PROBES, parms->app_probes); | 1613 | NLA_PUT_U32(skb, NDTPA_APP_PROBES, parms->app_probes); |
1584 | RTA_PUT_U32(skb, NDTPA_UCAST_PROBES, parms->ucast_probes); | 1614 | NLA_PUT_U32(skb, NDTPA_UCAST_PROBES, parms->ucast_probes); |
1585 | RTA_PUT_U32(skb, NDTPA_MCAST_PROBES, parms->mcast_probes); | 1615 | NLA_PUT_U32(skb, NDTPA_MCAST_PROBES, parms->mcast_probes); |
1586 | RTA_PUT_MSECS(skb, NDTPA_REACHABLE_TIME, parms->reachable_time); | 1616 | NLA_PUT_MSECS(skb, NDTPA_REACHABLE_TIME, parms->reachable_time); |
1587 | RTA_PUT_MSECS(skb, NDTPA_BASE_REACHABLE_TIME, | 1617 | NLA_PUT_MSECS(skb, NDTPA_BASE_REACHABLE_TIME, |
1588 | parms->base_reachable_time); | 1618 | parms->base_reachable_time); |
1589 | RTA_PUT_MSECS(skb, NDTPA_GC_STALETIME, parms->gc_staletime); | 1619 | NLA_PUT_MSECS(skb, NDTPA_GC_STALETIME, parms->gc_staletime); |
1590 | RTA_PUT_MSECS(skb, NDTPA_DELAY_PROBE_TIME, parms->delay_probe_time); | 1620 | NLA_PUT_MSECS(skb, NDTPA_DELAY_PROBE_TIME, parms->delay_probe_time); |
1591 | RTA_PUT_MSECS(skb, NDTPA_RETRANS_TIME, parms->retrans_time); | 1621 | NLA_PUT_MSECS(skb, NDTPA_RETRANS_TIME, parms->retrans_time); |
1592 | RTA_PUT_MSECS(skb, NDTPA_ANYCAST_DELAY, parms->anycast_delay); | 1622 | NLA_PUT_MSECS(skb, NDTPA_ANYCAST_DELAY, parms->anycast_delay); |
1593 | RTA_PUT_MSECS(skb, NDTPA_PROXY_DELAY, parms->proxy_delay); | 1623 | NLA_PUT_MSECS(skb, NDTPA_PROXY_DELAY, parms->proxy_delay); |
1594 | RTA_PUT_MSECS(skb, NDTPA_LOCKTIME, parms->locktime); | 1624 | NLA_PUT_MSECS(skb, NDTPA_LOCKTIME, parms->locktime); |
1595 | 1625 | ||
1596 | return RTA_NEST_END(skb, nest); | 1626 | return nla_nest_end(skb, nest); |
1597 | 1627 | ||
1598 | rtattr_failure: | 1628 | nla_put_failure: |
1599 | return RTA_NEST_CANCEL(skb, nest); | 1629 | return nla_nest_cancel(skb, nest); |
1600 | } | 1630 | } |
1601 | 1631 | ||
1602 | static int neightbl_fill_info(struct neigh_table *tbl, struct sk_buff *skb, | 1632 | static int neightbl_fill_info(struct sk_buff *skb, struct neigh_table *tbl, |
1603 | struct netlink_callback *cb) | 1633 | u32 pid, u32 seq, int type, int flags) |
1604 | { | 1634 | { |
1605 | struct nlmsghdr *nlh; | 1635 | struct nlmsghdr *nlh; |
1606 | struct ndtmsg *ndtmsg; | 1636 | struct ndtmsg *ndtmsg; |
1607 | 1637 | ||
1608 | nlh = NLMSG_NEW_ANSWER(skb, cb, RTM_NEWNEIGHTBL, sizeof(struct ndtmsg), | 1638 | nlh = nlmsg_put(skb, pid, seq, type, sizeof(*ndtmsg), flags); |
1609 | NLM_F_MULTI); | 1639 | if (nlh == NULL) |
1640 | return -ENOBUFS; | ||
1610 | 1641 | ||
1611 | ndtmsg = NLMSG_DATA(nlh); | 1642 | ndtmsg = nlmsg_data(nlh); |
1612 | 1643 | ||
1613 | read_lock_bh(&tbl->lock); | 1644 | read_lock_bh(&tbl->lock); |
1614 | ndtmsg->ndtm_family = tbl->family; | 1645 | ndtmsg->ndtm_family = tbl->family; |
1615 | ndtmsg->ndtm_pad1 = 0; | 1646 | ndtmsg->ndtm_pad1 = 0; |
1616 | ndtmsg->ndtm_pad2 = 0; | 1647 | ndtmsg->ndtm_pad2 = 0; |
1617 | 1648 | ||
1618 | RTA_PUT_STRING(skb, NDTA_NAME, tbl->id); | 1649 | NLA_PUT_STRING(skb, NDTA_NAME, tbl->id); |
1619 | RTA_PUT_MSECS(skb, NDTA_GC_INTERVAL, tbl->gc_interval); | 1650 | NLA_PUT_MSECS(skb, NDTA_GC_INTERVAL, tbl->gc_interval); |
1620 | RTA_PUT_U32(skb, NDTA_THRESH1, tbl->gc_thresh1); | 1651 | NLA_PUT_U32(skb, NDTA_THRESH1, tbl->gc_thresh1); |
1621 | RTA_PUT_U32(skb, NDTA_THRESH2, tbl->gc_thresh2); | 1652 | NLA_PUT_U32(skb, NDTA_THRESH2, tbl->gc_thresh2); |
1622 | RTA_PUT_U32(skb, NDTA_THRESH3, tbl->gc_thresh3); | 1653 | NLA_PUT_U32(skb, NDTA_THRESH3, tbl->gc_thresh3); |
1623 | 1654 | ||
1624 | { | 1655 | { |
1625 | unsigned long now = jiffies; | 1656 | unsigned long now = jiffies; |
@@ -1638,7 +1669,7 @@ static int neightbl_fill_info(struct neigh_table *tbl, struct sk_buff *skb, | |||
1638 | .ndtc_proxy_qlen = tbl->proxy_queue.qlen, | 1669 | .ndtc_proxy_qlen = tbl->proxy_queue.qlen, |
1639 | }; | 1670 | }; |
1640 | 1671 | ||
1641 | RTA_PUT(skb, NDTA_CONFIG, sizeof(ndc), &ndc); | 1672 | NLA_PUT(skb, NDTA_CONFIG, sizeof(ndc), &ndc); |
1642 | } | 1673 | } |
1643 | 1674 | ||
1644 | { | 1675 | { |
@@ -1663,55 +1694,50 @@ static int neightbl_fill_info(struct neigh_table *tbl, struct sk_buff *skb, | |||
1663 | ndst.ndts_forced_gc_runs += st->forced_gc_runs; | 1694 | ndst.ndts_forced_gc_runs += st->forced_gc_runs; |
1664 | } | 1695 | } |
1665 | 1696 | ||
1666 | RTA_PUT(skb, NDTA_STATS, sizeof(ndst), &ndst); | 1697 | NLA_PUT(skb, NDTA_STATS, sizeof(ndst), &ndst); |
1667 | } | 1698 | } |
1668 | 1699 | ||
1669 | BUG_ON(tbl->parms.dev); | 1700 | BUG_ON(tbl->parms.dev); |
1670 | if (neightbl_fill_parms(skb, &tbl->parms) < 0) | 1701 | if (neightbl_fill_parms(skb, &tbl->parms) < 0) |
1671 | goto rtattr_failure; | 1702 | goto nla_put_failure; |
1672 | 1703 | ||
1673 | read_unlock_bh(&tbl->lock); | 1704 | read_unlock_bh(&tbl->lock); |
1674 | return NLMSG_END(skb, nlh); | 1705 | return nlmsg_end(skb, nlh); |
1675 | 1706 | ||
1676 | rtattr_failure: | 1707 | nla_put_failure: |
1677 | read_unlock_bh(&tbl->lock); | 1708 | read_unlock_bh(&tbl->lock); |
1678 | return NLMSG_CANCEL(skb, nlh); | 1709 | return nlmsg_cancel(skb, nlh); |
1679 | |||
1680 | nlmsg_failure: | ||
1681 | return -1; | ||
1682 | } | 1710 | } |
1683 | 1711 | ||
1684 | static int neightbl_fill_param_info(struct neigh_table *tbl, | 1712 | static int neightbl_fill_param_info(struct sk_buff *skb, |
1713 | struct neigh_table *tbl, | ||
1685 | struct neigh_parms *parms, | 1714 | struct neigh_parms *parms, |
1686 | struct sk_buff *skb, | 1715 | u32 pid, u32 seq, int type, |
1687 | struct netlink_callback *cb) | 1716 | unsigned int flags) |
1688 | { | 1717 | { |
1689 | struct ndtmsg *ndtmsg; | 1718 | struct ndtmsg *ndtmsg; |
1690 | struct nlmsghdr *nlh; | 1719 | struct nlmsghdr *nlh; |
1691 | 1720 | ||
1692 | nlh = NLMSG_NEW_ANSWER(skb, cb, RTM_NEWNEIGHTBL, sizeof(struct ndtmsg), | 1721 | nlh = nlmsg_put(skb, pid, seq, type, sizeof(*ndtmsg), flags); |
1693 | NLM_F_MULTI); | 1722 | if (nlh == NULL) |
1723 | return -ENOBUFS; | ||
1694 | 1724 | ||
1695 | ndtmsg = NLMSG_DATA(nlh); | 1725 | ndtmsg = nlmsg_data(nlh); |
1696 | 1726 | ||
1697 | read_lock_bh(&tbl->lock); | 1727 | read_lock_bh(&tbl->lock); |
1698 | ndtmsg->ndtm_family = tbl->family; | 1728 | ndtmsg->ndtm_family = tbl->family; |
1699 | ndtmsg->ndtm_pad1 = 0; | 1729 | ndtmsg->ndtm_pad1 = 0; |
1700 | ndtmsg->ndtm_pad2 = 0; | 1730 | ndtmsg->ndtm_pad2 = 0; |
1701 | RTA_PUT_STRING(skb, NDTA_NAME, tbl->id); | ||
1702 | 1731 | ||
1703 | if (neightbl_fill_parms(skb, parms) < 0) | 1732 | if (nla_put_string(skb, NDTA_NAME, tbl->id) < 0 || |
1704 | goto rtattr_failure; | 1733 | neightbl_fill_parms(skb, parms) < 0) |
1734 | goto errout; | ||
1705 | 1735 | ||
1706 | read_unlock_bh(&tbl->lock); | 1736 | read_unlock_bh(&tbl->lock); |
1707 | return NLMSG_END(skb, nlh); | 1737 | return nlmsg_end(skb, nlh); |
1708 | 1738 | errout: | |
1709 | rtattr_failure: | ||
1710 | read_unlock_bh(&tbl->lock); | 1739 | read_unlock_bh(&tbl->lock); |
1711 | return NLMSG_CANCEL(skb, nlh); | 1740 | return nlmsg_cancel(skb, nlh); |
1712 | |||
1713 | nlmsg_failure: | ||
1714 | return -1; | ||
1715 | } | 1741 | } |
1716 | 1742 | ||
1717 | static inline struct neigh_parms *lookup_neigh_params(struct neigh_table *tbl, | 1743 | static inline struct neigh_parms *lookup_neigh_params(struct neigh_table *tbl, |
@@ -1727,28 +1753,61 @@ static inline struct neigh_parms *lookup_neigh_params(struct neigh_table *tbl, | |||
1727 | return NULL; | 1753 | return NULL; |
1728 | } | 1754 | } |
1729 | 1755 | ||
1756 | static struct nla_policy nl_neightbl_policy[NDTA_MAX+1] __read_mostly = { | ||
1757 | [NDTA_NAME] = { .type = NLA_STRING }, | ||
1758 | [NDTA_THRESH1] = { .type = NLA_U32 }, | ||
1759 | [NDTA_THRESH2] = { .type = NLA_U32 }, | ||
1760 | [NDTA_THRESH3] = { .type = NLA_U32 }, | ||
1761 | [NDTA_GC_INTERVAL] = { .type = NLA_U64 }, | ||
1762 | [NDTA_PARMS] = { .type = NLA_NESTED }, | ||
1763 | }; | ||
1764 | |||
1765 | static struct nla_policy nl_ntbl_parm_policy[NDTPA_MAX+1] __read_mostly = { | ||
1766 | [NDTPA_IFINDEX] = { .type = NLA_U32 }, | ||
1767 | [NDTPA_QUEUE_LEN] = { .type = NLA_U32 }, | ||
1768 | [NDTPA_PROXY_QLEN] = { .type = NLA_U32 }, | ||
1769 | [NDTPA_APP_PROBES] = { .type = NLA_U32 }, | ||
1770 | [NDTPA_UCAST_PROBES] = { .type = NLA_U32 }, | ||
1771 | [NDTPA_MCAST_PROBES] = { .type = NLA_U32 }, | ||
1772 | [NDTPA_BASE_REACHABLE_TIME] = { .type = NLA_U64 }, | ||
1773 | [NDTPA_GC_STALETIME] = { .type = NLA_U64 }, | ||
1774 | [NDTPA_DELAY_PROBE_TIME] = { .type = NLA_U64 }, | ||
1775 | [NDTPA_RETRANS_TIME] = { .type = NLA_U64 }, | ||
1776 | [NDTPA_ANYCAST_DELAY] = { .type = NLA_U64 }, | ||
1777 | [NDTPA_PROXY_DELAY] = { .type = NLA_U64 }, | ||
1778 | [NDTPA_LOCKTIME] = { .type = NLA_U64 }, | ||
1779 | }; | ||
1780 | |||
1730 | int neightbl_set(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) | 1781 | int neightbl_set(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) |
1731 | { | 1782 | { |
1732 | struct neigh_table *tbl; | 1783 | struct neigh_table *tbl; |
1733 | struct ndtmsg *ndtmsg = NLMSG_DATA(nlh); | 1784 | struct ndtmsg *ndtmsg; |
1734 | struct rtattr **tb = arg; | 1785 | struct nlattr *tb[NDTA_MAX+1]; |
1735 | int err = -EINVAL; | 1786 | int err; |
1736 | 1787 | ||
1737 | if (!tb[NDTA_NAME - 1] || !RTA_PAYLOAD(tb[NDTA_NAME - 1])) | 1788 | err = nlmsg_parse(nlh, sizeof(*ndtmsg), tb, NDTA_MAX, |
1738 | return -EINVAL; | 1789 | nl_neightbl_policy); |
1790 | if (err < 0) | ||
1791 | goto errout; | ||
1792 | |||
1793 | if (tb[NDTA_NAME] == NULL) { | ||
1794 | err = -EINVAL; | ||
1795 | goto errout; | ||
1796 | } | ||
1739 | 1797 | ||
1798 | ndtmsg = nlmsg_data(nlh); | ||
1740 | read_lock(&neigh_tbl_lock); | 1799 | read_lock(&neigh_tbl_lock); |
1741 | for (tbl = neigh_tables; tbl; tbl = tbl->next) { | 1800 | for (tbl = neigh_tables; tbl; tbl = tbl->next) { |
1742 | if (ndtmsg->ndtm_family && tbl->family != ndtmsg->ndtm_family) | 1801 | if (ndtmsg->ndtm_family && tbl->family != ndtmsg->ndtm_family) |
1743 | continue; | 1802 | continue; |
1744 | 1803 | ||
1745 | if (!rtattr_strcmp(tb[NDTA_NAME - 1], tbl->id)) | 1804 | if (nla_strcmp(tb[NDTA_NAME], tbl->id) == 0) |
1746 | break; | 1805 | break; |
1747 | } | 1806 | } |
1748 | 1807 | ||
1749 | if (tbl == NULL) { | 1808 | if (tbl == NULL) { |
1750 | err = -ENOENT; | 1809 | err = -ENOENT; |
1751 | goto errout; | 1810 | goto errout_locked; |
1752 | } | 1811 | } |
1753 | 1812 | ||
1754 | /* | 1813 | /* |
@@ -1757,165 +1816,178 @@ int neightbl_set(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) | |||
1757 | */ | 1816 | */ |
1758 | write_lock_bh(&tbl->lock); | 1817 | write_lock_bh(&tbl->lock); |
1759 | 1818 | ||
1760 | if (tb[NDTA_THRESH1 - 1]) | 1819 | if (tb[NDTA_PARMS]) { |
1761 | tbl->gc_thresh1 = RTA_GET_U32(tb[NDTA_THRESH1 - 1]); | 1820 | struct nlattr *tbp[NDTPA_MAX+1]; |
1762 | |||
1763 | if (tb[NDTA_THRESH2 - 1]) | ||
1764 | tbl->gc_thresh2 = RTA_GET_U32(tb[NDTA_THRESH2 - 1]); | ||
1765 | |||
1766 | if (tb[NDTA_THRESH3 - 1]) | ||
1767 | tbl->gc_thresh3 = RTA_GET_U32(tb[NDTA_THRESH3 - 1]); | ||
1768 | |||
1769 | if (tb[NDTA_GC_INTERVAL - 1]) | ||
1770 | tbl->gc_interval = RTA_GET_MSECS(tb[NDTA_GC_INTERVAL - 1]); | ||
1771 | |||
1772 | if (tb[NDTA_PARMS - 1]) { | ||
1773 | struct rtattr *tbp[NDTPA_MAX]; | ||
1774 | struct neigh_parms *p; | 1821 | struct neigh_parms *p; |
1775 | u32 ifindex = 0; | 1822 | int i, ifindex = 0; |
1776 | 1823 | ||
1777 | if (rtattr_parse_nested(tbp, NDTPA_MAX, tb[NDTA_PARMS - 1]) < 0) | 1824 | err = nla_parse_nested(tbp, NDTPA_MAX, tb[NDTA_PARMS], |
1778 | goto rtattr_failure; | 1825 | nl_ntbl_parm_policy); |
1826 | if (err < 0) | ||
1827 | goto errout_tbl_lock; | ||
1779 | 1828 | ||
1780 | if (tbp[NDTPA_IFINDEX - 1]) | 1829 | if (tbp[NDTPA_IFINDEX]) |
1781 | ifindex = RTA_GET_U32(tbp[NDTPA_IFINDEX - 1]); | 1830 | ifindex = nla_get_u32(tbp[NDTPA_IFINDEX]); |
1782 | 1831 | ||
1783 | p = lookup_neigh_params(tbl, ifindex); | 1832 | p = lookup_neigh_params(tbl, ifindex); |
1784 | if (p == NULL) { | 1833 | if (p == NULL) { |
1785 | err = -ENOENT; | 1834 | err = -ENOENT; |
1786 | goto rtattr_failure; | 1835 | goto errout_tbl_lock; |
1787 | } | 1836 | } |
1788 | |||
1789 | if (tbp[NDTPA_QUEUE_LEN - 1]) | ||
1790 | p->queue_len = RTA_GET_U32(tbp[NDTPA_QUEUE_LEN - 1]); | ||
1791 | |||
1792 | if (tbp[NDTPA_PROXY_QLEN - 1]) | ||
1793 | p->proxy_qlen = RTA_GET_U32(tbp[NDTPA_PROXY_QLEN - 1]); | ||
1794 | |||
1795 | if (tbp[NDTPA_APP_PROBES - 1]) | ||
1796 | p->app_probes = RTA_GET_U32(tbp[NDTPA_APP_PROBES - 1]); | ||
1797 | 1837 | ||
1798 | if (tbp[NDTPA_UCAST_PROBES - 1]) | 1838 | for (i = 1; i <= NDTPA_MAX; i++) { |
1799 | p->ucast_probes = | 1839 | if (tbp[i] == NULL) |
1800 | RTA_GET_U32(tbp[NDTPA_UCAST_PROBES - 1]); | 1840 | continue; |
1801 | |||
1802 | if (tbp[NDTPA_MCAST_PROBES - 1]) | ||
1803 | p->mcast_probes = | ||
1804 | RTA_GET_U32(tbp[NDTPA_MCAST_PROBES - 1]); | ||
1805 | |||
1806 | if (tbp[NDTPA_BASE_REACHABLE_TIME - 1]) | ||
1807 | p->base_reachable_time = | ||
1808 | RTA_GET_MSECS(tbp[NDTPA_BASE_REACHABLE_TIME - 1]); | ||
1809 | |||
1810 | if (tbp[NDTPA_GC_STALETIME - 1]) | ||
1811 | p->gc_staletime = | ||
1812 | RTA_GET_MSECS(tbp[NDTPA_GC_STALETIME - 1]); | ||
1813 | 1841 | ||
1814 | if (tbp[NDTPA_DELAY_PROBE_TIME - 1]) | 1842 | switch (i) { |
1815 | p->delay_probe_time = | 1843 | case NDTPA_QUEUE_LEN: |
1816 | RTA_GET_MSECS(tbp[NDTPA_DELAY_PROBE_TIME - 1]); | 1844 | p->queue_len = nla_get_u32(tbp[i]); |
1845 | break; | ||
1846 | case NDTPA_PROXY_QLEN: | ||
1847 | p->proxy_qlen = nla_get_u32(tbp[i]); | ||
1848 | break; | ||
1849 | case NDTPA_APP_PROBES: | ||
1850 | p->app_probes = nla_get_u32(tbp[i]); | ||
1851 | break; | ||
1852 | case NDTPA_UCAST_PROBES: | ||
1853 | p->ucast_probes = nla_get_u32(tbp[i]); | ||
1854 | break; | ||
1855 | case NDTPA_MCAST_PROBES: | ||
1856 | p->mcast_probes = nla_get_u32(tbp[i]); | ||
1857 | break; | ||
1858 | case NDTPA_BASE_REACHABLE_TIME: | ||
1859 | p->base_reachable_time = nla_get_msecs(tbp[i]); | ||
1860 | break; | ||
1861 | case NDTPA_GC_STALETIME: | ||
1862 | p->gc_staletime = nla_get_msecs(tbp[i]); | ||
1863 | break; | ||
1864 | case NDTPA_DELAY_PROBE_TIME: | ||
1865 | p->delay_probe_time = nla_get_msecs(tbp[i]); | ||
1866 | break; | ||
1867 | case NDTPA_RETRANS_TIME: | ||
1868 | p->retrans_time = nla_get_msecs(tbp[i]); | ||
1869 | break; | ||
1870 | case NDTPA_ANYCAST_DELAY: | ||
1871 | p->anycast_delay = nla_get_msecs(tbp[i]); | ||
1872 | break; | ||
1873 | case NDTPA_PROXY_DELAY: | ||
1874 | p->proxy_delay = nla_get_msecs(tbp[i]); | ||
1875 | break; | ||
1876 | case NDTPA_LOCKTIME: | ||
1877 | p->locktime = nla_get_msecs(tbp[i]); | ||
1878 | break; | ||
1879 | } | ||
1880 | } | ||
1881 | } | ||
1817 | 1882 | ||
1818 | if (tbp[NDTPA_RETRANS_TIME - 1]) | 1883 | if (tb[NDTA_THRESH1]) |
1819 | p->retrans_time = | 1884 | tbl->gc_thresh1 = nla_get_u32(tb[NDTA_THRESH1]); |
1820 | RTA_GET_MSECS(tbp[NDTPA_RETRANS_TIME - 1]); | ||
1821 | 1885 | ||
1822 | if (tbp[NDTPA_ANYCAST_DELAY - 1]) | 1886 | if (tb[NDTA_THRESH2]) |
1823 | p->anycast_delay = | 1887 | tbl->gc_thresh2 = nla_get_u32(tb[NDTA_THRESH2]); |
1824 | RTA_GET_MSECS(tbp[NDTPA_ANYCAST_DELAY - 1]); | ||
1825 | 1888 | ||
1826 | if (tbp[NDTPA_PROXY_DELAY - 1]) | 1889 | if (tb[NDTA_THRESH3]) |
1827 | p->proxy_delay = | 1890 | tbl->gc_thresh3 = nla_get_u32(tb[NDTA_THRESH3]); |
1828 | RTA_GET_MSECS(tbp[NDTPA_PROXY_DELAY - 1]); | ||
1829 | 1891 | ||
1830 | if (tbp[NDTPA_LOCKTIME - 1]) | 1892 | if (tb[NDTA_GC_INTERVAL]) |
1831 | p->locktime = RTA_GET_MSECS(tbp[NDTPA_LOCKTIME - 1]); | 1893 | tbl->gc_interval = nla_get_msecs(tb[NDTA_GC_INTERVAL]); |
1832 | } | ||
1833 | 1894 | ||
1834 | err = 0; | 1895 | err = 0; |
1835 | 1896 | ||
1836 | rtattr_failure: | 1897 | errout_tbl_lock: |
1837 | write_unlock_bh(&tbl->lock); | 1898 | write_unlock_bh(&tbl->lock); |
1838 | errout: | 1899 | errout_locked: |
1839 | read_unlock(&neigh_tbl_lock); | 1900 | read_unlock(&neigh_tbl_lock); |
1901 | errout: | ||
1840 | return err; | 1902 | return err; |
1841 | } | 1903 | } |
1842 | 1904 | ||
1843 | int neightbl_dump_info(struct sk_buff *skb, struct netlink_callback *cb) | 1905 | int neightbl_dump_info(struct sk_buff *skb, struct netlink_callback *cb) |
1844 | { | 1906 | { |
1845 | int idx, family; | 1907 | int family, tidx, nidx = 0; |
1846 | int s_idx = cb->args[0]; | 1908 | int tbl_skip = cb->args[0]; |
1909 | int neigh_skip = cb->args[1]; | ||
1847 | struct neigh_table *tbl; | 1910 | struct neigh_table *tbl; |
1848 | 1911 | ||
1849 | family = ((struct rtgenmsg *)NLMSG_DATA(cb->nlh))->rtgen_family; | 1912 | family = ((struct rtgenmsg *) nlmsg_data(cb->nlh))->rtgen_family; |
1850 | 1913 | ||
1851 | read_lock(&neigh_tbl_lock); | 1914 | read_lock(&neigh_tbl_lock); |
1852 | for (tbl = neigh_tables, idx = 0; tbl; tbl = tbl->next) { | 1915 | for (tbl = neigh_tables, tidx = 0; tbl; tbl = tbl->next, tidx++) { |
1853 | struct neigh_parms *p; | 1916 | struct neigh_parms *p; |
1854 | 1917 | ||
1855 | if (idx < s_idx || (family && tbl->family != family)) | 1918 | if (tidx < tbl_skip || (family && tbl->family != family)) |
1856 | continue; | 1919 | continue; |
1857 | 1920 | ||
1858 | if (neightbl_fill_info(tbl, skb, cb) <= 0) | 1921 | if (neightbl_fill_info(skb, tbl, NETLINK_CB(cb->skb).pid, |
1922 | cb->nlh->nlmsg_seq, RTM_NEWNEIGHTBL, | ||
1923 | NLM_F_MULTI) <= 0) | ||
1859 | break; | 1924 | break; |
1860 | 1925 | ||
1861 | for (++idx, p = tbl->parms.next; p; p = p->next, idx++) { | 1926 | for (nidx = 0, p = tbl->parms.next; p; p = p->next, nidx++) { |
1862 | if (idx < s_idx) | 1927 | if (nidx < neigh_skip) |
1863 | continue; | 1928 | continue; |
1864 | 1929 | ||
1865 | if (neightbl_fill_param_info(tbl, p, skb, cb) <= 0) | 1930 | if (neightbl_fill_param_info(skb, tbl, p, |
1931 | NETLINK_CB(cb->skb).pid, | ||
1932 | cb->nlh->nlmsg_seq, | ||
1933 | RTM_NEWNEIGHTBL, | ||
1934 | NLM_F_MULTI) <= 0) | ||
1866 | goto out; | 1935 | goto out; |
1867 | } | 1936 | } |
1868 | 1937 | ||
1938 | neigh_skip = 0; | ||
1869 | } | 1939 | } |
1870 | out: | 1940 | out: |
1871 | read_unlock(&neigh_tbl_lock); | 1941 | read_unlock(&neigh_tbl_lock); |
1872 | cb->args[0] = idx; | 1942 | cb->args[0] = tidx; |
1943 | cb->args[1] = nidx; | ||
1873 | 1944 | ||
1874 | return skb->len; | 1945 | return skb->len; |
1875 | } | 1946 | } |
1876 | 1947 | ||
1877 | static int neigh_fill_info(struct sk_buff *skb, struct neighbour *n, | 1948 | static int neigh_fill_info(struct sk_buff *skb, struct neighbour *neigh, |
1878 | u32 pid, u32 seq, int event, unsigned int flags) | 1949 | u32 pid, u32 seq, int type, unsigned int flags) |
1879 | { | 1950 | { |
1880 | unsigned long now = jiffies; | 1951 | unsigned long now = jiffies; |
1881 | unsigned char *b = skb->tail; | ||
1882 | struct nda_cacheinfo ci; | 1952 | struct nda_cacheinfo ci; |
1883 | int locked = 0; | 1953 | struct nlmsghdr *nlh; |
1884 | u32 probes; | 1954 | struct ndmsg *ndm; |
1885 | struct nlmsghdr *nlh = NLMSG_NEW(skb, pid, seq, event, | 1955 | |
1886 | sizeof(struct ndmsg), flags); | 1956 | nlh = nlmsg_put(skb, pid, seq, type, sizeof(*ndm), flags); |
1887 | struct ndmsg *ndm = NLMSG_DATA(nlh); | 1957 | if (nlh == NULL) |
1958 | return -ENOBUFS; | ||
1888 | 1959 | ||
1889 | ndm->ndm_family = n->ops->family; | 1960 | ndm = nlmsg_data(nlh); |
1961 | ndm->ndm_family = neigh->ops->family; | ||
1890 | ndm->ndm_pad1 = 0; | 1962 | ndm->ndm_pad1 = 0; |
1891 | ndm->ndm_pad2 = 0; | 1963 | ndm->ndm_pad2 = 0; |
1892 | ndm->ndm_flags = n->flags; | 1964 | ndm->ndm_flags = neigh->flags; |
1893 | ndm->ndm_type = n->type; | 1965 | ndm->ndm_type = neigh->type; |
1894 | ndm->ndm_ifindex = n->dev->ifindex; | 1966 | ndm->ndm_ifindex = neigh->dev->ifindex; |
1895 | RTA_PUT(skb, NDA_DST, n->tbl->key_len, n->primary_key); | 1967 | |
1896 | read_lock_bh(&n->lock); | 1968 | NLA_PUT(skb, NDA_DST, neigh->tbl->key_len, neigh->primary_key); |
1897 | locked = 1; | ||
1898 | ndm->ndm_state = n->nud_state; | ||
1899 | if (n->nud_state & NUD_VALID) | ||
1900 | RTA_PUT(skb, NDA_LLADDR, n->dev->addr_len, n->ha); | ||
1901 | ci.ndm_used = now - n->used; | ||
1902 | ci.ndm_confirmed = now - n->confirmed; | ||
1903 | ci.ndm_updated = now - n->updated; | ||
1904 | ci.ndm_refcnt = atomic_read(&n->refcnt) - 1; | ||
1905 | probes = atomic_read(&n->probes); | ||
1906 | read_unlock_bh(&n->lock); | ||
1907 | locked = 0; | ||
1908 | RTA_PUT(skb, NDA_CACHEINFO, sizeof(ci), &ci); | ||
1909 | RTA_PUT(skb, NDA_PROBES, sizeof(probes), &probes); | ||
1910 | nlh->nlmsg_len = skb->tail - b; | ||
1911 | return skb->len; | ||
1912 | 1969 | ||
1913 | nlmsg_failure: | 1970 | read_lock_bh(&neigh->lock); |
1914 | rtattr_failure: | 1971 | ndm->ndm_state = neigh->nud_state; |
1915 | if (locked) | 1972 | if ((neigh->nud_state & NUD_VALID) && |
1916 | read_unlock_bh(&n->lock); | 1973 | nla_put(skb, NDA_LLADDR, neigh->dev->addr_len, neigh->ha) < 0) { |
1917 | skb_trim(skb, b - skb->data); | 1974 | read_unlock_bh(&neigh->lock); |
1918 | return -1; | 1975 | goto nla_put_failure; |
1976 | } | ||
1977 | |||
1978 | ci.ndm_used = now - neigh->used; | ||
1979 | ci.ndm_confirmed = now - neigh->confirmed; | ||
1980 | ci.ndm_updated = now - neigh->updated; | ||
1981 | ci.ndm_refcnt = atomic_read(&neigh->refcnt) - 1; | ||
1982 | read_unlock_bh(&neigh->lock); | ||
1983 | |||
1984 | NLA_PUT_U32(skb, NDA_PROBES, atomic_read(&neigh->probes)); | ||
1985 | NLA_PUT(skb, NDA_CACHEINFO, sizeof(ci), &ci); | ||
1986 | |||
1987 | return nlmsg_end(skb, nlh); | ||
1988 | |||
1989 | nla_put_failure: | ||
1990 | return nlmsg_cancel(skb, nlh); | ||
1919 | } | 1991 | } |
1920 | 1992 | ||
1921 | 1993 | ||
@@ -1959,7 +2031,7 @@ int neigh_dump_info(struct sk_buff *skb, struct netlink_callback *cb) | |||
1959 | int t, family, s_t; | 2031 | int t, family, s_t; |
1960 | 2032 | ||
1961 | read_lock(&neigh_tbl_lock); | 2033 | read_lock(&neigh_tbl_lock); |
1962 | family = ((struct rtgenmsg *)NLMSG_DATA(cb->nlh))->rtgen_family; | 2034 | family = ((struct rtgenmsg *) nlmsg_data(cb->nlh))->rtgen_family; |
1963 | s_t = cb->args[0]; | 2035 | s_t = cb->args[0]; |
1964 | 2036 | ||
1965 | for (tbl = neigh_tables, t = 0; tbl; tbl = tbl->next, t++) { | 2037 | for (tbl = neigh_tables, t = 0; tbl; tbl = tbl->next, t++) { |
@@ -2338,41 +2410,35 @@ static struct file_operations neigh_stat_seq_fops = { | |||
2338 | #endif /* CONFIG_PROC_FS */ | 2410 | #endif /* CONFIG_PROC_FS */ |
2339 | 2411 | ||
2340 | #ifdef CONFIG_ARPD | 2412 | #ifdef CONFIG_ARPD |
2341 | void neigh_app_ns(struct neighbour *n) | 2413 | static void __neigh_notify(struct neighbour *n, int type, int flags) |
2342 | { | 2414 | { |
2343 | struct nlmsghdr *nlh; | 2415 | struct sk_buff *skb; |
2344 | int size = NLMSG_SPACE(sizeof(struct ndmsg) + 256); | 2416 | int err = -ENOBUFS; |
2345 | struct sk_buff *skb = alloc_skb(size, GFP_ATOMIC); | ||
2346 | 2417 | ||
2347 | if (!skb) | 2418 | skb = nlmsg_new(NLMSG_GOODSIZE, GFP_ATOMIC); |
2348 | return; | 2419 | if (skb == NULL) |
2420 | goto errout; | ||
2349 | 2421 | ||
2350 | if (neigh_fill_info(skb, n, 0, 0, RTM_GETNEIGH, 0) < 0) { | 2422 | err = neigh_fill_info(skb, n, 0, 0, type, flags); |
2423 | if (err < 0) { | ||
2351 | kfree_skb(skb); | 2424 | kfree_skb(skb); |
2352 | return; | 2425 | goto errout; |
2353 | } | 2426 | } |
2354 | nlh = (struct nlmsghdr *)skb->data; | 2427 | |
2355 | nlh->nlmsg_flags = NLM_F_REQUEST; | 2428 | err = rtnl_notify(skb, 0, RTNLGRP_NEIGH, NULL, GFP_ATOMIC); |
2356 | NETLINK_CB(skb).dst_group = RTNLGRP_NEIGH; | 2429 | errout: |
2357 | netlink_broadcast(rtnl, skb, 0, RTNLGRP_NEIGH, GFP_ATOMIC); | 2430 | if (err < 0) |
2431 | rtnl_set_sk_err(RTNLGRP_NEIGH, err); | ||
2358 | } | 2432 | } |
2359 | 2433 | ||
2360 | static void neigh_app_notify(struct neighbour *n) | 2434 | void neigh_app_ns(struct neighbour *n) |
2361 | { | 2435 | { |
2362 | struct nlmsghdr *nlh; | 2436 | __neigh_notify(n, RTM_GETNEIGH, NLM_F_REQUEST); |
2363 | int size = NLMSG_SPACE(sizeof(struct ndmsg) + 256); | 2437 | } |
2364 | struct sk_buff *skb = alloc_skb(size, GFP_ATOMIC); | ||
2365 | |||
2366 | if (!skb) | ||
2367 | return; | ||
2368 | 2438 | ||
2369 | if (neigh_fill_info(skb, n, 0, 0, RTM_NEWNEIGH, 0) < 0) { | 2439 | static void neigh_app_notify(struct neighbour *n) |
2370 | kfree_skb(skb); | 2440 | { |
2371 | return; | 2441 | __neigh_notify(n, RTM_NEWNEIGH, 0); |
2372 | } | ||
2373 | nlh = (struct nlmsghdr *)skb->data; | ||
2374 | NETLINK_CB(skb).dst_group = RTNLGRP_NEIGH; | ||
2375 | netlink_broadcast(rtnl, skb, 0, RTNLGRP_NEIGH, GFP_ATOMIC); | ||
2376 | } | 2442 | } |
2377 | 2443 | ||
2378 | #endif /* CONFIG_ARPD */ | 2444 | #endif /* CONFIG_ARPD */ |
@@ -2386,7 +2452,7 @@ static struct neigh_sysctl_table { | |||
2386 | ctl_table neigh_neigh_dir[2]; | 2452 | ctl_table neigh_neigh_dir[2]; |
2387 | ctl_table neigh_proto_dir[2]; | 2453 | ctl_table neigh_proto_dir[2]; |
2388 | ctl_table neigh_root_dir[2]; | 2454 | ctl_table neigh_root_dir[2]; |
2389 | } neigh_sysctl_template = { | 2455 | } neigh_sysctl_template __read_mostly = { |
2390 | .neigh_vars = { | 2456 | .neigh_vars = { |
2391 | { | 2457 | { |
2392 | .ctl_name = NET_NEIGH_MCAST_SOLICIT, | 2458 | .ctl_name = NET_NEIGH_MCAST_SOLICIT, |
@@ -2659,7 +2725,6 @@ void neigh_sysctl_unregister(struct neigh_parms *p) | |||
2659 | #endif /* CONFIG_SYSCTL */ | 2725 | #endif /* CONFIG_SYSCTL */ |
2660 | 2726 | ||
2661 | EXPORT_SYMBOL(__neigh_event_send); | 2727 | EXPORT_SYMBOL(__neigh_event_send); |
2662 | EXPORT_SYMBOL(neigh_add); | ||
2663 | EXPORT_SYMBOL(neigh_changeaddr); | 2728 | EXPORT_SYMBOL(neigh_changeaddr); |
2664 | EXPORT_SYMBOL(neigh_compat_output); | 2729 | EXPORT_SYMBOL(neigh_compat_output); |
2665 | EXPORT_SYMBOL(neigh_connected_output); | 2730 | EXPORT_SYMBOL(neigh_connected_output); |
@@ -2679,11 +2744,8 @@ EXPORT_SYMBOL(neigh_table_clear); | |||
2679 | EXPORT_SYMBOL(neigh_table_init); | 2744 | EXPORT_SYMBOL(neigh_table_init); |
2680 | EXPORT_SYMBOL(neigh_table_init_no_netlink); | 2745 | EXPORT_SYMBOL(neigh_table_init_no_netlink); |
2681 | EXPORT_SYMBOL(neigh_update); | 2746 | EXPORT_SYMBOL(neigh_update); |
2682 | EXPORT_SYMBOL(neigh_update_hhs); | ||
2683 | EXPORT_SYMBOL(pneigh_enqueue); | 2747 | EXPORT_SYMBOL(pneigh_enqueue); |
2684 | EXPORT_SYMBOL(pneigh_lookup); | 2748 | EXPORT_SYMBOL(pneigh_lookup); |
2685 | EXPORT_SYMBOL(neightbl_dump_info); | ||
2686 | EXPORT_SYMBOL(neightbl_set); | ||
2687 | 2749 | ||
2688 | #ifdef CONFIG_ARPD | 2750 | #ifdef CONFIG_ARPD |
2689 | EXPORT_SYMBOL(neigh_app_ns); | 2751 | EXPORT_SYMBOL(neigh_app_ns); |
diff --git a/net/core/netpoll.c b/net/core/netpoll.c index 471da451cd48..ead5920c26d6 100644 --- a/net/core/netpoll.c +++ b/net/core/netpoll.c | |||
@@ -110,7 +110,7 @@ static int checksum_udp(struct sk_buff *skb, struct udphdr *uh, | |||
110 | 110 | ||
111 | psum = csum_tcpudp_nofold(saddr, daddr, ulen, IPPROTO_UDP, 0); | 111 | psum = csum_tcpudp_nofold(saddr, daddr, ulen, IPPROTO_UDP, 0); |
112 | 112 | ||
113 | if (skb->ip_summed == CHECKSUM_HW && | 113 | if (skb->ip_summed == CHECKSUM_COMPLETE && |
114 | !(u16)csum_fold(csum_add(psum, skb->csum))) | 114 | !(u16)csum_fold(csum_add(psum, skb->csum))) |
115 | return 0; | 115 | return 0; |
116 | 116 | ||
diff --git a/net/core/pktgen.c b/net/core/pktgen.c index 6a7320b39ed0..72145d4a2600 100644 --- a/net/core/pktgen.c +++ b/net/core/pktgen.c | |||
@@ -1786,7 +1786,7 @@ static void pktgen_setup_inject(struct pktgen_dev *pkt_dev) | |||
1786 | * use ipv6_get_lladdr if/when it's get exported | 1786 | * use ipv6_get_lladdr if/when it's get exported |
1787 | */ | 1787 | */ |
1788 | 1788 | ||
1789 | read_lock(&addrconf_lock); | 1789 | rcu_read_lock(); |
1790 | if ((idev = __in6_dev_get(pkt_dev->odev)) != NULL) { | 1790 | if ((idev = __in6_dev_get(pkt_dev->odev)) != NULL) { |
1791 | struct inet6_ifaddr *ifp; | 1791 | struct inet6_ifaddr *ifp; |
1792 | 1792 | ||
@@ -1805,7 +1805,7 @@ static void pktgen_setup_inject(struct pktgen_dev *pkt_dev) | |||
1805 | } | 1805 | } |
1806 | read_unlock_bh(&idev->lock); | 1806 | read_unlock_bh(&idev->lock); |
1807 | } | 1807 | } |
1808 | read_unlock(&addrconf_lock); | 1808 | rcu_read_unlock(); |
1809 | if (err) | 1809 | if (err) |
1810 | printk("pktgen: ERROR: IPv6 link address not availble.\n"); | 1810 | printk("pktgen: ERROR: IPv6 link address not availble.\n"); |
1811 | } | 1811 | } |
diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c index 30cc1ba6ed5c..d8e25e08cb7e 100644 --- a/net/core/rtnetlink.c +++ b/net/core/rtnetlink.c | |||
@@ -35,6 +35,7 @@ | |||
35 | #include <linux/init.h> | 35 | #include <linux/init.h> |
36 | #include <linux/security.h> | 36 | #include <linux/security.h> |
37 | #include <linux/mutex.h> | 37 | #include <linux/mutex.h> |
38 | #include <linux/if_addr.h> | ||
38 | 39 | ||
39 | #include <asm/uaccess.h> | 40 | #include <asm/uaccess.h> |
40 | #include <asm/system.h> | 41 | #include <asm/system.h> |
@@ -49,6 +50,7 @@ | |||
49 | #include <net/udp.h> | 50 | #include <net/udp.h> |
50 | #include <net/sock.h> | 51 | #include <net/sock.h> |
51 | #include <net/pkt_sched.h> | 52 | #include <net/pkt_sched.h> |
53 | #include <net/fib_rules.h> | ||
52 | #include <net/netlink.h> | 54 | #include <net/netlink.h> |
53 | #ifdef CONFIG_NET_WIRELESS_RTNETLINK | 55 | #ifdef CONFIG_NET_WIRELESS_RTNETLINK |
54 | #include <linux/wireless.h> | 56 | #include <linux/wireless.h> |
@@ -56,6 +58,7 @@ | |||
56 | #endif /* CONFIG_NET_WIRELESS_RTNETLINK */ | 58 | #endif /* CONFIG_NET_WIRELESS_RTNETLINK */ |
57 | 59 | ||
58 | static DEFINE_MUTEX(rtnl_mutex); | 60 | static DEFINE_MUTEX(rtnl_mutex); |
61 | static struct sock *rtnl; | ||
59 | 62 | ||
60 | void rtnl_lock(void) | 63 | void rtnl_lock(void) |
61 | { | 64 | { |
@@ -93,8 +96,6 @@ int rtattr_parse(struct rtattr *tb[], int maxattr, struct rtattr *rta, int len) | |||
93 | return 0; | 96 | return 0; |
94 | } | 97 | } |
95 | 98 | ||
96 | struct sock *rtnl; | ||
97 | |||
98 | struct rtnetlink_link * rtnetlink_links[NPROTO]; | 99 | struct rtnetlink_link * rtnetlink_links[NPROTO]; |
99 | 100 | ||
100 | static const int rtm_min[RTM_NR_FAMILIES] = | 101 | static const int rtm_min[RTM_NR_FAMILIES] = |
@@ -102,8 +103,7 @@ static const int rtm_min[RTM_NR_FAMILIES] = | |||
102 | [RTM_FAM(RTM_NEWLINK)] = NLMSG_LENGTH(sizeof(struct ifinfomsg)), | 103 | [RTM_FAM(RTM_NEWLINK)] = NLMSG_LENGTH(sizeof(struct ifinfomsg)), |
103 | [RTM_FAM(RTM_NEWADDR)] = NLMSG_LENGTH(sizeof(struct ifaddrmsg)), | 104 | [RTM_FAM(RTM_NEWADDR)] = NLMSG_LENGTH(sizeof(struct ifaddrmsg)), |
104 | [RTM_FAM(RTM_NEWROUTE)] = NLMSG_LENGTH(sizeof(struct rtmsg)), | 105 | [RTM_FAM(RTM_NEWROUTE)] = NLMSG_LENGTH(sizeof(struct rtmsg)), |
105 | [RTM_FAM(RTM_NEWNEIGH)] = NLMSG_LENGTH(sizeof(struct ndmsg)), | 106 | [RTM_FAM(RTM_NEWRULE)] = NLMSG_LENGTH(sizeof(struct fib_rule_hdr)), |
106 | [RTM_FAM(RTM_NEWRULE)] = NLMSG_LENGTH(sizeof(struct rtmsg)), | ||
107 | [RTM_FAM(RTM_NEWQDISC)] = NLMSG_LENGTH(sizeof(struct tcmsg)), | 107 | [RTM_FAM(RTM_NEWQDISC)] = NLMSG_LENGTH(sizeof(struct tcmsg)), |
108 | [RTM_FAM(RTM_NEWTCLASS)] = NLMSG_LENGTH(sizeof(struct tcmsg)), | 108 | [RTM_FAM(RTM_NEWTCLASS)] = NLMSG_LENGTH(sizeof(struct tcmsg)), |
109 | [RTM_FAM(RTM_NEWTFILTER)] = NLMSG_LENGTH(sizeof(struct tcmsg)), | 109 | [RTM_FAM(RTM_NEWTFILTER)] = NLMSG_LENGTH(sizeof(struct tcmsg)), |
@@ -111,7 +111,6 @@ static const int rtm_min[RTM_NR_FAMILIES] = | |||
111 | [RTM_FAM(RTM_NEWPREFIX)] = NLMSG_LENGTH(sizeof(struct rtgenmsg)), | 111 | [RTM_FAM(RTM_NEWPREFIX)] = NLMSG_LENGTH(sizeof(struct rtgenmsg)), |
112 | [RTM_FAM(RTM_GETMULTICAST)] = NLMSG_LENGTH(sizeof(struct rtgenmsg)), | 112 | [RTM_FAM(RTM_GETMULTICAST)] = NLMSG_LENGTH(sizeof(struct rtgenmsg)), |
113 | [RTM_FAM(RTM_GETANYCAST)] = NLMSG_LENGTH(sizeof(struct rtgenmsg)), | 113 | [RTM_FAM(RTM_GETANYCAST)] = NLMSG_LENGTH(sizeof(struct rtgenmsg)), |
114 | [RTM_FAM(RTM_NEWNEIGHTBL)] = NLMSG_LENGTH(sizeof(struct ndtmsg)), | ||
115 | }; | 114 | }; |
116 | 115 | ||
117 | static const int rta_max[RTM_NR_FAMILIES] = | 116 | static const int rta_max[RTM_NR_FAMILIES] = |
@@ -119,13 +118,11 @@ static const int rta_max[RTM_NR_FAMILIES] = | |||
119 | [RTM_FAM(RTM_NEWLINK)] = IFLA_MAX, | 118 | [RTM_FAM(RTM_NEWLINK)] = IFLA_MAX, |
120 | [RTM_FAM(RTM_NEWADDR)] = IFA_MAX, | 119 | [RTM_FAM(RTM_NEWADDR)] = IFA_MAX, |
121 | [RTM_FAM(RTM_NEWROUTE)] = RTA_MAX, | 120 | [RTM_FAM(RTM_NEWROUTE)] = RTA_MAX, |
122 | [RTM_FAM(RTM_NEWNEIGH)] = NDA_MAX, | 121 | [RTM_FAM(RTM_NEWRULE)] = FRA_MAX, |
123 | [RTM_FAM(RTM_NEWRULE)] = RTA_MAX, | ||
124 | [RTM_FAM(RTM_NEWQDISC)] = TCA_MAX, | 122 | [RTM_FAM(RTM_NEWQDISC)] = TCA_MAX, |
125 | [RTM_FAM(RTM_NEWTCLASS)] = TCA_MAX, | 123 | [RTM_FAM(RTM_NEWTCLASS)] = TCA_MAX, |
126 | [RTM_FAM(RTM_NEWTFILTER)] = TCA_MAX, | 124 | [RTM_FAM(RTM_NEWTFILTER)] = TCA_MAX, |
127 | [RTM_FAM(RTM_NEWACTION)] = TCAA_MAX, | 125 | [RTM_FAM(RTM_NEWACTION)] = TCAA_MAX, |
128 | [RTM_FAM(RTM_NEWNEIGHTBL)] = NDTA_MAX, | ||
129 | }; | 126 | }; |
130 | 127 | ||
131 | void __rta_fill(struct sk_buff *skb, int attrtype, int attrlen, const void *data) | 128 | void __rta_fill(struct sk_buff *skb, int attrtype, int attrlen, const void *data) |
@@ -168,24 +165,52 @@ int rtnetlink_send(struct sk_buff *skb, u32 pid, unsigned group, int echo) | |||
168 | return err; | 165 | return err; |
169 | } | 166 | } |
170 | 167 | ||
168 | int rtnl_unicast(struct sk_buff *skb, u32 pid) | ||
169 | { | ||
170 | return nlmsg_unicast(rtnl, skb, pid); | ||
171 | } | ||
172 | |||
173 | int rtnl_notify(struct sk_buff *skb, u32 pid, u32 group, | ||
174 | struct nlmsghdr *nlh, gfp_t flags) | ||
175 | { | ||
176 | int report = 0; | ||
177 | |||
178 | if (nlh) | ||
179 | report = nlmsg_report(nlh); | ||
180 | |||
181 | return nlmsg_notify(rtnl, skb, pid, group, report, flags); | ||
182 | } | ||
183 | |||
184 | void rtnl_set_sk_err(u32 group, int error) | ||
185 | { | ||
186 | netlink_set_err(rtnl, 0, group, error); | ||
187 | } | ||
188 | |||
171 | int rtnetlink_put_metrics(struct sk_buff *skb, u32 *metrics) | 189 | int rtnetlink_put_metrics(struct sk_buff *skb, u32 *metrics) |
172 | { | 190 | { |
173 | struct rtattr *mx = (struct rtattr*)skb->tail; | 191 | struct nlattr *mx; |
174 | int i; | 192 | int i, valid = 0; |
193 | |||
194 | mx = nla_nest_start(skb, RTA_METRICS); | ||
195 | if (mx == NULL) | ||
196 | return -ENOBUFS; | ||
197 | |||
198 | for (i = 0; i < RTAX_MAX; i++) { | ||
199 | if (metrics[i]) { | ||
200 | valid++; | ||
201 | NLA_PUT_U32(skb, i+1, metrics[i]); | ||
202 | } | ||
203 | } | ||
175 | 204 | ||
176 | RTA_PUT(skb, RTA_METRICS, 0, NULL); | 205 | if (!valid) { |
177 | for (i=0; i<RTAX_MAX; i++) { | 206 | nla_nest_cancel(skb, mx); |
178 | if (metrics[i]) | 207 | return 0; |
179 | RTA_PUT(skb, i+1, sizeof(u32), metrics+i); | ||
180 | } | 208 | } |
181 | mx->rta_len = skb->tail - (u8*)mx; | ||
182 | if (mx->rta_len == RTA_LENGTH(0)) | ||
183 | skb_trim(skb, (u8*)mx - skb->data); | ||
184 | return 0; | ||
185 | 209 | ||
186 | rtattr_failure: | 210 | return nla_nest_end(skb, mx); |
187 | skb_trim(skb, (u8*)mx - skb->data); | 211 | |
188 | return -1; | 212 | nla_put_failure: |
213 | return nla_nest_cancel(skb, mx); | ||
189 | } | 214 | } |
190 | 215 | ||
191 | 216 | ||
@@ -216,41 +241,73 @@ static void set_operstate(struct net_device *dev, unsigned char transition) | |||
216 | } | 241 | } |
217 | } | 242 | } |
218 | 243 | ||
219 | static int rtnetlink_fill_ifinfo(struct sk_buff *skb, struct net_device *dev, | 244 | static void copy_rtnl_link_stats(struct rtnl_link_stats *a, |
220 | int type, u32 pid, u32 seq, u32 change, | 245 | struct net_device_stats *b) |
221 | unsigned int flags) | ||
222 | { | 246 | { |
223 | struct ifinfomsg *r; | 247 | a->rx_packets = b->rx_packets; |
224 | struct nlmsghdr *nlh; | 248 | a->tx_packets = b->tx_packets; |
225 | unsigned char *b = skb->tail; | 249 | a->rx_bytes = b->rx_bytes; |
226 | 250 | a->tx_bytes = b->tx_bytes; | |
227 | nlh = NLMSG_NEW(skb, pid, seq, type, sizeof(*r), flags); | 251 | a->rx_errors = b->rx_errors; |
228 | r = NLMSG_DATA(nlh); | 252 | a->tx_errors = b->tx_errors; |
229 | r->ifi_family = AF_UNSPEC; | 253 | a->rx_dropped = b->rx_dropped; |
230 | r->__ifi_pad = 0; | 254 | a->tx_dropped = b->tx_dropped; |
231 | r->ifi_type = dev->type; | 255 | |
232 | r->ifi_index = dev->ifindex; | 256 | a->multicast = b->multicast; |
233 | r->ifi_flags = dev_get_flags(dev); | 257 | a->collisions = b->collisions; |
234 | r->ifi_change = change; | 258 | |
235 | 259 | a->rx_length_errors = b->rx_length_errors; | |
236 | RTA_PUT(skb, IFLA_IFNAME, strlen(dev->name)+1, dev->name); | 260 | a->rx_over_errors = b->rx_over_errors; |
237 | 261 | a->rx_crc_errors = b->rx_crc_errors; | |
238 | if (1) { | 262 | a->rx_frame_errors = b->rx_frame_errors; |
239 | u32 txqlen = dev->tx_queue_len; | 263 | a->rx_fifo_errors = b->rx_fifo_errors; |
240 | RTA_PUT(skb, IFLA_TXQLEN, sizeof(txqlen), &txqlen); | 264 | a->rx_missed_errors = b->rx_missed_errors; |
241 | } | 265 | |
266 | a->tx_aborted_errors = b->tx_aborted_errors; | ||
267 | a->tx_carrier_errors = b->tx_carrier_errors; | ||
268 | a->tx_fifo_errors = b->tx_fifo_errors; | ||
269 | a->tx_heartbeat_errors = b->tx_heartbeat_errors; | ||
270 | a->tx_window_errors = b->tx_window_errors; | ||
271 | |||
272 | a->rx_compressed = b->rx_compressed; | ||
273 | a->tx_compressed = b->tx_compressed; | ||
274 | }; | ||
242 | 275 | ||
243 | if (1) { | 276 | static int rtnl_fill_ifinfo(struct sk_buff *skb, struct net_device *dev, |
244 | u32 weight = dev->weight; | 277 | void *iwbuf, int iwbuflen, int type, u32 pid, |
245 | RTA_PUT(skb, IFLA_WEIGHT, sizeof(weight), &weight); | 278 | u32 seq, u32 change, unsigned int flags) |
246 | } | 279 | { |
280 | struct ifinfomsg *ifm; | ||
281 | struct nlmsghdr *nlh; | ||
282 | |||
283 | nlh = nlmsg_put(skb, pid, seq, type, sizeof(*ifm), flags); | ||
284 | if (nlh == NULL) | ||
285 | return -ENOBUFS; | ||
286 | |||
287 | ifm = nlmsg_data(nlh); | ||
288 | ifm->ifi_family = AF_UNSPEC; | ||
289 | ifm->__ifi_pad = 0; | ||
290 | ifm->ifi_type = dev->type; | ||
291 | ifm->ifi_index = dev->ifindex; | ||
292 | ifm->ifi_flags = dev_get_flags(dev); | ||
293 | ifm->ifi_change = change; | ||
294 | |||
295 | NLA_PUT_STRING(skb, IFLA_IFNAME, dev->name); | ||
296 | NLA_PUT_U32(skb, IFLA_TXQLEN, dev->tx_queue_len); | ||
297 | NLA_PUT_U32(skb, IFLA_WEIGHT, dev->weight); | ||
298 | NLA_PUT_U8(skb, IFLA_OPERSTATE, | ||
299 | netif_running(dev) ? dev->operstate : IF_OPER_DOWN); | ||
300 | NLA_PUT_U8(skb, IFLA_LINKMODE, dev->link_mode); | ||
301 | NLA_PUT_U32(skb, IFLA_MTU, dev->mtu); | ||
302 | |||
303 | if (dev->ifindex != dev->iflink) | ||
304 | NLA_PUT_U32(skb, IFLA_LINK, dev->iflink); | ||
305 | |||
306 | if (dev->master) | ||
307 | NLA_PUT_U32(skb, IFLA_MASTER, dev->master->ifindex); | ||
247 | 308 | ||
248 | if (1) { | 309 | if (dev->qdisc_sleeping) |
249 | u8 operstate = netif_running(dev)?dev->operstate:IF_OPER_DOWN; | 310 | NLA_PUT_STRING(skb, IFLA_QDISC, dev->qdisc_sleeping->ops->id); |
250 | u8 link_mode = dev->link_mode; | ||
251 | RTA_PUT(skb, IFLA_OPERSTATE, sizeof(operstate), &operstate); | ||
252 | RTA_PUT(skb, IFLA_LINKMODE, sizeof(link_mode), &link_mode); | ||
253 | } | ||
254 | 311 | ||
255 | if (1) { | 312 | if (1) { |
256 | struct rtnl_link_ifmap map = { | 313 | struct rtnl_link_ifmap map = { |
@@ -261,58 +318,38 @@ static int rtnetlink_fill_ifinfo(struct sk_buff *skb, struct net_device *dev, | |||
261 | .dma = dev->dma, | 318 | .dma = dev->dma, |
262 | .port = dev->if_port, | 319 | .port = dev->if_port, |
263 | }; | 320 | }; |
264 | RTA_PUT(skb, IFLA_MAP, sizeof(map), &map); | 321 | NLA_PUT(skb, IFLA_MAP, sizeof(map), &map); |
265 | } | 322 | } |
266 | 323 | ||
267 | if (dev->addr_len) { | 324 | if (dev->addr_len) { |
268 | RTA_PUT(skb, IFLA_ADDRESS, dev->addr_len, dev->dev_addr); | 325 | NLA_PUT(skb, IFLA_ADDRESS, dev->addr_len, dev->dev_addr); |
269 | RTA_PUT(skb, IFLA_BROADCAST, dev->addr_len, dev->broadcast); | 326 | NLA_PUT(skb, IFLA_BROADCAST, dev->addr_len, dev->broadcast); |
270 | } | ||
271 | |||
272 | if (1) { | ||
273 | u32 mtu = dev->mtu; | ||
274 | RTA_PUT(skb, IFLA_MTU, sizeof(mtu), &mtu); | ||
275 | } | ||
276 | |||
277 | if (dev->ifindex != dev->iflink) { | ||
278 | u32 iflink = dev->iflink; | ||
279 | RTA_PUT(skb, IFLA_LINK, sizeof(iflink), &iflink); | ||
280 | } | ||
281 | |||
282 | if (dev->qdisc_sleeping) | ||
283 | RTA_PUT(skb, IFLA_QDISC, | ||
284 | strlen(dev->qdisc_sleeping->ops->id) + 1, | ||
285 | dev->qdisc_sleeping->ops->id); | ||
286 | |||
287 | if (dev->master) { | ||
288 | u32 master = dev->master->ifindex; | ||
289 | RTA_PUT(skb, IFLA_MASTER, sizeof(master), &master); | ||
290 | } | 327 | } |
291 | 328 | ||
292 | if (dev->get_stats) { | 329 | if (dev->get_stats) { |
293 | unsigned long *stats = (unsigned long*)dev->get_stats(dev); | 330 | struct net_device_stats *stats = dev->get_stats(dev); |
294 | if (stats) { | 331 | if (stats) { |
295 | struct rtattr *a; | 332 | struct nlattr *attr; |
296 | __u32 *s; | 333 | |
297 | int i; | 334 | attr = nla_reserve(skb, IFLA_STATS, |
298 | int n = sizeof(struct rtnl_link_stats)/4; | 335 | sizeof(struct rtnl_link_stats)); |
299 | 336 | if (attr == NULL) | |
300 | a = __RTA_PUT(skb, IFLA_STATS, n*4); | 337 | goto nla_put_failure; |
301 | s = RTA_DATA(a); | 338 | |
302 | for (i=0; i<n; i++) | 339 | copy_rtnl_link_stats(nla_data(attr), stats); |
303 | s[i] = stats[i]; | ||
304 | } | 340 | } |
305 | } | 341 | } |
306 | nlh->nlmsg_len = skb->tail - b; | ||
307 | return skb->len; | ||
308 | 342 | ||
309 | nlmsg_failure: | 343 | if (iwbuf) |
310 | rtattr_failure: | 344 | NLA_PUT(skb, IFLA_WIRELESS, iwbuflen, iwbuf); |
311 | skb_trim(skb, b - skb->data); | 345 | |
312 | return -1; | 346 | return nlmsg_end(skb, nlh); |
347 | |||
348 | nla_put_failure: | ||
349 | return nlmsg_cancel(skb, nlh); | ||
313 | } | 350 | } |
314 | 351 | ||
315 | static int rtnetlink_dump_ifinfo(struct sk_buff *skb, struct netlink_callback *cb) | 352 | static int rtnl_dump_ifinfo(struct sk_buff *skb, struct netlink_callback *cb) |
316 | { | 353 | { |
317 | int idx; | 354 | int idx; |
318 | int s_idx = cb->args[0]; | 355 | int s_idx = cb->args[0]; |
@@ -322,10 +359,9 @@ static int rtnetlink_dump_ifinfo(struct sk_buff *skb, struct netlink_callback *c | |||
322 | for (dev=dev_base, idx=0; dev; dev = dev->next, idx++) { | 359 | for (dev=dev_base, idx=0; dev; dev = dev->next, idx++) { |
323 | if (idx < s_idx) | 360 | if (idx < s_idx) |
324 | continue; | 361 | continue; |
325 | if (rtnetlink_fill_ifinfo(skb, dev, RTM_NEWLINK, | 362 | if (rtnl_fill_ifinfo(skb, dev, NULL, 0, RTM_NEWLINK, |
326 | NETLINK_CB(cb->skb).pid, | 363 | NETLINK_CB(cb->skb).pid, |
327 | cb->nlh->nlmsg_seq, 0, | 364 | cb->nlh->nlmsg_seq, 0, NLM_F_MULTI) <= 0) |
328 | NLM_F_MULTI) <= 0) | ||
329 | break; | 365 | break; |
330 | } | 366 | } |
331 | read_unlock(&dev_base_lock); | 367 | read_unlock(&dev_base_lock); |
@@ -334,52 +370,70 @@ static int rtnetlink_dump_ifinfo(struct sk_buff *skb, struct netlink_callback *c | |||
334 | return skb->len; | 370 | return skb->len; |
335 | } | 371 | } |
336 | 372 | ||
337 | static int do_setlink(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) | 373 | static struct nla_policy ifla_policy[IFLA_MAX+1] __read_mostly = { |
374 | [IFLA_IFNAME] = { .type = NLA_STRING, .len = IFNAMSIZ-1 }, | ||
375 | [IFLA_MAP] = { .len = sizeof(struct rtnl_link_ifmap) }, | ||
376 | [IFLA_MTU] = { .type = NLA_U32 }, | ||
377 | [IFLA_TXQLEN] = { .type = NLA_U32 }, | ||
378 | [IFLA_WEIGHT] = { .type = NLA_U32 }, | ||
379 | [IFLA_OPERSTATE] = { .type = NLA_U8 }, | ||
380 | [IFLA_LINKMODE] = { .type = NLA_U8 }, | ||
381 | }; | ||
382 | |||
383 | static int rtnl_setlink(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) | ||
338 | { | 384 | { |
339 | struct ifinfomsg *ifm = NLMSG_DATA(nlh); | 385 | struct ifinfomsg *ifm; |
340 | struct rtattr **ida = arg; | ||
341 | struct net_device *dev; | 386 | struct net_device *dev; |
342 | int err, send_addr_notify = 0; | 387 | int err, send_addr_notify = 0, modified = 0; |
388 | struct nlattr *tb[IFLA_MAX+1]; | ||
389 | char ifname[IFNAMSIZ]; | ||
390 | |||
391 | err = nlmsg_parse(nlh, sizeof(*ifm), tb, IFLA_MAX, ifla_policy); | ||
392 | if (err < 0) | ||
393 | goto errout; | ||
394 | |||
395 | if (tb[IFLA_IFNAME]) | ||
396 | nla_strlcpy(ifname, tb[IFLA_IFNAME], IFNAMSIZ); | ||
397 | else | ||
398 | ifname[0] = '\0'; | ||
343 | 399 | ||
400 | err = -EINVAL; | ||
401 | ifm = nlmsg_data(nlh); | ||
344 | if (ifm->ifi_index >= 0) | 402 | if (ifm->ifi_index >= 0) |
345 | dev = dev_get_by_index(ifm->ifi_index); | 403 | dev = dev_get_by_index(ifm->ifi_index); |
346 | else if (ida[IFLA_IFNAME - 1]) { | 404 | else if (tb[IFLA_IFNAME]) |
347 | char ifname[IFNAMSIZ]; | ||
348 | |||
349 | if (rtattr_strlcpy(ifname, ida[IFLA_IFNAME - 1], | ||
350 | IFNAMSIZ) >= IFNAMSIZ) | ||
351 | return -EINVAL; | ||
352 | dev = dev_get_by_name(ifname); | 405 | dev = dev_get_by_name(ifname); |
353 | } else | 406 | else |
354 | return -EINVAL; | 407 | goto errout; |
355 | 408 | ||
356 | if (!dev) | 409 | if (dev == NULL) { |
357 | return -ENODEV; | 410 | err = -ENODEV; |
411 | goto errout; | ||
412 | } | ||
358 | 413 | ||
359 | err = -EINVAL; | 414 | if (tb[IFLA_ADDRESS] && |
415 | nla_len(tb[IFLA_ADDRESS]) < dev->addr_len) | ||
416 | goto errout_dev; | ||
360 | 417 | ||
361 | if (ifm->ifi_flags) | 418 | if (tb[IFLA_BROADCAST] && |
362 | dev_change_flags(dev, ifm->ifi_flags); | 419 | nla_len(tb[IFLA_BROADCAST]) < dev->addr_len) |
420 | goto errout_dev; | ||
363 | 421 | ||
364 | if (ida[IFLA_MAP - 1]) { | 422 | if (tb[IFLA_MAP]) { |
365 | struct rtnl_link_ifmap *u_map; | 423 | struct rtnl_link_ifmap *u_map; |
366 | struct ifmap k_map; | 424 | struct ifmap k_map; |
367 | 425 | ||
368 | if (!dev->set_config) { | 426 | if (!dev->set_config) { |
369 | err = -EOPNOTSUPP; | 427 | err = -EOPNOTSUPP; |
370 | goto out; | 428 | goto errout_dev; |
371 | } | 429 | } |
372 | 430 | ||
373 | if (!netif_device_present(dev)) { | 431 | if (!netif_device_present(dev)) { |
374 | err = -ENODEV; | 432 | err = -ENODEV; |
375 | goto out; | 433 | goto errout_dev; |
376 | } | 434 | } |
377 | |||
378 | if (ida[IFLA_MAP - 1]->rta_len != RTA_LENGTH(sizeof(*u_map))) | ||
379 | goto out; | ||
380 | |||
381 | u_map = RTA_DATA(ida[IFLA_MAP - 1]); | ||
382 | 435 | ||
436 | u_map = nla_data(tb[IFLA_MAP]); | ||
383 | k_map.mem_start = (unsigned long) u_map->mem_start; | 437 | k_map.mem_start = (unsigned long) u_map->mem_start; |
384 | k_map.mem_end = (unsigned long) u_map->mem_end; | 438 | k_map.mem_end = (unsigned long) u_map->mem_end; |
385 | k_map.base_addr = (unsigned short) u_map->base_addr; | 439 | k_map.base_addr = (unsigned short) u_map->base_addr; |
@@ -388,200 +442,175 @@ static int do_setlink(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) | |||
388 | k_map.port = (unsigned char) u_map->port; | 442 | k_map.port = (unsigned char) u_map->port; |
389 | 443 | ||
390 | err = dev->set_config(dev, &k_map); | 444 | err = dev->set_config(dev, &k_map); |
445 | if (err < 0) | ||
446 | goto errout_dev; | ||
391 | 447 | ||
392 | if (err) | 448 | modified = 1; |
393 | goto out; | ||
394 | } | 449 | } |
395 | 450 | ||
396 | if (ida[IFLA_ADDRESS - 1]) { | 451 | if (tb[IFLA_ADDRESS]) { |
397 | struct sockaddr *sa; | 452 | struct sockaddr *sa; |
398 | int len; | 453 | int len; |
399 | 454 | ||
400 | if (!dev->set_mac_address) { | 455 | if (!dev->set_mac_address) { |
401 | err = -EOPNOTSUPP; | 456 | err = -EOPNOTSUPP; |
402 | goto out; | 457 | goto errout_dev; |
403 | } | 458 | } |
459 | |||
404 | if (!netif_device_present(dev)) { | 460 | if (!netif_device_present(dev)) { |
405 | err = -ENODEV; | 461 | err = -ENODEV; |
406 | goto out; | 462 | goto errout_dev; |
407 | } | 463 | } |
408 | if (ida[IFLA_ADDRESS - 1]->rta_len != RTA_LENGTH(dev->addr_len)) | ||
409 | goto out; | ||
410 | 464 | ||
411 | len = sizeof(sa_family_t) + dev->addr_len; | 465 | len = sizeof(sa_family_t) + dev->addr_len; |
412 | sa = kmalloc(len, GFP_KERNEL); | 466 | sa = kmalloc(len, GFP_KERNEL); |
413 | if (!sa) { | 467 | if (!sa) { |
414 | err = -ENOMEM; | 468 | err = -ENOMEM; |
415 | goto out; | 469 | goto errout_dev; |
416 | } | 470 | } |
417 | sa->sa_family = dev->type; | 471 | sa->sa_family = dev->type; |
418 | memcpy(sa->sa_data, RTA_DATA(ida[IFLA_ADDRESS - 1]), | 472 | memcpy(sa->sa_data, nla_data(tb[IFLA_ADDRESS]), |
419 | dev->addr_len); | 473 | dev->addr_len); |
420 | err = dev->set_mac_address(dev, sa); | 474 | err = dev->set_mac_address(dev, sa); |
421 | kfree(sa); | 475 | kfree(sa); |
422 | if (err) | 476 | if (err) |
423 | goto out; | 477 | goto errout_dev; |
424 | send_addr_notify = 1; | 478 | send_addr_notify = 1; |
479 | modified = 1; | ||
425 | } | 480 | } |
426 | 481 | ||
427 | if (ida[IFLA_BROADCAST - 1]) { | 482 | if (tb[IFLA_MTU]) { |
428 | if (ida[IFLA_BROADCAST - 1]->rta_len != RTA_LENGTH(dev->addr_len)) | 483 | err = dev_set_mtu(dev, nla_get_u32(tb[IFLA_MTU])); |
429 | goto out; | 484 | if (err < 0) |
430 | memcpy(dev->broadcast, RTA_DATA(ida[IFLA_BROADCAST - 1]), | 485 | goto errout_dev; |
431 | dev->addr_len); | 486 | modified = 1; |
432 | send_addr_notify = 1; | ||
433 | } | 487 | } |
434 | 488 | ||
435 | if (ida[IFLA_MTU - 1]) { | 489 | /* |
436 | if (ida[IFLA_MTU - 1]->rta_len != RTA_LENGTH(sizeof(u32))) | 490 | * Interface selected by interface index but interface |
437 | goto out; | 491 | * name provided implies that a name change has been |
438 | err = dev_set_mtu(dev, *((u32 *) RTA_DATA(ida[IFLA_MTU - 1]))); | 492 | * requested. |
439 | 493 | */ | |
440 | if (err) | 494 | if (ifm->ifi_index >= 0 && ifname[0]) { |
441 | goto out; | 495 | err = dev_change_name(dev, ifname); |
442 | 496 | if (err < 0) | |
497 | goto errout_dev; | ||
498 | modified = 1; | ||
443 | } | 499 | } |
444 | 500 | ||
445 | if (ida[IFLA_TXQLEN - 1]) { | 501 | #ifdef CONFIG_NET_WIRELESS_RTNETLINK |
446 | if (ida[IFLA_TXQLEN - 1]->rta_len != RTA_LENGTH(sizeof(u32))) | 502 | if (tb[IFLA_WIRELESS]) { |
447 | goto out; | 503 | /* Call Wireless Extensions. |
504 | * Various stuff checked in there... */ | ||
505 | err = wireless_rtnetlink_set(dev, nla_data(tb[IFLA_WIRELESS]), | ||
506 | nla_len(tb[IFLA_WIRELESS])); | ||
507 | if (err < 0) | ||
508 | goto errout_dev; | ||
509 | } | ||
510 | #endif /* CONFIG_NET_WIRELESS_RTNETLINK */ | ||
448 | 511 | ||
449 | dev->tx_queue_len = *((u32 *) RTA_DATA(ida[IFLA_TXQLEN - 1])); | 512 | if (tb[IFLA_BROADCAST]) { |
513 | nla_memcpy(dev->broadcast, tb[IFLA_BROADCAST], dev->addr_len); | ||
514 | send_addr_notify = 1; | ||
450 | } | 515 | } |
451 | 516 | ||
452 | if (ida[IFLA_WEIGHT - 1]) { | ||
453 | if (ida[IFLA_WEIGHT - 1]->rta_len != RTA_LENGTH(sizeof(u32))) | ||
454 | goto out; | ||
455 | 517 | ||
456 | dev->weight = *((u32 *) RTA_DATA(ida[IFLA_WEIGHT - 1])); | 518 | if (ifm->ifi_flags) |
457 | } | 519 | dev_change_flags(dev, ifm->ifi_flags); |
458 | 520 | ||
459 | if (ida[IFLA_OPERSTATE - 1]) { | 521 | if (tb[IFLA_TXQLEN]) |
460 | if (ida[IFLA_OPERSTATE - 1]->rta_len != RTA_LENGTH(sizeof(u8))) | 522 | dev->tx_queue_len = nla_get_u32(tb[IFLA_TXQLEN]); |
461 | goto out; | ||
462 | 523 | ||
463 | set_operstate(dev, *((u8 *) RTA_DATA(ida[IFLA_OPERSTATE - 1]))); | 524 | if (tb[IFLA_WEIGHT]) |
464 | } | 525 | dev->weight = nla_get_u32(tb[IFLA_WEIGHT]); |
465 | 526 | ||
466 | if (ida[IFLA_LINKMODE - 1]) { | 527 | if (tb[IFLA_OPERSTATE]) |
467 | if (ida[IFLA_LINKMODE - 1]->rta_len != RTA_LENGTH(sizeof(u8))) | 528 | set_operstate(dev, nla_get_u8(tb[IFLA_OPERSTATE])); |
468 | goto out; | ||
469 | 529 | ||
530 | if (tb[IFLA_LINKMODE]) { | ||
470 | write_lock_bh(&dev_base_lock); | 531 | write_lock_bh(&dev_base_lock); |
471 | dev->link_mode = *((u8 *) RTA_DATA(ida[IFLA_LINKMODE - 1])); | 532 | dev->link_mode = nla_get_u8(tb[IFLA_LINKMODE]); |
472 | write_unlock_bh(&dev_base_lock); | 533 | write_unlock_bh(&dev_base_lock); |
473 | } | 534 | } |
474 | 535 | ||
475 | if (ifm->ifi_index >= 0 && ida[IFLA_IFNAME - 1]) { | ||
476 | char ifname[IFNAMSIZ]; | ||
477 | |||
478 | if (rtattr_strlcpy(ifname, ida[IFLA_IFNAME - 1], | ||
479 | IFNAMSIZ) >= IFNAMSIZ) | ||
480 | goto out; | ||
481 | err = dev_change_name(dev, ifname); | ||
482 | if (err) | ||
483 | goto out; | ||
484 | } | ||
485 | |||
486 | #ifdef CONFIG_NET_WIRELESS_RTNETLINK | ||
487 | if (ida[IFLA_WIRELESS - 1]) { | ||
488 | |||
489 | /* Call Wireless Extensions. | ||
490 | * Various stuff checked in there... */ | ||
491 | err = wireless_rtnetlink_set(dev, RTA_DATA(ida[IFLA_WIRELESS - 1]), ida[IFLA_WIRELESS - 1]->rta_len); | ||
492 | if (err) | ||
493 | goto out; | ||
494 | } | ||
495 | #endif /* CONFIG_NET_WIRELESS_RTNETLINK */ | ||
496 | |||
497 | err = 0; | 536 | err = 0; |
498 | 537 | ||
499 | out: | 538 | errout_dev: |
539 | if (err < 0 && modified && net_ratelimit()) | ||
540 | printk(KERN_WARNING "A link change request failed with " | ||
541 | "some changes comitted already. Interface %s may " | ||
542 | "have been left with an inconsistent configuration, " | ||
543 | "please check.\n", dev->name); | ||
544 | |||
500 | if (send_addr_notify) | 545 | if (send_addr_notify) |
501 | call_netdevice_notifiers(NETDEV_CHANGEADDR, dev); | 546 | call_netdevice_notifiers(NETDEV_CHANGEADDR, dev); |
502 | 547 | ||
503 | dev_put(dev); | 548 | dev_put(dev); |
549 | errout: | ||
504 | return err; | 550 | return err; |
505 | } | 551 | } |
506 | 552 | ||
507 | #ifdef CONFIG_NET_WIRELESS_RTNETLINK | 553 | static int rtnl_getlink(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg) |
508 | static int do_getlink(struct sk_buff *in_skb, struct nlmsghdr* in_nlh, void *arg) | ||
509 | { | 554 | { |
510 | struct ifinfomsg *ifm = NLMSG_DATA(in_nlh); | 555 | struct ifinfomsg *ifm; |
511 | struct rtattr **ida = arg; | 556 | struct nlattr *tb[IFLA_MAX+1]; |
512 | struct net_device *dev; | 557 | struct net_device *dev = NULL; |
513 | struct ifinfomsg *r; | 558 | struct sk_buff *nskb; |
514 | struct nlmsghdr *nlh; | 559 | char *iw_buf = NULL, *iw = NULL; |
515 | int err = -ENOBUFS; | ||
516 | struct sk_buff *skb; | ||
517 | unsigned char *b; | ||
518 | char *iw_buf = NULL; | ||
519 | int iw_buf_len = 0; | 560 | int iw_buf_len = 0; |
561 | int err, payload; | ||
520 | 562 | ||
521 | if (ifm->ifi_index >= 0) | 563 | err = nlmsg_parse(nlh, sizeof(*ifm), tb, IFLA_MAX, ifla_policy); |
564 | if (err < 0) | ||
565 | goto errout; | ||
566 | |||
567 | ifm = nlmsg_data(nlh); | ||
568 | if (ifm->ifi_index >= 0) { | ||
522 | dev = dev_get_by_index(ifm->ifi_index); | 569 | dev = dev_get_by_index(ifm->ifi_index); |
523 | else | 570 | if (dev == NULL) |
571 | return -ENODEV; | ||
572 | } else | ||
524 | return -EINVAL; | 573 | return -EINVAL; |
525 | if (!dev) | ||
526 | return -ENODEV; | ||
527 | 574 | ||
528 | #ifdef CONFIG_NET_WIRELESS_RTNETLINK | ||
529 | if (ida[IFLA_WIRELESS - 1]) { | ||
530 | 575 | ||
576 | #ifdef CONFIG_NET_WIRELESS_RTNETLINK | ||
577 | if (tb[IFLA_WIRELESS]) { | ||
531 | /* Call Wireless Extensions. We need to know the size before | 578 | /* Call Wireless Extensions. We need to know the size before |
532 | * we can alloc. Various stuff checked in there... */ | 579 | * we can alloc. Various stuff checked in there... */ |
533 | err = wireless_rtnetlink_get(dev, RTA_DATA(ida[IFLA_WIRELESS - 1]), ida[IFLA_WIRELESS - 1]->rta_len, &iw_buf, &iw_buf_len); | 580 | err = wireless_rtnetlink_get(dev, nla_data(tb[IFLA_WIRELESS]), |
534 | if (err) | 581 | nla_len(tb[IFLA_WIRELESS]), |
535 | goto out; | 582 | &iw_buf, &iw_buf_len); |
583 | if (err < 0) | ||
584 | goto errout; | ||
585 | |||
586 | iw += IW_EV_POINT_OFF; | ||
536 | } | 587 | } |
537 | #endif /* CONFIG_NET_WIRELESS_RTNETLINK */ | 588 | #endif /* CONFIG_NET_WIRELESS_RTNETLINK */ |
538 | 589 | ||
539 | /* Create a skb big enough to include all the data. | 590 | payload = NLMSG_ALIGN(sizeof(struct ifinfomsg) + |
540 | * Some requests are way bigger than 4k... Jean II */ | 591 | nla_total_size(iw_buf_len)); |
541 | skb = alloc_skb((NLMSG_LENGTH(sizeof(*r))) + (RTA_SPACE(iw_buf_len)), | 592 | nskb = nlmsg_new(nlmsg_total_size(payload), GFP_KERNEL); |
542 | GFP_KERNEL); | 593 | if (nskb == NULL) { |
543 | if (!skb) | 594 | err = -ENOBUFS; |
544 | goto out; | 595 | goto errout; |
545 | b = skb->tail; | 596 | } |
546 | 597 | ||
547 | /* Put in the message the usual good stuff */ | 598 | err = rtnl_fill_ifinfo(nskb, dev, iw, iw_buf_len, RTM_NEWLINK, |
548 | nlh = NLMSG_PUT(skb, NETLINK_CB(in_skb).pid, in_nlh->nlmsg_seq, | 599 | NETLINK_CB(skb).pid, nlh->nlmsg_seq, 0, 0); |
549 | RTM_NEWLINK, sizeof(*r)); | 600 | if (err <= 0) { |
550 | r = NLMSG_DATA(nlh); | 601 | kfree_skb(nskb); |
551 | r->ifi_family = AF_UNSPEC; | 602 | goto errout; |
552 | r->__ifi_pad = 0; | 603 | } |
553 | r->ifi_type = dev->type; | 604 | |
554 | r->ifi_index = dev->ifindex; | 605 | err = rtnl_unicast(skb, NETLINK_CB(skb).pid); |
555 | r->ifi_flags = dev->flags; | 606 | errout: |
556 | r->ifi_change = 0; | 607 | kfree(iw_buf); |
557 | |||
558 | /* Put the wireless payload if it exist */ | ||
559 | if(iw_buf != NULL) | ||
560 | RTA_PUT(skb, IFLA_WIRELESS, iw_buf_len, | ||
561 | iw_buf + IW_EV_POINT_OFF); | ||
562 | |||
563 | nlh->nlmsg_len = skb->tail - b; | ||
564 | |||
565 | /* Needed ? */ | ||
566 | NETLINK_CB(skb).dst_pid = NETLINK_CB(in_skb).pid; | ||
567 | |||
568 | err = netlink_unicast(rtnl, skb, NETLINK_CB(in_skb).pid, MSG_DONTWAIT); | ||
569 | if (err > 0) | ||
570 | err = 0; | ||
571 | out: | ||
572 | if(iw_buf != NULL) | ||
573 | kfree(iw_buf); | ||
574 | dev_put(dev); | 608 | dev_put(dev); |
575 | return err; | ||
576 | 609 | ||
577 | rtattr_failure: | 610 | return err; |
578 | nlmsg_failure: | ||
579 | kfree_skb(skb); | ||
580 | goto out; | ||
581 | } | 611 | } |
582 | #endif /* CONFIG_NET_WIRELESS_RTNETLINK */ | ||
583 | 612 | ||
584 | static int rtnetlink_dump_all(struct sk_buff *skb, struct netlink_callback *cb) | 613 | static int rtnl_dump_all(struct sk_buff *skb, struct netlink_callback *cb) |
585 | { | 614 | { |
586 | int idx; | 615 | int idx; |
587 | int s_idx = cb->family; | 616 | int s_idx = cb->family; |
@@ -608,20 +637,22 @@ static int rtnetlink_dump_all(struct sk_buff *skb, struct netlink_callback *cb) | |||
608 | void rtmsg_ifinfo(int type, struct net_device *dev, unsigned change) | 637 | void rtmsg_ifinfo(int type, struct net_device *dev, unsigned change) |
609 | { | 638 | { |
610 | struct sk_buff *skb; | 639 | struct sk_buff *skb; |
611 | int size = NLMSG_SPACE(sizeof(struct ifinfomsg) + | 640 | int err = -ENOBUFS; |
612 | sizeof(struct rtnl_link_ifmap) + | ||
613 | sizeof(struct rtnl_link_stats) + 128); | ||
614 | 641 | ||
615 | skb = alloc_skb(size, GFP_KERNEL); | 642 | skb = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); |
616 | if (!skb) | 643 | if (skb == NULL) |
617 | return; | 644 | goto errout; |
618 | 645 | ||
619 | if (rtnetlink_fill_ifinfo(skb, dev, type, 0, 0, change, 0) < 0) { | 646 | err = rtnl_fill_ifinfo(skb, dev, NULL, 0, type, 0, 0, change, 0); |
647 | if (err < 0) { | ||
620 | kfree_skb(skb); | 648 | kfree_skb(skb); |
621 | return; | 649 | goto errout; |
622 | } | 650 | } |
623 | NETLINK_CB(skb).dst_group = RTNLGRP_LINK; | 651 | |
624 | netlink_broadcast(rtnl, skb, 0, RTNLGRP_LINK, GFP_KERNEL); | 652 | err = rtnl_notify(skb, 0, RTNLGRP_LINK, NULL, GFP_KERNEL); |
653 | errout: | ||
654 | if (err < 0) | ||
655 | rtnl_set_sk_err(RTNLGRP_LINK, err); | ||
625 | } | 656 | } |
626 | 657 | ||
627 | /* Protected by RTNL sempahore. */ | 658 | /* Protected by RTNL sempahore. */ |
@@ -746,18 +777,19 @@ static void rtnetlink_rcv(struct sock *sk, int len) | |||
746 | 777 | ||
747 | static struct rtnetlink_link link_rtnetlink_table[RTM_NR_MSGTYPES] = | 778 | static struct rtnetlink_link link_rtnetlink_table[RTM_NR_MSGTYPES] = |
748 | { | 779 | { |
749 | [RTM_GETLINK - RTM_BASE] = { | 780 | [RTM_GETLINK - RTM_BASE] = { .doit = rtnl_getlink, |
750 | #ifdef CONFIG_NET_WIRELESS_RTNETLINK | 781 | .dumpit = rtnl_dump_ifinfo }, |
751 | .doit = do_getlink, | 782 | [RTM_SETLINK - RTM_BASE] = { .doit = rtnl_setlink }, |
752 | #endif /* CONFIG_NET_WIRELESS_RTNETLINK */ | 783 | [RTM_GETADDR - RTM_BASE] = { .dumpit = rtnl_dump_all }, |
753 | .dumpit = rtnetlink_dump_ifinfo }, | 784 | [RTM_GETROUTE - RTM_BASE] = { .dumpit = rtnl_dump_all }, |
754 | [RTM_SETLINK - RTM_BASE] = { .doit = do_setlink }, | ||
755 | [RTM_GETADDR - RTM_BASE] = { .dumpit = rtnetlink_dump_all }, | ||
756 | [RTM_GETROUTE - RTM_BASE] = { .dumpit = rtnetlink_dump_all }, | ||
757 | [RTM_NEWNEIGH - RTM_BASE] = { .doit = neigh_add }, | 785 | [RTM_NEWNEIGH - RTM_BASE] = { .doit = neigh_add }, |
758 | [RTM_DELNEIGH - RTM_BASE] = { .doit = neigh_delete }, | 786 | [RTM_DELNEIGH - RTM_BASE] = { .doit = neigh_delete }, |
759 | [RTM_GETNEIGH - RTM_BASE] = { .dumpit = neigh_dump_info }, | 787 | [RTM_GETNEIGH - RTM_BASE] = { .dumpit = neigh_dump_info }, |
760 | [RTM_GETRULE - RTM_BASE] = { .dumpit = rtnetlink_dump_all }, | 788 | #ifdef CONFIG_FIB_RULES |
789 | [RTM_NEWRULE - RTM_BASE] = { .doit = fib_nl_newrule }, | ||
790 | [RTM_DELRULE - RTM_BASE] = { .doit = fib_nl_delrule }, | ||
791 | #endif | ||
792 | [RTM_GETRULE - RTM_BASE] = { .dumpit = rtnl_dump_all }, | ||
761 | [RTM_GETNEIGHTBL - RTM_BASE] = { .dumpit = neightbl_dump_info }, | 793 | [RTM_GETNEIGHTBL - RTM_BASE] = { .dumpit = neightbl_dump_info }, |
762 | [RTM_SETNEIGHTBL - RTM_BASE] = { .doit = neightbl_set }, | 794 | [RTM_SETNEIGHTBL - RTM_BASE] = { .doit = neightbl_set }, |
763 | }; | 795 | }; |
@@ -817,7 +849,9 @@ EXPORT_SYMBOL(rtattr_strlcpy); | |||
817 | EXPORT_SYMBOL(rtattr_parse); | 849 | EXPORT_SYMBOL(rtattr_parse); |
818 | EXPORT_SYMBOL(rtnetlink_links); | 850 | EXPORT_SYMBOL(rtnetlink_links); |
819 | EXPORT_SYMBOL(rtnetlink_put_metrics); | 851 | EXPORT_SYMBOL(rtnetlink_put_metrics); |
820 | EXPORT_SYMBOL(rtnl); | ||
821 | EXPORT_SYMBOL(rtnl_lock); | 852 | EXPORT_SYMBOL(rtnl_lock); |
822 | EXPORT_SYMBOL(rtnl_trylock); | 853 | EXPORT_SYMBOL(rtnl_trylock); |
823 | EXPORT_SYMBOL(rtnl_unlock); | 854 | EXPORT_SYMBOL(rtnl_unlock); |
855 | EXPORT_SYMBOL(rtnl_unicast); | ||
856 | EXPORT_SYMBOL(rtnl_notify); | ||
857 | EXPORT_SYMBOL(rtnl_set_sk_err); | ||
diff --git a/net/core/skbuff.c b/net/core/skbuff.c index c54f3664bce5..c448c7f6fde2 100644 --- a/net/core/skbuff.c +++ b/net/core/skbuff.c | |||
@@ -1397,7 +1397,7 @@ void skb_copy_and_csum_dev(const struct sk_buff *skb, u8 *to) | |||
1397 | unsigned int csum; | 1397 | unsigned int csum; |
1398 | long csstart; | 1398 | long csstart; |
1399 | 1399 | ||
1400 | if (skb->ip_summed == CHECKSUM_HW) | 1400 | if (skb->ip_summed == CHECKSUM_PARTIAL) |
1401 | csstart = skb->h.raw - skb->data; | 1401 | csstart = skb->h.raw - skb->data; |
1402 | else | 1402 | else |
1403 | csstart = skb_headlen(skb); | 1403 | csstart = skb_headlen(skb); |
@@ -1411,7 +1411,7 @@ void skb_copy_and_csum_dev(const struct sk_buff *skb, u8 *to) | |||
1411 | csum = skb_copy_and_csum_bits(skb, csstart, to + csstart, | 1411 | csum = skb_copy_and_csum_bits(skb, csstart, to + csstart, |
1412 | skb->len - csstart, 0); | 1412 | skb->len - csstart, 0); |
1413 | 1413 | ||
1414 | if (skb->ip_summed == CHECKSUM_HW) { | 1414 | if (skb->ip_summed == CHECKSUM_PARTIAL) { |
1415 | long csstuff = csstart + skb->csum; | 1415 | long csstuff = csstart + skb->csum; |
1416 | 1416 | ||
1417 | *((unsigned short *)(to + csstuff)) = csum_fold(csum); | 1417 | *((unsigned short *)(to + csstuff)) = csum_fold(csum); |
@@ -1898,10 +1898,10 @@ int skb_append_datato_frags(struct sock *sk, struct sk_buff *skb, | |||
1898 | * @len: length of data pulled | 1898 | * @len: length of data pulled |
1899 | * | 1899 | * |
1900 | * This function performs an skb_pull on the packet and updates | 1900 | * This function performs an skb_pull on the packet and updates |
1901 | * update the CHECKSUM_HW checksum. It should be used on receive | 1901 | * update the CHECKSUM_COMPLETE checksum. It should be used on |
1902 | * path processing instead of skb_pull unless you know that the | 1902 | * receive path processing instead of skb_pull unless you know |
1903 | * checksum difference is zero (e.g., a valid IP header) or you | 1903 | * that the checksum difference is zero (e.g., a valid IP header) |
1904 | * are setting ip_summed to CHECKSUM_NONE. | 1904 | * or you are setting ip_summed to CHECKSUM_NONE. |
1905 | */ | 1905 | */ |
1906 | unsigned char *skb_pull_rcsum(struct sk_buff *skb, unsigned int len) | 1906 | unsigned char *skb_pull_rcsum(struct sk_buff *skb, unsigned int len) |
1907 | { | 1907 | { |
@@ -1994,7 +1994,7 @@ struct sk_buff *skb_segment(struct sk_buff *skb, int features) | |||
1994 | frag = skb_shinfo(nskb)->frags; | 1994 | frag = skb_shinfo(nskb)->frags; |
1995 | k = 0; | 1995 | k = 0; |
1996 | 1996 | ||
1997 | nskb->ip_summed = CHECKSUM_HW; | 1997 | nskb->ip_summed = CHECKSUM_PARTIAL; |
1998 | nskb->csum = skb->csum; | 1998 | nskb->csum = skb->csum; |
1999 | memcpy(skb_put(nskb, hsize), skb->data + offset, hsize); | 1999 | memcpy(skb_put(nskb, hsize), skb->data + offset, hsize); |
2000 | 2000 | ||
@@ -2046,19 +2046,14 @@ void __init skb_init(void) | |||
2046 | skbuff_head_cache = kmem_cache_create("skbuff_head_cache", | 2046 | skbuff_head_cache = kmem_cache_create("skbuff_head_cache", |
2047 | sizeof(struct sk_buff), | 2047 | sizeof(struct sk_buff), |
2048 | 0, | 2048 | 0, |
2049 | SLAB_HWCACHE_ALIGN, | 2049 | SLAB_HWCACHE_ALIGN|SLAB_PANIC, |
2050 | NULL, NULL); | 2050 | NULL, NULL); |
2051 | if (!skbuff_head_cache) | ||
2052 | panic("cannot create skbuff cache"); | ||
2053 | |||
2054 | skbuff_fclone_cache = kmem_cache_create("skbuff_fclone_cache", | 2051 | skbuff_fclone_cache = kmem_cache_create("skbuff_fclone_cache", |
2055 | (2*sizeof(struct sk_buff)) + | 2052 | (2*sizeof(struct sk_buff)) + |
2056 | sizeof(atomic_t), | 2053 | sizeof(atomic_t), |
2057 | 0, | 2054 | 0, |
2058 | SLAB_HWCACHE_ALIGN, | 2055 | SLAB_HWCACHE_ALIGN|SLAB_PANIC, |
2059 | NULL, NULL); | 2056 | NULL, NULL); |
2060 | if (!skbuff_fclone_cache) | ||
2061 | panic("cannot create skbuff cache"); | ||
2062 | } | 2057 | } |
2063 | 2058 | ||
2064 | EXPORT_SYMBOL(___pskb_trim); | 2059 | EXPORT_SYMBOL(___pskb_trim); |
diff --git a/net/core/sock.c b/net/core/sock.c index 51fcfbc041a7..b77e155cbe6c 100644 --- a/net/core/sock.c +++ b/net/core/sock.c | |||
@@ -187,13 +187,13 @@ static struct lock_class_key af_callback_keys[AF_MAX]; | |||
187 | #define SK_RMEM_MAX (_SK_MEM_OVERHEAD * _SK_MEM_PACKETS) | 187 | #define SK_RMEM_MAX (_SK_MEM_OVERHEAD * _SK_MEM_PACKETS) |
188 | 188 | ||
189 | /* Run time adjustable parameters. */ | 189 | /* Run time adjustable parameters. */ |
190 | __u32 sysctl_wmem_max = SK_WMEM_MAX; | 190 | __u32 sysctl_wmem_max __read_mostly = SK_WMEM_MAX; |
191 | __u32 sysctl_rmem_max = SK_RMEM_MAX; | 191 | __u32 sysctl_rmem_max __read_mostly = SK_RMEM_MAX; |
192 | __u32 sysctl_wmem_default = SK_WMEM_MAX; | 192 | __u32 sysctl_wmem_default __read_mostly = SK_WMEM_MAX; |
193 | __u32 sysctl_rmem_default = SK_RMEM_MAX; | 193 | __u32 sysctl_rmem_default __read_mostly = SK_RMEM_MAX; |
194 | 194 | ||
195 | /* Maximal space eaten by iovec or ancilliary data plus some space */ | 195 | /* Maximal space eaten by iovec or ancilliary data plus some space */ |
196 | int sysctl_optmem_max = sizeof(unsigned long)*(2*UIO_MAXIOV + 512); | 196 | int sysctl_optmem_max __read_mostly = sizeof(unsigned long)*(2*UIO_MAXIOV+512); |
197 | 197 | ||
198 | static int sock_set_timeout(long *timeo_p, char __user *optval, int optlen) | 198 | static int sock_set_timeout(long *timeo_p, char __user *optval, int optlen) |
199 | { | 199 | { |
@@ -247,11 +247,7 @@ int sock_queue_rcv_skb(struct sock *sk, struct sk_buff *skb) | |||
247 | goto out; | 247 | goto out; |
248 | } | 248 | } |
249 | 249 | ||
250 | /* It would be deadlock, if sock_queue_rcv_skb is used | 250 | err = sk_filter(sk, skb); |
251 | with socket lock! We assume that users of this | ||
252 | function are lock free. | ||
253 | */ | ||
254 | err = sk_filter(sk, skb, 1); | ||
255 | if (err) | 251 | if (err) |
256 | goto out; | 252 | goto out; |
257 | 253 | ||
@@ -278,7 +274,7 @@ int sk_receive_skb(struct sock *sk, struct sk_buff *skb) | |||
278 | { | 274 | { |
279 | int rc = NET_RX_SUCCESS; | 275 | int rc = NET_RX_SUCCESS; |
280 | 276 | ||
281 | if (sk_filter(sk, skb, 0)) | 277 | if (sk_filter(sk, skb)) |
282 | goto discard_and_relse; | 278 | goto discard_and_relse; |
283 | 279 | ||
284 | skb->dev = NULL; | 280 | skb->dev = NULL; |
@@ -606,15 +602,15 @@ set_rcvbuf: | |||
606 | break; | 602 | break; |
607 | 603 | ||
608 | case SO_DETACH_FILTER: | 604 | case SO_DETACH_FILTER: |
609 | spin_lock_bh(&sk->sk_lock.slock); | 605 | rcu_read_lock_bh(); |
610 | filter = sk->sk_filter; | 606 | filter = rcu_dereference(sk->sk_filter); |
611 | if (filter) { | 607 | if (filter) { |
612 | sk->sk_filter = NULL; | 608 | rcu_assign_pointer(sk->sk_filter, NULL); |
613 | spin_unlock_bh(&sk->sk_lock.slock); | ||
614 | sk_filter_release(sk, filter); | 609 | sk_filter_release(sk, filter); |
610 | rcu_read_unlock_bh(); | ||
615 | break; | 611 | break; |
616 | } | 612 | } |
617 | spin_unlock_bh(&sk->sk_lock.slock); | 613 | rcu_read_unlock_bh(); |
618 | ret = -ENONET; | 614 | ret = -ENONET; |
619 | break; | 615 | break; |
620 | 616 | ||
@@ -884,10 +880,10 @@ void sk_free(struct sock *sk) | |||
884 | if (sk->sk_destruct) | 880 | if (sk->sk_destruct) |
885 | sk->sk_destruct(sk); | 881 | sk->sk_destruct(sk); |
886 | 882 | ||
887 | filter = sk->sk_filter; | 883 | filter = rcu_dereference(sk->sk_filter); |
888 | if (filter) { | 884 | if (filter) { |
889 | sk_filter_release(sk, filter); | 885 | sk_filter_release(sk, filter); |
890 | sk->sk_filter = NULL; | 886 | rcu_assign_pointer(sk->sk_filter, NULL); |
891 | } | 887 | } |
892 | 888 | ||
893 | sock_disable_timestamp(sk); | 889 | sock_disable_timestamp(sk); |
@@ -911,7 +907,7 @@ struct sock *sk_clone(const struct sock *sk, const gfp_t priority) | |||
911 | if (newsk != NULL) { | 907 | if (newsk != NULL) { |
912 | struct sk_filter *filter; | 908 | struct sk_filter *filter; |
913 | 909 | ||
914 | memcpy(newsk, sk, sk->sk_prot->obj_size); | 910 | sock_copy(newsk, sk); |
915 | 911 | ||
916 | /* SANITY */ | 912 | /* SANITY */ |
917 | sk_node_init(&newsk->sk_node); | 913 | sk_node_init(&newsk->sk_node); |
diff --git a/net/core/utils.c b/net/core/utils.c index e31c90e05594..2682490777de 100644 --- a/net/core/utils.c +++ b/net/core/utils.c | |||
@@ -4,6 +4,7 @@ | |||
4 | * Authors: | 4 | * Authors: |
5 | * net_random Alan Cox | 5 | * net_random Alan Cox |
6 | * net_ratelimit Andy Kleen | 6 | * net_ratelimit Andy Kleen |
7 | * in{4,6}_pton YOSHIFUJI Hideaki, Copyright (C)2006 USAGI/WIDE Project | ||
7 | * | 8 | * |
8 | * Created by Alexey Kuznetsov <kuznet@ms2.inr.ac.ru> | 9 | * Created by Alexey Kuznetsov <kuznet@ms2.inr.ac.ru> |
9 | * | 10 | * |
@@ -191,3 +192,215 @@ __be32 in_aton(const char *str) | |||
191 | } | 192 | } |
192 | 193 | ||
193 | EXPORT_SYMBOL(in_aton); | 194 | EXPORT_SYMBOL(in_aton); |
195 | |||
196 | #define IN6PTON_XDIGIT 0x00010000 | ||
197 | #define IN6PTON_DIGIT 0x00020000 | ||
198 | #define IN6PTON_COLON_MASK 0x00700000 | ||
199 | #define IN6PTON_COLON_1 0x00100000 /* single : requested */ | ||
200 | #define IN6PTON_COLON_2 0x00200000 /* second : requested */ | ||
201 | #define IN6PTON_COLON_1_2 0x00400000 /* :: requested */ | ||
202 | #define IN6PTON_DOT 0x00800000 /* . */ | ||
203 | #define IN6PTON_DELIM 0x10000000 | ||
204 | #define IN6PTON_NULL 0x20000000 /* first/tail */ | ||
205 | #define IN6PTON_UNKNOWN 0x40000000 | ||
206 | |||
207 | static inline int digit2bin(char c, char delim) | ||
208 | { | ||
209 | if (c == delim || c == '\0') | ||
210 | return IN6PTON_DELIM; | ||
211 | if (c == '.') | ||
212 | return IN6PTON_DOT; | ||
213 | if (c >= '0' && c <= '9') | ||
214 | return (IN6PTON_DIGIT | (c - '0')); | ||
215 | return IN6PTON_UNKNOWN; | ||
216 | } | ||
217 | |||
218 | static inline int xdigit2bin(char c, char delim) | ||
219 | { | ||
220 | if (c == delim || c == '\0') | ||
221 | return IN6PTON_DELIM; | ||
222 | if (c == ':') | ||
223 | return IN6PTON_COLON_MASK; | ||
224 | if (c == '.') | ||
225 | return IN6PTON_DOT; | ||
226 | if (c >= '0' && c <= '9') | ||
227 | return (IN6PTON_XDIGIT | IN6PTON_DIGIT| (c - '0')); | ||
228 | if (c >= 'a' && c <= 'f') | ||
229 | return (IN6PTON_XDIGIT | (c - 'a' + 10)); | ||
230 | if (c >= 'A' && c <= 'F') | ||
231 | return (IN6PTON_XDIGIT | (c - 'A' + 10)); | ||
232 | return IN6PTON_UNKNOWN; | ||
233 | } | ||
234 | |||
235 | int in4_pton(const char *src, int srclen, | ||
236 | u8 *dst, | ||
237 | char delim, const char **end) | ||
238 | { | ||
239 | const char *s; | ||
240 | u8 *d; | ||
241 | u8 dbuf[4]; | ||
242 | int ret = 0; | ||
243 | int i; | ||
244 | int w = 0; | ||
245 | |||
246 | if (srclen < 0) | ||
247 | srclen = strlen(src); | ||
248 | s = src; | ||
249 | d = dbuf; | ||
250 | i = 0; | ||
251 | while(1) { | ||
252 | int c; | ||
253 | c = xdigit2bin(srclen > 0 ? *s : '\0', delim); | ||
254 | if (!(c & (IN6PTON_DIGIT | IN6PTON_DOT | IN6PTON_DELIM))) { | ||
255 | goto out; | ||
256 | } | ||
257 | if (c & (IN6PTON_DOT | IN6PTON_DELIM)) { | ||
258 | if (w == 0) | ||
259 | goto out; | ||
260 | *d++ = w & 0xff; | ||
261 | w = 0; | ||
262 | i++; | ||
263 | if (c & IN6PTON_DELIM) { | ||
264 | if (i != 4) | ||
265 | goto out; | ||
266 | break; | ||
267 | } | ||
268 | goto cont; | ||
269 | } | ||
270 | w = (w * 10) + c; | ||
271 | if ((w & 0xffff) > 255) { | ||
272 | goto out; | ||
273 | } | ||
274 | cont: | ||
275 | if (i >= 4) | ||
276 | goto out; | ||
277 | s++; | ||
278 | srclen--; | ||
279 | } | ||
280 | ret = 1; | ||
281 | memcpy(dst, dbuf, sizeof(dbuf)); | ||
282 | out: | ||
283 | if (end) | ||
284 | *end = s; | ||
285 | return ret; | ||
286 | } | ||
287 | |||
288 | EXPORT_SYMBOL(in4_pton); | ||
289 | |||
290 | int in6_pton(const char *src, int srclen, | ||
291 | u8 *dst, | ||
292 | char delim, const char **end) | ||
293 | { | ||
294 | const char *s, *tok = NULL; | ||
295 | u8 *d, *dc = NULL; | ||
296 | u8 dbuf[16]; | ||
297 | int ret = 0; | ||
298 | int i; | ||
299 | int state = IN6PTON_COLON_1_2 | IN6PTON_XDIGIT | IN6PTON_NULL; | ||
300 | int w = 0; | ||
301 | |||
302 | memset(dbuf, 0, sizeof(dbuf)); | ||
303 | |||
304 | s = src; | ||
305 | d = dbuf; | ||
306 | if (srclen < 0) | ||
307 | srclen = strlen(src); | ||
308 | |||
309 | while (1) { | ||
310 | int c; | ||
311 | |||
312 | c = xdigit2bin(srclen > 0 ? *s : '\0', delim); | ||
313 | if (!(c & state)) | ||
314 | goto out; | ||
315 | if (c & (IN6PTON_DELIM | IN6PTON_COLON_MASK)) { | ||
316 | /* process one 16-bit word */ | ||
317 | if (!(state & IN6PTON_NULL)) { | ||
318 | *d++ = (w >> 8) & 0xff; | ||
319 | *d++ = w & 0xff; | ||
320 | } | ||
321 | w = 0; | ||
322 | if (c & IN6PTON_DELIM) { | ||
323 | /* We've processed last word */ | ||
324 | break; | ||
325 | } | ||
326 | /* | ||
327 | * COLON_1 => XDIGIT | ||
328 | * COLON_2 => XDIGIT|DELIM | ||
329 | * COLON_1_2 => COLON_2 | ||
330 | */ | ||
331 | switch (state & IN6PTON_COLON_MASK) { | ||
332 | case IN6PTON_COLON_2: | ||
333 | dc = d; | ||
334 | state = IN6PTON_XDIGIT | IN6PTON_DELIM; | ||
335 | if (dc - dbuf >= sizeof(dbuf)) | ||
336 | state |= IN6PTON_NULL; | ||
337 | break; | ||
338 | case IN6PTON_COLON_1|IN6PTON_COLON_1_2: | ||
339 | state = IN6PTON_XDIGIT | IN6PTON_COLON_2; | ||
340 | break; | ||
341 | case IN6PTON_COLON_1: | ||
342 | state = IN6PTON_XDIGIT; | ||
343 | break; | ||
344 | case IN6PTON_COLON_1_2: | ||
345 | state = IN6PTON_COLON_2; | ||
346 | break; | ||
347 | default: | ||
348 | state = 0; | ||
349 | } | ||
350 | tok = s + 1; | ||
351 | goto cont; | ||
352 | } | ||
353 | |||
354 | if (c & IN6PTON_DOT) { | ||
355 | ret = in4_pton(tok ? tok : s, srclen + (int)(s - tok), d, delim, &s); | ||
356 | if (ret > 0) { | ||
357 | d += 4; | ||
358 | break; | ||
359 | } | ||
360 | goto out; | ||
361 | } | ||
362 | |||
363 | w = (w << 4) | (0xff & c); | ||
364 | state = IN6PTON_COLON_1 | IN6PTON_DELIM; | ||
365 | if (!(w & 0xf000)) { | ||
366 | state |= IN6PTON_XDIGIT; | ||
367 | } | ||
368 | if (!dc && d + 2 < dbuf + sizeof(dbuf)) { | ||
369 | state |= IN6PTON_COLON_1_2; | ||
370 | state &= ~IN6PTON_DELIM; | ||
371 | } | ||
372 | if (d + 2 >= dbuf + sizeof(dbuf)) { | ||
373 | state &= ~(IN6PTON_COLON_1|IN6PTON_COLON_1_2); | ||
374 | } | ||
375 | cont: | ||
376 | if ((dc && d + 4 < dbuf + sizeof(dbuf)) || | ||
377 | d + 4 == dbuf + sizeof(dbuf)) { | ||
378 | state |= IN6PTON_DOT; | ||
379 | } | ||
380 | if (d >= dbuf + sizeof(dbuf)) { | ||
381 | state &= ~(IN6PTON_XDIGIT|IN6PTON_COLON_MASK); | ||
382 | } | ||
383 | s++; | ||
384 | srclen--; | ||
385 | } | ||
386 | |||
387 | i = 15; d--; | ||
388 | |||
389 | if (dc) { | ||
390 | while(d >= dc) | ||
391 | dst[i--] = *d--; | ||
392 | while(i >= dc - dbuf) | ||
393 | dst[i--] = 0; | ||
394 | while(i >= 0) | ||
395 | dst[i--] = *d--; | ||
396 | } else | ||
397 | memcpy(dst, dbuf, sizeof(dbuf)); | ||
398 | |||
399 | ret = 1; | ||
400 | out: | ||
401 | if (end) | ||
402 | *end = s; | ||
403 | return ret; | ||
404 | } | ||
405 | |||
406 | EXPORT_SYMBOL(in6_pton); | ||
diff --git a/net/core/wireless.c b/net/core/wireless.c index de0bde4b51dd..3168fca312f7 100644 --- a/net/core/wireless.c +++ b/net/core/wireless.c | |||
@@ -72,7 +72,6 @@ | |||
72 | 72 | ||
73 | /***************************** INCLUDES *****************************/ | 73 | /***************************** INCLUDES *****************************/ |
74 | 74 | ||
75 | #include <linux/config.h> /* Not needed ??? */ | ||
76 | #include <linux/module.h> | 75 | #include <linux/module.h> |
77 | #include <linux/types.h> /* off_t */ | 76 | #include <linux/types.h> /* off_t */ |
78 | #include <linux/netdevice.h> /* struct ifreq, dev_get_by_name() */ | 77 | #include <linux/netdevice.h> /* struct ifreq, dev_get_by_name() */ |
@@ -86,6 +85,7 @@ | |||
86 | 85 | ||
87 | #include <linux/wireless.h> /* Pretty obvious */ | 86 | #include <linux/wireless.h> /* Pretty obvious */ |
88 | #include <net/iw_handler.h> /* New driver API */ | 87 | #include <net/iw_handler.h> /* New driver API */ |
88 | #include <net/netlink.h> | ||
89 | 89 | ||
90 | #include <asm/uaccess.h> /* copy_to_user() */ | 90 | #include <asm/uaccess.h> /* copy_to_user() */ |
91 | 91 | ||
@@ -1850,7 +1850,7 @@ static void wireless_nlevent_process(unsigned long data) | |||
1850 | struct sk_buff *skb; | 1850 | struct sk_buff *skb; |
1851 | 1851 | ||
1852 | while ((skb = skb_dequeue(&wireless_nlevent_queue))) | 1852 | while ((skb = skb_dequeue(&wireless_nlevent_queue))) |
1853 | netlink_broadcast(rtnl, skb, 0, RTNLGRP_LINK, GFP_ATOMIC); | 1853 | rtnl_notify(skb, 0, RTNLGRP_LINK, NULL, GFP_ATOMIC); |
1854 | } | 1854 | } |
1855 | 1855 | ||
1856 | static DECLARE_TASKLET(wireless_nlevent_tasklet, wireless_nlevent_process, 0); | 1856 | static DECLARE_TASKLET(wireless_nlevent_tasklet, wireless_nlevent_process, 0); |
diff --git a/net/dccp/ackvec.c b/net/dccp/ackvec.c index 8c211c58893b..4d176d33983f 100644 --- a/net/dccp/ackvec.c +++ b/net/dccp/ackvec.c | |||
@@ -142,14 +142,13 @@ struct dccp_ackvec *dccp_ackvec_alloc(const gfp_t priority) | |||
142 | struct dccp_ackvec *av = kmem_cache_alloc(dccp_ackvec_slab, priority); | 142 | struct dccp_ackvec *av = kmem_cache_alloc(dccp_ackvec_slab, priority); |
143 | 143 | ||
144 | if (av != NULL) { | 144 | if (av != NULL) { |
145 | av->dccpav_buf_head = | 145 | av->dccpav_buf_head = DCCP_MAX_ACKVEC_LEN - 1; |
146 | av->dccpav_buf_tail = DCCP_MAX_ACKVEC_LEN - 1; | ||
147 | av->dccpav_buf_ackno = DCCP_MAX_SEQNO + 1; | 146 | av->dccpav_buf_ackno = DCCP_MAX_SEQNO + 1; |
148 | av->dccpav_buf_nonce = av->dccpav_buf_nonce = 0; | 147 | av->dccpav_buf_nonce = av->dccpav_buf_nonce = 0; |
149 | av->dccpav_ack_ptr = 0; | 148 | av->dccpav_ack_ptr = 0; |
150 | av->dccpav_time.tv_sec = 0; | 149 | av->dccpav_time.tv_sec = 0; |
151 | av->dccpav_time.tv_usec = 0; | 150 | av->dccpav_time.tv_usec = 0; |
152 | av->dccpav_sent_len = av->dccpav_vec_len = 0; | 151 | av->dccpav_vec_len = 0; |
153 | INIT_LIST_HEAD(&av->dccpav_records); | 152 | INIT_LIST_HEAD(&av->dccpav_records); |
154 | } | 153 | } |
155 | 154 | ||
@@ -353,11 +352,13 @@ static void dccp_ackvec_throw_record(struct dccp_ackvec *av, | |||
353 | { | 352 | { |
354 | struct dccp_ackvec_record *next; | 353 | struct dccp_ackvec_record *next; |
355 | 354 | ||
356 | av->dccpav_buf_tail = avr->dccpavr_ack_ptr - 1; | 355 | /* sort out vector length */ |
357 | if (av->dccpav_buf_tail == 0) | 356 | if (av->dccpav_buf_head <= avr->dccpavr_ack_ptr) |
358 | av->dccpav_buf_tail = DCCP_MAX_ACKVEC_LEN - 1; | 357 | av->dccpav_vec_len = avr->dccpavr_ack_ptr - av->dccpav_buf_head; |
359 | 358 | else | |
360 | av->dccpav_vec_len -= avr->dccpavr_sent_len; | 359 | av->dccpav_vec_len = DCCP_MAX_ACKVEC_LEN - 1 |
360 | - av->dccpav_buf_head | ||
361 | + avr->dccpavr_ack_ptr; | ||
361 | 362 | ||
362 | /* free records */ | 363 | /* free records */ |
363 | list_for_each_entry_safe_from(avr, next, &av->dccpav_records, | 364 | list_for_each_entry_safe_from(avr, next, &av->dccpav_records, |
@@ -434,8 +435,7 @@ static void dccp_ackvec_check_rcv_ackvector(struct dccp_ackvec *av, | |||
434 | break; | 435 | break; |
435 | found: | 436 | found: |
436 | if (between48(avr->dccpavr_ack_seqno, ackno_end_rl, ackno)) { | 437 | if (between48(avr->dccpavr_ack_seqno, ackno_end_rl, ackno)) { |
437 | const u8 state = (*vector & | 438 | const u8 state = *vector & DCCP_ACKVEC_STATE_MASK; |
438 | DCCP_ACKVEC_STATE_MASK) >> 6; | ||
439 | if (state != DCCP_ACKVEC_STATE_NOT_RECEIVED) { | 439 | if (state != DCCP_ACKVEC_STATE_NOT_RECEIVED) { |
440 | #ifdef CONFIG_IP_DCCP_DEBUG | 440 | #ifdef CONFIG_IP_DCCP_DEBUG |
441 | struct dccp_sock *dp = dccp_sk(sk); | 441 | struct dccp_sock *dp = dccp_sk(sk); |
diff --git a/net/dccp/ackvec.h b/net/dccp/ackvec.h index 0adf4b56c34c..2424effac7f6 100644 --- a/net/dccp/ackvec.h +++ b/net/dccp/ackvec.h | |||
@@ -54,9 +54,7 @@ struct dccp_ackvec { | |||
54 | struct list_head dccpav_records; | 54 | struct list_head dccpav_records; |
55 | struct timeval dccpav_time; | 55 | struct timeval dccpav_time; |
56 | u8 dccpav_buf_head; | 56 | u8 dccpav_buf_head; |
57 | u8 dccpav_buf_tail; | ||
58 | u8 dccpav_ack_ptr; | 57 | u8 dccpav_ack_ptr; |
59 | u8 dccpav_sent_len; | ||
60 | u8 dccpav_vec_len; | 58 | u8 dccpav_vec_len; |
61 | u8 dccpav_buf_nonce; | 59 | u8 dccpav_buf_nonce; |
62 | u8 dccpav_ack_nonce; | 60 | u8 dccpav_ack_nonce; |
@@ -107,7 +105,7 @@ extern int dccp_insert_option_ackvec(struct sock *sk, struct sk_buff *skb); | |||
107 | 105 | ||
108 | static inline int dccp_ackvec_pending(const struct dccp_ackvec *av) | 106 | static inline int dccp_ackvec_pending(const struct dccp_ackvec *av) |
109 | { | 107 | { |
110 | return av->dccpav_sent_len != av->dccpav_vec_len; | 108 | return av->dccpav_vec_len; |
111 | } | 109 | } |
112 | #else /* CONFIG_IP_DCCP_ACKVEC */ | 110 | #else /* CONFIG_IP_DCCP_ACKVEC */ |
113 | static inline int dccp_ackvec_init(void) | 111 | static inline int dccp_ackvec_init(void) |
diff --git a/net/dccp/ccids/Kconfig b/net/dccp/ccids/Kconfig index ca00191628f7..32752f750447 100644 --- a/net/dccp/ccids/Kconfig +++ b/net/dccp/ccids/Kconfig | |||
@@ -30,6 +30,14 @@ config IP_DCCP_CCID2 | |||
30 | 30 | ||
31 | If in doubt, say M. | 31 | If in doubt, say M. |
32 | 32 | ||
33 | config IP_DCCP_CCID2_DEBUG | ||
34 | bool "CCID2 debug" | ||
35 | depends on IP_DCCP_CCID2 | ||
36 | ---help--- | ||
37 | Enable CCID2 debug messages. | ||
38 | |||
39 | If in doubt, say N. | ||
40 | |||
33 | config IP_DCCP_CCID3 | 41 | config IP_DCCP_CCID3 |
34 | tristate "CCID3 (TCP-Friendly) (EXPERIMENTAL)" | 42 | tristate "CCID3 (TCP-Friendly) (EXPERIMENTAL)" |
35 | depends on IP_DCCP | 43 | depends on IP_DCCP |
diff --git a/net/dccp/ccids/ccid2.c b/net/dccp/ccids/ccid2.c index e9615627dcd6..457dd3db7f41 100644 --- a/net/dccp/ccids/ccid2.c +++ b/net/dccp/ccids/ccid2.c | |||
@@ -27,7 +27,6 @@ | |||
27 | * | 27 | * |
28 | * BUGS: | 28 | * BUGS: |
29 | * - sequence number wrapping | 29 | * - sequence number wrapping |
30 | * - jiffies wrapping | ||
31 | */ | 30 | */ |
32 | 31 | ||
33 | #include "../ccid.h" | 32 | #include "../ccid.h" |
@@ -36,8 +35,7 @@ | |||
36 | 35 | ||
37 | static int ccid2_debug; | 36 | static int ccid2_debug; |
38 | 37 | ||
39 | #undef CCID2_DEBUG | 38 | #ifdef CONFIG_IP_DCCP_CCID2_DEBUG |
40 | #ifdef CCID2_DEBUG | ||
41 | #define ccid2_pr_debug(format, a...) \ | 39 | #define ccid2_pr_debug(format, a...) \ |
42 | do { if (ccid2_debug) \ | 40 | do { if (ccid2_debug) \ |
43 | printk(KERN_DEBUG "%s: " format, __FUNCTION__, ##a); \ | 41 | printk(KERN_DEBUG "%s: " format, __FUNCTION__, ##a); \ |
@@ -46,9 +44,7 @@ static int ccid2_debug; | |||
46 | #define ccid2_pr_debug(format, a...) | 44 | #define ccid2_pr_debug(format, a...) |
47 | #endif | 45 | #endif |
48 | 46 | ||
49 | static const int ccid2_seq_len = 128; | 47 | #ifdef CONFIG_IP_DCCP_CCID2_DEBUG |
50 | |||
51 | #ifdef CCID2_DEBUG | ||
52 | static void ccid2_hc_tx_check_sanity(const struct ccid2_hc_tx_sock *hctx) | 48 | static void ccid2_hc_tx_check_sanity(const struct ccid2_hc_tx_sock *hctx) |
53 | { | 49 | { |
54 | int len = 0; | 50 | int len = 0; |
@@ -71,8 +67,8 @@ static void ccid2_hc_tx_check_sanity(const struct ccid2_hc_tx_sock *hctx) | |||
71 | 67 | ||
72 | /* packets are sent sequentially */ | 68 | /* packets are sent sequentially */ |
73 | BUG_ON(seqp->ccid2s_seq <= prev->ccid2s_seq); | 69 | BUG_ON(seqp->ccid2s_seq <= prev->ccid2s_seq); |
74 | BUG_ON(seqp->ccid2s_sent < prev->ccid2s_sent); | 70 | BUG_ON(time_before(seqp->ccid2s_sent, |
75 | BUG_ON(len > ccid2_seq_len); | 71 | prev->ccid2s_sent)); |
76 | 72 | ||
77 | seqp = prev; | 73 | seqp = prev; |
78 | } | 74 | } |
@@ -84,16 +80,57 @@ static void ccid2_hc_tx_check_sanity(const struct ccid2_hc_tx_sock *hctx) | |||
84 | do { | 80 | do { |
85 | seqp = seqp->ccid2s_prev; | 81 | seqp = seqp->ccid2s_prev; |
86 | len++; | 82 | len++; |
87 | BUG_ON(len > ccid2_seq_len); | ||
88 | } while (seqp != hctx->ccid2hctx_seqh); | 83 | } while (seqp != hctx->ccid2hctx_seqh); |
89 | 84 | ||
90 | BUG_ON(len != ccid2_seq_len); | ||
91 | ccid2_pr_debug("total len=%d\n", len); | 85 | ccid2_pr_debug("total len=%d\n", len); |
86 | BUG_ON(len != hctx->ccid2hctx_seqbufc * CCID2_SEQBUF_LEN); | ||
92 | } | 87 | } |
93 | #else | 88 | #else |
94 | #define ccid2_hc_tx_check_sanity(hctx) do {} while (0) | 89 | #define ccid2_hc_tx_check_sanity(hctx) do {} while (0) |
95 | #endif | 90 | #endif |
96 | 91 | ||
92 | static int ccid2_hc_tx_alloc_seq(struct ccid2_hc_tx_sock *hctx, int num, | ||
93 | gfp_t gfp) | ||
94 | { | ||
95 | struct ccid2_seq *seqp; | ||
96 | int i; | ||
97 | |||
98 | /* check if we have space to preserve the pointer to the buffer */ | ||
99 | if (hctx->ccid2hctx_seqbufc >= (sizeof(hctx->ccid2hctx_seqbuf) / | ||
100 | sizeof(struct ccid2_seq*))) | ||
101 | return -ENOMEM; | ||
102 | |||
103 | /* allocate buffer and initialize linked list */ | ||
104 | seqp = kmalloc(sizeof(*seqp) * num, gfp); | ||
105 | if (seqp == NULL) | ||
106 | return -ENOMEM; | ||
107 | |||
108 | for (i = 0; i < (num - 1); i++) { | ||
109 | seqp[i].ccid2s_next = &seqp[i + 1]; | ||
110 | seqp[i + 1].ccid2s_prev = &seqp[i]; | ||
111 | } | ||
112 | seqp[num - 1].ccid2s_next = seqp; | ||
113 | seqp->ccid2s_prev = &seqp[num - 1]; | ||
114 | |||
115 | /* This is the first allocation. Initiate the head and tail. */ | ||
116 | if (hctx->ccid2hctx_seqbufc == 0) | ||
117 | hctx->ccid2hctx_seqh = hctx->ccid2hctx_seqt = seqp; | ||
118 | else { | ||
119 | /* link the existing list with the one we just created */ | ||
120 | hctx->ccid2hctx_seqh->ccid2s_next = seqp; | ||
121 | seqp->ccid2s_prev = hctx->ccid2hctx_seqh; | ||
122 | |||
123 | hctx->ccid2hctx_seqt->ccid2s_prev = &seqp[num - 1]; | ||
124 | seqp[num - 1].ccid2s_next = hctx->ccid2hctx_seqt; | ||
125 | } | ||
126 | |||
127 | /* store the original pointer to the buffer so we can free it */ | ||
128 | hctx->ccid2hctx_seqbuf[hctx->ccid2hctx_seqbufc] = seqp; | ||
129 | hctx->ccid2hctx_seqbufc++; | ||
130 | |||
131 | return 0; | ||
132 | } | ||
133 | |||
97 | static int ccid2_hc_tx_send_packet(struct sock *sk, | 134 | static int ccid2_hc_tx_send_packet(struct sock *sk, |
98 | struct sk_buff *skb, int len) | 135 | struct sk_buff *skb, int len) |
99 | { | 136 | { |
@@ -122,7 +159,7 @@ static int ccid2_hc_tx_send_packet(struct sock *sk, | |||
122 | } | 159 | } |
123 | } | 160 | } |
124 | 161 | ||
125 | return 100; /* XXX */ | 162 | return 1; /* XXX CCID should dequeue when ready instead of polling */ |
126 | } | 163 | } |
127 | 164 | ||
128 | static void ccid2_change_l_ack_ratio(struct sock *sk, int val) | 165 | static void ccid2_change_l_ack_ratio(struct sock *sk, int val) |
@@ -150,10 +187,8 @@ static void ccid2_change_l_ack_ratio(struct sock *sk, int val) | |||
150 | dp->dccps_l_ack_ratio = val; | 187 | dp->dccps_l_ack_ratio = val; |
151 | } | 188 | } |
152 | 189 | ||
153 | static void ccid2_change_cwnd(struct sock *sk, int val) | 190 | static void ccid2_change_cwnd(struct ccid2_hc_tx_sock *hctx, int val) |
154 | { | 191 | { |
155 | struct ccid2_hc_tx_sock *hctx = ccid2_hc_tx_sk(sk); | ||
156 | |||
157 | if (val == 0) | 192 | if (val == 0) |
158 | val = 1; | 193 | val = 1; |
159 | 194 | ||
@@ -164,6 +199,17 @@ static void ccid2_change_cwnd(struct sock *sk, int val) | |||
164 | hctx->ccid2hctx_cwnd = val; | 199 | hctx->ccid2hctx_cwnd = val; |
165 | } | 200 | } |
166 | 201 | ||
202 | static void ccid2_change_srtt(struct ccid2_hc_tx_sock *hctx, long val) | ||
203 | { | ||
204 | ccid2_pr_debug("change SRTT to %ld\n", val); | ||
205 | hctx->ccid2hctx_srtt = val; | ||
206 | } | ||
207 | |||
208 | static void ccid2_change_pipe(struct ccid2_hc_tx_sock *hctx, long val) | ||
209 | { | ||
210 | hctx->ccid2hctx_pipe = val; | ||
211 | } | ||
212 | |||
167 | static void ccid2_start_rto_timer(struct sock *sk); | 213 | static void ccid2_start_rto_timer(struct sock *sk); |
168 | 214 | ||
169 | static void ccid2_hc_tx_rto_expire(unsigned long data) | 215 | static void ccid2_hc_tx_rto_expire(unsigned long data) |
@@ -193,11 +239,11 @@ static void ccid2_hc_tx_rto_expire(unsigned long data) | |||
193 | ccid2_start_rto_timer(sk); | 239 | ccid2_start_rto_timer(sk); |
194 | 240 | ||
195 | /* adjust pipe, cwnd etc */ | 241 | /* adjust pipe, cwnd etc */ |
196 | hctx->ccid2hctx_pipe = 0; | 242 | ccid2_change_pipe(hctx, 0); |
197 | hctx->ccid2hctx_ssthresh = hctx->ccid2hctx_cwnd >> 1; | 243 | hctx->ccid2hctx_ssthresh = hctx->ccid2hctx_cwnd >> 1; |
198 | if (hctx->ccid2hctx_ssthresh < 2) | 244 | if (hctx->ccid2hctx_ssthresh < 2) |
199 | hctx->ccid2hctx_ssthresh = 2; | 245 | hctx->ccid2hctx_ssthresh = 2; |
200 | ccid2_change_cwnd(sk, 1); | 246 | ccid2_change_cwnd(hctx, 1); |
201 | 247 | ||
202 | /* clear state about stuff we sent */ | 248 | /* clear state about stuff we sent */ |
203 | hctx->ccid2hctx_seqt = hctx->ccid2hctx_seqh; | 249 | hctx->ccid2hctx_seqt = hctx->ccid2hctx_seqh; |
@@ -232,13 +278,14 @@ static void ccid2_hc_tx_packet_sent(struct sock *sk, int more, int len) | |||
232 | { | 278 | { |
233 | struct dccp_sock *dp = dccp_sk(sk); | 279 | struct dccp_sock *dp = dccp_sk(sk); |
234 | struct ccid2_hc_tx_sock *hctx = ccid2_hc_tx_sk(sk); | 280 | struct ccid2_hc_tx_sock *hctx = ccid2_hc_tx_sk(sk); |
281 | struct ccid2_seq *next; | ||
235 | u64 seq; | 282 | u64 seq; |
236 | 283 | ||
237 | ccid2_hc_tx_check_sanity(hctx); | 284 | ccid2_hc_tx_check_sanity(hctx); |
238 | 285 | ||
239 | BUG_ON(!hctx->ccid2hctx_sendwait); | 286 | BUG_ON(!hctx->ccid2hctx_sendwait); |
240 | hctx->ccid2hctx_sendwait = 0; | 287 | hctx->ccid2hctx_sendwait = 0; |
241 | hctx->ccid2hctx_pipe++; | 288 | ccid2_change_pipe(hctx, hctx->ccid2hctx_pipe + 1); |
242 | BUG_ON(hctx->ccid2hctx_pipe < 0); | 289 | BUG_ON(hctx->ccid2hctx_pipe < 0); |
243 | 290 | ||
244 | /* There is an issue. What if another packet is sent between | 291 | /* There is an issue. What if another packet is sent between |
@@ -251,15 +298,23 @@ static void ccid2_hc_tx_packet_sent(struct sock *sk, int more, int len) | |||
251 | hctx->ccid2hctx_seqh->ccid2s_seq = seq; | 298 | hctx->ccid2hctx_seqh->ccid2s_seq = seq; |
252 | hctx->ccid2hctx_seqh->ccid2s_acked = 0; | 299 | hctx->ccid2hctx_seqh->ccid2s_acked = 0; |
253 | hctx->ccid2hctx_seqh->ccid2s_sent = jiffies; | 300 | hctx->ccid2hctx_seqh->ccid2s_sent = jiffies; |
254 | hctx->ccid2hctx_seqh = hctx->ccid2hctx_seqh->ccid2s_next; | ||
255 | 301 | ||
256 | ccid2_pr_debug("cwnd=%d pipe=%d\n", hctx->ccid2hctx_cwnd, | 302 | next = hctx->ccid2hctx_seqh->ccid2s_next; |
257 | hctx->ccid2hctx_pipe); | 303 | /* check if we need to alloc more space */ |
304 | if (next == hctx->ccid2hctx_seqt) { | ||
305 | int rc; | ||
306 | |||
307 | ccid2_pr_debug("allocating more space in history\n"); | ||
308 | rc = ccid2_hc_tx_alloc_seq(hctx, CCID2_SEQBUF_LEN, GFP_KERNEL); | ||
309 | BUG_ON(rc); /* XXX what do we do? */ | ||
258 | 310 | ||
259 | if (hctx->ccid2hctx_seqh == hctx->ccid2hctx_seqt) { | 311 | next = hctx->ccid2hctx_seqh->ccid2s_next; |
260 | /* XXX allocate more space */ | 312 | BUG_ON(next == hctx->ccid2hctx_seqt); |
261 | WARN_ON(1); | ||
262 | } | 313 | } |
314 | hctx->ccid2hctx_seqh = next; | ||
315 | |||
316 | ccid2_pr_debug("cwnd=%d pipe=%d\n", hctx->ccid2hctx_cwnd, | ||
317 | hctx->ccid2hctx_pipe); | ||
263 | 318 | ||
264 | hctx->ccid2hctx_sent++; | 319 | hctx->ccid2hctx_sent++; |
265 | 320 | ||
@@ -295,7 +350,7 @@ static void ccid2_hc_tx_packet_sent(struct sock *sk, int more, int len) | |||
295 | if (!timer_pending(&hctx->ccid2hctx_rtotimer)) | 350 | if (!timer_pending(&hctx->ccid2hctx_rtotimer)) |
296 | ccid2_start_rto_timer(sk); | 351 | ccid2_start_rto_timer(sk); |
297 | 352 | ||
298 | #ifdef CCID2_DEBUG | 353 | #ifdef CONFIG_IP_DCCP_CCID2_DEBUG |
299 | ccid2_pr_debug("pipe=%d\n", hctx->ccid2hctx_pipe); | 354 | ccid2_pr_debug("pipe=%d\n", hctx->ccid2hctx_pipe); |
300 | ccid2_pr_debug("Sent: seq=%llu\n", seq); | 355 | ccid2_pr_debug("Sent: seq=%llu\n", seq); |
301 | do { | 356 | do { |
@@ -398,7 +453,7 @@ static inline void ccid2_new_ack(struct sock *sk, | |||
398 | /* increase every 2 acks */ | 453 | /* increase every 2 acks */ |
399 | hctx->ccid2hctx_ssacks++; | 454 | hctx->ccid2hctx_ssacks++; |
400 | if (hctx->ccid2hctx_ssacks == 2) { | 455 | if (hctx->ccid2hctx_ssacks == 2) { |
401 | ccid2_change_cwnd(sk, hctx->ccid2hctx_cwnd + 1); | 456 | ccid2_change_cwnd(hctx, hctx->ccid2hctx_cwnd+1); |
402 | hctx->ccid2hctx_ssacks = 0; | 457 | hctx->ccid2hctx_ssacks = 0; |
403 | *maxincr = *maxincr - 1; | 458 | *maxincr = *maxincr - 1; |
404 | } | 459 | } |
@@ -411,26 +466,28 @@ static inline void ccid2_new_ack(struct sock *sk, | |||
411 | hctx->ccid2hctx_acks++; | 466 | hctx->ccid2hctx_acks++; |
412 | 467 | ||
413 | if (hctx->ccid2hctx_acks >= hctx->ccid2hctx_cwnd) { | 468 | if (hctx->ccid2hctx_acks >= hctx->ccid2hctx_cwnd) { |
414 | ccid2_change_cwnd(sk, hctx->ccid2hctx_cwnd + 1); | 469 | ccid2_change_cwnd(hctx, hctx->ccid2hctx_cwnd + 1); |
415 | hctx->ccid2hctx_acks = 0; | 470 | hctx->ccid2hctx_acks = 0; |
416 | } | 471 | } |
417 | } | 472 | } |
418 | 473 | ||
419 | /* update RTO */ | 474 | /* update RTO */ |
420 | if (hctx->ccid2hctx_srtt == -1 || | 475 | if (hctx->ccid2hctx_srtt == -1 || |
421 | (jiffies - hctx->ccid2hctx_lastrtt) >= hctx->ccid2hctx_srtt) { | 476 | time_after(jiffies, hctx->ccid2hctx_lastrtt + hctx->ccid2hctx_srtt)) { |
422 | unsigned long r = jiffies - seqp->ccid2s_sent; | 477 | unsigned long r = (long)jiffies - (long)seqp->ccid2s_sent; |
423 | int s; | 478 | int s; |
424 | 479 | ||
425 | /* first measurement */ | 480 | /* first measurement */ |
426 | if (hctx->ccid2hctx_srtt == -1) { | 481 | if (hctx->ccid2hctx_srtt == -1) { |
427 | ccid2_pr_debug("R: %lu Time=%lu seq=%llu\n", | 482 | ccid2_pr_debug("R: %lu Time=%lu seq=%llu\n", |
428 | r, jiffies, seqp->ccid2s_seq); | 483 | r, jiffies, seqp->ccid2s_seq); |
429 | hctx->ccid2hctx_srtt = r; | 484 | ccid2_change_srtt(hctx, r); |
430 | hctx->ccid2hctx_rttvar = r >> 1; | 485 | hctx->ccid2hctx_rttvar = r >> 1; |
431 | } else { | 486 | } else { |
432 | /* RTTVAR */ | 487 | /* RTTVAR */ |
433 | long tmp = hctx->ccid2hctx_srtt - r; | 488 | long tmp = hctx->ccid2hctx_srtt - r; |
489 | long srtt; | ||
490 | |||
434 | if (tmp < 0) | 491 | if (tmp < 0) |
435 | tmp *= -1; | 492 | tmp *= -1; |
436 | 493 | ||
@@ -440,10 +497,12 @@ static inline void ccid2_new_ack(struct sock *sk, | |||
440 | hctx->ccid2hctx_rttvar += tmp; | 497 | hctx->ccid2hctx_rttvar += tmp; |
441 | 498 | ||
442 | /* SRTT */ | 499 | /* SRTT */ |
443 | hctx->ccid2hctx_srtt *= 7; | 500 | srtt = hctx->ccid2hctx_srtt; |
444 | hctx->ccid2hctx_srtt >>= 3; | 501 | srtt *= 7; |
502 | srtt >>= 3; | ||
445 | tmp = r >> 3; | 503 | tmp = r >> 3; |
446 | hctx->ccid2hctx_srtt += tmp; | 504 | srtt += tmp; |
505 | ccid2_change_srtt(hctx, srtt); | ||
447 | } | 506 | } |
448 | s = hctx->ccid2hctx_rttvar << 2; | 507 | s = hctx->ccid2hctx_rttvar << 2; |
449 | /* clock granularity is 1 when based on jiffies */ | 508 | /* clock granularity is 1 when based on jiffies */ |
@@ -479,13 +538,29 @@ static void ccid2_hc_tx_dec_pipe(struct sock *sk) | |||
479 | { | 538 | { |
480 | struct ccid2_hc_tx_sock *hctx = ccid2_hc_tx_sk(sk); | 539 | struct ccid2_hc_tx_sock *hctx = ccid2_hc_tx_sk(sk); |
481 | 540 | ||
482 | hctx->ccid2hctx_pipe--; | 541 | ccid2_change_pipe(hctx, hctx->ccid2hctx_pipe-1); |
483 | BUG_ON(hctx->ccid2hctx_pipe < 0); | 542 | BUG_ON(hctx->ccid2hctx_pipe < 0); |
484 | 543 | ||
485 | if (hctx->ccid2hctx_pipe == 0) | 544 | if (hctx->ccid2hctx_pipe == 0) |
486 | ccid2_hc_tx_kill_rto_timer(sk); | 545 | ccid2_hc_tx_kill_rto_timer(sk); |
487 | } | 546 | } |
488 | 547 | ||
548 | static void ccid2_congestion_event(struct ccid2_hc_tx_sock *hctx, | ||
549 | struct ccid2_seq *seqp) | ||
550 | { | ||
551 | if (time_before(seqp->ccid2s_sent, hctx->ccid2hctx_last_cong)) { | ||
552 | ccid2_pr_debug("Multiple losses in an RTT---treating as one\n"); | ||
553 | return; | ||
554 | } | ||
555 | |||
556 | hctx->ccid2hctx_last_cong = jiffies; | ||
557 | |||
558 | ccid2_change_cwnd(hctx, hctx->ccid2hctx_cwnd >> 1); | ||
559 | hctx->ccid2hctx_ssthresh = hctx->ccid2hctx_cwnd; | ||
560 | if (hctx->ccid2hctx_ssthresh < 2) | ||
561 | hctx->ccid2hctx_ssthresh = 2; | ||
562 | } | ||
563 | |||
489 | static void ccid2_hc_tx_packet_recv(struct sock *sk, struct sk_buff *skb) | 564 | static void ccid2_hc_tx_packet_recv(struct sock *sk, struct sk_buff *skb) |
490 | { | 565 | { |
491 | struct dccp_sock *dp = dccp_sk(sk); | 566 | struct dccp_sock *dp = dccp_sk(sk); |
@@ -496,7 +571,6 @@ static void ccid2_hc_tx_packet_recv(struct sock *sk, struct sk_buff *skb) | |||
496 | unsigned char veclen; | 571 | unsigned char veclen; |
497 | int offset = 0; | 572 | int offset = 0; |
498 | int done = 0; | 573 | int done = 0; |
499 | int loss = 0; | ||
500 | unsigned int maxincr = 0; | 574 | unsigned int maxincr = 0; |
501 | 575 | ||
502 | ccid2_hc_tx_check_sanity(hctx); | 576 | ccid2_hc_tx_check_sanity(hctx); |
@@ -582,15 +656,16 @@ static void ccid2_hc_tx_packet_recv(struct sock *sk, struct sk_buff *skb) | |||
582 | * run length | 656 | * run length |
583 | */ | 657 | */ |
584 | while (between48(seqp->ccid2s_seq,ackno_end_rl,ackno)) { | 658 | while (between48(seqp->ccid2s_seq,ackno_end_rl,ackno)) { |
585 | const u8 state = (*vector & | 659 | const u8 state = *vector & |
586 | DCCP_ACKVEC_STATE_MASK) >> 6; | 660 | DCCP_ACKVEC_STATE_MASK; |
587 | 661 | ||
588 | /* new packet received or marked */ | 662 | /* new packet received or marked */ |
589 | if (state != DCCP_ACKVEC_STATE_NOT_RECEIVED && | 663 | if (state != DCCP_ACKVEC_STATE_NOT_RECEIVED && |
590 | !seqp->ccid2s_acked) { | 664 | !seqp->ccid2s_acked) { |
591 | if (state == | 665 | if (state == |
592 | DCCP_ACKVEC_STATE_ECN_MARKED) { | 666 | DCCP_ACKVEC_STATE_ECN_MARKED) { |
593 | loss = 1; | 667 | ccid2_congestion_event(hctx, |
668 | seqp); | ||
594 | } else | 669 | } else |
595 | ccid2_new_ack(sk, seqp, | 670 | ccid2_new_ack(sk, seqp, |
596 | &maxincr); | 671 | &maxincr); |
@@ -642,7 +717,13 @@ static void ccid2_hc_tx_packet_recv(struct sock *sk, struct sk_buff *skb) | |||
642 | /* check for lost packets */ | 717 | /* check for lost packets */ |
643 | while (1) { | 718 | while (1) { |
644 | if (!seqp->ccid2s_acked) { | 719 | if (!seqp->ccid2s_acked) { |
645 | loss = 1; | 720 | ccid2_pr_debug("Packet lost: %llu\n", |
721 | seqp->ccid2s_seq); | ||
722 | /* XXX need to traverse from tail -> head in | ||
723 | * order to detect multiple congestion events in | ||
724 | * one ack vector. | ||
725 | */ | ||
726 | ccid2_congestion_event(hctx, seqp); | ||
646 | ccid2_hc_tx_dec_pipe(sk); | 727 | ccid2_hc_tx_dec_pipe(sk); |
647 | } | 728 | } |
648 | if (seqp == hctx->ccid2hctx_seqt) | 729 | if (seqp == hctx->ccid2hctx_seqt) |
@@ -661,53 +742,33 @@ static void ccid2_hc_tx_packet_recv(struct sock *sk, struct sk_buff *skb) | |||
661 | hctx->ccid2hctx_seqt = hctx->ccid2hctx_seqt->ccid2s_next; | 742 | hctx->ccid2hctx_seqt = hctx->ccid2hctx_seqt->ccid2s_next; |
662 | } | 743 | } |
663 | 744 | ||
664 | if (loss) { | ||
665 | /* XXX do bit shifts guarantee a 0 as the new bit? */ | ||
666 | ccid2_change_cwnd(sk, hctx->ccid2hctx_cwnd >> 1); | ||
667 | hctx->ccid2hctx_ssthresh = hctx->ccid2hctx_cwnd; | ||
668 | if (hctx->ccid2hctx_ssthresh < 2) | ||
669 | hctx->ccid2hctx_ssthresh = 2; | ||
670 | } | ||
671 | |||
672 | ccid2_hc_tx_check_sanity(hctx); | 745 | ccid2_hc_tx_check_sanity(hctx); |
673 | } | 746 | } |
674 | 747 | ||
675 | static int ccid2_hc_tx_init(struct ccid *ccid, struct sock *sk) | 748 | static int ccid2_hc_tx_init(struct ccid *ccid, struct sock *sk) |
676 | { | 749 | { |
677 | struct ccid2_hc_tx_sock *hctx = ccid_priv(ccid); | 750 | struct ccid2_hc_tx_sock *hctx = ccid_priv(ccid); |
678 | int seqcount = ccid2_seq_len; | ||
679 | int i; | ||
680 | 751 | ||
681 | /* XXX init variables with proper values */ | 752 | ccid2_change_cwnd(hctx, 1); |
682 | hctx->ccid2hctx_cwnd = 1; | 753 | /* Initialize ssthresh to infinity. This means that we will exit the |
683 | hctx->ccid2hctx_ssthresh = 10; | 754 | * initial slow-start after the first packet loss. This is what we |
755 | * want. | ||
756 | */ | ||
757 | hctx->ccid2hctx_ssthresh = ~0; | ||
684 | hctx->ccid2hctx_numdupack = 3; | 758 | hctx->ccid2hctx_numdupack = 3; |
759 | hctx->ccid2hctx_seqbufc = 0; | ||
685 | 760 | ||
686 | /* XXX init ~ to window size... */ | 761 | /* XXX init ~ to window size... */ |
687 | hctx->ccid2hctx_seqbuf = kmalloc(sizeof(*hctx->ccid2hctx_seqbuf) * | 762 | if (ccid2_hc_tx_alloc_seq(hctx, CCID2_SEQBUF_LEN, GFP_ATOMIC) != 0) |
688 | seqcount, gfp_any()); | ||
689 | if (hctx->ccid2hctx_seqbuf == NULL) | ||
690 | return -ENOMEM; | 763 | return -ENOMEM; |
691 | 764 | ||
692 | for (i = 0; i < (seqcount - 1); i++) { | ||
693 | hctx->ccid2hctx_seqbuf[i].ccid2s_next = | ||
694 | &hctx->ccid2hctx_seqbuf[i + 1]; | ||
695 | hctx->ccid2hctx_seqbuf[i + 1].ccid2s_prev = | ||
696 | &hctx->ccid2hctx_seqbuf[i]; | ||
697 | } | ||
698 | hctx->ccid2hctx_seqbuf[seqcount - 1].ccid2s_next = | ||
699 | hctx->ccid2hctx_seqbuf; | ||
700 | hctx->ccid2hctx_seqbuf->ccid2s_prev = | ||
701 | &hctx->ccid2hctx_seqbuf[seqcount - 1]; | ||
702 | |||
703 | hctx->ccid2hctx_seqh = hctx->ccid2hctx_seqbuf; | ||
704 | hctx->ccid2hctx_seqt = hctx->ccid2hctx_seqh; | ||
705 | hctx->ccid2hctx_sent = 0; | 765 | hctx->ccid2hctx_sent = 0; |
706 | hctx->ccid2hctx_rto = 3 * HZ; | 766 | hctx->ccid2hctx_rto = 3 * HZ; |
707 | hctx->ccid2hctx_srtt = -1; | 767 | ccid2_change_srtt(hctx, -1); |
708 | hctx->ccid2hctx_rttvar = -1; | 768 | hctx->ccid2hctx_rttvar = -1; |
709 | hctx->ccid2hctx_lastrtt = 0; | 769 | hctx->ccid2hctx_lastrtt = 0; |
710 | hctx->ccid2hctx_rpdupack = -1; | 770 | hctx->ccid2hctx_rpdupack = -1; |
771 | hctx->ccid2hctx_last_cong = jiffies; | ||
711 | 772 | ||
712 | hctx->ccid2hctx_rtotimer.function = &ccid2_hc_tx_rto_expire; | 773 | hctx->ccid2hctx_rtotimer.function = &ccid2_hc_tx_rto_expire; |
713 | hctx->ccid2hctx_rtotimer.data = (unsigned long)sk; | 774 | hctx->ccid2hctx_rtotimer.data = (unsigned long)sk; |
@@ -720,10 +781,13 @@ static int ccid2_hc_tx_init(struct ccid *ccid, struct sock *sk) | |||
720 | static void ccid2_hc_tx_exit(struct sock *sk) | 781 | static void ccid2_hc_tx_exit(struct sock *sk) |
721 | { | 782 | { |
722 | struct ccid2_hc_tx_sock *hctx = ccid2_hc_tx_sk(sk); | 783 | struct ccid2_hc_tx_sock *hctx = ccid2_hc_tx_sk(sk); |
784 | int i; | ||
723 | 785 | ||
724 | ccid2_hc_tx_kill_rto_timer(sk); | 786 | ccid2_hc_tx_kill_rto_timer(sk); |
725 | kfree(hctx->ccid2hctx_seqbuf); | 787 | |
726 | hctx->ccid2hctx_seqbuf = NULL; | 788 | for (i = 0; i < hctx->ccid2hctx_seqbufc; i++) |
789 | kfree(hctx->ccid2hctx_seqbuf[i]); | ||
790 | hctx->ccid2hctx_seqbufc = 0; | ||
727 | } | 791 | } |
728 | 792 | ||
729 | static void ccid2_hc_rx_packet_recv(struct sock *sk, struct sk_buff *skb) | 793 | static void ccid2_hc_rx_packet_recv(struct sock *sk, struct sk_buff *skb) |
diff --git a/net/dccp/ccids/ccid2.h b/net/dccp/ccids/ccid2.h index 451a87464fa5..5b2ef4acb300 100644 --- a/net/dccp/ccids/ccid2.h +++ b/net/dccp/ccids/ccid2.h | |||
@@ -35,6 +35,9 @@ struct ccid2_seq { | |||
35 | struct ccid2_seq *ccid2s_next; | 35 | struct ccid2_seq *ccid2s_next; |
36 | }; | 36 | }; |
37 | 37 | ||
38 | #define CCID2_SEQBUF_LEN 256 | ||
39 | #define CCID2_SEQBUF_MAX 128 | ||
40 | |||
38 | /** struct ccid2_hc_tx_sock - CCID2 TX half connection | 41 | /** struct ccid2_hc_tx_sock - CCID2 TX half connection |
39 | * | 42 | * |
40 | * @ccid2hctx_ssacks - ACKs recv in slow start | 43 | * @ccid2hctx_ssacks - ACKs recv in slow start |
@@ -50,10 +53,11 @@ struct ccid2_hc_tx_sock { | |||
50 | int ccid2hctx_cwnd; | 53 | int ccid2hctx_cwnd; |
51 | int ccid2hctx_ssacks; | 54 | int ccid2hctx_ssacks; |
52 | int ccid2hctx_acks; | 55 | int ccid2hctx_acks; |
53 | int ccid2hctx_ssthresh; | 56 | unsigned int ccid2hctx_ssthresh; |
54 | int ccid2hctx_pipe; | 57 | int ccid2hctx_pipe; |
55 | int ccid2hctx_numdupack; | 58 | int ccid2hctx_numdupack; |
56 | struct ccid2_seq *ccid2hctx_seqbuf; | 59 | struct ccid2_seq *ccid2hctx_seqbuf[CCID2_SEQBUF_MAX]; |
60 | int ccid2hctx_seqbufc; | ||
57 | struct ccid2_seq *ccid2hctx_seqh; | 61 | struct ccid2_seq *ccid2hctx_seqh; |
58 | struct ccid2_seq *ccid2hctx_seqt; | 62 | struct ccid2_seq *ccid2hctx_seqt; |
59 | long ccid2hctx_rto; | 63 | long ccid2hctx_rto; |
@@ -67,6 +71,7 @@ struct ccid2_hc_tx_sock { | |||
67 | u64 ccid2hctx_rpseq; | 71 | u64 ccid2hctx_rpseq; |
68 | int ccid2hctx_rpdupack; | 72 | int ccid2hctx_rpdupack; |
69 | int ccid2hctx_sendwait; | 73 | int ccid2hctx_sendwait; |
74 | unsigned long ccid2hctx_last_cong; | ||
70 | }; | 75 | }; |
71 | 76 | ||
72 | struct ccid2_hc_rx_sock { | 77 | struct ccid2_hc_rx_sock { |
diff --git a/net/dccp/ccids/ccid3.c b/net/dccp/ccids/ccid3.c index 090bc39e8199..195aa9566228 100644 --- a/net/dccp/ccids/ccid3.c +++ b/net/dccp/ccids/ccid3.c | |||
@@ -900,7 +900,7 @@ found: | |||
900 | static void ccid3_hc_rx_update_li(struct sock *sk, u64 seq_loss, u8 win_loss) | 900 | static void ccid3_hc_rx_update_li(struct sock *sk, u64 seq_loss, u8 win_loss) |
901 | { | 901 | { |
902 | struct ccid3_hc_rx_sock *hcrx = ccid3_hc_rx_sk(sk); | 902 | struct ccid3_hc_rx_sock *hcrx = ccid3_hc_rx_sk(sk); |
903 | struct dccp_li_hist_entry *next, *head; | 903 | struct dccp_li_hist_entry *head; |
904 | u64 seq_temp; | 904 | u64 seq_temp; |
905 | 905 | ||
906 | if (list_empty(&hcrx->ccid3hcrx_li_hist)) { | 906 | if (list_empty(&hcrx->ccid3hcrx_li_hist)) { |
@@ -908,15 +908,15 @@ static void ccid3_hc_rx_update_li(struct sock *sk, u64 seq_loss, u8 win_loss) | |||
908 | &hcrx->ccid3hcrx_li_hist, seq_loss, win_loss)) | 908 | &hcrx->ccid3hcrx_li_hist, seq_loss, win_loss)) |
909 | return; | 909 | return; |
910 | 910 | ||
911 | next = (struct dccp_li_hist_entry *) | 911 | head = list_entry(hcrx->ccid3hcrx_li_hist.next, |
912 | hcrx->ccid3hcrx_li_hist.next; | 912 | struct dccp_li_hist_entry, dccplih_node); |
913 | next->dccplih_interval = ccid3_hc_rx_calc_first_li(sk); | 913 | head->dccplih_interval = ccid3_hc_rx_calc_first_li(sk); |
914 | } else { | 914 | } else { |
915 | struct dccp_li_hist_entry *entry; | 915 | struct dccp_li_hist_entry *entry; |
916 | struct list_head *tail; | 916 | struct list_head *tail; |
917 | 917 | ||
918 | head = (struct dccp_li_hist_entry *) | 918 | head = list_entry(hcrx->ccid3hcrx_li_hist.next, |
919 | hcrx->ccid3hcrx_li_hist.next; | 919 | struct dccp_li_hist_entry, dccplih_node); |
920 | /* FIXME win count check removed as was wrong */ | 920 | /* FIXME win count check removed as was wrong */ |
921 | /* should make this check with receive history */ | 921 | /* should make this check with receive history */ |
922 | /* and compare there as per section 10.2 of RFC4342 */ | 922 | /* and compare there as per section 10.2 of RFC4342 */ |
diff --git a/net/dccp/dccp.h b/net/dccp/dccp.h index a5c5475724c0..0a21be437ed3 100644 --- a/net/dccp/dccp.h +++ b/net/dccp/dccp.h | |||
@@ -130,7 +130,7 @@ extern void dccp_send_delayed_ack(struct sock *sk); | |||
130 | extern void dccp_send_sync(struct sock *sk, const u64 seq, | 130 | extern void dccp_send_sync(struct sock *sk, const u64 seq, |
131 | const enum dccp_pkt_type pkt_type); | 131 | const enum dccp_pkt_type pkt_type); |
132 | 132 | ||
133 | extern int dccp_write_xmit(struct sock *sk, struct sk_buff *skb, long *timeo); | 133 | extern void dccp_write_xmit(struct sock *sk, int block); |
134 | extern void dccp_write_space(struct sock *sk); | 134 | extern void dccp_write_space(struct sock *sk); |
135 | 135 | ||
136 | extern void dccp_init_xmit_timers(struct sock *sk); | 136 | extern void dccp_init_xmit_timers(struct sock *sk); |
diff --git a/net/dccp/feat.h b/net/dccp/feat.h index b44c45504fb6..cee553d416ca 100644 --- a/net/dccp/feat.h +++ b/net/dccp/feat.h | |||
@@ -27,5 +27,10 @@ extern int dccp_feat_clone(struct sock *oldsk, struct sock *newsk); | |||
27 | extern int dccp_feat_init(struct dccp_minisock *dmsk); | 27 | extern int dccp_feat_init(struct dccp_minisock *dmsk); |
28 | 28 | ||
29 | extern int dccp_feat_default_sequence_window; | 29 | extern int dccp_feat_default_sequence_window; |
30 | extern int dccp_feat_default_rx_ccid; | ||
31 | extern int dccp_feat_default_tx_ccid; | ||
32 | extern int dccp_feat_default_ack_ratio; | ||
33 | extern int dccp_feat_default_send_ack_vector; | ||
34 | extern int dccp_feat_default_send_ndp_count; | ||
30 | 35 | ||
31 | #endif /* _DCCP_FEAT_H */ | 36 | #endif /* _DCCP_FEAT_H */ |
diff --git a/net/dccp/ipv4.c b/net/dccp/ipv4.c index 7f56f7e8f571..9a1a76a7dc41 100644 --- a/net/dccp/ipv4.c +++ b/net/dccp/ipv4.c | |||
@@ -501,6 +501,9 @@ int dccp_v4_conn_request(struct sock *sk, struct sk_buff *skb) | |||
501 | 501 | ||
502 | dccp_openreq_init(req, &dp, skb); | 502 | dccp_openreq_init(req, &dp, skb); |
503 | 503 | ||
504 | if (security_inet_conn_request(sk, skb, req)) | ||
505 | goto drop_and_free; | ||
506 | |||
504 | ireq = inet_rsk(req); | 507 | ireq = inet_rsk(req); |
505 | ireq->loc_addr = daddr; | 508 | ireq->loc_addr = daddr; |
506 | ireq->rmt_addr = saddr; | 509 | ireq->rmt_addr = saddr; |
@@ -605,10 +608,10 @@ static struct sock *dccp_v4_hnd_req(struct sock *sk, struct sk_buff *skb) | |||
605 | if (req != NULL) | 608 | if (req != NULL) |
606 | return dccp_check_req(sk, skb, req, prev); | 609 | return dccp_check_req(sk, skb, req, prev); |
607 | 610 | ||
608 | nsk = __inet_lookup_established(&dccp_hashinfo, | 611 | nsk = inet_lookup_established(&dccp_hashinfo, |
609 | iph->saddr, dh->dccph_sport, | 612 | iph->saddr, dh->dccph_sport, |
610 | iph->daddr, ntohs(dh->dccph_dport), | 613 | iph->daddr, dh->dccph_dport, |
611 | inet_iif(skb)); | 614 | inet_iif(skb)); |
612 | if (nsk != NULL) { | 615 | if (nsk != NULL) { |
613 | if (nsk->sk_state != DCCP_TIME_WAIT) { | 616 | if (nsk->sk_state != DCCP_TIME_WAIT) { |
614 | bh_lock_sock(nsk); | 617 | bh_lock_sock(nsk); |
@@ -678,6 +681,7 @@ static struct dst_entry* dccp_v4_route_skb(struct sock *sk, | |||
678 | } | 681 | } |
679 | }; | 682 | }; |
680 | 683 | ||
684 | security_skb_classify_flow(skb, &fl); | ||
681 | if (ip_route_output_flow(&rt, &fl, sk, 0)) { | 685 | if (ip_route_output_flow(&rt, &fl, sk, 0)) { |
682 | IP_INC_STATS_BH(IPSTATS_MIB_OUTNOROUTES); | 686 | IP_INC_STATS_BH(IPSTATS_MIB_OUTNOROUTES); |
683 | return NULL; | 687 | return NULL; |
@@ -921,7 +925,7 @@ static int dccp_v4_rcv(struct sk_buff *skb) | |||
921 | * Look up flow ID in table and get corresponding socket */ | 925 | * Look up flow ID in table and get corresponding socket */ |
922 | sk = __inet_lookup(&dccp_hashinfo, | 926 | sk = __inet_lookup(&dccp_hashinfo, |
923 | skb->nh.iph->saddr, dh->dccph_sport, | 927 | skb->nh.iph->saddr, dh->dccph_sport, |
924 | skb->nh.iph->daddr, ntohs(dh->dccph_dport), | 928 | skb->nh.iph->daddr, dh->dccph_dport, |
925 | inet_iif(skb)); | 929 | inet_iif(skb)); |
926 | 930 | ||
927 | /* | 931 | /* |
diff --git a/net/dccp/ipv6.c b/net/dccp/ipv6.c index 610c722ac27f..7a47399cf31f 100644 --- a/net/dccp/ipv6.c +++ b/net/dccp/ipv6.c | |||
@@ -201,6 +201,7 @@ static int dccp_v6_connect(struct sock *sk, struct sockaddr *uaddr, | |||
201 | fl.oif = sk->sk_bound_dev_if; | 201 | fl.oif = sk->sk_bound_dev_if; |
202 | fl.fl_ip_dport = usin->sin6_port; | 202 | fl.fl_ip_dport = usin->sin6_port; |
203 | fl.fl_ip_sport = inet->sport; | 203 | fl.fl_ip_sport = inet->sport; |
204 | security_sk_classify_flow(sk, &fl); | ||
204 | 205 | ||
205 | if (np->opt != NULL && np->opt->srcrt != NULL) { | 206 | if (np->opt != NULL && np->opt->srcrt != NULL) { |
206 | const struct rt0_hdr *rt0 = (struct rt0_hdr *)np->opt->srcrt; | 207 | const struct rt0_hdr *rt0 = (struct rt0_hdr *)np->opt->srcrt; |
@@ -230,7 +231,7 @@ static int dccp_v6_connect(struct sock *sk, struct sockaddr *uaddr, | |||
230 | ipv6_addr_copy(&np->saddr, saddr); | 231 | ipv6_addr_copy(&np->saddr, saddr); |
231 | inet->rcv_saddr = LOOPBACK4_IPV6; | 232 | inet->rcv_saddr = LOOPBACK4_IPV6; |
232 | 233 | ||
233 | __ip6_dst_store(sk, dst, NULL); | 234 | __ip6_dst_store(sk, dst, NULL, NULL); |
234 | 235 | ||
235 | icsk->icsk_ext_hdr_len = 0; | 236 | icsk->icsk_ext_hdr_len = 0; |
236 | if (np->opt != NULL) | 237 | if (np->opt != NULL) |
@@ -322,6 +323,7 @@ static void dccp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, | |||
322 | fl.oif = sk->sk_bound_dev_if; | 323 | fl.oif = sk->sk_bound_dev_if; |
323 | fl.fl_ip_dport = inet->dport; | 324 | fl.fl_ip_dport = inet->dport; |
324 | fl.fl_ip_sport = inet->sport; | 325 | fl.fl_ip_sport = inet->sport; |
326 | security_sk_classify_flow(sk, &fl); | ||
325 | 327 | ||
326 | err = ip6_dst_lookup(sk, &dst, &fl); | 328 | err = ip6_dst_lookup(sk, &dst, &fl); |
327 | if (err) { | 329 | if (err) { |
@@ -422,6 +424,7 @@ static int dccp_v6_send_response(struct sock *sk, struct request_sock *req, | |||
422 | fl.oif = ireq6->iif; | 424 | fl.oif = ireq6->iif; |
423 | fl.fl_ip_dport = inet_rsk(req)->rmt_port; | 425 | fl.fl_ip_dport = inet_rsk(req)->rmt_port; |
424 | fl.fl_ip_sport = inet_sk(sk)->sport; | 426 | fl.fl_ip_sport = inet_sk(sk)->sport; |
427 | security_req_classify_flow(req, &fl); | ||
425 | 428 | ||
426 | if (dst == NULL) { | 429 | if (dst == NULL) { |
427 | opt = np->opt; | 430 | opt = np->opt; |
@@ -566,6 +569,7 @@ static void dccp_v6_ctl_send_reset(struct sk_buff *rxskb) | |||
566 | fl.oif = inet6_iif(rxskb); | 569 | fl.oif = inet6_iif(rxskb); |
567 | fl.fl_ip_dport = dh->dccph_dport; | 570 | fl.fl_ip_dport = dh->dccph_dport; |
568 | fl.fl_ip_sport = dh->dccph_sport; | 571 | fl.fl_ip_sport = dh->dccph_sport; |
572 | security_skb_classify_flow(rxskb, &fl); | ||
569 | 573 | ||
570 | /* sk = NULL, but it is safe for now. RST socket required. */ | 574 | /* sk = NULL, but it is safe for now. RST socket required. */ |
571 | if (!ip6_dst_lookup(NULL, &skb->dst, &fl)) { | 575 | if (!ip6_dst_lookup(NULL, &skb->dst, &fl)) { |
@@ -622,6 +626,7 @@ static void dccp_v6_reqsk_send_ack(struct sk_buff *rxskb, | |||
622 | fl.oif = inet6_iif(rxskb); | 626 | fl.oif = inet6_iif(rxskb); |
623 | fl.fl_ip_dport = dh->dccph_dport; | 627 | fl.fl_ip_dport = dh->dccph_dport; |
624 | fl.fl_ip_sport = dh->dccph_sport; | 628 | fl.fl_ip_sport = dh->dccph_sport; |
629 | security_req_classify_flow(req, &fl); | ||
625 | 630 | ||
626 | if (!ip6_dst_lookup(NULL, &skb->dst, &fl)) { | 631 | if (!ip6_dst_lookup(NULL, &skb->dst, &fl)) { |
627 | if (xfrm_lookup(&skb->dst, &fl, NULL, 0) >= 0) { | 632 | if (xfrm_lookup(&skb->dst, &fl, NULL, 0) >= 0) { |
@@ -704,6 +709,9 @@ static int dccp_v6_conn_request(struct sock *sk, struct sk_buff *skb) | |||
704 | 709 | ||
705 | dccp_openreq_init(req, &dp, skb); | 710 | dccp_openreq_init(req, &dp, skb); |
706 | 711 | ||
712 | if (security_inet_conn_request(sk, skb, req)) | ||
713 | goto drop_and_free; | ||
714 | |||
707 | ireq6 = inet6_rsk(req); | 715 | ireq6 = inet6_rsk(req); |
708 | ireq = inet_rsk(req); | 716 | ireq = inet_rsk(req); |
709 | ipv6_addr_copy(&ireq6->rmt_addr, &skb->nh.ipv6h->saddr); | 717 | ipv6_addr_copy(&ireq6->rmt_addr, &skb->nh.ipv6h->saddr); |
@@ -842,6 +850,7 @@ static struct sock *dccp_v6_request_recv_sock(struct sock *sk, | |||
842 | fl.oif = sk->sk_bound_dev_if; | 850 | fl.oif = sk->sk_bound_dev_if; |
843 | fl.fl_ip_dport = inet_rsk(req)->rmt_port; | 851 | fl.fl_ip_dport = inet_rsk(req)->rmt_port; |
844 | fl.fl_ip_sport = inet_sk(sk)->sport; | 852 | fl.fl_ip_sport = inet_sk(sk)->sport; |
853 | security_sk_classify_flow(sk, &fl); | ||
845 | 854 | ||
846 | if (ip6_dst_lookup(sk, &dst, &fl)) | 855 | if (ip6_dst_lookup(sk, &dst, &fl)) |
847 | goto out; | 856 | goto out; |
@@ -863,7 +872,7 @@ static struct sock *dccp_v6_request_recv_sock(struct sock *sk, | |||
863 | * comment in that function for the gory details. -acme | 872 | * comment in that function for the gory details. -acme |
864 | */ | 873 | */ |
865 | 874 | ||
866 | __ip6_dst_store(newsk, dst, NULL); | 875 | __ip6_dst_store(newsk, dst, NULL, NULL); |
867 | newsk->sk_route_caps = dst->dev->features & ~(NETIF_F_IP_CSUM | | 876 | newsk->sk_route_caps = dst->dev->features & ~(NETIF_F_IP_CSUM | |
868 | NETIF_F_TSO); | 877 | NETIF_F_TSO); |
869 | newdp6 = (struct dccp6_sock *)newsk; | 878 | newdp6 = (struct dccp6_sock *)newsk; |
@@ -961,7 +970,7 @@ static int dccp_v6_do_rcv(struct sock *sk, struct sk_buff *skb) | |||
961 | if (skb->protocol == htons(ETH_P_IP)) | 970 | if (skb->protocol == htons(ETH_P_IP)) |
962 | return dccp_v4_do_rcv(sk, skb); | 971 | return dccp_v4_do_rcv(sk, skb); |
963 | 972 | ||
964 | if (sk_filter(sk, skb, 0)) | 973 | if (sk_filter(sk, skb)) |
965 | goto discard; | 974 | goto discard; |
966 | 975 | ||
967 | /* | 976 | /* |
diff --git a/net/dccp/output.c b/net/dccp/output.c index 58669beee132..7102e3aed4ca 100644 --- a/net/dccp/output.c +++ b/net/dccp/output.c | |||
@@ -198,7 +198,7 @@ static int dccp_wait_for_ccid(struct sock *sk, struct sk_buff *skb, | |||
198 | while (1) { | 198 | while (1) { |
199 | prepare_to_wait(sk->sk_sleep, &wait, TASK_INTERRUPTIBLE); | 199 | prepare_to_wait(sk->sk_sleep, &wait, TASK_INTERRUPTIBLE); |
200 | 200 | ||
201 | if (sk->sk_err || (sk->sk_shutdown & SEND_SHUTDOWN)) | 201 | if (sk->sk_err) |
202 | goto do_error; | 202 | goto do_error; |
203 | if (!*timeo) | 203 | if (!*timeo) |
204 | goto do_nonblock; | 204 | goto do_nonblock; |
@@ -234,37 +234,72 @@ do_interrupted: | |||
234 | goto out; | 234 | goto out; |
235 | } | 235 | } |
236 | 236 | ||
237 | int dccp_write_xmit(struct sock *sk, struct sk_buff *skb, long *timeo) | 237 | static void dccp_write_xmit_timer(unsigned long data) { |
238 | struct sock *sk = (struct sock *)data; | ||
239 | struct dccp_sock *dp = dccp_sk(sk); | ||
240 | |||
241 | bh_lock_sock(sk); | ||
242 | if (sock_owned_by_user(sk)) | ||
243 | sk_reset_timer(sk, &dp->dccps_xmit_timer, jiffies+1); | ||
244 | else | ||
245 | dccp_write_xmit(sk, 0); | ||
246 | bh_unlock_sock(sk); | ||
247 | sock_put(sk); | ||
248 | } | ||
249 | |||
250 | void dccp_write_xmit(struct sock *sk, int block) | ||
238 | { | 251 | { |
239 | const struct dccp_sock *dp = dccp_sk(sk); | 252 | struct dccp_sock *dp = dccp_sk(sk); |
240 | int err = ccid_hc_tx_send_packet(dp->dccps_hc_tx_ccid, sk, skb, | 253 | struct sk_buff *skb; |
254 | long timeo = 30000; /* If a packet is taking longer than 2 secs | ||
255 | we have other issues */ | ||
256 | |||
257 | while ((skb = skb_peek(&sk->sk_write_queue))) { | ||
258 | int err = ccid_hc_tx_send_packet(dp->dccps_hc_tx_ccid, sk, skb, | ||
241 | skb->len); | 259 | skb->len); |
242 | 260 | ||
243 | if (err > 0) | 261 | if (err > 0) { |
244 | err = dccp_wait_for_ccid(sk, skb, timeo); | 262 | if (!block) { |
263 | sk_reset_timer(sk, &dp->dccps_xmit_timer, | ||
264 | msecs_to_jiffies(err)+jiffies); | ||
265 | break; | ||
266 | } else | ||
267 | err = dccp_wait_for_ccid(sk, skb, &timeo); | ||
268 | if (err) { | ||
269 | printk(KERN_CRIT "%s:err at dccp_wait_for_ccid" | ||
270 | " %d\n", __FUNCTION__, err); | ||
271 | dump_stack(); | ||
272 | } | ||
273 | } | ||
245 | 274 | ||
246 | if (err == 0) { | 275 | skb_dequeue(&sk->sk_write_queue); |
247 | struct dccp_skb_cb *dcb = DCCP_SKB_CB(skb); | 276 | if (err == 0) { |
248 | const int len = skb->len; | 277 | struct dccp_skb_cb *dcb = DCCP_SKB_CB(skb); |
278 | const int len = skb->len; | ||
249 | 279 | ||
250 | if (sk->sk_state == DCCP_PARTOPEN) { | 280 | if (sk->sk_state == DCCP_PARTOPEN) { |
251 | /* See 8.1.5. Handshake Completion */ | 281 | /* See 8.1.5. Handshake Completion */ |
252 | inet_csk_schedule_ack(sk); | 282 | inet_csk_schedule_ack(sk); |
253 | inet_csk_reset_xmit_timer(sk, ICSK_TIME_DACK, | 283 | inet_csk_reset_xmit_timer(sk, ICSK_TIME_DACK, |
254 | inet_csk(sk)->icsk_rto, | 284 | inet_csk(sk)->icsk_rto, |
255 | DCCP_RTO_MAX); | 285 | DCCP_RTO_MAX); |
256 | dcb->dccpd_type = DCCP_PKT_DATAACK; | 286 | dcb->dccpd_type = DCCP_PKT_DATAACK; |
257 | } else if (dccp_ack_pending(sk)) | 287 | } else if (dccp_ack_pending(sk)) |
258 | dcb->dccpd_type = DCCP_PKT_DATAACK; | 288 | dcb->dccpd_type = DCCP_PKT_DATAACK; |
259 | else | 289 | else |
260 | dcb->dccpd_type = DCCP_PKT_DATA; | 290 | dcb->dccpd_type = DCCP_PKT_DATA; |
261 | 291 | ||
262 | err = dccp_transmit_skb(sk, skb); | 292 | err = dccp_transmit_skb(sk, skb); |
263 | ccid_hc_tx_packet_sent(dp->dccps_hc_tx_ccid, sk, 0, len); | 293 | ccid_hc_tx_packet_sent(dp->dccps_hc_tx_ccid, sk, 0, len); |
264 | } else | 294 | if (err) { |
265 | kfree_skb(skb); | 295 | printk(KERN_CRIT "%s:err from " |
266 | 296 | "ccid_hc_tx_packet_sent %d\n", | |
267 | return err; | 297 | __FUNCTION__, err); |
298 | dump_stack(); | ||
299 | } | ||
300 | } else | ||
301 | kfree(skb); | ||
302 | } | ||
268 | } | 303 | } |
269 | 304 | ||
270 | int dccp_retransmit_skb(struct sock *sk, struct sk_buff *skb) | 305 | int dccp_retransmit_skb(struct sock *sk, struct sk_buff *skb) |
@@ -426,6 +461,9 @@ static inline void dccp_connect_init(struct sock *sk) | |||
426 | dccp_set_seqno(&dp->dccps_awl, max48(dp->dccps_awl, dp->dccps_iss)); | 461 | dccp_set_seqno(&dp->dccps_awl, max48(dp->dccps_awl, dp->dccps_iss)); |
427 | 462 | ||
428 | icsk->icsk_retransmits = 0; | 463 | icsk->icsk_retransmits = 0; |
464 | init_timer(&dp->dccps_xmit_timer); | ||
465 | dp->dccps_xmit_timer.data = (unsigned long)sk; | ||
466 | dp->dccps_xmit_timer.function = dccp_write_xmit_timer; | ||
429 | } | 467 | } |
430 | 468 | ||
431 | int dccp_connect(struct sock *sk) | 469 | int dccp_connect(struct sock *sk) |
@@ -560,8 +598,10 @@ void dccp_send_close(struct sock *sk, const int active) | |||
560 | DCCP_PKT_CLOSE : DCCP_PKT_CLOSEREQ; | 598 | DCCP_PKT_CLOSE : DCCP_PKT_CLOSEREQ; |
561 | 599 | ||
562 | if (active) { | 600 | if (active) { |
601 | dccp_write_xmit(sk, 1); | ||
563 | dccp_skb_entail(sk, skb); | 602 | dccp_skb_entail(sk, skb); |
564 | dccp_transmit_skb(sk, skb_clone(skb, prio)); | 603 | dccp_transmit_skb(sk, skb_clone(skb, prio)); |
604 | /* FIXME do we need a retransmit timer here? */ | ||
565 | } else | 605 | } else |
566 | dccp_transmit_skb(sk, skb); | 606 | dccp_transmit_skb(sk, skb); |
567 | } | 607 | } |
diff --git a/net/dccp/proto.c b/net/dccp/proto.c index 6f14bb5a28d4..962df0ea31aa 100644 --- a/net/dccp/proto.c +++ b/net/dccp/proto.c | |||
@@ -662,17 +662,8 @@ int dccp_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, | |||
662 | if (rc != 0) | 662 | if (rc != 0) |
663 | goto out_discard; | 663 | goto out_discard; |
664 | 664 | ||
665 | rc = dccp_write_xmit(sk, skb, &timeo); | 665 | skb_queue_tail(&sk->sk_write_queue, skb); |
666 | /* | 666 | dccp_write_xmit(sk,0); |
667 | * XXX we don't use sk_write_queue, so just discard the packet. | ||
668 | * Current plan however is to _use_ sk_write_queue with | ||
669 | * an algorith similar to tcp_sendmsg, where the main difference | ||
670 | * is that in DCCP we have to respect packet boundaries, so | ||
671 | * no coalescing of skbs. | ||
672 | * | ||
673 | * This bug was _quickly_ found & fixed by just looking at an OSTRA | ||
674 | * generated callgraph 8) -acme | ||
675 | */ | ||
676 | out_release: | 667 | out_release: |
677 | release_sock(sk); | 668 | release_sock(sk); |
678 | return rc ? : len; | 669 | return rc ? : len; |
@@ -846,6 +837,7 @@ static int dccp_close_state(struct sock *sk) | |||
846 | 837 | ||
847 | void dccp_close(struct sock *sk, long timeout) | 838 | void dccp_close(struct sock *sk, long timeout) |
848 | { | 839 | { |
840 | struct dccp_sock *dp = dccp_sk(sk); | ||
849 | struct sk_buff *skb; | 841 | struct sk_buff *skb; |
850 | int state; | 842 | int state; |
851 | 843 | ||
@@ -862,6 +854,8 @@ void dccp_close(struct sock *sk, long timeout) | |||
862 | goto adjudge_to_death; | 854 | goto adjudge_to_death; |
863 | } | 855 | } |
864 | 856 | ||
857 | sk_stop_timer(sk, &dp->dccps_xmit_timer); | ||
858 | |||
865 | /* | 859 | /* |
866 | * We need to flush the recv. buffs. We do this only on the | 860 | * We need to flush the recv. buffs. We do this only on the |
867 | * descriptor close, not protocol-sourced closes, because the | 861 | * descriptor close, not protocol-sourced closes, because the |
diff --git a/net/dccp/sysctl.c b/net/dccp/sysctl.c index c1ba9451bc3d..38bc157876f3 100644 --- a/net/dccp/sysctl.c +++ b/net/dccp/sysctl.c | |||
@@ -11,18 +11,12 @@ | |||
11 | 11 | ||
12 | #include <linux/mm.h> | 12 | #include <linux/mm.h> |
13 | #include <linux/sysctl.h> | 13 | #include <linux/sysctl.h> |
14 | #include "feat.h" | ||
14 | 15 | ||
15 | #ifndef CONFIG_SYSCTL | 16 | #ifndef CONFIG_SYSCTL |
16 | #error This file should not be compiled without CONFIG_SYSCTL defined | 17 | #error This file should not be compiled without CONFIG_SYSCTL defined |
17 | #endif | 18 | #endif |
18 | 19 | ||
19 | extern int dccp_feat_default_sequence_window; | ||
20 | extern int dccp_feat_default_rx_ccid; | ||
21 | extern int dccp_feat_default_tx_ccid; | ||
22 | extern int dccp_feat_default_ack_ratio; | ||
23 | extern int dccp_feat_default_send_ack_vector; | ||
24 | extern int dccp_feat_default_send_ndp_count; | ||
25 | |||
26 | static struct ctl_table dccp_default_table[] = { | 20 | static struct ctl_table dccp_default_table[] = { |
27 | { | 21 | { |
28 | .ctl_name = NET_DCCP_DEFAULT_SEQ_WINDOW, | 22 | .ctl_name = NET_DCCP_DEFAULT_SEQ_WINDOW, |
diff --git a/net/decnet/Kconfig b/net/decnet/Kconfig index 92f2ec46fd22..36e72cb145b0 100644 --- a/net/decnet/Kconfig +++ b/net/decnet/Kconfig | |||
@@ -27,6 +27,7 @@ config DECNET | |||
27 | config DECNET_ROUTER | 27 | config DECNET_ROUTER |
28 | bool "DECnet: router support (EXPERIMENTAL)" | 28 | bool "DECnet: router support (EXPERIMENTAL)" |
29 | depends on DECNET && EXPERIMENTAL | 29 | depends on DECNET && EXPERIMENTAL |
30 | select FIB_RULES | ||
30 | ---help--- | 31 | ---help--- |
31 | Add support for turning your DECnet Endnode into a level 1 or 2 | 32 | Add support for turning your DECnet Endnode into a level 1 or 2 |
32 | router. This is an experimental, but functional option. If you | 33 | router. This is an experimental, but functional option. If you |
diff --git a/net/decnet/af_decnet.c b/net/decnet/af_decnet.c index 5486247735f6..70e027375682 100644 --- a/net/decnet/af_decnet.c +++ b/net/decnet/af_decnet.c | |||
@@ -130,6 +130,7 @@ Version 0.0.6 2.1.110 07-aug-98 Eduardo Marcelo Serrat | |||
130 | #include <linux/poll.h> | 130 | #include <linux/poll.h> |
131 | #include <net/neighbour.h> | 131 | #include <net/neighbour.h> |
132 | #include <net/dst.h> | 132 | #include <net/dst.h> |
133 | #include <net/fib_rules.h> | ||
133 | #include <net/dn.h> | 134 | #include <net/dn.h> |
134 | #include <net/dn_nsp.h> | 135 | #include <net/dn_nsp.h> |
135 | #include <net/dn_dev.h> | 136 | #include <net/dn_dev.h> |
diff --git a/net/decnet/dn_dev.c b/net/decnet/dn_dev.c index 476455fbdb03..01861feb608d 100644 --- a/net/decnet/dn_dev.c +++ b/net/decnet/dn_dev.c | |||
@@ -34,6 +34,7 @@ | |||
34 | #include <linux/seq_file.h> | 34 | #include <linux/seq_file.h> |
35 | #include <linux/timer.h> | 35 | #include <linux/timer.h> |
36 | #include <linux/string.h> | 36 | #include <linux/string.h> |
37 | #include <linux/if_addr.h> | ||
37 | #include <linux/if_arp.h> | 38 | #include <linux/if_arp.h> |
38 | #include <linux/if_ether.h> | 39 | #include <linux/if_ether.h> |
39 | #include <linux/skbuff.h> | 40 | #include <linux/skbuff.h> |
@@ -45,6 +46,7 @@ | |||
45 | #include <net/neighbour.h> | 46 | #include <net/neighbour.h> |
46 | #include <net/dst.h> | 47 | #include <net/dst.h> |
47 | #include <net/flow.h> | 48 | #include <net/flow.h> |
49 | #include <net/fib_rules.h> | ||
48 | #include <net/dn.h> | 50 | #include <net/dn.h> |
49 | #include <net/dn_dev.h> | 51 | #include <net/dn_dev.h> |
50 | #include <net/dn_route.h> | 52 | #include <net/dn_route.h> |
@@ -744,20 +746,23 @@ rtattr_failure: | |||
744 | static void rtmsg_ifa(int event, struct dn_ifaddr *ifa) | 746 | static void rtmsg_ifa(int event, struct dn_ifaddr *ifa) |
745 | { | 747 | { |
746 | struct sk_buff *skb; | 748 | struct sk_buff *skb; |
747 | int size = NLMSG_SPACE(sizeof(struct ifaddrmsg)+128); | 749 | int payload = sizeof(struct ifaddrmsg) + 128; |
750 | int err = -ENOBUFS; | ||
748 | 751 | ||
749 | skb = alloc_skb(size, GFP_KERNEL); | 752 | skb = alloc_skb(nlmsg_total_size(payload), GFP_KERNEL); |
750 | if (!skb) { | 753 | if (skb == NULL) |
751 | netlink_set_err(rtnl, 0, RTNLGRP_DECnet_IFADDR, ENOBUFS); | 754 | goto errout; |
752 | return; | 755 | |
753 | } | 756 | err = dn_dev_fill_ifaddr(skb, ifa, 0, 0, event, 0); |
754 | if (dn_dev_fill_ifaddr(skb, ifa, 0, 0, event, 0) < 0) { | 757 | if (err < 0) { |
755 | kfree_skb(skb); | 758 | kfree_skb(skb); |
756 | netlink_set_err(rtnl, 0, RTNLGRP_DECnet_IFADDR, EINVAL); | 759 | goto errout; |
757 | return; | ||
758 | } | 760 | } |
759 | NETLINK_CB(skb).dst_group = RTNLGRP_DECnet_IFADDR; | 761 | |
760 | netlink_broadcast(rtnl, skb, 0, RTNLGRP_DECnet_IFADDR, GFP_KERNEL); | 762 | err = rtnl_notify(skb, 0, RTNLGRP_DECnet_IFADDR, NULL, GFP_KERNEL); |
763 | errout: | ||
764 | if (err < 0) | ||
765 | rtnl_set_sk_err(RTNLGRP_DECnet_IFADDR, err); | ||
761 | } | 766 | } |
762 | 767 | ||
763 | static int dn_dev_dump_ifaddr(struct sk_buff *skb, struct netlink_callback *cb) | 768 | static int dn_dev_dump_ifaddr(struct sk_buff *skb, struct netlink_callback *cb) |
@@ -1417,8 +1422,6 @@ static struct rtnetlink_link dnet_rtnetlink_table[RTM_NR_MSGTYPES] = | |||
1417 | [RTM_DELROUTE - RTM_BASE] = { .doit = dn_fib_rtm_delroute, }, | 1422 | [RTM_DELROUTE - RTM_BASE] = { .doit = dn_fib_rtm_delroute, }, |
1418 | [RTM_GETROUTE - RTM_BASE] = { .doit = dn_cache_getroute, | 1423 | [RTM_GETROUTE - RTM_BASE] = { .doit = dn_cache_getroute, |
1419 | .dumpit = dn_fib_dump, }, | 1424 | .dumpit = dn_fib_dump, }, |
1420 | [RTM_NEWRULE - RTM_BASE] = { .doit = dn_fib_rtm_newrule, }, | ||
1421 | [RTM_DELRULE - RTM_BASE] = { .doit = dn_fib_rtm_delrule, }, | ||
1422 | [RTM_GETRULE - RTM_BASE] = { .dumpit = dn_fib_dump_rules, }, | 1425 | [RTM_GETRULE - RTM_BASE] = { .dumpit = dn_fib_dump_rules, }, |
1423 | #else | 1426 | #else |
1424 | [RTM_GETROUTE - RTM_BASE] = { .doit = dn_cache_getroute, | 1427 | [RTM_GETROUTE - RTM_BASE] = { .doit = dn_cache_getroute, |
diff --git a/net/decnet/dn_fib.c b/net/decnet/dn_fib.c index fa20e2efcfc1..1cf010124ec5 100644 --- a/net/decnet/dn_fib.c +++ b/net/decnet/dn_fib.c | |||
@@ -34,6 +34,7 @@ | |||
34 | #include <net/neighbour.h> | 34 | #include <net/neighbour.h> |
35 | #include <net/dst.h> | 35 | #include <net/dst.h> |
36 | #include <net/flow.h> | 36 | #include <net/flow.h> |
37 | #include <net/fib_rules.h> | ||
37 | #include <net/dn.h> | 38 | #include <net/dn.h> |
38 | #include <net/dn_route.h> | 39 | #include <net/dn_route.h> |
39 | #include <net/dn_fib.h> | 40 | #include <net/dn_fib.h> |
@@ -54,11 +55,9 @@ | |||
54 | 55 | ||
55 | #define endfor_nexthops(fi) } | 56 | #define endfor_nexthops(fi) } |
56 | 57 | ||
57 | extern int dn_cache_dump(struct sk_buff *skb, struct netlink_callback *cb); | ||
58 | |||
59 | static DEFINE_SPINLOCK(dn_fib_multipath_lock); | 58 | static DEFINE_SPINLOCK(dn_fib_multipath_lock); |
60 | static struct dn_fib_info *dn_fib_info_list; | 59 | static struct dn_fib_info *dn_fib_info_list; |
61 | static DEFINE_RWLOCK(dn_fib_info_lock); | 60 | static DEFINE_SPINLOCK(dn_fib_info_lock); |
62 | 61 | ||
63 | static struct | 62 | static struct |
64 | { | 63 | { |
@@ -79,6 +78,9 @@ static struct | |||
79 | [RTN_XRESOLVE] = { .error = -EINVAL, .scope = RT_SCOPE_NOWHERE }, | 78 | [RTN_XRESOLVE] = { .error = -EINVAL, .scope = RT_SCOPE_NOWHERE }, |
80 | }; | 79 | }; |
81 | 80 | ||
81 | static int dn_fib_sync_down(__le16 local, struct net_device *dev, int force); | ||
82 | static int dn_fib_sync_up(struct net_device *dev); | ||
83 | |||
82 | void dn_fib_free_info(struct dn_fib_info *fi) | 84 | void dn_fib_free_info(struct dn_fib_info *fi) |
83 | { | 85 | { |
84 | if (fi->fib_dead == 0) { | 86 | if (fi->fib_dead == 0) { |
@@ -96,7 +98,7 @@ void dn_fib_free_info(struct dn_fib_info *fi) | |||
96 | 98 | ||
97 | void dn_fib_release_info(struct dn_fib_info *fi) | 99 | void dn_fib_release_info(struct dn_fib_info *fi) |
98 | { | 100 | { |
99 | write_lock(&dn_fib_info_lock); | 101 | spin_lock(&dn_fib_info_lock); |
100 | if (fi && --fi->fib_treeref == 0) { | 102 | if (fi && --fi->fib_treeref == 0) { |
101 | if (fi->fib_next) | 103 | if (fi->fib_next) |
102 | fi->fib_next->fib_prev = fi->fib_prev; | 104 | fi->fib_next->fib_prev = fi->fib_prev; |
@@ -107,7 +109,7 @@ void dn_fib_release_info(struct dn_fib_info *fi) | |||
107 | fi->fib_dead = 1; | 109 | fi->fib_dead = 1; |
108 | dn_fib_info_put(fi); | 110 | dn_fib_info_put(fi); |
109 | } | 111 | } |
110 | write_unlock(&dn_fib_info_lock); | 112 | spin_unlock(&dn_fib_info_lock); |
111 | } | 113 | } |
112 | 114 | ||
113 | static inline int dn_fib_nh_comp(const struct dn_fib_info *fi, const struct dn_fib_info *ofi) | 115 | static inline int dn_fib_nh_comp(const struct dn_fib_info *fi, const struct dn_fib_info *ofi) |
@@ -378,13 +380,13 @@ link_it: | |||
378 | 380 | ||
379 | fi->fib_treeref++; | 381 | fi->fib_treeref++; |
380 | atomic_inc(&fi->fib_clntref); | 382 | atomic_inc(&fi->fib_clntref); |
381 | write_lock(&dn_fib_info_lock); | 383 | spin_lock(&dn_fib_info_lock); |
382 | fi->fib_next = dn_fib_info_list; | 384 | fi->fib_next = dn_fib_info_list; |
383 | fi->fib_prev = NULL; | 385 | fi->fib_prev = NULL; |
384 | if (dn_fib_info_list) | 386 | if (dn_fib_info_list) |
385 | dn_fib_info_list->fib_prev = fi; | 387 | dn_fib_info_list->fib_prev = fi; |
386 | dn_fib_info_list = fi; | 388 | dn_fib_info_list = fi; |
387 | write_unlock(&dn_fib_info_lock); | 389 | spin_unlock(&dn_fib_info_lock); |
388 | return fi; | 390 | return fi; |
389 | 391 | ||
390 | err_inval: | 392 | err_inval: |
@@ -490,7 +492,8 @@ static int dn_fib_check_attr(struct rtmsg *r, struct rtattr **rta) | |||
490 | if (attr) { | 492 | if (attr) { |
491 | if (RTA_PAYLOAD(attr) < 4 && RTA_PAYLOAD(attr) != 2) | 493 | if (RTA_PAYLOAD(attr) < 4 && RTA_PAYLOAD(attr) != 2) |
492 | return -EINVAL; | 494 | return -EINVAL; |
493 | if (i != RTA_MULTIPATH && i != RTA_METRICS) | 495 | if (i != RTA_MULTIPATH && i != RTA_METRICS && |
496 | i != RTA_TABLE) | ||
494 | rta[i-1] = (struct rtattr *)RTA_DATA(attr); | 497 | rta[i-1] = (struct rtattr *)RTA_DATA(attr); |
495 | } | 498 | } |
496 | } | 499 | } |
@@ -507,7 +510,7 @@ int dn_fib_rtm_delroute(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) | |||
507 | if (dn_fib_check_attr(r, rta)) | 510 | if (dn_fib_check_attr(r, rta)) |
508 | return -EINVAL; | 511 | return -EINVAL; |
509 | 512 | ||
510 | tb = dn_fib_get_table(r->rtm_table, 0); | 513 | tb = dn_fib_get_table(rtm_get_table(rta, r->rtm_table), 0); |
511 | if (tb) | 514 | if (tb) |
512 | return tb->delete(tb, r, (struct dn_kern_rta *)rta, nlh, &NETLINK_CB(skb)); | 515 | return tb->delete(tb, r, (struct dn_kern_rta *)rta, nlh, &NETLINK_CB(skb)); |
513 | 516 | ||
@@ -523,46 +526,13 @@ int dn_fib_rtm_newroute(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) | |||
523 | if (dn_fib_check_attr(r, rta)) | 526 | if (dn_fib_check_attr(r, rta)) |
524 | return -EINVAL; | 527 | return -EINVAL; |
525 | 528 | ||
526 | tb = dn_fib_get_table(r->rtm_table, 1); | 529 | tb = dn_fib_get_table(rtm_get_table(rta, r->rtm_table), 1); |
527 | if (tb) | 530 | if (tb) |
528 | return tb->insert(tb, r, (struct dn_kern_rta *)rta, nlh, &NETLINK_CB(skb)); | 531 | return tb->insert(tb, r, (struct dn_kern_rta *)rta, nlh, &NETLINK_CB(skb)); |
529 | 532 | ||
530 | return -ENOBUFS; | 533 | return -ENOBUFS; |
531 | } | 534 | } |
532 | 535 | ||
533 | |||
534 | int dn_fib_dump(struct sk_buff *skb, struct netlink_callback *cb) | ||
535 | { | ||
536 | int t; | ||
537 | int s_t; | ||
538 | struct dn_fib_table *tb; | ||
539 | |||
540 | if (NLMSG_PAYLOAD(cb->nlh, 0) >= sizeof(struct rtmsg) && | ||
541 | ((struct rtmsg *)NLMSG_DATA(cb->nlh))->rtm_flags&RTM_F_CLONED) | ||
542 | return dn_cache_dump(skb, cb); | ||
543 | |||
544 | s_t = cb->args[0]; | ||
545 | if (s_t == 0) | ||
546 | s_t = cb->args[0] = RT_MIN_TABLE; | ||
547 | |||
548 | for(t = s_t; t <= RT_TABLE_MAX; t++) { | ||
549 | if (t < s_t) | ||
550 | continue; | ||
551 | if (t > s_t) | ||
552 | memset(&cb->args[1], 0, | ||
553 | sizeof(cb->args) - sizeof(cb->args[0])); | ||
554 | tb = dn_fib_get_table(t, 0); | ||
555 | if (tb == NULL) | ||
556 | continue; | ||
557 | if (tb->dump(tb, skb, cb) < 0) | ||
558 | break; | ||
559 | } | ||
560 | |||
561 | cb->args[0] = t; | ||
562 | |||
563 | return skb->len; | ||
564 | } | ||
565 | |||
566 | static void fib_magic(int cmd, int type, __le16 dst, int dst_len, struct dn_ifaddr *ifa) | 536 | static void fib_magic(int cmd, int type, __le16 dst, int dst_len, struct dn_ifaddr *ifa) |
567 | { | 537 | { |
568 | struct dn_fib_table *tb; | 538 | struct dn_fib_table *tb; |
@@ -682,7 +652,7 @@ static int dn_fib_dnaddr_event(struct notifier_block *this, unsigned long event, | |||
682 | return NOTIFY_DONE; | 652 | return NOTIFY_DONE; |
683 | } | 653 | } |
684 | 654 | ||
685 | int dn_fib_sync_down(__le16 local, struct net_device *dev, int force) | 655 | static int dn_fib_sync_down(__le16 local, struct net_device *dev, int force) |
686 | { | 656 | { |
687 | int ret = 0; | 657 | int ret = 0; |
688 | int scope = RT_SCOPE_NOWHERE; | 658 | int scope = RT_SCOPE_NOWHERE; |
@@ -726,7 +696,7 @@ int dn_fib_sync_down(__le16 local, struct net_device *dev, int force) | |||
726 | } | 696 | } |
727 | 697 | ||
728 | 698 | ||
729 | int dn_fib_sync_up(struct net_device *dev) | 699 | static int dn_fib_sync_up(struct net_device *dev) |
730 | { | 700 | { |
731 | int ret = 0; | 701 | int ret = 0; |
732 | 702 | ||
@@ -760,22 +730,6 @@ int dn_fib_sync_up(struct net_device *dev) | |||
760 | return ret; | 730 | return ret; |
761 | } | 731 | } |
762 | 732 | ||
763 | void dn_fib_flush(void) | ||
764 | { | ||
765 | int flushed = 0; | ||
766 | struct dn_fib_table *tb; | ||
767 | int id; | ||
768 | |||
769 | for(id = RT_TABLE_MAX; id > 0; id--) { | ||
770 | if ((tb = dn_fib_get_table(id, 0)) == NULL) | ||
771 | continue; | ||
772 | flushed += tb->flush(tb); | ||
773 | } | ||
774 | |||
775 | if (flushed) | ||
776 | dn_rt_cache_flush(-1); | ||
777 | } | ||
778 | |||
779 | static struct notifier_block dn_fib_dnaddr_notifier = { | 733 | static struct notifier_block dn_fib_dnaddr_notifier = { |
780 | .notifier_call = dn_fib_dnaddr_event, | 734 | .notifier_call = dn_fib_dnaddr_event, |
781 | }; | 735 | }; |
diff --git a/net/decnet/dn_nsp_in.c b/net/decnet/dn_nsp_in.c index 86f7f3b28e70..72ecc6e62ec4 100644 --- a/net/decnet/dn_nsp_in.c +++ b/net/decnet/dn_nsp_in.c | |||
@@ -586,7 +586,7 @@ static __inline__ int dn_queue_skb(struct sock *sk, struct sk_buff *skb, int sig | |||
586 | goto out; | 586 | goto out; |
587 | } | 587 | } |
588 | 588 | ||
589 | err = sk_filter(sk, skb, 0); | 589 | err = sk_filter(sk, skb); |
590 | if (err) | 590 | if (err) |
591 | goto out; | 591 | goto out; |
592 | 592 | ||
diff --git a/net/decnet/dn_route.c b/net/decnet/dn_route.c index 743e9fcf7c5a..dd0761e3d280 100644 --- a/net/decnet/dn_route.c +++ b/net/decnet/dn_route.c | |||
@@ -80,6 +80,7 @@ | |||
80 | #include <net/neighbour.h> | 80 | #include <net/neighbour.h> |
81 | #include <net/dst.h> | 81 | #include <net/dst.h> |
82 | #include <net/flow.h> | 82 | #include <net/flow.h> |
83 | #include <net/fib_rules.h> | ||
83 | #include <net/dn.h> | 84 | #include <net/dn.h> |
84 | #include <net/dn_dev.h> | 85 | #include <net/dn_dev.h> |
85 | #include <net/dn_nsp.h> | 86 | #include <net/dn_nsp.h> |
@@ -1284,7 +1285,7 @@ static int dn_route_input_slow(struct sk_buff *skb) | |||
1284 | dev_hold(out_dev); | 1285 | dev_hold(out_dev); |
1285 | 1286 | ||
1286 | if (res.r) | 1287 | if (res.r) |
1287 | src_map = dn_fib_rules_policy(fl.fld_src, &res, &flags); | 1288 | src_map = fl.fld_src; /* no NAT support for now */ |
1288 | 1289 | ||
1289 | gateway = DN_FIB_RES_GW(res); | 1290 | gateway = DN_FIB_RES_GW(res); |
1290 | if (res.type == RTN_NAT) { | 1291 | if (res.type == RTN_NAT) { |
@@ -1485,6 +1486,7 @@ static int dn_rt_fill_info(struct sk_buff *skb, u32 pid, u32 seq, | |||
1485 | r->rtm_src_len = 0; | 1486 | r->rtm_src_len = 0; |
1486 | r->rtm_tos = 0; | 1487 | r->rtm_tos = 0; |
1487 | r->rtm_table = RT_TABLE_MAIN; | 1488 | r->rtm_table = RT_TABLE_MAIN; |
1489 | RTA_PUT_U32(skb, RTA_TABLE, RT_TABLE_MAIN); | ||
1488 | r->rtm_type = rt->rt_type; | 1490 | r->rtm_type = rt->rt_type; |
1489 | r->rtm_flags = (rt->rt_flags & ~0xFFFF) | RTM_F_CLONED; | 1491 | r->rtm_flags = (rt->rt_flags & ~0xFFFF) | RTM_F_CLONED; |
1490 | r->rtm_scope = RT_SCOPE_UNIVERSE; | 1492 | r->rtm_scope = RT_SCOPE_UNIVERSE; |
@@ -1609,9 +1611,7 @@ int dn_cache_getroute(struct sk_buff *in_skb, struct nlmsghdr *nlh, void *arg) | |||
1609 | goto out_free; | 1611 | goto out_free; |
1610 | } | 1612 | } |
1611 | 1613 | ||
1612 | err = netlink_unicast(rtnl, skb, NETLINK_CB(in_skb).pid, MSG_DONTWAIT); | 1614 | return rtnl_unicast(skb, NETLINK_CB(in_skb).pid); |
1613 | |||
1614 | return err; | ||
1615 | 1615 | ||
1616 | out_free: | 1616 | out_free: |
1617 | kfree_skb(skb); | 1617 | kfree_skb(skb); |
@@ -1781,14 +1781,9 @@ void __init dn_route_init(void) | |||
1781 | { | 1781 | { |
1782 | int i, goal, order; | 1782 | int i, goal, order; |
1783 | 1783 | ||
1784 | dn_dst_ops.kmem_cachep = kmem_cache_create("dn_dst_cache", | 1784 | dn_dst_ops.kmem_cachep = |
1785 | sizeof(struct dn_route), | 1785 | kmem_cache_create("dn_dst_cache", sizeof(struct dn_route), 0, |
1786 | 0, SLAB_HWCACHE_ALIGN, | 1786 | SLAB_HWCACHE_ALIGN|SLAB_PANIC, NULL, NULL); |
1787 | NULL, NULL); | ||
1788 | |||
1789 | if (!dn_dst_ops.kmem_cachep) | ||
1790 | panic("DECnet: Failed to allocate dn_dst_cache\n"); | ||
1791 | |||
1792 | init_timer(&dn_route_timer); | 1787 | init_timer(&dn_route_timer); |
1793 | dn_route_timer.function = dn_dst_check_expire; | 1788 | dn_route_timer.function = dn_dst_check_expire; |
1794 | dn_route_timer.expires = jiffies + decnet_dst_gc_interval * HZ; | 1789 | dn_route_timer.expires = jiffies + decnet_dst_gc_interval * HZ; |
diff --git a/net/decnet/dn_rules.c b/net/decnet/dn_rules.c index 6986be754ef2..3e0c882c90bf 100644 --- a/net/decnet/dn_rules.c +++ b/net/decnet/dn_rules.c | |||
@@ -11,259 +11,213 @@ | |||
11 | * | 11 | * |
12 | * | 12 | * |
13 | * Changes: | 13 | * Changes: |
14 | * Steve Whitehouse <steve@chygwyn.com> | ||
15 | * Updated for Thomas Graf's generic rules | ||
14 | * | 16 | * |
15 | */ | 17 | */ |
16 | #include <linux/string.h> | ||
17 | #include <linux/net.h> | 18 | #include <linux/net.h> |
18 | #include <linux/socket.h> | ||
19 | #include <linux/sockios.h> | ||
20 | #include <linux/init.h> | 19 | #include <linux/init.h> |
21 | #include <linux/skbuff.h> | ||
22 | #include <linux/netlink.h> | 20 | #include <linux/netlink.h> |
23 | #include <linux/rtnetlink.h> | 21 | #include <linux/rtnetlink.h> |
24 | #include <linux/proc_fs.h> | ||
25 | #include <linux/netdevice.h> | 22 | #include <linux/netdevice.h> |
26 | #include <linux/timer.h> | ||
27 | #include <linux/spinlock.h> | 23 | #include <linux/spinlock.h> |
28 | #include <linux/in_route.h> | ||
29 | #include <linux/list.h> | 24 | #include <linux/list.h> |
30 | #include <linux/rcupdate.h> | 25 | #include <linux/rcupdate.h> |
31 | #include <asm/atomic.h> | ||
32 | #include <asm/uaccess.h> | ||
33 | #include <net/neighbour.h> | 26 | #include <net/neighbour.h> |
34 | #include <net/dst.h> | 27 | #include <net/dst.h> |
35 | #include <net/flow.h> | 28 | #include <net/flow.h> |
29 | #include <net/fib_rules.h> | ||
36 | #include <net/dn.h> | 30 | #include <net/dn.h> |
37 | #include <net/dn_fib.h> | 31 | #include <net/dn_fib.h> |
38 | #include <net/dn_neigh.h> | 32 | #include <net/dn_neigh.h> |
39 | #include <net/dn_dev.h> | 33 | #include <net/dn_dev.h> |
40 | 34 | ||
35 | static struct fib_rules_ops dn_fib_rules_ops; | ||
36 | |||
41 | struct dn_fib_rule | 37 | struct dn_fib_rule |
42 | { | 38 | { |
43 | struct hlist_node r_hlist; | 39 | struct fib_rule common; |
44 | atomic_t r_clntref; | 40 | unsigned char dst_len; |
45 | u32 r_preference; | 41 | unsigned char src_len; |
46 | unsigned char r_table; | 42 | __le16 src; |
47 | unsigned char r_action; | 43 | __le16 srcmask; |
48 | unsigned char r_dst_len; | 44 | __le16 dst; |
49 | unsigned char r_src_len; | 45 | __le16 dstmask; |
50 | __le16 r_src; | 46 | __le16 srcmap; |
51 | __le16 r_srcmask; | 47 | u8 flags; |
52 | __le16 r_dst; | ||
53 | __le16 r_dstmask; | ||
54 | __le16 r_srcmap; | ||
55 | u8 r_flags; | ||
56 | #ifdef CONFIG_DECNET_ROUTE_FWMARK | 48 | #ifdef CONFIG_DECNET_ROUTE_FWMARK |
57 | u32 r_fwmark; | 49 | u32 fwmark; |
50 | u32 fwmask; | ||
58 | #endif | 51 | #endif |
59 | int r_ifindex; | ||
60 | char r_ifname[IFNAMSIZ]; | ||
61 | int r_dead; | ||
62 | struct rcu_head rcu; | ||
63 | }; | 52 | }; |
64 | 53 | ||
65 | static struct dn_fib_rule default_rule = { | 54 | static struct dn_fib_rule default_rule = { |
66 | .r_clntref = ATOMIC_INIT(2), | 55 | .common = { |
67 | .r_preference = 0x7fff, | 56 | .refcnt = ATOMIC_INIT(2), |
68 | .r_table = RT_TABLE_MAIN, | 57 | .pref = 0x7fff, |
69 | .r_action = RTN_UNICAST | 58 | .table = RT_TABLE_MAIN, |
59 | .action = FR_ACT_TO_TBL, | ||
60 | }, | ||
70 | }; | 61 | }; |
71 | 62 | ||
72 | static struct hlist_head dn_fib_rules; | 63 | static LIST_HEAD(dn_fib_rules); |
64 | |||
73 | 65 | ||
74 | int dn_fib_rtm_delrule(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) | 66 | int dn_fib_lookup(struct flowi *flp, struct dn_fib_res *res) |
75 | { | 67 | { |
76 | struct rtattr **rta = arg; | 68 | struct fib_lookup_arg arg = { |
77 | struct rtmsg *rtm = NLMSG_DATA(nlh); | 69 | .result = res, |
78 | struct dn_fib_rule *r; | 70 | }; |
79 | struct hlist_node *node; | 71 | int err; |
80 | int err = -ESRCH; | 72 | |
81 | 73 | err = fib_rules_lookup(&dn_fib_rules_ops, flp, 0, &arg); | |
82 | hlist_for_each_entry(r, node, &dn_fib_rules, r_hlist) { | 74 | res->r = arg.rule; |
83 | if ((!rta[RTA_SRC-1] || memcmp(RTA_DATA(rta[RTA_SRC-1]), &r->r_src, 2) == 0) && | ||
84 | rtm->rtm_src_len == r->r_src_len && | ||
85 | rtm->rtm_dst_len == r->r_dst_len && | ||
86 | (!rta[RTA_DST-1] || memcmp(RTA_DATA(rta[RTA_DST-1]), &r->r_dst, 2) == 0) && | ||
87 | #ifdef CONFIG_DECNET_ROUTE_FWMARK | ||
88 | (!rta[RTA_PROTOINFO-1] || memcmp(RTA_DATA(rta[RTA_PROTOINFO-1]), &r->r_fwmark, 4) == 0) && | ||
89 | #endif | ||
90 | (!rtm->rtm_type || rtm->rtm_type == r->r_action) && | ||
91 | (!rta[RTA_PRIORITY-1] || memcmp(RTA_DATA(rta[RTA_PRIORITY-1]), &r->r_preference, 4) == 0) && | ||
92 | (!rta[RTA_IIF-1] || rtattr_strcmp(rta[RTA_IIF-1], r->r_ifname) == 0) && | ||
93 | (!rtm->rtm_table || (r && rtm->rtm_table == r->r_table))) { | ||
94 | |||
95 | err = -EPERM; | ||
96 | if (r == &default_rule) | ||
97 | break; | ||
98 | |||
99 | hlist_del_rcu(&r->r_hlist); | ||
100 | r->r_dead = 1; | ||
101 | dn_fib_rule_put(r); | ||
102 | err = 0; | ||
103 | break; | ||
104 | } | ||
105 | } | ||
106 | 75 | ||
107 | return err; | 76 | return err; |
108 | } | 77 | } |
109 | 78 | ||
110 | static inline void dn_fib_rule_put_rcu(struct rcu_head *head) | 79 | static int dn_fib_rule_action(struct fib_rule *rule, struct flowi *flp, |
80 | int flags, struct fib_lookup_arg *arg) | ||
111 | { | 81 | { |
112 | struct dn_fib_rule *r = container_of(head, struct dn_fib_rule, rcu); | 82 | int err = -EAGAIN; |
113 | kfree(r); | 83 | struct dn_fib_table *tbl; |
114 | } | ||
115 | 84 | ||
116 | void dn_fib_rule_put(struct dn_fib_rule *r) | 85 | switch(rule->action) { |
117 | { | 86 | case FR_ACT_TO_TBL: |
118 | if (atomic_dec_and_test(&r->r_clntref)) { | 87 | break; |
119 | if (r->r_dead) | 88 | |
120 | call_rcu(&r->rcu, dn_fib_rule_put_rcu); | 89 | case FR_ACT_UNREACHABLE: |
121 | else | 90 | err = -ENETUNREACH; |
122 | printk(KERN_DEBUG "Attempt to free alive dn_fib_rule\n"); | 91 | goto errout; |
92 | |||
93 | case FR_ACT_PROHIBIT: | ||
94 | err = -EACCES; | ||
95 | goto errout; | ||
96 | |||
97 | case FR_ACT_BLACKHOLE: | ||
98 | default: | ||
99 | err = -EINVAL; | ||
100 | goto errout; | ||
123 | } | 101 | } |
102 | |||
103 | tbl = dn_fib_get_table(rule->table, 0); | ||
104 | if (tbl == NULL) | ||
105 | goto errout; | ||
106 | |||
107 | err = tbl->lookup(tbl, flp, (struct dn_fib_res *)arg->result); | ||
108 | if (err > 0) | ||
109 | err = -EAGAIN; | ||
110 | errout: | ||
111 | return err; | ||
124 | } | 112 | } |
125 | 113 | ||
114 | static struct nla_policy dn_fib_rule_policy[FRA_MAX+1] __read_mostly = { | ||
115 | [FRA_IFNAME] = { .type = NLA_STRING, .len = IFNAMSIZ - 1 }, | ||
116 | [FRA_PRIORITY] = { .type = NLA_U32 }, | ||
117 | [FRA_SRC] = { .type = NLA_U16 }, | ||
118 | [FRA_DST] = { .type = NLA_U16 }, | ||
119 | [FRA_FWMARK] = { .type = NLA_U32 }, | ||
120 | [FRA_FWMASK] = { .type = NLA_U32 }, | ||
121 | [FRA_TABLE] = { .type = NLA_U32 }, | ||
122 | }; | ||
126 | 123 | ||
127 | int dn_fib_rtm_newrule(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) | 124 | static int dn_fib_rule_match(struct fib_rule *rule, struct flowi *fl, int flags) |
128 | { | 125 | { |
129 | struct rtattr **rta = arg; | 126 | struct dn_fib_rule *r = (struct dn_fib_rule *)rule; |
130 | struct rtmsg *rtm = NLMSG_DATA(nlh); | 127 | u16 daddr = fl->fld_dst; |
131 | struct dn_fib_rule *r, *new_r, *last = NULL; | 128 | u16 saddr = fl->fld_src; |
132 | struct hlist_node *node = NULL; | 129 | |
133 | unsigned char table_id; | 130 | if (((saddr ^ r->src) & r->srcmask) || |
134 | 131 | ((daddr ^ r->dst) & r->dstmask)) | |
135 | if (rtm->rtm_src_len > 16 || rtm->rtm_dst_len > 16) | 132 | return 0; |
136 | return -EINVAL; | ||
137 | |||
138 | if (rta[RTA_IIF-1] && RTA_PAYLOAD(rta[RTA_IIF-1]) > IFNAMSIZ) | ||
139 | return -EINVAL; | ||
140 | |||
141 | if (rtm->rtm_type == RTN_NAT) | ||
142 | return -EINVAL; | ||
143 | |||
144 | table_id = rtm->rtm_table; | ||
145 | if (table_id == RT_TABLE_UNSPEC) { | ||
146 | struct dn_fib_table *tb; | ||
147 | if (rtm->rtm_type == RTN_UNICAST) { | ||
148 | if ((tb = dn_fib_empty_table()) == NULL) | ||
149 | return -ENOBUFS; | ||
150 | table_id = tb->n; | ||
151 | } | ||
152 | } | ||
153 | 133 | ||
154 | new_r = kzalloc(sizeof(*new_r), GFP_KERNEL); | ||
155 | if (!new_r) | ||
156 | return -ENOMEM; | ||
157 | |||
158 | if (rta[RTA_SRC-1]) | ||
159 | memcpy(&new_r->r_src, RTA_DATA(rta[RTA_SRC-1]), 2); | ||
160 | if (rta[RTA_DST-1]) | ||
161 | memcpy(&new_r->r_dst, RTA_DATA(rta[RTA_DST-1]), 2); | ||
162 | if (rta[RTA_GATEWAY-1]) | ||
163 | memcpy(&new_r->r_srcmap, RTA_DATA(rta[RTA_GATEWAY-1]), 2); | ||
164 | new_r->r_src_len = rtm->rtm_src_len; | ||
165 | new_r->r_dst_len = rtm->rtm_dst_len; | ||
166 | new_r->r_srcmask = dnet_make_mask(rtm->rtm_src_len); | ||
167 | new_r->r_dstmask = dnet_make_mask(rtm->rtm_dst_len); | ||
168 | #ifdef CONFIG_DECNET_ROUTE_FWMARK | 134 | #ifdef CONFIG_DECNET_ROUTE_FWMARK |
169 | if (rta[RTA_PROTOINFO-1]) | 135 | if ((r->fwmark ^ fl->fld_fwmark) & r->fwmask) |
170 | memcpy(&new_r->r_fwmark, RTA_DATA(rta[RTA_PROTOINFO-1]), 4); | 136 | return 0; |
171 | #endif | 137 | #endif |
172 | new_r->r_action = rtm->rtm_type; | ||
173 | new_r->r_flags = rtm->rtm_flags; | ||
174 | if (rta[RTA_PRIORITY-1]) | ||
175 | memcpy(&new_r->r_preference, RTA_DATA(rta[RTA_PRIORITY-1]), 4); | ||
176 | new_r->r_table = table_id; | ||
177 | if (rta[RTA_IIF-1]) { | ||
178 | struct net_device *dev; | ||
179 | rtattr_strlcpy(new_r->r_ifname, rta[RTA_IIF-1], IFNAMSIZ); | ||
180 | new_r->r_ifindex = -1; | ||
181 | dev = dev_get_by_name(new_r->r_ifname); | ||
182 | if (dev) { | ||
183 | new_r->r_ifindex = dev->ifindex; | ||
184 | dev_put(dev); | ||
185 | } | ||
186 | } | ||
187 | 138 | ||
188 | r = container_of(dn_fib_rules.first, struct dn_fib_rule, r_hlist); | 139 | return 1; |
189 | if (!new_r->r_preference) { | 140 | } |
190 | if (r && r->r_hlist.next != NULL) { | 141 | |
191 | r = container_of(r->r_hlist.next, struct dn_fib_rule, r_hlist); | 142 | static int dn_fib_rule_configure(struct fib_rule *rule, struct sk_buff *skb, |
192 | if (r->r_preference) | 143 | struct nlmsghdr *nlh, struct fib_rule_hdr *frh, |
193 | new_r->r_preference = r->r_preference - 1; | 144 | struct nlattr **tb) |
145 | { | ||
146 | int err = -EINVAL; | ||
147 | struct dn_fib_rule *r = (struct dn_fib_rule *)rule; | ||
148 | |||
149 | if (frh->src_len > 16 || frh->dst_len > 16 || frh->tos) | ||
150 | goto errout; | ||
151 | |||
152 | if (rule->table == RT_TABLE_UNSPEC) { | ||
153 | if (rule->action == FR_ACT_TO_TBL) { | ||
154 | struct dn_fib_table *table; | ||
155 | |||
156 | table = dn_fib_empty_table(); | ||
157 | if (table == NULL) { | ||
158 | err = -ENOBUFS; | ||
159 | goto errout; | ||
160 | } | ||
161 | |||
162 | rule->table = table->n; | ||
194 | } | 163 | } |
195 | } | 164 | } |
196 | 165 | ||
197 | hlist_for_each_entry(r, node, &dn_fib_rules, r_hlist) { | 166 | if (tb[FRA_SRC]) |
198 | if (r->r_preference > new_r->r_preference) | 167 | r->src = nla_get_u16(tb[FRA_SRC]); |
199 | break; | 168 | |
200 | last = r; | 169 | if (tb[FRA_DST]) |
170 | r->dst = nla_get_u16(tb[FRA_DST]); | ||
171 | |||
172 | #ifdef CONFIG_DECNET_ROUTE_FWMARK | ||
173 | if (tb[FRA_FWMARK]) { | ||
174 | r->fwmark = nla_get_u32(tb[FRA_FWMARK]); | ||
175 | if (r->fwmark) | ||
176 | /* compatibility: if the mark value is non-zero all bits | ||
177 | * are compared unless a mask is explicitly specified. | ||
178 | */ | ||
179 | r->fwmask = 0xFFFFFFFF; | ||
201 | } | 180 | } |
202 | atomic_inc(&new_r->r_clntref); | ||
203 | 181 | ||
204 | if (last) | 182 | if (tb[FRA_FWMASK]) |
205 | hlist_add_after_rcu(&last->r_hlist, &new_r->r_hlist); | 183 | r->fwmask = nla_get_u32(tb[FRA_FWMASK]); |
206 | else | 184 | #endif |
207 | hlist_add_before_rcu(&new_r->r_hlist, &r->r_hlist); | ||
208 | return 0; | ||
209 | } | ||
210 | 185 | ||
186 | r->src_len = frh->src_len; | ||
187 | r->srcmask = dnet_make_mask(r->src_len); | ||
188 | r->dst_len = frh->dst_len; | ||
189 | r->dstmask = dnet_make_mask(r->dst_len); | ||
190 | err = 0; | ||
191 | errout: | ||
192 | return err; | ||
193 | } | ||
211 | 194 | ||
212 | int dn_fib_lookup(const struct flowi *flp, struct dn_fib_res *res) | 195 | static int dn_fib_rule_compare(struct fib_rule *rule, struct fib_rule_hdr *frh, |
196 | struct nlattr **tb) | ||
213 | { | 197 | { |
214 | struct dn_fib_rule *r, *policy; | 198 | struct dn_fib_rule *r = (struct dn_fib_rule *)rule; |
215 | struct dn_fib_table *tb; | 199 | |
216 | __le16 saddr = flp->fld_src; | 200 | if (frh->src_len && (r->src_len != frh->src_len)) |
217 | __le16 daddr = flp->fld_dst; | 201 | return 0; |
218 | struct hlist_node *node; | ||
219 | int err; | ||
220 | 202 | ||
221 | rcu_read_lock(); | 203 | if (frh->dst_len && (r->dst_len != frh->dst_len)) |
204 | return 0; | ||
222 | 205 | ||
223 | hlist_for_each_entry_rcu(r, node, &dn_fib_rules, r_hlist) { | ||
224 | if (((saddr^r->r_src) & r->r_srcmask) || | ||
225 | ((daddr^r->r_dst) & r->r_dstmask) || | ||
226 | #ifdef CONFIG_DECNET_ROUTE_FWMARK | 206 | #ifdef CONFIG_DECNET_ROUTE_FWMARK |
227 | (r->r_fwmark && r->r_fwmark != flp->fld_fwmark) || | 207 | if (tb[FRA_FWMARK] && (r->fwmark != nla_get_u32(tb[FRA_FWMARK]))) |
208 | return 0; | ||
209 | |||
210 | if (tb[FRA_FWMASK] && (r->fwmask != nla_get_u32(tb[FRA_FWMASK]))) | ||
211 | return 0; | ||
228 | #endif | 212 | #endif |
229 | (r->r_ifindex && r->r_ifindex != flp->iif)) | ||
230 | continue; | ||
231 | |||
232 | switch(r->r_action) { | ||
233 | case RTN_UNICAST: | ||
234 | case RTN_NAT: | ||
235 | policy = r; | ||
236 | break; | ||
237 | case RTN_UNREACHABLE: | ||
238 | rcu_read_unlock(); | ||
239 | return -ENETUNREACH; | ||
240 | default: | ||
241 | case RTN_BLACKHOLE: | ||
242 | rcu_read_unlock(); | ||
243 | return -EINVAL; | ||
244 | case RTN_PROHIBIT: | ||
245 | rcu_read_unlock(); | ||
246 | return -EACCES; | ||
247 | } | ||
248 | 213 | ||
249 | if ((tb = dn_fib_get_table(r->r_table, 0)) == NULL) | 214 | if (tb[FRA_SRC] && (r->src != nla_get_u16(tb[FRA_SRC]))) |
250 | continue; | 215 | return 0; |
251 | err = tb->lookup(tb, flp, res); | 216 | |
252 | if (err == 0) { | 217 | if (tb[FRA_DST] && (r->dst != nla_get_u16(tb[FRA_DST]))) |
253 | res->r = policy; | 218 | return 0; |
254 | if (policy) | ||
255 | atomic_inc(&policy->r_clntref); | ||
256 | rcu_read_unlock(); | ||
257 | return 0; | ||
258 | } | ||
259 | if (err < 0 && err != -EAGAIN) { | ||
260 | rcu_read_unlock(); | ||
261 | return err; | ||
262 | } | ||
263 | } | ||
264 | 219 | ||
265 | rcu_read_unlock(); | 220 | return 1; |
266 | return -ESRCH; | ||
267 | } | 221 | } |
268 | 222 | ||
269 | unsigned dnet_addr_type(__le16 addr) | 223 | unsigned dnet_addr_type(__le16 addr) |
@@ -271,7 +225,7 @@ unsigned dnet_addr_type(__le16 addr) | |||
271 | struct flowi fl = { .nl_u = { .dn_u = { .daddr = addr } } }; | 225 | struct flowi fl = { .nl_u = { .dn_u = { .daddr = addr } } }; |
272 | struct dn_fib_res res; | 226 | struct dn_fib_res res; |
273 | unsigned ret = RTN_UNICAST; | 227 | unsigned ret = RTN_UNICAST; |
274 | struct dn_fib_table *tb = dn_fib_tables[RT_TABLE_LOCAL]; | 228 | struct dn_fib_table *tb = dn_fib_get_table(RT_TABLE_LOCAL, 0); |
275 | 229 | ||
276 | res.r = NULL; | 230 | res.r = NULL; |
277 | 231 | ||
@@ -284,142 +238,79 @@ unsigned dnet_addr_type(__le16 addr) | |||
284 | return ret; | 238 | return ret; |
285 | } | 239 | } |
286 | 240 | ||
287 | __le16 dn_fib_rules_policy(__le16 saddr, struct dn_fib_res *res, unsigned *flags) | 241 | static int dn_fib_rule_fill(struct fib_rule *rule, struct sk_buff *skb, |
242 | struct nlmsghdr *nlh, struct fib_rule_hdr *frh) | ||
288 | { | 243 | { |
289 | struct dn_fib_rule *r = res->r; | 244 | struct dn_fib_rule *r = (struct dn_fib_rule *)rule; |
290 | 245 | ||
291 | if (r->r_action == RTN_NAT) { | 246 | frh->family = AF_DECnet; |
292 | int addrtype = dnet_addr_type(r->r_srcmap); | 247 | frh->dst_len = r->dst_len; |
248 | frh->src_len = r->src_len; | ||
249 | frh->tos = 0; | ||
293 | 250 | ||
294 | if (addrtype == RTN_NAT) { | 251 | #ifdef CONFIG_DECNET_ROUTE_FWMARK |
295 | saddr = (saddr&~r->r_srcmask)|r->r_srcmap; | 252 | if (r->fwmark) |
296 | *flags |= RTCF_SNAT; | 253 | NLA_PUT_U32(skb, FRA_FWMARK, r->fwmark); |
297 | } else if (addrtype == RTN_LOCAL || r->r_srcmap == 0) { | 254 | if (r->fwmask || r->fwmark) |
298 | saddr = r->r_srcmap; | 255 | NLA_PUT_U32(skb, FRA_FWMASK, r->fwmask); |
299 | *flags |= RTCF_MASQ; | 256 | #endif |
300 | } | 257 | if (r->dst_len) |
301 | } | 258 | NLA_PUT_U16(skb, FRA_DST, r->dst); |
302 | return saddr; | 259 | if (r->src_len) |
303 | } | 260 | NLA_PUT_U16(skb, FRA_SRC, r->src); |
304 | |||
305 | static void dn_fib_rules_detach(struct net_device *dev) | ||
306 | { | ||
307 | struct hlist_node *node; | ||
308 | struct dn_fib_rule *r; | ||
309 | |||
310 | hlist_for_each_entry(r, node, &dn_fib_rules, r_hlist) { | ||
311 | if (r->r_ifindex == dev->ifindex) | ||
312 | r->r_ifindex = -1; | ||
313 | } | ||
314 | } | ||
315 | 261 | ||
316 | static void dn_fib_rules_attach(struct net_device *dev) | 262 | return 0; |
317 | { | ||
318 | struct hlist_node *node; | ||
319 | struct dn_fib_rule *r; | ||
320 | 263 | ||
321 | hlist_for_each_entry(r, node, &dn_fib_rules, r_hlist) { | 264 | nla_put_failure: |
322 | if (r->r_ifindex == -1 && strcmp(dev->name, r->r_ifname) == 0) | 265 | return -ENOBUFS; |
323 | r->r_ifindex = dev->ifindex; | ||
324 | } | ||
325 | } | 266 | } |
326 | 267 | ||
327 | static int dn_fib_rules_event(struct notifier_block *this, unsigned long event, void *ptr) | 268 | static u32 dn_fib_rule_default_pref(void) |
328 | { | 269 | { |
329 | struct net_device *dev = ptr; | 270 | struct list_head *pos; |
330 | 271 | struct fib_rule *rule; | |
331 | switch(event) { | 272 | |
332 | case NETDEV_UNREGISTER: | 273 | if (!list_empty(&dn_fib_rules)) { |
333 | dn_fib_rules_detach(dev); | 274 | pos = dn_fib_rules.next; |
334 | dn_fib_sync_down(0, dev, 1); | 275 | if (pos->next != &dn_fib_rules) { |
335 | case NETDEV_REGISTER: | 276 | rule = list_entry(pos->next, struct fib_rule, list); |
336 | dn_fib_rules_attach(dev); | 277 | if (rule->pref) |
337 | dn_fib_sync_up(dev); | 278 | return rule->pref - 1; |
279 | } | ||
338 | } | 280 | } |
339 | 281 | ||
340 | return NOTIFY_DONE; | 282 | return 0; |
341 | } | ||
342 | |||
343 | |||
344 | static struct notifier_block dn_fib_rules_notifier = { | ||
345 | .notifier_call = dn_fib_rules_event, | ||
346 | }; | ||
347 | |||
348 | static int dn_fib_fill_rule(struct sk_buff *skb, struct dn_fib_rule *r, | ||
349 | struct netlink_callback *cb, unsigned int flags) | ||
350 | { | ||
351 | struct rtmsg *rtm; | ||
352 | struct nlmsghdr *nlh; | ||
353 | unsigned char *b = skb->tail; | ||
354 | |||
355 | |||
356 | nlh = NLMSG_NEW_ANSWER(skb, cb, RTM_NEWRULE, sizeof(*rtm), flags); | ||
357 | rtm = NLMSG_DATA(nlh); | ||
358 | rtm->rtm_family = AF_DECnet; | ||
359 | rtm->rtm_dst_len = r->r_dst_len; | ||
360 | rtm->rtm_src_len = r->r_src_len; | ||
361 | rtm->rtm_tos = 0; | ||
362 | #ifdef CONFIG_DECNET_ROUTE_FWMARK | ||
363 | if (r->r_fwmark) | ||
364 | RTA_PUT(skb, RTA_PROTOINFO, 4, &r->r_fwmark); | ||
365 | #endif | ||
366 | rtm->rtm_table = r->r_table; | ||
367 | rtm->rtm_protocol = 0; | ||
368 | rtm->rtm_scope = 0; | ||
369 | rtm->rtm_type = r->r_action; | ||
370 | rtm->rtm_flags = r->r_flags; | ||
371 | |||
372 | if (r->r_dst_len) | ||
373 | RTA_PUT(skb, RTA_DST, 2, &r->r_dst); | ||
374 | if (r->r_src_len) | ||
375 | RTA_PUT(skb, RTA_SRC, 2, &r->r_src); | ||
376 | if (r->r_ifname[0]) | ||
377 | RTA_PUT(skb, RTA_IIF, IFNAMSIZ, &r->r_ifname); | ||
378 | if (r->r_preference) | ||
379 | RTA_PUT(skb, RTA_PRIORITY, 4, &r->r_preference); | ||
380 | if (r->r_srcmap) | ||
381 | RTA_PUT(skb, RTA_GATEWAY, 2, &r->r_srcmap); | ||
382 | nlh->nlmsg_len = skb->tail - b; | ||
383 | return skb->len; | ||
384 | |||
385 | nlmsg_failure: | ||
386 | rtattr_failure: | ||
387 | skb_trim(skb, b - skb->data); | ||
388 | return -1; | ||
389 | } | 283 | } |
390 | 284 | ||
391 | int dn_fib_dump_rules(struct sk_buff *skb, struct netlink_callback *cb) | 285 | int dn_fib_dump_rules(struct sk_buff *skb, struct netlink_callback *cb) |
392 | { | 286 | { |
393 | int idx = 0; | 287 | return fib_rules_dump(skb, cb, AF_DECnet); |
394 | int s_idx = cb->args[0]; | ||
395 | struct dn_fib_rule *r; | ||
396 | struct hlist_node *node; | ||
397 | |||
398 | rcu_read_lock(); | ||
399 | hlist_for_each_entry(r, node, &dn_fib_rules, r_hlist) { | ||
400 | if (idx < s_idx) | ||
401 | goto next; | ||
402 | if (dn_fib_fill_rule(skb, r, cb, NLM_F_MULTI) < 0) | ||
403 | break; | ||
404 | next: | ||
405 | idx++; | ||
406 | } | ||
407 | rcu_read_unlock(); | ||
408 | cb->args[0] = idx; | ||
409 | |||
410 | return skb->len; | ||
411 | } | 288 | } |
412 | 289 | ||
290 | static struct fib_rules_ops dn_fib_rules_ops = { | ||
291 | .family = AF_DECnet, | ||
292 | .rule_size = sizeof(struct dn_fib_rule), | ||
293 | .action = dn_fib_rule_action, | ||
294 | .match = dn_fib_rule_match, | ||
295 | .configure = dn_fib_rule_configure, | ||
296 | .compare = dn_fib_rule_compare, | ||
297 | .fill = dn_fib_rule_fill, | ||
298 | .default_pref = dn_fib_rule_default_pref, | ||
299 | .nlgroup = RTNLGRP_DECnet_RULE, | ||
300 | .policy = dn_fib_rule_policy, | ||
301 | .rules_list = &dn_fib_rules, | ||
302 | .owner = THIS_MODULE, | ||
303 | }; | ||
304 | |||
413 | void __init dn_fib_rules_init(void) | 305 | void __init dn_fib_rules_init(void) |
414 | { | 306 | { |
415 | INIT_HLIST_HEAD(&dn_fib_rules); | 307 | list_add_tail(&default_rule.common.list, &dn_fib_rules); |
416 | hlist_add_head(&default_rule.r_hlist, &dn_fib_rules); | 308 | fib_rules_register(&dn_fib_rules_ops); |
417 | register_netdevice_notifier(&dn_fib_rules_notifier); | ||
418 | } | 309 | } |
419 | 310 | ||
420 | void __exit dn_fib_rules_cleanup(void) | 311 | void __exit dn_fib_rules_cleanup(void) |
421 | { | 312 | { |
422 | unregister_netdevice_notifier(&dn_fib_rules_notifier); | 313 | fib_rules_unregister(&dn_fib_rules_ops); |
423 | } | 314 | } |
424 | 315 | ||
425 | 316 | ||
diff --git a/net/decnet/dn_table.c b/net/decnet/dn_table.c index e926c952e363..317904bb5896 100644 --- a/net/decnet/dn_table.c +++ b/net/decnet/dn_table.c | |||
@@ -30,6 +30,7 @@ | |||
30 | #include <net/neighbour.h> | 30 | #include <net/neighbour.h> |
31 | #include <net/dst.h> | 31 | #include <net/dst.h> |
32 | #include <net/flow.h> | 32 | #include <net/flow.h> |
33 | #include <net/fib_rules.h> | ||
33 | #include <net/dn.h> | 34 | #include <net/dn.h> |
34 | #include <net/dn_route.h> | 35 | #include <net/dn_route.h> |
35 | #include <net/dn_fib.h> | 36 | #include <net/dn_fib.h> |
@@ -74,9 +75,9 @@ for( ; ((f) = *(fp)) != NULL; (fp) = &(f)->fn_next) | |||
74 | for( ; ((f) = *(fp)) != NULL && dn_key_eq((f)->fn_key, (key)); (fp) = &(f)->fn_next) | 75 | for( ; ((f) = *(fp)) != NULL && dn_key_eq((f)->fn_key, (key)); (fp) = &(f)->fn_next) |
75 | 76 | ||
76 | #define RT_TABLE_MIN 1 | 77 | #define RT_TABLE_MIN 1 |
77 | 78 | #define DN_FIB_TABLE_HASHSZ 256 | |
79 | static struct hlist_head dn_fib_table_hash[DN_FIB_TABLE_HASHSZ]; | ||
78 | static DEFINE_RWLOCK(dn_fib_tables_lock); | 80 | static DEFINE_RWLOCK(dn_fib_tables_lock); |
79 | struct dn_fib_table *dn_fib_tables[RT_TABLE_MAX + 1]; | ||
80 | 81 | ||
81 | static kmem_cache_t *dn_hash_kmem __read_mostly; | 82 | static kmem_cache_t *dn_hash_kmem __read_mostly; |
82 | static int dn_fib_hash_zombies; | 83 | static int dn_fib_hash_zombies; |
@@ -263,7 +264,7 @@ static int dn_fib_nh_match(struct rtmsg *r, struct nlmsghdr *nlh, struct dn_kern | |||
263 | } | 264 | } |
264 | 265 | ||
265 | static int dn_fib_dump_info(struct sk_buff *skb, u32 pid, u32 seq, int event, | 266 | static int dn_fib_dump_info(struct sk_buff *skb, u32 pid, u32 seq, int event, |
266 | u8 tb_id, u8 type, u8 scope, void *dst, int dst_len, | 267 | u32 tb_id, u8 type, u8 scope, void *dst, int dst_len, |
267 | struct dn_fib_info *fi, unsigned int flags) | 268 | struct dn_fib_info *fi, unsigned int flags) |
268 | { | 269 | { |
269 | struct rtmsg *rtm; | 270 | struct rtmsg *rtm; |
@@ -277,6 +278,7 @@ static int dn_fib_dump_info(struct sk_buff *skb, u32 pid, u32 seq, int event, | |||
277 | rtm->rtm_src_len = 0; | 278 | rtm->rtm_src_len = 0; |
278 | rtm->rtm_tos = 0; | 279 | rtm->rtm_tos = 0; |
279 | rtm->rtm_table = tb_id; | 280 | rtm->rtm_table = tb_id; |
281 | RTA_PUT_U32(skb, RTA_TABLE, tb_id); | ||
280 | rtm->rtm_flags = fi->fib_flags; | 282 | rtm->rtm_flags = fi->fib_flags; |
281 | rtm->rtm_scope = scope; | 283 | rtm->rtm_scope = scope; |
282 | rtm->rtm_type = type; | 284 | rtm->rtm_type = type; |
@@ -326,29 +328,29 @@ rtattr_failure: | |||
326 | } | 328 | } |
327 | 329 | ||
328 | 330 | ||
329 | static void dn_rtmsg_fib(int event, struct dn_fib_node *f, int z, int tb_id, | 331 | static void dn_rtmsg_fib(int event, struct dn_fib_node *f, int z, u32 tb_id, |
330 | struct nlmsghdr *nlh, struct netlink_skb_parms *req) | 332 | struct nlmsghdr *nlh, struct netlink_skb_parms *req) |
331 | { | 333 | { |
332 | struct sk_buff *skb; | 334 | struct sk_buff *skb; |
333 | u32 pid = req ? req->pid : 0; | 335 | u32 pid = req ? req->pid : 0; |
334 | int size = NLMSG_SPACE(sizeof(struct rtmsg) + 256); | 336 | int err = -ENOBUFS; |
335 | 337 | ||
336 | skb = alloc_skb(size, GFP_KERNEL); | 338 | skb = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); |
337 | if (!skb) | 339 | if (skb == NULL) |
338 | return; | 340 | goto errout; |
339 | 341 | ||
340 | if (dn_fib_dump_info(skb, pid, nlh->nlmsg_seq, event, tb_id, | 342 | err = dn_fib_dump_info(skb, pid, nlh->nlmsg_seq, event, tb_id, |
341 | f->fn_type, f->fn_scope, &f->fn_key, z, | 343 | f->fn_type, f->fn_scope, &f->fn_key, z, |
342 | DN_FIB_INFO(f), 0) < 0) { | 344 | DN_FIB_INFO(f), 0); |
345 | if (err < 0) { | ||
343 | kfree_skb(skb); | 346 | kfree_skb(skb); |
344 | return; | 347 | goto errout; |
345 | } | 348 | } |
346 | NETLINK_CB(skb).dst_group = RTNLGRP_DECnet_ROUTE; | 349 | |
347 | if (nlh->nlmsg_flags & NLM_F_ECHO) | 350 | err = rtnl_notify(skb, pid, RTNLGRP_DECnet_ROUTE, nlh, GFP_KERNEL); |
348 | atomic_inc(&skb->users); | 351 | errout: |
349 | netlink_broadcast(rtnl, skb, pid, RTNLGRP_DECnet_ROUTE, GFP_KERNEL); | 352 | if (err < 0) |
350 | if (nlh->nlmsg_flags & NLM_F_ECHO) | 353 | rtnl_set_sk_err(RTNLGRP_DECnet_ROUTE, err); |
351 | netlink_unicast(rtnl, skb, pid, MSG_DONTWAIT); | ||
352 | } | 354 | } |
353 | 355 | ||
354 | static __inline__ int dn_hash_dump_bucket(struct sk_buff *skb, | 356 | static __inline__ int dn_hash_dump_bucket(struct sk_buff *skb, |
@@ -359,7 +361,7 @@ static __inline__ int dn_hash_dump_bucket(struct sk_buff *skb, | |||
359 | { | 361 | { |
360 | int i, s_i; | 362 | int i, s_i; |
361 | 363 | ||
362 | s_i = cb->args[3]; | 364 | s_i = cb->args[4]; |
363 | for(i = 0; f; i++, f = f->fn_next) { | 365 | for(i = 0; f; i++, f = f->fn_next) { |
364 | if (i < s_i) | 366 | if (i < s_i) |
365 | continue; | 367 | continue; |
@@ -372,11 +374,11 @@ static __inline__ int dn_hash_dump_bucket(struct sk_buff *skb, | |||
372 | (f->fn_state & DN_S_ZOMBIE) ? 0 : f->fn_type, | 374 | (f->fn_state & DN_S_ZOMBIE) ? 0 : f->fn_type, |
373 | f->fn_scope, &f->fn_key, dz->dz_order, | 375 | f->fn_scope, &f->fn_key, dz->dz_order, |
374 | f->fn_info, NLM_F_MULTI) < 0) { | 376 | f->fn_info, NLM_F_MULTI) < 0) { |
375 | cb->args[3] = i; | 377 | cb->args[4] = i; |
376 | return -1; | 378 | return -1; |
377 | } | 379 | } |
378 | } | 380 | } |
379 | cb->args[3] = i; | 381 | cb->args[4] = i; |
380 | return skb->len; | 382 | return skb->len; |
381 | } | 383 | } |
382 | 384 | ||
@@ -387,20 +389,20 @@ static __inline__ int dn_hash_dump_zone(struct sk_buff *skb, | |||
387 | { | 389 | { |
388 | int h, s_h; | 390 | int h, s_h; |
389 | 391 | ||
390 | s_h = cb->args[2]; | 392 | s_h = cb->args[3]; |
391 | for(h = 0; h < dz->dz_divisor; h++) { | 393 | for(h = 0; h < dz->dz_divisor; h++) { |
392 | if (h < s_h) | 394 | if (h < s_h) |
393 | continue; | 395 | continue; |
394 | if (h > s_h) | 396 | if (h > s_h) |
395 | memset(&cb->args[3], 0, sizeof(cb->args) - 3*sizeof(cb->args[0])); | 397 | memset(&cb->args[4], 0, sizeof(cb->args) - 4*sizeof(cb->args[0])); |
396 | if (dz->dz_hash == NULL || dz->dz_hash[h] == NULL) | 398 | if (dz->dz_hash == NULL || dz->dz_hash[h] == NULL) |
397 | continue; | 399 | continue; |
398 | if (dn_hash_dump_bucket(skb, cb, tb, dz, dz->dz_hash[h]) < 0) { | 400 | if (dn_hash_dump_bucket(skb, cb, tb, dz, dz->dz_hash[h]) < 0) { |
399 | cb->args[2] = h; | 401 | cb->args[3] = h; |
400 | return -1; | 402 | return -1; |
401 | } | 403 | } |
402 | } | 404 | } |
403 | cb->args[2] = h; | 405 | cb->args[3] = h; |
404 | return skb->len; | 406 | return skb->len; |
405 | } | 407 | } |
406 | 408 | ||
@@ -411,26 +413,63 @@ static int dn_fib_table_dump(struct dn_fib_table *tb, struct sk_buff *skb, | |||
411 | struct dn_zone *dz; | 413 | struct dn_zone *dz; |
412 | struct dn_hash *table = (struct dn_hash *)tb->data; | 414 | struct dn_hash *table = (struct dn_hash *)tb->data; |
413 | 415 | ||
414 | s_m = cb->args[1]; | 416 | s_m = cb->args[2]; |
415 | read_lock(&dn_fib_tables_lock); | 417 | read_lock(&dn_fib_tables_lock); |
416 | for(dz = table->dh_zone_list, m = 0; dz; dz = dz->dz_next, m++) { | 418 | for(dz = table->dh_zone_list, m = 0; dz; dz = dz->dz_next, m++) { |
417 | if (m < s_m) | 419 | if (m < s_m) |
418 | continue; | 420 | continue; |
419 | if (m > s_m) | 421 | if (m > s_m) |
420 | memset(&cb->args[2], 0, sizeof(cb->args) - 2*sizeof(cb->args[0])); | 422 | memset(&cb->args[3], 0, sizeof(cb->args) - 3*sizeof(cb->args[0])); |
421 | 423 | ||
422 | if (dn_hash_dump_zone(skb, cb, tb, dz) < 0) { | 424 | if (dn_hash_dump_zone(skb, cb, tb, dz) < 0) { |
423 | cb->args[1] = m; | 425 | cb->args[2] = m; |
424 | read_unlock(&dn_fib_tables_lock); | 426 | read_unlock(&dn_fib_tables_lock); |
425 | return -1; | 427 | return -1; |
426 | } | 428 | } |
427 | } | 429 | } |
428 | read_unlock(&dn_fib_tables_lock); | 430 | read_unlock(&dn_fib_tables_lock); |
429 | cb->args[1] = m; | 431 | cb->args[2] = m; |
430 | 432 | ||
431 | return skb->len; | 433 | return skb->len; |
432 | } | 434 | } |
433 | 435 | ||
436 | int dn_fib_dump(struct sk_buff *skb, struct netlink_callback *cb) | ||
437 | { | ||
438 | unsigned int h, s_h; | ||
439 | unsigned int e = 0, s_e; | ||
440 | struct dn_fib_table *tb; | ||
441 | struct hlist_node *node; | ||
442 | int dumped = 0; | ||
443 | |||
444 | if (NLMSG_PAYLOAD(cb->nlh, 0) >= sizeof(struct rtmsg) && | ||
445 | ((struct rtmsg *)NLMSG_DATA(cb->nlh))->rtm_flags&RTM_F_CLONED) | ||
446 | return dn_cache_dump(skb, cb); | ||
447 | |||
448 | s_h = cb->args[0]; | ||
449 | s_e = cb->args[1]; | ||
450 | |||
451 | for (h = s_h; h < DN_FIB_TABLE_HASHSZ; h++, s_h = 0) { | ||
452 | e = 0; | ||
453 | hlist_for_each_entry(tb, node, &dn_fib_table_hash[h], hlist) { | ||
454 | if (e < s_e) | ||
455 | goto next; | ||
456 | if (dumped) | ||
457 | memset(&cb->args[2], 0, sizeof(cb->args) - | ||
458 | 2 * sizeof(cb->args[0])); | ||
459 | if (tb->dump(tb, skb, cb) < 0) | ||
460 | goto out; | ||
461 | dumped = 1; | ||
462 | next: | ||
463 | e++; | ||
464 | } | ||
465 | } | ||
466 | out: | ||
467 | cb->args[1] = e; | ||
468 | cb->args[0] = h; | ||
469 | |||
470 | return skb->len; | ||
471 | } | ||
472 | |||
434 | static int dn_fib_table_insert(struct dn_fib_table *tb, struct rtmsg *r, struct dn_kern_rta *rta, struct nlmsghdr *n, struct netlink_skb_parms *req) | 473 | static int dn_fib_table_insert(struct dn_fib_table *tb, struct rtmsg *r, struct dn_kern_rta *rta, struct nlmsghdr *n, struct netlink_skb_parms *req) |
435 | { | 474 | { |
436 | struct dn_hash *table = (struct dn_hash *)tb->data; | 475 | struct dn_hash *table = (struct dn_hash *)tb->data; |
@@ -739,9 +778,11 @@ out: | |||
739 | } | 778 | } |
740 | 779 | ||
741 | 780 | ||
742 | struct dn_fib_table *dn_fib_get_table(int n, int create) | 781 | struct dn_fib_table *dn_fib_get_table(u32 n, int create) |
743 | { | 782 | { |
744 | struct dn_fib_table *t; | 783 | struct dn_fib_table *t; |
784 | struct hlist_node *node; | ||
785 | unsigned int h; | ||
745 | 786 | ||
746 | if (n < RT_TABLE_MIN) | 787 | if (n < RT_TABLE_MIN) |
747 | return NULL; | 788 | return NULL; |
@@ -749,8 +790,15 @@ struct dn_fib_table *dn_fib_get_table(int n, int create) | |||
749 | if (n > RT_TABLE_MAX) | 790 | if (n > RT_TABLE_MAX) |
750 | return NULL; | 791 | return NULL; |
751 | 792 | ||
752 | if (dn_fib_tables[n]) | 793 | h = n & (DN_FIB_TABLE_HASHSZ - 1); |
753 | return dn_fib_tables[n]; | 794 | rcu_read_lock(); |
795 | hlist_for_each_entry_rcu(t, node, &dn_fib_table_hash[h], hlist) { | ||
796 | if (t->n == n) { | ||
797 | rcu_read_unlock(); | ||
798 | return t; | ||
799 | } | ||
800 | } | ||
801 | rcu_read_unlock(); | ||
754 | 802 | ||
755 | if (!create) | 803 | if (!create) |
756 | return NULL; | 804 | return NULL; |
@@ -771,33 +819,37 @@ struct dn_fib_table *dn_fib_get_table(int n, int create) | |||
771 | t->flush = dn_fib_table_flush; | 819 | t->flush = dn_fib_table_flush; |
772 | t->dump = dn_fib_table_dump; | 820 | t->dump = dn_fib_table_dump; |
773 | memset(t->data, 0, sizeof(struct dn_hash)); | 821 | memset(t->data, 0, sizeof(struct dn_hash)); |
774 | dn_fib_tables[n] = t; | 822 | hlist_add_head_rcu(&t->hlist, &dn_fib_table_hash[h]); |
775 | 823 | ||
776 | return t; | 824 | return t; |
777 | } | 825 | } |
778 | 826 | ||
779 | static void dn_fib_del_tree(int n) | ||
780 | { | ||
781 | struct dn_fib_table *t; | ||
782 | |||
783 | write_lock(&dn_fib_tables_lock); | ||
784 | t = dn_fib_tables[n]; | ||
785 | dn_fib_tables[n] = NULL; | ||
786 | write_unlock(&dn_fib_tables_lock); | ||
787 | |||
788 | kfree(t); | ||
789 | } | ||
790 | |||
791 | struct dn_fib_table *dn_fib_empty_table(void) | 827 | struct dn_fib_table *dn_fib_empty_table(void) |
792 | { | 828 | { |
793 | int id; | 829 | u32 id; |
794 | 830 | ||
795 | for(id = RT_TABLE_MIN; id <= RT_TABLE_MAX; id++) | 831 | for(id = RT_TABLE_MIN; id <= RT_TABLE_MAX; id++) |
796 | if (dn_fib_tables[id] == NULL) | 832 | if (dn_fib_get_table(id, 0) == NULL) |
797 | return dn_fib_get_table(id, 1); | 833 | return dn_fib_get_table(id, 1); |
798 | return NULL; | 834 | return NULL; |
799 | } | 835 | } |
800 | 836 | ||
837 | void dn_fib_flush(void) | ||
838 | { | ||
839 | int flushed = 0; | ||
840 | struct dn_fib_table *tb; | ||
841 | struct hlist_node *node; | ||
842 | unsigned int h; | ||
843 | |||
844 | for (h = 0; h < DN_FIB_TABLE_HASHSZ; h++) { | ||
845 | hlist_for_each_entry(tb, node, &dn_fib_table_hash[h], hlist) | ||
846 | flushed += tb->flush(tb); | ||
847 | } | ||
848 | |||
849 | if (flushed) | ||
850 | dn_rt_cache_flush(-1); | ||
851 | } | ||
852 | |||
801 | void __init dn_fib_table_init(void) | 853 | void __init dn_fib_table_init(void) |
802 | { | 854 | { |
803 | dn_hash_kmem = kmem_cache_create("dn_fib_info_cache", | 855 | dn_hash_kmem = kmem_cache_create("dn_fib_info_cache", |
@@ -808,10 +860,17 @@ void __init dn_fib_table_init(void) | |||
808 | 860 | ||
809 | void __exit dn_fib_table_cleanup(void) | 861 | void __exit dn_fib_table_cleanup(void) |
810 | { | 862 | { |
811 | int i; | 863 | struct dn_fib_table *t; |
812 | 864 | struct hlist_node *node, *next; | |
813 | for (i = RT_TABLE_MIN; i <= RT_TABLE_MAX; ++i) | 865 | unsigned int h; |
814 | dn_fib_del_tree(i); | ||
815 | 866 | ||
816 | return; | 867 | write_lock(&dn_fib_tables_lock); |
868 | for (h = 0; h < DN_FIB_TABLE_HASHSZ; h++) { | ||
869 | hlist_for_each_entry_safe(t, node, next, &dn_fib_table_hash[h], | ||
870 | hlist) { | ||
871 | hlist_del(&t->hlist); | ||
872 | kfree(t); | ||
873 | } | ||
874 | } | ||
875 | write_unlock(&dn_fib_tables_lock); | ||
817 | } | 876 | } |
diff --git a/net/ethernet/eth.c b/net/ethernet/eth.c index 387c71c584ee..43863933f27f 100644 --- a/net/ethernet/eth.c +++ b/net/ethernet/eth.c | |||
@@ -64,81 +64,79 @@ | |||
64 | 64 | ||
65 | __setup("ether=", netdev_boot_setup); | 65 | __setup("ether=", netdev_boot_setup); |
66 | 66 | ||
67 | /* | 67 | /** |
68 | * Create the Ethernet MAC header for an arbitrary protocol layer | 68 | * eth_header - create the Ethernet header |
69 | * @skb: buffer to alter | ||
70 | * @dev: source device | ||
71 | * @type: Ethernet type field | ||
72 | * @daddr: destination address (NULL leave destination address) | ||
73 | * @saddr: source address (NULL use device source address) | ||
74 | * @len: packet length (<= skb->len) | ||
69 | * | 75 | * |
70 | * saddr=NULL means use device source address | 76 | * |
71 | * daddr=NULL means leave destination address (eg unresolved arp) | 77 | * Set the protocol type. For a packet of type ETH_P_802_3 we put the length |
78 | * in here instead. It is up to the 802.2 layer to carry protocol information. | ||
72 | */ | 79 | */ |
73 | |||
74 | int eth_header(struct sk_buff *skb, struct net_device *dev, unsigned short type, | 80 | int eth_header(struct sk_buff *skb, struct net_device *dev, unsigned short type, |
75 | void *daddr, void *saddr, unsigned len) | 81 | void *daddr, void *saddr, unsigned len) |
76 | { | 82 | { |
77 | struct ethhdr *eth = (struct ethhdr *)skb_push(skb,ETH_HLEN); | 83 | struct ethhdr *eth = (struct ethhdr *)skb_push(skb, ETH_HLEN); |
78 | 84 | ||
79 | /* | 85 | if (type != ETH_P_802_3) |
80 | * Set the protocol type. For a packet of type ETH_P_802_3 we put the length | ||
81 | * in here instead. It is up to the 802.2 layer to carry protocol information. | ||
82 | */ | ||
83 | |||
84 | if(type!=ETH_P_802_3) | ||
85 | eth->h_proto = htons(type); | 86 | eth->h_proto = htons(type); |
86 | else | 87 | else |
87 | eth->h_proto = htons(len); | 88 | eth->h_proto = htons(len); |
88 | 89 | ||
89 | /* | 90 | /* |
90 | * Set the source hardware address. | 91 | * Set the source hardware address. |
91 | */ | 92 | */ |
92 | 93 | ||
93 | if(!saddr) | 94 | if (!saddr) |
94 | saddr = dev->dev_addr; | 95 | saddr = dev->dev_addr; |
95 | memcpy(eth->h_source,saddr,dev->addr_len); | 96 | memcpy(eth->h_source, saddr, dev->addr_len); |
96 | 97 | ||
97 | if(daddr) | 98 | if (daddr) { |
98 | { | 99 | memcpy(eth->h_dest, daddr, dev->addr_len); |
99 | memcpy(eth->h_dest,daddr,dev->addr_len); | ||
100 | return ETH_HLEN; | 100 | return ETH_HLEN; |
101 | } | 101 | } |
102 | 102 | ||
103 | /* | 103 | /* |
104 | * Anyway, the loopback-device should never use this function... | 104 | * Anyway, the loopback-device should never use this function... |
105 | */ | 105 | */ |
106 | 106 | ||
107 | if (dev->flags & (IFF_LOOPBACK|IFF_NOARP)) | 107 | if (dev->flags & (IFF_LOOPBACK | IFF_NOARP)) { |
108 | { | ||
109 | memset(eth->h_dest, 0, dev->addr_len); | 108 | memset(eth->h_dest, 0, dev->addr_len); |
110 | return ETH_HLEN; | 109 | return ETH_HLEN; |
111 | } | 110 | } |
112 | 111 | ||
113 | return -ETH_HLEN; | 112 | return -ETH_HLEN; |
114 | } | 113 | } |
115 | 114 | ||
116 | 115 | /** | |
117 | /* | 116 | * eth_rebuild_header- rebuild the Ethernet MAC header. |
118 | * Rebuild the Ethernet MAC header. This is called after an ARP | 117 | * @skb: socket buffer to update |
119 | * (or in future other address resolution) has completed on this | ||
120 | * sk_buff. We now let ARP fill in the other fields. | ||
121 | * | 118 | * |
122 | * This routine CANNOT use cached dst->neigh! | 119 | * This is called after an ARP or IPV6 ndisc it's resolution on this |
123 | * Really, it is used only when dst->neigh is wrong. | 120 | * sk_buff. We now let protocol (ARP) fill in the other fields. |
121 | * | ||
122 | * This routine CANNOT use cached dst->neigh! | ||
123 | * Really, it is used only when dst->neigh is wrong. | ||
124 | */ | 124 | */ |
125 | |||
126 | int eth_rebuild_header(struct sk_buff *skb) | 125 | int eth_rebuild_header(struct sk_buff *skb) |
127 | { | 126 | { |
128 | struct ethhdr *eth = (struct ethhdr *)skb->data; | 127 | struct ethhdr *eth = (struct ethhdr *)skb->data; |
129 | struct net_device *dev = skb->dev; | 128 | struct net_device *dev = skb->dev; |
130 | 129 | ||
131 | switch (eth->h_proto) | 130 | switch (eth->h_proto) { |
132 | { | ||
133 | #ifdef CONFIG_INET | 131 | #ifdef CONFIG_INET |
134 | case __constant_htons(ETH_P_IP): | 132 | case __constant_htons(ETH_P_IP): |
135 | return arp_find(eth->h_dest, skb); | 133 | return arp_find(eth->h_dest, skb); |
136 | #endif | 134 | #endif |
137 | default: | 135 | default: |
138 | printk(KERN_DEBUG | 136 | printk(KERN_DEBUG |
139 | "%s: unable to resolve type %X addresses.\n", | 137 | "%s: unable to resolve type %X addresses.\n", |
140 | dev->name, (int)eth->h_proto); | 138 | dev->name, (int)eth->h_proto); |
141 | 139 | ||
142 | memcpy(eth->h_source, dev->dev_addr, dev->addr_len); | 140 | memcpy(eth->h_source, dev->dev_addr, dev->addr_len); |
143 | break; | 141 | break; |
144 | } | 142 | } |
@@ -146,62 +144,70 @@ int eth_rebuild_header(struct sk_buff *skb) | |||
146 | return 0; | 144 | return 0; |
147 | } | 145 | } |
148 | 146 | ||
149 | 147 | /** | |
150 | /* | 148 | * eth_type_trans - determine the packet's protocol ID. |
151 | * Determine the packet's protocol ID. The rule here is that we | 149 | * @skb: received socket data |
152 | * assume 802.3 if the type field is short enough to be a length. | 150 | * @dev: receiving network device |
153 | * This is normal practice and works for any 'now in use' protocol. | 151 | * |
152 | * The rule here is that we | ||
153 | * assume 802.3 if the type field is short enough to be a length. | ||
154 | * This is normal practice and works for any 'now in use' protocol. | ||
154 | */ | 155 | */ |
155 | |||
156 | __be16 eth_type_trans(struct sk_buff *skb, struct net_device *dev) | 156 | __be16 eth_type_trans(struct sk_buff *skb, struct net_device *dev) |
157 | { | 157 | { |
158 | struct ethhdr *eth; | 158 | struct ethhdr *eth; |
159 | unsigned char *rawp; | 159 | unsigned char *rawp; |
160 | 160 | ||
161 | skb->mac.raw = skb->data; | 161 | skb->mac.raw = skb->data; |
162 | skb_pull(skb,ETH_HLEN); | 162 | skb_pull(skb, ETH_HLEN); |
163 | eth = eth_hdr(skb); | 163 | eth = eth_hdr(skb); |
164 | 164 | ||
165 | if (is_multicast_ether_addr(eth->h_dest)) { | 165 | if (is_multicast_ether_addr(eth->h_dest)) { |
166 | if (!compare_ether_addr(eth->h_dest, dev->broadcast)) | 166 | if (!compare_ether_addr(eth->h_dest, dev->broadcast)) |
167 | skb->pkt_type = PACKET_BROADCAST; | 167 | skb->pkt_type = PACKET_BROADCAST; |
168 | else | 168 | else |
169 | skb->pkt_type = PACKET_MULTICAST; | 169 | skb->pkt_type = PACKET_MULTICAST; |
170 | } | 170 | } |
171 | 171 | ||
172 | /* | 172 | /* |
173 | * This ALLMULTI check should be redundant by 1.4 | 173 | * This ALLMULTI check should be redundant by 1.4 |
174 | * so don't forget to remove it. | 174 | * so don't forget to remove it. |
175 | * | 175 | * |
176 | * Seems, you forgot to remove it. All silly devices | 176 | * Seems, you forgot to remove it. All silly devices |
177 | * seems to set IFF_PROMISC. | 177 | * seems to set IFF_PROMISC. |
178 | */ | 178 | */ |
179 | 179 | ||
180 | else if(1 /*dev->flags&IFF_PROMISC*/) { | 180 | else if (1 /*dev->flags&IFF_PROMISC */ ) { |
181 | if (unlikely(compare_ether_addr(eth->h_dest, dev->dev_addr))) | 181 | if (unlikely(compare_ether_addr(eth->h_dest, dev->dev_addr))) |
182 | skb->pkt_type = PACKET_OTHERHOST; | 182 | skb->pkt_type = PACKET_OTHERHOST; |
183 | } | 183 | } |
184 | 184 | ||
185 | if (ntohs(eth->h_proto) >= 1536) | 185 | if (ntohs(eth->h_proto) >= 1536) |
186 | return eth->h_proto; | 186 | return eth->h_proto; |
187 | 187 | ||
188 | rawp = skb->data; | 188 | rawp = skb->data; |
189 | 189 | ||
190 | /* | 190 | /* |
191 | * This is a magic hack to spot IPX packets. Older Novell breaks | 191 | * This is a magic hack to spot IPX packets. Older Novell breaks |
192 | * the protocol design and runs IPX over 802.3 without an 802.2 LLC | 192 | * the protocol design and runs IPX over 802.3 without an 802.2 LLC |
193 | * layer. We look for FFFF which isn't a used 802.2 SSAP/DSAP. This | 193 | * layer. We look for FFFF which isn't a used 802.2 SSAP/DSAP. This |
194 | * won't work for fault tolerant netware but does for the rest. | 194 | * won't work for fault tolerant netware but does for the rest. |
195 | */ | 195 | */ |
196 | if (*(unsigned short *)rawp == 0xFFFF) | 196 | if (*(unsigned short *)rawp == 0xFFFF) |
197 | return htons(ETH_P_802_3); | 197 | return htons(ETH_P_802_3); |
198 | 198 | ||
199 | /* | 199 | /* |
200 | * Real 802.2 LLC | 200 | * Real 802.2 LLC |
201 | */ | 201 | */ |
202 | return htons(ETH_P_802_2); | 202 | return htons(ETH_P_802_2); |
203 | } | 203 | } |
204 | EXPORT_SYMBOL(eth_type_trans); | ||
204 | 205 | ||
206 | /** | ||
207 | * eth_header_parse - extract hardware address from packet | ||
208 | * @skb: packet to extract header from | ||
209 | * @haddr: destination buffer | ||
210 | */ | ||
205 | static int eth_header_parse(struct sk_buff *skb, unsigned char *haddr) | 211 | static int eth_header_parse(struct sk_buff *skb, unsigned char *haddr) |
206 | { | 212 | { |
207 | struct ethhdr *eth = eth_hdr(skb); | 213 | struct ethhdr *eth = eth_hdr(skb); |
@@ -209,14 +215,20 @@ static int eth_header_parse(struct sk_buff *skb, unsigned char *haddr) | |||
209 | return ETH_ALEN; | 215 | return ETH_ALEN; |
210 | } | 216 | } |
211 | 217 | ||
218 | /** | ||
219 | * eth_header_cache - fill cache entry from neighbour | ||
220 | * @neigh: source neighbour | ||
221 | * @hh: destination cache entry | ||
222 | * Create an Ethernet header template from the neighbour. | ||
223 | */ | ||
212 | int eth_header_cache(struct neighbour *neigh, struct hh_cache *hh) | 224 | int eth_header_cache(struct neighbour *neigh, struct hh_cache *hh) |
213 | { | 225 | { |
214 | unsigned short type = hh->hh_type; | 226 | unsigned short type = hh->hh_type; |
215 | struct ethhdr *eth; | 227 | struct ethhdr *eth; |
216 | struct net_device *dev = neigh->dev; | 228 | struct net_device *dev = neigh->dev; |
217 | 229 | ||
218 | eth = (struct ethhdr*) | 230 | eth = (struct ethhdr *) |
219 | (((u8*)hh->hh_data) + (HH_DATA_OFF(sizeof(*eth)))); | 231 | (((u8 *) hh->hh_data) + (HH_DATA_OFF(sizeof(*eth)))); |
220 | 232 | ||
221 | if (type == __constant_htons(ETH_P_802_3)) | 233 | if (type == __constant_htons(ETH_P_802_3)) |
222 | return -1; | 234 | return -1; |
@@ -228,27 +240,47 @@ int eth_header_cache(struct neighbour *neigh, struct hh_cache *hh) | |||
228 | return 0; | 240 | return 0; |
229 | } | 241 | } |
230 | 242 | ||
231 | /* | 243 | /** |
244 | * eth_header_cache_update - update cache entry | ||
245 | * @hh: destination cache entry | ||
246 | * @dev: network device | ||
247 | * @haddr: new hardware address | ||
248 | * | ||
232 | * Called by Address Resolution module to notify changes in address. | 249 | * Called by Address Resolution module to notify changes in address. |
233 | */ | 250 | */ |
234 | 251 | void eth_header_cache_update(struct hh_cache *hh, struct net_device *dev, | |
235 | void eth_header_cache_update(struct hh_cache *hh, struct net_device *dev, unsigned char * haddr) | 252 | unsigned char *haddr) |
236 | { | 253 | { |
237 | memcpy(((u8*)hh->hh_data) + HH_DATA_OFF(sizeof(struct ethhdr)), | 254 | memcpy(((u8 *) hh->hh_data) + HH_DATA_OFF(sizeof(struct ethhdr)), |
238 | haddr, dev->addr_len); | 255 | haddr, dev->addr_len); |
239 | } | 256 | } |
240 | 257 | ||
241 | EXPORT_SYMBOL(eth_type_trans); | 258 | /** |
242 | 259 | * eth_mac_addr - set new Ethernet hardware address | |
260 | * @dev: network device | ||
261 | * @p: socket address | ||
262 | * Change hardware address of device. | ||
263 | * | ||
264 | * This doesn't change hardware matching, so needs to be overridden | ||
265 | * for most real devices. | ||
266 | */ | ||
243 | static int eth_mac_addr(struct net_device *dev, void *p) | 267 | static int eth_mac_addr(struct net_device *dev, void *p) |
244 | { | 268 | { |
245 | struct sockaddr *addr=p; | 269 | struct sockaddr *addr = p; |
246 | if (netif_running(dev)) | 270 | if (netif_running(dev)) |
247 | return -EBUSY; | 271 | return -EBUSY; |
248 | memcpy(dev->dev_addr, addr->sa_data,dev->addr_len); | 272 | memcpy(dev->dev_addr, addr->sa_data, dev->addr_len); |
249 | return 0; | 273 | return 0; |
250 | } | 274 | } |
251 | 275 | ||
276 | /** | ||
277 | * eth_change_mtu - set new MTU size | ||
278 | * @dev: network device | ||
279 | * @new_mtu: new Maximum Transfer Unit | ||
280 | * | ||
281 | * Allow changing MTU size. Needs to be overridden for devices | ||
282 | * supporting jumbo frames. | ||
283 | */ | ||
252 | static int eth_change_mtu(struct net_device *dev, int new_mtu) | 284 | static int eth_change_mtu(struct net_device *dev, int new_mtu) |
253 | { | 285 | { |
254 | if (new_mtu < 68 || new_mtu > ETH_DATA_LEN) | 286 | if (new_mtu < 68 || new_mtu > ETH_DATA_LEN) |
@@ -257,8 +289,10 @@ static int eth_change_mtu(struct net_device *dev, int new_mtu) | |||
257 | return 0; | 289 | return 0; |
258 | } | 290 | } |
259 | 291 | ||
260 | /* | 292 | /** |
261 | * Fill in the fields of the device structure with ethernet-generic values. | 293 | * ether_setup - setup Ethernet network device |
294 | * @dev: network device | ||
295 | * Fill in the fields of the device structure with Ethernet-generic values. | ||
262 | */ | 296 | */ |
263 | void ether_setup(struct net_device *dev) | 297 | void ether_setup(struct net_device *dev) |
264 | { | 298 | { |
@@ -277,21 +311,21 @@ void ether_setup(struct net_device *dev) | |||
277 | dev->tx_queue_len = 1000; /* Ethernet wants good queues */ | 311 | dev->tx_queue_len = 1000; /* Ethernet wants good queues */ |
278 | dev->flags = IFF_BROADCAST|IFF_MULTICAST; | 312 | dev->flags = IFF_BROADCAST|IFF_MULTICAST; |
279 | 313 | ||
280 | memset(dev->broadcast,0xFF, ETH_ALEN); | 314 | memset(dev->broadcast, 0xFF, ETH_ALEN); |
281 | 315 | ||
282 | } | 316 | } |
283 | EXPORT_SYMBOL(ether_setup); | 317 | EXPORT_SYMBOL(ether_setup); |
284 | 318 | ||
285 | /** | 319 | /** |
286 | * alloc_etherdev - Allocates and sets up an ethernet device | 320 | * alloc_etherdev - Allocates and sets up an Ethernet device |
287 | * @sizeof_priv: Size of additional driver-private structure to be allocated | 321 | * @sizeof_priv: Size of additional driver-private structure to be allocated |
288 | * for this ethernet device | 322 | * for this Ethernet device |
289 | * | 323 | * |
290 | * Fill in the fields of the device structure with ethernet-generic | 324 | * Fill in the fields of the device structure with Ethernet-generic |
291 | * values. Basically does everything except registering the device. | 325 | * values. Basically does everything except registering the device. |
292 | * | 326 | * |
293 | * Constructs a new net device, complete with a private data area of | 327 | * Constructs a new net device, complete with a private data area of |
294 | * size @sizeof_priv. A 32-byte (not bit) alignment is enforced for | 328 | * size (sizeof_priv). A 32-byte (not bit) alignment is enforced for |
295 | * this private data area. | 329 | * this private data area. |
296 | */ | 330 | */ |
297 | 331 | ||
diff --git a/net/ipv4/Kconfig b/net/ipv4/Kconfig index 3b5d504a74be..1650b64415aa 100644 --- a/net/ipv4/Kconfig +++ b/net/ipv4/Kconfig | |||
@@ -88,6 +88,7 @@ config IP_FIB_HASH | |||
88 | config IP_MULTIPLE_TABLES | 88 | config IP_MULTIPLE_TABLES |
89 | bool "IP: policy routing" | 89 | bool "IP: policy routing" |
90 | depends on IP_ADVANCED_ROUTER | 90 | depends on IP_ADVANCED_ROUTER |
91 | select FIB_RULES | ||
91 | ---help--- | 92 | ---help--- |
92 | Normally, a router decides what to do with a received packet based | 93 | Normally, a router decides what to do with a received packet based |
93 | solely on the packet's final destination address. If you say Y here, | 94 | solely on the packet's final destination address. If you say Y here, |
diff --git a/net/ipv4/Makefile b/net/ipv4/Makefile index 4878fc5be85f..f66049e28aeb 100644 --- a/net/ipv4/Makefile +++ b/net/ipv4/Makefile | |||
@@ -47,6 +47,7 @@ obj-$(CONFIG_TCP_CONG_VEGAS) += tcp_vegas.o | |||
47 | obj-$(CONFIG_TCP_CONG_VENO) += tcp_veno.o | 47 | obj-$(CONFIG_TCP_CONG_VENO) += tcp_veno.o |
48 | obj-$(CONFIG_TCP_CONG_SCALABLE) += tcp_scalable.o | 48 | obj-$(CONFIG_TCP_CONG_SCALABLE) += tcp_scalable.o |
49 | obj-$(CONFIG_TCP_CONG_LP) += tcp_lp.o | 49 | obj-$(CONFIG_TCP_CONG_LP) += tcp_lp.o |
50 | obj-$(CONFIG_NETLABEL) += cipso_ipv4.o | ||
50 | 51 | ||
51 | obj-$(CONFIG_XFRM) += xfrm4_policy.o xfrm4_state.o xfrm4_input.o \ | 52 | obj-$(CONFIG_XFRM) += xfrm4_policy.o xfrm4_state.o xfrm4_input.o \ |
52 | xfrm4_output.o | 53 | xfrm4_output.o |
diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c index c84a32070f8d..fdd89e37b9aa 100644 --- a/net/ipv4/af_inet.c +++ b/net/ipv4/af_inet.c | |||
@@ -67,7 +67,6 @@ | |||
67 | * 2 of the License, or (at your option) any later version. | 67 | * 2 of the License, or (at your option) any later version. |
68 | */ | 68 | */ |
69 | 69 | ||
70 | #include <linux/config.h> | ||
71 | #include <linux/err.h> | 70 | #include <linux/err.h> |
72 | #include <linux/errno.h> | 71 | #include <linux/errno.h> |
73 | #include <linux/types.h> | 72 | #include <linux/types.h> |
@@ -392,7 +391,7 @@ int inet_release(struct socket *sock) | |||
392 | } | 391 | } |
393 | 392 | ||
394 | /* It is off by default, see below. */ | 393 | /* It is off by default, see below. */ |
395 | int sysctl_ip_nonlocal_bind; | 394 | int sysctl_ip_nonlocal_bind __read_mostly; |
396 | 395 | ||
397 | int inet_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len) | 396 | int inet_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len) |
398 | { | 397 | { |
@@ -988,7 +987,7 @@ void inet_unregister_protosw(struct inet_protosw *p) | |||
988 | * Shall we try to damage output packets if routing dev changes? | 987 | * Shall we try to damage output packets if routing dev changes? |
989 | */ | 988 | */ |
990 | 989 | ||
991 | int sysctl_ip_dynaddr; | 990 | int sysctl_ip_dynaddr __read_mostly; |
992 | 991 | ||
993 | static int inet_sk_reselect_saddr(struct sock *sk) | 992 | static int inet_sk_reselect_saddr(struct sock *sk) |
994 | { | 993 | { |
@@ -1074,6 +1073,7 @@ int inet_sk_rebuild_header(struct sock *sk) | |||
1074 | }, | 1073 | }, |
1075 | }; | 1074 | }; |
1076 | 1075 | ||
1076 | security_sk_classify_flow(sk, &fl); | ||
1077 | err = ip_route_output_flow(&rt, &fl, sk, 0); | 1077 | err = ip_route_output_flow(&rt, &fl, sk, 0); |
1078 | } | 1078 | } |
1079 | if (!err) | 1079 | if (!err) |
@@ -1254,10 +1254,7 @@ static int __init inet_init(void) | |||
1254 | struct list_head *r; | 1254 | struct list_head *r; |
1255 | int rc = -EINVAL; | 1255 | int rc = -EINVAL; |
1256 | 1256 | ||
1257 | if (sizeof(struct inet_skb_parm) > sizeof(dummy_skb->cb)) { | 1257 | BUILD_BUG_ON(sizeof(struct inet_skb_parm) > sizeof(dummy_skb->cb)); |
1258 | printk(KERN_CRIT "%s: panic\n", __FUNCTION__); | ||
1259 | goto out; | ||
1260 | } | ||
1261 | 1258 | ||
1262 | rc = proto_register(&tcp_prot, 1); | 1259 | rc = proto_register(&tcp_prot, 1); |
1263 | if (rc) | 1260 | if (rc) |
diff --git a/net/ipv4/ah4.c b/net/ipv4/ah4.c index 2b98943e6b02..99542977e47e 100644 --- a/net/ipv4/ah4.c +++ b/net/ipv4/ah4.c | |||
@@ -35,7 +35,7 @@ static int ip_clear_mutable_options(struct iphdr *iph, u32 *daddr) | |||
35 | switch (*optptr) { | 35 | switch (*optptr) { |
36 | case IPOPT_SEC: | 36 | case IPOPT_SEC: |
37 | case 0x85: /* Some "Extended Security" crap. */ | 37 | case 0x85: /* Some "Extended Security" crap. */ |
38 | case 0x86: /* Another "Commercial Security" crap. */ | 38 | case IPOPT_CIPSO: |
39 | case IPOPT_RA: | 39 | case IPOPT_RA: |
40 | case 0x80|21: /* RFC1770 */ | 40 | case 0x80|21: /* RFC1770 */ |
41 | break; | 41 | break; |
@@ -265,7 +265,7 @@ static int ah_init_state(struct xfrm_state *x) | |||
265 | goto error; | 265 | goto error; |
266 | 266 | ||
267 | x->props.header_len = XFRM_ALIGN8(sizeof(struct ip_auth_hdr) + ahp->icv_trunc_len); | 267 | x->props.header_len = XFRM_ALIGN8(sizeof(struct ip_auth_hdr) + ahp->icv_trunc_len); |
268 | if (x->props.mode) | 268 | if (x->props.mode == XFRM_MODE_TUNNEL) |
269 | x->props.header_len += sizeof(struct iphdr); | 269 | x->props.header_len += sizeof(struct iphdr); |
270 | x->data = ahp; | 270 | x->data = ahp; |
271 | 271 | ||
diff --git a/net/ipv4/cipso_ipv4.c b/net/ipv4/cipso_ipv4.c new file mode 100644 index 000000000000..80a2a0911b49 --- /dev/null +++ b/net/ipv4/cipso_ipv4.c | |||
@@ -0,0 +1,1607 @@ | |||
1 | /* | ||
2 | * CIPSO - Commercial IP Security Option | ||
3 | * | ||
4 | * This is an implementation of the CIPSO 2.2 protocol as specified in | ||
5 | * draft-ietf-cipso-ipsecurity-01.txt with additional tag types as found in | ||
6 | * FIPS-188, copies of both documents can be found in the Documentation | ||
7 | * directory. While CIPSO never became a full IETF RFC standard many vendors | ||
8 | * have chosen to adopt the protocol and over the years it has become a | ||
9 | * de-facto standard for labeled networking. | ||
10 | * | ||
11 | * Author: Paul Moore <paul.moore@hp.com> | ||
12 | * | ||
13 | */ | ||
14 | |||
15 | /* | ||
16 | * (c) Copyright Hewlett-Packard Development Company, L.P., 2006 | ||
17 | * | ||
18 | * This program is free software; you can redistribute it and/or modify | ||
19 | * it under the terms of the GNU General Public License as published by | ||
20 | * the Free Software Foundation; either version 2 of the License, or | ||
21 | * (at your option) any later version. | ||
22 | * | ||
23 | * This program is distributed in the hope that it will be useful, | ||
24 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
25 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See | ||
26 | * the GNU General Public License for more details. | ||
27 | * | ||
28 | * You should have received a copy of the GNU General Public License | ||
29 | * along with this program; if not, write to the Free Software | ||
30 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
31 | * | ||
32 | */ | ||
33 | |||
34 | #include <linux/init.h> | ||
35 | #include <linux/types.h> | ||
36 | #include <linux/rcupdate.h> | ||
37 | #include <linux/list.h> | ||
38 | #include <linux/spinlock.h> | ||
39 | #include <linux/string.h> | ||
40 | #include <linux/jhash.h> | ||
41 | #include <net/ip.h> | ||
42 | #include <net/icmp.h> | ||
43 | #include <net/tcp.h> | ||
44 | #include <net/netlabel.h> | ||
45 | #include <net/cipso_ipv4.h> | ||
46 | #include <asm/bug.h> | ||
47 | |||
48 | struct cipso_v4_domhsh_entry { | ||
49 | char *domain; | ||
50 | u32 valid; | ||
51 | struct list_head list; | ||
52 | struct rcu_head rcu; | ||
53 | }; | ||
54 | |||
55 | /* List of available DOI definitions */ | ||
56 | /* XXX - Updates should be minimal so having a single lock for the | ||
57 | * cipso_v4_doi_list and the cipso_v4_doi_list->dom_list should be | ||
58 | * okay. */ | ||
59 | /* XXX - This currently assumes a minimal number of different DOIs in use, | ||
60 | * if in practice there are a lot of different DOIs this list should | ||
61 | * probably be turned into a hash table or something similar so we | ||
62 | * can do quick lookups. */ | ||
63 | static DEFINE_SPINLOCK(cipso_v4_doi_list_lock); | ||
64 | static struct list_head cipso_v4_doi_list = LIST_HEAD_INIT(cipso_v4_doi_list); | ||
65 | |||
66 | /* Label mapping cache */ | ||
67 | int cipso_v4_cache_enabled = 1; | ||
68 | int cipso_v4_cache_bucketsize = 10; | ||
69 | #define CIPSO_V4_CACHE_BUCKETBITS 7 | ||
70 | #define CIPSO_V4_CACHE_BUCKETS (1 << CIPSO_V4_CACHE_BUCKETBITS) | ||
71 | #define CIPSO_V4_CACHE_REORDERLIMIT 10 | ||
72 | struct cipso_v4_map_cache_bkt { | ||
73 | spinlock_t lock; | ||
74 | u32 size; | ||
75 | struct list_head list; | ||
76 | }; | ||
77 | struct cipso_v4_map_cache_entry { | ||
78 | u32 hash; | ||
79 | unsigned char *key; | ||
80 | size_t key_len; | ||
81 | |||
82 | struct netlbl_lsm_cache lsm_data; | ||
83 | |||
84 | u32 activity; | ||
85 | struct list_head list; | ||
86 | }; | ||
87 | static struct cipso_v4_map_cache_bkt *cipso_v4_cache = NULL; | ||
88 | |||
89 | /* Restricted bitmap (tag #1) flags */ | ||
90 | int cipso_v4_rbm_optfmt = 0; | ||
91 | int cipso_v4_rbm_strictvalid = 1; | ||
92 | |||
93 | /* | ||
94 | * Helper Functions | ||
95 | */ | ||
96 | |||
97 | /** | ||
98 | * cipso_v4_bitmap_walk - Walk a bitmap looking for a bit | ||
99 | * @bitmap: the bitmap | ||
100 | * @bitmap_len: length in bits | ||
101 | * @offset: starting offset | ||
102 | * @state: if non-zero, look for a set (1) bit else look for a cleared (0) bit | ||
103 | * | ||
104 | * Description: | ||
105 | * Starting at @offset, walk the bitmap from left to right until either the | ||
106 | * desired bit is found or we reach the end. Return the bit offset, -1 if | ||
107 | * not found, or -2 if error. | ||
108 | */ | ||
109 | static int cipso_v4_bitmap_walk(const unsigned char *bitmap, | ||
110 | u32 bitmap_len, | ||
111 | u32 offset, | ||
112 | u8 state) | ||
113 | { | ||
114 | u32 bit_spot; | ||
115 | u32 byte_offset; | ||
116 | unsigned char bitmask; | ||
117 | unsigned char byte; | ||
118 | |||
119 | /* gcc always rounds to zero when doing integer division */ | ||
120 | byte_offset = offset / 8; | ||
121 | byte = bitmap[byte_offset]; | ||
122 | bit_spot = offset; | ||
123 | bitmask = 0x80 >> (offset % 8); | ||
124 | |||
125 | while (bit_spot < bitmap_len) { | ||
126 | if ((state && (byte & bitmask) == bitmask) || | ||
127 | (state == 0 && (byte & bitmask) == 0)) | ||
128 | return bit_spot; | ||
129 | |||
130 | bit_spot++; | ||
131 | bitmask >>= 1; | ||
132 | if (bitmask == 0) { | ||
133 | byte = bitmap[++byte_offset]; | ||
134 | bitmask = 0x80; | ||
135 | } | ||
136 | } | ||
137 | |||
138 | return -1; | ||
139 | } | ||
140 | |||
141 | /** | ||
142 | * cipso_v4_bitmap_setbit - Sets a single bit in a bitmap | ||
143 | * @bitmap: the bitmap | ||
144 | * @bit: the bit | ||
145 | * @state: if non-zero, set the bit (1) else clear the bit (0) | ||
146 | * | ||
147 | * Description: | ||
148 | * Set a single bit in the bitmask. Returns zero on success, negative values | ||
149 | * on error. | ||
150 | */ | ||
151 | static void cipso_v4_bitmap_setbit(unsigned char *bitmap, | ||
152 | u32 bit, | ||
153 | u8 state) | ||
154 | { | ||
155 | u32 byte_spot; | ||
156 | u8 bitmask; | ||
157 | |||
158 | /* gcc always rounds to zero when doing integer division */ | ||
159 | byte_spot = bit / 8; | ||
160 | bitmask = 0x80 >> (bit % 8); | ||
161 | if (state) | ||
162 | bitmap[byte_spot] |= bitmask; | ||
163 | else | ||
164 | bitmap[byte_spot] &= ~bitmask; | ||
165 | } | ||
166 | |||
167 | /** | ||
168 | * cipso_v4_doi_domhsh_free - Frees a domain list entry | ||
169 | * @entry: the entry's RCU field | ||
170 | * | ||
171 | * Description: | ||
172 | * This function is designed to be used as a callback to the call_rcu() | ||
173 | * function so that the memory allocated to a domain list entry can be released | ||
174 | * safely. | ||
175 | * | ||
176 | */ | ||
177 | static void cipso_v4_doi_domhsh_free(struct rcu_head *entry) | ||
178 | { | ||
179 | struct cipso_v4_domhsh_entry *ptr; | ||
180 | |||
181 | ptr = container_of(entry, struct cipso_v4_domhsh_entry, rcu); | ||
182 | kfree(ptr->domain); | ||
183 | kfree(ptr); | ||
184 | } | ||
185 | |||
186 | /** | ||
187 | * cipso_v4_cache_entry_free - Frees a cache entry | ||
188 | * @entry: the entry to free | ||
189 | * | ||
190 | * Description: | ||
191 | * This function frees the memory associated with a cache entry. | ||
192 | * | ||
193 | */ | ||
194 | static void cipso_v4_cache_entry_free(struct cipso_v4_map_cache_entry *entry) | ||
195 | { | ||
196 | if (entry->lsm_data.free) | ||
197 | entry->lsm_data.free(entry->lsm_data.data); | ||
198 | kfree(entry->key); | ||
199 | kfree(entry); | ||
200 | } | ||
201 | |||
202 | /** | ||
203 | * cipso_v4_map_cache_hash - Hashing function for the CIPSO cache | ||
204 | * @key: the hash key | ||
205 | * @key_len: the length of the key in bytes | ||
206 | * | ||
207 | * Description: | ||
208 | * The CIPSO tag hashing function. Returns a 32-bit hash value. | ||
209 | * | ||
210 | */ | ||
211 | static u32 cipso_v4_map_cache_hash(const unsigned char *key, u32 key_len) | ||
212 | { | ||
213 | return jhash(key, key_len, 0); | ||
214 | } | ||
215 | |||
216 | /* | ||
217 | * Label Mapping Cache Functions | ||
218 | */ | ||
219 | |||
220 | /** | ||
221 | * cipso_v4_cache_init - Initialize the CIPSO cache | ||
222 | * | ||
223 | * Description: | ||
224 | * Initializes the CIPSO label mapping cache, this function should be called | ||
225 | * before any of the other functions defined in this file. Returns zero on | ||
226 | * success, negative values on error. | ||
227 | * | ||
228 | */ | ||
229 | static int cipso_v4_cache_init(void) | ||
230 | { | ||
231 | u32 iter; | ||
232 | |||
233 | cipso_v4_cache = kcalloc(CIPSO_V4_CACHE_BUCKETS, | ||
234 | sizeof(struct cipso_v4_map_cache_bkt), | ||
235 | GFP_KERNEL); | ||
236 | if (cipso_v4_cache == NULL) | ||
237 | return -ENOMEM; | ||
238 | |||
239 | for (iter = 0; iter < CIPSO_V4_CACHE_BUCKETS; iter++) { | ||
240 | spin_lock_init(&cipso_v4_cache[iter].lock); | ||
241 | cipso_v4_cache[iter].size = 0; | ||
242 | INIT_LIST_HEAD(&cipso_v4_cache[iter].list); | ||
243 | } | ||
244 | |||
245 | return 0; | ||
246 | } | ||
247 | |||
248 | /** | ||
249 | * cipso_v4_cache_invalidate - Invalidates the current CIPSO cache | ||
250 | * | ||
251 | * Description: | ||
252 | * Invalidates and frees any entries in the CIPSO cache. Returns zero on | ||
253 | * success and negative values on failure. | ||
254 | * | ||
255 | */ | ||
256 | void cipso_v4_cache_invalidate(void) | ||
257 | { | ||
258 | struct cipso_v4_map_cache_entry *entry, *tmp_entry; | ||
259 | u32 iter; | ||
260 | |||
261 | for (iter = 0; iter < CIPSO_V4_CACHE_BUCKETS; iter++) { | ||
262 | spin_lock(&cipso_v4_cache[iter].lock); | ||
263 | list_for_each_entry_safe(entry, | ||
264 | tmp_entry, | ||
265 | &cipso_v4_cache[iter].list, list) { | ||
266 | list_del(&entry->list); | ||
267 | cipso_v4_cache_entry_free(entry); | ||
268 | } | ||
269 | cipso_v4_cache[iter].size = 0; | ||
270 | spin_unlock(&cipso_v4_cache[iter].lock); | ||
271 | } | ||
272 | |||
273 | return; | ||
274 | } | ||
275 | |||
276 | /** | ||
277 | * cipso_v4_cache_check - Check the CIPSO cache for a label mapping | ||
278 | * @key: the buffer to check | ||
279 | * @key_len: buffer length in bytes | ||
280 | * @secattr: the security attribute struct to use | ||
281 | * | ||
282 | * Description: | ||
283 | * This function checks the cache to see if a label mapping already exists for | ||
284 | * the given key. If there is a match then the cache is adjusted and the | ||
285 | * @secattr struct is populated with the correct LSM security attributes. The | ||
286 | * cache is adjusted in the following manner if the entry is not already the | ||
287 | * first in the cache bucket: | ||
288 | * | ||
289 | * 1. The cache entry's activity counter is incremented | ||
290 | * 2. The previous (higher ranking) entry's activity counter is decremented | ||
291 | * 3. If the difference between the two activity counters is geater than | ||
292 | * CIPSO_V4_CACHE_REORDERLIMIT the two entries are swapped | ||
293 | * | ||
294 | * Returns zero on success, -ENOENT for a cache miss, and other negative values | ||
295 | * on error. | ||
296 | * | ||
297 | */ | ||
298 | static int cipso_v4_cache_check(const unsigned char *key, | ||
299 | u32 key_len, | ||
300 | struct netlbl_lsm_secattr *secattr) | ||
301 | { | ||
302 | u32 bkt; | ||
303 | struct cipso_v4_map_cache_entry *entry; | ||
304 | struct cipso_v4_map_cache_entry *prev_entry = NULL; | ||
305 | u32 hash; | ||
306 | |||
307 | if (!cipso_v4_cache_enabled) | ||
308 | return -ENOENT; | ||
309 | |||
310 | hash = cipso_v4_map_cache_hash(key, key_len); | ||
311 | bkt = hash & (CIPSO_V4_CACHE_BUCKETBITS - 1); | ||
312 | spin_lock(&cipso_v4_cache[bkt].lock); | ||
313 | list_for_each_entry(entry, &cipso_v4_cache[bkt].list, list) { | ||
314 | if (entry->hash == hash && | ||
315 | entry->key_len == key_len && | ||
316 | memcmp(entry->key, key, key_len) == 0) { | ||
317 | entry->activity += 1; | ||
318 | secattr->cache.free = entry->lsm_data.free; | ||
319 | secattr->cache.data = entry->lsm_data.data; | ||
320 | if (prev_entry == NULL) { | ||
321 | spin_unlock(&cipso_v4_cache[bkt].lock); | ||
322 | return 0; | ||
323 | } | ||
324 | |||
325 | if (prev_entry->activity > 0) | ||
326 | prev_entry->activity -= 1; | ||
327 | if (entry->activity > prev_entry->activity && | ||
328 | entry->activity - prev_entry->activity > | ||
329 | CIPSO_V4_CACHE_REORDERLIMIT) { | ||
330 | __list_del(entry->list.prev, entry->list.next); | ||
331 | __list_add(&entry->list, | ||
332 | prev_entry->list.prev, | ||
333 | &prev_entry->list); | ||
334 | } | ||
335 | |||
336 | spin_unlock(&cipso_v4_cache[bkt].lock); | ||
337 | return 0; | ||
338 | } | ||
339 | prev_entry = entry; | ||
340 | } | ||
341 | spin_unlock(&cipso_v4_cache[bkt].lock); | ||
342 | |||
343 | return -ENOENT; | ||
344 | } | ||
345 | |||
346 | /** | ||
347 | * cipso_v4_cache_add - Add an entry to the CIPSO cache | ||
348 | * @skb: the packet | ||
349 | * @secattr: the packet's security attributes | ||
350 | * | ||
351 | * Description: | ||
352 | * Add a new entry into the CIPSO label mapping cache. Add the new entry to | ||
353 | * head of the cache bucket's list, if the cache bucket is out of room remove | ||
354 | * the last entry in the list first. It is important to note that there is | ||
355 | * currently no checking for duplicate keys. Returns zero on success, | ||
356 | * negative values on failure. | ||
357 | * | ||
358 | */ | ||
359 | int cipso_v4_cache_add(const struct sk_buff *skb, | ||
360 | const struct netlbl_lsm_secattr *secattr) | ||
361 | { | ||
362 | int ret_val = -EPERM; | ||
363 | u32 bkt; | ||
364 | struct cipso_v4_map_cache_entry *entry = NULL; | ||
365 | struct cipso_v4_map_cache_entry *old_entry = NULL; | ||
366 | unsigned char *cipso_ptr; | ||
367 | u32 cipso_ptr_len; | ||
368 | |||
369 | if (!cipso_v4_cache_enabled || cipso_v4_cache_bucketsize <= 0) | ||
370 | return 0; | ||
371 | |||
372 | cipso_ptr = CIPSO_V4_OPTPTR(skb); | ||
373 | cipso_ptr_len = cipso_ptr[1]; | ||
374 | |||
375 | entry = kzalloc(sizeof(*entry), GFP_ATOMIC); | ||
376 | if (entry == NULL) | ||
377 | return -ENOMEM; | ||
378 | entry->key = kmalloc(cipso_ptr_len, GFP_ATOMIC); | ||
379 | if (entry->key == NULL) { | ||
380 | ret_val = -ENOMEM; | ||
381 | goto cache_add_failure; | ||
382 | } | ||
383 | memcpy(entry->key, cipso_ptr, cipso_ptr_len); | ||
384 | entry->key_len = cipso_ptr_len; | ||
385 | entry->hash = cipso_v4_map_cache_hash(cipso_ptr, cipso_ptr_len); | ||
386 | entry->lsm_data.free = secattr->cache.free; | ||
387 | entry->lsm_data.data = secattr->cache.data; | ||
388 | |||
389 | bkt = entry->hash & (CIPSO_V4_CACHE_BUCKETBITS - 1); | ||
390 | spin_lock(&cipso_v4_cache[bkt].lock); | ||
391 | if (cipso_v4_cache[bkt].size < cipso_v4_cache_bucketsize) { | ||
392 | list_add(&entry->list, &cipso_v4_cache[bkt].list); | ||
393 | cipso_v4_cache[bkt].size += 1; | ||
394 | } else { | ||
395 | old_entry = list_entry(cipso_v4_cache[bkt].list.prev, | ||
396 | struct cipso_v4_map_cache_entry, list); | ||
397 | list_del(&old_entry->list); | ||
398 | list_add(&entry->list, &cipso_v4_cache[bkt].list); | ||
399 | cipso_v4_cache_entry_free(old_entry); | ||
400 | } | ||
401 | spin_unlock(&cipso_v4_cache[bkt].lock); | ||
402 | |||
403 | return 0; | ||
404 | |||
405 | cache_add_failure: | ||
406 | if (entry) | ||
407 | cipso_v4_cache_entry_free(entry); | ||
408 | return ret_val; | ||
409 | } | ||
410 | |||
411 | /* | ||
412 | * DOI List Functions | ||
413 | */ | ||
414 | |||
415 | /** | ||
416 | * cipso_v4_doi_search - Searches for a DOI definition | ||
417 | * @doi: the DOI to search for | ||
418 | * | ||
419 | * Description: | ||
420 | * Search the DOI definition list for a DOI definition with a DOI value that | ||
421 | * matches @doi. The caller is responsibile for calling rcu_read_[un]lock(). | ||
422 | * Returns a pointer to the DOI definition on success and NULL on failure. | ||
423 | */ | ||
424 | static struct cipso_v4_doi *cipso_v4_doi_search(u32 doi) | ||
425 | { | ||
426 | struct cipso_v4_doi *iter; | ||
427 | |||
428 | list_for_each_entry_rcu(iter, &cipso_v4_doi_list, list) | ||
429 | if (iter->doi == doi && iter->valid) | ||
430 | return iter; | ||
431 | return NULL; | ||
432 | } | ||
433 | |||
434 | /** | ||
435 | * cipso_v4_doi_add - Add a new DOI to the CIPSO protocol engine | ||
436 | * @doi_def: the DOI structure | ||
437 | * | ||
438 | * Description: | ||
439 | * The caller defines a new DOI for use by the CIPSO engine and calls this | ||
440 | * function to add it to the list of acceptable domains. The caller must | ||
441 | * ensure that the mapping table specified in @doi_def->map meets all of the | ||
442 | * requirements of the mapping type (see cipso_ipv4.h for details). Returns | ||
443 | * zero on success and non-zero on failure. | ||
444 | * | ||
445 | */ | ||
446 | int cipso_v4_doi_add(struct cipso_v4_doi *doi_def) | ||
447 | { | ||
448 | if (doi_def == NULL || doi_def->doi == CIPSO_V4_DOI_UNKNOWN) | ||
449 | return -EINVAL; | ||
450 | |||
451 | doi_def->valid = 1; | ||
452 | INIT_RCU_HEAD(&doi_def->rcu); | ||
453 | INIT_LIST_HEAD(&doi_def->dom_list); | ||
454 | |||
455 | rcu_read_lock(); | ||
456 | if (cipso_v4_doi_search(doi_def->doi) != NULL) | ||
457 | goto doi_add_failure_rlock; | ||
458 | spin_lock(&cipso_v4_doi_list_lock); | ||
459 | if (cipso_v4_doi_search(doi_def->doi) != NULL) | ||
460 | goto doi_add_failure_slock; | ||
461 | list_add_tail_rcu(&doi_def->list, &cipso_v4_doi_list); | ||
462 | spin_unlock(&cipso_v4_doi_list_lock); | ||
463 | rcu_read_unlock(); | ||
464 | |||
465 | return 0; | ||
466 | |||
467 | doi_add_failure_slock: | ||
468 | spin_unlock(&cipso_v4_doi_list_lock); | ||
469 | doi_add_failure_rlock: | ||
470 | rcu_read_unlock(); | ||
471 | return -EEXIST; | ||
472 | } | ||
473 | |||
474 | /** | ||
475 | * cipso_v4_doi_remove - Remove an existing DOI from the CIPSO protocol engine | ||
476 | * @doi: the DOI value | ||
477 | * @callback: the DOI cleanup/free callback | ||
478 | * | ||
479 | * Description: | ||
480 | * Removes a DOI definition from the CIPSO engine, @callback is called to | ||
481 | * free any memory. The NetLabel routines will be called to release their own | ||
482 | * LSM domain mappings as well as our own domain list. Returns zero on | ||
483 | * success and negative values on failure. | ||
484 | * | ||
485 | */ | ||
486 | int cipso_v4_doi_remove(u32 doi, void (*callback) (struct rcu_head * head)) | ||
487 | { | ||
488 | struct cipso_v4_doi *doi_def; | ||
489 | struct cipso_v4_domhsh_entry *dom_iter; | ||
490 | |||
491 | rcu_read_lock(); | ||
492 | if (cipso_v4_doi_search(doi) != NULL) { | ||
493 | spin_lock(&cipso_v4_doi_list_lock); | ||
494 | doi_def = cipso_v4_doi_search(doi); | ||
495 | if (doi_def == NULL) { | ||
496 | spin_unlock(&cipso_v4_doi_list_lock); | ||
497 | rcu_read_unlock(); | ||
498 | return -ENOENT; | ||
499 | } | ||
500 | doi_def->valid = 0; | ||
501 | list_del_rcu(&doi_def->list); | ||
502 | spin_unlock(&cipso_v4_doi_list_lock); | ||
503 | list_for_each_entry_rcu(dom_iter, &doi_def->dom_list, list) | ||
504 | if (dom_iter->valid) | ||
505 | netlbl_domhsh_remove(dom_iter->domain); | ||
506 | cipso_v4_cache_invalidate(); | ||
507 | rcu_read_unlock(); | ||
508 | |||
509 | call_rcu(&doi_def->rcu, callback); | ||
510 | return 0; | ||
511 | } | ||
512 | rcu_read_unlock(); | ||
513 | |||
514 | return -ENOENT; | ||
515 | } | ||
516 | |||
517 | /** | ||
518 | * cipso_v4_doi_getdef - Returns a pointer to a valid DOI definition | ||
519 | * @doi: the DOI value | ||
520 | * | ||
521 | * Description: | ||
522 | * Searches for a valid DOI definition and if one is found it is returned to | ||
523 | * the caller. Otherwise NULL is returned. The caller must ensure that | ||
524 | * rcu_read_lock() is held while accessing the returned definition. | ||
525 | * | ||
526 | */ | ||
527 | struct cipso_v4_doi *cipso_v4_doi_getdef(u32 doi) | ||
528 | { | ||
529 | return cipso_v4_doi_search(doi); | ||
530 | } | ||
531 | |||
532 | /** | ||
533 | * cipso_v4_doi_dump_all - Dump all the CIPSO DOI definitions into a sk_buff | ||
534 | * @headroom: the amount of headroom to allocate for the sk_buff | ||
535 | * | ||
536 | * Description: | ||
537 | * Dump a list of all the configured DOI values into a sk_buff. The returned | ||
538 | * sk_buff has room at the front of the sk_buff for @headroom bytes. See | ||
539 | * net/netlabel/netlabel_cipso_v4.h for the LISTALL message format. This | ||
540 | * function may fail if another process is changing the DOI list at the same | ||
541 | * time. Returns a pointer to a sk_buff on success, NULL on error. | ||
542 | * | ||
543 | */ | ||
544 | struct sk_buff *cipso_v4_doi_dump_all(size_t headroom) | ||
545 | { | ||
546 | struct sk_buff *skb = NULL; | ||
547 | struct cipso_v4_doi *iter; | ||
548 | u32 doi_cnt = 0; | ||
549 | ssize_t buf_len; | ||
550 | |||
551 | buf_len = NETLBL_LEN_U32; | ||
552 | rcu_read_lock(); | ||
553 | list_for_each_entry_rcu(iter, &cipso_v4_doi_list, list) | ||
554 | if (iter->valid) { | ||
555 | doi_cnt += 1; | ||
556 | buf_len += 2 * NETLBL_LEN_U32; | ||
557 | } | ||
558 | |||
559 | skb = netlbl_netlink_alloc_skb(headroom, buf_len, GFP_ATOMIC); | ||
560 | if (skb == NULL) | ||
561 | goto doi_dump_all_failure; | ||
562 | |||
563 | if (nla_put_u32(skb, NLA_U32, doi_cnt) != 0) | ||
564 | goto doi_dump_all_failure; | ||
565 | buf_len -= NETLBL_LEN_U32; | ||
566 | list_for_each_entry_rcu(iter, &cipso_v4_doi_list, list) | ||
567 | if (iter->valid) { | ||
568 | if (buf_len < 2 * NETLBL_LEN_U32) | ||
569 | goto doi_dump_all_failure; | ||
570 | if (nla_put_u32(skb, NLA_U32, iter->doi) != 0) | ||
571 | goto doi_dump_all_failure; | ||
572 | if (nla_put_u32(skb, NLA_U32, iter->type) != 0) | ||
573 | goto doi_dump_all_failure; | ||
574 | buf_len -= 2 * NETLBL_LEN_U32; | ||
575 | } | ||
576 | rcu_read_unlock(); | ||
577 | |||
578 | return skb; | ||
579 | |||
580 | doi_dump_all_failure: | ||
581 | rcu_read_unlock(); | ||
582 | kfree(skb); | ||
583 | return NULL; | ||
584 | } | ||
585 | |||
586 | /** | ||
587 | * cipso_v4_doi_dump - Dump a CIPSO DOI definition into a sk_buff | ||
588 | * @doi: the DOI value | ||
589 | * @headroom: the amount of headroom to allocate for the sk_buff | ||
590 | * | ||
591 | * Description: | ||
592 | * Lookup the DOI definition matching @doi and dump it's contents into a | ||
593 | * sk_buff. The returned sk_buff has room at the front of the sk_buff for | ||
594 | * @headroom bytes. See net/netlabel/netlabel_cipso_v4.h for the LIST message | ||
595 | * format. This function may fail if another process is changing the DOI list | ||
596 | * at the same time. Returns a pointer to a sk_buff on success, NULL on error. | ||
597 | * | ||
598 | */ | ||
599 | struct sk_buff *cipso_v4_doi_dump(u32 doi, size_t headroom) | ||
600 | { | ||
601 | struct sk_buff *skb = NULL; | ||
602 | struct cipso_v4_doi *iter; | ||
603 | u32 tag_cnt = 0; | ||
604 | u32 lvl_cnt = 0; | ||
605 | u32 cat_cnt = 0; | ||
606 | ssize_t buf_len; | ||
607 | ssize_t tmp; | ||
608 | |||
609 | rcu_read_lock(); | ||
610 | iter = cipso_v4_doi_getdef(doi); | ||
611 | if (iter == NULL) | ||
612 | goto doi_dump_failure; | ||
613 | buf_len = NETLBL_LEN_U32; | ||
614 | switch (iter->type) { | ||
615 | case CIPSO_V4_MAP_PASS: | ||
616 | buf_len += NETLBL_LEN_U32; | ||
617 | while(tag_cnt < CIPSO_V4_TAG_MAXCNT && | ||
618 | iter->tags[tag_cnt] != CIPSO_V4_TAG_INVALID) { | ||
619 | tag_cnt += 1; | ||
620 | buf_len += NETLBL_LEN_U8; | ||
621 | } | ||
622 | break; | ||
623 | case CIPSO_V4_MAP_STD: | ||
624 | buf_len += 3 * NETLBL_LEN_U32; | ||
625 | while (tag_cnt < CIPSO_V4_TAG_MAXCNT && | ||
626 | iter->tags[tag_cnt] != CIPSO_V4_TAG_INVALID) { | ||
627 | tag_cnt += 1; | ||
628 | buf_len += NETLBL_LEN_U8; | ||
629 | } | ||
630 | for (tmp = 0; tmp < iter->map.std->lvl.local_size; tmp++) | ||
631 | if (iter->map.std->lvl.local[tmp] != | ||
632 | CIPSO_V4_INV_LVL) { | ||
633 | lvl_cnt += 1; | ||
634 | buf_len += NETLBL_LEN_U32 + NETLBL_LEN_U8; | ||
635 | } | ||
636 | for (tmp = 0; tmp < iter->map.std->cat.local_size; tmp++) | ||
637 | if (iter->map.std->cat.local[tmp] != | ||
638 | CIPSO_V4_INV_CAT) { | ||
639 | cat_cnt += 1; | ||
640 | buf_len += NETLBL_LEN_U32 + NETLBL_LEN_U16; | ||
641 | } | ||
642 | break; | ||
643 | } | ||
644 | |||
645 | skb = netlbl_netlink_alloc_skb(headroom, buf_len, GFP_ATOMIC); | ||
646 | if (skb == NULL) | ||
647 | goto doi_dump_failure; | ||
648 | |||
649 | if (nla_put_u32(skb, NLA_U32, iter->type) != 0) | ||
650 | goto doi_dump_failure; | ||
651 | buf_len -= NETLBL_LEN_U32; | ||
652 | if (iter != cipso_v4_doi_getdef(doi)) | ||
653 | goto doi_dump_failure; | ||
654 | switch (iter->type) { | ||
655 | case CIPSO_V4_MAP_PASS: | ||
656 | if (nla_put_u32(skb, NLA_U32, tag_cnt) != 0) | ||
657 | goto doi_dump_failure; | ||
658 | buf_len -= NETLBL_LEN_U32; | ||
659 | for (tmp = 0; | ||
660 | tmp < CIPSO_V4_TAG_MAXCNT && | ||
661 | iter->tags[tmp] != CIPSO_V4_TAG_INVALID; | ||
662 | tmp++) { | ||
663 | if (buf_len < NETLBL_LEN_U8) | ||
664 | goto doi_dump_failure; | ||
665 | if (nla_put_u8(skb, NLA_U8, iter->tags[tmp]) != 0) | ||
666 | goto doi_dump_failure; | ||
667 | buf_len -= NETLBL_LEN_U8; | ||
668 | } | ||
669 | break; | ||
670 | case CIPSO_V4_MAP_STD: | ||
671 | if (nla_put_u32(skb, NLA_U32, tag_cnt) != 0) | ||
672 | goto doi_dump_failure; | ||
673 | if (nla_put_u32(skb, NLA_U32, lvl_cnt) != 0) | ||
674 | goto doi_dump_failure; | ||
675 | if (nla_put_u32(skb, NLA_U32, cat_cnt) != 0) | ||
676 | goto doi_dump_failure; | ||
677 | buf_len -= 3 * NETLBL_LEN_U32; | ||
678 | for (tmp = 0; | ||
679 | tmp < CIPSO_V4_TAG_MAXCNT && | ||
680 | iter->tags[tmp] != CIPSO_V4_TAG_INVALID; | ||
681 | tmp++) { | ||
682 | if (buf_len < NETLBL_LEN_U8) | ||
683 | goto doi_dump_failure; | ||
684 | if (nla_put_u8(skb, NLA_U8, iter->tags[tmp]) != 0) | ||
685 | goto doi_dump_failure; | ||
686 | buf_len -= NETLBL_LEN_U8; | ||
687 | } | ||
688 | for (tmp = 0; tmp < iter->map.std->lvl.local_size; tmp++) | ||
689 | if (iter->map.std->lvl.local[tmp] != | ||
690 | CIPSO_V4_INV_LVL) { | ||
691 | if (buf_len < NETLBL_LEN_U32 + NETLBL_LEN_U8) | ||
692 | goto doi_dump_failure; | ||
693 | if (nla_put_u32(skb, NLA_U32, tmp) != 0) | ||
694 | goto doi_dump_failure; | ||
695 | if (nla_put_u8(skb, | ||
696 | NLA_U8, | ||
697 | iter->map.std->lvl.local[tmp]) != 0) | ||
698 | goto doi_dump_failure; | ||
699 | buf_len -= NETLBL_LEN_U32 + NETLBL_LEN_U8; | ||
700 | } | ||
701 | for (tmp = 0; tmp < iter->map.std->cat.local_size; tmp++) | ||
702 | if (iter->map.std->cat.local[tmp] != | ||
703 | CIPSO_V4_INV_CAT) { | ||
704 | if (buf_len < NETLBL_LEN_U32 + NETLBL_LEN_U16) | ||
705 | goto doi_dump_failure; | ||
706 | if (nla_put_u32(skb, NLA_U32, tmp) != 0) | ||
707 | goto doi_dump_failure; | ||
708 | if (nla_put_u16(skb, | ||
709 | NLA_U16, | ||
710 | iter->map.std->cat.local[tmp]) != 0) | ||
711 | goto doi_dump_failure; | ||
712 | buf_len -= NETLBL_LEN_U32 + NETLBL_LEN_U16; | ||
713 | } | ||
714 | break; | ||
715 | } | ||
716 | rcu_read_unlock(); | ||
717 | |||
718 | return skb; | ||
719 | |||
720 | doi_dump_failure: | ||
721 | rcu_read_unlock(); | ||
722 | kfree(skb); | ||
723 | return NULL; | ||
724 | } | ||
725 | |||
726 | /** | ||
727 | * cipso_v4_doi_domhsh_add - Adds a domain entry to a DOI definition | ||
728 | * @doi_def: the DOI definition | ||
729 | * @domain: the domain to add | ||
730 | * | ||
731 | * Description: | ||
732 | * Adds the @domain to the the DOI specified by @doi_def, this function | ||
733 | * should only be called by external functions (i.e. NetLabel). This function | ||
734 | * does allocate memory. Returns zero on success, negative values on failure. | ||
735 | * | ||
736 | */ | ||
737 | int cipso_v4_doi_domhsh_add(struct cipso_v4_doi *doi_def, const char *domain) | ||
738 | { | ||
739 | struct cipso_v4_domhsh_entry *iter; | ||
740 | struct cipso_v4_domhsh_entry *new_dom; | ||
741 | |||
742 | new_dom = kzalloc(sizeof(*new_dom), GFP_KERNEL); | ||
743 | if (new_dom == NULL) | ||
744 | return -ENOMEM; | ||
745 | if (domain) { | ||
746 | new_dom->domain = kstrdup(domain, GFP_KERNEL); | ||
747 | if (new_dom->domain == NULL) { | ||
748 | kfree(new_dom); | ||
749 | return -ENOMEM; | ||
750 | } | ||
751 | } | ||
752 | new_dom->valid = 1; | ||
753 | INIT_RCU_HEAD(&new_dom->rcu); | ||
754 | |||
755 | rcu_read_lock(); | ||
756 | spin_lock(&cipso_v4_doi_list_lock); | ||
757 | list_for_each_entry_rcu(iter, &doi_def->dom_list, list) | ||
758 | if (iter->valid && | ||
759 | ((domain != NULL && iter->domain != NULL && | ||
760 | strcmp(iter->domain, domain) == 0) || | ||
761 | (domain == NULL && iter->domain == NULL))) { | ||
762 | spin_unlock(&cipso_v4_doi_list_lock); | ||
763 | rcu_read_unlock(); | ||
764 | kfree(new_dom->domain); | ||
765 | kfree(new_dom); | ||
766 | return -EEXIST; | ||
767 | } | ||
768 | list_add_tail_rcu(&new_dom->list, &doi_def->dom_list); | ||
769 | spin_unlock(&cipso_v4_doi_list_lock); | ||
770 | rcu_read_unlock(); | ||
771 | |||
772 | return 0; | ||
773 | } | ||
774 | |||
775 | /** | ||
776 | * cipso_v4_doi_domhsh_remove - Removes a domain entry from a DOI definition | ||
777 | * @doi_def: the DOI definition | ||
778 | * @domain: the domain to remove | ||
779 | * | ||
780 | * Description: | ||
781 | * Removes the @domain from the DOI specified by @doi_def, this function | ||
782 | * should only be called by external functions (i.e. NetLabel). Returns zero | ||
783 | * on success and negative values on error. | ||
784 | * | ||
785 | */ | ||
786 | int cipso_v4_doi_domhsh_remove(struct cipso_v4_doi *doi_def, | ||
787 | const char *domain) | ||
788 | { | ||
789 | struct cipso_v4_domhsh_entry *iter; | ||
790 | |||
791 | rcu_read_lock(); | ||
792 | spin_lock(&cipso_v4_doi_list_lock); | ||
793 | list_for_each_entry_rcu(iter, &doi_def->dom_list, list) | ||
794 | if (iter->valid && | ||
795 | ((domain != NULL && iter->domain != NULL && | ||
796 | strcmp(iter->domain, domain) == 0) || | ||
797 | (domain == NULL && iter->domain == NULL))) { | ||
798 | iter->valid = 0; | ||
799 | list_del_rcu(&iter->list); | ||
800 | spin_unlock(&cipso_v4_doi_list_lock); | ||
801 | rcu_read_unlock(); | ||
802 | call_rcu(&iter->rcu, cipso_v4_doi_domhsh_free); | ||
803 | |||
804 | return 0; | ||
805 | } | ||
806 | spin_unlock(&cipso_v4_doi_list_lock); | ||
807 | rcu_read_unlock(); | ||
808 | |||
809 | return -ENOENT; | ||
810 | } | ||
811 | |||
812 | /* | ||
813 | * Label Mapping Functions | ||
814 | */ | ||
815 | |||
816 | /** | ||
817 | * cipso_v4_map_lvl_valid - Checks to see if the given level is understood | ||
818 | * @doi_def: the DOI definition | ||
819 | * @level: the level to check | ||
820 | * | ||
821 | * Description: | ||
822 | * Checks the given level against the given DOI definition and returns a | ||
823 | * negative value if the level does not have a valid mapping and a zero value | ||
824 | * if the level is defined by the DOI. | ||
825 | * | ||
826 | */ | ||
827 | static int cipso_v4_map_lvl_valid(const struct cipso_v4_doi *doi_def, u8 level) | ||
828 | { | ||
829 | switch (doi_def->type) { | ||
830 | case CIPSO_V4_MAP_PASS: | ||
831 | return 0; | ||
832 | case CIPSO_V4_MAP_STD: | ||
833 | if (doi_def->map.std->lvl.cipso[level] < CIPSO_V4_INV_LVL) | ||
834 | return 0; | ||
835 | break; | ||
836 | } | ||
837 | |||
838 | return -EFAULT; | ||
839 | } | ||
840 | |||
841 | /** | ||
842 | * cipso_v4_map_lvl_hton - Perform a level mapping from the host to the network | ||
843 | * @doi_def: the DOI definition | ||
844 | * @host_lvl: the host MLS level | ||
845 | * @net_lvl: the network/CIPSO MLS level | ||
846 | * | ||
847 | * Description: | ||
848 | * Perform a label mapping to translate a local MLS level to the correct | ||
849 | * CIPSO level using the given DOI definition. Returns zero on success, | ||
850 | * negative values otherwise. | ||
851 | * | ||
852 | */ | ||
853 | static int cipso_v4_map_lvl_hton(const struct cipso_v4_doi *doi_def, | ||
854 | u32 host_lvl, | ||
855 | u32 *net_lvl) | ||
856 | { | ||
857 | switch (doi_def->type) { | ||
858 | case CIPSO_V4_MAP_PASS: | ||
859 | *net_lvl = host_lvl; | ||
860 | return 0; | ||
861 | case CIPSO_V4_MAP_STD: | ||
862 | if (host_lvl < doi_def->map.std->lvl.local_size) { | ||
863 | *net_lvl = doi_def->map.std->lvl.local[host_lvl]; | ||
864 | return 0; | ||
865 | } | ||
866 | break; | ||
867 | } | ||
868 | |||
869 | return -EINVAL; | ||
870 | } | ||
871 | |||
872 | /** | ||
873 | * cipso_v4_map_lvl_ntoh - Perform a level mapping from the network to the host | ||
874 | * @doi_def: the DOI definition | ||
875 | * @net_lvl: the network/CIPSO MLS level | ||
876 | * @host_lvl: the host MLS level | ||
877 | * | ||
878 | * Description: | ||
879 | * Perform a label mapping to translate a CIPSO level to the correct local MLS | ||
880 | * level using the given DOI definition. Returns zero on success, negative | ||
881 | * values otherwise. | ||
882 | * | ||
883 | */ | ||
884 | static int cipso_v4_map_lvl_ntoh(const struct cipso_v4_doi *doi_def, | ||
885 | u32 net_lvl, | ||
886 | u32 *host_lvl) | ||
887 | { | ||
888 | struct cipso_v4_std_map_tbl *map_tbl; | ||
889 | |||
890 | switch (doi_def->type) { | ||
891 | case CIPSO_V4_MAP_PASS: | ||
892 | *host_lvl = net_lvl; | ||
893 | return 0; | ||
894 | case CIPSO_V4_MAP_STD: | ||
895 | map_tbl = doi_def->map.std; | ||
896 | if (net_lvl < map_tbl->lvl.cipso_size && | ||
897 | map_tbl->lvl.cipso[net_lvl] < CIPSO_V4_INV_LVL) { | ||
898 | *host_lvl = doi_def->map.std->lvl.cipso[net_lvl]; | ||
899 | return 0; | ||
900 | } | ||
901 | break; | ||
902 | } | ||
903 | |||
904 | return -EINVAL; | ||
905 | } | ||
906 | |||
907 | /** | ||
908 | * cipso_v4_map_cat_rbm_valid - Checks to see if the category bitmap is valid | ||
909 | * @doi_def: the DOI definition | ||
910 | * @bitmap: category bitmap | ||
911 | * @bitmap_len: bitmap length in bytes | ||
912 | * | ||
913 | * Description: | ||
914 | * Checks the given category bitmap against the given DOI definition and | ||
915 | * returns a negative value if any of the categories in the bitmap do not have | ||
916 | * a valid mapping and a zero value if all of the categories are valid. | ||
917 | * | ||
918 | */ | ||
919 | static int cipso_v4_map_cat_rbm_valid(const struct cipso_v4_doi *doi_def, | ||
920 | const unsigned char *bitmap, | ||
921 | u32 bitmap_len) | ||
922 | { | ||
923 | int cat = -1; | ||
924 | u32 bitmap_len_bits = bitmap_len * 8; | ||
925 | u32 cipso_cat_size = doi_def->map.std->cat.cipso_size; | ||
926 | u32 *cipso_array = doi_def->map.std->cat.cipso; | ||
927 | |||
928 | switch (doi_def->type) { | ||
929 | case CIPSO_V4_MAP_PASS: | ||
930 | return 0; | ||
931 | case CIPSO_V4_MAP_STD: | ||
932 | for (;;) { | ||
933 | cat = cipso_v4_bitmap_walk(bitmap, | ||
934 | bitmap_len_bits, | ||
935 | cat + 1, | ||
936 | 1); | ||
937 | if (cat < 0) | ||
938 | break; | ||
939 | if (cat >= cipso_cat_size || | ||
940 | cipso_array[cat] >= CIPSO_V4_INV_CAT) | ||
941 | return -EFAULT; | ||
942 | } | ||
943 | |||
944 | if (cat == -1) | ||
945 | return 0; | ||
946 | break; | ||
947 | } | ||
948 | |||
949 | return -EFAULT; | ||
950 | } | ||
951 | |||
952 | /** | ||
953 | * cipso_v4_map_cat_rbm_hton - Perform a category mapping from host to network | ||
954 | * @doi_def: the DOI definition | ||
955 | * @host_cat: the category bitmap in host format | ||
956 | * @host_cat_len: the length of the host's category bitmap in bytes | ||
957 | * @net_cat: the zero'd out category bitmap in network/CIPSO format | ||
958 | * @net_cat_len: the length of the CIPSO bitmap in bytes | ||
959 | * | ||
960 | * Description: | ||
961 | * Perform a label mapping to translate a local MLS category bitmap to the | ||
962 | * correct CIPSO bitmap using the given DOI definition. Returns the minimum | ||
963 | * size in bytes of the network bitmap on success, negative values otherwise. | ||
964 | * | ||
965 | */ | ||
966 | static int cipso_v4_map_cat_rbm_hton(const struct cipso_v4_doi *doi_def, | ||
967 | const unsigned char *host_cat, | ||
968 | u32 host_cat_len, | ||
969 | unsigned char *net_cat, | ||
970 | u32 net_cat_len) | ||
971 | { | ||
972 | int host_spot = -1; | ||
973 | u32 net_spot; | ||
974 | u32 net_spot_max = 0; | ||
975 | u32 host_clen_bits = host_cat_len * 8; | ||
976 | u32 net_clen_bits = net_cat_len * 8; | ||
977 | u32 host_cat_size = doi_def->map.std->cat.local_size; | ||
978 | u32 *host_cat_array = doi_def->map.std->cat.local; | ||
979 | |||
980 | switch (doi_def->type) { | ||
981 | case CIPSO_V4_MAP_PASS: | ||
982 | net_spot_max = host_cat_len - 1; | ||
983 | while (net_spot_max > 0 && host_cat[net_spot_max] == 0) | ||
984 | net_spot_max--; | ||
985 | if (net_spot_max > net_cat_len) | ||
986 | return -EINVAL; | ||
987 | memcpy(net_cat, host_cat, net_spot_max); | ||
988 | return net_spot_max; | ||
989 | case CIPSO_V4_MAP_STD: | ||
990 | for (;;) { | ||
991 | host_spot = cipso_v4_bitmap_walk(host_cat, | ||
992 | host_clen_bits, | ||
993 | host_spot + 1, | ||
994 | 1); | ||
995 | if (host_spot < 0) | ||
996 | break; | ||
997 | if (host_spot >= host_cat_size) | ||
998 | return -EPERM; | ||
999 | |||
1000 | net_spot = host_cat_array[host_spot]; | ||
1001 | if (net_spot >= net_clen_bits) | ||
1002 | return -ENOSPC; | ||
1003 | cipso_v4_bitmap_setbit(net_cat, net_spot, 1); | ||
1004 | |||
1005 | if (net_spot > net_spot_max) | ||
1006 | net_spot_max = net_spot; | ||
1007 | } | ||
1008 | |||
1009 | if (host_spot == -2) | ||
1010 | return -EFAULT; | ||
1011 | |||
1012 | if (++net_spot_max % 8) | ||
1013 | return net_spot_max / 8 + 1; | ||
1014 | return net_spot_max / 8; | ||
1015 | } | ||
1016 | |||
1017 | return -EINVAL; | ||
1018 | } | ||
1019 | |||
1020 | /** | ||
1021 | * cipso_v4_map_cat_rbm_ntoh - Perform a category mapping from network to host | ||
1022 | * @doi_def: the DOI definition | ||
1023 | * @net_cat: the category bitmap in network/CIPSO format | ||
1024 | * @net_cat_len: the length of the CIPSO bitmap in bytes | ||
1025 | * @host_cat: the zero'd out category bitmap in host format | ||
1026 | * @host_cat_len: the length of the host's category bitmap in bytes | ||
1027 | * | ||
1028 | * Description: | ||
1029 | * Perform a label mapping to translate a CIPSO bitmap to the correct local | ||
1030 | * MLS category bitmap using the given DOI definition. Returns the minimum | ||
1031 | * size in bytes of the host bitmap on success, negative values otherwise. | ||
1032 | * | ||
1033 | */ | ||
1034 | static int cipso_v4_map_cat_rbm_ntoh(const struct cipso_v4_doi *doi_def, | ||
1035 | const unsigned char *net_cat, | ||
1036 | u32 net_cat_len, | ||
1037 | unsigned char *host_cat, | ||
1038 | u32 host_cat_len) | ||
1039 | { | ||
1040 | u32 host_spot; | ||
1041 | u32 host_spot_max = 0; | ||
1042 | int net_spot = -1; | ||
1043 | u32 net_clen_bits = net_cat_len * 8; | ||
1044 | u32 host_clen_bits = host_cat_len * 8; | ||
1045 | u32 net_cat_size = doi_def->map.std->cat.cipso_size; | ||
1046 | u32 *net_cat_array = doi_def->map.std->cat.cipso; | ||
1047 | |||
1048 | switch (doi_def->type) { | ||
1049 | case CIPSO_V4_MAP_PASS: | ||
1050 | if (net_cat_len > host_cat_len) | ||
1051 | return -EINVAL; | ||
1052 | memcpy(host_cat, net_cat, net_cat_len); | ||
1053 | return net_cat_len; | ||
1054 | case CIPSO_V4_MAP_STD: | ||
1055 | for (;;) { | ||
1056 | net_spot = cipso_v4_bitmap_walk(net_cat, | ||
1057 | net_clen_bits, | ||
1058 | net_spot + 1, | ||
1059 | 1); | ||
1060 | if (net_spot < 0) | ||
1061 | break; | ||
1062 | if (net_spot >= net_cat_size || | ||
1063 | net_cat_array[net_spot] >= CIPSO_V4_INV_CAT) | ||
1064 | return -EPERM; | ||
1065 | |||
1066 | host_spot = net_cat_array[net_spot]; | ||
1067 | if (host_spot >= host_clen_bits) | ||
1068 | return -ENOSPC; | ||
1069 | cipso_v4_bitmap_setbit(host_cat, host_spot, 1); | ||
1070 | |||
1071 | if (host_spot > host_spot_max) | ||
1072 | host_spot_max = host_spot; | ||
1073 | } | ||
1074 | |||
1075 | if (net_spot == -2) | ||
1076 | return -EFAULT; | ||
1077 | |||
1078 | if (++host_spot_max % 8) | ||
1079 | return host_spot_max / 8 + 1; | ||
1080 | return host_spot_max / 8; | ||
1081 | } | ||
1082 | |||
1083 | return -EINVAL; | ||
1084 | } | ||
1085 | |||
1086 | /* | ||
1087 | * Protocol Handling Functions | ||
1088 | */ | ||
1089 | |||
1090 | #define CIPSO_V4_HDR_LEN 6 | ||
1091 | |||
1092 | /** | ||
1093 | * cipso_v4_gentag_hdr - Generate a CIPSO option header | ||
1094 | * @doi_def: the DOI definition | ||
1095 | * @len: the total tag length in bytes | ||
1096 | * @buf: the CIPSO option buffer | ||
1097 | * | ||
1098 | * Description: | ||
1099 | * Write a CIPSO header into the beginning of @buffer. Return zero on success, | ||
1100 | * negative values on failure. | ||
1101 | * | ||
1102 | */ | ||
1103 | static int cipso_v4_gentag_hdr(const struct cipso_v4_doi *doi_def, | ||
1104 | u32 len, | ||
1105 | unsigned char *buf) | ||
1106 | { | ||
1107 | if (CIPSO_V4_HDR_LEN + len > 40) | ||
1108 | return -ENOSPC; | ||
1109 | |||
1110 | buf[0] = IPOPT_CIPSO; | ||
1111 | buf[1] = CIPSO_V4_HDR_LEN + len; | ||
1112 | *(u32 *)&buf[2] = htonl(doi_def->doi); | ||
1113 | |||
1114 | return 0; | ||
1115 | } | ||
1116 | |||
1117 | #define CIPSO_V4_TAG1_CAT_LEN 30 | ||
1118 | |||
1119 | /** | ||
1120 | * cipso_v4_gentag_rbm - Generate a CIPSO restricted bitmap tag (type #1) | ||
1121 | * @doi_def: the DOI definition | ||
1122 | * @secattr: the security attributes | ||
1123 | * @buffer: the option buffer | ||
1124 | * @buffer_len: length of buffer in bytes | ||
1125 | * | ||
1126 | * Description: | ||
1127 | * Generate a CIPSO option using the restricted bitmap tag, tag type #1. The | ||
1128 | * actual buffer length may be larger than the indicated size due to | ||
1129 | * translation between host and network category bitmaps. Returns zero on | ||
1130 | * success, negative values on failure. | ||
1131 | * | ||
1132 | */ | ||
1133 | static int cipso_v4_gentag_rbm(const struct cipso_v4_doi *doi_def, | ||
1134 | const struct netlbl_lsm_secattr *secattr, | ||
1135 | unsigned char **buffer, | ||
1136 | u32 *buffer_len) | ||
1137 | { | ||
1138 | int ret_val = -EPERM; | ||
1139 | unsigned char *buf = NULL; | ||
1140 | u32 buf_len; | ||
1141 | u32 level; | ||
1142 | |||
1143 | if (secattr->mls_cat) { | ||
1144 | buf = kzalloc(CIPSO_V4_HDR_LEN + 4 + CIPSO_V4_TAG1_CAT_LEN, | ||
1145 | GFP_ATOMIC); | ||
1146 | if (buf == NULL) | ||
1147 | return -ENOMEM; | ||
1148 | |||
1149 | ret_val = cipso_v4_map_cat_rbm_hton(doi_def, | ||
1150 | secattr->mls_cat, | ||
1151 | secattr->mls_cat_len, | ||
1152 | &buf[CIPSO_V4_HDR_LEN + 4], | ||
1153 | CIPSO_V4_TAG1_CAT_LEN); | ||
1154 | if (ret_val < 0) | ||
1155 | goto gentag_failure; | ||
1156 | |||
1157 | /* This will send packets using the "optimized" format when | ||
1158 | * possibile as specified in section 3.4.2.6 of the | ||
1159 | * CIPSO draft. */ | ||
1160 | if (cipso_v4_rbm_optfmt && (ret_val > 0 && ret_val < 10)) | ||
1161 | ret_val = 10; | ||
1162 | |||
1163 | buf_len = 4 + ret_val; | ||
1164 | } else { | ||
1165 | buf = kzalloc(CIPSO_V4_HDR_LEN + 4, GFP_ATOMIC); | ||
1166 | if (buf == NULL) | ||
1167 | return -ENOMEM; | ||
1168 | buf_len = 4; | ||
1169 | } | ||
1170 | |||
1171 | ret_val = cipso_v4_map_lvl_hton(doi_def, secattr->mls_lvl, &level); | ||
1172 | if (ret_val != 0) | ||
1173 | goto gentag_failure; | ||
1174 | |||
1175 | ret_val = cipso_v4_gentag_hdr(doi_def, buf_len, buf); | ||
1176 | if (ret_val != 0) | ||
1177 | goto gentag_failure; | ||
1178 | |||
1179 | buf[CIPSO_V4_HDR_LEN] = 0x01; | ||
1180 | buf[CIPSO_V4_HDR_LEN + 1] = buf_len; | ||
1181 | buf[CIPSO_V4_HDR_LEN + 3] = level; | ||
1182 | |||
1183 | *buffer = buf; | ||
1184 | *buffer_len = CIPSO_V4_HDR_LEN + buf_len; | ||
1185 | |||
1186 | return 0; | ||
1187 | |||
1188 | gentag_failure: | ||
1189 | kfree(buf); | ||
1190 | return ret_val; | ||
1191 | } | ||
1192 | |||
1193 | /** | ||
1194 | * cipso_v4_parsetag_rbm - Parse a CIPSO restricted bitmap tag | ||
1195 | * @doi_def: the DOI definition | ||
1196 | * @tag: the CIPSO tag | ||
1197 | * @secattr: the security attributes | ||
1198 | * | ||
1199 | * Description: | ||
1200 | * Parse a CIPSO restricted bitmap tag (tag type #1) and return the security | ||
1201 | * attributes in @secattr. Return zero on success, negatives values on | ||
1202 | * failure. | ||
1203 | * | ||
1204 | */ | ||
1205 | static int cipso_v4_parsetag_rbm(const struct cipso_v4_doi *doi_def, | ||
1206 | const unsigned char *tag, | ||
1207 | struct netlbl_lsm_secattr *secattr) | ||
1208 | { | ||
1209 | int ret_val; | ||
1210 | u8 tag_len = tag[1]; | ||
1211 | u32 level; | ||
1212 | |||
1213 | ret_val = cipso_v4_map_lvl_ntoh(doi_def, tag[3], &level); | ||
1214 | if (ret_val != 0) | ||
1215 | return ret_val; | ||
1216 | secattr->mls_lvl = level; | ||
1217 | secattr->mls_lvl_vld = 1; | ||
1218 | |||
1219 | if (tag_len > 4) { | ||
1220 | switch (doi_def->type) { | ||
1221 | case CIPSO_V4_MAP_PASS: | ||
1222 | secattr->mls_cat_len = tag_len - 4; | ||
1223 | break; | ||
1224 | case CIPSO_V4_MAP_STD: | ||
1225 | secattr->mls_cat_len = | ||
1226 | doi_def->map.std->cat.local_size; | ||
1227 | break; | ||
1228 | } | ||
1229 | secattr->mls_cat = kzalloc(secattr->mls_cat_len, GFP_ATOMIC); | ||
1230 | if (secattr->mls_cat == NULL) | ||
1231 | return -ENOMEM; | ||
1232 | |||
1233 | ret_val = cipso_v4_map_cat_rbm_ntoh(doi_def, | ||
1234 | &tag[4], | ||
1235 | tag_len - 4, | ||
1236 | secattr->mls_cat, | ||
1237 | secattr->mls_cat_len); | ||
1238 | if (ret_val < 0) { | ||
1239 | kfree(secattr->mls_cat); | ||
1240 | return ret_val; | ||
1241 | } | ||
1242 | secattr->mls_cat_len = ret_val; | ||
1243 | } | ||
1244 | |||
1245 | return 0; | ||
1246 | } | ||
1247 | |||
1248 | /** | ||
1249 | * cipso_v4_validate - Validate a CIPSO option | ||
1250 | * @option: the start of the option, on error it is set to point to the error | ||
1251 | * | ||
1252 | * Description: | ||
1253 | * This routine is called to validate a CIPSO option, it checks all of the | ||
1254 | * fields to ensure that they are at least valid, see the draft snippet below | ||
1255 | * for details. If the option is valid then a zero value is returned and | ||
1256 | * the value of @option is unchanged. If the option is invalid then a | ||
1257 | * non-zero value is returned and @option is adjusted to point to the | ||
1258 | * offending portion of the option. From the IETF draft ... | ||
1259 | * | ||
1260 | * "If any field within the CIPSO options, such as the DOI identifier, is not | ||
1261 | * recognized the IP datagram is discarded and an ICMP 'parameter problem' | ||
1262 | * (type 12) is generated and returned. The ICMP code field is set to 'bad | ||
1263 | * parameter' (code 0) and the pointer is set to the start of the CIPSO field | ||
1264 | * that is unrecognized." | ||
1265 | * | ||
1266 | */ | ||
1267 | int cipso_v4_validate(unsigned char **option) | ||
1268 | { | ||
1269 | unsigned char *opt = *option; | ||
1270 | unsigned char *tag; | ||
1271 | unsigned char opt_iter; | ||
1272 | unsigned char err_offset = 0; | ||
1273 | u8 opt_len; | ||
1274 | u8 tag_len; | ||
1275 | struct cipso_v4_doi *doi_def = NULL; | ||
1276 | u32 tag_iter; | ||
1277 | |||
1278 | /* caller already checks for length values that are too large */ | ||
1279 | opt_len = opt[1]; | ||
1280 | if (opt_len < 8) { | ||
1281 | err_offset = 1; | ||
1282 | goto validate_return; | ||
1283 | } | ||
1284 | |||
1285 | rcu_read_lock(); | ||
1286 | doi_def = cipso_v4_doi_getdef(ntohl(*((u32 *)&opt[2]))); | ||
1287 | if (doi_def == NULL) { | ||
1288 | err_offset = 2; | ||
1289 | goto validate_return_locked; | ||
1290 | } | ||
1291 | |||
1292 | opt_iter = 6; | ||
1293 | tag = opt + opt_iter; | ||
1294 | while (opt_iter < opt_len) { | ||
1295 | for (tag_iter = 0; doi_def->tags[tag_iter] != tag[0];) | ||
1296 | if (doi_def->tags[tag_iter] == CIPSO_V4_TAG_INVALID || | ||
1297 | ++tag_iter == CIPSO_V4_TAG_MAXCNT) { | ||
1298 | err_offset = opt_iter; | ||
1299 | goto validate_return_locked; | ||
1300 | } | ||
1301 | |||
1302 | tag_len = tag[1]; | ||
1303 | if (tag_len > (opt_len - opt_iter)) { | ||
1304 | err_offset = opt_iter + 1; | ||
1305 | goto validate_return_locked; | ||
1306 | } | ||
1307 | |||
1308 | switch (tag[0]) { | ||
1309 | case CIPSO_V4_TAG_RBITMAP: | ||
1310 | if (tag_len < 4) { | ||
1311 | err_offset = opt_iter + 1; | ||
1312 | goto validate_return_locked; | ||
1313 | } | ||
1314 | |||
1315 | /* We are already going to do all the verification | ||
1316 | * necessary at the socket layer so from our point of | ||
1317 | * view it is safe to turn these checks off (and less | ||
1318 | * work), however, the CIPSO draft says we should do | ||
1319 | * all the CIPSO validations here but it doesn't | ||
1320 | * really specify _exactly_ what we need to validate | ||
1321 | * ... so, just make it a sysctl tunable. */ | ||
1322 | if (cipso_v4_rbm_strictvalid) { | ||
1323 | if (cipso_v4_map_lvl_valid(doi_def, | ||
1324 | tag[3]) < 0) { | ||
1325 | err_offset = opt_iter + 3; | ||
1326 | goto validate_return_locked; | ||
1327 | } | ||
1328 | if (tag_len > 4 && | ||
1329 | cipso_v4_map_cat_rbm_valid(doi_def, | ||
1330 | &tag[4], | ||
1331 | tag_len - 4) < 0) { | ||
1332 | err_offset = opt_iter + 4; | ||
1333 | goto validate_return_locked; | ||
1334 | } | ||
1335 | } | ||
1336 | break; | ||
1337 | default: | ||
1338 | err_offset = opt_iter; | ||
1339 | goto validate_return_locked; | ||
1340 | } | ||
1341 | |||
1342 | tag += tag_len; | ||
1343 | opt_iter += tag_len; | ||
1344 | } | ||
1345 | |||
1346 | validate_return_locked: | ||
1347 | rcu_read_unlock(); | ||
1348 | validate_return: | ||
1349 | *option = opt + err_offset; | ||
1350 | return err_offset; | ||
1351 | } | ||
1352 | |||
1353 | /** | ||
1354 | * cipso_v4_error - Send the correct reponse for a bad packet | ||
1355 | * @skb: the packet | ||
1356 | * @error: the error code | ||
1357 | * @gateway: CIPSO gateway flag | ||
1358 | * | ||
1359 | * Description: | ||
1360 | * Based on the error code given in @error, send an ICMP error message back to | ||
1361 | * the originating host. From the IETF draft ... | ||
1362 | * | ||
1363 | * "If the contents of the CIPSO [option] are valid but the security label is | ||
1364 | * outside of the configured host or port label range, the datagram is | ||
1365 | * discarded and an ICMP 'destination unreachable' (type 3) is generated and | ||
1366 | * returned. The code field of the ICMP is set to 'communication with | ||
1367 | * destination network administratively prohibited' (code 9) or to | ||
1368 | * 'communication with destination host administratively prohibited' | ||
1369 | * (code 10). The value of the code is dependent on whether the originator | ||
1370 | * of the ICMP message is acting as a CIPSO host or a CIPSO gateway. The | ||
1371 | * recipient of the ICMP message MUST be able to handle either value. The | ||
1372 | * same procedure is performed if a CIPSO [option] can not be added to an | ||
1373 | * IP packet because it is too large to fit in the IP options area." | ||
1374 | * | ||
1375 | * "If the error is triggered by receipt of an ICMP message, the message is | ||
1376 | * discarded and no response is permitted (consistent with general ICMP | ||
1377 | * processing rules)." | ||
1378 | * | ||
1379 | */ | ||
1380 | void cipso_v4_error(struct sk_buff *skb, int error, u32 gateway) | ||
1381 | { | ||
1382 | if (skb->nh.iph->protocol == IPPROTO_ICMP || error != -EACCES) | ||
1383 | return; | ||
1384 | |||
1385 | if (gateway) | ||
1386 | icmp_send(skb, ICMP_DEST_UNREACH, ICMP_NET_ANO, 0); | ||
1387 | else | ||
1388 | icmp_send(skb, ICMP_DEST_UNREACH, ICMP_HOST_ANO, 0); | ||
1389 | } | ||
1390 | |||
1391 | /** | ||
1392 | * cipso_v4_socket_setattr - Add a CIPSO option to a socket | ||
1393 | * @sock: the socket | ||
1394 | * @doi_def: the CIPSO DOI to use | ||
1395 | * @secattr: the specific security attributes of the socket | ||
1396 | * | ||
1397 | * Description: | ||
1398 | * Set the CIPSO option on the given socket using the DOI definition and | ||
1399 | * security attributes passed to the function. This function requires | ||
1400 | * exclusive access to @sock->sk, which means it either needs to be in the | ||
1401 | * process of being created or locked via lock_sock(sock->sk). Returns zero on | ||
1402 | * success and negative values on failure. | ||
1403 | * | ||
1404 | */ | ||
1405 | int cipso_v4_socket_setattr(const struct socket *sock, | ||
1406 | const struct cipso_v4_doi *doi_def, | ||
1407 | const struct netlbl_lsm_secattr *secattr) | ||
1408 | { | ||
1409 | int ret_val = -EPERM; | ||
1410 | u32 iter; | ||
1411 | unsigned char *buf = NULL; | ||
1412 | u32 buf_len = 0; | ||
1413 | u32 opt_len; | ||
1414 | struct ip_options *opt = NULL; | ||
1415 | struct sock *sk; | ||
1416 | struct inet_sock *sk_inet; | ||
1417 | struct inet_connection_sock *sk_conn; | ||
1418 | |||
1419 | /* In the case of sock_create_lite(), the sock->sk field is not | ||
1420 | * defined yet but it is not a problem as the only users of these | ||
1421 | * "lite" PF_INET sockets are functions which do an accept() call | ||
1422 | * afterwards so we will label the socket as part of the accept(). */ | ||
1423 | sk = sock->sk; | ||
1424 | if (sk == NULL) | ||
1425 | return 0; | ||
1426 | |||
1427 | /* XXX - This code assumes only one tag per CIPSO option which isn't | ||
1428 | * really a good assumption to make but since we only support the MAC | ||
1429 | * tags right now it is a safe assumption. */ | ||
1430 | iter = 0; | ||
1431 | do { | ||
1432 | switch (doi_def->tags[iter]) { | ||
1433 | case CIPSO_V4_TAG_RBITMAP: | ||
1434 | ret_val = cipso_v4_gentag_rbm(doi_def, | ||
1435 | secattr, | ||
1436 | &buf, | ||
1437 | &buf_len); | ||
1438 | break; | ||
1439 | default: | ||
1440 | ret_val = -EPERM; | ||
1441 | goto socket_setattr_failure; | ||
1442 | } | ||
1443 | |||
1444 | iter++; | ||
1445 | } while (ret_val != 0 && | ||
1446 | iter < CIPSO_V4_TAG_MAXCNT && | ||
1447 | doi_def->tags[iter] != CIPSO_V4_TAG_INVALID); | ||
1448 | if (ret_val != 0) | ||
1449 | goto socket_setattr_failure; | ||
1450 | |||
1451 | /* We can't use ip_options_get() directly because it makes a call to | ||
1452 | * ip_options_get_alloc() which allocates memory with GFP_KERNEL and | ||
1453 | * we can't block here. */ | ||
1454 | opt_len = (buf_len + 3) & ~3; | ||
1455 | opt = kzalloc(sizeof(*opt) + opt_len, GFP_ATOMIC); | ||
1456 | if (opt == NULL) { | ||
1457 | ret_val = -ENOMEM; | ||
1458 | goto socket_setattr_failure; | ||
1459 | } | ||
1460 | memcpy(opt->__data, buf, buf_len); | ||
1461 | opt->optlen = opt_len; | ||
1462 | opt->is_data = 1; | ||
1463 | kfree(buf); | ||
1464 | buf = NULL; | ||
1465 | ret_val = ip_options_compile(opt, NULL); | ||
1466 | if (ret_val != 0) | ||
1467 | goto socket_setattr_failure; | ||
1468 | |||
1469 | sk_inet = inet_sk(sk); | ||
1470 | if (sk_inet->is_icsk) { | ||
1471 | sk_conn = inet_csk(sk); | ||
1472 | if (sk_inet->opt) | ||
1473 | sk_conn->icsk_ext_hdr_len -= sk_inet->opt->optlen; | ||
1474 | sk_conn->icsk_ext_hdr_len += opt->optlen; | ||
1475 | sk_conn->icsk_sync_mss(sk, sk_conn->icsk_pmtu_cookie); | ||
1476 | } | ||
1477 | opt = xchg(&sk_inet->opt, opt); | ||
1478 | kfree(opt); | ||
1479 | |||
1480 | return 0; | ||
1481 | |||
1482 | socket_setattr_failure: | ||
1483 | kfree(buf); | ||
1484 | kfree(opt); | ||
1485 | return ret_val; | ||
1486 | } | ||
1487 | |||
1488 | /** | ||
1489 | * cipso_v4_socket_getattr - Get the security attributes from a socket | ||
1490 | * @sock: the socket | ||
1491 | * @secattr: the security attributes | ||
1492 | * | ||
1493 | * Description: | ||
1494 | * Query @sock to see if there is a CIPSO option attached to the socket and if | ||
1495 | * there is return the CIPSO security attributes in @secattr. Returns zero on | ||
1496 | * success and negative values on failure. | ||
1497 | * | ||
1498 | */ | ||
1499 | int cipso_v4_socket_getattr(const struct socket *sock, | ||
1500 | struct netlbl_lsm_secattr *secattr) | ||
1501 | { | ||
1502 | int ret_val = -ENOMSG; | ||
1503 | struct sock *sk; | ||
1504 | struct inet_sock *sk_inet; | ||
1505 | unsigned char *cipso_ptr; | ||
1506 | u32 doi; | ||
1507 | struct cipso_v4_doi *doi_def; | ||
1508 | |||
1509 | sk = sock->sk; | ||
1510 | lock_sock(sk); | ||
1511 | sk_inet = inet_sk(sk); | ||
1512 | if (sk_inet->opt == NULL || sk_inet->opt->cipso == 0) | ||
1513 | goto socket_getattr_return; | ||
1514 | cipso_ptr = sk_inet->opt->__data + sk_inet->opt->cipso - | ||
1515 | sizeof(struct iphdr); | ||
1516 | ret_val = cipso_v4_cache_check(cipso_ptr, cipso_ptr[1], secattr); | ||
1517 | if (ret_val == 0) | ||
1518 | goto socket_getattr_return; | ||
1519 | |||
1520 | doi = ntohl(*(u32 *)&cipso_ptr[2]); | ||
1521 | rcu_read_lock(); | ||
1522 | doi_def = cipso_v4_doi_getdef(doi); | ||
1523 | if (doi_def == NULL) { | ||
1524 | rcu_read_unlock(); | ||
1525 | goto socket_getattr_return; | ||
1526 | } | ||
1527 | switch (cipso_ptr[6]) { | ||
1528 | case CIPSO_V4_TAG_RBITMAP: | ||
1529 | ret_val = cipso_v4_parsetag_rbm(doi_def, | ||
1530 | &cipso_ptr[6], | ||
1531 | secattr); | ||
1532 | break; | ||
1533 | } | ||
1534 | rcu_read_unlock(); | ||
1535 | |||
1536 | socket_getattr_return: | ||
1537 | release_sock(sk); | ||
1538 | return ret_val; | ||
1539 | } | ||
1540 | |||
1541 | /** | ||
1542 | * cipso_v4_skbuff_getattr - Get the security attributes from the CIPSO option | ||
1543 | * @skb: the packet | ||
1544 | * @secattr: the security attributes | ||
1545 | * | ||
1546 | * Description: | ||
1547 | * Parse the given packet's CIPSO option and return the security attributes. | ||
1548 | * Returns zero on success and negative values on failure. | ||
1549 | * | ||
1550 | */ | ||
1551 | int cipso_v4_skbuff_getattr(const struct sk_buff *skb, | ||
1552 | struct netlbl_lsm_secattr *secattr) | ||
1553 | { | ||
1554 | int ret_val = -ENOMSG; | ||
1555 | unsigned char *cipso_ptr; | ||
1556 | u32 doi; | ||
1557 | struct cipso_v4_doi *doi_def; | ||
1558 | |||
1559 | if (!CIPSO_V4_OPTEXIST(skb)) | ||
1560 | return -ENOMSG; | ||
1561 | cipso_ptr = CIPSO_V4_OPTPTR(skb); | ||
1562 | if (cipso_v4_cache_check(cipso_ptr, cipso_ptr[1], secattr) == 0) | ||
1563 | return 0; | ||
1564 | |||
1565 | doi = ntohl(*(u32 *)&cipso_ptr[2]); | ||
1566 | rcu_read_lock(); | ||
1567 | doi_def = cipso_v4_doi_getdef(doi); | ||
1568 | if (doi_def == NULL) | ||
1569 | goto skbuff_getattr_return; | ||
1570 | switch (cipso_ptr[6]) { | ||
1571 | case CIPSO_V4_TAG_RBITMAP: | ||
1572 | ret_val = cipso_v4_parsetag_rbm(doi_def, | ||
1573 | &cipso_ptr[6], | ||
1574 | secattr); | ||
1575 | break; | ||
1576 | } | ||
1577 | |||
1578 | skbuff_getattr_return: | ||
1579 | rcu_read_unlock(); | ||
1580 | return ret_val; | ||
1581 | } | ||
1582 | |||
1583 | /* | ||
1584 | * Setup Functions | ||
1585 | */ | ||
1586 | |||
1587 | /** | ||
1588 | * cipso_v4_init - Initialize the CIPSO module | ||
1589 | * | ||
1590 | * Description: | ||
1591 | * Initialize the CIPSO module and prepare it for use. Returns zero on success | ||
1592 | * and negative values on failure. | ||
1593 | * | ||
1594 | */ | ||
1595 | static int __init cipso_v4_init(void) | ||
1596 | { | ||
1597 | int ret_val; | ||
1598 | |||
1599 | ret_val = cipso_v4_cache_init(); | ||
1600 | if (ret_val != 0) | ||
1601 | panic("Failed to initialize the CIPSO/IPv4 cache (%d)\n", | ||
1602 | ret_val); | ||
1603 | |||
1604 | return 0; | ||
1605 | } | ||
1606 | |||
1607 | subsys_initcall(cipso_v4_init); | ||
diff --git a/net/ipv4/devinet.c b/net/ipv4/devinet.c index a6cc31d911eb..8e8d1f17d77a 100644 --- a/net/ipv4/devinet.c +++ b/net/ipv4/devinet.c | |||
@@ -43,6 +43,7 @@ | |||
43 | #include <linux/in.h> | 43 | #include <linux/in.h> |
44 | #include <linux/errno.h> | 44 | #include <linux/errno.h> |
45 | #include <linux/interrupt.h> | 45 | #include <linux/interrupt.h> |
46 | #include <linux/if_addr.h> | ||
46 | #include <linux/if_ether.h> | 47 | #include <linux/if_ether.h> |
47 | #include <linux/inet.h> | 48 | #include <linux/inet.h> |
48 | #include <linux/netdevice.h> | 49 | #include <linux/netdevice.h> |
@@ -62,6 +63,7 @@ | |||
62 | #include <net/ip.h> | 63 | #include <net/ip.h> |
63 | #include <net/route.h> | 64 | #include <net/route.h> |
64 | #include <net/ip_fib.h> | 65 | #include <net/ip_fib.h> |
66 | #include <net/netlink.h> | ||
65 | 67 | ||
66 | struct ipv4_devconf ipv4_devconf = { | 68 | struct ipv4_devconf ipv4_devconf = { |
67 | .accept_redirects = 1, | 69 | .accept_redirects = 1, |
@@ -78,7 +80,15 @@ static struct ipv4_devconf ipv4_devconf_dflt = { | |||
78 | .accept_source_route = 1, | 80 | .accept_source_route = 1, |
79 | }; | 81 | }; |
80 | 82 | ||
81 | static void rtmsg_ifa(int event, struct in_ifaddr *); | 83 | static struct nla_policy ifa_ipv4_policy[IFA_MAX+1] __read_mostly = { |
84 | [IFA_LOCAL] = { .type = NLA_U32 }, | ||
85 | [IFA_ADDRESS] = { .type = NLA_U32 }, | ||
86 | [IFA_BROADCAST] = { .type = NLA_U32 }, | ||
87 | [IFA_ANYCAST] = { .type = NLA_U32 }, | ||
88 | [IFA_LABEL] = { .type = NLA_STRING, .len = IFNAMSIZ - 1 }, | ||
89 | }; | ||
90 | |||
91 | static void rtmsg_ifa(int event, struct in_ifaddr *, struct nlmsghdr *, u32); | ||
82 | 92 | ||
83 | static BLOCKING_NOTIFIER_HEAD(inetaddr_chain); | 93 | static BLOCKING_NOTIFIER_HEAD(inetaddr_chain); |
84 | static void inet_del_ifa(struct in_device *in_dev, struct in_ifaddr **ifap, | 94 | static void inet_del_ifa(struct in_device *in_dev, struct in_ifaddr **ifap, |
@@ -229,8 +239,8 @@ int inet_addr_onlink(struct in_device *in_dev, u32 a, u32 b) | |||
229 | return 0; | 239 | return 0; |
230 | } | 240 | } |
231 | 241 | ||
232 | static void inet_del_ifa(struct in_device *in_dev, struct in_ifaddr **ifap, | 242 | static void __inet_del_ifa(struct in_device *in_dev, struct in_ifaddr **ifap, |
233 | int destroy) | 243 | int destroy, struct nlmsghdr *nlh, u32 pid) |
234 | { | 244 | { |
235 | struct in_ifaddr *promote = NULL; | 245 | struct in_ifaddr *promote = NULL; |
236 | struct in_ifaddr *ifa, *ifa1 = *ifap; | 246 | struct in_ifaddr *ifa, *ifa1 = *ifap; |
@@ -263,7 +273,7 @@ static void inet_del_ifa(struct in_device *in_dev, struct in_ifaddr **ifap, | |||
263 | if (!do_promote) { | 273 | if (!do_promote) { |
264 | *ifap1 = ifa->ifa_next; | 274 | *ifap1 = ifa->ifa_next; |
265 | 275 | ||
266 | rtmsg_ifa(RTM_DELADDR, ifa); | 276 | rtmsg_ifa(RTM_DELADDR, ifa, nlh, pid); |
267 | blocking_notifier_call_chain(&inetaddr_chain, | 277 | blocking_notifier_call_chain(&inetaddr_chain, |
268 | NETDEV_DOWN, ifa); | 278 | NETDEV_DOWN, ifa); |
269 | inet_free_ifa(ifa); | 279 | inet_free_ifa(ifa); |
@@ -288,7 +298,7 @@ static void inet_del_ifa(struct in_device *in_dev, struct in_ifaddr **ifap, | |||
288 | is valid, it will try to restore deleted routes... Grr. | 298 | is valid, it will try to restore deleted routes... Grr. |
289 | So that, this order is correct. | 299 | So that, this order is correct. |
290 | */ | 300 | */ |
291 | rtmsg_ifa(RTM_DELADDR, ifa1); | 301 | rtmsg_ifa(RTM_DELADDR, ifa1, nlh, pid); |
292 | blocking_notifier_call_chain(&inetaddr_chain, NETDEV_DOWN, ifa1); | 302 | blocking_notifier_call_chain(&inetaddr_chain, NETDEV_DOWN, ifa1); |
293 | 303 | ||
294 | if (promote) { | 304 | if (promote) { |
@@ -300,7 +310,7 @@ static void inet_del_ifa(struct in_device *in_dev, struct in_ifaddr **ifap, | |||
300 | } | 310 | } |
301 | 311 | ||
302 | promote->ifa_flags &= ~IFA_F_SECONDARY; | 312 | promote->ifa_flags &= ~IFA_F_SECONDARY; |
303 | rtmsg_ifa(RTM_NEWADDR, promote); | 313 | rtmsg_ifa(RTM_NEWADDR, promote, nlh, pid); |
304 | blocking_notifier_call_chain(&inetaddr_chain, | 314 | blocking_notifier_call_chain(&inetaddr_chain, |
305 | NETDEV_UP, promote); | 315 | NETDEV_UP, promote); |
306 | for (ifa = promote->ifa_next; ifa; ifa = ifa->ifa_next) { | 316 | for (ifa = promote->ifa_next; ifa; ifa = ifa->ifa_next) { |
@@ -319,7 +329,14 @@ static void inet_del_ifa(struct in_device *in_dev, struct in_ifaddr **ifap, | |||
319 | } | 329 | } |
320 | } | 330 | } |
321 | 331 | ||
322 | static int inet_insert_ifa(struct in_ifaddr *ifa) | 332 | static void inet_del_ifa(struct in_device *in_dev, struct in_ifaddr **ifap, |
333 | int destroy) | ||
334 | { | ||
335 | __inet_del_ifa(in_dev, ifap, destroy, NULL, 0); | ||
336 | } | ||
337 | |||
338 | static int __inet_insert_ifa(struct in_ifaddr *ifa, struct nlmsghdr *nlh, | ||
339 | u32 pid) | ||
323 | { | 340 | { |
324 | struct in_device *in_dev = ifa->ifa_dev; | 341 | struct in_device *in_dev = ifa->ifa_dev; |
325 | struct in_ifaddr *ifa1, **ifap, **last_primary; | 342 | struct in_ifaddr *ifa1, **ifap, **last_primary; |
@@ -364,12 +381,17 @@ static int inet_insert_ifa(struct in_ifaddr *ifa) | |||
364 | /* Send message first, then call notifier. | 381 | /* Send message first, then call notifier. |
365 | Notifier will trigger FIB update, so that | 382 | Notifier will trigger FIB update, so that |
366 | listeners of netlink will know about new ifaddr */ | 383 | listeners of netlink will know about new ifaddr */ |
367 | rtmsg_ifa(RTM_NEWADDR, ifa); | 384 | rtmsg_ifa(RTM_NEWADDR, ifa, nlh, pid); |
368 | blocking_notifier_call_chain(&inetaddr_chain, NETDEV_UP, ifa); | 385 | blocking_notifier_call_chain(&inetaddr_chain, NETDEV_UP, ifa); |
369 | 386 | ||
370 | return 0; | 387 | return 0; |
371 | } | 388 | } |
372 | 389 | ||
390 | static int inet_insert_ifa(struct in_ifaddr *ifa) | ||
391 | { | ||
392 | return __inet_insert_ifa(ifa, NULL, 0); | ||
393 | } | ||
394 | |||
373 | static int inet_set_ifa(struct net_device *dev, struct in_ifaddr *ifa) | 395 | static int inet_set_ifa(struct net_device *dev, struct in_ifaddr *ifa) |
374 | { | 396 | { |
375 | struct in_device *in_dev = __in_dev_get_rtnl(dev); | 397 | struct in_device *in_dev = __in_dev_get_rtnl(dev); |
@@ -421,87 +443,134 @@ struct in_ifaddr *inet_ifa_byprefix(struct in_device *in_dev, u32 prefix, | |||
421 | 443 | ||
422 | static int inet_rtm_deladdr(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) | 444 | static int inet_rtm_deladdr(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) |
423 | { | 445 | { |
424 | struct rtattr **rta = arg; | 446 | struct nlattr *tb[IFA_MAX+1]; |
425 | struct in_device *in_dev; | 447 | struct in_device *in_dev; |
426 | struct ifaddrmsg *ifm = NLMSG_DATA(nlh); | 448 | struct ifaddrmsg *ifm; |
427 | struct in_ifaddr *ifa, **ifap; | 449 | struct in_ifaddr *ifa, **ifap; |
450 | int err = -EINVAL; | ||
428 | 451 | ||
429 | ASSERT_RTNL(); | 452 | ASSERT_RTNL(); |
430 | 453 | ||
431 | if ((in_dev = inetdev_by_index(ifm->ifa_index)) == NULL) | 454 | err = nlmsg_parse(nlh, sizeof(*ifm), tb, IFA_MAX, ifa_ipv4_policy); |
432 | goto out; | 455 | if (err < 0) |
456 | goto errout; | ||
457 | |||
458 | ifm = nlmsg_data(nlh); | ||
459 | in_dev = inetdev_by_index(ifm->ifa_index); | ||
460 | if (in_dev == NULL) { | ||
461 | err = -ENODEV; | ||
462 | goto errout; | ||
463 | } | ||
464 | |||
433 | __in_dev_put(in_dev); | 465 | __in_dev_put(in_dev); |
434 | 466 | ||
435 | for (ifap = &in_dev->ifa_list; (ifa = *ifap) != NULL; | 467 | for (ifap = &in_dev->ifa_list; (ifa = *ifap) != NULL; |
436 | ifap = &ifa->ifa_next) { | 468 | ifap = &ifa->ifa_next) { |
437 | if ((rta[IFA_LOCAL - 1] && | 469 | if (tb[IFA_LOCAL] && |
438 | memcmp(RTA_DATA(rta[IFA_LOCAL - 1]), | 470 | ifa->ifa_local != nla_get_u32(tb[IFA_LOCAL])) |
439 | &ifa->ifa_local, 4)) || | 471 | continue; |
440 | (rta[IFA_LABEL - 1] && | 472 | |
441 | rtattr_strcmp(rta[IFA_LABEL - 1], ifa->ifa_label)) || | 473 | if (tb[IFA_LABEL] && nla_strcmp(tb[IFA_LABEL], ifa->ifa_label)) |
442 | (rta[IFA_ADDRESS - 1] && | 474 | continue; |
443 | (ifm->ifa_prefixlen != ifa->ifa_prefixlen || | 475 | |
444 | !inet_ifa_match(*(u32*)RTA_DATA(rta[IFA_ADDRESS - 1]), | 476 | if (tb[IFA_ADDRESS] && |
445 | ifa)))) | 477 | (ifm->ifa_prefixlen != ifa->ifa_prefixlen || |
478 | !inet_ifa_match(nla_get_u32(tb[IFA_ADDRESS]), ifa))) | ||
446 | continue; | 479 | continue; |
447 | inet_del_ifa(in_dev, ifap, 1); | 480 | |
481 | __inet_del_ifa(in_dev, ifap, 1, nlh, NETLINK_CB(skb).pid); | ||
448 | return 0; | 482 | return 0; |
449 | } | 483 | } |
450 | out: | 484 | |
451 | return -EADDRNOTAVAIL; | 485 | err = -EADDRNOTAVAIL; |
486 | errout: | ||
487 | return err; | ||
452 | } | 488 | } |
453 | 489 | ||
454 | static int inet_rtm_newaddr(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) | 490 | static struct in_ifaddr *rtm_to_ifaddr(struct nlmsghdr *nlh) |
455 | { | 491 | { |
456 | struct rtattr **rta = arg; | 492 | struct nlattr *tb[IFA_MAX+1]; |
493 | struct in_ifaddr *ifa; | ||
494 | struct ifaddrmsg *ifm; | ||
457 | struct net_device *dev; | 495 | struct net_device *dev; |
458 | struct in_device *in_dev; | 496 | struct in_device *in_dev; |
459 | struct ifaddrmsg *ifm = NLMSG_DATA(nlh); | 497 | int err = -EINVAL; |
460 | struct in_ifaddr *ifa; | ||
461 | int rc = -EINVAL; | ||
462 | 498 | ||
463 | ASSERT_RTNL(); | 499 | err = nlmsg_parse(nlh, sizeof(*ifm), tb, IFA_MAX, ifa_ipv4_policy); |
500 | if (err < 0) | ||
501 | goto errout; | ||
464 | 502 | ||
465 | if (ifm->ifa_prefixlen > 32 || !rta[IFA_LOCAL - 1]) | 503 | ifm = nlmsg_data(nlh); |
466 | goto out; | 504 | if (ifm->ifa_prefixlen > 32 || tb[IFA_LOCAL] == NULL) |
505 | goto errout; | ||
467 | 506 | ||
468 | rc = -ENODEV; | 507 | dev = __dev_get_by_index(ifm->ifa_index); |
469 | if ((dev = __dev_get_by_index(ifm->ifa_index)) == NULL) | 508 | if (dev == NULL) { |
470 | goto out; | 509 | err = -ENODEV; |
510 | goto errout; | ||
511 | } | ||
471 | 512 | ||
472 | rc = -ENOBUFS; | 513 | in_dev = __in_dev_get_rtnl(dev); |
473 | if ((in_dev = __in_dev_get_rtnl(dev)) == NULL) { | 514 | if (in_dev == NULL) { |
474 | in_dev = inetdev_init(dev); | 515 | in_dev = inetdev_init(dev); |
475 | if (!in_dev) | 516 | if (in_dev == NULL) { |
476 | goto out; | 517 | err = -ENOBUFS; |
518 | goto errout; | ||
519 | } | ||
477 | } | 520 | } |
478 | 521 | ||
479 | if ((ifa = inet_alloc_ifa()) == NULL) | 522 | ifa = inet_alloc_ifa(); |
480 | goto out; | 523 | if (ifa == NULL) { |
524 | /* | ||
525 | * A potential indev allocation can be left alive, it stays | ||
526 | * assigned to its device and is destroy with it. | ||
527 | */ | ||
528 | err = -ENOBUFS; | ||
529 | goto errout; | ||
530 | } | ||
531 | |||
532 | in_dev_hold(in_dev); | ||
533 | |||
534 | if (tb[IFA_ADDRESS] == NULL) | ||
535 | tb[IFA_ADDRESS] = tb[IFA_LOCAL]; | ||
481 | 536 | ||
482 | if (!rta[IFA_ADDRESS - 1]) | ||
483 | rta[IFA_ADDRESS - 1] = rta[IFA_LOCAL - 1]; | ||
484 | memcpy(&ifa->ifa_local, RTA_DATA(rta[IFA_LOCAL - 1]), 4); | ||
485 | memcpy(&ifa->ifa_address, RTA_DATA(rta[IFA_ADDRESS - 1]), 4); | ||
486 | ifa->ifa_prefixlen = ifm->ifa_prefixlen; | 537 | ifa->ifa_prefixlen = ifm->ifa_prefixlen; |
487 | ifa->ifa_mask = inet_make_mask(ifm->ifa_prefixlen); | 538 | ifa->ifa_mask = inet_make_mask(ifm->ifa_prefixlen); |
488 | if (rta[IFA_BROADCAST - 1]) | ||
489 | memcpy(&ifa->ifa_broadcast, | ||
490 | RTA_DATA(rta[IFA_BROADCAST - 1]), 4); | ||
491 | if (rta[IFA_ANYCAST - 1]) | ||
492 | memcpy(&ifa->ifa_anycast, RTA_DATA(rta[IFA_ANYCAST - 1]), 4); | ||
493 | ifa->ifa_flags = ifm->ifa_flags; | 539 | ifa->ifa_flags = ifm->ifa_flags; |
494 | ifa->ifa_scope = ifm->ifa_scope; | 540 | ifa->ifa_scope = ifm->ifa_scope; |
495 | in_dev_hold(in_dev); | 541 | ifa->ifa_dev = in_dev; |
496 | ifa->ifa_dev = in_dev; | 542 | |
497 | if (rta[IFA_LABEL - 1]) | 543 | ifa->ifa_local = nla_get_u32(tb[IFA_LOCAL]); |
498 | rtattr_strlcpy(ifa->ifa_label, rta[IFA_LABEL - 1], IFNAMSIZ); | 544 | ifa->ifa_address = nla_get_u32(tb[IFA_ADDRESS]); |
545 | |||
546 | if (tb[IFA_BROADCAST]) | ||
547 | ifa->ifa_broadcast = nla_get_u32(tb[IFA_BROADCAST]); | ||
548 | |||
549 | if (tb[IFA_ANYCAST]) | ||
550 | ifa->ifa_anycast = nla_get_u32(tb[IFA_ANYCAST]); | ||
551 | |||
552 | if (tb[IFA_LABEL]) | ||
553 | nla_strlcpy(ifa->ifa_label, tb[IFA_LABEL], IFNAMSIZ); | ||
499 | else | 554 | else |
500 | memcpy(ifa->ifa_label, dev->name, IFNAMSIZ); | 555 | memcpy(ifa->ifa_label, dev->name, IFNAMSIZ); |
501 | 556 | ||
502 | rc = inet_insert_ifa(ifa); | 557 | return ifa; |
503 | out: | 558 | |
504 | return rc; | 559 | errout: |
560 | return ERR_PTR(err); | ||
561 | } | ||
562 | |||
563 | static int inet_rtm_newaddr(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) | ||
564 | { | ||
565 | struct in_ifaddr *ifa; | ||
566 | |||
567 | ASSERT_RTNL(); | ||
568 | |||
569 | ifa = rtm_to_ifaddr(nlh); | ||
570 | if (IS_ERR(ifa)) | ||
571 | return PTR_ERR(ifa); | ||
572 | |||
573 | return __inet_insert_ifa(ifa, nlh, NETLINK_CB(skb).pid); | ||
505 | } | 574 | } |
506 | 575 | ||
507 | /* | 576 | /* |
@@ -1056,32 +1125,37 @@ static int inet_fill_ifaddr(struct sk_buff *skb, struct in_ifaddr *ifa, | |||
1056 | { | 1125 | { |
1057 | struct ifaddrmsg *ifm; | 1126 | struct ifaddrmsg *ifm; |
1058 | struct nlmsghdr *nlh; | 1127 | struct nlmsghdr *nlh; |
1059 | unsigned char *b = skb->tail; | ||
1060 | 1128 | ||
1061 | nlh = NLMSG_NEW(skb, pid, seq, event, sizeof(*ifm), flags); | 1129 | nlh = nlmsg_put(skb, pid, seq, event, sizeof(*ifm), flags); |
1062 | ifm = NLMSG_DATA(nlh); | 1130 | if (nlh == NULL) |
1131 | return -ENOBUFS; | ||
1132 | |||
1133 | ifm = nlmsg_data(nlh); | ||
1063 | ifm->ifa_family = AF_INET; | 1134 | ifm->ifa_family = AF_INET; |
1064 | ifm->ifa_prefixlen = ifa->ifa_prefixlen; | 1135 | ifm->ifa_prefixlen = ifa->ifa_prefixlen; |
1065 | ifm->ifa_flags = ifa->ifa_flags|IFA_F_PERMANENT; | 1136 | ifm->ifa_flags = ifa->ifa_flags|IFA_F_PERMANENT; |
1066 | ifm->ifa_scope = ifa->ifa_scope; | 1137 | ifm->ifa_scope = ifa->ifa_scope; |
1067 | ifm->ifa_index = ifa->ifa_dev->dev->ifindex; | 1138 | ifm->ifa_index = ifa->ifa_dev->dev->ifindex; |
1139 | |||
1068 | if (ifa->ifa_address) | 1140 | if (ifa->ifa_address) |
1069 | RTA_PUT(skb, IFA_ADDRESS, 4, &ifa->ifa_address); | 1141 | NLA_PUT_U32(skb, IFA_ADDRESS, ifa->ifa_address); |
1142 | |||
1070 | if (ifa->ifa_local) | 1143 | if (ifa->ifa_local) |
1071 | RTA_PUT(skb, IFA_LOCAL, 4, &ifa->ifa_local); | 1144 | NLA_PUT_U32(skb, IFA_LOCAL, ifa->ifa_local); |
1145 | |||
1072 | if (ifa->ifa_broadcast) | 1146 | if (ifa->ifa_broadcast) |
1073 | RTA_PUT(skb, IFA_BROADCAST, 4, &ifa->ifa_broadcast); | 1147 | NLA_PUT_U32(skb, IFA_BROADCAST, ifa->ifa_broadcast); |
1148 | |||
1074 | if (ifa->ifa_anycast) | 1149 | if (ifa->ifa_anycast) |
1075 | RTA_PUT(skb, IFA_ANYCAST, 4, &ifa->ifa_anycast); | 1150 | NLA_PUT_U32(skb, IFA_ANYCAST, ifa->ifa_anycast); |
1151 | |||
1076 | if (ifa->ifa_label[0]) | 1152 | if (ifa->ifa_label[0]) |
1077 | RTA_PUT(skb, IFA_LABEL, IFNAMSIZ, &ifa->ifa_label); | 1153 | NLA_PUT_STRING(skb, IFA_LABEL, ifa->ifa_label); |
1078 | nlh->nlmsg_len = skb->tail - b; | ||
1079 | return skb->len; | ||
1080 | 1154 | ||
1081 | nlmsg_failure: | 1155 | return nlmsg_end(skb, nlh); |
1082 | rtattr_failure: | 1156 | |
1083 | skb_trim(skb, b - skb->data); | 1157 | nla_put_failure: |
1084 | return -1; | 1158 | return nlmsg_cancel(skb, nlh); |
1085 | } | 1159 | } |
1086 | 1160 | ||
1087 | static int inet_dump_ifaddr(struct sk_buff *skb, struct netlink_callback *cb) | 1161 | static int inet_dump_ifaddr(struct sk_buff *skb, struct netlink_callback *cb) |
@@ -1127,19 +1201,27 @@ done: | |||
1127 | return skb->len; | 1201 | return skb->len; |
1128 | } | 1202 | } |
1129 | 1203 | ||
1130 | static void rtmsg_ifa(int event, struct in_ifaddr* ifa) | 1204 | static void rtmsg_ifa(int event, struct in_ifaddr* ifa, struct nlmsghdr *nlh, |
1205 | u32 pid) | ||
1131 | { | 1206 | { |
1132 | int size = NLMSG_SPACE(sizeof(struct ifaddrmsg) + 128); | 1207 | struct sk_buff *skb; |
1133 | struct sk_buff *skb = alloc_skb(size, GFP_KERNEL); | 1208 | u32 seq = nlh ? nlh->nlmsg_seq : 0; |
1209 | int err = -ENOBUFS; | ||
1210 | |||
1211 | skb = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); | ||
1212 | if (skb == NULL) | ||
1213 | goto errout; | ||
1134 | 1214 | ||
1135 | if (!skb) | 1215 | err = inet_fill_ifaddr(skb, ifa, pid, seq, event, 0); |
1136 | netlink_set_err(rtnl, 0, RTNLGRP_IPV4_IFADDR, ENOBUFS); | 1216 | if (err < 0) { |
1137 | else if (inet_fill_ifaddr(skb, ifa, 0, 0, event, 0) < 0) { | ||
1138 | kfree_skb(skb); | 1217 | kfree_skb(skb); |
1139 | netlink_set_err(rtnl, 0, RTNLGRP_IPV4_IFADDR, EINVAL); | 1218 | goto errout; |
1140 | } else { | ||
1141 | netlink_broadcast(rtnl, skb, 0, RTNLGRP_IPV4_IFADDR, GFP_KERNEL); | ||
1142 | } | 1219 | } |
1220 | |||
1221 | err = rtnl_notify(skb, pid, RTNLGRP_IPV4_IFADDR, nlh, GFP_KERNEL); | ||
1222 | errout: | ||
1223 | if (err < 0) | ||
1224 | rtnl_set_sk_err(RTNLGRP_IPV4_IFADDR, err); | ||
1143 | } | 1225 | } |
1144 | 1226 | ||
1145 | static struct rtnetlink_link inet_rtnetlink_table[RTM_NR_MSGTYPES] = { | 1227 | static struct rtnetlink_link inet_rtnetlink_table[RTM_NR_MSGTYPES] = { |
@@ -1151,9 +1233,7 @@ static struct rtnetlink_link inet_rtnetlink_table[RTM_NR_MSGTYPES] = { | |||
1151 | [RTM_GETROUTE - RTM_BASE] = { .doit = inet_rtm_getroute, | 1233 | [RTM_GETROUTE - RTM_BASE] = { .doit = inet_rtm_getroute, |
1152 | .dumpit = inet_dump_fib, }, | 1234 | .dumpit = inet_dump_fib, }, |
1153 | #ifdef CONFIG_IP_MULTIPLE_TABLES | 1235 | #ifdef CONFIG_IP_MULTIPLE_TABLES |
1154 | [RTM_NEWRULE - RTM_BASE] = { .doit = inet_rtm_newrule, }, | 1236 | [RTM_GETRULE - RTM_BASE] = { .dumpit = fib4_rules_dump, }, |
1155 | [RTM_DELRULE - RTM_BASE] = { .doit = inet_rtm_delrule, }, | ||
1156 | [RTM_GETRULE - RTM_BASE] = { .dumpit = inet_dump_rules, }, | ||
1157 | #endif | 1237 | #endif |
1158 | }; | 1238 | }; |
1159 | 1239 | ||
diff --git a/net/ipv4/esp4.c b/net/ipv4/esp4.c index b428489f6ccd..13b29360d102 100644 --- a/net/ipv4/esp4.c +++ b/net/ipv4/esp4.c | |||
@@ -95,8 +95,13 @@ static int esp_output(struct xfrm_state *x, struct sk_buff *skb) | |||
95 | esph->seq_no = htonl(++x->replay.oseq); | 95 | esph->seq_no = htonl(++x->replay.oseq); |
96 | xfrm_aevent_doreplay(x); | 96 | xfrm_aevent_doreplay(x); |
97 | 97 | ||
98 | if (esp->conf.ivlen) | 98 | if (esp->conf.ivlen) { |
99 | if (unlikely(!esp->conf.ivinitted)) { | ||
100 | get_random_bytes(esp->conf.ivec, esp->conf.ivlen); | ||
101 | esp->conf.ivinitted = 1; | ||
102 | } | ||
99 | crypto_blkcipher_set_iv(tfm, esp->conf.ivec, esp->conf.ivlen); | 103 | crypto_blkcipher_set_iv(tfm, esp->conf.ivec, esp->conf.ivlen); |
104 | } | ||
100 | 105 | ||
101 | do { | 106 | do { |
102 | struct scatterlist *sg = &esp->sgbuf[0]; | 107 | struct scatterlist *sg = &esp->sgbuf[0]; |
@@ -248,7 +253,7 @@ static int esp_input(struct xfrm_state *x, struct sk_buff *skb) | |||
248 | * as per draft-ietf-ipsec-udp-encaps-06, | 253 | * as per draft-ietf-ipsec-udp-encaps-06, |
249 | * section 3.1.2 | 254 | * section 3.1.2 |
250 | */ | 255 | */ |
251 | if (!x->props.mode) | 256 | if (x->props.mode == XFRM_MODE_TRANSPORT) |
252 | skb->ip_summed = CHECKSUM_UNNECESSARY; | 257 | skb->ip_summed = CHECKSUM_UNNECESSARY; |
253 | } | 258 | } |
254 | 259 | ||
@@ -267,7 +272,7 @@ static u32 esp4_get_max_size(struct xfrm_state *x, int mtu) | |||
267 | struct esp_data *esp = x->data; | 272 | struct esp_data *esp = x->data; |
268 | u32 blksize = ALIGN(crypto_blkcipher_blocksize(esp->conf.tfm), 4); | 273 | u32 blksize = ALIGN(crypto_blkcipher_blocksize(esp->conf.tfm), 4); |
269 | 274 | ||
270 | if (x->props.mode) { | 275 | if (x->props.mode == XFRM_MODE_TUNNEL) { |
271 | mtu = ALIGN(mtu + 2, blksize); | 276 | mtu = ALIGN(mtu + 2, blksize); |
272 | } else { | 277 | } else { |
273 | /* The worst case. */ | 278 | /* The worst case. */ |
@@ -378,12 +383,12 @@ static int esp_init_state(struct xfrm_state *x) | |||
378 | esp->conf.ivec = kmalloc(esp->conf.ivlen, GFP_KERNEL); | 383 | esp->conf.ivec = kmalloc(esp->conf.ivlen, GFP_KERNEL); |
379 | if (unlikely(esp->conf.ivec == NULL)) | 384 | if (unlikely(esp->conf.ivec == NULL)) |
380 | goto error; | 385 | goto error; |
381 | get_random_bytes(esp->conf.ivec, esp->conf.ivlen); | 386 | esp->conf.ivinitted = 0; |
382 | } | 387 | } |
383 | if (crypto_blkcipher_setkey(tfm, esp->conf.key, esp->conf.key_len)) | 388 | if (crypto_blkcipher_setkey(tfm, esp->conf.key, esp->conf.key_len)) |
384 | goto error; | 389 | goto error; |
385 | x->props.header_len = sizeof(struct ip_esp_hdr) + esp->conf.ivlen; | 390 | x->props.header_len = sizeof(struct ip_esp_hdr) + esp->conf.ivlen; |
386 | if (x->props.mode) | 391 | if (x->props.mode == XFRM_MODE_TUNNEL) |
387 | x->props.header_len += sizeof(struct iphdr); | 392 | x->props.header_len += sizeof(struct iphdr); |
388 | if (x->encap) { | 393 | if (x->encap) { |
389 | struct xfrm_encap_tmpl *encap = x->encap; | 394 | struct xfrm_encap_tmpl *encap = x->encap; |
diff --git a/net/ipv4/fib_frontend.c b/net/ipv4/fib_frontend.c index ba2a70745a63..cfb527c060e4 100644 --- a/net/ipv4/fib_frontend.c +++ b/net/ipv4/fib_frontend.c | |||
@@ -32,10 +32,12 @@ | |||
32 | #include <linux/inet.h> | 32 | #include <linux/inet.h> |
33 | #include <linux/inetdevice.h> | 33 | #include <linux/inetdevice.h> |
34 | #include <linux/netdevice.h> | 34 | #include <linux/netdevice.h> |
35 | #include <linux/if_addr.h> | ||
35 | #include <linux/if_arp.h> | 36 | #include <linux/if_arp.h> |
36 | #include <linux/skbuff.h> | 37 | #include <linux/skbuff.h> |
37 | #include <linux/netlink.h> | 38 | #include <linux/netlink.h> |
38 | #include <linux/init.h> | 39 | #include <linux/init.h> |
40 | #include <linux/list.h> | ||
39 | 41 | ||
40 | #include <net/ip.h> | 42 | #include <net/ip.h> |
41 | #include <net/protocol.h> | 43 | #include <net/protocol.h> |
@@ -50,48 +52,67 @@ | |||
50 | 52 | ||
51 | #ifndef CONFIG_IP_MULTIPLE_TABLES | 53 | #ifndef CONFIG_IP_MULTIPLE_TABLES |
52 | 54 | ||
53 | #define RT_TABLE_MIN RT_TABLE_MAIN | ||
54 | |||
55 | struct fib_table *ip_fib_local_table; | 55 | struct fib_table *ip_fib_local_table; |
56 | struct fib_table *ip_fib_main_table; | 56 | struct fib_table *ip_fib_main_table; |
57 | 57 | ||
58 | #else | 58 | #define FIB_TABLE_HASHSZ 1 |
59 | static struct hlist_head fib_table_hash[FIB_TABLE_HASHSZ]; | ||
59 | 60 | ||
60 | #define RT_TABLE_MIN 1 | 61 | #else |
61 | 62 | ||
62 | struct fib_table *fib_tables[RT_TABLE_MAX+1]; | 63 | #define FIB_TABLE_HASHSZ 256 |
64 | static struct hlist_head fib_table_hash[FIB_TABLE_HASHSZ]; | ||
63 | 65 | ||
64 | struct fib_table *__fib_new_table(int id) | 66 | struct fib_table *fib_new_table(u32 id) |
65 | { | 67 | { |
66 | struct fib_table *tb; | 68 | struct fib_table *tb; |
69 | unsigned int h; | ||
67 | 70 | ||
71 | if (id == 0) | ||
72 | id = RT_TABLE_MAIN; | ||
73 | tb = fib_get_table(id); | ||
74 | if (tb) | ||
75 | return tb; | ||
68 | tb = fib_hash_init(id); | 76 | tb = fib_hash_init(id); |
69 | if (!tb) | 77 | if (!tb) |
70 | return NULL; | 78 | return NULL; |
71 | fib_tables[id] = tb; | 79 | h = id & (FIB_TABLE_HASHSZ - 1); |
80 | hlist_add_head_rcu(&tb->tb_hlist, &fib_table_hash[h]); | ||
72 | return tb; | 81 | return tb; |
73 | } | 82 | } |
74 | 83 | ||
84 | struct fib_table *fib_get_table(u32 id) | ||
85 | { | ||
86 | struct fib_table *tb; | ||
87 | struct hlist_node *node; | ||
88 | unsigned int h; | ||
75 | 89 | ||
90 | if (id == 0) | ||
91 | id = RT_TABLE_MAIN; | ||
92 | h = id & (FIB_TABLE_HASHSZ - 1); | ||
93 | rcu_read_lock(); | ||
94 | hlist_for_each_entry_rcu(tb, node, &fib_table_hash[h], tb_hlist) { | ||
95 | if (tb->tb_id == id) { | ||
96 | rcu_read_unlock(); | ||
97 | return tb; | ||
98 | } | ||
99 | } | ||
100 | rcu_read_unlock(); | ||
101 | return NULL; | ||
102 | } | ||
76 | #endif /* CONFIG_IP_MULTIPLE_TABLES */ | 103 | #endif /* CONFIG_IP_MULTIPLE_TABLES */ |
77 | 104 | ||
78 | |||
79 | static void fib_flush(void) | 105 | static void fib_flush(void) |
80 | { | 106 | { |
81 | int flushed = 0; | 107 | int flushed = 0; |
82 | #ifdef CONFIG_IP_MULTIPLE_TABLES | ||
83 | struct fib_table *tb; | 108 | struct fib_table *tb; |
84 | int id; | 109 | struct hlist_node *node; |
110 | unsigned int h; | ||
85 | 111 | ||
86 | for (id = RT_TABLE_MAX; id>0; id--) { | 112 | for (h = 0; h < FIB_TABLE_HASHSZ; h++) { |
87 | if ((tb = fib_get_table(id))==NULL) | 113 | hlist_for_each_entry(tb, node, &fib_table_hash[h], tb_hlist) |
88 | continue; | 114 | flushed += tb->tb_flush(tb); |
89 | flushed += tb->tb_flush(tb); | ||
90 | } | 115 | } |
91 | #else /* CONFIG_IP_MULTIPLE_TABLES */ | ||
92 | flushed += ip_fib_main_table->tb_flush(ip_fib_main_table); | ||
93 | flushed += ip_fib_local_table->tb_flush(ip_fib_local_table); | ||
94 | #endif /* CONFIG_IP_MULTIPLE_TABLES */ | ||
95 | 116 | ||
96 | if (flushed) | 117 | if (flushed) |
97 | rt_cache_flush(-1); | 118 | rt_cache_flush(-1); |
@@ -232,42 +253,190 @@ e_inval: | |||
232 | 253 | ||
233 | #ifndef CONFIG_IP_NOSIOCRT | 254 | #ifndef CONFIG_IP_NOSIOCRT |
234 | 255 | ||
256 | static inline u32 sk_extract_addr(struct sockaddr *addr) | ||
257 | { | ||
258 | return ((struct sockaddr_in *) addr)->sin_addr.s_addr; | ||
259 | } | ||
260 | |||
261 | static int put_rtax(struct nlattr *mx, int len, int type, u32 value) | ||
262 | { | ||
263 | struct nlattr *nla; | ||
264 | |||
265 | nla = (struct nlattr *) ((char *) mx + len); | ||
266 | nla->nla_type = type; | ||
267 | nla->nla_len = nla_attr_size(4); | ||
268 | *(u32 *) nla_data(nla) = value; | ||
269 | |||
270 | return len + nla_total_size(4); | ||
271 | } | ||
272 | |||
273 | static int rtentry_to_fib_config(int cmd, struct rtentry *rt, | ||
274 | struct fib_config *cfg) | ||
275 | { | ||
276 | u32 addr; | ||
277 | int plen; | ||
278 | |||
279 | memset(cfg, 0, sizeof(*cfg)); | ||
280 | |||
281 | if (rt->rt_dst.sa_family != AF_INET) | ||
282 | return -EAFNOSUPPORT; | ||
283 | |||
284 | /* | ||
285 | * Check mask for validity: | ||
286 | * a) it must be contiguous. | ||
287 | * b) destination must have all host bits clear. | ||
288 | * c) if application forgot to set correct family (AF_INET), | ||
289 | * reject request unless it is absolutely clear i.e. | ||
290 | * both family and mask are zero. | ||
291 | */ | ||
292 | plen = 32; | ||
293 | addr = sk_extract_addr(&rt->rt_dst); | ||
294 | if (!(rt->rt_flags & RTF_HOST)) { | ||
295 | u32 mask = sk_extract_addr(&rt->rt_genmask); | ||
296 | |||
297 | if (rt->rt_genmask.sa_family != AF_INET) { | ||
298 | if (mask || rt->rt_genmask.sa_family) | ||
299 | return -EAFNOSUPPORT; | ||
300 | } | ||
301 | |||
302 | if (bad_mask(mask, addr)) | ||
303 | return -EINVAL; | ||
304 | |||
305 | plen = inet_mask_len(mask); | ||
306 | } | ||
307 | |||
308 | cfg->fc_dst_len = plen; | ||
309 | cfg->fc_dst = addr; | ||
310 | |||
311 | if (cmd != SIOCDELRT) { | ||
312 | cfg->fc_nlflags = NLM_F_CREATE; | ||
313 | cfg->fc_protocol = RTPROT_BOOT; | ||
314 | } | ||
315 | |||
316 | if (rt->rt_metric) | ||
317 | cfg->fc_priority = rt->rt_metric - 1; | ||
318 | |||
319 | if (rt->rt_flags & RTF_REJECT) { | ||
320 | cfg->fc_scope = RT_SCOPE_HOST; | ||
321 | cfg->fc_type = RTN_UNREACHABLE; | ||
322 | return 0; | ||
323 | } | ||
324 | |||
325 | cfg->fc_scope = RT_SCOPE_NOWHERE; | ||
326 | cfg->fc_type = RTN_UNICAST; | ||
327 | |||
328 | if (rt->rt_dev) { | ||
329 | char *colon; | ||
330 | struct net_device *dev; | ||
331 | char devname[IFNAMSIZ]; | ||
332 | |||
333 | if (copy_from_user(devname, rt->rt_dev, IFNAMSIZ-1)) | ||
334 | return -EFAULT; | ||
335 | |||
336 | devname[IFNAMSIZ-1] = 0; | ||
337 | colon = strchr(devname, ':'); | ||
338 | if (colon) | ||
339 | *colon = 0; | ||
340 | dev = __dev_get_by_name(devname); | ||
341 | if (!dev) | ||
342 | return -ENODEV; | ||
343 | cfg->fc_oif = dev->ifindex; | ||
344 | if (colon) { | ||
345 | struct in_ifaddr *ifa; | ||
346 | struct in_device *in_dev = __in_dev_get_rtnl(dev); | ||
347 | if (!in_dev) | ||
348 | return -ENODEV; | ||
349 | *colon = ':'; | ||
350 | for (ifa = in_dev->ifa_list; ifa; ifa = ifa->ifa_next) | ||
351 | if (strcmp(ifa->ifa_label, devname) == 0) | ||
352 | break; | ||
353 | if (ifa == NULL) | ||
354 | return -ENODEV; | ||
355 | cfg->fc_prefsrc = ifa->ifa_local; | ||
356 | } | ||
357 | } | ||
358 | |||
359 | addr = sk_extract_addr(&rt->rt_gateway); | ||
360 | if (rt->rt_gateway.sa_family == AF_INET && addr) { | ||
361 | cfg->fc_gw = addr; | ||
362 | if (rt->rt_flags & RTF_GATEWAY && | ||
363 | inet_addr_type(addr) == RTN_UNICAST) | ||
364 | cfg->fc_scope = RT_SCOPE_UNIVERSE; | ||
365 | } | ||
366 | |||
367 | if (cmd == SIOCDELRT) | ||
368 | return 0; | ||
369 | |||
370 | if (rt->rt_flags & RTF_GATEWAY && !cfg->fc_gw) | ||
371 | return -EINVAL; | ||
372 | |||
373 | if (cfg->fc_scope == RT_SCOPE_NOWHERE) | ||
374 | cfg->fc_scope = RT_SCOPE_LINK; | ||
375 | |||
376 | if (rt->rt_flags & (RTF_MTU | RTF_WINDOW | RTF_IRTT)) { | ||
377 | struct nlattr *mx; | ||
378 | int len = 0; | ||
379 | |||
380 | mx = kzalloc(3 * nla_total_size(4), GFP_KERNEL); | ||
381 | if (mx == NULL) | ||
382 | return -ENOMEM; | ||
383 | |||
384 | if (rt->rt_flags & RTF_MTU) | ||
385 | len = put_rtax(mx, len, RTAX_ADVMSS, rt->rt_mtu - 40); | ||
386 | |||
387 | if (rt->rt_flags & RTF_WINDOW) | ||
388 | len = put_rtax(mx, len, RTAX_WINDOW, rt->rt_window); | ||
389 | |||
390 | if (rt->rt_flags & RTF_IRTT) | ||
391 | len = put_rtax(mx, len, RTAX_RTT, rt->rt_irtt << 3); | ||
392 | |||
393 | cfg->fc_mx = mx; | ||
394 | cfg->fc_mx_len = len; | ||
395 | } | ||
396 | |||
397 | return 0; | ||
398 | } | ||
399 | |||
235 | /* | 400 | /* |
236 | * Handle IP routing ioctl calls. These are used to manipulate the routing tables | 401 | * Handle IP routing ioctl calls. These are used to manipulate the routing tables |
237 | */ | 402 | */ |
238 | 403 | ||
239 | int ip_rt_ioctl(unsigned int cmd, void __user *arg) | 404 | int ip_rt_ioctl(unsigned int cmd, void __user *arg) |
240 | { | 405 | { |
406 | struct fib_config cfg; | ||
407 | struct rtentry rt; | ||
241 | int err; | 408 | int err; |
242 | struct kern_rta rta; | ||
243 | struct rtentry r; | ||
244 | struct { | ||
245 | struct nlmsghdr nlh; | ||
246 | struct rtmsg rtm; | ||
247 | } req; | ||
248 | 409 | ||
249 | switch (cmd) { | 410 | switch (cmd) { |
250 | case SIOCADDRT: /* Add a route */ | 411 | case SIOCADDRT: /* Add a route */ |
251 | case SIOCDELRT: /* Delete a route */ | 412 | case SIOCDELRT: /* Delete a route */ |
252 | if (!capable(CAP_NET_ADMIN)) | 413 | if (!capable(CAP_NET_ADMIN)) |
253 | return -EPERM; | 414 | return -EPERM; |
254 | if (copy_from_user(&r, arg, sizeof(struct rtentry))) | 415 | |
416 | if (copy_from_user(&rt, arg, sizeof(rt))) | ||
255 | return -EFAULT; | 417 | return -EFAULT; |
418 | |||
256 | rtnl_lock(); | 419 | rtnl_lock(); |
257 | err = fib_convert_rtentry(cmd, &req.nlh, &req.rtm, &rta, &r); | 420 | err = rtentry_to_fib_config(cmd, &rt, &cfg); |
258 | if (err == 0) { | 421 | if (err == 0) { |
422 | struct fib_table *tb; | ||
423 | |||
259 | if (cmd == SIOCDELRT) { | 424 | if (cmd == SIOCDELRT) { |
260 | struct fib_table *tb = fib_get_table(req.rtm.rtm_table); | 425 | tb = fib_get_table(cfg.fc_table); |
261 | err = -ESRCH; | ||
262 | if (tb) | 426 | if (tb) |
263 | err = tb->tb_delete(tb, &req.rtm, &rta, &req.nlh, NULL); | 427 | err = tb->tb_delete(tb, &cfg); |
428 | else | ||
429 | err = -ESRCH; | ||
264 | } else { | 430 | } else { |
265 | struct fib_table *tb = fib_new_table(req.rtm.rtm_table); | 431 | tb = fib_new_table(cfg.fc_table); |
266 | err = -ENOBUFS; | ||
267 | if (tb) | 432 | if (tb) |
268 | err = tb->tb_insert(tb, &req.rtm, &rta, &req.nlh, NULL); | 433 | err = tb->tb_insert(tb, &cfg); |
434 | else | ||
435 | err = -ENOBUFS; | ||
269 | } | 436 | } |
270 | kfree(rta.rta_mx); | 437 | |
438 | /* allocated by rtentry_to_fib_config() */ | ||
439 | kfree(cfg.fc_mx); | ||
271 | } | 440 | } |
272 | rtnl_unlock(); | 441 | rtnl_unlock(); |
273 | return err; | 442 | return err; |
@@ -284,77 +453,169 @@ int ip_rt_ioctl(unsigned int cmd, void *arg) | |||
284 | 453 | ||
285 | #endif | 454 | #endif |
286 | 455 | ||
287 | static int inet_check_attr(struct rtmsg *r, struct rtattr **rta) | 456 | struct nla_policy rtm_ipv4_policy[RTA_MAX+1] __read_mostly = { |
457 | [RTA_DST] = { .type = NLA_U32 }, | ||
458 | [RTA_SRC] = { .type = NLA_U32 }, | ||
459 | [RTA_IIF] = { .type = NLA_U32 }, | ||
460 | [RTA_OIF] = { .type = NLA_U32 }, | ||
461 | [RTA_GATEWAY] = { .type = NLA_U32 }, | ||
462 | [RTA_PRIORITY] = { .type = NLA_U32 }, | ||
463 | [RTA_PREFSRC] = { .type = NLA_U32 }, | ||
464 | [RTA_METRICS] = { .type = NLA_NESTED }, | ||
465 | [RTA_MULTIPATH] = { .len = sizeof(struct rtnexthop) }, | ||
466 | [RTA_PROTOINFO] = { .type = NLA_U32 }, | ||
467 | [RTA_FLOW] = { .type = NLA_U32 }, | ||
468 | [RTA_MP_ALGO] = { .type = NLA_U32 }, | ||
469 | }; | ||
470 | |||
471 | static int rtm_to_fib_config(struct sk_buff *skb, struct nlmsghdr *nlh, | ||
472 | struct fib_config *cfg) | ||
288 | { | 473 | { |
289 | int i; | 474 | struct nlattr *attr; |
290 | 475 | int err, remaining; | |
291 | for (i=1; i<=RTA_MAX; i++, rta++) { | 476 | struct rtmsg *rtm; |
292 | struct rtattr *attr = *rta; | 477 | |
293 | if (attr) { | 478 | err = nlmsg_validate(nlh, sizeof(*rtm), RTA_MAX, rtm_ipv4_policy); |
294 | if (RTA_PAYLOAD(attr) < 4) | 479 | if (err < 0) |
295 | return -EINVAL; | 480 | goto errout; |
296 | if (i != RTA_MULTIPATH && i != RTA_METRICS) | 481 | |
297 | *rta = (struct rtattr*)RTA_DATA(attr); | 482 | memset(cfg, 0, sizeof(*cfg)); |
483 | |||
484 | rtm = nlmsg_data(nlh); | ||
485 | cfg->fc_family = rtm->rtm_family; | ||
486 | cfg->fc_dst_len = rtm->rtm_dst_len; | ||
487 | cfg->fc_src_len = rtm->rtm_src_len; | ||
488 | cfg->fc_tos = rtm->rtm_tos; | ||
489 | cfg->fc_table = rtm->rtm_table; | ||
490 | cfg->fc_protocol = rtm->rtm_protocol; | ||
491 | cfg->fc_scope = rtm->rtm_scope; | ||
492 | cfg->fc_type = rtm->rtm_type; | ||
493 | cfg->fc_flags = rtm->rtm_flags; | ||
494 | cfg->fc_nlflags = nlh->nlmsg_flags; | ||
495 | |||
496 | cfg->fc_nlinfo.pid = NETLINK_CB(skb).pid; | ||
497 | cfg->fc_nlinfo.nlh = nlh; | ||
498 | |||
499 | nlmsg_for_each_attr(attr, nlh, sizeof(struct rtmsg), remaining) { | ||
500 | switch (attr->nla_type) { | ||
501 | case RTA_DST: | ||
502 | cfg->fc_dst = nla_get_u32(attr); | ||
503 | break; | ||
504 | case RTA_SRC: | ||
505 | cfg->fc_src = nla_get_u32(attr); | ||
506 | break; | ||
507 | case RTA_OIF: | ||
508 | cfg->fc_oif = nla_get_u32(attr); | ||
509 | break; | ||
510 | case RTA_GATEWAY: | ||
511 | cfg->fc_gw = nla_get_u32(attr); | ||
512 | break; | ||
513 | case RTA_PRIORITY: | ||
514 | cfg->fc_priority = nla_get_u32(attr); | ||
515 | break; | ||
516 | case RTA_PREFSRC: | ||
517 | cfg->fc_prefsrc = nla_get_u32(attr); | ||
518 | break; | ||
519 | case RTA_METRICS: | ||
520 | cfg->fc_mx = nla_data(attr); | ||
521 | cfg->fc_mx_len = nla_len(attr); | ||
522 | break; | ||
523 | case RTA_MULTIPATH: | ||
524 | cfg->fc_mp = nla_data(attr); | ||
525 | cfg->fc_mp_len = nla_len(attr); | ||
526 | break; | ||
527 | case RTA_FLOW: | ||
528 | cfg->fc_flow = nla_get_u32(attr); | ||
529 | break; | ||
530 | case RTA_MP_ALGO: | ||
531 | cfg->fc_mp_alg = nla_get_u32(attr); | ||
532 | break; | ||
533 | case RTA_TABLE: | ||
534 | cfg->fc_table = nla_get_u32(attr); | ||
535 | break; | ||
298 | } | 536 | } |
299 | } | 537 | } |
538 | |||
300 | return 0; | 539 | return 0; |
540 | errout: | ||
541 | return err; | ||
301 | } | 542 | } |
302 | 543 | ||
303 | int inet_rtm_delroute(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg) | 544 | int inet_rtm_delroute(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg) |
304 | { | 545 | { |
305 | struct fib_table * tb; | 546 | struct fib_config cfg; |
306 | struct rtattr **rta = arg; | 547 | struct fib_table *tb; |
307 | struct rtmsg *r = NLMSG_DATA(nlh); | 548 | int err; |
308 | 549 | ||
309 | if (inet_check_attr(r, rta)) | 550 | err = rtm_to_fib_config(skb, nlh, &cfg); |
310 | return -EINVAL; | 551 | if (err < 0) |
552 | goto errout; | ||
311 | 553 | ||
312 | tb = fib_get_table(r->rtm_table); | 554 | tb = fib_get_table(cfg.fc_table); |
313 | if (tb) | 555 | if (tb == NULL) { |
314 | return tb->tb_delete(tb, r, (struct kern_rta*)rta, nlh, &NETLINK_CB(skb)); | 556 | err = -ESRCH; |
315 | return -ESRCH; | 557 | goto errout; |
558 | } | ||
559 | |||
560 | err = tb->tb_delete(tb, &cfg); | ||
561 | errout: | ||
562 | return err; | ||
316 | } | 563 | } |
317 | 564 | ||
318 | int inet_rtm_newroute(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg) | 565 | int inet_rtm_newroute(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg) |
319 | { | 566 | { |
320 | struct fib_table * tb; | 567 | struct fib_config cfg; |
321 | struct rtattr **rta = arg; | 568 | struct fib_table *tb; |
322 | struct rtmsg *r = NLMSG_DATA(nlh); | 569 | int err; |
323 | 570 | ||
324 | if (inet_check_attr(r, rta)) | 571 | err = rtm_to_fib_config(skb, nlh, &cfg); |
325 | return -EINVAL; | 572 | if (err < 0) |
573 | goto errout; | ||
326 | 574 | ||
327 | tb = fib_new_table(r->rtm_table); | 575 | tb = fib_new_table(cfg.fc_table); |
328 | if (tb) | 576 | if (tb == NULL) { |
329 | return tb->tb_insert(tb, r, (struct kern_rta*)rta, nlh, &NETLINK_CB(skb)); | 577 | err = -ENOBUFS; |
330 | return -ENOBUFS; | 578 | goto errout; |
579 | } | ||
580 | |||
581 | err = tb->tb_insert(tb, &cfg); | ||
582 | errout: | ||
583 | return err; | ||
331 | } | 584 | } |
332 | 585 | ||
333 | int inet_dump_fib(struct sk_buff *skb, struct netlink_callback *cb) | 586 | int inet_dump_fib(struct sk_buff *skb, struct netlink_callback *cb) |
334 | { | 587 | { |
335 | int t; | 588 | unsigned int h, s_h; |
336 | int s_t; | 589 | unsigned int e = 0, s_e; |
337 | struct fib_table *tb; | 590 | struct fib_table *tb; |
591 | struct hlist_node *node; | ||
592 | int dumped = 0; | ||
338 | 593 | ||
339 | if (NLMSG_PAYLOAD(cb->nlh, 0) >= sizeof(struct rtmsg) && | 594 | if (nlmsg_len(cb->nlh) >= sizeof(struct rtmsg) && |
340 | ((struct rtmsg*)NLMSG_DATA(cb->nlh))->rtm_flags&RTM_F_CLONED) | 595 | ((struct rtmsg *) nlmsg_data(cb->nlh))->rtm_flags & RTM_F_CLONED) |
341 | return ip_rt_dump(skb, cb); | 596 | return ip_rt_dump(skb, cb); |
342 | 597 | ||
343 | s_t = cb->args[0]; | 598 | s_h = cb->args[0]; |
344 | if (s_t == 0) | 599 | s_e = cb->args[1]; |
345 | s_t = cb->args[0] = RT_TABLE_MIN; | 600 | |
346 | 601 | for (h = s_h; h < FIB_TABLE_HASHSZ; h++, s_e = 0) { | |
347 | for (t=s_t; t<=RT_TABLE_MAX; t++) { | 602 | e = 0; |
348 | if (t < s_t) continue; | 603 | hlist_for_each_entry(tb, node, &fib_table_hash[h], tb_hlist) { |
349 | if (t > s_t) | 604 | if (e < s_e) |
350 | memset(&cb->args[1], 0, sizeof(cb->args)-sizeof(cb->args[0])); | 605 | goto next; |
351 | if ((tb = fib_get_table(t))==NULL) | 606 | if (dumped) |
352 | continue; | 607 | memset(&cb->args[2], 0, sizeof(cb->args) - |
353 | if (tb->tb_dump(tb, skb, cb) < 0) | 608 | 2 * sizeof(cb->args[0])); |
354 | break; | 609 | if (tb->tb_dump(tb, skb, cb) < 0) |
610 | goto out; | ||
611 | dumped = 1; | ||
612 | next: | ||
613 | e++; | ||
614 | } | ||
355 | } | 615 | } |
356 | 616 | out: | |
357 | cb->args[0] = t; | 617 | cb->args[1] = e; |
618 | cb->args[0] = h; | ||
358 | 619 | ||
359 | return skb->len; | 620 | return skb->len; |
360 | } | 621 | } |
@@ -366,17 +627,19 @@ int inet_dump_fib(struct sk_buff *skb, struct netlink_callback *cb) | |||
366 | only when netlink is already locked. | 627 | only when netlink is already locked. |
367 | */ | 628 | */ |
368 | 629 | ||
369 | static void fib_magic(int cmd, int type, u32 dst, int dst_len, struct in_ifaddr *ifa) | 630 | static void fib_magic(int cmd, int type, u32 dst, int dst_len, |
631 | struct in_ifaddr *ifa) | ||
370 | { | 632 | { |
371 | struct fib_table * tb; | 633 | struct fib_table *tb; |
372 | struct { | 634 | struct fib_config cfg = { |
373 | struct nlmsghdr nlh; | 635 | .fc_protocol = RTPROT_KERNEL, |
374 | struct rtmsg rtm; | 636 | .fc_type = type, |
375 | } req; | 637 | .fc_dst = dst, |
376 | struct kern_rta rta; | 638 | .fc_dst_len = dst_len, |
377 | 639 | .fc_prefsrc = ifa->ifa_local, | |
378 | memset(&req.rtm, 0, sizeof(req.rtm)); | 640 | .fc_oif = ifa->ifa_dev->dev->ifindex, |
379 | memset(&rta, 0, sizeof(rta)); | 641 | .fc_nlflags = NLM_F_CREATE | NLM_F_APPEND, |
642 | }; | ||
380 | 643 | ||
381 | if (type == RTN_UNICAST) | 644 | if (type == RTN_UNICAST) |
382 | tb = fib_new_table(RT_TABLE_MAIN); | 645 | tb = fib_new_table(RT_TABLE_MAIN); |
@@ -386,26 +649,17 @@ static void fib_magic(int cmd, int type, u32 dst, int dst_len, struct in_ifaddr | |||
386 | if (tb == NULL) | 649 | if (tb == NULL) |
387 | return; | 650 | return; |
388 | 651 | ||
389 | req.nlh.nlmsg_len = sizeof(req); | 652 | cfg.fc_table = tb->tb_id; |
390 | req.nlh.nlmsg_type = cmd; | ||
391 | req.nlh.nlmsg_flags = NLM_F_REQUEST|NLM_F_CREATE|NLM_F_APPEND; | ||
392 | req.nlh.nlmsg_pid = 0; | ||
393 | req.nlh.nlmsg_seq = 0; | ||
394 | 653 | ||
395 | req.rtm.rtm_dst_len = dst_len; | 654 | if (type != RTN_LOCAL) |
396 | req.rtm.rtm_table = tb->tb_id; | 655 | cfg.fc_scope = RT_SCOPE_LINK; |
397 | req.rtm.rtm_protocol = RTPROT_KERNEL; | 656 | else |
398 | req.rtm.rtm_scope = (type != RTN_LOCAL ? RT_SCOPE_LINK : RT_SCOPE_HOST); | 657 | cfg.fc_scope = RT_SCOPE_HOST; |
399 | req.rtm.rtm_type = type; | ||
400 | |||
401 | rta.rta_dst = &dst; | ||
402 | rta.rta_prefsrc = &ifa->ifa_local; | ||
403 | rta.rta_oif = &ifa->ifa_dev->dev->ifindex; | ||
404 | 658 | ||
405 | if (cmd == RTM_NEWROUTE) | 659 | if (cmd == RTM_NEWROUTE) |
406 | tb->tb_insert(tb, &req.rtm, &rta, &req.nlh, NULL); | 660 | tb->tb_insert(tb, &cfg); |
407 | else | 661 | else |
408 | tb->tb_delete(tb, &req.rtm, &rta, &req.nlh, NULL); | 662 | tb->tb_delete(tb, &cfg); |
409 | } | 663 | } |
410 | 664 | ||
411 | void fib_add_ifaddr(struct in_ifaddr *ifa) | 665 | void fib_add_ifaddr(struct in_ifaddr *ifa) |
@@ -652,11 +906,17 @@ static struct notifier_block fib_netdev_notifier = { | |||
652 | 906 | ||
653 | void __init ip_fib_init(void) | 907 | void __init ip_fib_init(void) |
654 | { | 908 | { |
909 | unsigned int i; | ||
910 | |||
911 | for (i = 0; i < FIB_TABLE_HASHSZ; i++) | ||
912 | INIT_HLIST_HEAD(&fib_table_hash[i]); | ||
655 | #ifndef CONFIG_IP_MULTIPLE_TABLES | 913 | #ifndef CONFIG_IP_MULTIPLE_TABLES |
656 | ip_fib_local_table = fib_hash_init(RT_TABLE_LOCAL); | 914 | ip_fib_local_table = fib_hash_init(RT_TABLE_LOCAL); |
915 | hlist_add_head_rcu(&ip_fib_local_table->tb_hlist, &fib_table_hash[0]); | ||
657 | ip_fib_main_table = fib_hash_init(RT_TABLE_MAIN); | 916 | ip_fib_main_table = fib_hash_init(RT_TABLE_MAIN); |
917 | hlist_add_head_rcu(&ip_fib_main_table->tb_hlist, &fib_table_hash[0]); | ||
658 | #else | 918 | #else |
659 | fib_rules_init(); | 919 | fib4_rules_init(); |
660 | #endif | 920 | #endif |
661 | 921 | ||
662 | register_netdevice_notifier(&fib_netdev_notifier); | 922 | register_netdevice_notifier(&fib_netdev_notifier); |
diff --git a/net/ipv4/fib_hash.c b/net/ipv4/fib_hash.c index 72c633b357cf..88133b383dc5 100644 --- a/net/ipv4/fib_hash.c +++ b/net/ipv4/fib_hash.c | |||
@@ -379,42 +379,39 @@ static struct fib_node *fib_find_node(struct fn_zone *fz, u32 key) | |||
379 | return NULL; | 379 | return NULL; |
380 | } | 380 | } |
381 | 381 | ||
382 | static int | 382 | static int fn_hash_insert(struct fib_table *tb, struct fib_config *cfg) |
383 | fn_hash_insert(struct fib_table *tb, struct rtmsg *r, struct kern_rta *rta, | ||
384 | struct nlmsghdr *n, struct netlink_skb_parms *req) | ||
385 | { | 383 | { |
386 | struct fn_hash *table = (struct fn_hash *) tb->tb_data; | 384 | struct fn_hash *table = (struct fn_hash *) tb->tb_data; |
387 | struct fib_node *new_f, *f; | 385 | struct fib_node *new_f, *f; |
388 | struct fib_alias *fa, *new_fa; | 386 | struct fib_alias *fa, *new_fa; |
389 | struct fn_zone *fz; | 387 | struct fn_zone *fz; |
390 | struct fib_info *fi; | 388 | struct fib_info *fi; |
391 | int z = r->rtm_dst_len; | 389 | u8 tos = cfg->fc_tos; |
392 | int type = r->rtm_type; | ||
393 | u8 tos = r->rtm_tos; | ||
394 | u32 key; | 390 | u32 key; |
395 | int err; | 391 | int err; |
396 | 392 | ||
397 | if (z > 32) | 393 | if (cfg->fc_dst_len > 32) |
398 | return -EINVAL; | 394 | return -EINVAL; |
399 | fz = table->fn_zones[z]; | 395 | |
400 | if (!fz && !(fz = fn_new_zone(table, z))) | 396 | fz = table->fn_zones[cfg->fc_dst_len]; |
397 | if (!fz && !(fz = fn_new_zone(table, cfg->fc_dst_len))) | ||
401 | return -ENOBUFS; | 398 | return -ENOBUFS; |
402 | 399 | ||
403 | key = 0; | 400 | key = 0; |
404 | if (rta->rta_dst) { | 401 | if (cfg->fc_dst) { |
405 | u32 dst; | 402 | if (cfg->fc_dst & ~FZ_MASK(fz)) |
406 | memcpy(&dst, rta->rta_dst, 4); | ||
407 | if (dst & ~FZ_MASK(fz)) | ||
408 | return -EINVAL; | 403 | return -EINVAL; |
409 | key = fz_key(dst, fz); | 404 | key = fz_key(cfg->fc_dst, fz); |
410 | } | 405 | } |
411 | 406 | ||
412 | if ((fi = fib_create_info(r, rta, n, &err)) == NULL) | 407 | fi = fib_create_info(cfg); |
413 | return err; | 408 | if (IS_ERR(fi)) |
409 | return PTR_ERR(fi); | ||
414 | 410 | ||
415 | if (fz->fz_nent > (fz->fz_divisor<<1) && | 411 | if (fz->fz_nent > (fz->fz_divisor<<1) && |
416 | fz->fz_divisor < FZ_MAX_DIVISOR && | 412 | fz->fz_divisor < FZ_MAX_DIVISOR && |
417 | (z==32 || (1<<z) > fz->fz_divisor)) | 413 | (cfg->fc_dst_len == 32 || |
414 | (1 << cfg->fc_dst_len) > fz->fz_divisor)) | ||
418 | fn_rehash_zone(fz); | 415 | fn_rehash_zone(fz); |
419 | 416 | ||
420 | f = fib_find_node(fz, key); | 417 | f = fib_find_node(fz, key); |
@@ -440,18 +437,18 @@ fn_hash_insert(struct fib_table *tb, struct rtmsg *r, struct kern_rta *rta, | |||
440 | struct fib_alias *fa_orig; | 437 | struct fib_alias *fa_orig; |
441 | 438 | ||
442 | err = -EEXIST; | 439 | err = -EEXIST; |
443 | if (n->nlmsg_flags & NLM_F_EXCL) | 440 | if (cfg->fc_nlflags & NLM_F_EXCL) |
444 | goto out; | 441 | goto out; |
445 | 442 | ||
446 | if (n->nlmsg_flags & NLM_F_REPLACE) { | 443 | if (cfg->fc_nlflags & NLM_F_REPLACE) { |
447 | struct fib_info *fi_drop; | 444 | struct fib_info *fi_drop; |
448 | u8 state; | 445 | u8 state; |
449 | 446 | ||
450 | write_lock_bh(&fib_hash_lock); | 447 | write_lock_bh(&fib_hash_lock); |
451 | fi_drop = fa->fa_info; | 448 | fi_drop = fa->fa_info; |
452 | fa->fa_info = fi; | 449 | fa->fa_info = fi; |
453 | fa->fa_type = type; | 450 | fa->fa_type = cfg->fc_type; |
454 | fa->fa_scope = r->rtm_scope; | 451 | fa->fa_scope = cfg->fc_scope; |
455 | state = fa->fa_state; | 452 | state = fa->fa_state; |
456 | fa->fa_state &= ~FA_S_ACCESSED; | 453 | fa->fa_state &= ~FA_S_ACCESSED; |
457 | fib_hash_genid++; | 454 | fib_hash_genid++; |
@@ -474,17 +471,17 @@ fn_hash_insert(struct fib_table *tb, struct rtmsg *r, struct kern_rta *rta, | |||
474 | break; | 471 | break; |
475 | if (fa->fa_info->fib_priority != fi->fib_priority) | 472 | if (fa->fa_info->fib_priority != fi->fib_priority) |
476 | break; | 473 | break; |
477 | if (fa->fa_type == type && | 474 | if (fa->fa_type == cfg->fc_type && |
478 | fa->fa_scope == r->rtm_scope && | 475 | fa->fa_scope == cfg->fc_scope && |
479 | fa->fa_info == fi) | 476 | fa->fa_info == fi) |
480 | goto out; | 477 | goto out; |
481 | } | 478 | } |
482 | if (!(n->nlmsg_flags & NLM_F_APPEND)) | 479 | if (!(cfg->fc_nlflags & NLM_F_APPEND)) |
483 | fa = fa_orig; | 480 | fa = fa_orig; |
484 | } | 481 | } |
485 | 482 | ||
486 | err = -ENOENT; | 483 | err = -ENOENT; |
487 | if (!(n->nlmsg_flags&NLM_F_CREATE)) | 484 | if (!(cfg->fc_nlflags & NLM_F_CREATE)) |
488 | goto out; | 485 | goto out; |
489 | 486 | ||
490 | err = -ENOBUFS; | 487 | err = -ENOBUFS; |
@@ -506,8 +503,8 @@ fn_hash_insert(struct fib_table *tb, struct rtmsg *r, struct kern_rta *rta, | |||
506 | 503 | ||
507 | new_fa->fa_info = fi; | 504 | new_fa->fa_info = fi; |
508 | new_fa->fa_tos = tos; | 505 | new_fa->fa_tos = tos; |
509 | new_fa->fa_type = type; | 506 | new_fa->fa_type = cfg->fc_type; |
510 | new_fa->fa_scope = r->rtm_scope; | 507 | new_fa->fa_scope = cfg->fc_scope; |
511 | new_fa->fa_state = 0; | 508 | new_fa->fa_state = 0; |
512 | 509 | ||
513 | /* | 510 | /* |
@@ -526,7 +523,8 @@ fn_hash_insert(struct fib_table *tb, struct rtmsg *r, struct kern_rta *rta, | |||
526 | fz->fz_nent++; | 523 | fz->fz_nent++; |
527 | rt_cache_flush(-1); | 524 | rt_cache_flush(-1); |
528 | 525 | ||
529 | rtmsg_fib(RTM_NEWROUTE, key, new_fa, z, tb->tb_id, n, req); | 526 | rtmsg_fib(RTM_NEWROUTE, key, new_fa, cfg->fc_dst_len, tb->tb_id, |
527 | &cfg->fc_nlinfo); | ||
530 | return 0; | 528 | return 0; |
531 | 529 | ||
532 | out_free_new_fa: | 530 | out_free_new_fa: |
@@ -537,30 +535,25 @@ out: | |||
537 | } | 535 | } |
538 | 536 | ||
539 | 537 | ||
540 | static int | 538 | static int fn_hash_delete(struct fib_table *tb, struct fib_config *cfg) |
541 | fn_hash_delete(struct fib_table *tb, struct rtmsg *r, struct kern_rta *rta, | ||
542 | struct nlmsghdr *n, struct netlink_skb_parms *req) | ||
543 | { | 539 | { |
544 | struct fn_hash *table = (struct fn_hash*)tb->tb_data; | 540 | struct fn_hash *table = (struct fn_hash*)tb->tb_data; |
545 | struct fib_node *f; | 541 | struct fib_node *f; |
546 | struct fib_alias *fa, *fa_to_delete; | 542 | struct fib_alias *fa, *fa_to_delete; |
547 | int z = r->rtm_dst_len; | ||
548 | struct fn_zone *fz; | 543 | struct fn_zone *fz; |
549 | u32 key; | 544 | u32 key; |
550 | u8 tos = r->rtm_tos; | ||
551 | 545 | ||
552 | if (z > 32) | 546 | if (cfg->fc_dst_len > 32) |
553 | return -EINVAL; | 547 | return -EINVAL; |
554 | if ((fz = table->fn_zones[z]) == NULL) | 548 | |
549 | if ((fz = table->fn_zones[cfg->fc_dst_len]) == NULL) | ||
555 | return -ESRCH; | 550 | return -ESRCH; |
556 | 551 | ||
557 | key = 0; | 552 | key = 0; |
558 | if (rta->rta_dst) { | 553 | if (cfg->fc_dst) { |
559 | u32 dst; | 554 | if (cfg->fc_dst & ~FZ_MASK(fz)) |
560 | memcpy(&dst, rta->rta_dst, 4); | ||
561 | if (dst & ~FZ_MASK(fz)) | ||
562 | return -EINVAL; | 555 | return -EINVAL; |
563 | key = fz_key(dst, fz); | 556 | key = fz_key(cfg->fc_dst, fz); |
564 | } | 557 | } |
565 | 558 | ||
566 | f = fib_find_node(fz, key); | 559 | f = fib_find_node(fz, key); |
@@ -568,7 +561,7 @@ fn_hash_delete(struct fib_table *tb, struct rtmsg *r, struct kern_rta *rta, | |||
568 | if (!f) | 561 | if (!f) |
569 | fa = NULL; | 562 | fa = NULL; |
570 | else | 563 | else |
571 | fa = fib_find_alias(&f->fn_alias, tos, 0); | 564 | fa = fib_find_alias(&f->fn_alias, cfg->fc_tos, 0); |
572 | if (!fa) | 565 | if (!fa) |
573 | return -ESRCH; | 566 | return -ESRCH; |
574 | 567 | ||
@@ -577,16 +570,16 @@ fn_hash_delete(struct fib_table *tb, struct rtmsg *r, struct kern_rta *rta, | |||
577 | list_for_each_entry_continue(fa, &f->fn_alias, fa_list) { | 570 | list_for_each_entry_continue(fa, &f->fn_alias, fa_list) { |
578 | struct fib_info *fi = fa->fa_info; | 571 | struct fib_info *fi = fa->fa_info; |
579 | 572 | ||
580 | if (fa->fa_tos != tos) | 573 | if (fa->fa_tos != cfg->fc_tos) |
581 | break; | 574 | break; |
582 | 575 | ||
583 | if ((!r->rtm_type || | 576 | if ((!cfg->fc_type || |
584 | fa->fa_type == r->rtm_type) && | 577 | fa->fa_type == cfg->fc_type) && |
585 | (r->rtm_scope == RT_SCOPE_NOWHERE || | 578 | (cfg->fc_scope == RT_SCOPE_NOWHERE || |
586 | fa->fa_scope == r->rtm_scope) && | 579 | fa->fa_scope == cfg->fc_scope) && |
587 | (!r->rtm_protocol || | 580 | (!cfg->fc_protocol || |
588 | fi->fib_protocol == r->rtm_protocol) && | 581 | fi->fib_protocol == cfg->fc_protocol) && |
589 | fib_nh_match(r, n, rta, fi) == 0) { | 582 | fib_nh_match(cfg, fi) == 0) { |
590 | fa_to_delete = fa; | 583 | fa_to_delete = fa; |
591 | break; | 584 | break; |
592 | } | 585 | } |
@@ -596,7 +589,8 @@ fn_hash_delete(struct fib_table *tb, struct rtmsg *r, struct kern_rta *rta, | |||
596 | int kill_fn; | 589 | int kill_fn; |
597 | 590 | ||
598 | fa = fa_to_delete; | 591 | fa = fa_to_delete; |
599 | rtmsg_fib(RTM_DELROUTE, key, fa, z, tb->tb_id, n, req); | 592 | rtmsg_fib(RTM_DELROUTE, key, fa, cfg->fc_dst_len, |
593 | tb->tb_id, &cfg->fc_nlinfo); | ||
600 | 594 | ||
601 | kill_fn = 0; | 595 | kill_fn = 0; |
602 | write_lock_bh(&fib_hash_lock); | 596 | write_lock_bh(&fib_hash_lock); |
@@ -684,7 +678,7 @@ fn_hash_dump_bucket(struct sk_buff *skb, struct netlink_callback *cb, | |||
684 | struct fib_node *f; | 678 | struct fib_node *f; |
685 | int i, s_i; | 679 | int i, s_i; |
686 | 680 | ||
687 | s_i = cb->args[3]; | 681 | s_i = cb->args[4]; |
688 | i = 0; | 682 | i = 0; |
689 | hlist_for_each_entry(f, node, head, fn_hash) { | 683 | hlist_for_each_entry(f, node, head, fn_hash) { |
690 | struct fib_alias *fa; | 684 | struct fib_alias *fa; |
@@ -699,19 +693,19 @@ fn_hash_dump_bucket(struct sk_buff *skb, struct netlink_callback *cb, | |||
699 | tb->tb_id, | 693 | tb->tb_id, |
700 | fa->fa_type, | 694 | fa->fa_type, |
701 | fa->fa_scope, | 695 | fa->fa_scope, |
702 | &f->fn_key, | 696 | f->fn_key, |
703 | fz->fz_order, | 697 | fz->fz_order, |
704 | fa->fa_tos, | 698 | fa->fa_tos, |
705 | fa->fa_info, | 699 | fa->fa_info, |
706 | NLM_F_MULTI) < 0) { | 700 | NLM_F_MULTI) < 0) { |
707 | cb->args[3] = i; | 701 | cb->args[4] = i; |
708 | return -1; | 702 | return -1; |
709 | } | 703 | } |
710 | next: | 704 | next: |
711 | i++; | 705 | i++; |
712 | } | 706 | } |
713 | } | 707 | } |
714 | cb->args[3] = i; | 708 | cb->args[4] = i; |
715 | return skb->len; | 709 | return skb->len; |
716 | } | 710 | } |
717 | 711 | ||
@@ -722,21 +716,21 @@ fn_hash_dump_zone(struct sk_buff *skb, struct netlink_callback *cb, | |||
722 | { | 716 | { |
723 | int h, s_h; | 717 | int h, s_h; |
724 | 718 | ||
725 | s_h = cb->args[2]; | 719 | s_h = cb->args[3]; |
726 | for (h=0; h < fz->fz_divisor; h++) { | 720 | for (h=0; h < fz->fz_divisor; h++) { |
727 | if (h < s_h) continue; | 721 | if (h < s_h) continue; |
728 | if (h > s_h) | 722 | if (h > s_h) |
729 | memset(&cb->args[3], 0, | 723 | memset(&cb->args[4], 0, |
730 | sizeof(cb->args) - 3*sizeof(cb->args[0])); | 724 | sizeof(cb->args) - 4*sizeof(cb->args[0])); |
731 | if (fz->fz_hash == NULL || | 725 | if (fz->fz_hash == NULL || |
732 | hlist_empty(&fz->fz_hash[h])) | 726 | hlist_empty(&fz->fz_hash[h])) |
733 | continue; | 727 | continue; |
734 | if (fn_hash_dump_bucket(skb, cb, tb, fz, &fz->fz_hash[h])<0) { | 728 | if (fn_hash_dump_bucket(skb, cb, tb, fz, &fz->fz_hash[h])<0) { |
735 | cb->args[2] = h; | 729 | cb->args[3] = h; |
736 | return -1; | 730 | return -1; |
737 | } | 731 | } |
738 | } | 732 | } |
739 | cb->args[2] = h; | 733 | cb->args[3] = h; |
740 | return skb->len; | 734 | return skb->len; |
741 | } | 735 | } |
742 | 736 | ||
@@ -746,28 +740,28 @@ static int fn_hash_dump(struct fib_table *tb, struct sk_buff *skb, struct netlin | |||
746 | struct fn_zone *fz; | 740 | struct fn_zone *fz; |
747 | struct fn_hash *table = (struct fn_hash*)tb->tb_data; | 741 | struct fn_hash *table = (struct fn_hash*)tb->tb_data; |
748 | 742 | ||
749 | s_m = cb->args[1]; | 743 | s_m = cb->args[2]; |
750 | read_lock(&fib_hash_lock); | 744 | read_lock(&fib_hash_lock); |
751 | for (fz = table->fn_zone_list, m=0; fz; fz = fz->fz_next, m++) { | 745 | for (fz = table->fn_zone_list, m=0; fz; fz = fz->fz_next, m++) { |
752 | if (m < s_m) continue; | 746 | if (m < s_m) continue; |
753 | if (m > s_m) | 747 | if (m > s_m) |
754 | memset(&cb->args[2], 0, | 748 | memset(&cb->args[3], 0, |
755 | sizeof(cb->args) - 2*sizeof(cb->args[0])); | 749 | sizeof(cb->args) - 3*sizeof(cb->args[0])); |
756 | if (fn_hash_dump_zone(skb, cb, tb, fz) < 0) { | 750 | if (fn_hash_dump_zone(skb, cb, tb, fz) < 0) { |
757 | cb->args[1] = m; | 751 | cb->args[2] = m; |
758 | read_unlock(&fib_hash_lock); | 752 | read_unlock(&fib_hash_lock); |
759 | return -1; | 753 | return -1; |
760 | } | 754 | } |
761 | } | 755 | } |
762 | read_unlock(&fib_hash_lock); | 756 | read_unlock(&fib_hash_lock); |
763 | cb->args[1] = m; | 757 | cb->args[2] = m; |
764 | return skb->len; | 758 | return skb->len; |
765 | } | 759 | } |
766 | 760 | ||
767 | #ifdef CONFIG_IP_MULTIPLE_TABLES | 761 | #ifdef CONFIG_IP_MULTIPLE_TABLES |
768 | struct fib_table * fib_hash_init(int id) | 762 | struct fib_table * fib_hash_init(u32 id) |
769 | #else | 763 | #else |
770 | struct fib_table * __init fib_hash_init(int id) | 764 | struct fib_table * __init fib_hash_init(u32 id) |
771 | #endif | 765 | #endif |
772 | { | 766 | { |
773 | struct fib_table *tb; | 767 | struct fib_table *tb; |
diff --git a/net/ipv4/fib_lookup.h b/net/ipv4/fib_lookup.h index ef6609ea0eb7..fd6f7769f8ab 100644 --- a/net/ipv4/fib_lookup.h +++ b/net/ipv4/fib_lookup.h | |||
@@ -23,19 +23,14 @@ extern int fib_semantic_match(struct list_head *head, | |||
23 | struct fib_result *res, __u32 zone, __u32 mask, | 23 | struct fib_result *res, __u32 zone, __u32 mask, |
24 | int prefixlen); | 24 | int prefixlen); |
25 | extern void fib_release_info(struct fib_info *); | 25 | extern void fib_release_info(struct fib_info *); |
26 | extern struct fib_info *fib_create_info(const struct rtmsg *r, | 26 | extern struct fib_info *fib_create_info(struct fib_config *cfg); |
27 | struct kern_rta *rta, | 27 | extern int fib_nh_match(struct fib_config *cfg, struct fib_info *fi); |
28 | const struct nlmsghdr *, | ||
29 | int *err); | ||
30 | extern int fib_nh_match(struct rtmsg *r, struct nlmsghdr *, | ||
31 | struct kern_rta *rta, struct fib_info *fi); | ||
32 | extern int fib_dump_info(struct sk_buff *skb, u32 pid, u32 seq, int event, | 28 | extern int fib_dump_info(struct sk_buff *skb, u32 pid, u32 seq, int event, |
33 | u8 tb_id, u8 type, u8 scope, void *dst, | 29 | u32 tb_id, u8 type, u8 scope, u32 dst, |
34 | int dst_len, u8 tos, struct fib_info *fi, | 30 | int dst_len, u8 tos, struct fib_info *fi, |
35 | unsigned int); | 31 | unsigned int); |
36 | extern void rtmsg_fib(int event, u32 key, struct fib_alias *fa, | 32 | extern void rtmsg_fib(int event, u32 key, struct fib_alias *fa, |
37 | int z, int tb_id, | 33 | int dst_len, u32 tb_id, struct nl_info *info); |
38 | struct nlmsghdr *n, struct netlink_skb_parms *req); | ||
39 | extern struct fib_alias *fib_find_alias(struct list_head *fah, | 34 | extern struct fib_alias *fib_find_alias(struct list_head *fah, |
40 | u8 tos, u32 prio); | 35 | u8 tos, u32 prio); |
41 | extern int fib_detect_death(struct fib_info *fi, int order, | 36 | extern int fib_detect_death(struct fib_info *fi, int order, |
diff --git a/net/ipv4/fib_rules.c b/net/ipv4/fib_rules.c index 79b04718bdfd..52b2adae4f22 100644 --- a/net/ipv4/fib_rules.c +++ b/net/ipv4/fib_rules.c | |||
@@ -5,9 +5,8 @@ | |||
5 | * | 5 | * |
6 | * IPv4 Forwarding Information Base: policy rules. | 6 | * IPv4 Forwarding Information Base: policy rules. |
7 | * | 7 | * |
8 | * Version: $Id: fib_rules.c,v 1.17 2001/10/31 21:55:54 davem Exp $ | ||
9 | * | ||
10 | * Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru> | 8 | * Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru> |
9 | * Thomas Graf <tgraf@suug.ch> | ||
11 | * | 10 | * |
12 | * This program is free software; you can redistribute it and/or | 11 | * This program is free software; you can redistribute it and/or |
13 | * modify it under the terms of the GNU General Public License | 12 | * modify it under the terms of the GNU General Public License |
@@ -19,463 +18,350 @@ | |||
19 | * Marc Boucher : routing by fwmark | 18 | * Marc Boucher : routing by fwmark |
20 | */ | 19 | */ |
21 | 20 | ||
22 | #include <asm/uaccess.h> | ||
23 | #include <asm/system.h> | ||
24 | #include <linux/bitops.h> | ||
25 | #include <linux/types.h> | 21 | #include <linux/types.h> |
26 | #include <linux/kernel.h> | 22 | #include <linux/kernel.h> |
27 | #include <linux/sched.h> | ||
28 | #include <linux/mm.h> | ||
29 | #include <linux/string.h> | ||
30 | #include <linux/socket.h> | ||
31 | #include <linux/sockios.h> | ||
32 | #include <linux/errno.h> | ||
33 | #include <linux/in.h> | ||
34 | #include <linux/inet.h> | ||
35 | #include <linux/inetdevice.h> | ||
36 | #include <linux/netdevice.h> | 23 | #include <linux/netdevice.h> |
37 | #include <linux/if_arp.h> | ||
38 | #include <linux/proc_fs.h> | ||
39 | #include <linux/skbuff.h> | ||
40 | #include <linux/netlink.h> | 24 | #include <linux/netlink.h> |
25 | #include <linux/inetdevice.h> | ||
41 | #include <linux/init.h> | 26 | #include <linux/init.h> |
42 | #include <linux/list.h> | 27 | #include <linux/list.h> |
43 | #include <linux/rcupdate.h> | 28 | #include <linux/rcupdate.h> |
44 | |||
45 | #include <net/ip.h> | 29 | #include <net/ip.h> |
46 | #include <net/protocol.h> | ||
47 | #include <net/route.h> | 30 | #include <net/route.h> |
48 | #include <net/tcp.h> | 31 | #include <net/tcp.h> |
49 | #include <net/sock.h> | ||
50 | #include <net/ip_fib.h> | 32 | #include <net/ip_fib.h> |
33 | #include <net/fib_rules.h> | ||
51 | 34 | ||
52 | #define FRprintk(a...) | 35 | static struct fib_rules_ops fib4_rules_ops; |
53 | 36 | ||
54 | struct fib_rule | 37 | struct fib4_rule |
55 | { | 38 | { |
56 | struct hlist_node hlist; | 39 | struct fib_rule common; |
57 | atomic_t r_clntref; | 40 | u8 dst_len; |
58 | u32 r_preference; | 41 | u8 src_len; |
59 | unsigned char r_table; | 42 | u8 tos; |
60 | unsigned char r_action; | 43 | u32 src; |
61 | unsigned char r_dst_len; | 44 | u32 srcmask; |
62 | unsigned char r_src_len; | 45 | u32 dst; |
63 | u32 r_src; | 46 | u32 dstmask; |
64 | u32 r_srcmask; | ||
65 | u32 r_dst; | ||
66 | u32 r_dstmask; | ||
67 | u32 r_srcmap; | ||
68 | u8 r_flags; | ||
69 | u8 r_tos; | ||
70 | #ifdef CONFIG_IP_ROUTE_FWMARK | 47 | #ifdef CONFIG_IP_ROUTE_FWMARK |
71 | u32 r_fwmark; | 48 | u32 fwmark; |
49 | u32 fwmask; | ||
72 | #endif | 50 | #endif |
73 | int r_ifindex; | ||
74 | #ifdef CONFIG_NET_CLS_ROUTE | 51 | #ifdef CONFIG_NET_CLS_ROUTE |
75 | __u32 r_tclassid; | 52 | u32 tclassid; |
76 | #endif | 53 | #endif |
77 | char r_ifname[IFNAMSIZ]; | ||
78 | int r_dead; | ||
79 | struct rcu_head rcu; | ||
80 | }; | 54 | }; |
81 | 55 | ||
82 | static struct fib_rule default_rule = { | 56 | static struct fib4_rule default_rule = { |
83 | .r_clntref = ATOMIC_INIT(2), | 57 | .common = { |
84 | .r_preference = 0x7FFF, | 58 | .refcnt = ATOMIC_INIT(2), |
85 | .r_table = RT_TABLE_DEFAULT, | 59 | .pref = 0x7FFF, |
86 | .r_action = RTN_UNICAST, | 60 | .table = RT_TABLE_DEFAULT, |
61 | .action = FR_ACT_TO_TBL, | ||
62 | }, | ||
87 | }; | 63 | }; |
88 | 64 | ||
89 | static struct fib_rule main_rule = { | 65 | static struct fib4_rule main_rule = { |
90 | .r_clntref = ATOMIC_INIT(2), | 66 | .common = { |
91 | .r_preference = 0x7FFE, | 67 | .refcnt = ATOMIC_INIT(2), |
92 | .r_table = RT_TABLE_MAIN, | 68 | .pref = 0x7FFE, |
93 | .r_action = RTN_UNICAST, | 69 | .table = RT_TABLE_MAIN, |
70 | .action = FR_ACT_TO_TBL, | ||
71 | }, | ||
94 | }; | 72 | }; |
95 | 73 | ||
96 | static struct fib_rule local_rule = { | 74 | static struct fib4_rule local_rule = { |
97 | .r_clntref = ATOMIC_INIT(2), | 75 | .common = { |
98 | .r_table = RT_TABLE_LOCAL, | 76 | .refcnt = ATOMIC_INIT(2), |
99 | .r_action = RTN_UNICAST, | 77 | .table = RT_TABLE_LOCAL, |
78 | .action = FR_ACT_TO_TBL, | ||
79 | .flags = FIB_RULE_PERMANENT, | ||
80 | }, | ||
100 | }; | 81 | }; |
101 | 82 | ||
102 | static struct hlist_head fib_rules; | 83 | static LIST_HEAD(fib4_rules); |
103 | 84 | ||
104 | /* writer func called from netlink -- rtnl_sem hold*/ | 85 | #ifdef CONFIG_NET_CLS_ROUTE |
105 | 86 | u32 fib_rules_tclass(struct fib_result *res) | |
106 | static void rtmsg_rule(int, struct fib_rule *); | ||
107 | |||
108 | int inet_rtm_delrule(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg) | ||
109 | { | 87 | { |
110 | struct rtattr **rta = arg; | 88 | return res->r ? ((struct fib4_rule *) res->r)->tclassid : 0; |
111 | struct rtmsg *rtm = NLMSG_DATA(nlh); | ||
112 | struct fib_rule *r; | ||
113 | struct hlist_node *node; | ||
114 | int err = -ESRCH; | ||
115 | |||
116 | hlist_for_each_entry(r, node, &fib_rules, hlist) { | ||
117 | if ((!rta[RTA_SRC-1] || memcmp(RTA_DATA(rta[RTA_SRC-1]), &r->r_src, 4) == 0) && | ||
118 | rtm->rtm_src_len == r->r_src_len && | ||
119 | rtm->rtm_dst_len == r->r_dst_len && | ||
120 | (!rta[RTA_DST-1] || memcmp(RTA_DATA(rta[RTA_DST-1]), &r->r_dst, 4) == 0) && | ||
121 | rtm->rtm_tos == r->r_tos && | ||
122 | #ifdef CONFIG_IP_ROUTE_FWMARK | ||
123 | (!rta[RTA_PROTOINFO-1] || memcmp(RTA_DATA(rta[RTA_PROTOINFO-1]), &r->r_fwmark, 4) == 0) && | ||
124 | #endif | ||
125 | (!rtm->rtm_type || rtm->rtm_type == r->r_action) && | ||
126 | (!rta[RTA_PRIORITY-1] || memcmp(RTA_DATA(rta[RTA_PRIORITY-1]), &r->r_preference, 4) == 0) && | ||
127 | (!rta[RTA_IIF-1] || rtattr_strcmp(rta[RTA_IIF-1], r->r_ifname) == 0) && | ||
128 | (!rtm->rtm_table || (r && rtm->rtm_table == r->r_table))) { | ||
129 | err = -EPERM; | ||
130 | if (r == &local_rule) | ||
131 | break; | ||
132 | |||
133 | hlist_del_rcu(&r->hlist); | ||
134 | r->r_dead = 1; | ||
135 | rtmsg_rule(RTM_DELRULE, r); | ||
136 | fib_rule_put(r); | ||
137 | err = 0; | ||
138 | break; | ||
139 | } | ||
140 | } | ||
141 | return err; | ||
142 | } | 89 | } |
90 | #endif | ||
143 | 91 | ||
144 | /* Allocate new unique table id */ | 92 | int fib_lookup(struct flowi *flp, struct fib_result *res) |
145 | |||
146 | static struct fib_table *fib_empty_table(void) | ||
147 | { | 93 | { |
148 | int id; | 94 | struct fib_lookup_arg arg = { |
95 | .result = res, | ||
96 | }; | ||
97 | int err; | ||
149 | 98 | ||
150 | for (id = 1; id <= RT_TABLE_MAX; id++) | 99 | err = fib_rules_lookup(&fib4_rules_ops, flp, 0, &arg); |
151 | if (fib_tables[id] == NULL) | 100 | res->r = arg.rule; |
152 | return __fib_new_table(id); | ||
153 | return NULL; | ||
154 | } | ||
155 | 101 | ||
156 | static inline void fib_rule_put_rcu(struct rcu_head *head) | 102 | return err; |
157 | { | ||
158 | struct fib_rule *r = container_of(head, struct fib_rule, rcu); | ||
159 | kfree(r); | ||
160 | } | 103 | } |
161 | 104 | ||
162 | void fib_rule_put(struct fib_rule *r) | 105 | static int fib4_rule_action(struct fib_rule *rule, struct flowi *flp, |
106 | int flags, struct fib_lookup_arg *arg) | ||
163 | { | 107 | { |
164 | if (atomic_dec_and_test(&r->r_clntref)) { | 108 | int err = -EAGAIN; |
165 | if (r->r_dead) | 109 | struct fib_table *tbl; |
166 | call_rcu(&r->rcu, fib_rule_put_rcu); | 110 | |
167 | else | 111 | switch (rule->action) { |
168 | printk("Freeing alive rule %p\n", r); | 112 | case FR_ACT_TO_TBL: |
113 | break; | ||
114 | |||
115 | case FR_ACT_UNREACHABLE: | ||
116 | err = -ENETUNREACH; | ||
117 | goto errout; | ||
118 | |||
119 | case FR_ACT_PROHIBIT: | ||
120 | err = -EACCES; | ||
121 | goto errout; | ||
122 | |||
123 | case FR_ACT_BLACKHOLE: | ||
124 | default: | ||
125 | err = -EINVAL; | ||
126 | goto errout; | ||
169 | } | 127 | } |
128 | |||
129 | if ((tbl = fib_get_table(rule->table)) == NULL) | ||
130 | goto errout; | ||
131 | |||
132 | err = tbl->tb_lookup(tbl, flp, (struct fib_result *) arg->result); | ||
133 | if (err > 0) | ||
134 | err = -EAGAIN; | ||
135 | errout: | ||
136 | return err; | ||
170 | } | 137 | } |
171 | 138 | ||
172 | /* writer func called from netlink -- rtnl_sem hold*/ | ||
173 | 139 | ||
174 | int inet_rtm_newrule(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg) | 140 | void fib_select_default(const struct flowi *flp, struct fib_result *res) |
175 | { | 141 | { |
176 | struct rtattr **rta = arg; | 142 | if (res->r && res->r->action == FR_ACT_TO_TBL && |
177 | struct rtmsg *rtm = NLMSG_DATA(nlh); | 143 | FIB_RES_GW(*res) && FIB_RES_NH(*res).nh_scope == RT_SCOPE_LINK) { |
178 | struct fib_rule *r, *new_r, *last = NULL; | 144 | struct fib_table *tb; |
179 | struct hlist_node *node = NULL; | 145 | if ((tb = fib_get_table(res->r->table)) != NULL) |
180 | unsigned char table_id; | 146 | tb->tb_select_default(tb, flp, res); |
181 | |||
182 | if (rtm->rtm_src_len > 32 || rtm->rtm_dst_len > 32 || | ||
183 | (rtm->rtm_tos & ~IPTOS_TOS_MASK)) | ||
184 | return -EINVAL; | ||
185 | |||
186 | if (rta[RTA_IIF-1] && RTA_PAYLOAD(rta[RTA_IIF-1]) > IFNAMSIZ) | ||
187 | return -EINVAL; | ||
188 | |||
189 | table_id = rtm->rtm_table; | ||
190 | if (table_id == RT_TABLE_UNSPEC) { | ||
191 | struct fib_table *table; | ||
192 | if (rtm->rtm_type == RTN_UNICAST) { | ||
193 | if ((table = fib_empty_table()) == NULL) | ||
194 | return -ENOBUFS; | ||
195 | table_id = table->tb_id; | ||
196 | } | ||
197 | } | 147 | } |
148 | } | ||
198 | 149 | ||
199 | new_r = kzalloc(sizeof(*new_r), GFP_KERNEL); | 150 | static int fib4_rule_match(struct fib_rule *rule, struct flowi *fl, int flags) |
200 | if (!new_r) | 151 | { |
201 | return -ENOMEM; | 152 | struct fib4_rule *r = (struct fib4_rule *) rule; |
202 | 153 | u32 daddr = fl->fl4_dst; | |
203 | if (rta[RTA_SRC-1]) | 154 | u32 saddr = fl->fl4_src; |
204 | memcpy(&new_r->r_src, RTA_DATA(rta[RTA_SRC-1]), 4); | ||
205 | if (rta[RTA_DST-1]) | ||
206 | memcpy(&new_r->r_dst, RTA_DATA(rta[RTA_DST-1]), 4); | ||
207 | if (rta[RTA_GATEWAY-1]) | ||
208 | memcpy(&new_r->r_srcmap, RTA_DATA(rta[RTA_GATEWAY-1]), 4); | ||
209 | new_r->r_src_len = rtm->rtm_src_len; | ||
210 | new_r->r_dst_len = rtm->rtm_dst_len; | ||
211 | new_r->r_srcmask = inet_make_mask(rtm->rtm_src_len); | ||
212 | new_r->r_dstmask = inet_make_mask(rtm->rtm_dst_len); | ||
213 | new_r->r_tos = rtm->rtm_tos; | ||
214 | #ifdef CONFIG_IP_ROUTE_FWMARK | ||
215 | if (rta[RTA_PROTOINFO-1]) | ||
216 | memcpy(&new_r->r_fwmark, RTA_DATA(rta[RTA_PROTOINFO-1]), 4); | ||
217 | #endif | ||
218 | new_r->r_action = rtm->rtm_type; | ||
219 | new_r->r_flags = rtm->rtm_flags; | ||
220 | if (rta[RTA_PRIORITY-1]) | ||
221 | memcpy(&new_r->r_preference, RTA_DATA(rta[RTA_PRIORITY-1]), 4); | ||
222 | new_r->r_table = table_id; | ||
223 | if (rta[RTA_IIF-1]) { | ||
224 | struct net_device *dev; | ||
225 | rtattr_strlcpy(new_r->r_ifname, rta[RTA_IIF-1], IFNAMSIZ); | ||
226 | new_r->r_ifindex = -1; | ||
227 | dev = __dev_get_by_name(new_r->r_ifname); | ||
228 | if (dev) | ||
229 | new_r->r_ifindex = dev->ifindex; | ||
230 | } | ||
231 | #ifdef CONFIG_NET_CLS_ROUTE | ||
232 | if (rta[RTA_FLOW-1]) | ||
233 | memcpy(&new_r->r_tclassid, RTA_DATA(rta[RTA_FLOW-1]), 4); | ||
234 | #endif | ||
235 | r = container_of(fib_rules.first, struct fib_rule, hlist); | ||
236 | 155 | ||
237 | if (!new_r->r_preference) { | 156 | if (((saddr ^ r->src) & r->srcmask) || |
238 | if (r && r->hlist.next != NULL) { | 157 | ((daddr ^ r->dst) & r->dstmask)) |
239 | r = container_of(r->hlist.next, struct fib_rule, hlist); | 158 | return 0; |
240 | if (r->r_preference) | ||
241 | new_r->r_preference = r->r_preference - 1; | ||
242 | } | ||
243 | } | ||
244 | 159 | ||
245 | hlist_for_each_entry(r, node, &fib_rules, hlist) { | 160 | if (r->tos && (r->tos != fl->fl4_tos)) |
246 | if (r->r_preference > new_r->r_preference) | 161 | return 0; |
247 | break; | ||
248 | last = r; | ||
249 | } | ||
250 | atomic_inc(&new_r->r_clntref); | ||
251 | 162 | ||
252 | if (last) | 163 | #ifdef CONFIG_IP_ROUTE_FWMARK |
253 | hlist_add_after_rcu(&last->hlist, &new_r->hlist); | 164 | if ((r->fwmark ^ fl->fl4_fwmark) & r->fwmask) |
254 | else | 165 | return 0; |
255 | hlist_add_before_rcu(&new_r->hlist, &r->hlist); | 166 | #endif |
256 | 167 | ||
257 | rtmsg_rule(RTM_NEWRULE, new_r); | 168 | return 1; |
258 | return 0; | ||
259 | } | 169 | } |
260 | 170 | ||
261 | #ifdef CONFIG_NET_CLS_ROUTE | 171 | static struct fib_table *fib_empty_table(void) |
262 | u32 fib_rules_tclass(struct fib_result *res) | ||
263 | { | 172 | { |
264 | if (res->r) | 173 | u32 id; |
265 | return res->r->r_tclassid; | 174 | |
266 | return 0; | 175 | for (id = 1; id <= RT_TABLE_MAX; id++) |
176 | if (fib_get_table(id) == NULL) | ||
177 | return fib_new_table(id); | ||
178 | return NULL; | ||
267 | } | 179 | } |
268 | #endif | ||
269 | 180 | ||
270 | /* callers should hold rtnl semaphore */ | 181 | static struct nla_policy fib4_rule_policy[FRA_MAX+1] __read_mostly = { |
182 | [FRA_IFNAME] = { .type = NLA_STRING, .len = IFNAMSIZ - 1 }, | ||
183 | [FRA_PRIORITY] = { .type = NLA_U32 }, | ||
184 | [FRA_SRC] = { .type = NLA_U32 }, | ||
185 | [FRA_DST] = { .type = NLA_U32 }, | ||
186 | [FRA_FWMARK] = { .type = NLA_U32 }, | ||
187 | [FRA_FWMASK] = { .type = NLA_U32 }, | ||
188 | [FRA_FLOW] = { .type = NLA_U32 }, | ||
189 | [FRA_TABLE] = { .type = NLA_U32 }, | ||
190 | }; | ||
271 | 191 | ||
272 | static void fib_rules_detach(struct net_device *dev) | 192 | static int fib4_rule_configure(struct fib_rule *rule, struct sk_buff *skb, |
193 | struct nlmsghdr *nlh, struct fib_rule_hdr *frh, | ||
194 | struct nlattr **tb) | ||
273 | { | 195 | { |
274 | struct hlist_node *node; | 196 | int err = -EINVAL; |
275 | struct fib_rule *r; | 197 | struct fib4_rule *rule4 = (struct fib4_rule *) rule; |
198 | |||
199 | if (frh->src_len > 32 || frh->dst_len > 32 || | ||
200 | (frh->tos & ~IPTOS_TOS_MASK)) | ||
201 | goto errout; | ||
202 | |||
203 | if (rule->table == RT_TABLE_UNSPEC) { | ||
204 | if (rule->action == FR_ACT_TO_TBL) { | ||
205 | struct fib_table *table; | ||
276 | 206 | ||
277 | hlist_for_each_entry(r, node, &fib_rules, hlist) { | 207 | table = fib_empty_table(); |
278 | if (r->r_ifindex == dev->ifindex) | 208 | if (table == NULL) { |
279 | r->r_ifindex = -1; | 209 | err = -ENOBUFS; |
210 | goto errout; | ||
211 | } | ||
280 | 212 | ||
213 | rule->table = table->tb_id; | ||
214 | } | ||
281 | } | 215 | } |
282 | } | ||
283 | 216 | ||
284 | /* callers should hold rtnl semaphore */ | 217 | if (tb[FRA_SRC]) |
218 | rule4->src = nla_get_u32(tb[FRA_SRC]); | ||
285 | 219 | ||
286 | static void fib_rules_attach(struct net_device *dev) | 220 | if (tb[FRA_DST]) |
287 | { | 221 | rule4->dst = nla_get_u32(tb[FRA_DST]); |
288 | struct hlist_node *node; | ||
289 | struct fib_rule *r; | ||
290 | 222 | ||
291 | hlist_for_each_entry(r, node, &fib_rules, hlist) { | 223 | #ifdef CONFIG_IP_ROUTE_FWMARK |
292 | if (r->r_ifindex == -1 && strcmp(dev->name, r->r_ifname) == 0) | 224 | if (tb[FRA_FWMARK]) { |
293 | r->r_ifindex = dev->ifindex; | 225 | rule4->fwmark = nla_get_u32(tb[FRA_FWMARK]); |
226 | if (rule4->fwmark) | ||
227 | /* compatibility: if the mark value is non-zero all bits | ||
228 | * are compared unless a mask is explicitly specified. | ||
229 | */ | ||
230 | rule4->fwmask = 0xFFFFFFFF; | ||
294 | } | 231 | } |
232 | |||
233 | if (tb[FRA_FWMASK]) | ||
234 | rule4->fwmask = nla_get_u32(tb[FRA_FWMASK]); | ||
235 | #endif | ||
236 | |||
237 | #ifdef CONFIG_NET_CLS_ROUTE | ||
238 | if (tb[FRA_FLOW]) | ||
239 | rule4->tclassid = nla_get_u32(tb[FRA_FLOW]); | ||
240 | #endif | ||
241 | |||
242 | rule4->src_len = frh->src_len; | ||
243 | rule4->srcmask = inet_make_mask(rule4->src_len); | ||
244 | rule4->dst_len = frh->dst_len; | ||
245 | rule4->dstmask = inet_make_mask(rule4->dst_len); | ||
246 | rule4->tos = frh->tos; | ||
247 | |||
248 | err = 0; | ||
249 | errout: | ||
250 | return err; | ||
295 | } | 251 | } |
296 | 252 | ||
297 | int fib_lookup(const struct flowi *flp, struct fib_result *res) | 253 | static int fib4_rule_compare(struct fib_rule *rule, struct fib_rule_hdr *frh, |
254 | struct nlattr **tb) | ||
298 | { | 255 | { |
299 | int err; | 256 | struct fib4_rule *rule4 = (struct fib4_rule *) rule; |
300 | struct fib_rule *r, *policy; | ||
301 | struct fib_table *tb; | ||
302 | struct hlist_node *node; | ||
303 | 257 | ||
304 | u32 daddr = flp->fl4_dst; | 258 | if (frh->src_len && (rule4->src_len != frh->src_len)) |
305 | u32 saddr = flp->fl4_src; | 259 | return 0; |
306 | 260 | ||
307 | FRprintk("Lookup: %u.%u.%u.%u <- %u.%u.%u.%u ", | 261 | if (frh->dst_len && (rule4->dst_len != frh->dst_len)) |
308 | NIPQUAD(flp->fl4_dst), NIPQUAD(flp->fl4_src)); | 262 | return 0; |
309 | 263 | ||
310 | rcu_read_lock(); | 264 | if (frh->tos && (rule4->tos != frh->tos)) |
265 | return 0; | ||
311 | 266 | ||
312 | hlist_for_each_entry_rcu(r, node, &fib_rules, hlist) { | ||
313 | if (((saddr^r->r_src) & r->r_srcmask) || | ||
314 | ((daddr^r->r_dst) & r->r_dstmask) || | ||
315 | (r->r_tos && r->r_tos != flp->fl4_tos) || | ||
316 | #ifdef CONFIG_IP_ROUTE_FWMARK | 267 | #ifdef CONFIG_IP_ROUTE_FWMARK |
317 | (r->r_fwmark && r->r_fwmark != flp->fl4_fwmark) || | 268 | if (tb[FRA_FWMARK] && (rule4->fwmark != nla_get_u32(tb[FRA_FWMARK]))) |
269 | return 0; | ||
270 | |||
271 | if (tb[FRA_FWMASK] && (rule4->fwmask != nla_get_u32(tb[FRA_FWMASK]))) | ||
272 | return 0; | ||
318 | #endif | 273 | #endif |
319 | (r->r_ifindex && r->r_ifindex != flp->iif)) | ||
320 | continue; | ||
321 | |||
322 | FRprintk("tb %d r %d ", r->r_table, r->r_action); | ||
323 | switch (r->r_action) { | ||
324 | case RTN_UNICAST: | ||
325 | policy = r; | ||
326 | break; | ||
327 | case RTN_UNREACHABLE: | ||
328 | rcu_read_unlock(); | ||
329 | return -ENETUNREACH; | ||
330 | default: | ||
331 | case RTN_BLACKHOLE: | ||
332 | rcu_read_unlock(); | ||
333 | return -EINVAL; | ||
334 | case RTN_PROHIBIT: | ||
335 | rcu_read_unlock(); | ||
336 | return -EACCES; | ||
337 | } | ||
338 | 274 | ||
339 | if ((tb = fib_get_table(r->r_table)) == NULL) | 275 | #ifdef CONFIG_NET_CLS_ROUTE |
340 | continue; | 276 | if (tb[FRA_FLOW] && (rule4->tclassid != nla_get_u32(tb[FRA_FLOW]))) |
341 | err = tb->tb_lookup(tb, flp, res); | 277 | return 0; |
342 | if (err == 0) { | 278 | #endif |
343 | res->r = policy; | ||
344 | if (policy) | ||
345 | atomic_inc(&policy->r_clntref); | ||
346 | rcu_read_unlock(); | ||
347 | return 0; | ||
348 | } | ||
349 | if (err < 0 && err != -EAGAIN) { | ||
350 | rcu_read_unlock(); | ||
351 | return err; | ||
352 | } | ||
353 | } | ||
354 | FRprintk("FAILURE\n"); | ||
355 | rcu_read_unlock(); | ||
356 | return -ENETUNREACH; | ||
357 | } | ||
358 | 279 | ||
359 | void fib_select_default(const struct flowi *flp, struct fib_result *res) | 280 | if (tb[FRA_SRC] && (rule4->src != nla_get_u32(tb[FRA_SRC]))) |
360 | { | 281 | return 0; |
361 | if (res->r && res->r->r_action == RTN_UNICAST && | ||
362 | FIB_RES_GW(*res) && FIB_RES_NH(*res).nh_scope == RT_SCOPE_LINK) { | ||
363 | struct fib_table *tb; | ||
364 | if ((tb = fib_get_table(res->r->r_table)) != NULL) | ||
365 | tb->tb_select_default(tb, flp, res); | ||
366 | } | ||
367 | } | ||
368 | 282 | ||
369 | static int fib_rules_event(struct notifier_block *this, unsigned long event, void *ptr) | 283 | if (tb[FRA_DST] && (rule4->dst != nla_get_u32(tb[FRA_DST]))) |
370 | { | 284 | return 0; |
371 | struct net_device *dev = ptr; | ||
372 | 285 | ||
373 | if (event == NETDEV_UNREGISTER) | 286 | return 1; |
374 | fib_rules_detach(dev); | ||
375 | else if (event == NETDEV_REGISTER) | ||
376 | fib_rules_attach(dev); | ||
377 | return NOTIFY_DONE; | ||
378 | } | 287 | } |
379 | 288 | ||
289 | static int fib4_rule_fill(struct fib_rule *rule, struct sk_buff *skb, | ||
290 | struct nlmsghdr *nlh, struct fib_rule_hdr *frh) | ||
291 | { | ||
292 | struct fib4_rule *rule4 = (struct fib4_rule *) rule; | ||
380 | 293 | ||
381 | static struct notifier_block fib_rules_notifier = { | 294 | frh->family = AF_INET; |
382 | .notifier_call =fib_rules_event, | 295 | frh->dst_len = rule4->dst_len; |
383 | }; | 296 | frh->src_len = rule4->src_len; |
297 | frh->tos = rule4->tos; | ||
384 | 298 | ||
385 | static __inline__ int inet_fill_rule(struct sk_buff *skb, | ||
386 | struct fib_rule *r, | ||
387 | u32 pid, u32 seq, int event, | ||
388 | unsigned int flags) | ||
389 | { | ||
390 | struct rtmsg *rtm; | ||
391 | struct nlmsghdr *nlh; | ||
392 | unsigned char *b = skb->tail; | ||
393 | |||
394 | nlh = NLMSG_NEW(skb, pid, seq, event, sizeof(*rtm), flags); | ||
395 | rtm = NLMSG_DATA(nlh); | ||
396 | rtm->rtm_family = AF_INET; | ||
397 | rtm->rtm_dst_len = r->r_dst_len; | ||
398 | rtm->rtm_src_len = r->r_src_len; | ||
399 | rtm->rtm_tos = r->r_tos; | ||
400 | #ifdef CONFIG_IP_ROUTE_FWMARK | 299 | #ifdef CONFIG_IP_ROUTE_FWMARK |
401 | if (r->r_fwmark) | 300 | if (rule4->fwmark) |
402 | RTA_PUT(skb, RTA_PROTOINFO, 4, &r->r_fwmark); | 301 | NLA_PUT_U32(skb, FRA_FWMARK, rule4->fwmark); |
302 | |||
303 | if (rule4->fwmask || rule4->fwmark) | ||
304 | NLA_PUT_U32(skb, FRA_FWMASK, rule4->fwmask); | ||
403 | #endif | 305 | #endif |
404 | rtm->rtm_table = r->r_table; | 306 | |
405 | rtm->rtm_protocol = 0; | 307 | if (rule4->dst_len) |
406 | rtm->rtm_scope = 0; | 308 | NLA_PUT_U32(skb, FRA_DST, rule4->dst); |
407 | rtm->rtm_type = r->r_action; | 309 | |
408 | rtm->rtm_flags = r->r_flags; | 310 | if (rule4->src_len) |
409 | 311 | NLA_PUT_U32(skb, FRA_SRC, rule4->src); | |
410 | if (r->r_dst_len) | 312 | |
411 | RTA_PUT(skb, RTA_DST, 4, &r->r_dst); | ||
412 | if (r->r_src_len) | ||
413 | RTA_PUT(skb, RTA_SRC, 4, &r->r_src); | ||
414 | if (r->r_ifname[0]) | ||
415 | RTA_PUT(skb, RTA_IIF, IFNAMSIZ, &r->r_ifname); | ||
416 | if (r->r_preference) | ||
417 | RTA_PUT(skb, RTA_PRIORITY, 4, &r->r_preference); | ||
418 | if (r->r_srcmap) | ||
419 | RTA_PUT(skb, RTA_GATEWAY, 4, &r->r_srcmap); | ||
420 | #ifdef CONFIG_NET_CLS_ROUTE | 313 | #ifdef CONFIG_NET_CLS_ROUTE |
421 | if (r->r_tclassid) | 314 | if (rule4->tclassid) |
422 | RTA_PUT(skb, RTA_FLOW, 4, &r->r_tclassid); | 315 | NLA_PUT_U32(skb, FRA_FLOW, rule4->tclassid); |
423 | #endif | 316 | #endif |
424 | nlh->nlmsg_len = skb->tail - b; | 317 | return 0; |
425 | return skb->len; | ||
426 | 318 | ||
427 | nlmsg_failure: | 319 | nla_put_failure: |
428 | rtattr_failure: | 320 | return -ENOBUFS; |
429 | skb_trim(skb, b - skb->data); | ||
430 | return -1; | ||
431 | } | 321 | } |
432 | 322 | ||
433 | /* callers should hold rtnl semaphore */ | 323 | int fib4_rules_dump(struct sk_buff *skb, struct netlink_callback *cb) |
434 | |||
435 | static void rtmsg_rule(int event, struct fib_rule *r) | ||
436 | { | 324 | { |
437 | int size = NLMSG_SPACE(sizeof(struct rtmsg) + 128); | 325 | return fib_rules_dump(skb, cb, AF_INET); |
438 | struct sk_buff *skb = alloc_skb(size, GFP_KERNEL); | ||
439 | |||
440 | if (!skb) | ||
441 | netlink_set_err(rtnl, 0, RTNLGRP_IPV4_RULE, ENOBUFS); | ||
442 | else if (inet_fill_rule(skb, r, 0, 0, event, 0) < 0) { | ||
443 | kfree_skb(skb); | ||
444 | netlink_set_err(rtnl, 0, RTNLGRP_IPV4_RULE, EINVAL); | ||
445 | } else { | ||
446 | netlink_broadcast(rtnl, skb, 0, RTNLGRP_IPV4_RULE, GFP_KERNEL); | ||
447 | } | ||
448 | } | 326 | } |
449 | 327 | ||
450 | int inet_dump_rules(struct sk_buff *skb, struct netlink_callback *cb) | 328 | static u32 fib4_rule_default_pref(void) |
451 | { | 329 | { |
452 | int idx = 0; | 330 | struct list_head *pos; |
453 | int s_idx = cb->args[0]; | 331 | struct fib_rule *rule; |
454 | struct fib_rule *r; | 332 | |
455 | struct hlist_node *node; | 333 | if (!list_empty(&fib4_rules)) { |
456 | 334 | pos = fib4_rules.next; | |
457 | rcu_read_lock(); | 335 | if (pos->next != &fib4_rules) { |
458 | hlist_for_each_entry(r, node, &fib_rules, hlist) { | 336 | rule = list_entry(pos->next, struct fib_rule, list); |
459 | if (idx < s_idx) | 337 | if (rule->pref) |
460 | goto next; | 338 | return rule->pref - 1; |
461 | if (inet_fill_rule(skb, r, NETLINK_CB(cb->skb).pid, | 339 | } |
462 | cb->nlh->nlmsg_seq, | ||
463 | RTM_NEWRULE, NLM_F_MULTI) < 0) | ||
464 | break; | ||
465 | next: | ||
466 | idx++; | ||
467 | } | 340 | } |
468 | rcu_read_unlock(); | ||
469 | cb->args[0] = idx; | ||
470 | 341 | ||
471 | return skb->len; | 342 | return 0; |
472 | } | 343 | } |
473 | 344 | ||
474 | void __init fib_rules_init(void) | 345 | static struct fib_rules_ops fib4_rules_ops = { |
346 | .family = AF_INET, | ||
347 | .rule_size = sizeof(struct fib4_rule), | ||
348 | .action = fib4_rule_action, | ||
349 | .match = fib4_rule_match, | ||
350 | .configure = fib4_rule_configure, | ||
351 | .compare = fib4_rule_compare, | ||
352 | .fill = fib4_rule_fill, | ||
353 | .default_pref = fib4_rule_default_pref, | ||
354 | .nlgroup = RTNLGRP_IPV4_RULE, | ||
355 | .policy = fib4_rule_policy, | ||
356 | .rules_list = &fib4_rules, | ||
357 | .owner = THIS_MODULE, | ||
358 | }; | ||
359 | |||
360 | void __init fib4_rules_init(void) | ||
475 | { | 361 | { |
476 | INIT_HLIST_HEAD(&fib_rules); | 362 | list_add_tail(&local_rule.common.list, &fib4_rules); |
477 | hlist_add_head(&local_rule.hlist, &fib_rules); | 363 | list_add_tail(&main_rule.common.list, &fib4_rules); |
478 | hlist_add_after(&local_rule.hlist, &main_rule.hlist); | 364 | list_add_tail(&default_rule.common.list, &fib4_rules); |
479 | hlist_add_after(&main_rule.hlist, &default_rule.hlist); | 365 | |
480 | register_netdevice_notifier(&fib_rules_notifier); | 366 | fib_rules_register(&fib4_rules_ops); |
481 | } | 367 | } |
diff --git a/net/ipv4/fib_semantics.c b/net/ipv4/fib_semantics.c index 51738000f3dc..2ead09543f68 100644 --- a/net/ipv4/fib_semantics.c +++ b/net/ipv4/fib_semantics.c | |||
@@ -33,7 +33,6 @@ | |||
33 | #include <linux/if_arp.h> | 33 | #include <linux/if_arp.h> |
34 | #include <linux/proc_fs.h> | 34 | #include <linux/proc_fs.h> |
35 | #include <linux/skbuff.h> | 35 | #include <linux/skbuff.h> |
36 | #include <linux/netlink.h> | ||
37 | #include <linux/init.h> | 36 | #include <linux/init.h> |
38 | 37 | ||
39 | #include <net/arp.h> | 38 | #include <net/arp.h> |
@@ -44,12 +43,14 @@ | |||
44 | #include <net/sock.h> | 43 | #include <net/sock.h> |
45 | #include <net/ip_fib.h> | 44 | #include <net/ip_fib.h> |
46 | #include <net/ip_mp_alg.h> | 45 | #include <net/ip_mp_alg.h> |
46 | #include <net/netlink.h> | ||
47 | #include <net/nexthop.h> | ||
47 | 48 | ||
48 | #include "fib_lookup.h" | 49 | #include "fib_lookup.h" |
49 | 50 | ||
50 | #define FSprintk(a...) | 51 | #define FSprintk(a...) |
51 | 52 | ||
52 | static DEFINE_RWLOCK(fib_info_lock); | 53 | static DEFINE_SPINLOCK(fib_info_lock); |
53 | static struct hlist_head *fib_info_hash; | 54 | static struct hlist_head *fib_info_hash; |
54 | static struct hlist_head *fib_info_laddrhash; | 55 | static struct hlist_head *fib_info_laddrhash; |
55 | static unsigned int fib_hash_size; | 56 | static unsigned int fib_hash_size; |
@@ -159,7 +160,7 @@ void free_fib_info(struct fib_info *fi) | |||
159 | 160 | ||
160 | void fib_release_info(struct fib_info *fi) | 161 | void fib_release_info(struct fib_info *fi) |
161 | { | 162 | { |
162 | write_lock_bh(&fib_info_lock); | 163 | spin_lock_bh(&fib_info_lock); |
163 | if (fi && --fi->fib_treeref == 0) { | 164 | if (fi && --fi->fib_treeref == 0) { |
164 | hlist_del(&fi->fib_hash); | 165 | hlist_del(&fi->fib_hash); |
165 | if (fi->fib_prefsrc) | 166 | if (fi->fib_prefsrc) |
@@ -172,7 +173,7 @@ void fib_release_info(struct fib_info *fi) | |||
172 | fi->fib_dead = 1; | 173 | fi->fib_dead = 1; |
173 | fib_info_put(fi); | 174 | fib_info_put(fi); |
174 | } | 175 | } |
175 | write_unlock_bh(&fib_info_lock); | 176 | spin_unlock_bh(&fib_info_lock); |
176 | } | 177 | } |
177 | 178 | ||
178 | static __inline__ int nh_comp(const struct fib_info *fi, const struct fib_info *ofi) | 179 | static __inline__ int nh_comp(const struct fib_info *fi, const struct fib_info *ofi) |
@@ -254,7 +255,7 @@ int ip_fib_check_default(u32 gw, struct net_device *dev) | |||
254 | struct fib_nh *nh; | 255 | struct fib_nh *nh; |
255 | unsigned int hash; | 256 | unsigned int hash; |
256 | 257 | ||
257 | read_lock(&fib_info_lock); | 258 | spin_lock(&fib_info_lock); |
258 | 259 | ||
259 | hash = fib_devindex_hashfn(dev->ifindex); | 260 | hash = fib_devindex_hashfn(dev->ifindex); |
260 | head = &fib_info_devhash[hash]; | 261 | head = &fib_info_devhash[hash]; |
@@ -262,41 +263,41 @@ int ip_fib_check_default(u32 gw, struct net_device *dev) | |||
262 | if (nh->nh_dev == dev && | 263 | if (nh->nh_dev == dev && |
263 | nh->nh_gw == gw && | 264 | nh->nh_gw == gw && |
264 | !(nh->nh_flags&RTNH_F_DEAD)) { | 265 | !(nh->nh_flags&RTNH_F_DEAD)) { |
265 | read_unlock(&fib_info_lock); | 266 | spin_unlock(&fib_info_lock); |
266 | return 0; | 267 | return 0; |
267 | } | 268 | } |
268 | } | 269 | } |
269 | 270 | ||
270 | read_unlock(&fib_info_lock); | 271 | spin_unlock(&fib_info_lock); |
271 | 272 | ||
272 | return -1; | 273 | return -1; |
273 | } | 274 | } |
274 | 275 | ||
275 | void rtmsg_fib(int event, u32 key, struct fib_alias *fa, | 276 | void rtmsg_fib(int event, u32 key, struct fib_alias *fa, |
276 | int z, int tb_id, | 277 | int dst_len, u32 tb_id, struct nl_info *info) |
277 | struct nlmsghdr *n, struct netlink_skb_parms *req) | ||
278 | { | 278 | { |
279 | struct sk_buff *skb; | 279 | struct sk_buff *skb; |
280 | u32 pid = req ? req->pid : n->nlmsg_pid; | 280 | int payload = sizeof(struct rtmsg) + 256; |
281 | int size = NLMSG_SPACE(sizeof(struct rtmsg)+256); | 281 | u32 seq = info->nlh ? info->nlh->nlmsg_seq : 0; |
282 | 282 | int err = -ENOBUFS; | |
283 | skb = alloc_skb(size, GFP_KERNEL); | 283 | |
284 | if (!skb) | 284 | skb = nlmsg_new(nlmsg_total_size(payload), GFP_KERNEL); |
285 | return; | 285 | if (skb == NULL) |
286 | 286 | goto errout; | |
287 | if (fib_dump_info(skb, pid, n->nlmsg_seq, event, tb_id, | 287 | |
288 | fa->fa_type, fa->fa_scope, &key, z, | 288 | err = fib_dump_info(skb, info->pid, seq, event, tb_id, |
289 | fa->fa_tos, | 289 | fa->fa_type, fa->fa_scope, key, dst_len, |
290 | fa->fa_info, 0) < 0) { | 290 | fa->fa_tos, fa->fa_info, 0); |
291 | if (err < 0) { | ||
291 | kfree_skb(skb); | 292 | kfree_skb(skb); |
292 | return; | 293 | goto errout; |
293 | } | 294 | } |
294 | NETLINK_CB(skb).dst_group = RTNLGRP_IPV4_ROUTE; | 295 | |
295 | if (n->nlmsg_flags&NLM_F_ECHO) | 296 | err = rtnl_notify(skb, info->pid, RTNLGRP_IPV4_ROUTE, |
296 | atomic_inc(&skb->users); | 297 | info->nlh, GFP_KERNEL); |
297 | netlink_broadcast(rtnl, skb, pid, RTNLGRP_IPV4_ROUTE, GFP_KERNEL); | 298 | errout: |
298 | if (n->nlmsg_flags&NLM_F_ECHO) | 299 | if (err < 0) |
299 | netlink_unicast(rtnl, skb, pid, MSG_DONTWAIT); | 300 | rtnl_set_sk_err(RTNLGRP_IPV4_ROUTE, err); |
300 | } | 301 | } |
301 | 302 | ||
302 | /* Return the first fib alias matching TOS with | 303 | /* Return the first fib alias matching TOS with |
@@ -342,102 +343,100 @@ int fib_detect_death(struct fib_info *fi, int order, | |||
342 | 343 | ||
343 | #ifdef CONFIG_IP_ROUTE_MULTIPATH | 344 | #ifdef CONFIG_IP_ROUTE_MULTIPATH |
344 | 345 | ||
345 | static u32 fib_get_attr32(struct rtattr *attr, int attrlen, int type) | 346 | static int fib_count_nexthops(struct rtnexthop *rtnh, int remaining) |
346 | { | ||
347 | while (RTA_OK(attr,attrlen)) { | ||
348 | if (attr->rta_type == type) | ||
349 | return *(u32*)RTA_DATA(attr); | ||
350 | attr = RTA_NEXT(attr, attrlen); | ||
351 | } | ||
352 | return 0; | ||
353 | } | ||
354 | |||
355 | static int | ||
356 | fib_count_nexthops(struct rtattr *rta) | ||
357 | { | 347 | { |
358 | int nhs = 0; | 348 | int nhs = 0; |
359 | struct rtnexthop *nhp = RTA_DATA(rta); | ||
360 | int nhlen = RTA_PAYLOAD(rta); | ||
361 | 349 | ||
362 | while (nhlen >= (int)sizeof(struct rtnexthop)) { | 350 | while (rtnh_ok(rtnh, remaining)) { |
363 | if ((nhlen -= nhp->rtnh_len) < 0) | ||
364 | return 0; | ||
365 | nhs++; | 351 | nhs++; |
366 | nhp = RTNH_NEXT(nhp); | 352 | rtnh = rtnh_next(rtnh, &remaining); |
367 | }; | 353 | } |
368 | return nhs; | 354 | |
355 | /* leftover implies invalid nexthop configuration, discard it */ | ||
356 | return remaining > 0 ? 0 : nhs; | ||
369 | } | 357 | } |
370 | 358 | ||
371 | static int | 359 | static int fib_get_nhs(struct fib_info *fi, struct rtnexthop *rtnh, |
372 | fib_get_nhs(struct fib_info *fi, const struct rtattr *rta, const struct rtmsg *r) | 360 | int remaining, struct fib_config *cfg) |
373 | { | 361 | { |
374 | struct rtnexthop *nhp = RTA_DATA(rta); | ||
375 | int nhlen = RTA_PAYLOAD(rta); | ||
376 | |||
377 | change_nexthops(fi) { | 362 | change_nexthops(fi) { |
378 | int attrlen = nhlen - sizeof(struct rtnexthop); | 363 | int attrlen; |
379 | if (attrlen < 0 || (nhlen -= nhp->rtnh_len) < 0) | 364 | |
365 | if (!rtnh_ok(rtnh, remaining)) | ||
380 | return -EINVAL; | 366 | return -EINVAL; |
381 | nh->nh_flags = (r->rtm_flags&~0xFF) | nhp->rtnh_flags; | 367 | |
382 | nh->nh_oif = nhp->rtnh_ifindex; | 368 | nh->nh_flags = (cfg->fc_flags & ~0xFF) | rtnh->rtnh_flags; |
383 | nh->nh_weight = nhp->rtnh_hops + 1; | 369 | nh->nh_oif = rtnh->rtnh_ifindex; |
384 | if (attrlen) { | 370 | nh->nh_weight = rtnh->rtnh_hops + 1; |
385 | nh->nh_gw = fib_get_attr32(RTNH_DATA(nhp), attrlen, RTA_GATEWAY); | 371 | |
372 | attrlen = rtnh_attrlen(rtnh); | ||
373 | if (attrlen > 0) { | ||
374 | struct nlattr *nla, *attrs = rtnh_attrs(rtnh); | ||
375 | |||
376 | nla = nla_find(attrs, attrlen, RTA_GATEWAY); | ||
377 | nh->nh_gw = nla ? nla_get_u32(nla) : 0; | ||
386 | #ifdef CONFIG_NET_CLS_ROUTE | 378 | #ifdef CONFIG_NET_CLS_ROUTE |
387 | nh->nh_tclassid = fib_get_attr32(RTNH_DATA(nhp), attrlen, RTA_FLOW); | 379 | nla = nla_find(attrs, attrlen, RTA_FLOW); |
380 | nh->nh_tclassid = nla ? nla_get_u32(nla) : 0; | ||
388 | #endif | 381 | #endif |
389 | } | 382 | } |
390 | nhp = RTNH_NEXT(nhp); | 383 | |
384 | rtnh = rtnh_next(rtnh, &remaining); | ||
391 | } endfor_nexthops(fi); | 385 | } endfor_nexthops(fi); |
386 | |||
392 | return 0; | 387 | return 0; |
393 | } | 388 | } |
394 | 389 | ||
395 | #endif | 390 | #endif |
396 | 391 | ||
397 | int fib_nh_match(struct rtmsg *r, struct nlmsghdr *nlh, struct kern_rta *rta, | 392 | int fib_nh_match(struct fib_config *cfg, struct fib_info *fi) |
398 | struct fib_info *fi) | ||
399 | { | 393 | { |
400 | #ifdef CONFIG_IP_ROUTE_MULTIPATH | 394 | #ifdef CONFIG_IP_ROUTE_MULTIPATH |
401 | struct rtnexthop *nhp; | 395 | struct rtnexthop *rtnh; |
402 | int nhlen; | 396 | int remaining; |
403 | #endif | 397 | #endif |
404 | 398 | ||
405 | if (rta->rta_priority && | 399 | if (cfg->fc_priority && cfg->fc_priority != fi->fib_priority) |
406 | *rta->rta_priority != fi->fib_priority) | ||
407 | return 1; | 400 | return 1; |
408 | 401 | ||
409 | if (rta->rta_oif || rta->rta_gw) { | 402 | if (cfg->fc_oif || cfg->fc_gw) { |
410 | if ((!rta->rta_oif || *rta->rta_oif == fi->fib_nh->nh_oif) && | 403 | if ((!cfg->fc_oif || cfg->fc_oif == fi->fib_nh->nh_oif) && |
411 | (!rta->rta_gw || memcmp(rta->rta_gw, &fi->fib_nh->nh_gw, 4) == 0)) | 404 | (!cfg->fc_gw || cfg->fc_gw == fi->fib_nh->nh_gw)) |
412 | return 0; | 405 | return 0; |
413 | return 1; | 406 | return 1; |
414 | } | 407 | } |
415 | 408 | ||
416 | #ifdef CONFIG_IP_ROUTE_MULTIPATH | 409 | #ifdef CONFIG_IP_ROUTE_MULTIPATH |
417 | if (rta->rta_mp == NULL) | 410 | if (cfg->fc_mp == NULL) |
418 | return 0; | 411 | return 0; |
419 | nhp = RTA_DATA(rta->rta_mp); | 412 | |
420 | nhlen = RTA_PAYLOAD(rta->rta_mp); | 413 | rtnh = cfg->fc_mp; |
414 | remaining = cfg->fc_mp_len; | ||
421 | 415 | ||
422 | for_nexthops(fi) { | 416 | for_nexthops(fi) { |
423 | int attrlen = nhlen - sizeof(struct rtnexthop); | 417 | int attrlen; |
424 | u32 gw; | ||
425 | 418 | ||
426 | if (attrlen < 0 || (nhlen -= nhp->rtnh_len) < 0) | 419 | if (!rtnh_ok(rtnh, remaining)) |
427 | return -EINVAL; | 420 | return -EINVAL; |
428 | if (nhp->rtnh_ifindex && nhp->rtnh_ifindex != nh->nh_oif) | 421 | |
422 | if (rtnh->rtnh_ifindex && rtnh->rtnh_ifindex != nh->nh_oif) | ||
429 | return 1; | 423 | return 1; |
430 | if (attrlen) { | 424 | |
431 | gw = fib_get_attr32(RTNH_DATA(nhp), attrlen, RTA_GATEWAY); | 425 | attrlen = rtnh_attrlen(rtnh); |
432 | if (gw && gw != nh->nh_gw) | 426 | if (attrlen < 0) { |
427 | struct nlattr *nla, *attrs = rtnh_attrs(rtnh); | ||
428 | |||
429 | nla = nla_find(attrs, attrlen, RTA_GATEWAY); | ||
430 | if (nla && nla_get_u32(nla) != nh->nh_gw) | ||
433 | return 1; | 431 | return 1; |
434 | #ifdef CONFIG_NET_CLS_ROUTE | 432 | #ifdef CONFIG_NET_CLS_ROUTE |
435 | gw = fib_get_attr32(RTNH_DATA(nhp), attrlen, RTA_FLOW); | 433 | nla = nla_find(attrs, attrlen, RTA_FLOW); |
436 | if (gw && gw != nh->nh_tclassid) | 434 | if (nla && nla_get_u32(nla) != nh->nh_tclassid) |
437 | return 1; | 435 | return 1; |
438 | #endif | 436 | #endif |
439 | } | 437 | } |
440 | nhp = RTNH_NEXT(nhp); | 438 | |
439 | rtnh = rtnh_next(rtnh, &remaining); | ||
441 | } endfor_nexthops(fi); | 440 | } endfor_nexthops(fi); |
442 | #endif | 441 | #endif |
443 | return 0; | 442 | return 0; |
@@ -488,7 +487,8 @@ int fib_nh_match(struct rtmsg *r, struct nlmsghdr *nlh, struct kern_rta *rta, | |||
488 | |-> {local prefix} (terminal node) | 487 | |-> {local prefix} (terminal node) |
489 | */ | 488 | */ |
490 | 489 | ||
491 | static int fib_check_nh(const struct rtmsg *r, struct fib_info *fi, struct fib_nh *nh) | 490 | static int fib_check_nh(struct fib_config *cfg, struct fib_info *fi, |
491 | struct fib_nh *nh) | ||
492 | { | 492 | { |
493 | int err; | 493 | int err; |
494 | 494 | ||
@@ -502,7 +502,7 @@ static int fib_check_nh(const struct rtmsg *r, struct fib_info *fi, struct fib_n | |||
502 | if (nh->nh_flags&RTNH_F_ONLINK) { | 502 | if (nh->nh_flags&RTNH_F_ONLINK) { |
503 | struct net_device *dev; | 503 | struct net_device *dev; |
504 | 504 | ||
505 | if (r->rtm_scope >= RT_SCOPE_LINK) | 505 | if (cfg->fc_scope >= RT_SCOPE_LINK) |
506 | return -EINVAL; | 506 | return -EINVAL; |
507 | if (inet_addr_type(nh->nh_gw) != RTN_UNICAST) | 507 | if (inet_addr_type(nh->nh_gw) != RTN_UNICAST) |
508 | return -EINVAL; | 508 | return -EINVAL; |
@@ -516,10 +516,15 @@ static int fib_check_nh(const struct rtmsg *r, struct fib_info *fi, struct fib_n | |||
516 | return 0; | 516 | return 0; |
517 | } | 517 | } |
518 | { | 518 | { |
519 | struct flowi fl = { .nl_u = { .ip4_u = | 519 | struct flowi fl = { |
520 | { .daddr = nh->nh_gw, | 520 | .nl_u = { |
521 | .scope = r->rtm_scope + 1 } }, | 521 | .ip4_u = { |
522 | .oif = nh->nh_oif }; | 522 | .daddr = nh->nh_gw, |
523 | .scope = cfg->fc_scope + 1, | ||
524 | }, | ||
525 | }, | ||
526 | .oif = nh->nh_oif, | ||
527 | }; | ||
523 | 528 | ||
524 | /* It is not necessary, but requires a bit of thinking */ | 529 | /* It is not necessary, but requires a bit of thinking */ |
525 | if (fl.fl4_scope < RT_SCOPE_LINK) | 530 | if (fl.fl4_scope < RT_SCOPE_LINK) |
@@ -598,7 +603,7 @@ static void fib_hash_move(struct hlist_head *new_info_hash, | |||
598 | unsigned int old_size = fib_hash_size; | 603 | unsigned int old_size = fib_hash_size; |
599 | unsigned int i, bytes; | 604 | unsigned int i, bytes; |
600 | 605 | ||
601 | write_lock_bh(&fib_info_lock); | 606 | spin_lock_bh(&fib_info_lock); |
602 | old_info_hash = fib_info_hash; | 607 | old_info_hash = fib_info_hash; |
603 | old_laddrhash = fib_info_laddrhash; | 608 | old_laddrhash = fib_info_laddrhash; |
604 | fib_hash_size = new_size; | 609 | fib_hash_size = new_size; |
@@ -639,46 +644,35 @@ static void fib_hash_move(struct hlist_head *new_info_hash, | |||
639 | } | 644 | } |
640 | fib_info_laddrhash = new_laddrhash; | 645 | fib_info_laddrhash = new_laddrhash; |
641 | 646 | ||
642 | write_unlock_bh(&fib_info_lock); | 647 | spin_unlock_bh(&fib_info_lock); |
643 | 648 | ||
644 | bytes = old_size * sizeof(struct hlist_head *); | 649 | bytes = old_size * sizeof(struct hlist_head *); |
645 | fib_hash_free(old_info_hash, bytes); | 650 | fib_hash_free(old_info_hash, bytes); |
646 | fib_hash_free(old_laddrhash, bytes); | 651 | fib_hash_free(old_laddrhash, bytes); |
647 | } | 652 | } |
648 | 653 | ||
649 | struct fib_info * | 654 | struct fib_info *fib_create_info(struct fib_config *cfg) |
650 | fib_create_info(const struct rtmsg *r, struct kern_rta *rta, | ||
651 | const struct nlmsghdr *nlh, int *errp) | ||
652 | { | 655 | { |
653 | int err; | 656 | int err; |
654 | struct fib_info *fi = NULL; | 657 | struct fib_info *fi = NULL; |
655 | struct fib_info *ofi; | 658 | struct fib_info *ofi; |
656 | #ifdef CONFIG_IP_ROUTE_MULTIPATH | ||
657 | int nhs = 1; | 659 | int nhs = 1; |
658 | #else | ||
659 | const int nhs = 1; | ||
660 | #endif | ||
661 | #ifdef CONFIG_IP_ROUTE_MULTIPATH_CACHED | ||
662 | u32 mp_alg = IP_MP_ALG_NONE; | ||
663 | #endif | ||
664 | 660 | ||
665 | /* Fast check to catch the most weird cases */ | 661 | /* Fast check to catch the most weird cases */ |
666 | if (fib_props[r->rtm_type].scope > r->rtm_scope) | 662 | if (fib_props[cfg->fc_type].scope > cfg->fc_scope) |
667 | goto err_inval; | 663 | goto err_inval; |
668 | 664 | ||
669 | #ifdef CONFIG_IP_ROUTE_MULTIPATH | 665 | #ifdef CONFIG_IP_ROUTE_MULTIPATH |
670 | if (rta->rta_mp) { | 666 | if (cfg->fc_mp) { |
671 | nhs = fib_count_nexthops(rta->rta_mp); | 667 | nhs = fib_count_nexthops(cfg->fc_mp, cfg->fc_mp_len); |
672 | if (nhs == 0) | 668 | if (nhs == 0) |
673 | goto err_inval; | 669 | goto err_inval; |
674 | } | 670 | } |
675 | #endif | 671 | #endif |
676 | #ifdef CONFIG_IP_ROUTE_MULTIPATH_CACHED | 672 | #ifdef CONFIG_IP_ROUTE_MULTIPATH_CACHED |
677 | if (rta->rta_mp_alg) { | 673 | if (cfg->fc_mp_alg) { |
678 | mp_alg = *rta->rta_mp_alg; | 674 | if (cfg->fc_mp_alg < IP_MP_ALG_NONE || |
679 | 675 | cfg->fc_mp_alg > IP_MP_ALG_MAX) | |
680 | if (mp_alg < IP_MP_ALG_NONE || | ||
681 | mp_alg > IP_MP_ALG_MAX) | ||
682 | goto err_inval; | 676 | goto err_inval; |
683 | } | 677 | } |
684 | #endif | 678 | #endif |
@@ -714,43 +708,42 @@ fib_create_info(const struct rtmsg *r, struct kern_rta *rta, | |||
714 | goto failure; | 708 | goto failure; |
715 | fib_info_cnt++; | 709 | fib_info_cnt++; |
716 | 710 | ||
717 | fi->fib_protocol = r->rtm_protocol; | 711 | fi->fib_protocol = cfg->fc_protocol; |
712 | fi->fib_flags = cfg->fc_flags; | ||
713 | fi->fib_priority = cfg->fc_priority; | ||
714 | fi->fib_prefsrc = cfg->fc_prefsrc; | ||
718 | 715 | ||
719 | fi->fib_nhs = nhs; | 716 | fi->fib_nhs = nhs; |
720 | change_nexthops(fi) { | 717 | change_nexthops(fi) { |
721 | nh->nh_parent = fi; | 718 | nh->nh_parent = fi; |
722 | } endfor_nexthops(fi) | 719 | } endfor_nexthops(fi) |
723 | 720 | ||
724 | fi->fib_flags = r->rtm_flags; | 721 | if (cfg->fc_mx) { |
725 | if (rta->rta_priority) | 722 | struct nlattr *nla; |
726 | fi->fib_priority = *rta->rta_priority; | 723 | int remaining; |
727 | if (rta->rta_mx) { | 724 | |
728 | int attrlen = RTA_PAYLOAD(rta->rta_mx); | 725 | nla_for_each_attr(nla, cfg->fc_mx, cfg->fc_mx_len, remaining) { |
729 | struct rtattr *attr = RTA_DATA(rta->rta_mx); | 726 | int type = nla->nla_type; |
730 | 727 | ||
731 | while (RTA_OK(attr, attrlen)) { | 728 | if (type) { |
732 | unsigned flavor = attr->rta_type; | 729 | if (type > RTAX_MAX) |
733 | if (flavor) { | ||
734 | if (flavor > RTAX_MAX) | ||
735 | goto err_inval; | 730 | goto err_inval; |
736 | fi->fib_metrics[flavor-1] = *(unsigned*)RTA_DATA(attr); | 731 | fi->fib_metrics[type - 1] = nla_get_u32(nla); |
737 | } | 732 | } |
738 | attr = RTA_NEXT(attr, attrlen); | ||
739 | } | 733 | } |
740 | } | 734 | } |
741 | if (rta->rta_prefsrc) | ||
742 | memcpy(&fi->fib_prefsrc, rta->rta_prefsrc, 4); | ||
743 | 735 | ||
744 | if (rta->rta_mp) { | 736 | if (cfg->fc_mp) { |
745 | #ifdef CONFIG_IP_ROUTE_MULTIPATH | 737 | #ifdef CONFIG_IP_ROUTE_MULTIPATH |
746 | if ((err = fib_get_nhs(fi, rta->rta_mp, r)) != 0) | 738 | err = fib_get_nhs(fi, cfg->fc_mp, cfg->fc_mp_len, cfg); |
739 | if (err != 0) | ||
747 | goto failure; | 740 | goto failure; |
748 | if (rta->rta_oif && fi->fib_nh->nh_oif != *rta->rta_oif) | 741 | if (cfg->fc_oif && fi->fib_nh->nh_oif != cfg->fc_oif) |
749 | goto err_inval; | 742 | goto err_inval; |
750 | if (rta->rta_gw && memcmp(&fi->fib_nh->nh_gw, rta->rta_gw, 4)) | 743 | if (cfg->fc_gw && fi->fib_nh->nh_gw != cfg->fc_gw) |
751 | goto err_inval; | 744 | goto err_inval; |
752 | #ifdef CONFIG_NET_CLS_ROUTE | 745 | #ifdef CONFIG_NET_CLS_ROUTE |
753 | if (rta->rta_flow && memcmp(&fi->fib_nh->nh_tclassid, rta->rta_flow, 4)) | 746 | if (cfg->fc_flow && fi->fib_nh->nh_tclassid != cfg->fc_flow) |
754 | goto err_inval; | 747 | goto err_inval; |
755 | #endif | 748 | #endif |
756 | #else | 749 | #else |
@@ -758,34 +751,32 @@ fib_create_info(const struct rtmsg *r, struct kern_rta *rta, | |||
758 | #endif | 751 | #endif |
759 | } else { | 752 | } else { |
760 | struct fib_nh *nh = fi->fib_nh; | 753 | struct fib_nh *nh = fi->fib_nh; |
761 | if (rta->rta_oif) | 754 | |
762 | nh->nh_oif = *rta->rta_oif; | 755 | nh->nh_oif = cfg->fc_oif; |
763 | if (rta->rta_gw) | 756 | nh->nh_gw = cfg->fc_gw; |
764 | memcpy(&nh->nh_gw, rta->rta_gw, 4); | 757 | nh->nh_flags = cfg->fc_flags; |
765 | #ifdef CONFIG_NET_CLS_ROUTE | 758 | #ifdef CONFIG_NET_CLS_ROUTE |
766 | if (rta->rta_flow) | 759 | nh->nh_tclassid = cfg->fc_flow; |
767 | memcpy(&nh->nh_tclassid, rta->rta_flow, 4); | ||
768 | #endif | 760 | #endif |
769 | nh->nh_flags = r->rtm_flags; | ||
770 | #ifdef CONFIG_IP_ROUTE_MULTIPATH | 761 | #ifdef CONFIG_IP_ROUTE_MULTIPATH |
771 | nh->nh_weight = 1; | 762 | nh->nh_weight = 1; |
772 | #endif | 763 | #endif |
773 | } | 764 | } |
774 | 765 | ||
775 | #ifdef CONFIG_IP_ROUTE_MULTIPATH_CACHED | 766 | #ifdef CONFIG_IP_ROUTE_MULTIPATH_CACHED |
776 | fi->fib_mp_alg = mp_alg; | 767 | fi->fib_mp_alg = cfg->fc_mp_alg; |
777 | #endif | 768 | #endif |
778 | 769 | ||
779 | if (fib_props[r->rtm_type].error) { | 770 | if (fib_props[cfg->fc_type].error) { |
780 | if (rta->rta_gw || rta->rta_oif || rta->rta_mp) | 771 | if (cfg->fc_gw || cfg->fc_oif || cfg->fc_mp) |
781 | goto err_inval; | 772 | goto err_inval; |
782 | goto link_it; | 773 | goto link_it; |
783 | } | 774 | } |
784 | 775 | ||
785 | if (r->rtm_scope > RT_SCOPE_HOST) | 776 | if (cfg->fc_scope > RT_SCOPE_HOST) |
786 | goto err_inval; | 777 | goto err_inval; |
787 | 778 | ||
788 | if (r->rtm_scope == RT_SCOPE_HOST) { | 779 | if (cfg->fc_scope == RT_SCOPE_HOST) { |
789 | struct fib_nh *nh = fi->fib_nh; | 780 | struct fib_nh *nh = fi->fib_nh; |
790 | 781 | ||
791 | /* Local address is added. */ | 782 | /* Local address is added. */ |
@@ -798,14 +789,14 @@ fib_create_info(const struct rtmsg *r, struct kern_rta *rta, | |||
798 | goto failure; | 789 | goto failure; |
799 | } else { | 790 | } else { |
800 | change_nexthops(fi) { | 791 | change_nexthops(fi) { |
801 | if ((err = fib_check_nh(r, fi, nh)) != 0) | 792 | if ((err = fib_check_nh(cfg, fi, nh)) != 0) |
802 | goto failure; | 793 | goto failure; |
803 | } endfor_nexthops(fi) | 794 | } endfor_nexthops(fi) |
804 | } | 795 | } |
805 | 796 | ||
806 | if (fi->fib_prefsrc) { | 797 | if (fi->fib_prefsrc) { |
807 | if (r->rtm_type != RTN_LOCAL || rta->rta_dst == NULL || | 798 | if (cfg->fc_type != RTN_LOCAL || !cfg->fc_dst || |
808 | memcmp(&fi->fib_prefsrc, rta->rta_dst, 4)) | 799 | fi->fib_prefsrc != cfg->fc_dst) |
809 | if (inet_addr_type(fi->fib_prefsrc) != RTN_LOCAL) | 800 | if (inet_addr_type(fi->fib_prefsrc) != RTN_LOCAL) |
810 | goto err_inval; | 801 | goto err_inval; |
811 | } | 802 | } |
@@ -820,7 +811,7 @@ link_it: | |||
820 | 811 | ||
821 | fi->fib_treeref++; | 812 | fi->fib_treeref++; |
822 | atomic_inc(&fi->fib_clntref); | 813 | atomic_inc(&fi->fib_clntref); |
823 | write_lock_bh(&fib_info_lock); | 814 | spin_lock_bh(&fib_info_lock); |
824 | hlist_add_head(&fi->fib_hash, | 815 | hlist_add_head(&fi->fib_hash, |
825 | &fib_info_hash[fib_info_hashfn(fi)]); | 816 | &fib_info_hash[fib_info_hashfn(fi)]); |
826 | if (fi->fib_prefsrc) { | 817 | if (fi->fib_prefsrc) { |
@@ -839,19 +830,19 @@ link_it: | |||
839 | head = &fib_info_devhash[hash]; | 830 | head = &fib_info_devhash[hash]; |
840 | hlist_add_head(&nh->nh_hash, head); | 831 | hlist_add_head(&nh->nh_hash, head); |
841 | } endfor_nexthops(fi) | 832 | } endfor_nexthops(fi) |
842 | write_unlock_bh(&fib_info_lock); | 833 | spin_unlock_bh(&fib_info_lock); |
843 | return fi; | 834 | return fi; |
844 | 835 | ||
845 | err_inval: | 836 | err_inval: |
846 | err = -EINVAL; | 837 | err = -EINVAL; |
847 | 838 | ||
848 | failure: | 839 | failure: |
849 | *errp = err; | ||
850 | if (fi) { | 840 | if (fi) { |
851 | fi->fib_dead = 1; | 841 | fi->fib_dead = 1; |
852 | free_fib_info(fi); | 842 | free_fib_info(fi); |
853 | } | 843 | } |
854 | return NULL; | 844 | |
845 | return ERR_PTR(err); | ||
855 | } | 846 | } |
856 | 847 | ||
857 | /* Note! fib_semantic_match intentionally uses RCU list functions. */ | 848 | /* Note! fib_semantic_match intentionally uses RCU list functions. */ |
@@ -937,224 +928,89 @@ u32 __fib_res_prefsrc(struct fib_result *res) | |||
937 | return inet_select_addr(FIB_RES_DEV(*res), FIB_RES_GW(*res), res->scope); | 928 | return inet_select_addr(FIB_RES_DEV(*res), FIB_RES_GW(*res), res->scope); |
938 | } | 929 | } |
939 | 930 | ||
940 | int | 931 | int fib_dump_info(struct sk_buff *skb, u32 pid, u32 seq, int event, |
941 | fib_dump_info(struct sk_buff *skb, u32 pid, u32 seq, int event, | 932 | u32 tb_id, u8 type, u8 scope, u32 dst, int dst_len, u8 tos, |
942 | u8 tb_id, u8 type, u8 scope, void *dst, int dst_len, u8 tos, | 933 | struct fib_info *fi, unsigned int flags) |
943 | struct fib_info *fi, unsigned int flags) | ||
944 | { | 934 | { |
935 | struct nlmsghdr *nlh; | ||
945 | struct rtmsg *rtm; | 936 | struct rtmsg *rtm; |
946 | struct nlmsghdr *nlh; | ||
947 | unsigned char *b = skb->tail; | ||
948 | 937 | ||
949 | nlh = NLMSG_NEW(skb, pid, seq, event, sizeof(*rtm), flags); | 938 | nlh = nlmsg_put(skb, pid, seq, event, sizeof(*rtm), flags); |
950 | rtm = NLMSG_DATA(nlh); | 939 | if (nlh == NULL) |
940 | return -ENOBUFS; | ||
941 | |||
942 | rtm = nlmsg_data(nlh); | ||
951 | rtm->rtm_family = AF_INET; | 943 | rtm->rtm_family = AF_INET; |
952 | rtm->rtm_dst_len = dst_len; | 944 | rtm->rtm_dst_len = dst_len; |
953 | rtm->rtm_src_len = 0; | 945 | rtm->rtm_src_len = 0; |
954 | rtm->rtm_tos = tos; | 946 | rtm->rtm_tos = tos; |
955 | rtm->rtm_table = tb_id; | 947 | rtm->rtm_table = tb_id; |
948 | NLA_PUT_U32(skb, RTA_TABLE, tb_id); | ||
956 | rtm->rtm_type = type; | 949 | rtm->rtm_type = type; |
957 | rtm->rtm_flags = fi->fib_flags; | 950 | rtm->rtm_flags = fi->fib_flags; |
958 | rtm->rtm_scope = scope; | 951 | rtm->rtm_scope = scope; |
959 | if (rtm->rtm_dst_len) | ||
960 | RTA_PUT(skb, RTA_DST, 4, dst); | ||
961 | rtm->rtm_protocol = fi->fib_protocol; | 952 | rtm->rtm_protocol = fi->fib_protocol; |
953 | |||
954 | if (rtm->rtm_dst_len) | ||
955 | NLA_PUT_U32(skb, RTA_DST, dst); | ||
956 | |||
962 | if (fi->fib_priority) | 957 | if (fi->fib_priority) |
963 | RTA_PUT(skb, RTA_PRIORITY, 4, &fi->fib_priority); | 958 | NLA_PUT_U32(skb, RTA_PRIORITY, fi->fib_priority); |
959 | |||
964 | if (rtnetlink_put_metrics(skb, fi->fib_metrics) < 0) | 960 | if (rtnetlink_put_metrics(skb, fi->fib_metrics) < 0) |
965 | goto rtattr_failure; | 961 | goto nla_put_failure; |
962 | |||
966 | if (fi->fib_prefsrc) | 963 | if (fi->fib_prefsrc) |
967 | RTA_PUT(skb, RTA_PREFSRC, 4, &fi->fib_prefsrc); | 964 | NLA_PUT_U32(skb, RTA_PREFSRC, fi->fib_prefsrc); |
965 | |||
968 | if (fi->fib_nhs == 1) { | 966 | if (fi->fib_nhs == 1) { |
969 | if (fi->fib_nh->nh_gw) | 967 | if (fi->fib_nh->nh_gw) |
970 | RTA_PUT(skb, RTA_GATEWAY, 4, &fi->fib_nh->nh_gw); | 968 | NLA_PUT_U32(skb, RTA_GATEWAY, fi->fib_nh->nh_gw); |
969 | |||
971 | if (fi->fib_nh->nh_oif) | 970 | if (fi->fib_nh->nh_oif) |
972 | RTA_PUT(skb, RTA_OIF, sizeof(int), &fi->fib_nh->nh_oif); | 971 | NLA_PUT_U32(skb, RTA_OIF, fi->fib_nh->nh_oif); |
973 | #ifdef CONFIG_NET_CLS_ROUTE | 972 | #ifdef CONFIG_NET_CLS_ROUTE |
974 | if (fi->fib_nh[0].nh_tclassid) | 973 | if (fi->fib_nh[0].nh_tclassid) |
975 | RTA_PUT(skb, RTA_FLOW, 4, &fi->fib_nh[0].nh_tclassid); | 974 | NLA_PUT_U32(skb, RTA_FLOW, fi->fib_nh[0].nh_tclassid); |
976 | #endif | 975 | #endif |
977 | } | 976 | } |
978 | #ifdef CONFIG_IP_ROUTE_MULTIPATH | 977 | #ifdef CONFIG_IP_ROUTE_MULTIPATH |
979 | if (fi->fib_nhs > 1) { | 978 | if (fi->fib_nhs > 1) { |
980 | struct rtnexthop *nhp; | 979 | struct rtnexthop *rtnh; |
981 | struct rtattr *mp_head; | 980 | struct nlattr *mp; |
982 | if (skb_tailroom(skb) <= RTA_SPACE(0)) | 981 | |
983 | goto rtattr_failure; | 982 | mp = nla_nest_start(skb, RTA_MULTIPATH); |
984 | mp_head = (struct rtattr*)skb_put(skb, RTA_SPACE(0)); | 983 | if (mp == NULL) |
984 | goto nla_put_failure; | ||
985 | 985 | ||
986 | for_nexthops(fi) { | 986 | for_nexthops(fi) { |
987 | if (skb_tailroom(skb) < RTA_ALIGN(RTA_ALIGN(sizeof(*nhp)) + 4)) | 987 | rtnh = nla_reserve_nohdr(skb, sizeof(*rtnh)); |
988 | goto rtattr_failure; | 988 | if (rtnh == NULL) |
989 | nhp = (struct rtnexthop*)skb_put(skb, RTA_ALIGN(sizeof(*nhp))); | 989 | goto nla_put_failure; |
990 | nhp->rtnh_flags = nh->nh_flags & 0xFF; | 990 | |
991 | nhp->rtnh_hops = nh->nh_weight-1; | 991 | rtnh->rtnh_flags = nh->nh_flags & 0xFF; |
992 | nhp->rtnh_ifindex = nh->nh_oif; | 992 | rtnh->rtnh_hops = nh->nh_weight - 1; |
993 | rtnh->rtnh_ifindex = nh->nh_oif; | ||
994 | |||
993 | if (nh->nh_gw) | 995 | if (nh->nh_gw) |
994 | RTA_PUT(skb, RTA_GATEWAY, 4, &nh->nh_gw); | 996 | NLA_PUT_U32(skb, RTA_GATEWAY, nh->nh_gw); |
995 | #ifdef CONFIG_NET_CLS_ROUTE | 997 | #ifdef CONFIG_NET_CLS_ROUTE |
996 | if (nh->nh_tclassid) | 998 | if (nh->nh_tclassid) |
997 | RTA_PUT(skb, RTA_FLOW, 4, &nh->nh_tclassid); | 999 | NLA_PUT_U32(skb, RTA_FLOW, nh->nh_tclassid); |
998 | #endif | 1000 | #endif |
999 | nhp->rtnh_len = skb->tail - (unsigned char*)nhp; | 1001 | /* length of rtnetlink header + attributes */ |
1002 | rtnh->rtnh_len = nlmsg_get_pos(skb) - (void *) rtnh; | ||
1000 | } endfor_nexthops(fi); | 1003 | } endfor_nexthops(fi); |
1001 | mp_head->rta_type = RTA_MULTIPATH; | ||
1002 | mp_head->rta_len = skb->tail - (u8*)mp_head; | ||
1003 | } | ||
1004 | #endif | ||
1005 | nlh->nlmsg_len = skb->tail - b; | ||
1006 | return skb->len; | ||
1007 | |||
1008 | nlmsg_failure: | ||
1009 | rtattr_failure: | ||
1010 | skb_trim(skb, b - skb->data); | ||
1011 | return -1; | ||
1012 | } | ||
1013 | |||
1014 | #ifndef CONFIG_IP_NOSIOCRT | ||
1015 | |||
1016 | int | ||
1017 | fib_convert_rtentry(int cmd, struct nlmsghdr *nl, struct rtmsg *rtm, | ||
1018 | struct kern_rta *rta, struct rtentry *r) | ||
1019 | { | ||
1020 | int plen; | ||
1021 | u32 *ptr; | ||
1022 | |||
1023 | memset(rtm, 0, sizeof(*rtm)); | ||
1024 | memset(rta, 0, sizeof(*rta)); | ||
1025 | |||
1026 | if (r->rt_dst.sa_family != AF_INET) | ||
1027 | return -EAFNOSUPPORT; | ||
1028 | |||
1029 | /* Check mask for validity: | ||
1030 | a) it must be contiguous. | ||
1031 | b) destination must have all host bits clear. | ||
1032 | c) if application forgot to set correct family (AF_INET), | ||
1033 | reject request unless it is absolutely clear i.e. | ||
1034 | both family and mask are zero. | ||
1035 | */ | ||
1036 | plen = 32; | ||
1037 | ptr = &((struct sockaddr_in*)&r->rt_dst)->sin_addr.s_addr; | ||
1038 | if (!(r->rt_flags&RTF_HOST)) { | ||
1039 | u32 mask = ((struct sockaddr_in*)&r->rt_genmask)->sin_addr.s_addr; | ||
1040 | if (r->rt_genmask.sa_family != AF_INET) { | ||
1041 | if (mask || r->rt_genmask.sa_family) | ||
1042 | return -EAFNOSUPPORT; | ||
1043 | } | ||
1044 | if (bad_mask(mask, *ptr)) | ||
1045 | return -EINVAL; | ||
1046 | plen = inet_mask_len(mask); | ||
1047 | } | ||
1048 | |||
1049 | nl->nlmsg_flags = NLM_F_REQUEST; | ||
1050 | nl->nlmsg_pid = 0; | ||
1051 | nl->nlmsg_seq = 0; | ||
1052 | nl->nlmsg_len = NLMSG_LENGTH(sizeof(*rtm)); | ||
1053 | if (cmd == SIOCDELRT) { | ||
1054 | nl->nlmsg_type = RTM_DELROUTE; | ||
1055 | nl->nlmsg_flags = 0; | ||
1056 | } else { | ||
1057 | nl->nlmsg_type = RTM_NEWROUTE; | ||
1058 | nl->nlmsg_flags = NLM_F_REQUEST|NLM_F_CREATE; | ||
1059 | rtm->rtm_protocol = RTPROT_BOOT; | ||
1060 | } | ||
1061 | |||
1062 | rtm->rtm_dst_len = plen; | ||
1063 | rta->rta_dst = ptr; | ||
1064 | |||
1065 | if (r->rt_metric) { | ||
1066 | *(u32*)&r->rt_pad3 = r->rt_metric - 1; | ||
1067 | rta->rta_priority = (u32*)&r->rt_pad3; | ||
1068 | } | ||
1069 | if (r->rt_flags&RTF_REJECT) { | ||
1070 | rtm->rtm_scope = RT_SCOPE_HOST; | ||
1071 | rtm->rtm_type = RTN_UNREACHABLE; | ||
1072 | return 0; | ||
1073 | } | ||
1074 | rtm->rtm_scope = RT_SCOPE_NOWHERE; | ||
1075 | rtm->rtm_type = RTN_UNICAST; | ||
1076 | |||
1077 | if (r->rt_dev) { | ||
1078 | char *colon; | ||
1079 | struct net_device *dev; | ||
1080 | char devname[IFNAMSIZ]; | ||
1081 | |||
1082 | if (copy_from_user(devname, r->rt_dev, IFNAMSIZ-1)) | ||
1083 | return -EFAULT; | ||
1084 | devname[IFNAMSIZ-1] = 0; | ||
1085 | colon = strchr(devname, ':'); | ||
1086 | if (colon) | ||
1087 | *colon = 0; | ||
1088 | dev = __dev_get_by_name(devname); | ||
1089 | if (!dev) | ||
1090 | return -ENODEV; | ||
1091 | rta->rta_oif = &dev->ifindex; | ||
1092 | if (colon) { | ||
1093 | struct in_ifaddr *ifa; | ||
1094 | struct in_device *in_dev = __in_dev_get_rtnl(dev); | ||
1095 | if (!in_dev) | ||
1096 | return -ENODEV; | ||
1097 | *colon = ':'; | ||
1098 | for (ifa = in_dev->ifa_list; ifa; ifa = ifa->ifa_next) | ||
1099 | if (strcmp(ifa->ifa_label, devname) == 0) | ||
1100 | break; | ||
1101 | if (ifa == NULL) | ||
1102 | return -ENODEV; | ||
1103 | rta->rta_prefsrc = &ifa->ifa_local; | ||
1104 | } | ||
1105 | } | ||
1106 | 1004 | ||
1107 | ptr = &((struct sockaddr_in*)&r->rt_gateway)->sin_addr.s_addr; | 1005 | nla_nest_end(skb, mp); |
1108 | if (r->rt_gateway.sa_family == AF_INET && *ptr) { | ||
1109 | rta->rta_gw = ptr; | ||
1110 | if (r->rt_flags&RTF_GATEWAY && inet_addr_type(*ptr) == RTN_UNICAST) | ||
1111 | rtm->rtm_scope = RT_SCOPE_UNIVERSE; | ||
1112 | } | 1006 | } |
1007 | #endif | ||
1008 | return nlmsg_end(skb, nlh); | ||
1113 | 1009 | ||
1114 | if (cmd == SIOCDELRT) | 1010 | nla_put_failure: |
1115 | return 0; | 1011 | return nlmsg_cancel(skb, nlh); |
1116 | |||
1117 | if (r->rt_flags&RTF_GATEWAY && rta->rta_gw == NULL) | ||
1118 | return -EINVAL; | ||
1119 | |||
1120 | if (rtm->rtm_scope == RT_SCOPE_NOWHERE) | ||
1121 | rtm->rtm_scope = RT_SCOPE_LINK; | ||
1122 | |||
1123 | if (r->rt_flags&(RTF_MTU|RTF_WINDOW|RTF_IRTT)) { | ||
1124 | struct rtattr *rec; | ||
1125 | struct rtattr *mx = kmalloc(RTA_LENGTH(3*RTA_LENGTH(4)), GFP_KERNEL); | ||
1126 | if (mx == NULL) | ||
1127 | return -ENOMEM; | ||
1128 | rta->rta_mx = mx; | ||
1129 | mx->rta_type = RTA_METRICS; | ||
1130 | mx->rta_len = RTA_LENGTH(0); | ||
1131 | if (r->rt_flags&RTF_MTU) { | ||
1132 | rec = (void*)((char*)mx + RTA_ALIGN(mx->rta_len)); | ||
1133 | rec->rta_type = RTAX_ADVMSS; | ||
1134 | rec->rta_len = RTA_LENGTH(4); | ||
1135 | mx->rta_len += RTA_LENGTH(4); | ||
1136 | *(u32*)RTA_DATA(rec) = r->rt_mtu - 40; | ||
1137 | } | ||
1138 | if (r->rt_flags&RTF_WINDOW) { | ||
1139 | rec = (void*)((char*)mx + RTA_ALIGN(mx->rta_len)); | ||
1140 | rec->rta_type = RTAX_WINDOW; | ||
1141 | rec->rta_len = RTA_LENGTH(4); | ||
1142 | mx->rta_len += RTA_LENGTH(4); | ||
1143 | *(u32*)RTA_DATA(rec) = r->rt_window; | ||
1144 | } | ||
1145 | if (r->rt_flags&RTF_IRTT) { | ||
1146 | rec = (void*)((char*)mx + RTA_ALIGN(mx->rta_len)); | ||
1147 | rec->rta_type = RTAX_RTT; | ||
1148 | rec->rta_len = RTA_LENGTH(4); | ||
1149 | mx->rta_len += RTA_LENGTH(4); | ||
1150 | *(u32*)RTA_DATA(rec) = r->rt_irtt<<3; | ||
1151 | } | ||
1152 | } | ||
1153 | return 0; | ||
1154 | } | 1012 | } |
1155 | 1013 | ||
1156 | #endif | ||
1157 | |||
1158 | /* | 1014 | /* |
1159 | Update FIB if: | 1015 | Update FIB if: |
1160 | - local address disappeared -> we must delete all the entries | 1016 | - local address disappeared -> we must delete all the entries |
diff --git a/net/ipv4/fib_trie.c b/net/ipv4/fib_trie.c index 01801c0f885d..9c3ff6ba6e21 100644 --- a/net/ipv4/fib_trie.c +++ b/net/ipv4/fib_trie.c | |||
@@ -1124,17 +1124,14 @@ err: | |||
1124 | return fa_head; | 1124 | return fa_head; |
1125 | } | 1125 | } |
1126 | 1126 | ||
1127 | static int | 1127 | static int fn_trie_insert(struct fib_table *tb, struct fib_config *cfg) |
1128 | fn_trie_insert(struct fib_table *tb, struct rtmsg *r, struct kern_rta *rta, | ||
1129 | struct nlmsghdr *nlhdr, struct netlink_skb_parms *req) | ||
1130 | { | 1128 | { |
1131 | struct trie *t = (struct trie *) tb->tb_data; | 1129 | struct trie *t = (struct trie *) tb->tb_data; |
1132 | struct fib_alias *fa, *new_fa; | 1130 | struct fib_alias *fa, *new_fa; |
1133 | struct list_head *fa_head = NULL; | 1131 | struct list_head *fa_head = NULL; |
1134 | struct fib_info *fi; | 1132 | struct fib_info *fi; |
1135 | int plen = r->rtm_dst_len; | 1133 | int plen = cfg->fc_dst_len; |
1136 | int type = r->rtm_type; | 1134 | u8 tos = cfg->fc_tos; |
1137 | u8 tos = r->rtm_tos; | ||
1138 | u32 key, mask; | 1135 | u32 key, mask; |
1139 | int err; | 1136 | int err; |
1140 | struct leaf *l; | 1137 | struct leaf *l; |
@@ -1142,13 +1139,9 @@ fn_trie_insert(struct fib_table *tb, struct rtmsg *r, struct kern_rta *rta, | |||
1142 | if (plen > 32) | 1139 | if (plen > 32) |
1143 | return -EINVAL; | 1140 | return -EINVAL; |
1144 | 1141 | ||
1145 | key = 0; | 1142 | key = ntohl(cfg->fc_dst); |
1146 | if (rta->rta_dst) | ||
1147 | memcpy(&key, rta->rta_dst, 4); | ||
1148 | |||
1149 | key = ntohl(key); | ||
1150 | 1143 | ||
1151 | pr_debug("Insert table=%d %08x/%d\n", tb->tb_id, key, plen); | 1144 | pr_debug("Insert table=%u %08x/%d\n", tb->tb_id, key, plen); |
1152 | 1145 | ||
1153 | mask = ntohl(inet_make_mask(plen)); | 1146 | mask = ntohl(inet_make_mask(plen)); |
1154 | 1147 | ||
@@ -1157,10 +1150,11 @@ fn_trie_insert(struct fib_table *tb, struct rtmsg *r, struct kern_rta *rta, | |||
1157 | 1150 | ||
1158 | key = key & mask; | 1151 | key = key & mask; |
1159 | 1152 | ||
1160 | fi = fib_create_info(r, rta, nlhdr, &err); | 1153 | fi = fib_create_info(cfg); |
1161 | 1154 | if (IS_ERR(fi)) { | |
1162 | if (!fi) | 1155 | err = PTR_ERR(fi); |
1163 | goto err; | 1156 | goto err; |
1157 | } | ||
1164 | 1158 | ||
1165 | l = fib_find_node(t, key); | 1159 | l = fib_find_node(t, key); |
1166 | fa = NULL; | 1160 | fa = NULL; |
@@ -1185,10 +1179,10 @@ fn_trie_insert(struct fib_table *tb, struct rtmsg *r, struct kern_rta *rta, | |||
1185 | struct fib_alias *fa_orig; | 1179 | struct fib_alias *fa_orig; |
1186 | 1180 | ||
1187 | err = -EEXIST; | 1181 | err = -EEXIST; |
1188 | if (nlhdr->nlmsg_flags & NLM_F_EXCL) | 1182 | if (cfg->fc_nlflags & NLM_F_EXCL) |
1189 | goto out; | 1183 | goto out; |
1190 | 1184 | ||
1191 | if (nlhdr->nlmsg_flags & NLM_F_REPLACE) { | 1185 | if (cfg->fc_nlflags & NLM_F_REPLACE) { |
1192 | struct fib_info *fi_drop; | 1186 | struct fib_info *fi_drop; |
1193 | u8 state; | 1187 | u8 state; |
1194 | 1188 | ||
@@ -1200,8 +1194,8 @@ fn_trie_insert(struct fib_table *tb, struct rtmsg *r, struct kern_rta *rta, | |||
1200 | fi_drop = fa->fa_info; | 1194 | fi_drop = fa->fa_info; |
1201 | new_fa->fa_tos = fa->fa_tos; | 1195 | new_fa->fa_tos = fa->fa_tos; |
1202 | new_fa->fa_info = fi; | 1196 | new_fa->fa_info = fi; |
1203 | new_fa->fa_type = type; | 1197 | new_fa->fa_type = cfg->fc_type; |
1204 | new_fa->fa_scope = r->rtm_scope; | 1198 | new_fa->fa_scope = cfg->fc_scope; |
1205 | state = fa->fa_state; | 1199 | state = fa->fa_state; |
1206 | new_fa->fa_state &= ~FA_S_ACCESSED; | 1200 | new_fa->fa_state &= ~FA_S_ACCESSED; |
1207 | 1201 | ||
@@ -1224,17 +1218,17 @@ fn_trie_insert(struct fib_table *tb, struct rtmsg *r, struct kern_rta *rta, | |||
1224 | break; | 1218 | break; |
1225 | if (fa->fa_info->fib_priority != fi->fib_priority) | 1219 | if (fa->fa_info->fib_priority != fi->fib_priority) |
1226 | break; | 1220 | break; |
1227 | if (fa->fa_type == type && | 1221 | if (fa->fa_type == cfg->fc_type && |
1228 | fa->fa_scope == r->rtm_scope && | 1222 | fa->fa_scope == cfg->fc_scope && |
1229 | fa->fa_info == fi) { | 1223 | fa->fa_info == fi) { |
1230 | goto out; | 1224 | goto out; |
1231 | } | 1225 | } |
1232 | } | 1226 | } |
1233 | if (!(nlhdr->nlmsg_flags & NLM_F_APPEND)) | 1227 | if (!(cfg->fc_nlflags & NLM_F_APPEND)) |
1234 | fa = fa_orig; | 1228 | fa = fa_orig; |
1235 | } | 1229 | } |
1236 | err = -ENOENT; | 1230 | err = -ENOENT; |
1237 | if (!(nlhdr->nlmsg_flags & NLM_F_CREATE)) | 1231 | if (!(cfg->fc_nlflags & NLM_F_CREATE)) |
1238 | goto out; | 1232 | goto out; |
1239 | 1233 | ||
1240 | err = -ENOBUFS; | 1234 | err = -ENOBUFS; |
@@ -1244,8 +1238,8 @@ fn_trie_insert(struct fib_table *tb, struct rtmsg *r, struct kern_rta *rta, | |||
1244 | 1238 | ||
1245 | new_fa->fa_info = fi; | 1239 | new_fa->fa_info = fi; |
1246 | new_fa->fa_tos = tos; | 1240 | new_fa->fa_tos = tos; |
1247 | new_fa->fa_type = type; | 1241 | new_fa->fa_type = cfg->fc_type; |
1248 | new_fa->fa_scope = r->rtm_scope; | 1242 | new_fa->fa_scope = cfg->fc_scope; |
1249 | new_fa->fa_state = 0; | 1243 | new_fa->fa_state = 0; |
1250 | /* | 1244 | /* |
1251 | * Insert new entry to the list. | 1245 | * Insert new entry to the list. |
@@ -1262,7 +1256,8 @@ fn_trie_insert(struct fib_table *tb, struct rtmsg *r, struct kern_rta *rta, | |||
1262 | (fa ? &fa->fa_list : fa_head)); | 1256 | (fa ? &fa->fa_list : fa_head)); |
1263 | 1257 | ||
1264 | rt_cache_flush(-1); | 1258 | rt_cache_flush(-1); |
1265 | rtmsg_fib(RTM_NEWROUTE, htonl(key), new_fa, plen, tb->tb_id, nlhdr, req); | 1259 | rtmsg_fib(RTM_NEWROUTE, htonl(key), new_fa, plen, tb->tb_id, |
1260 | &cfg->fc_nlinfo); | ||
1266 | succeeded: | 1261 | succeeded: |
1267 | return 0; | 1262 | return 0; |
1268 | 1263 | ||
@@ -1548,28 +1543,21 @@ static int trie_leaf_remove(struct trie *t, t_key key) | |||
1548 | return 1; | 1543 | return 1; |
1549 | } | 1544 | } |
1550 | 1545 | ||
1551 | static int | 1546 | static int fn_trie_delete(struct fib_table *tb, struct fib_config *cfg) |
1552 | fn_trie_delete(struct fib_table *tb, struct rtmsg *r, struct kern_rta *rta, | ||
1553 | struct nlmsghdr *nlhdr, struct netlink_skb_parms *req) | ||
1554 | { | 1547 | { |
1555 | struct trie *t = (struct trie *) tb->tb_data; | 1548 | struct trie *t = (struct trie *) tb->tb_data; |
1556 | u32 key, mask; | 1549 | u32 key, mask; |
1557 | int plen = r->rtm_dst_len; | 1550 | int plen = cfg->fc_dst_len; |
1558 | u8 tos = r->rtm_tos; | 1551 | u8 tos = cfg->fc_tos; |
1559 | struct fib_alias *fa, *fa_to_delete; | 1552 | struct fib_alias *fa, *fa_to_delete; |
1560 | struct list_head *fa_head; | 1553 | struct list_head *fa_head; |
1561 | struct leaf *l; | 1554 | struct leaf *l; |
1562 | struct leaf_info *li; | 1555 | struct leaf_info *li; |
1563 | 1556 | ||
1564 | |||
1565 | if (plen > 32) | 1557 | if (plen > 32) |
1566 | return -EINVAL; | 1558 | return -EINVAL; |
1567 | 1559 | ||
1568 | key = 0; | 1560 | key = ntohl(cfg->fc_dst); |
1569 | if (rta->rta_dst) | ||
1570 | memcpy(&key, rta->rta_dst, 4); | ||
1571 | |||
1572 | key = ntohl(key); | ||
1573 | mask = ntohl(inet_make_mask(plen)); | 1561 | mask = ntohl(inet_make_mask(plen)); |
1574 | 1562 | ||
1575 | if (key & ~mask) | 1563 | if (key & ~mask) |
@@ -1598,13 +1586,12 @@ fn_trie_delete(struct fib_table *tb, struct rtmsg *r, struct kern_rta *rta, | |||
1598 | if (fa->fa_tos != tos) | 1586 | if (fa->fa_tos != tos) |
1599 | break; | 1587 | break; |
1600 | 1588 | ||
1601 | if ((!r->rtm_type || | 1589 | if ((!cfg->fc_type || fa->fa_type == cfg->fc_type) && |
1602 | fa->fa_type == r->rtm_type) && | 1590 | (cfg->fc_scope == RT_SCOPE_NOWHERE || |
1603 | (r->rtm_scope == RT_SCOPE_NOWHERE || | 1591 | fa->fa_scope == cfg->fc_scope) && |
1604 | fa->fa_scope == r->rtm_scope) && | 1592 | (!cfg->fc_protocol || |
1605 | (!r->rtm_protocol || | 1593 | fi->fib_protocol == cfg->fc_protocol) && |
1606 | fi->fib_protocol == r->rtm_protocol) && | 1594 | fib_nh_match(cfg, fi) == 0) { |
1607 | fib_nh_match(r, nlhdr, rta, fi) == 0) { | ||
1608 | fa_to_delete = fa; | 1595 | fa_to_delete = fa; |
1609 | break; | 1596 | break; |
1610 | } | 1597 | } |
@@ -1614,7 +1601,8 @@ fn_trie_delete(struct fib_table *tb, struct rtmsg *r, struct kern_rta *rta, | |||
1614 | return -ESRCH; | 1601 | return -ESRCH; |
1615 | 1602 | ||
1616 | fa = fa_to_delete; | 1603 | fa = fa_to_delete; |
1617 | rtmsg_fib(RTM_DELROUTE, htonl(key), fa, plen, tb->tb_id, nlhdr, req); | 1604 | rtmsg_fib(RTM_DELROUTE, htonl(key), fa, plen, tb->tb_id, |
1605 | &cfg->fc_nlinfo); | ||
1618 | 1606 | ||
1619 | l = fib_find_node(t, key); | 1607 | l = fib_find_node(t, key); |
1620 | li = find_leaf_info(l, plen); | 1608 | li = find_leaf_info(l, plen); |
@@ -1848,7 +1836,7 @@ static int fn_trie_dump_fa(t_key key, int plen, struct list_head *fah, struct fi | |||
1848 | 1836 | ||
1849 | u32 xkey = htonl(key); | 1837 | u32 xkey = htonl(key); |
1850 | 1838 | ||
1851 | s_i = cb->args[3]; | 1839 | s_i = cb->args[4]; |
1852 | i = 0; | 1840 | i = 0; |
1853 | 1841 | ||
1854 | /* rcu_read_lock is hold by caller */ | 1842 | /* rcu_read_lock is hold by caller */ |
@@ -1866,16 +1854,16 @@ static int fn_trie_dump_fa(t_key key, int plen, struct list_head *fah, struct fi | |||
1866 | tb->tb_id, | 1854 | tb->tb_id, |
1867 | fa->fa_type, | 1855 | fa->fa_type, |
1868 | fa->fa_scope, | 1856 | fa->fa_scope, |
1869 | &xkey, | 1857 | xkey, |
1870 | plen, | 1858 | plen, |
1871 | fa->fa_tos, | 1859 | fa->fa_tos, |
1872 | fa->fa_info, 0) < 0) { | 1860 | fa->fa_info, 0) < 0) { |
1873 | cb->args[3] = i; | 1861 | cb->args[4] = i; |
1874 | return -1; | 1862 | return -1; |
1875 | } | 1863 | } |
1876 | i++; | 1864 | i++; |
1877 | } | 1865 | } |
1878 | cb->args[3] = i; | 1866 | cb->args[4] = i; |
1879 | return skb->len; | 1867 | return skb->len; |
1880 | } | 1868 | } |
1881 | 1869 | ||
@@ -1886,14 +1874,14 @@ static int fn_trie_dump_plen(struct trie *t, int plen, struct fib_table *tb, str | |||
1886 | struct list_head *fa_head; | 1874 | struct list_head *fa_head; |
1887 | struct leaf *l = NULL; | 1875 | struct leaf *l = NULL; |
1888 | 1876 | ||
1889 | s_h = cb->args[2]; | 1877 | s_h = cb->args[3]; |
1890 | 1878 | ||
1891 | for (h = 0; (l = nextleaf(t, l)) != NULL; h++) { | 1879 | for (h = 0; (l = nextleaf(t, l)) != NULL; h++) { |
1892 | if (h < s_h) | 1880 | if (h < s_h) |
1893 | continue; | 1881 | continue; |
1894 | if (h > s_h) | 1882 | if (h > s_h) |
1895 | memset(&cb->args[3], 0, | 1883 | memset(&cb->args[4], 0, |
1896 | sizeof(cb->args) - 3*sizeof(cb->args[0])); | 1884 | sizeof(cb->args) - 4*sizeof(cb->args[0])); |
1897 | 1885 | ||
1898 | fa_head = get_fa_head(l, plen); | 1886 | fa_head = get_fa_head(l, plen); |
1899 | 1887 | ||
@@ -1904,11 +1892,11 @@ static int fn_trie_dump_plen(struct trie *t, int plen, struct fib_table *tb, str | |||
1904 | continue; | 1892 | continue; |
1905 | 1893 | ||
1906 | if (fn_trie_dump_fa(l->key, plen, fa_head, tb, skb, cb)<0) { | 1894 | if (fn_trie_dump_fa(l->key, plen, fa_head, tb, skb, cb)<0) { |
1907 | cb->args[2] = h; | 1895 | cb->args[3] = h; |
1908 | return -1; | 1896 | return -1; |
1909 | } | 1897 | } |
1910 | } | 1898 | } |
1911 | cb->args[2] = h; | 1899 | cb->args[3] = h; |
1912 | return skb->len; | 1900 | return skb->len; |
1913 | } | 1901 | } |
1914 | 1902 | ||
@@ -1917,23 +1905,23 @@ static int fn_trie_dump(struct fib_table *tb, struct sk_buff *skb, struct netlin | |||
1917 | int m, s_m; | 1905 | int m, s_m; |
1918 | struct trie *t = (struct trie *) tb->tb_data; | 1906 | struct trie *t = (struct trie *) tb->tb_data; |
1919 | 1907 | ||
1920 | s_m = cb->args[1]; | 1908 | s_m = cb->args[2]; |
1921 | 1909 | ||
1922 | rcu_read_lock(); | 1910 | rcu_read_lock(); |
1923 | for (m = 0; m <= 32; m++) { | 1911 | for (m = 0; m <= 32; m++) { |
1924 | if (m < s_m) | 1912 | if (m < s_m) |
1925 | continue; | 1913 | continue; |
1926 | if (m > s_m) | 1914 | if (m > s_m) |
1927 | memset(&cb->args[2], 0, | 1915 | memset(&cb->args[3], 0, |
1928 | sizeof(cb->args) - 2*sizeof(cb->args[0])); | 1916 | sizeof(cb->args) - 3*sizeof(cb->args[0])); |
1929 | 1917 | ||
1930 | if (fn_trie_dump_plen(t, 32-m, tb, skb, cb)<0) { | 1918 | if (fn_trie_dump_plen(t, 32-m, tb, skb, cb)<0) { |
1931 | cb->args[1] = m; | 1919 | cb->args[2] = m; |
1932 | goto out; | 1920 | goto out; |
1933 | } | 1921 | } |
1934 | } | 1922 | } |
1935 | rcu_read_unlock(); | 1923 | rcu_read_unlock(); |
1936 | cb->args[1] = m; | 1924 | cb->args[2] = m; |
1937 | return skb->len; | 1925 | return skb->len; |
1938 | out: | 1926 | out: |
1939 | rcu_read_unlock(); | 1927 | rcu_read_unlock(); |
@@ -1943,9 +1931,9 @@ out: | |||
1943 | /* Fix more generic FIB names for init later */ | 1931 | /* Fix more generic FIB names for init later */ |
1944 | 1932 | ||
1945 | #ifdef CONFIG_IP_MULTIPLE_TABLES | 1933 | #ifdef CONFIG_IP_MULTIPLE_TABLES |
1946 | struct fib_table * fib_hash_init(int id) | 1934 | struct fib_table * fib_hash_init(u32 id) |
1947 | #else | 1935 | #else |
1948 | struct fib_table * __init fib_hash_init(int id) | 1936 | struct fib_table * __init fib_hash_init(u32 id) |
1949 | #endif | 1937 | #endif |
1950 | { | 1938 | { |
1951 | struct fib_table *tb; | 1939 | struct fib_table *tb; |
diff --git a/net/ipv4/icmp.c b/net/ipv4/icmp.c index 4c86ac3d882d..c2ad07e48ab4 100644 --- a/net/ipv4/icmp.c +++ b/net/ipv4/icmp.c | |||
@@ -187,11 +187,11 @@ struct icmp_err icmp_err_convert[] = { | |||
187 | }; | 187 | }; |
188 | 188 | ||
189 | /* Control parameters for ECHO replies. */ | 189 | /* Control parameters for ECHO replies. */ |
190 | int sysctl_icmp_echo_ignore_all; | 190 | int sysctl_icmp_echo_ignore_all __read_mostly; |
191 | int sysctl_icmp_echo_ignore_broadcasts = 1; | 191 | int sysctl_icmp_echo_ignore_broadcasts __read_mostly = 1; |
192 | 192 | ||
193 | /* Control parameter - ignore bogus broadcast responses? */ | 193 | /* Control parameter - ignore bogus broadcast responses? */ |
194 | int sysctl_icmp_ignore_bogus_error_responses = 1; | 194 | int sysctl_icmp_ignore_bogus_error_responses __read_mostly = 1; |
195 | 195 | ||
196 | /* | 196 | /* |
197 | * Configurable global rate limit. | 197 | * Configurable global rate limit. |
@@ -205,9 +205,9 @@ int sysctl_icmp_ignore_bogus_error_responses = 1; | |||
205 | * time exceeded (11), parameter problem (12) | 205 | * time exceeded (11), parameter problem (12) |
206 | */ | 206 | */ |
207 | 207 | ||
208 | int sysctl_icmp_ratelimit = 1 * HZ; | 208 | int sysctl_icmp_ratelimit __read_mostly = 1 * HZ; |
209 | int sysctl_icmp_ratemask = 0x1818; | 209 | int sysctl_icmp_ratemask __read_mostly = 0x1818; |
210 | int sysctl_icmp_errors_use_inbound_ifaddr; | 210 | int sysctl_icmp_errors_use_inbound_ifaddr __read_mostly; |
211 | 211 | ||
212 | /* | 212 | /* |
213 | * ICMP control array. This specifies what to do with each ICMP. | 213 | * ICMP control array. This specifies what to do with each ICMP. |
@@ -406,6 +406,7 @@ static void icmp_reply(struct icmp_bxm *icmp_param, struct sk_buff *skb) | |||
406 | .saddr = rt->rt_spec_dst, | 406 | .saddr = rt->rt_spec_dst, |
407 | .tos = RT_TOS(skb->nh.iph->tos) } }, | 407 | .tos = RT_TOS(skb->nh.iph->tos) } }, |
408 | .proto = IPPROTO_ICMP }; | 408 | .proto = IPPROTO_ICMP }; |
409 | security_skb_classify_flow(skb, &fl); | ||
409 | if (ip_route_output_key(&rt, &fl)) | 410 | if (ip_route_output_key(&rt, &fl)) |
410 | goto out_unlock; | 411 | goto out_unlock; |
411 | } | 412 | } |
@@ -560,6 +561,7 @@ void icmp_send(struct sk_buff *skb_in, int type, int code, u32 info) | |||
560 | } | 561 | } |
561 | } | 562 | } |
562 | }; | 563 | }; |
564 | security_skb_classify_flow(skb_in, &fl); | ||
563 | if (ip_route_output_key(&rt, &fl)) | 565 | if (ip_route_output_key(&rt, &fl)) |
564 | goto out_unlock; | 566 | goto out_unlock; |
565 | } | 567 | } |
@@ -928,7 +930,7 @@ int icmp_rcv(struct sk_buff *skb) | |||
928 | ICMP_INC_STATS_BH(ICMP_MIB_INMSGS); | 930 | ICMP_INC_STATS_BH(ICMP_MIB_INMSGS); |
929 | 931 | ||
930 | switch (skb->ip_summed) { | 932 | switch (skb->ip_summed) { |
931 | case CHECKSUM_HW: | 933 | case CHECKSUM_COMPLETE: |
932 | if (!(u16)csum_fold(skb->csum)) | 934 | if (!(u16)csum_fold(skb->csum)) |
933 | break; | 935 | break; |
934 | /* fall through */ | 936 | /* fall through */ |
diff --git a/net/ipv4/igmp.c b/net/ipv4/igmp.c index 8e8117c19e4d..58be8227b0cb 100644 --- a/net/ipv4/igmp.c +++ b/net/ipv4/igmp.c | |||
@@ -931,7 +931,7 @@ int igmp_rcv(struct sk_buff *skb) | |||
931 | goto drop; | 931 | goto drop; |
932 | 932 | ||
933 | switch (skb->ip_summed) { | 933 | switch (skb->ip_summed) { |
934 | case CHECKSUM_HW: | 934 | case CHECKSUM_COMPLETE: |
935 | if (!(u16)csum_fold(skb->csum)) | 935 | if (!(u16)csum_fold(skb->csum)) |
936 | break; | 936 | break; |
937 | /* fall through */ | 937 | /* fall through */ |
@@ -1397,8 +1397,8 @@ static struct in_device * ip_mc_find_dev(struct ip_mreqn *imr) | |||
1397 | /* | 1397 | /* |
1398 | * Join a socket to a group | 1398 | * Join a socket to a group |
1399 | */ | 1399 | */ |
1400 | int sysctl_igmp_max_memberships = IP_MAX_MEMBERSHIPS; | 1400 | int sysctl_igmp_max_memberships __read_mostly = IP_MAX_MEMBERSHIPS; |
1401 | int sysctl_igmp_max_msf = IP_MAX_MSF; | 1401 | int sysctl_igmp_max_msf __read_mostly = IP_MAX_MSF; |
1402 | 1402 | ||
1403 | 1403 | ||
1404 | static int ip_mc_del1_src(struct ip_mc_list *pmc, int sfmode, | 1404 | static int ip_mc_del1_src(struct ip_mc_list *pmc, int sfmode, |
diff --git a/net/ipv4/inet_connection_sock.c b/net/ipv4/inet_connection_sock.c index e50a1bfd7ccc..07204391d083 100644 --- a/net/ipv4/inet_connection_sock.c +++ b/net/ipv4/inet_connection_sock.c | |||
@@ -327,6 +327,7 @@ struct dst_entry* inet_csk_route_req(struct sock *sk, | |||
327 | { .sport = inet_sk(sk)->sport, | 327 | { .sport = inet_sk(sk)->sport, |
328 | .dport = ireq->rmt_port } } }; | 328 | .dport = ireq->rmt_port } } }; |
329 | 329 | ||
330 | security_req_classify_flow(req, &fl); | ||
330 | if (ip_route_output_flow(&rt, &fl, sk, 0)) { | 331 | if (ip_route_output_flow(&rt, &fl, sk, 0)) { |
331 | IP_INC_STATS_BH(IPSTATS_MIB_OUTNOROUTES); | 332 | IP_INC_STATS_BH(IPSTATS_MIB_OUTNOROUTES); |
332 | return NULL; | 333 | return NULL; |
@@ -509,6 +510,8 @@ struct sock *inet_csk_clone(struct sock *sk, const struct request_sock *req, | |||
509 | 510 | ||
510 | /* Deinitialize accept_queue to trap illegal accesses. */ | 511 | /* Deinitialize accept_queue to trap illegal accesses. */ |
511 | memset(&newicsk->icsk_accept_queue, 0, sizeof(newicsk->icsk_accept_queue)); | 512 | memset(&newicsk->icsk_accept_queue, 0, sizeof(newicsk->icsk_accept_queue)); |
513 | |||
514 | security_inet_csk_clone(newsk, req); | ||
512 | } | 515 | } |
513 | return newsk; | 516 | return newsk; |
514 | } | 517 | } |
diff --git a/net/ipv4/inet_hashtables.c b/net/ipv4/inet_hashtables.c index 95fac5532994..fb296c9a7f3f 100644 --- a/net/ipv4/inet_hashtables.c +++ b/net/ipv4/inet_hashtables.c | |||
@@ -124,8 +124,10 @@ EXPORT_SYMBOL(inet_listen_wlock); | |||
124 | * remote address for the connection. So always assume those are both | 124 | * remote address for the connection. So always assume those are both |
125 | * wildcarded during the search since they can never be otherwise. | 125 | * wildcarded during the search since they can never be otherwise. |
126 | */ | 126 | */ |
127 | struct sock *__inet_lookup_listener(const struct hlist_head *head, const u32 daddr, | 127 | static struct sock *inet_lookup_listener_slow(const struct hlist_head *head, |
128 | const unsigned short hnum, const int dif) | 128 | const u32 daddr, |
129 | const unsigned short hnum, | ||
130 | const int dif) | ||
129 | { | 131 | { |
130 | struct sock *result = NULL, *sk; | 132 | struct sock *result = NULL, *sk; |
131 | const struct hlist_node *node; | 133 | const struct hlist_node *node; |
@@ -159,6 +161,33 @@ struct sock *__inet_lookup_listener(const struct hlist_head *head, const u32 dad | |||
159 | return result; | 161 | return result; |
160 | } | 162 | } |
161 | 163 | ||
164 | /* Optimize the common listener case. */ | ||
165 | struct sock *__inet_lookup_listener(struct inet_hashinfo *hashinfo, | ||
166 | const u32 daddr, const unsigned short hnum, | ||
167 | const int dif) | ||
168 | { | ||
169 | struct sock *sk = NULL; | ||
170 | const struct hlist_head *head; | ||
171 | |||
172 | read_lock(&hashinfo->lhash_lock); | ||
173 | head = &hashinfo->listening_hash[inet_lhashfn(hnum)]; | ||
174 | if (!hlist_empty(head)) { | ||
175 | const struct inet_sock *inet = inet_sk((sk = __sk_head(head))); | ||
176 | |||
177 | if (inet->num == hnum && !sk->sk_node.next && | ||
178 | (!inet->rcv_saddr || inet->rcv_saddr == daddr) && | ||
179 | (sk->sk_family == PF_INET || !ipv6_only_sock(sk)) && | ||
180 | !sk->sk_bound_dev_if) | ||
181 | goto sherry_cache; | ||
182 | sk = inet_lookup_listener_slow(head, daddr, hnum, dif); | ||
183 | } | ||
184 | if (sk) { | ||
185 | sherry_cache: | ||
186 | sock_hold(sk); | ||
187 | } | ||
188 | read_unlock(&hashinfo->lhash_lock); | ||
189 | return sk; | ||
190 | } | ||
162 | EXPORT_SYMBOL_GPL(__inet_lookup_listener); | 191 | EXPORT_SYMBOL_GPL(__inet_lookup_listener); |
163 | 192 | ||
164 | /* called with local bh disabled */ | 193 | /* called with local bh disabled */ |
diff --git a/net/ipv4/inetpeer.c b/net/ipv4/inetpeer.c index 03ff62ebcfeb..a675602ef295 100644 --- a/net/ipv4/inetpeer.c +++ b/net/ipv4/inetpeer.c | |||
@@ -126,12 +126,9 @@ void __init inet_initpeers(void) | |||
126 | 126 | ||
127 | peer_cachep = kmem_cache_create("inet_peer_cache", | 127 | peer_cachep = kmem_cache_create("inet_peer_cache", |
128 | sizeof(struct inet_peer), | 128 | sizeof(struct inet_peer), |
129 | 0, SLAB_HWCACHE_ALIGN, | 129 | 0, SLAB_HWCACHE_ALIGN|SLAB_PANIC, |
130 | NULL, NULL); | 130 | NULL, NULL); |
131 | 131 | ||
132 | if (!peer_cachep) | ||
133 | panic("cannot create inet_peer_cache"); | ||
134 | |||
135 | /* All the timers, started at system startup tend | 132 | /* All the timers, started at system startup tend |
136 | to synchronize. Perturb it a bit. | 133 | to synchronize. Perturb it a bit. |
137 | */ | 134 | */ |
diff --git a/net/ipv4/ip_fragment.c b/net/ipv4/ip_fragment.c index b84b53a47526..165d72859ddf 100644 --- a/net/ipv4/ip_fragment.c +++ b/net/ipv4/ip_fragment.c | |||
@@ -54,15 +54,15 @@ | |||
54 | * even the most extreme cases without allowing an attacker to measurably | 54 | * even the most extreme cases without allowing an attacker to measurably |
55 | * harm machine performance. | 55 | * harm machine performance. |
56 | */ | 56 | */ |
57 | int sysctl_ipfrag_high_thresh = 256*1024; | 57 | int sysctl_ipfrag_high_thresh __read_mostly = 256*1024; |
58 | int sysctl_ipfrag_low_thresh = 192*1024; | 58 | int sysctl_ipfrag_low_thresh __read_mostly = 192*1024; |
59 | 59 | ||
60 | int sysctl_ipfrag_max_dist = 64; | 60 | int sysctl_ipfrag_max_dist __read_mostly = 64; |
61 | 61 | ||
62 | /* Important NOTE! Fragment queue must be destroyed before MSL expires. | 62 | /* Important NOTE! Fragment queue must be destroyed before MSL expires. |
63 | * RFC791 is wrong proposing to prolongate timer each fragment arrival by TTL. | 63 | * RFC791 is wrong proposing to prolongate timer each fragment arrival by TTL. |
64 | */ | 64 | */ |
65 | int sysctl_ipfrag_time = IP_FRAG_TIME; | 65 | int sysctl_ipfrag_time __read_mostly = IP_FRAG_TIME; |
66 | 66 | ||
67 | struct ipfrag_skb_cb | 67 | struct ipfrag_skb_cb |
68 | { | 68 | { |
@@ -130,7 +130,7 @@ static unsigned int ipqhashfn(u16 id, u32 saddr, u32 daddr, u8 prot) | |||
130 | } | 130 | } |
131 | 131 | ||
132 | static struct timer_list ipfrag_secret_timer; | 132 | static struct timer_list ipfrag_secret_timer; |
133 | int sysctl_ipfrag_secret_interval = 10 * 60 * HZ; | 133 | int sysctl_ipfrag_secret_interval __read_mostly = 10 * 60 * HZ; |
134 | 134 | ||
135 | static void ipfrag_secret_rebuild(unsigned long dummy) | 135 | static void ipfrag_secret_rebuild(unsigned long dummy) |
136 | { | 136 | { |
@@ -665,7 +665,7 @@ static struct sk_buff *ip_frag_reasm(struct ipq *qp, struct net_device *dev) | |||
665 | head->len += fp->len; | 665 | head->len += fp->len; |
666 | if (head->ip_summed != fp->ip_summed) | 666 | if (head->ip_summed != fp->ip_summed) |
667 | head->ip_summed = CHECKSUM_NONE; | 667 | head->ip_summed = CHECKSUM_NONE; |
668 | else if (head->ip_summed == CHECKSUM_HW) | 668 | else if (head->ip_summed == CHECKSUM_COMPLETE) |
669 | head->csum = csum_add(head->csum, fp->csum); | 669 | head->csum = csum_add(head->csum, fp->csum); |
670 | head->truesize += fp->truesize; | 670 | head->truesize += fp->truesize; |
671 | atomic_sub(fp->truesize, &ip_frag_mem); | 671 | atomic_sub(fp->truesize, &ip_frag_mem); |
diff --git a/net/ipv4/ip_gre.c b/net/ipv4/ip_gre.c index 0f9b3a31997b..f5fba051df3d 100644 --- a/net/ipv4/ip_gre.c +++ b/net/ipv4/ip_gre.c | |||
@@ -393,7 +393,8 @@ out: | |||
393 | int code = skb->h.icmph->code; | 393 | int code = skb->h.icmph->code; |
394 | int rel_type = 0; | 394 | int rel_type = 0; |
395 | int rel_code = 0; | 395 | int rel_code = 0; |
396 | int rel_info = 0; | 396 | __be32 rel_info = 0; |
397 | __u32 n = 0; | ||
397 | u16 flags; | 398 | u16 flags; |
398 | int grehlen = (iph->ihl<<2) + 4; | 399 | int grehlen = (iph->ihl<<2) + 4; |
399 | struct sk_buff *skb2; | 400 | struct sk_buff *skb2; |
@@ -422,14 +423,16 @@ out: | |||
422 | default: | 423 | default: |
423 | return; | 424 | return; |
424 | case ICMP_PARAMETERPROB: | 425 | case ICMP_PARAMETERPROB: |
425 | if (skb->h.icmph->un.gateway < (iph->ihl<<2)) | 426 | n = ntohl(skb->h.icmph->un.gateway) >> 24; |
427 | if (n < (iph->ihl<<2)) | ||
426 | return; | 428 | return; |
427 | 429 | ||
428 | /* So... This guy found something strange INSIDE encapsulated | 430 | /* So... This guy found something strange INSIDE encapsulated |
429 | packet. Well, he is fool, but what can we do ? | 431 | packet. Well, he is fool, but what can we do ? |
430 | */ | 432 | */ |
431 | rel_type = ICMP_PARAMETERPROB; | 433 | rel_type = ICMP_PARAMETERPROB; |
432 | rel_info = skb->h.icmph->un.gateway - grehlen; | 434 | n -= grehlen; |
435 | rel_info = htonl(n << 24); | ||
433 | break; | 436 | break; |
434 | 437 | ||
435 | case ICMP_DEST_UNREACH: | 438 | case ICMP_DEST_UNREACH: |
@@ -440,13 +443,14 @@ out: | |||
440 | return; | 443 | return; |
441 | case ICMP_FRAG_NEEDED: | 444 | case ICMP_FRAG_NEEDED: |
442 | /* And it is the only really necessary thing :-) */ | 445 | /* And it is the only really necessary thing :-) */ |
443 | rel_info = ntohs(skb->h.icmph->un.frag.mtu); | 446 | n = ntohs(skb->h.icmph->un.frag.mtu); |
444 | if (rel_info < grehlen+68) | 447 | if (n < grehlen+68) |
445 | return; | 448 | return; |
446 | rel_info -= grehlen; | 449 | n -= grehlen; |
447 | /* BSD 4.2 MORE DOES NOT EXIST IN NATURE. */ | 450 | /* BSD 4.2 MORE DOES NOT EXIST IN NATURE. */ |
448 | if (rel_info > ntohs(eiph->tot_len)) | 451 | if (n > ntohs(eiph->tot_len)) |
449 | return; | 452 | return; |
453 | rel_info = htonl(n); | ||
450 | break; | 454 | break; |
451 | default: | 455 | default: |
452 | /* All others are translated to HOST_UNREACH. | 456 | /* All others are translated to HOST_UNREACH. |
@@ -508,12 +512,11 @@ out: | |||
508 | 512 | ||
509 | /* change mtu on this route */ | 513 | /* change mtu on this route */ |
510 | if (type == ICMP_DEST_UNREACH && code == ICMP_FRAG_NEEDED) { | 514 | if (type == ICMP_DEST_UNREACH && code == ICMP_FRAG_NEEDED) { |
511 | if (rel_info > dst_mtu(skb2->dst)) { | 515 | if (n > dst_mtu(skb2->dst)) { |
512 | kfree_skb(skb2); | 516 | kfree_skb(skb2); |
513 | return; | 517 | return; |
514 | } | 518 | } |
515 | skb2->dst->ops->update_pmtu(skb2->dst, rel_info); | 519 | skb2->dst->ops->update_pmtu(skb2->dst, n); |
516 | rel_info = htonl(rel_info); | ||
517 | } else if (type == ICMP_TIME_EXCEEDED) { | 520 | } else if (type == ICMP_TIME_EXCEEDED) { |
518 | struct ip_tunnel *t = netdev_priv(skb2->dev); | 521 | struct ip_tunnel *t = netdev_priv(skb2->dev); |
519 | if (t->parms.iph.ttl) { | 522 | if (t->parms.iph.ttl) { |
@@ -576,7 +579,7 @@ static int ipgre_rcv(struct sk_buff *skb) | |||
576 | 579 | ||
577 | if (flags&GRE_CSUM) { | 580 | if (flags&GRE_CSUM) { |
578 | switch (skb->ip_summed) { | 581 | switch (skb->ip_summed) { |
579 | case CHECKSUM_HW: | 582 | case CHECKSUM_COMPLETE: |
580 | csum = (u16)csum_fold(skb->csum); | 583 | csum = (u16)csum_fold(skb->csum); |
581 | if (!csum) | 584 | if (!csum) |
582 | break; | 585 | break; |
@@ -584,7 +587,7 @@ static int ipgre_rcv(struct sk_buff *skb) | |||
584 | case CHECKSUM_NONE: | 587 | case CHECKSUM_NONE: |
585 | skb->csum = 0; | 588 | skb->csum = 0; |
586 | csum = __skb_checksum_complete(skb); | 589 | csum = __skb_checksum_complete(skb); |
587 | skb->ip_summed = CHECKSUM_HW; | 590 | skb->ip_summed = CHECKSUM_COMPLETE; |
588 | } | 591 | } |
589 | offset += 4; | 592 | offset += 4; |
590 | } | 593 | } |
diff --git a/net/ipv4/ip_options.c b/net/ipv4/ip_options.c index 406056edc02b..e7437c091326 100644 --- a/net/ipv4/ip_options.c +++ b/net/ipv4/ip_options.c | |||
@@ -24,6 +24,7 @@ | |||
24 | #include <net/ip.h> | 24 | #include <net/ip.h> |
25 | #include <net/icmp.h> | 25 | #include <net/icmp.h> |
26 | #include <net/route.h> | 26 | #include <net/route.h> |
27 | #include <net/cipso_ipv4.h> | ||
27 | 28 | ||
28 | /* | 29 | /* |
29 | * Write options to IP header, record destination address to | 30 | * Write options to IP header, record destination address to |
@@ -194,6 +195,13 @@ int ip_options_echo(struct ip_options * dopt, struct sk_buff * skb) | |||
194 | dopt->is_strictroute = sopt->is_strictroute; | 195 | dopt->is_strictroute = sopt->is_strictroute; |
195 | } | 196 | } |
196 | } | 197 | } |
198 | if (sopt->cipso) { | ||
199 | optlen = sptr[sopt->cipso+1]; | ||
200 | dopt->cipso = dopt->optlen+sizeof(struct iphdr); | ||
201 | memcpy(dptr, sptr+sopt->cipso, optlen); | ||
202 | dptr += optlen; | ||
203 | dopt->optlen += optlen; | ||
204 | } | ||
197 | while (dopt->optlen & 3) { | 205 | while (dopt->optlen & 3) { |
198 | *dptr++ = IPOPT_END; | 206 | *dptr++ = IPOPT_END; |
199 | dopt->optlen++; | 207 | dopt->optlen++; |
@@ -434,6 +442,17 @@ int ip_options_compile(struct ip_options * opt, struct sk_buff * skb) | |||
434 | if (optptr[2] == 0 && optptr[3] == 0) | 442 | if (optptr[2] == 0 && optptr[3] == 0) |
435 | opt->router_alert = optptr - iph; | 443 | opt->router_alert = optptr - iph; |
436 | break; | 444 | break; |
445 | case IPOPT_CIPSO: | ||
446 | if (opt->cipso) { | ||
447 | pp_ptr = optptr; | ||
448 | goto error; | ||
449 | } | ||
450 | opt->cipso = optptr - iph; | ||
451 | if (cipso_v4_validate(&optptr)) { | ||
452 | pp_ptr = optptr; | ||
453 | goto error; | ||
454 | } | ||
455 | break; | ||
437 | case IPOPT_SEC: | 456 | case IPOPT_SEC: |
438 | case IPOPT_SID: | 457 | case IPOPT_SID: |
439 | default: | 458 | default: |
@@ -506,7 +525,6 @@ static int ip_options_get_finish(struct ip_options **optp, | |||
506 | opt->__data[optlen++] = IPOPT_END; | 525 | opt->__data[optlen++] = IPOPT_END; |
507 | opt->optlen = optlen; | 526 | opt->optlen = optlen; |
508 | opt->is_data = 1; | 527 | opt->is_data = 1; |
509 | opt->is_setbyuser = 1; | ||
510 | if (optlen && ip_options_compile(opt, NULL)) { | 528 | if (optlen && ip_options_compile(opt, NULL)) { |
511 | kfree(opt); | 529 | kfree(opt); |
512 | return -EINVAL; | 530 | return -EINVAL; |
diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c index a2ede167e045..97aee76fb746 100644 --- a/net/ipv4/ip_output.c +++ b/net/ipv4/ip_output.c | |||
@@ -83,7 +83,7 @@ | |||
83 | #include <linux/netlink.h> | 83 | #include <linux/netlink.h> |
84 | #include <linux/tcp.h> | 84 | #include <linux/tcp.h> |
85 | 85 | ||
86 | int sysctl_ip_default_ttl = IPDEFTTL; | 86 | int sysctl_ip_default_ttl __read_mostly = IPDEFTTL; |
87 | 87 | ||
88 | /* Generate a checksum for an outgoing IP datagram. */ | 88 | /* Generate a checksum for an outgoing IP datagram. */ |
89 | __inline__ void ip_send_check(struct iphdr *iph) | 89 | __inline__ void ip_send_check(struct iphdr *iph) |
@@ -328,6 +328,7 @@ int ip_queue_xmit(struct sk_buff *skb, int ipfragok) | |||
328 | * keep trying until route appears or the connection times | 328 | * keep trying until route appears or the connection times |
329 | * itself out. | 329 | * itself out. |
330 | */ | 330 | */ |
331 | security_sk_classify_flow(sk, &fl); | ||
331 | if (ip_route_output_flow(&rt, &fl, sk, 0)) | 332 | if (ip_route_output_flow(&rt, &fl, sk, 0)) |
332 | goto no_route; | 333 | goto no_route; |
333 | } | 334 | } |
@@ -425,7 +426,7 @@ int ip_fragment(struct sk_buff *skb, int (*output)(struct sk_buff*)) | |||
425 | int ptr; | 426 | int ptr; |
426 | struct net_device *dev; | 427 | struct net_device *dev; |
427 | struct sk_buff *skb2; | 428 | struct sk_buff *skb2; |
428 | unsigned int mtu, hlen, left, len, ll_rs; | 429 | unsigned int mtu, hlen, left, len, ll_rs, pad; |
429 | int offset; | 430 | int offset; |
430 | __be16 not_last_frag; | 431 | __be16 not_last_frag; |
431 | struct rtable *rt = (struct rtable*)skb->dst; | 432 | struct rtable *rt = (struct rtable*)skb->dst; |
@@ -555,14 +556,13 @@ slow_path: | |||
555 | left = skb->len - hlen; /* Space per frame */ | 556 | left = skb->len - hlen; /* Space per frame */ |
556 | ptr = raw + hlen; /* Where to start from */ | 557 | ptr = raw + hlen; /* Where to start from */ |
557 | 558 | ||
558 | #ifdef CONFIG_BRIDGE_NETFILTER | ||
559 | /* for bridged IP traffic encapsulated inside f.e. a vlan header, | 559 | /* for bridged IP traffic encapsulated inside f.e. a vlan header, |
560 | * we need to make room for the encapsulating header */ | 560 | * we need to make room for the encapsulating header |
561 | ll_rs = LL_RESERVED_SPACE_EXTRA(rt->u.dst.dev, nf_bridge_pad(skb)); | 561 | */ |
562 | mtu -= nf_bridge_pad(skb); | 562 | pad = nf_bridge_pad(skb); |
563 | #else | 563 | ll_rs = LL_RESERVED_SPACE_EXTRA(rt->u.dst.dev, pad); |
564 | ll_rs = LL_RESERVED_SPACE(rt->u.dst.dev); | 564 | mtu -= pad; |
565 | #endif | 565 | |
566 | /* | 566 | /* |
567 | * Fragment the datagram. | 567 | * Fragment the datagram. |
568 | */ | 568 | */ |
@@ -679,7 +679,7 @@ ip_generic_getfrag(void *from, char *to, int offset, int len, int odd, struct sk | |||
679 | { | 679 | { |
680 | struct iovec *iov = from; | 680 | struct iovec *iov = from; |
681 | 681 | ||
682 | if (skb->ip_summed == CHECKSUM_HW) { | 682 | if (skb->ip_summed == CHECKSUM_PARTIAL) { |
683 | if (memcpy_fromiovecend(to, iov, offset, len) < 0) | 683 | if (memcpy_fromiovecend(to, iov, offset, len) < 0) |
684 | return -EFAULT; | 684 | return -EFAULT; |
685 | } else { | 685 | } else { |
@@ -735,7 +735,7 @@ static inline int ip_ufo_append_data(struct sock *sk, | |||
735 | /* initialize protocol header pointer */ | 735 | /* initialize protocol header pointer */ |
736 | skb->h.raw = skb->data + fragheaderlen; | 736 | skb->h.raw = skb->data + fragheaderlen; |
737 | 737 | ||
738 | skb->ip_summed = CHECKSUM_HW; | 738 | skb->ip_summed = CHECKSUM_PARTIAL; |
739 | skb->csum = 0; | 739 | skb->csum = 0; |
740 | sk->sk_sndmsg_off = 0; | 740 | sk->sk_sndmsg_off = 0; |
741 | } | 741 | } |
@@ -843,7 +843,7 @@ int ip_append_data(struct sock *sk, | |||
843 | length + fragheaderlen <= mtu && | 843 | length + fragheaderlen <= mtu && |
844 | rt->u.dst.dev->features & NETIF_F_ALL_CSUM && | 844 | rt->u.dst.dev->features & NETIF_F_ALL_CSUM && |
845 | !exthdrlen) | 845 | !exthdrlen) |
846 | csummode = CHECKSUM_HW; | 846 | csummode = CHECKSUM_PARTIAL; |
847 | 847 | ||
848 | inet->cork.length += length; | 848 | inet->cork.length += length; |
849 | if (((length > mtu) && (sk->sk_protocol == IPPROTO_UDP)) && | 849 | if (((length > mtu) && (sk->sk_protocol == IPPROTO_UDP)) && |
@@ -1366,6 +1366,7 @@ void ip_send_reply(struct sock *sk, struct sk_buff *skb, struct ip_reply_arg *ar | |||
1366 | { .sport = skb->h.th->dest, | 1366 | { .sport = skb->h.th->dest, |
1367 | .dport = skb->h.th->source } }, | 1367 | .dport = skb->h.th->source } }, |
1368 | .proto = sk->sk_protocol }; | 1368 | .proto = sk->sk_protocol }; |
1369 | security_skb_classify_flow(skb, &fl); | ||
1369 | if (ip_route_output_key(&rt, &fl)) | 1370 | if (ip_route_output_key(&rt, &fl)) |
1370 | return; | 1371 | return; |
1371 | } | 1372 | } |
diff --git a/net/ipv4/ipcomp.c b/net/ipv4/ipcomp.c index 5bb9c9f03fb6..17342430a843 100644 --- a/net/ipv4/ipcomp.c +++ b/net/ipv4/ipcomp.c | |||
@@ -176,7 +176,7 @@ static int ipcomp_output(struct xfrm_state *x, struct sk_buff *skb) | |||
176 | return 0; | 176 | return 0; |
177 | 177 | ||
178 | out_ok: | 178 | out_ok: |
179 | if (x->props.mode) | 179 | if (x->props.mode == XFRM_MODE_TUNNEL) |
180 | ip_send_check(iph); | 180 | ip_send_check(iph); |
181 | return 0; | 181 | return 0; |
182 | } | 182 | } |
@@ -216,7 +216,7 @@ static struct xfrm_state *ipcomp_tunnel_create(struct xfrm_state *x) | |||
216 | t->id.daddr.a4 = x->id.daddr.a4; | 216 | t->id.daddr.a4 = x->id.daddr.a4; |
217 | memcpy(&t->sel, &x->sel, sizeof(t->sel)); | 217 | memcpy(&t->sel, &x->sel, sizeof(t->sel)); |
218 | t->props.family = AF_INET; | 218 | t->props.family = AF_INET; |
219 | t->props.mode = 1; | 219 | t->props.mode = XFRM_MODE_TUNNEL; |
220 | t->props.saddr.a4 = x->props.saddr.a4; | 220 | t->props.saddr.a4 = x->props.saddr.a4; |
221 | t->props.flags = x->props.flags; | 221 | t->props.flags = x->props.flags; |
222 | 222 | ||
@@ -416,7 +416,7 @@ static int ipcomp_init_state(struct xfrm_state *x) | |||
416 | goto out; | 416 | goto out; |
417 | 417 | ||
418 | x->props.header_len = 0; | 418 | x->props.header_len = 0; |
419 | if (x->props.mode) | 419 | if (x->props.mode == XFRM_MODE_TUNNEL) |
420 | x->props.header_len += sizeof(struct iphdr); | 420 | x->props.header_len += sizeof(struct iphdr); |
421 | 421 | ||
422 | mutex_lock(&ipcomp_resource_mutex); | 422 | mutex_lock(&ipcomp_resource_mutex); |
@@ -428,7 +428,7 @@ static int ipcomp_init_state(struct xfrm_state *x) | |||
428 | goto error; | 428 | goto error; |
429 | mutex_unlock(&ipcomp_resource_mutex); | 429 | mutex_unlock(&ipcomp_resource_mutex); |
430 | 430 | ||
431 | if (x->props.mode) { | 431 | if (x->props.mode == XFRM_MODE_TUNNEL) { |
432 | err = ipcomp_tunnel_attach(x); | 432 | err = ipcomp_tunnel_attach(x); |
433 | if (err) | 433 | if (err) |
434 | goto error_tunnel; | 434 | goto error_tunnel; |
diff --git a/net/ipv4/ipconfig.c b/net/ipv4/ipconfig.c index cb8a92f18ef6..1fbb38415b19 100644 --- a/net/ipv4/ipconfig.c +++ b/net/ipv4/ipconfig.c | |||
@@ -31,7 +31,6 @@ | |||
31 | * -- Josef Siemes <jsiemes@web.de>, Aug 2002 | 31 | * -- Josef Siemes <jsiemes@web.de>, Aug 2002 |
32 | */ | 32 | */ |
33 | 33 | ||
34 | #include <linux/config.h> | ||
35 | #include <linux/types.h> | 34 | #include <linux/types.h> |
36 | #include <linux/string.h> | 35 | #include <linux/string.h> |
37 | #include <linux/kernel.h> | 36 | #include <linux/kernel.h> |
diff --git a/net/ipv4/ipip.c b/net/ipv4/ipip.c index 76ab50b0d6ef..0c4556529228 100644 --- a/net/ipv4/ipip.c +++ b/net/ipv4/ipip.c | |||
@@ -341,7 +341,8 @@ out: | |||
341 | int code = skb->h.icmph->code; | 341 | int code = skb->h.icmph->code; |
342 | int rel_type = 0; | 342 | int rel_type = 0; |
343 | int rel_code = 0; | 343 | int rel_code = 0; |
344 | int rel_info = 0; | 344 | __be32 rel_info = 0; |
345 | __u32 n = 0; | ||
345 | struct sk_buff *skb2; | 346 | struct sk_buff *skb2; |
346 | struct flowi fl; | 347 | struct flowi fl; |
347 | struct rtable *rt; | 348 | struct rtable *rt; |
@@ -354,14 +355,15 @@ out: | |||
354 | default: | 355 | default: |
355 | return 0; | 356 | return 0; |
356 | case ICMP_PARAMETERPROB: | 357 | case ICMP_PARAMETERPROB: |
357 | if (skb->h.icmph->un.gateway < hlen) | 358 | n = ntohl(skb->h.icmph->un.gateway) >> 24; |
359 | if (n < hlen) | ||
358 | return 0; | 360 | return 0; |
359 | 361 | ||
360 | /* So... This guy found something strange INSIDE encapsulated | 362 | /* So... This guy found something strange INSIDE encapsulated |
361 | packet. Well, he is fool, but what can we do ? | 363 | packet. Well, he is fool, but what can we do ? |
362 | */ | 364 | */ |
363 | rel_type = ICMP_PARAMETERPROB; | 365 | rel_type = ICMP_PARAMETERPROB; |
364 | rel_info = skb->h.icmph->un.gateway - hlen; | 366 | rel_info = htonl((n - hlen) << 24); |
365 | break; | 367 | break; |
366 | 368 | ||
367 | case ICMP_DEST_UNREACH: | 369 | case ICMP_DEST_UNREACH: |
@@ -372,13 +374,14 @@ out: | |||
372 | return 0; | 374 | return 0; |
373 | case ICMP_FRAG_NEEDED: | 375 | case ICMP_FRAG_NEEDED: |
374 | /* And it is the only really necessary thing :-) */ | 376 | /* And it is the only really necessary thing :-) */ |
375 | rel_info = ntohs(skb->h.icmph->un.frag.mtu); | 377 | n = ntohs(skb->h.icmph->un.frag.mtu); |
376 | if (rel_info < hlen+68) | 378 | if (n < hlen+68) |
377 | return 0; | 379 | return 0; |
378 | rel_info -= hlen; | 380 | n -= hlen; |
379 | /* BSD 4.2 MORE DOES NOT EXIST IN NATURE. */ | 381 | /* BSD 4.2 MORE DOES NOT EXIST IN NATURE. */ |
380 | if (rel_info > ntohs(eiph->tot_len)) | 382 | if (n > ntohs(eiph->tot_len)) |
381 | return 0; | 383 | return 0; |
384 | rel_info = htonl(n); | ||
382 | break; | 385 | break; |
383 | default: | 386 | default: |
384 | /* All others are translated to HOST_UNREACH. | 387 | /* All others are translated to HOST_UNREACH. |
@@ -440,12 +443,11 @@ out: | |||
440 | 443 | ||
441 | /* change mtu on this route */ | 444 | /* change mtu on this route */ |
442 | if (type == ICMP_DEST_UNREACH && code == ICMP_FRAG_NEEDED) { | 445 | if (type == ICMP_DEST_UNREACH && code == ICMP_FRAG_NEEDED) { |
443 | if (rel_info > dst_mtu(skb2->dst)) { | 446 | if (n > dst_mtu(skb2->dst)) { |
444 | kfree_skb(skb2); | 447 | kfree_skb(skb2); |
445 | return 0; | 448 | return 0; |
446 | } | 449 | } |
447 | skb2->dst->ops->update_pmtu(skb2->dst, rel_info); | 450 | skb2->dst->ops->update_pmtu(skb2->dst, n); |
448 | rel_info = htonl(rel_info); | ||
449 | } else if (type == ICMP_TIME_EXCEEDED) { | 451 | } else if (type == ICMP_TIME_EXCEEDED) { |
450 | struct ip_tunnel *t = netdev_priv(skb2->dev); | 452 | struct ip_tunnel *t = netdev_priv(skb2->dev); |
451 | if (t->parms.iph.ttl) { | 453 | if (t->parms.iph.ttl) { |
diff --git a/net/ipv4/ipmr.c b/net/ipv4/ipmr.c index 85893eef6b16..ba49588da242 100644 --- a/net/ipv4/ipmr.c +++ b/net/ipv4/ipmr.c | |||
@@ -312,7 +312,8 @@ static void ipmr_destroy_unres(struct mfc_cache *c) | |||
312 | e = NLMSG_DATA(nlh); | 312 | e = NLMSG_DATA(nlh); |
313 | e->error = -ETIMEDOUT; | 313 | e->error = -ETIMEDOUT; |
314 | memset(&e->msg, 0, sizeof(e->msg)); | 314 | memset(&e->msg, 0, sizeof(e->msg)); |
315 | netlink_unicast(rtnl, skb, NETLINK_CB(skb).dst_pid, MSG_DONTWAIT); | 315 | |
316 | rtnl_unicast(skb, NETLINK_CB(skb).pid); | ||
316 | } else | 317 | } else |
317 | kfree_skb(skb); | 318 | kfree_skb(skb); |
318 | } | 319 | } |
@@ -512,7 +513,6 @@ static void ipmr_cache_resolve(struct mfc_cache *uc, struct mfc_cache *c) | |||
512 | 513 | ||
513 | while((skb=__skb_dequeue(&uc->mfc_un.unres.unresolved))) { | 514 | while((skb=__skb_dequeue(&uc->mfc_un.unres.unresolved))) { |
514 | if (skb->nh.iph->version == 0) { | 515 | if (skb->nh.iph->version == 0) { |
515 | int err; | ||
516 | struct nlmsghdr *nlh = (struct nlmsghdr *)skb_pull(skb, sizeof(struct iphdr)); | 516 | struct nlmsghdr *nlh = (struct nlmsghdr *)skb_pull(skb, sizeof(struct iphdr)); |
517 | 517 | ||
518 | if (ipmr_fill_mroute(skb, c, NLMSG_DATA(nlh)) > 0) { | 518 | if (ipmr_fill_mroute(skb, c, NLMSG_DATA(nlh)) > 0) { |
@@ -525,7 +525,8 @@ static void ipmr_cache_resolve(struct mfc_cache *uc, struct mfc_cache *c) | |||
525 | e->error = -EMSGSIZE; | 525 | e->error = -EMSGSIZE; |
526 | memset(&e->msg, 0, sizeof(e->msg)); | 526 | memset(&e->msg, 0, sizeof(e->msg)); |
527 | } | 527 | } |
528 | err = netlink_unicast(rtnl, skb, NETLINK_CB(skb).dst_pid, MSG_DONTWAIT); | 528 | |
529 | rtnl_unicast(skb, NETLINK_CB(skb).pid); | ||
529 | } else | 530 | } else |
530 | ip_mr_forward(skb, c, 0); | 531 | ip_mr_forward(skb, c, 0); |
531 | } | 532 | } |
@@ -1899,11 +1900,8 @@ void __init ip_mr_init(void) | |||
1899 | { | 1900 | { |
1900 | mrt_cachep = kmem_cache_create("ip_mrt_cache", | 1901 | mrt_cachep = kmem_cache_create("ip_mrt_cache", |
1901 | sizeof(struct mfc_cache), | 1902 | sizeof(struct mfc_cache), |
1902 | 0, SLAB_HWCACHE_ALIGN, | 1903 | 0, SLAB_HWCACHE_ALIGN|SLAB_PANIC, |
1903 | NULL, NULL); | 1904 | NULL, NULL); |
1904 | if (!mrt_cachep) | ||
1905 | panic("cannot allocate ip_mrt_cache"); | ||
1906 | |||
1907 | init_timer(&ipmr_expire_timer); | 1905 | init_timer(&ipmr_expire_timer); |
1908 | ipmr_expire_timer.function=ipmr_expire_process; | 1906 | ipmr_expire_timer.function=ipmr_expire_process; |
1909 | register_netdevice_notifier(&ip_mr_notifier); | 1907 | register_netdevice_notifier(&ip_mr_notifier); |
diff --git a/net/ipv4/ipvs/ip_vs_proto_tcp.c b/net/ipv4/ipvs/ip_vs_proto_tcp.c index bc28b1160a3a..820e8318d10d 100644 --- a/net/ipv4/ipvs/ip_vs_proto_tcp.c +++ b/net/ipv4/ipvs/ip_vs_proto_tcp.c | |||
@@ -151,7 +151,7 @@ tcp_snat_handler(struct sk_buff **pskb, | |||
151 | /* Only port and addr are changed, do fast csum update */ | 151 | /* Only port and addr are changed, do fast csum update */ |
152 | tcp_fast_csum_update(tcph, cp->daddr, cp->vaddr, | 152 | tcp_fast_csum_update(tcph, cp->daddr, cp->vaddr, |
153 | cp->dport, cp->vport); | 153 | cp->dport, cp->vport); |
154 | if ((*pskb)->ip_summed == CHECKSUM_HW) | 154 | if ((*pskb)->ip_summed == CHECKSUM_COMPLETE) |
155 | (*pskb)->ip_summed = CHECKSUM_NONE; | 155 | (*pskb)->ip_summed = CHECKSUM_NONE; |
156 | } else { | 156 | } else { |
157 | /* full checksum calculation */ | 157 | /* full checksum calculation */ |
@@ -204,7 +204,7 @@ tcp_dnat_handler(struct sk_buff **pskb, | |||
204 | /* Only port and addr are changed, do fast csum update */ | 204 | /* Only port and addr are changed, do fast csum update */ |
205 | tcp_fast_csum_update(tcph, cp->vaddr, cp->daddr, | 205 | tcp_fast_csum_update(tcph, cp->vaddr, cp->daddr, |
206 | cp->vport, cp->dport); | 206 | cp->vport, cp->dport); |
207 | if ((*pskb)->ip_summed == CHECKSUM_HW) | 207 | if ((*pskb)->ip_summed == CHECKSUM_COMPLETE) |
208 | (*pskb)->ip_summed = CHECKSUM_NONE; | 208 | (*pskb)->ip_summed = CHECKSUM_NONE; |
209 | } else { | 209 | } else { |
210 | /* full checksum calculation */ | 210 | /* full checksum calculation */ |
@@ -229,7 +229,7 @@ tcp_csum_check(struct sk_buff *skb, struct ip_vs_protocol *pp) | |||
229 | switch (skb->ip_summed) { | 229 | switch (skb->ip_summed) { |
230 | case CHECKSUM_NONE: | 230 | case CHECKSUM_NONE: |
231 | skb->csum = skb_checksum(skb, tcphoff, skb->len - tcphoff, 0); | 231 | skb->csum = skb_checksum(skb, tcphoff, skb->len - tcphoff, 0); |
232 | case CHECKSUM_HW: | 232 | case CHECKSUM_COMPLETE: |
233 | if (csum_tcpudp_magic(skb->nh.iph->saddr, skb->nh.iph->daddr, | 233 | if (csum_tcpudp_magic(skb->nh.iph->saddr, skb->nh.iph->daddr, |
234 | skb->len - tcphoff, | 234 | skb->len - tcphoff, |
235 | skb->nh.iph->protocol, skb->csum)) { | 235 | skb->nh.iph->protocol, skb->csum)) { |
@@ -239,7 +239,7 @@ tcp_csum_check(struct sk_buff *skb, struct ip_vs_protocol *pp) | |||
239 | } | 239 | } |
240 | break; | 240 | break; |
241 | default: | 241 | default: |
242 | /* CHECKSUM_UNNECESSARY */ | 242 | /* No need to checksum. */ |
243 | break; | 243 | break; |
244 | } | 244 | } |
245 | 245 | ||
diff --git a/net/ipv4/ipvs/ip_vs_proto_udp.c b/net/ipv4/ipvs/ip_vs_proto_udp.c index 89d9175d8f28..90c8166c0ec1 100644 --- a/net/ipv4/ipvs/ip_vs_proto_udp.c +++ b/net/ipv4/ipvs/ip_vs_proto_udp.c | |||
@@ -161,7 +161,7 @@ udp_snat_handler(struct sk_buff **pskb, | |||
161 | /* Only port and addr are changed, do fast csum update */ | 161 | /* Only port and addr are changed, do fast csum update */ |
162 | udp_fast_csum_update(udph, cp->daddr, cp->vaddr, | 162 | udp_fast_csum_update(udph, cp->daddr, cp->vaddr, |
163 | cp->dport, cp->vport); | 163 | cp->dport, cp->vport); |
164 | if ((*pskb)->ip_summed == CHECKSUM_HW) | 164 | if ((*pskb)->ip_summed == CHECKSUM_COMPLETE) |
165 | (*pskb)->ip_summed = CHECKSUM_NONE; | 165 | (*pskb)->ip_summed = CHECKSUM_NONE; |
166 | } else { | 166 | } else { |
167 | /* full checksum calculation */ | 167 | /* full checksum calculation */ |
@@ -216,7 +216,7 @@ udp_dnat_handler(struct sk_buff **pskb, | |||
216 | /* Only port and addr are changed, do fast csum update */ | 216 | /* Only port and addr are changed, do fast csum update */ |
217 | udp_fast_csum_update(udph, cp->vaddr, cp->daddr, | 217 | udp_fast_csum_update(udph, cp->vaddr, cp->daddr, |
218 | cp->vport, cp->dport); | 218 | cp->vport, cp->dport); |
219 | if ((*pskb)->ip_summed == CHECKSUM_HW) | 219 | if ((*pskb)->ip_summed == CHECKSUM_COMPLETE) |
220 | (*pskb)->ip_summed = CHECKSUM_NONE; | 220 | (*pskb)->ip_summed = CHECKSUM_NONE; |
221 | } else { | 221 | } else { |
222 | /* full checksum calculation */ | 222 | /* full checksum calculation */ |
@@ -250,7 +250,7 @@ udp_csum_check(struct sk_buff *skb, struct ip_vs_protocol *pp) | |||
250 | case CHECKSUM_NONE: | 250 | case CHECKSUM_NONE: |
251 | skb->csum = skb_checksum(skb, udphoff, | 251 | skb->csum = skb_checksum(skb, udphoff, |
252 | skb->len - udphoff, 0); | 252 | skb->len - udphoff, 0); |
253 | case CHECKSUM_HW: | 253 | case CHECKSUM_COMPLETE: |
254 | if (csum_tcpudp_magic(skb->nh.iph->saddr, | 254 | if (csum_tcpudp_magic(skb->nh.iph->saddr, |
255 | skb->nh.iph->daddr, | 255 | skb->nh.iph->daddr, |
256 | skb->len - udphoff, | 256 | skb->len - udphoff, |
@@ -262,7 +262,7 @@ udp_csum_check(struct sk_buff *skb, struct ip_vs_protocol *pp) | |||
262 | } | 262 | } |
263 | break; | 263 | break; |
264 | default: | 264 | default: |
265 | /* CHECKSUM_UNNECESSARY */ | 265 | /* No need to checksum. */ |
266 | break; | 266 | break; |
267 | } | 267 | } |
268 | } | 268 | } |
diff --git a/net/ipv4/netfilter.c b/net/ipv4/netfilter.c index 6a9e34b794bc..f88347de21a9 100644 --- a/net/ipv4/netfilter.c +++ b/net/ipv4/netfilter.c | |||
@@ -168,7 +168,7 @@ unsigned int nf_ip_checksum(struct sk_buff *skb, unsigned int hook, | |||
168 | unsigned int csum = 0; | 168 | unsigned int csum = 0; |
169 | 169 | ||
170 | switch (skb->ip_summed) { | 170 | switch (skb->ip_summed) { |
171 | case CHECKSUM_HW: | 171 | case CHECKSUM_COMPLETE: |
172 | if (hook != NF_IP_PRE_ROUTING && hook != NF_IP_LOCAL_IN) | 172 | if (hook != NF_IP_PRE_ROUTING && hook != NF_IP_LOCAL_IN) |
173 | break; | 173 | break; |
174 | if ((protocol == 0 && !(u16)csum_fold(skb->csum)) || | 174 | if ((protocol == 0 && !(u16)csum_fold(skb->csum)) || |
diff --git a/net/ipv4/netfilter/Kconfig b/net/ipv4/netfilter/Kconfig index ef0b5aac5838..a55b8ff70ded 100644 --- a/net/ipv4/netfilter/Kconfig +++ b/net/ipv4/netfilter/Kconfig | |||
@@ -278,17 +278,6 @@ config IP_NF_MATCH_ECN | |||
278 | 278 | ||
279 | To compile it as a module, choose M here. If unsure, say N. | 279 | To compile it as a module, choose M here. If unsure, say N. |
280 | 280 | ||
281 | config IP_NF_MATCH_DSCP | ||
282 | tristate "DSCP match support" | ||
283 | depends on IP_NF_IPTABLES | ||
284 | help | ||
285 | This option adds a `DSCP' match, which allows you to match against | ||
286 | the IPv4 header DSCP field (DSCP codepoint). | ||
287 | |||
288 | The DSCP codepoint can have any value between 0x0 and 0x4f. | ||
289 | |||
290 | To compile it as a module, choose M here. If unsure, say N. | ||
291 | |||
292 | config IP_NF_MATCH_AH | 281 | config IP_NF_MATCH_AH |
293 | tristate "AH match support" | 282 | tristate "AH match support" |
294 | depends on IP_NF_IPTABLES | 283 | depends on IP_NF_IPTABLES |
@@ -568,17 +557,6 @@ config IP_NF_TARGET_ECN | |||
568 | 557 | ||
569 | To compile it as a module, choose M here. If unsure, say N. | 558 | To compile it as a module, choose M here. If unsure, say N. |
570 | 559 | ||
571 | config IP_NF_TARGET_DSCP | ||
572 | tristate "DSCP target support" | ||
573 | depends on IP_NF_MANGLE | ||
574 | help | ||
575 | This option adds a `DSCP' match, which allows you to match against | ||
576 | the IPv4 header DSCP field (DSCP codepoint). | ||
577 | |||
578 | The DSCP codepoint can have any value between 0x0 and 0x4f. | ||
579 | |||
580 | To compile it as a module, choose M here. If unsure, say N. | ||
581 | |||
582 | config IP_NF_TARGET_TTL | 560 | config IP_NF_TARGET_TTL |
583 | tristate 'TTL target support' | 561 | tristate 'TTL target support' |
584 | depends on IP_NF_MANGLE | 562 | depends on IP_NF_MANGLE |
diff --git a/net/ipv4/netfilter/Makefile b/net/ipv4/netfilter/Makefile index 3ded4a3af59c..09aaed1a8063 100644 --- a/net/ipv4/netfilter/Makefile +++ b/net/ipv4/netfilter/Makefile | |||
@@ -59,7 +59,6 @@ obj-$(CONFIG_IP_NF_MATCH_OWNER) += ipt_owner.o | |||
59 | obj-$(CONFIG_IP_NF_MATCH_TOS) += ipt_tos.o | 59 | obj-$(CONFIG_IP_NF_MATCH_TOS) += ipt_tos.o |
60 | obj-$(CONFIG_IP_NF_MATCH_RECENT) += ipt_recent.o | 60 | obj-$(CONFIG_IP_NF_MATCH_RECENT) += ipt_recent.o |
61 | obj-$(CONFIG_IP_NF_MATCH_ECN) += ipt_ecn.o | 61 | obj-$(CONFIG_IP_NF_MATCH_ECN) += ipt_ecn.o |
62 | obj-$(CONFIG_IP_NF_MATCH_DSCP) += ipt_dscp.o | ||
63 | obj-$(CONFIG_IP_NF_MATCH_AH) += ipt_ah.o | 62 | obj-$(CONFIG_IP_NF_MATCH_AH) += ipt_ah.o |
64 | obj-$(CONFIG_IP_NF_MATCH_TTL) += ipt_ttl.o | 63 | obj-$(CONFIG_IP_NF_MATCH_TTL) += ipt_ttl.o |
65 | obj-$(CONFIG_IP_NF_MATCH_ADDRTYPE) += ipt_addrtype.o | 64 | obj-$(CONFIG_IP_NF_MATCH_ADDRTYPE) += ipt_addrtype.o |
@@ -68,7 +67,6 @@ obj-$(CONFIG_IP_NF_MATCH_ADDRTYPE) += ipt_addrtype.o | |||
68 | obj-$(CONFIG_IP_NF_TARGET_REJECT) += ipt_REJECT.o | 67 | obj-$(CONFIG_IP_NF_TARGET_REJECT) += ipt_REJECT.o |
69 | obj-$(CONFIG_IP_NF_TARGET_TOS) += ipt_TOS.o | 68 | obj-$(CONFIG_IP_NF_TARGET_TOS) += ipt_TOS.o |
70 | obj-$(CONFIG_IP_NF_TARGET_ECN) += ipt_ECN.o | 69 | obj-$(CONFIG_IP_NF_TARGET_ECN) += ipt_ECN.o |
71 | obj-$(CONFIG_IP_NF_TARGET_DSCP) += ipt_DSCP.o | ||
72 | obj-$(CONFIG_IP_NF_TARGET_MASQUERADE) += ipt_MASQUERADE.o | 70 | obj-$(CONFIG_IP_NF_TARGET_MASQUERADE) += ipt_MASQUERADE.o |
73 | obj-$(CONFIG_IP_NF_TARGET_REDIRECT) += ipt_REDIRECT.o | 71 | obj-$(CONFIG_IP_NF_TARGET_REDIRECT) += ipt_REDIRECT.o |
74 | obj-$(CONFIG_IP_NF_TARGET_NETMAP) += ipt_NETMAP.o | 72 | obj-$(CONFIG_IP_NF_TARGET_NETMAP) += ipt_NETMAP.o |
diff --git a/net/ipv4/netfilter/arp_tables.c b/net/ipv4/netfilter/arp_tables.c index 8d1d7a6e72a5..85f0d73ebfb4 100644 --- a/net/ipv4/netfilter/arp_tables.c +++ b/net/ipv4/netfilter/arp_tables.c | |||
@@ -56,8 +56,6 @@ do { \ | |||
56 | #define ARP_NF_ASSERT(x) | 56 | #define ARP_NF_ASSERT(x) |
57 | #endif | 57 | #endif |
58 | 58 | ||
59 | #include <linux/netfilter_ipv4/listhelp.h> | ||
60 | |||
61 | static inline int arp_devaddr_compare(const struct arpt_devaddr_info *ap, | 59 | static inline int arp_devaddr_compare(const struct arpt_devaddr_info *ap, |
62 | char *hdr_addr, int len) | 60 | char *hdr_addr, int len) |
63 | { | 61 | { |
@@ -208,8 +206,7 @@ static unsigned int arpt_error(struct sk_buff **pskb, | |||
208 | const struct net_device *out, | 206 | const struct net_device *out, |
209 | unsigned int hooknum, | 207 | unsigned int hooknum, |
210 | const struct xt_target *target, | 208 | const struct xt_target *target, |
211 | const void *targinfo, | 209 | const void *targinfo) |
212 | void *userinfo) | ||
213 | { | 210 | { |
214 | if (net_ratelimit()) | 211 | if (net_ratelimit()) |
215 | printk("arp_tables: error: '%s'\n", (char *)targinfo); | 212 | printk("arp_tables: error: '%s'\n", (char *)targinfo); |
@@ -226,8 +223,7 @@ unsigned int arpt_do_table(struct sk_buff **pskb, | |||
226 | unsigned int hook, | 223 | unsigned int hook, |
227 | const struct net_device *in, | 224 | const struct net_device *in, |
228 | const struct net_device *out, | 225 | const struct net_device *out, |
229 | struct arpt_table *table, | 226 | struct arpt_table *table) |
230 | void *userdata) | ||
231 | { | 227 | { |
232 | static const char nulldevname[IFNAMSIZ]; | 228 | static const char nulldevname[IFNAMSIZ]; |
233 | unsigned int verdict = NF_DROP; | 229 | unsigned int verdict = NF_DROP; |
@@ -302,8 +298,7 @@ unsigned int arpt_do_table(struct sk_buff **pskb, | |||
302 | in, out, | 298 | in, out, |
303 | hook, | 299 | hook, |
304 | t->u.kernel.target, | 300 | t->u.kernel.target, |
305 | t->data, | 301 | t->data); |
306 | userdata); | ||
307 | 302 | ||
308 | /* Target might have changed stuff. */ | 303 | /* Target might have changed stuff. */ |
309 | arp = (*pskb)->nh.arph; | 304 | arp = (*pskb)->nh.arph; |
@@ -490,12 +485,10 @@ static inline int check_entry(struct arpt_entry *e, const char *name, unsigned i | |||
490 | if (t->u.kernel.target == &arpt_standard_target) { | 485 | if (t->u.kernel.target == &arpt_standard_target) { |
491 | if (!standard_check(t, size)) { | 486 | if (!standard_check(t, size)) { |
492 | ret = -EINVAL; | 487 | ret = -EINVAL; |
493 | goto out; | 488 | goto err; |
494 | } | 489 | } |
495 | } else if (t->u.kernel.target->checkentry | 490 | } else if (t->u.kernel.target->checkentry |
496 | && !t->u.kernel.target->checkentry(name, e, target, t->data, | 491 | && !t->u.kernel.target->checkentry(name, e, target, t->data, |
497 | t->u.target_size | ||
498 | - sizeof(*t), | ||
499 | e->comefrom)) { | 492 | e->comefrom)) { |
500 | duprintf("arp_tables: check failed for `%s'.\n", | 493 | duprintf("arp_tables: check failed for `%s'.\n", |
501 | t->u.kernel.target->name); | 494 | t->u.kernel.target->name); |
@@ -562,8 +555,7 @@ static inline int cleanup_entry(struct arpt_entry *e, unsigned int *i) | |||
562 | 555 | ||
563 | t = arpt_get_target(e); | 556 | t = arpt_get_target(e); |
564 | if (t->u.kernel.target->destroy) | 557 | if (t->u.kernel.target->destroy) |
565 | t->u.kernel.target->destroy(t->u.kernel.target, t->data, | 558 | t->u.kernel.target->destroy(t->u.kernel.target, t->data); |
566 | t->u.target_size - sizeof(*t)); | ||
567 | module_put(t->u.kernel.target->me); | 559 | module_put(t->u.kernel.target->me); |
568 | return 0; | 560 | return 0; |
569 | } | 561 | } |
diff --git a/net/ipv4/netfilter/arpt_mangle.c b/net/ipv4/netfilter/arpt_mangle.c index a58325c1ceb9..d12b1df252a1 100644 --- a/net/ipv4/netfilter/arpt_mangle.c +++ b/net/ipv4/netfilter/arpt_mangle.c | |||
@@ -11,7 +11,7 @@ static unsigned int | |||
11 | target(struct sk_buff **pskb, | 11 | target(struct sk_buff **pskb, |
12 | const struct net_device *in, const struct net_device *out, | 12 | const struct net_device *in, const struct net_device *out, |
13 | unsigned int hooknum, const struct xt_target *target, | 13 | unsigned int hooknum, const struct xt_target *target, |
14 | const void *targinfo, void *userinfo) | 14 | const void *targinfo) |
15 | { | 15 | { |
16 | const struct arpt_mangle *mangle = targinfo; | 16 | const struct arpt_mangle *mangle = targinfo; |
17 | struct arphdr *arp; | 17 | struct arphdr *arp; |
@@ -67,7 +67,7 @@ target(struct sk_buff **pskb, | |||
67 | 67 | ||
68 | static int | 68 | static int |
69 | checkentry(const char *tablename, const void *e, const struct xt_target *target, | 69 | checkentry(const char *tablename, const void *e, const struct xt_target *target, |
70 | void *targinfo, unsigned int targinfosize, unsigned int hook_mask) | 70 | void *targinfo, unsigned int hook_mask) |
71 | { | 71 | { |
72 | const struct arpt_mangle *mangle = targinfo; | 72 | const struct arpt_mangle *mangle = targinfo; |
73 | 73 | ||
diff --git a/net/ipv4/netfilter/arptable_filter.c b/net/ipv4/netfilter/arptable_filter.c index d7c472faa53b..7edea2a1696c 100644 --- a/net/ipv4/netfilter/arptable_filter.c +++ b/net/ipv4/netfilter/arptable_filter.c | |||
@@ -155,7 +155,7 @@ static unsigned int arpt_hook(unsigned int hook, | |||
155 | const struct net_device *out, | 155 | const struct net_device *out, |
156 | int (*okfn)(struct sk_buff *)) | 156 | int (*okfn)(struct sk_buff *)) |
157 | { | 157 | { |
158 | return arpt_do_table(pskb, hook, in, out, &packet_filter, NULL); | 158 | return arpt_do_table(pskb, hook, in, out, &packet_filter); |
159 | } | 159 | } |
160 | 160 | ||
161 | static struct nf_hook_ops arpt_ops[] = { | 161 | static struct nf_hook_ops arpt_ops[] = { |
diff --git a/net/ipv4/netfilter/ip_conntrack_core.c b/net/ipv4/netfilter/ip_conntrack_core.c index aa459177c3f8..c432b3163609 100644 --- a/net/ipv4/netfilter/ip_conntrack_core.c +++ b/net/ipv4/netfilter/ip_conntrack_core.c | |||
@@ -47,7 +47,6 @@ | |||
47 | #include <linux/netfilter_ipv4/ip_conntrack_protocol.h> | 47 | #include <linux/netfilter_ipv4/ip_conntrack_protocol.h> |
48 | #include <linux/netfilter_ipv4/ip_conntrack_helper.h> | 48 | #include <linux/netfilter_ipv4/ip_conntrack_helper.h> |
49 | #include <linux/netfilter_ipv4/ip_conntrack_core.h> | 49 | #include <linux/netfilter_ipv4/ip_conntrack_core.h> |
50 | #include <linux/netfilter_ipv4/listhelp.h> | ||
51 | 50 | ||
52 | #define IP_CONNTRACK_VERSION "2.4" | 51 | #define IP_CONNTRACK_VERSION "2.4" |
53 | 52 | ||
@@ -64,17 +63,17 @@ atomic_t ip_conntrack_count = ATOMIC_INIT(0); | |||
64 | 63 | ||
65 | void (*ip_conntrack_destroyed)(struct ip_conntrack *conntrack) = NULL; | 64 | void (*ip_conntrack_destroyed)(struct ip_conntrack *conntrack) = NULL; |
66 | LIST_HEAD(ip_conntrack_expect_list); | 65 | LIST_HEAD(ip_conntrack_expect_list); |
67 | struct ip_conntrack_protocol *ip_ct_protos[MAX_IP_CT_PROTO]; | 66 | struct ip_conntrack_protocol *ip_ct_protos[MAX_IP_CT_PROTO] __read_mostly; |
68 | static LIST_HEAD(helpers); | 67 | static LIST_HEAD(helpers); |
69 | unsigned int ip_conntrack_htable_size = 0; | 68 | unsigned int ip_conntrack_htable_size __read_mostly = 0; |
70 | int ip_conntrack_max; | 69 | int ip_conntrack_max __read_mostly; |
71 | struct list_head *ip_conntrack_hash; | 70 | struct list_head *ip_conntrack_hash __read_mostly; |
72 | static kmem_cache_t *ip_conntrack_cachep __read_mostly; | 71 | static kmem_cache_t *ip_conntrack_cachep __read_mostly; |
73 | static kmem_cache_t *ip_conntrack_expect_cachep __read_mostly; | 72 | static kmem_cache_t *ip_conntrack_expect_cachep __read_mostly; |
74 | struct ip_conntrack ip_conntrack_untracked; | 73 | struct ip_conntrack ip_conntrack_untracked; |
75 | unsigned int ip_ct_log_invalid; | 74 | unsigned int ip_ct_log_invalid __read_mostly; |
76 | static LIST_HEAD(unconfirmed); | 75 | static LIST_HEAD(unconfirmed); |
77 | static int ip_conntrack_vmalloc; | 76 | static int ip_conntrack_vmalloc __read_mostly; |
78 | 77 | ||
79 | static unsigned int ip_conntrack_next_id; | 78 | static unsigned int ip_conntrack_next_id; |
80 | static unsigned int ip_conntrack_expect_next_id; | 79 | static unsigned int ip_conntrack_expect_next_id; |
@@ -294,15 +293,10 @@ void ip_ct_remove_expectations(struct ip_conntrack *ct) | |||
294 | static void | 293 | static void |
295 | clean_from_lists(struct ip_conntrack *ct) | 294 | clean_from_lists(struct ip_conntrack *ct) |
296 | { | 295 | { |
297 | unsigned int ho, hr; | ||
298 | |||
299 | DEBUGP("clean_from_lists(%p)\n", ct); | 296 | DEBUGP("clean_from_lists(%p)\n", ct); |
300 | ASSERT_WRITE_LOCK(&ip_conntrack_lock); | 297 | ASSERT_WRITE_LOCK(&ip_conntrack_lock); |
301 | 298 | list_del(&ct->tuplehash[IP_CT_DIR_ORIGINAL].list); | |
302 | ho = hash_conntrack(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple); | 299 | list_del(&ct->tuplehash[IP_CT_DIR_REPLY].list); |
303 | hr = hash_conntrack(&ct->tuplehash[IP_CT_DIR_REPLY].tuple); | ||
304 | LIST_DELETE(&ip_conntrack_hash[ho], &ct->tuplehash[IP_CT_DIR_ORIGINAL]); | ||
305 | LIST_DELETE(&ip_conntrack_hash[hr], &ct->tuplehash[IP_CT_DIR_REPLY]); | ||
306 | 300 | ||
307 | /* Destroy all pending expectations */ | 301 | /* Destroy all pending expectations */ |
308 | ip_ct_remove_expectations(ct); | 302 | ip_ct_remove_expectations(ct); |
@@ -313,6 +307,7 @@ destroy_conntrack(struct nf_conntrack *nfct) | |||
313 | { | 307 | { |
314 | struct ip_conntrack *ct = (struct ip_conntrack *)nfct; | 308 | struct ip_conntrack *ct = (struct ip_conntrack *)nfct; |
315 | struct ip_conntrack_protocol *proto; | 309 | struct ip_conntrack_protocol *proto; |
310 | struct ip_conntrack_helper *helper; | ||
316 | 311 | ||
317 | DEBUGP("destroy_conntrack(%p)\n", ct); | 312 | DEBUGP("destroy_conntrack(%p)\n", ct); |
318 | IP_NF_ASSERT(atomic_read(&nfct->use) == 0); | 313 | IP_NF_ASSERT(atomic_read(&nfct->use) == 0); |
@@ -321,6 +316,10 @@ destroy_conntrack(struct nf_conntrack *nfct) | |||
321 | ip_conntrack_event(IPCT_DESTROY, ct); | 316 | ip_conntrack_event(IPCT_DESTROY, ct); |
322 | set_bit(IPS_DYING_BIT, &ct->status); | 317 | set_bit(IPS_DYING_BIT, &ct->status); |
323 | 318 | ||
319 | helper = ct->helper; | ||
320 | if (helper && helper->destroy) | ||
321 | helper->destroy(ct); | ||
322 | |||
324 | /* To make sure we don't get any weird locking issues here: | 323 | /* To make sure we don't get any weird locking issues here: |
325 | * destroy_conntrack() MUST NOT be called with a write lock | 324 | * destroy_conntrack() MUST NOT be called with a write lock |
326 | * to ip_conntrack_lock!!! -HW */ | 325 | * to ip_conntrack_lock!!! -HW */ |
@@ -367,16 +366,6 @@ static void death_by_timeout(unsigned long ul_conntrack) | |||
367 | ip_conntrack_put(ct); | 366 | ip_conntrack_put(ct); |
368 | } | 367 | } |
369 | 368 | ||
370 | static inline int | ||
371 | conntrack_tuple_cmp(const struct ip_conntrack_tuple_hash *i, | ||
372 | const struct ip_conntrack_tuple *tuple, | ||
373 | const struct ip_conntrack *ignored_conntrack) | ||
374 | { | ||
375 | ASSERT_READ_LOCK(&ip_conntrack_lock); | ||
376 | return tuplehash_to_ctrack(i) != ignored_conntrack | ||
377 | && ip_ct_tuple_equal(tuple, &i->tuple); | ||
378 | } | ||
379 | |||
380 | struct ip_conntrack_tuple_hash * | 369 | struct ip_conntrack_tuple_hash * |
381 | __ip_conntrack_find(const struct ip_conntrack_tuple *tuple, | 370 | __ip_conntrack_find(const struct ip_conntrack_tuple *tuple, |
382 | const struct ip_conntrack *ignored_conntrack) | 371 | const struct ip_conntrack *ignored_conntrack) |
@@ -386,7 +375,8 @@ __ip_conntrack_find(const struct ip_conntrack_tuple *tuple, | |||
386 | 375 | ||
387 | ASSERT_READ_LOCK(&ip_conntrack_lock); | 376 | ASSERT_READ_LOCK(&ip_conntrack_lock); |
388 | list_for_each_entry(h, &ip_conntrack_hash[hash], list) { | 377 | list_for_each_entry(h, &ip_conntrack_hash[hash], list) { |
389 | if (conntrack_tuple_cmp(h, tuple, ignored_conntrack)) { | 378 | if (tuplehash_to_ctrack(h) != ignored_conntrack && |
379 | ip_ct_tuple_equal(tuple, &h->tuple)) { | ||
390 | CONNTRACK_STAT_INC(found); | 380 | CONNTRACK_STAT_INC(found); |
391 | return h; | 381 | return h; |
392 | } | 382 | } |
@@ -417,10 +407,10 @@ static void __ip_conntrack_hash_insert(struct ip_conntrack *ct, | |||
417 | unsigned int repl_hash) | 407 | unsigned int repl_hash) |
418 | { | 408 | { |
419 | ct->id = ++ip_conntrack_next_id; | 409 | ct->id = ++ip_conntrack_next_id; |
420 | list_prepend(&ip_conntrack_hash[hash], | 410 | list_add(&ct->tuplehash[IP_CT_DIR_ORIGINAL].list, |
421 | &ct->tuplehash[IP_CT_DIR_ORIGINAL].list); | 411 | &ip_conntrack_hash[hash]); |
422 | list_prepend(&ip_conntrack_hash[repl_hash], | 412 | list_add(&ct->tuplehash[IP_CT_DIR_REPLY].list, |
423 | &ct->tuplehash[IP_CT_DIR_REPLY].list); | 413 | &ip_conntrack_hash[repl_hash]); |
424 | } | 414 | } |
425 | 415 | ||
426 | void ip_conntrack_hash_insert(struct ip_conntrack *ct) | 416 | void ip_conntrack_hash_insert(struct ip_conntrack *ct) |
@@ -440,6 +430,7 @@ int | |||
440 | __ip_conntrack_confirm(struct sk_buff **pskb) | 430 | __ip_conntrack_confirm(struct sk_buff **pskb) |
441 | { | 431 | { |
442 | unsigned int hash, repl_hash; | 432 | unsigned int hash, repl_hash; |
433 | struct ip_conntrack_tuple_hash *h; | ||
443 | struct ip_conntrack *ct; | 434 | struct ip_conntrack *ct; |
444 | enum ip_conntrack_info ctinfo; | 435 | enum ip_conntrack_info ctinfo; |
445 | 436 | ||
@@ -470,43 +461,43 @@ __ip_conntrack_confirm(struct sk_buff **pskb) | |||
470 | /* See if there's one in the list already, including reverse: | 461 | /* See if there's one in the list already, including reverse: |
471 | NAT could have grabbed it without realizing, since we're | 462 | NAT could have grabbed it without realizing, since we're |
472 | not in the hash. If there is, we lost race. */ | 463 | not in the hash. If there is, we lost race. */ |
473 | if (!LIST_FIND(&ip_conntrack_hash[hash], | 464 | list_for_each_entry(h, &ip_conntrack_hash[hash], list) |
474 | conntrack_tuple_cmp, | 465 | if (ip_ct_tuple_equal(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple, |
475 | struct ip_conntrack_tuple_hash *, | 466 | &h->tuple)) |
476 | &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple, NULL) | 467 | goto out; |
477 | && !LIST_FIND(&ip_conntrack_hash[repl_hash], | 468 | list_for_each_entry(h, &ip_conntrack_hash[repl_hash], list) |
478 | conntrack_tuple_cmp, | 469 | if (ip_ct_tuple_equal(&ct->tuplehash[IP_CT_DIR_REPLY].tuple, |
479 | struct ip_conntrack_tuple_hash *, | 470 | &h->tuple)) |
480 | &ct->tuplehash[IP_CT_DIR_REPLY].tuple, NULL)) { | 471 | goto out; |
481 | /* Remove from unconfirmed list */ | ||
482 | list_del(&ct->tuplehash[IP_CT_DIR_ORIGINAL].list); | ||
483 | 472 | ||
484 | __ip_conntrack_hash_insert(ct, hash, repl_hash); | 473 | /* Remove from unconfirmed list */ |
485 | /* Timer relative to confirmation time, not original | 474 | list_del(&ct->tuplehash[IP_CT_DIR_ORIGINAL].list); |
486 | setting time, otherwise we'd get timer wrap in | 475 | |
487 | weird delay cases. */ | 476 | __ip_conntrack_hash_insert(ct, hash, repl_hash); |
488 | ct->timeout.expires += jiffies; | 477 | /* Timer relative to confirmation time, not original |
489 | add_timer(&ct->timeout); | 478 | setting time, otherwise we'd get timer wrap in |
490 | atomic_inc(&ct->ct_general.use); | 479 | weird delay cases. */ |
491 | set_bit(IPS_CONFIRMED_BIT, &ct->status); | 480 | ct->timeout.expires += jiffies; |
492 | CONNTRACK_STAT_INC(insert); | 481 | add_timer(&ct->timeout); |
493 | write_unlock_bh(&ip_conntrack_lock); | 482 | atomic_inc(&ct->ct_general.use); |
494 | if (ct->helper) | 483 | set_bit(IPS_CONFIRMED_BIT, &ct->status); |
495 | ip_conntrack_event_cache(IPCT_HELPER, *pskb); | 484 | CONNTRACK_STAT_INC(insert); |
485 | write_unlock_bh(&ip_conntrack_lock); | ||
486 | if (ct->helper) | ||
487 | ip_conntrack_event_cache(IPCT_HELPER, *pskb); | ||
496 | #ifdef CONFIG_IP_NF_NAT_NEEDED | 488 | #ifdef CONFIG_IP_NF_NAT_NEEDED |
497 | if (test_bit(IPS_SRC_NAT_DONE_BIT, &ct->status) || | 489 | if (test_bit(IPS_SRC_NAT_DONE_BIT, &ct->status) || |
498 | test_bit(IPS_DST_NAT_DONE_BIT, &ct->status)) | 490 | test_bit(IPS_DST_NAT_DONE_BIT, &ct->status)) |
499 | ip_conntrack_event_cache(IPCT_NATINFO, *pskb); | 491 | ip_conntrack_event_cache(IPCT_NATINFO, *pskb); |
500 | #endif | 492 | #endif |
501 | ip_conntrack_event_cache(master_ct(ct) ? | 493 | ip_conntrack_event_cache(master_ct(ct) ? |
502 | IPCT_RELATED : IPCT_NEW, *pskb); | 494 | IPCT_RELATED : IPCT_NEW, *pskb); |
503 | 495 | ||
504 | return NF_ACCEPT; | 496 | return NF_ACCEPT; |
505 | } | ||
506 | 497 | ||
498 | out: | ||
507 | CONNTRACK_STAT_INC(insert_failed); | 499 | CONNTRACK_STAT_INC(insert_failed); |
508 | write_unlock_bh(&ip_conntrack_lock); | 500 | write_unlock_bh(&ip_conntrack_lock); |
509 | |||
510 | return NF_DROP; | 501 | return NF_DROP; |
511 | } | 502 | } |
512 | 503 | ||
@@ -527,23 +518,21 @@ ip_conntrack_tuple_taken(const struct ip_conntrack_tuple *tuple, | |||
527 | 518 | ||
528 | /* There's a small race here where we may free a just-assured | 519 | /* There's a small race here where we may free a just-assured |
529 | connection. Too bad: we're in trouble anyway. */ | 520 | connection. Too bad: we're in trouble anyway. */ |
530 | static inline int unreplied(const struct ip_conntrack_tuple_hash *i) | ||
531 | { | ||
532 | return !(test_bit(IPS_ASSURED_BIT, &tuplehash_to_ctrack(i)->status)); | ||
533 | } | ||
534 | |||
535 | static int early_drop(struct list_head *chain) | 521 | static int early_drop(struct list_head *chain) |
536 | { | 522 | { |
537 | /* Traverse backwards: gives us oldest, which is roughly LRU */ | 523 | /* Traverse backwards: gives us oldest, which is roughly LRU */ |
538 | struct ip_conntrack_tuple_hash *h; | 524 | struct ip_conntrack_tuple_hash *h; |
539 | struct ip_conntrack *ct = NULL; | 525 | struct ip_conntrack *ct = NULL, *tmp; |
540 | int dropped = 0; | 526 | int dropped = 0; |
541 | 527 | ||
542 | read_lock_bh(&ip_conntrack_lock); | 528 | read_lock_bh(&ip_conntrack_lock); |
543 | h = LIST_FIND_B(chain, unreplied, struct ip_conntrack_tuple_hash *); | 529 | list_for_each_entry_reverse(h, chain, list) { |
544 | if (h) { | 530 | tmp = tuplehash_to_ctrack(h); |
545 | ct = tuplehash_to_ctrack(h); | 531 | if (!test_bit(IPS_ASSURED_BIT, &tmp->status)) { |
546 | atomic_inc(&ct->ct_general.use); | 532 | ct = tmp; |
533 | atomic_inc(&ct->ct_general.use); | ||
534 | break; | ||
535 | } | ||
547 | } | 536 | } |
548 | read_unlock_bh(&ip_conntrack_lock); | 537 | read_unlock_bh(&ip_conntrack_lock); |
549 | 538 | ||
@@ -559,18 +548,16 @@ static int early_drop(struct list_head *chain) | |||
559 | return dropped; | 548 | return dropped; |
560 | } | 549 | } |
561 | 550 | ||
562 | static inline int helper_cmp(const struct ip_conntrack_helper *i, | ||
563 | const struct ip_conntrack_tuple *rtuple) | ||
564 | { | ||
565 | return ip_ct_tuple_mask_cmp(rtuple, &i->tuple, &i->mask); | ||
566 | } | ||
567 | |||
568 | static struct ip_conntrack_helper * | 551 | static struct ip_conntrack_helper * |
569 | __ip_conntrack_helper_find( const struct ip_conntrack_tuple *tuple) | 552 | __ip_conntrack_helper_find( const struct ip_conntrack_tuple *tuple) |
570 | { | 553 | { |
571 | return LIST_FIND(&helpers, helper_cmp, | 554 | struct ip_conntrack_helper *h; |
572 | struct ip_conntrack_helper *, | 555 | |
573 | tuple); | 556 | list_for_each_entry(h, &helpers, list) { |
557 | if (ip_ct_tuple_mask_cmp(tuple, &h->tuple, &h->mask)) | ||
558 | return h; | ||
559 | } | ||
560 | return NULL; | ||
574 | } | 561 | } |
575 | 562 | ||
576 | struct ip_conntrack_helper * | 563 | struct ip_conntrack_helper * |
@@ -640,11 +627,15 @@ struct ip_conntrack *ip_conntrack_alloc(struct ip_conntrack_tuple *orig, | |||
640 | ip_conntrack_hash_rnd_initted = 1; | 627 | ip_conntrack_hash_rnd_initted = 1; |
641 | } | 628 | } |
642 | 629 | ||
630 | /* We don't want any race condition at early drop stage */ | ||
631 | atomic_inc(&ip_conntrack_count); | ||
632 | |||
643 | if (ip_conntrack_max | 633 | if (ip_conntrack_max |
644 | && atomic_read(&ip_conntrack_count) >= ip_conntrack_max) { | 634 | && atomic_read(&ip_conntrack_count) > ip_conntrack_max) { |
645 | unsigned int hash = hash_conntrack(orig); | 635 | unsigned int hash = hash_conntrack(orig); |
646 | /* Try dropping from this hash chain. */ | 636 | /* Try dropping from this hash chain. */ |
647 | if (!early_drop(&ip_conntrack_hash[hash])) { | 637 | if (!early_drop(&ip_conntrack_hash[hash])) { |
638 | atomic_dec(&ip_conntrack_count); | ||
648 | if (net_ratelimit()) | 639 | if (net_ratelimit()) |
649 | printk(KERN_WARNING | 640 | printk(KERN_WARNING |
650 | "ip_conntrack: table full, dropping" | 641 | "ip_conntrack: table full, dropping" |
@@ -656,6 +647,7 @@ struct ip_conntrack *ip_conntrack_alloc(struct ip_conntrack_tuple *orig, | |||
656 | conntrack = kmem_cache_alloc(ip_conntrack_cachep, GFP_ATOMIC); | 647 | conntrack = kmem_cache_alloc(ip_conntrack_cachep, GFP_ATOMIC); |
657 | if (!conntrack) { | 648 | if (!conntrack) { |
658 | DEBUGP("Can't allocate conntrack.\n"); | 649 | DEBUGP("Can't allocate conntrack.\n"); |
650 | atomic_dec(&ip_conntrack_count); | ||
659 | return ERR_PTR(-ENOMEM); | 651 | return ERR_PTR(-ENOMEM); |
660 | } | 652 | } |
661 | 653 | ||
@@ -669,8 +661,6 @@ struct ip_conntrack *ip_conntrack_alloc(struct ip_conntrack_tuple *orig, | |||
669 | conntrack->timeout.data = (unsigned long)conntrack; | 661 | conntrack->timeout.data = (unsigned long)conntrack; |
670 | conntrack->timeout.function = death_by_timeout; | 662 | conntrack->timeout.function = death_by_timeout; |
671 | 663 | ||
672 | atomic_inc(&ip_conntrack_count); | ||
673 | |||
674 | return conntrack; | 664 | return conntrack; |
675 | } | 665 | } |
676 | 666 | ||
@@ -1062,7 +1052,7 @@ int ip_conntrack_helper_register(struct ip_conntrack_helper *me) | |||
1062 | { | 1052 | { |
1063 | BUG_ON(me->timeout == 0); | 1053 | BUG_ON(me->timeout == 0); |
1064 | write_lock_bh(&ip_conntrack_lock); | 1054 | write_lock_bh(&ip_conntrack_lock); |
1065 | list_prepend(&helpers, me); | 1055 | list_add(&me->list, &helpers); |
1066 | write_unlock_bh(&ip_conntrack_lock); | 1056 | write_unlock_bh(&ip_conntrack_lock); |
1067 | 1057 | ||
1068 | return 0; | 1058 | return 0; |
@@ -1081,24 +1071,24 @@ __ip_conntrack_helper_find_byname(const char *name) | |||
1081 | return NULL; | 1071 | return NULL; |
1082 | } | 1072 | } |
1083 | 1073 | ||
1084 | static inline int unhelp(struct ip_conntrack_tuple_hash *i, | 1074 | static inline void unhelp(struct ip_conntrack_tuple_hash *i, |
1085 | const struct ip_conntrack_helper *me) | 1075 | const struct ip_conntrack_helper *me) |
1086 | { | 1076 | { |
1087 | if (tuplehash_to_ctrack(i)->helper == me) { | 1077 | if (tuplehash_to_ctrack(i)->helper == me) { |
1088 | ip_conntrack_event(IPCT_HELPER, tuplehash_to_ctrack(i)); | 1078 | ip_conntrack_event(IPCT_HELPER, tuplehash_to_ctrack(i)); |
1089 | tuplehash_to_ctrack(i)->helper = NULL; | 1079 | tuplehash_to_ctrack(i)->helper = NULL; |
1090 | } | 1080 | } |
1091 | return 0; | ||
1092 | } | 1081 | } |
1093 | 1082 | ||
1094 | void ip_conntrack_helper_unregister(struct ip_conntrack_helper *me) | 1083 | void ip_conntrack_helper_unregister(struct ip_conntrack_helper *me) |
1095 | { | 1084 | { |
1096 | unsigned int i; | 1085 | unsigned int i; |
1086 | struct ip_conntrack_tuple_hash *h; | ||
1097 | struct ip_conntrack_expect *exp, *tmp; | 1087 | struct ip_conntrack_expect *exp, *tmp; |
1098 | 1088 | ||
1099 | /* Need write lock here, to delete helper. */ | 1089 | /* Need write lock here, to delete helper. */ |
1100 | write_lock_bh(&ip_conntrack_lock); | 1090 | write_lock_bh(&ip_conntrack_lock); |
1101 | LIST_DELETE(&helpers, me); | 1091 | list_del(&me->list); |
1102 | 1092 | ||
1103 | /* Get rid of expectations */ | 1093 | /* Get rid of expectations */ |
1104 | list_for_each_entry_safe(exp, tmp, &ip_conntrack_expect_list, list) { | 1094 | list_for_each_entry_safe(exp, tmp, &ip_conntrack_expect_list, list) { |
@@ -1108,10 +1098,12 @@ void ip_conntrack_helper_unregister(struct ip_conntrack_helper *me) | |||
1108 | } | 1098 | } |
1109 | } | 1099 | } |
1110 | /* Get rid of expecteds, set helpers to NULL. */ | 1100 | /* Get rid of expecteds, set helpers to NULL. */ |
1111 | LIST_FIND_W(&unconfirmed, unhelp, struct ip_conntrack_tuple_hash*, me); | 1101 | list_for_each_entry(h, &unconfirmed, list) |
1112 | for (i = 0; i < ip_conntrack_htable_size; i++) | 1102 | unhelp(h, me); |
1113 | LIST_FIND_W(&ip_conntrack_hash[i], unhelp, | 1103 | for (i = 0; i < ip_conntrack_htable_size; i++) { |
1114 | struct ip_conntrack_tuple_hash *, me); | 1104 | list_for_each_entry(h, &ip_conntrack_hash[i], list) |
1105 | unhelp(h, me); | ||
1106 | } | ||
1115 | write_unlock_bh(&ip_conntrack_lock); | 1107 | write_unlock_bh(&ip_conntrack_lock); |
1116 | 1108 | ||
1117 | /* Someone could be still looking at the helper in a bh. */ | 1109 | /* Someone could be still looking at the helper in a bh. */ |
@@ -1237,46 +1229,43 @@ static void ip_conntrack_attach(struct sk_buff *nskb, struct sk_buff *skb) | |||
1237 | nf_conntrack_get(nskb->nfct); | 1229 | nf_conntrack_get(nskb->nfct); |
1238 | } | 1230 | } |
1239 | 1231 | ||
1240 | static inline int | ||
1241 | do_iter(const struct ip_conntrack_tuple_hash *i, | ||
1242 | int (*iter)(struct ip_conntrack *i, void *data), | ||
1243 | void *data) | ||
1244 | { | ||
1245 | return iter(tuplehash_to_ctrack(i), data); | ||
1246 | } | ||
1247 | |||
1248 | /* Bring out ya dead! */ | 1232 | /* Bring out ya dead! */ |
1249 | static struct ip_conntrack_tuple_hash * | 1233 | static struct ip_conntrack * |
1250 | get_next_corpse(int (*iter)(struct ip_conntrack *i, void *data), | 1234 | get_next_corpse(int (*iter)(struct ip_conntrack *i, void *data), |
1251 | void *data, unsigned int *bucket) | 1235 | void *data, unsigned int *bucket) |
1252 | { | 1236 | { |
1253 | struct ip_conntrack_tuple_hash *h = NULL; | 1237 | struct ip_conntrack_tuple_hash *h; |
1238 | struct ip_conntrack *ct; | ||
1254 | 1239 | ||
1255 | write_lock_bh(&ip_conntrack_lock); | 1240 | write_lock_bh(&ip_conntrack_lock); |
1256 | for (; *bucket < ip_conntrack_htable_size; (*bucket)++) { | 1241 | for (; *bucket < ip_conntrack_htable_size; (*bucket)++) { |
1257 | h = LIST_FIND_W(&ip_conntrack_hash[*bucket], do_iter, | 1242 | list_for_each_entry(h, &ip_conntrack_hash[*bucket], list) { |
1258 | struct ip_conntrack_tuple_hash *, iter, data); | 1243 | ct = tuplehash_to_ctrack(h); |
1259 | if (h) | 1244 | if (iter(ct, data)) |
1260 | break; | 1245 | goto found; |
1246 | } | ||
1247 | } | ||
1248 | list_for_each_entry(h, &unconfirmed, list) { | ||
1249 | ct = tuplehash_to_ctrack(h); | ||
1250 | if (iter(ct, data)) | ||
1251 | goto found; | ||
1261 | } | 1252 | } |
1262 | if (!h) | ||
1263 | h = LIST_FIND_W(&unconfirmed, do_iter, | ||
1264 | struct ip_conntrack_tuple_hash *, iter, data); | ||
1265 | if (h) | ||
1266 | atomic_inc(&tuplehash_to_ctrack(h)->ct_general.use); | ||
1267 | write_unlock_bh(&ip_conntrack_lock); | 1253 | write_unlock_bh(&ip_conntrack_lock); |
1254 | return NULL; | ||
1268 | 1255 | ||
1269 | return h; | 1256 | found: |
1257 | atomic_inc(&ct->ct_general.use); | ||
1258 | write_unlock_bh(&ip_conntrack_lock); | ||
1259 | return ct; | ||
1270 | } | 1260 | } |
1271 | 1261 | ||
1272 | void | 1262 | void |
1273 | ip_ct_iterate_cleanup(int (*iter)(struct ip_conntrack *i, void *), void *data) | 1263 | ip_ct_iterate_cleanup(int (*iter)(struct ip_conntrack *i, void *), void *data) |
1274 | { | 1264 | { |
1275 | struct ip_conntrack_tuple_hash *h; | 1265 | struct ip_conntrack *ct; |
1276 | unsigned int bucket = 0; | 1266 | unsigned int bucket = 0; |
1277 | 1267 | ||
1278 | while ((h = get_next_corpse(iter, data, &bucket)) != NULL) { | 1268 | while ((ct = get_next_corpse(iter, data, &bucket)) != NULL) { |
1279 | struct ip_conntrack *ct = tuplehash_to_ctrack(h); | ||
1280 | /* Time to push up daises... */ | 1269 | /* Time to push up daises... */ |
1281 | if (del_timer(&ct->timeout)) | 1270 | if (del_timer(&ct->timeout)) |
1282 | death_by_timeout((unsigned long)ct); | 1271 | death_by_timeout((unsigned long)ct); |
diff --git a/net/ipv4/netfilter/ip_conntrack_helper_pptp.c b/net/ipv4/netfilter/ip_conntrack_helper_pptp.c index b020a33e65e9..fb0aee691721 100644 --- a/net/ipv4/netfilter/ip_conntrack_helper_pptp.c +++ b/net/ipv4/netfilter/ip_conntrack_helper_pptp.c | |||
@@ -20,11 +20,11 @@ | |||
20 | * - We can only support one single call within each session | 20 | * - We can only support one single call within each session |
21 | * | 21 | * |
22 | * TODO: | 22 | * TODO: |
23 | * - testing of incoming PPTP calls | 23 | * - testing of incoming PPTP calls |
24 | * | 24 | * |
25 | * Changes: | 25 | * Changes: |
26 | * 2002-02-05 - Version 1.3 | 26 | * 2002-02-05 - Version 1.3 |
27 | * - Call ip_conntrack_unexpect_related() from | 27 | * - Call ip_conntrack_unexpect_related() from |
28 | * pptp_destroy_siblings() to destroy expectations in case | 28 | * pptp_destroy_siblings() to destroy expectations in case |
29 | * CALL_DISCONNECT_NOTIFY or tcp fin packet was seen | 29 | * CALL_DISCONNECT_NOTIFY or tcp fin packet was seen |
30 | * (Philip Craig <philipc@snapgear.com>) | 30 | * (Philip Craig <philipc@snapgear.com>) |
@@ -80,7 +80,7 @@ int | |||
80 | struct PptpControlHeader *ctlh, | 80 | struct PptpControlHeader *ctlh, |
81 | union pptp_ctrl_union *pptpReq); | 81 | union pptp_ctrl_union *pptpReq); |
82 | 82 | ||
83 | int | 83 | void |
84 | (*ip_nat_pptp_hook_exp_gre)(struct ip_conntrack_expect *expect_orig, | 84 | (*ip_nat_pptp_hook_exp_gre)(struct ip_conntrack_expect *expect_orig, |
85 | struct ip_conntrack_expect *expect_reply); | 85 | struct ip_conntrack_expect *expect_reply); |
86 | 86 | ||
@@ -141,7 +141,7 @@ static void pptp_expectfn(struct ip_conntrack *ct, | |||
141 | invert_tuplepr(&inv_t, &exp->tuple); | 141 | invert_tuplepr(&inv_t, &exp->tuple); |
142 | DEBUGP("trying to unexpect other dir: "); | 142 | DEBUGP("trying to unexpect other dir: "); |
143 | DUMP_TUPLE(&inv_t); | 143 | DUMP_TUPLE(&inv_t); |
144 | 144 | ||
145 | exp_other = ip_conntrack_expect_find(&inv_t); | 145 | exp_other = ip_conntrack_expect_find(&inv_t); |
146 | if (exp_other) { | 146 | if (exp_other) { |
147 | /* delete other expectation. */ | 147 | /* delete other expectation. */ |
@@ -194,15 +194,16 @@ static void pptp_destroy_siblings(struct ip_conntrack *ct) | |||
194 | { | 194 | { |
195 | struct ip_conntrack_tuple t; | 195 | struct ip_conntrack_tuple t; |
196 | 196 | ||
197 | /* Since ct->sibling_list has literally rusted away in 2.6.11, | 197 | ip_ct_gre_keymap_destroy(ct); |
198 | /* Since ct->sibling_list has literally rusted away in 2.6.11, | ||
198 | * we now need another way to find out about our sibling | 199 | * we now need another way to find out about our sibling |
199 | * contrack and expects... -HW */ | 200 | * contrack and expects... -HW */ |
200 | 201 | ||
201 | /* try original (pns->pac) tuple */ | 202 | /* try original (pns->pac) tuple */ |
202 | memcpy(&t, &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple, sizeof(t)); | 203 | memcpy(&t, &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple, sizeof(t)); |
203 | t.dst.protonum = IPPROTO_GRE; | 204 | t.dst.protonum = IPPROTO_GRE; |
204 | t.src.u.gre.key = htons(ct->help.ct_pptp_info.pns_call_id); | 205 | t.src.u.gre.key = ct->help.ct_pptp_info.pns_call_id; |
205 | t.dst.u.gre.key = htons(ct->help.ct_pptp_info.pac_call_id); | 206 | t.dst.u.gre.key = ct->help.ct_pptp_info.pac_call_id; |
206 | 207 | ||
207 | if (!destroy_sibling_or_exp(&t)) | 208 | if (!destroy_sibling_or_exp(&t)) |
208 | DEBUGP("failed to timeout original pns->pac ct/exp\n"); | 209 | DEBUGP("failed to timeout original pns->pac ct/exp\n"); |
@@ -210,8 +211,8 @@ static void pptp_destroy_siblings(struct ip_conntrack *ct) | |||
210 | /* try reply (pac->pns) tuple */ | 211 | /* try reply (pac->pns) tuple */ |
211 | memcpy(&t, &ct->tuplehash[IP_CT_DIR_REPLY].tuple, sizeof(t)); | 212 | memcpy(&t, &ct->tuplehash[IP_CT_DIR_REPLY].tuple, sizeof(t)); |
212 | t.dst.protonum = IPPROTO_GRE; | 213 | t.dst.protonum = IPPROTO_GRE; |
213 | t.src.u.gre.key = htons(ct->help.ct_pptp_info.pac_call_id); | 214 | t.src.u.gre.key = ct->help.ct_pptp_info.pac_call_id; |
214 | t.dst.u.gre.key = htons(ct->help.ct_pptp_info.pns_call_id); | 215 | t.dst.u.gre.key = ct->help.ct_pptp_info.pns_call_id; |
215 | 216 | ||
216 | if (!destroy_sibling_or_exp(&t)) | 217 | if (!destroy_sibling_or_exp(&t)) |
217 | DEBUGP("failed to timeout reply pac->pns ct/exp\n"); | 218 | DEBUGP("failed to timeout reply pac->pns ct/exp\n"); |
@@ -219,94 +220,63 @@ static void pptp_destroy_siblings(struct ip_conntrack *ct) | |||
219 | 220 | ||
220 | /* expect GRE connections (PNS->PAC and PAC->PNS direction) */ | 221 | /* expect GRE connections (PNS->PAC and PAC->PNS direction) */ |
221 | static inline int | 222 | static inline int |
222 | exp_gre(struct ip_conntrack *master, | 223 | exp_gre(struct ip_conntrack *ct, |
223 | u_int32_t seq, | ||
224 | __be16 callid, | 224 | __be16 callid, |
225 | __be16 peer_callid) | 225 | __be16 peer_callid) |
226 | { | 226 | { |
227 | struct ip_conntrack_tuple inv_tuple; | ||
228 | struct ip_conntrack_tuple exp_tuples[] = { | ||
229 | /* tuple in original direction, PNS->PAC */ | ||
230 | { .src = { .ip = master->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip, | ||
231 | .u = { .gre = { .key = peer_callid } } | ||
232 | }, | ||
233 | .dst = { .ip = master->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip, | ||
234 | .u = { .gre = { .key = callid } }, | ||
235 | .protonum = IPPROTO_GRE | ||
236 | }, | ||
237 | }, | ||
238 | /* tuple in reply direction, PAC->PNS */ | ||
239 | { .src = { .ip = master->tuplehash[IP_CT_DIR_REPLY].tuple.src.ip, | ||
240 | .u = { .gre = { .key = callid } } | ||
241 | }, | ||
242 | .dst = { .ip = master->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip, | ||
243 | .u = { .gre = { .key = peer_callid } }, | ||
244 | .protonum = IPPROTO_GRE | ||
245 | }, | ||
246 | } | ||
247 | }; | ||
248 | struct ip_conntrack_expect *exp_orig, *exp_reply; | 227 | struct ip_conntrack_expect *exp_orig, *exp_reply; |
249 | int ret = 1; | 228 | int ret = 1; |
250 | 229 | ||
251 | exp_orig = ip_conntrack_expect_alloc(master); | 230 | exp_orig = ip_conntrack_expect_alloc(ct); |
252 | if (exp_orig == NULL) | 231 | if (exp_orig == NULL) |
253 | goto out; | 232 | goto out; |
254 | 233 | ||
255 | exp_reply = ip_conntrack_expect_alloc(master); | 234 | exp_reply = ip_conntrack_expect_alloc(ct); |
256 | if (exp_reply == NULL) | 235 | if (exp_reply == NULL) |
257 | goto out_put_orig; | 236 | goto out_put_orig; |
258 | 237 | ||
259 | memcpy(&exp_orig->tuple, &exp_tuples[0], sizeof(exp_orig->tuple)); | 238 | /* original direction, PNS->PAC */ |
239 | exp_orig->tuple.src.ip = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip; | ||
240 | exp_orig->tuple.src.u.gre.key = peer_callid; | ||
241 | exp_orig->tuple.dst.ip = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip; | ||
242 | exp_orig->tuple.dst.u.gre.key = callid; | ||
243 | exp_orig->tuple.dst.protonum = IPPROTO_GRE; | ||
260 | 244 | ||
261 | exp_orig->mask.src.ip = 0xffffffff; | 245 | exp_orig->mask.src.ip = 0xffffffff; |
262 | exp_orig->mask.src.u.all = 0; | 246 | exp_orig->mask.src.u.all = 0; |
263 | exp_orig->mask.dst.u.all = 0; | ||
264 | exp_orig->mask.dst.u.gre.key = htons(0xffff); | 247 | exp_orig->mask.dst.u.gre.key = htons(0xffff); |
265 | exp_orig->mask.dst.ip = 0xffffffff; | 248 | exp_orig->mask.dst.ip = 0xffffffff; |
266 | exp_orig->mask.dst.protonum = 0xff; | 249 | exp_orig->mask.dst.protonum = 0xff; |
267 | 250 | ||
268 | exp_orig->master = master; | 251 | exp_orig->master = ct; |
269 | exp_orig->expectfn = pptp_expectfn; | 252 | exp_orig->expectfn = pptp_expectfn; |
270 | exp_orig->flags = 0; | 253 | exp_orig->flags = 0; |
271 | 254 | ||
272 | /* both expectations are identical apart from tuple */ | 255 | /* both expectations are identical apart from tuple */ |
273 | memcpy(exp_reply, exp_orig, sizeof(*exp_reply)); | 256 | memcpy(exp_reply, exp_orig, sizeof(*exp_reply)); |
274 | memcpy(&exp_reply->tuple, &exp_tuples[1], sizeof(exp_reply->tuple)); | ||
275 | 257 | ||
276 | if (ip_nat_pptp_hook_exp_gre) | 258 | /* reply direction, PAC->PNS */ |
277 | ret = ip_nat_pptp_hook_exp_gre(exp_orig, exp_reply); | 259 | exp_reply->tuple.src.ip = ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.ip; |
278 | else { | 260 | exp_reply->tuple.src.u.gre.key = callid; |
279 | 261 | exp_reply->tuple.dst.ip = ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip; | |
280 | DEBUGP("calling expect_related PNS->PAC"); | 262 | exp_reply->tuple.dst.u.gre.key = peer_callid; |
281 | DUMP_TUPLE(&exp_orig->tuple); | 263 | exp_reply->tuple.dst.protonum = IPPROTO_GRE; |
282 | |||
283 | if (ip_conntrack_expect_related(exp_orig) != 0) { | ||
284 | DEBUGP("cannot expect_related()\n"); | ||
285 | goto out_put_both; | ||
286 | } | ||
287 | 264 | ||
288 | DEBUGP("calling expect_related PAC->PNS"); | 265 | if (ip_nat_pptp_hook_exp_gre) |
289 | DUMP_TUPLE(&exp_reply->tuple); | 266 | ip_nat_pptp_hook_exp_gre(exp_orig, exp_reply); |
290 | 267 | if (ip_conntrack_expect_related(exp_orig) != 0) | |
291 | if (ip_conntrack_expect_related(exp_reply) != 0) { | 268 | goto out_put_both; |
292 | DEBUGP("cannot expect_related()\n"); | 269 | if (ip_conntrack_expect_related(exp_reply) != 0) |
293 | goto out_unexpect_orig; | 270 | goto out_unexpect_orig; |
294 | } | 271 | |
295 | 272 | /* Add GRE keymap entries */ | |
296 | /* Add GRE keymap entries */ | 273 | if (ip_ct_gre_keymap_add(ct, &exp_orig->tuple, 0) != 0) |
297 | if (ip_ct_gre_keymap_add(master, &exp_reply->tuple, 0) != 0) { | 274 | goto out_unexpect_both; |
298 | DEBUGP("cannot keymap_add() exp\n"); | 275 | if (ip_ct_gre_keymap_add(ct, &exp_reply->tuple, 1) != 0) { |
299 | goto out_unexpect_both; | 276 | ip_ct_gre_keymap_destroy(ct); |
300 | } | 277 | goto out_unexpect_both; |
301 | |||
302 | invert_tuplepr(&inv_tuple, &exp_reply->tuple); | ||
303 | if (ip_ct_gre_keymap_add(master, &inv_tuple, 1) != 0) { | ||
304 | ip_ct_gre_keymap_destroy(master); | ||
305 | DEBUGP("cannot keymap_add() exp_inv\n"); | ||
306 | goto out_unexpect_both; | ||
307 | } | ||
308 | ret = 0; | ||
309 | } | 278 | } |
279 | ret = 0; | ||
310 | 280 | ||
311 | out_put_both: | 281 | out_put_both: |
312 | ip_conntrack_expect_put(exp_reply); | 282 | ip_conntrack_expect_put(exp_reply); |
@@ -322,73 +292,36 @@ out_unexpect_orig: | |||
322 | goto out_put_both; | 292 | goto out_put_both; |
323 | } | 293 | } |
324 | 294 | ||
325 | static inline int | 295 | static inline int |
326 | pptp_inbound_pkt(struct sk_buff **pskb, | 296 | pptp_inbound_pkt(struct sk_buff **pskb, |
327 | struct tcphdr *tcph, | 297 | struct PptpControlHeader *ctlh, |
328 | unsigned int nexthdr_off, | 298 | union pptp_ctrl_union *pptpReq, |
329 | unsigned int datalen, | 299 | unsigned int reqlen, |
330 | struct ip_conntrack *ct, | 300 | struct ip_conntrack *ct, |
331 | enum ip_conntrack_info ctinfo) | 301 | enum ip_conntrack_info ctinfo) |
332 | { | 302 | { |
333 | struct PptpControlHeader _ctlh, *ctlh; | ||
334 | unsigned int reqlen; | ||
335 | union pptp_ctrl_union _pptpReq, *pptpReq; | ||
336 | struct ip_ct_pptp_master *info = &ct->help.ct_pptp_info; | 303 | struct ip_ct_pptp_master *info = &ct->help.ct_pptp_info; |
337 | u_int16_t msg; | 304 | u_int16_t msg; |
338 | __be16 *cid, *pcid; | 305 | __be16 cid = 0, pcid = 0; |
339 | u_int32_t seq; | ||
340 | |||
341 | ctlh = skb_header_pointer(*pskb, nexthdr_off, sizeof(_ctlh), &_ctlh); | ||
342 | if (!ctlh) { | ||
343 | DEBUGP("error during skb_header_pointer\n"); | ||
344 | return NF_ACCEPT; | ||
345 | } | ||
346 | nexthdr_off += sizeof(_ctlh); | ||
347 | datalen -= sizeof(_ctlh); | ||
348 | |||
349 | reqlen = datalen; | ||
350 | if (reqlen > sizeof(*pptpReq)) | ||
351 | reqlen = sizeof(*pptpReq); | ||
352 | pptpReq = skb_header_pointer(*pskb, nexthdr_off, reqlen, &_pptpReq); | ||
353 | if (!pptpReq) { | ||
354 | DEBUGP("error during skb_header_pointer\n"); | ||
355 | return NF_ACCEPT; | ||
356 | } | ||
357 | 306 | ||
358 | msg = ntohs(ctlh->messageType); | 307 | msg = ntohs(ctlh->messageType); |
359 | DEBUGP("inbound control message %s\n", pptp_msg_name[msg]); | 308 | DEBUGP("inbound control message %s\n", pptp_msg_name[msg]); |
360 | 309 | ||
361 | switch (msg) { | 310 | switch (msg) { |
362 | case PPTP_START_SESSION_REPLY: | 311 | case PPTP_START_SESSION_REPLY: |
363 | if (reqlen < sizeof(_pptpReq.srep)) { | ||
364 | DEBUGP("%s: short packet\n", pptp_msg_name[msg]); | ||
365 | break; | ||
366 | } | ||
367 | |||
368 | /* server confirms new control session */ | 312 | /* server confirms new control session */ |
369 | if (info->sstate < PPTP_SESSION_REQUESTED) { | 313 | if (info->sstate < PPTP_SESSION_REQUESTED) |
370 | DEBUGP("%s without START_SESS_REQUEST\n", | 314 | goto invalid; |
371 | pptp_msg_name[msg]); | ||
372 | break; | ||
373 | } | ||
374 | if (pptpReq->srep.resultCode == PPTP_START_OK) | 315 | if (pptpReq->srep.resultCode == PPTP_START_OK) |
375 | info->sstate = PPTP_SESSION_CONFIRMED; | 316 | info->sstate = PPTP_SESSION_CONFIRMED; |
376 | else | 317 | else |
377 | info->sstate = PPTP_SESSION_ERROR; | 318 | info->sstate = PPTP_SESSION_ERROR; |
378 | break; | 319 | break; |
379 | 320 | ||
380 | case PPTP_STOP_SESSION_REPLY: | 321 | case PPTP_STOP_SESSION_REPLY: |
381 | if (reqlen < sizeof(_pptpReq.strep)) { | ||
382 | DEBUGP("%s: short packet\n", pptp_msg_name[msg]); | ||
383 | break; | ||
384 | } | ||
385 | |||
386 | /* server confirms end of control session */ | 322 | /* server confirms end of control session */ |
387 | if (info->sstate > PPTP_SESSION_STOPREQ) { | 323 | if (info->sstate > PPTP_SESSION_STOPREQ) |
388 | DEBUGP("%s without STOP_SESS_REQUEST\n", | 324 | goto invalid; |
389 | pptp_msg_name[msg]); | ||
390 | break; | ||
391 | } | ||
392 | if (pptpReq->strep.resultCode == PPTP_STOP_OK) | 325 | if (pptpReq->strep.resultCode == PPTP_STOP_OK) |
393 | info->sstate = PPTP_SESSION_NONE; | 326 | info->sstate = PPTP_SESSION_NONE; |
394 | else | 327 | else |
@@ -396,116 +329,64 @@ pptp_inbound_pkt(struct sk_buff **pskb, | |||
396 | break; | 329 | break; |
397 | 330 | ||
398 | case PPTP_OUT_CALL_REPLY: | 331 | case PPTP_OUT_CALL_REPLY: |
399 | if (reqlen < sizeof(_pptpReq.ocack)) { | ||
400 | DEBUGP("%s: short packet\n", pptp_msg_name[msg]); | ||
401 | break; | ||
402 | } | ||
403 | |||
404 | /* server accepted call, we now expect GRE frames */ | 332 | /* server accepted call, we now expect GRE frames */ |
405 | if (info->sstate != PPTP_SESSION_CONFIRMED) { | 333 | if (info->sstate != PPTP_SESSION_CONFIRMED) |
406 | DEBUGP("%s but no session\n", pptp_msg_name[msg]); | 334 | goto invalid; |
407 | break; | ||
408 | } | ||
409 | if (info->cstate != PPTP_CALL_OUT_REQ && | 335 | if (info->cstate != PPTP_CALL_OUT_REQ && |
410 | info->cstate != PPTP_CALL_OUT_CONF) { | 336 | info->cstate != PPTP_CALL_OUT_CONF) |
411 | DEBUGP("%s without OUTCALL_REQ\n", pptp_msg_name[msg]); | 337 | goto invalid; |
412 | break; | 338 | |
413 | } | 339 | cid = pptpReq->ocack.callID; |
414 | if (pptpReq->ocack.resultCode != PPTP_OUTCALL_CONNECT) { | 340 | pcid = pptpReq->ocack.peersCallID; |
341 | if (info->pns_call_id != pcid) | ||
342 | goto invalid; | ||
343 | DEBUGP("%s, CID=%X, PCID=%X\n", pptp_msg_name[msg], | ||
344 | ntohs(cid), ntohs(pcid)); | ||
345 | |||
346 | if (pptpReq->ocack.resultCode == PPTP_OUTCALL_CONNECT) { | ||
347 | info->cstate = PPTP_CALL_OUT_CONF; | ||
348 | info->pac_call_id = cid; | ||
349 | exp_gre(ct, cid, pcid); | ||
350 | } else | ||
415 | info->cstate = PPTP_CALL_NONE; | 351 | info->cstate = PPTP_CALL_NONE; |
416 | break; | ||
417 | } | ||
418 | |||
419 | cid = &pptpReq->ocack.callID; | ||
420 | pcid = &pptpReq->ocack.peersCallID; | ||
421 | |||
422 | info->pac_call_id = ntohs(*cid); | ||
423 | |||
424 | if (htons(info->pns_call_id) != *pcid) { | ||
425 | DEBUGP("%s for unknown callid %u\n", | ||
426 | pptp_msg_name[msg], ntohs(*pcid)); | ||
427 | break; | ||
428 | } | ||
429 | |||
430 | DEBUGP("%s, CID=%X, PCID=%X\n", pptp_msg_name[msg], | ||
431 | ntohs(*cid), ntohs(*pcid)); | ||
432 | |||
433 | info->cstate = PPTP_CALL_OUT_CONF; | ||
434 | |||
435 | seq = ntohl(tcph->seq) + sizeof(struct pptp_pkt_hdr) | ||
436 | + sizeof(struct PptpControlHeader) | ||
437 | + ((void *)pcid - (void *)pptpReq); | ||
438 | |||
439 | if (exp_gre(ct, seq, *cid, *pcid) != 0) | ||
440 | printk("ip_conntrack_pptp: error during exp_gre\n"); | ||
441 | break; | 352 | break; |
442 | 353 | ||
443 | case PPTP_IN_CALL_REQUEST: | 354 | case PPTP_IN_CALL_REQUEST: |
444 | if (reqlen < sizeof(_pptpReq.icack)) { | ||
445 | DEBUGP("%s: short packet\n", pptp_msg_name[msg]); | ||
446 | break; | ||
447 | } | ||
448 | |||
449 | /* server tells us about incoming call request */ | 355 | /* server tells us about incoming call request */ |
450 | if (info->sstate != PPTP_SESSION_CONFIRMED) { | 356 | if (info->sstate != PPTP_SESSION_CONFIRMED) |
451 | DEBUGP("%s but no session\n", pptp_msg_name[msg]); | 357 | goto invalid; |
452 | break; | 358 | |
453 | } | 359 | cid = pptpReq->icreq.callID; |
454 | pcid = &pptpReq->icack.peersCallID; | 360 | DEBUGP("%s, CID=%X\n", pptp_msg_name[msg], ntohs(cid)); |
455 | DEBUGP("%s, PCID=%X\n", pptp_msg_name[msg], ntohs(*pcid)); | ||
456 | info->cstate = PPTP_CALL_IN_REQ; | 361 | info->cstate = PPTP_CALL_IN_REQ; |
457 | info->pac_call_id = ntohs(*pcid); | 362 | info->pac_call_id = cid; |
458 | break; | 363 | break; |
459 | 364 | ||
460 | case PPTP_IN_CALL_CONNECT: | 365 | case PPTP_IN_CALL_CONNECT: |
461 | if (reqlen < sizeof(_pptpReq.iccon)) { | ||
462 | DEBUGP("%s: short packet\n", pptp_msg_name[msg]); | ||
463 | break; | ||
464 | } | ||
465 | |||
466 | /* server tells us about incoming call established */ | 366 | /* server tells us about incoming call established */ |
467 | if (info->sstate != PPTP_SESSION_CONFIRMED) { | 367 | if (info->sstate != PPTP_SESSION_CONFIRMED) |
468 | DEBUGP("%s but no session\n", pptp_msg_name[msg]); | 368 | goto invalid; |
469 | break; | 369 | if (info->cstate != PPTP_CALL_IN_REP && |
470 | } | 370 | info->cstate != PPTP_CALL_IN_CONF) |
471 | if (info->cstate != PPTP_CALL_IN_REP | 371 | goto invalid; |
472 | && info->cstate != PPTP_CALL_IN_CONF) { | ||
473 | DEBUGP("%s but never sent IN_CALL_REPLY\n", | ||
474 | pptp_msg_name[msg]); | ||
475 | break; | ||
476 | } | ||
477 | 372 | ||
478 | pcid = &pptpReq->iccon.peersCallID; | 373 | pcid = pptpReq->iccon.peersCallID; |
479 | cid = &info->pac_call_id; | 374 | cid = info->pac_call_id; |
480 | 375 | ||
481 | if (info->pns_call_id != ntohs(*pcid)) { | 376 | if (info->pns_call_id != pcid) |
482 | DEBUGP("%s for unknown CallID %u\n", | 377 | goto invalid; |
483 | pptp_msg_name[msg], ntohs(*pcid)); | ||
484 | break; | ||
485 | } | ||
486 | 378 | ||
487 | DEBUGP("%s, PCID=%X\n", pptp_msg_name[msg], ntohs(*pcid)); | 379 | DEBUGP("%s, PCID=%X\n", pptp_msg_name[msg], ntohs(pcid)); |
488 | info->cstate = PPTP_CALL_IN_CONF; | 380 | info->cstate = PPTP_CALL_IN_CONF; |
489 | 381 | ||
490 | /* we expect a GRE connection from PAC to PNS */ | 382 | /* we expect a GRE connection from PAC to PNS */ |
491 | seq = ntohl(tcph->seq) + sizeof(struct pptp_pkt_hdr) | 383 | exp_gre(ct, cid, pcid); |
492 | + sizeof(struct PptpControlHeader) | ||
493 | + ((void *)pcid - (void *)pptpReq); | ||
494 | |||
495 | if (exp_gre(ct, seq, *cid, *pcid) != 0) | ||
496 | printk("ip_conntrack_pptp: error during exp_gre\n"); | ||
497 | |||
498 | break; | 384 | break; |
499 | 385 | ||
500 | case PPTP_CALL_DISCONNECT_NOTIFY: | 386 | case PPTP_CALL_DISCONNECT_NOTIFY: |
501 | if (reqlen < sizeof(_pptpReq.disc)) { | ||
502 | DEBUGP("%s: short packet\n", pptp_msg_name[msg]); | ||
503 | break; | ||
504 | } | ||
505 | |||
506 | /* server confirms disconnect */ | 387 | /* server confirms disconnect */ |
507 | cid = &pptpReq->disc.callID; | 388 | cid = pptpReq->disc.callID; |
508 | DEBUGP("%s, CID=%X\n", pptp_msg_name[msg], ntohs(*cid)); | 389 | DEBUGP("%s, CID=%X\n", pptp_msg_name[msg], ntohs(cid)); |
509 | info->cstate = PPTP_CALL_NONE; | 390 | info->cstate = PPTP_CALL_NONE; |
510 | 391 | ||
511 | /* untrack this call id, unexpect GRE packets */ | 392 | /* untrack this call id, unexpect GRE packets */ |
@@ -513,54 +394,39 @@ pptp_inbound_pkt(struct sk_buff **pskb, | |||
513 | break; | 394 | break; |
514 | 395 | ||
515 | case PPTP_WAN_ERROR_NOTIFY: | 396 | case PPTP_WAN_ERROR_NOTIFY: |
516 | break; | ||
517 | |||
518 | case PPTP_ECHO_REQUEST: | 397 | case PPTP_ECHO_REQUEST: |
519 | case PPTP_ECHO_REPLY: | 398 | case PPTP_ECHO_REPLY: |
520 | /* I don't have to explain these ;) */ | 399 | /* I don't have to explain these ;) */ |
521 | break; | 400 | break; |
522 | default: | 401 | default: |
523 | DEBUGP("invalid %s (TY=%d)\n", (msg <= PPTP_MSG_MAX) | 402 | goto invalid; |
524 | ? pptp_msg_name[msg]:pptp_msg_name[0], msg); | ||
525 | break; | ||
526 | } | 403 | } |
527 | 404 | ||
528 | |||
529 | if (ip_nat_pptp_hook_inbound) | 405 | if (ip_nat_pptp_hook_inbound) |
530 | return ip_nat_pptp_hook_inbound(pskb, ct, ctinfo, ctlh, | 406 | return ip_nat_pptp_hook_inbound(pskb, ct, ctinfo, ctlh, |
531 | pptpReq); | 407 | pptpReq); |
532 | |||
533 | return NF_ACCEPT; | 408 | return NF_ACCEPT; |
534 | 409 | ||
410 | invalid: | ||
411 | DEBUGP("invalid %s: type=%d cid=%u pcid=%u " | ||
412 | "cstate=%d sstate=%d pns_cid=%u pac_cid=%u\n", | ||
413 | msg <= PPTP_MSG_MAX ? pptp_msg_name[msg] : pptp_msg_name[0], | ||
414 | msg, ntohs(cid), ntohs(pcid), info->cstate, info->sstate, | ||
415 | ntohs(info->pns_call_id), ntohs(info->pac_call_id)); | ||
416 | return NF_ACCEPT; | ||
535 | } | 417 | } |
536 | 418 | ||
537 | static inline int | 419 | static inline int |
538 | pptp_outbound_pkt(struct sk_buff **pskb, | 420 | pptp_outbound_pkt(struct sk_buff **pskb, |
539 | struct tcphdr *tcph, | 421 | struct PptpControlHeader *ctlh, |
540 | unsigned int nexthdr_off, | 422 | union pptp_ctrl_union *pptpReq, |
541 | unsigned int datalen, | 423 | unsigned int reqlen, |
542 | struct ip_conntrack *ct, | 424 | struct ip_conntrack *ct, |
543 | enum ip_conntrack_info ctinfo) | 425 | enum ip_conntrack_info ctinfo) |
544 | { | 426 | { |
545 | struct PptpControlHeader _ctlh, *ctlh; | ||
546 | unsigned int reqlen; | ||
547 | union pptp_ctrl_union _pptpReq, *pptpReq; | ||
548 | struct ip_ct_pptp_master *info = &ct->help.ct_pptp_info; | 427 | struct ip_ct_pptp_master *info = &ct->help.ct_pptp_info; |
549 | u_int16_t msg; | 428 | u_int16_t msg; |
550 | __be16 *cid, *pcid; | 429 | __be16 cid = 0, pcid = 0; |
551 | |||
552 | ctlh = skb_header_pointer(*pskb, nexthdr_off, sizeof(_ctlh), &_ctlh); | ||
553 | if (!ctlh) | ||
554 | return NF_ACCEPT; | ||
555 | nexthdr_off += sizeof(_ctlh); | ||
556 | datalen -= sizeof(_ctlh); | ||
557 | |||
558 | reqlen = datalen; | ||
559 | if (reqlen > sizeof(*pptpReq)) | ||
560 | reqlen = sizeof(*pptpReq); | ||
561 | pptpReq = skb_header_pointer(*pskb, nexthdr_off, reqlen, &_pptpReq); | ||
562 | if (!pptpReq) | ||
563 | return NF_ACCEPT; | ||
564 | 430 | ||
565 | msg = ntohs(ctlh->messageType); | 431 | msg = ntohs(ctlh->messageType); |
566 | DEBUGP("outbound control message %s\n", pptp_msg_name[msg]); | 432 | DEBUGP("outbound control message %s\n", pptp_msg_name[msg]); |
@@ -568,10 +434,8 @@ pptp_outbound_pkt(struct sk_buff **pskb, | |||
568 | switch (msg) { | 434 | switch (msg) { |
569 | case PPTP_START_SESSION_REQUEST: | 435 | case PPTP_START_SESSION_REQUEST: |
570 | /* client requests for new control session */ | 436 | /* client requests for new control session */ |
571 | if (info->sstate != PPTP_SESSION_NONE) { | 437 | if (info->sstate != PPTP_SESSION_NONE) |
572 | DEBUGP("%s but we already have one", | 438 | goto invalid; |
573 | pptp_msg_name[msg]); | ||
574 | } | ||
575 | info->sstate = PPTP_SESSION_REQUESTED; | 439 | info->sstate = PPTP_SESSION_REQUESTED; |
576 | break; | 440 | break; |
577 | case PPTP_STOP_SESSION_REQUEST: | 441 | case PPTP_STOP_SESSION_REQUEST: |
@@ -580,123 +444,115 @@ pptp_outbound_pkt(struct sk_buff **pskb, | |||
580 | break; | 444 | break; |
581 | 445 | ||
582 | case PPTP_OUT_CALL_REQUEST: | 446 | case PPTP_OUT_CALL_REQUEST: |
583 | if (reqlen < sizeof(_pptpReq.ocreq)) { | ||
584 | DEBUGP("%s: short packet\n", pptp_msg_name[msg]); | ||
585 | /* FIXME: break; */ | ||
586 | } | ||
587 | |||
588 | /* client initiating connection to server */ | 447 | /* client initiating connection to server */ |
589 | if (info->sstate != PPTP_SESSION_CONFIRMED) { | 448 | if (info->sstate != PPTP_SESSION_CONFIRMED) |
590 | DEBUGP("%s but no session\n", | 449 | goto invalid; |
591 | pptp_msg_name[msg]); | ||
592 | break; | ||
593 | } | ||
594 | info->cstate = PPTP_CALL_OUT_REQ; | 450 | info->cstate = PPTP_CALL_OUT_REQ; |
595 | /* track PNS call id */ | 451 | /* track PNS call id */ |
596 | cid = &pptpReq->ocreq.callID; | 452 | cid = pptpReq->ocreq.callID; |
597 | DEBUGP("%s, CID=%X\n", pptp_msg_name[msg], ntohs(*cid)); | 453 | DEBUGP("%s, CID=%X\n", pptp_msg_name[msg], ntohs(cid)); |
598 | info->pns_call_id = ntohs(*cid); | 454 | info->pns_call_id = cid; |
599 | break; | 455 | break; |
600 | case PPTP_IN_CALL_REPLY: | 456 | case PPTP_IN_CALL_REPLY: |
601 | if (reqlen < sizeof(_pptpReq.icack)) { | ||
602 | DEBUGP("%s: short packet\n", pptp_msg_name[msg]); | ||
603 | break; | ||
604 | } | ||
605 | |||
606 | /* client answers incoming call */ | 457 | /* client answers incoming call */ |
607 | if (info->cstate != PPTP_CALL_IN_REQ | 458 | if (info->cstate != PPTP_CALL_IN_REQ && |
608 | && info->cstate != PPTP_CALL_IN_REP) { | 459 | info->cstate != PPTP_CALL_IN_REP) |
609 | DEBUGP("%s without incall_req\n", | 460 | goto invalid; |
610 | pptp_msg_name[msg]); | 461 | |
611 | break; | 462 | cid = pptpReq->icack.callID; |
612 | } | 463 | pcid = pptpReq->icack.peersCallID; |
613 | if (pptpReq->icack.resultCode != PPTP_INCALL_ACCEPT) { | 464 | if (info->pac_call_id != pcid) |
465 | goto invalid; | ||
466 | DEBUGP("%s, CID=%X PCID=%X\n", pptp_msg_name[msg], | ||
467 | ntohs(cid), ntohs(pcid)); | ||
468 | |||
469 | if (pptpReq->icack.resultCode == PPTP_INCALL_ACCEPT) { | ||
470 | /* part two of the three-way handshake */ | ||
471 | info->cstate = PPTP_CALL_IN_REP; | ||
472 | info->pns_call_id = cid; | ||
473 | } else | ||
614 | info->cstate = PPTP_CALL_NONE; | 474 | info->cstate = PPTP_CALL_NONE; |
615 | break; | ||
616 | } | ||
617 | pcid = &pptpReq->icack.peersCallID; | ||
618 | if (info->pac_call_id != ntohs(*pcid)) { | ||
619 | DEBUGP("%s for unknown call %u\n", | ||
620 | pptp_msg_name[msg], ntohs(*pcid)); | ||
621 | break; | ||
622 | } | ||
623 | DEBUGP("%s, CID=%X\n", pptp_msg_name[msg], ntohs(*pcid)); | ||
624 | /* part two of the three-way handshake */ | ||
625 | info->cstate = PPTP_CALL_IN_REP; | ||
626 | info->pns_call_id = ntohs(pptpReq->icack.callID); | ||
627 | break; | 475 | break; |
628 | 476 | ||
629 | case PPTP_CALL_CLEAR_REQUEST: | 477 | case PPTP_CALL_CLEAR_REQUEST: |
630 | /* client requests hangup of call */ | 478 | /* client requests hangup of call */ |
631 | if (info->sstate != PPTP_SESSION_CONFIRMED) { | 479 | if (info->sstate != PPTP_SESSION_CONFIRMED) |
632 | DEBUGP("CLEAR_CALL but no session\n"); | 480 | goto invalid; |
633 | break; | ||
634 | } | ||
635 | /* FUTURE: iterate over all calls and check if | 481 | /* FUTURE: iterate over all calls and check if |
636 | * call ID is valid. We don't do this without newnat, | 482 | * call ID is valid. We don't do this without newnat, |
637 | * because we only know about last call */ | 483 | * because we only know about last call */ |
638 | info->cstate = PPTP_CALL_CLEAR_REQ; | 484 | info->cstate = PPTP_CALL_CLEAR_REQ; |
639 | break; | 485 | break; |
640 | case PPTP_SET_LINK_INFO: | 486 | case PPTP_SET_LINK_INFO: |
641 | break; | ||
642 | case PPTP_ECHO_REQUEST: | 487 | case PPTP_ECHO_REQUEST: |
643 | case PPTP_ECHO_REPLY: | 488 | case PPTP_ECHO_REPLY: |
644 | /* I don't have to explain these ;) */ | 489 | /* I don't have to explain these ;) */ |
645 | break; | 490 | break; |
646 | default: | 491 | default: |
647 | DEBUGP("invalid %s (TY=%d)\n", (msg <= PPTP_MSG_MAX)? | 492 | goto invalid; |
648 | pptp_msg_name[msg]:pptp_msg_name[0], msg); | ||
649 | /* unknown: no need to create GRE masq table entry */ | ||
650 | break; | ||
651 | } | 493 | } |
652 | 494 | ||
653 | if (ip_nat_pptp_hook_outbound) | 495 | if (ip_nat_pptp_hook_outbound) |
654 | return ip_nat_pptp_hook_outbound(pskb, ct, ctinfo, ctlh, | 496 | return ip_nat_pptp_hook_outbound(pskb, ct, ctinfo, ctlh, |
655 | pptpReq); | 497 | pptpReq); |
498 | return NF_ACCEPT; | ||
656 | 499 | ||
500 | invalid: | ||
501 | DEBUGP("invalid %s: type=%d cid=%u pcid=%u " | ||
502 | "cstate=%d sstate=%d pns_cid=%u pac_cid=%u\n", | ||
503 | msg <= PPTP_MSG_MAX ? pptp_msg_name[msg] : pptp_msg_name[0], | ||
504 | msg, ntohs(cid), ntohs(pcid), info->cstate, info->sstate, | ||
505 | ntohs(info->pns_call_id), ntohs(info->pac_call_id)); | ||
657 | return NF_ACCEPT; | 506 | return NF_ACCEPT; |
658 | } | 507 | } |
659 | 508 | ||
509 | static const unsigned int pptp_msg_size[] = { | ||
510 | [PPTP_START_SESSION_REQUEST] = sizeof(struct PptpStartSessionRequest), | ||
511 | [PPTP_START_SESSION_REPLY] = sizeof(struct PptpStartSessionReply), | ||
512 | [PPTP_STOP_SESSION_REQUEST] = sizeof(struct PptpStopSessionRequest), | ||
513 | [PPTP_STOP_SESSION_REPLY] = sizeof(struct PptpStopSessionReply), | ||
514 | [PPTP_OUT_CALL_REQUEST] = sizeof(struct PptpOutCallRequest), | ||
515 | [PPTP_OUT_CALL_REPLY] = sizeof(struct PptpOutCallReply), | ||
516 | [PPTP_IN_CALL_REQUEST] = sizeof(struct PptpInCallRequest), | ||
517 | [PPTP_IN_CALL_REPLY] = sizeof(struct PptpInCallReply), | ||
518 | [PPTP_IN_CALL_CONNECT] = sizeof(struct PptpInCallConnected), | ||
519 | [PPTP_CALL_CLEAR_REQUEST] = sizeof(struct PptpClearCallRequest), | ||
520 | [PPTP_CALL_DISCONNECT_NOTIFY] = sizeof(struct PptpCallDisconnectNotify), | ||
521 | [PPTP_WAN_ERROR_NOTIFY] = sizeof(struct PptpWanErrorNotify), | ||
522 | [PPTP_SET_LINK_INFO] = sizeof(struct PptpSetLinkInfo), | ||
523 | }; | ||
660 | 524 | ||
661 | /* track caller id inside control connection, call expect_related */ | 525 | /* track caller id inside control connection, call expect_related */ |
662 | static int | 526 | static int |
663 | conntrack_pptp_help(struct sk_buff **pskb, | 527 | conntrack_pptp_help(struct sk_buff **pskb, |
664 | struct ip_conntrack *ct, enum ip_conntrack_info ctinfo) | 528 | struct ip_conntrack *ct, enum ip_conntrack_info ctinfo) |
665 | 529 | ||
666 | { | 530 | { |
667 | struct pptp_pkt_hdr _pptph, *pptph; | ||
668 | struct tcphdr _tcph, *tcph; | ||
669 | u_int32_t tcplen = (*pskb)->len - (*pskb)->nh.iph->ihl * 4; | ||
670 | u_int32_t datalen; | ||
671 | int dir = CTINFO2DIR(ctinfo); | 531 | int dir = CTINFO2DIR(ctinfo); |
672 | struct ip_ct_pptp_master *info = &ct->help.ct_pptp_info; | 532 | struct ip_ct_pptp_master *info = &ct->help.ct_pptp_info; |
673 | unsigned int nexthdr_off; | 533 | struct tcphdr _tcph, *tcph; |
674 | 534 | struct pptp_pkt_hdr _pptph, *pptph; | |
535 | struct PptpControlHeader _ctlh, *ctlh; | ||
536 | union pptp_ctrl_union _pptpReq, *pptpReq; | ||
537 | unsigned int tcplen = (*pskb)->len - (*pskb)->nh.iph->ihl * 4; | ||
538 | unsigned int datalen, reqlen, nexthdr_off; | ||
675 | int oldsstate, oldcstate; | 539 | int oldsstate, oldcstate; |
676 | int ret; | 540 | int ret; |
541 | u_int16_t msg; | ||
677 | 542 | ||
678 | /* don't do any tracking before tcp handshake complete */ | 543 | /* don't do any tracking before tcp handshake complete */ |
679 | if (ctinfo != IP_CT_ESTABLISHED | 544 | if (ctinfo != IP_CT_ESTABLISHED |
680 | && ctinfo != IP_CT_ESTABLISHED+IP_CT_IS_REPLY) { | 545 | && ctinfo != IP_CT_ESTABLISHED+IP_CT_IS_REPLY) { |
681 | DEBUGP("ctinfo = %u, skipping\n", ctinfo); | 546 | DEBUGP("ctinfo = %u, skipping\n", ctinfo); |
682 | return NF_ACCEPT; | 547 | return NF_ACCEPT; |
683 | } | 548 | } |
684 | 549 | ||
685 | nexthdr_off = (*pskb)->nh.iph->ihl*4; | 550 | nexthdr_off = (*pskb)->nh.iph->ihl*4; |
686 | tcph = skb_header_pointer(*pskb, nexthdr_off, sizeof(_tcph), &_tcph); | 551 | tcph = skb_header_pointer(*pskb, nexthdr_off, sizeof(_tcph), &_tcph); |
687 | BUG_ON(!tcph); | 552 | BUG_ON(!tcph); |
688 | nexthdr_off += tcph->doff * 4; | 553 | nexthdr_off += tcph->doff * 4; |
689 | datalen = tcplen - tcph->doff * 4; | 554 | datalen = tcplen - tcph->doff * 4; |
690 | 555 | ||
691 | if (tcph->fin || tcph->rst) { | ||
692 | DEBUGP("RST/FIN received, timeouting GRE\n"); | ||
693 | /* can't do this after real newnat */ | ||
694 | info->cstate = PPTP_CALL_NONE; | ||
695 | |||
696 | /* untrack this call id, unexpect GRE packets */ | ||
697 | pptp_destroy_siblings(ct); | ||
698 | } | ||
699 | |||
700 | pptph = skb_header_pointer(*pskb, nexthdr_off, sizeof(_pptph), &_pptph); | 556 | pptph = skb_header_pointer(*pskb, nexthdr_off, sizeof(_pptph), &_pptph); |
701 | if (!pptph) { | 557 | if (!pptph) { |
702 | DEBUGP("no full PPTP header, can't track\n"); | 558 | DEBUGP("no full PPTP header, can't track\n"); |
@@ -712,6 +568,23 @@ conntrack_pptp_help(struct sk_buff **pskb, | |||
712 | return NF_ACCEPT; | 568 | return NF_ACCEPT; |
713 | } | 569 | } |
714 | 570 | ||
571 | ctlh = skb_header_pointer(*pskb, nexthdr_off, sizeof(_ctlh), &_ctlh); | ||
572 | if (!ctlh) | ||
573 | return NF_ACCEPT; | ||
574 | nexthdr_off += sizeof(_ctlh); | ||
575 | datalen -= sizeof(_ctlh); | ||
576 | |||
577 | reqlen = datalen; | ||
578 | msg = ntohs(ctlh->messageType); | ||
579 | if (msg > 0 && msg <= PPTP_MSG_MAX && reqlen < pptp_msg_size[msg]) | ||
580 | return NF_ACCEPT; | ||
581 | if (reqlen > sizeof(*pptpReq)) | ||
582 | reqlen = sizeof(*pptpReq); | ||
583 | |||
584 | pptpReq = skb_header_pointer(*pskb, nexthdr_off, reqlen, &_pptpReq); | ||
585 | if (!pptpReq) | ||
586 | return NF_ACCEPT; | ||
587 | |||
715 | oldsstate = info->sstate; | 588 | oldsstate = info->sstate; |
716 | oldcstate = info->cstate; | 589 | oldcstate = info->cstate; |
717 | 590 | ||
@@ -721,11 +594,11 @@ conntrack_pptp_help(struct sk_buff **pskb, | |||
721 | * established from PNS->PAC. However, RFC makes no guarantee */ | 594 | * established from PNS->PAC. However, RFC makes no guarantee */ |
722 | if (dir == IP_CT_DIR_ORIGINAL) | 595 | if (dir == IP_CT_DIR_ORIGINAL) |
723 | /* client -> server (PNS -> PAC) */ | 596 | /* client -> server (PNS -> PAC) */ |
724 | ret = pptp_outbound_pkt(pskb, tcph, nexthdr_off, datalen, ct, | 597 | ret = pptp_outbound_pkt(pskb, ctlh, pptpReq, reqlen, ct, |
725 | ctinfo); | 598 | ctinfo); |
726 | else | 599 | else |
727 | /* server -> client (PAC -> PNS) */ | 600 | /* server -> client (PAC -> PNS) */ |
728 | ret = pptp_inbound_pkt(pskb, tcph, nexthdr_off, datalen, ct, | 601 | ret = pptp_inbound_pkt(pskb, ctlh, pptpReq, reqlen, ct, |
729 | ctinfo); | 602 | ctinfo); |
730 | DEBUGP("sstate: %d->%d, cstate: %d->%d\n", | 603 | DEBUGP("sstate: %d->%d, cstate: %d->%d\n", |
731 | oldsstate, info->sstate, oldcstate, info->cstate); | 604 | oldsstate, info->sstate, oldcstate, info->cstate); |
@@ -735,30 +608,31 @@ conntrack_pptp_help(struct sk_buff **pskb, | |||
735 | } | 608 | } |
736 | 609 | ||
737 | /* control protocol helper */ | 610 | /* control protocol helper */ |
738 | static struct ip_conntrack_helper pptp = { | 611 | static struct ip_conntrack_helper pptp = { |
739 | .list = { NULL, NULL }, | 612 | .list = { NULL, NULL }, |
740 | .name = "pptp", | 613 | .name = "pptp", |
741 | .me = THIS_MODULE, | 614 | .me = THIS_MODULE, |
742 | .max_expected = 2, | 615 | .max_expected = 2, |
743 | .timeout = 5 * 60, | 616 | .timeout = 5 * 60, |
744 | .tuple = { .src = { .ip = 0, | 617 | .tuple = { .src = { .ip = 0, |
745 | .u = { .tcp = { .port = | 618 | .u = { .tcp = { .port = |
746 | __constant_htons(PPTP_CONTROL_PORT) } } | 619 | __constant_htons(PPTP_CONTROL_PORT) } } |
747 | }, | 620 | }, |
748 | .dst = { .ip = 0, | 621 | .dst = { .ip = 0, |
749 | .u = { .all = 0 }, | 622 | .u = { .all = 0 }, |
750 | .protonum = IPPROTO_TCP | 623 | .protonum = IPPROTO_TCP |
751 | } | 624 | } |
752 | }, | 625 | }, |
753 | .mask = { .src = { .ip = 0, | 626 | .mask = { .src = { .ip = 0, |
754 | .u = { .tcp = { .port = __constant_htons(0xffff) } } | 627 | .u = { .tcp = { .port = __constant_htons(0xffff) } } |
755 | }, | 628 | }, |
756 | .dst = { .ip = 0, | 629 | .dst = { .ip = 0, |
757 | .u = { .all = 0 }, | 630 | .u = { .all = 0 }, |
758 | .protonum = 0xff | 631 | .protonum = 0xff |
759 | } | 632 | } |
760 | }, | 633 | }, |
761 | .help = conntrack_pptp_help | 634 | .help = conntrack_pptp_help, |
635 | .destroy = pptp_destroy_siblings, | ||
762 | }; | 636 | }; |
763 | 637 | ||
764 | extern void ip_ct_proto_gre_fini(void); | 638 | extern void ip_ct_proto_gre_fini(void); |
@@ -768,7 +642,7 @@ extern int __init ip_ct_proto_gre_init(void); | |||
768 | static int __init ip_conntrack_helper_pptp_init(void) | 642 | static int __init ip_conntrack_helper_pptp_init(void) |
769 | { | 643 | { |
770 | int retcode; | 644 | int retcode; |
771 | 645 | ||
772 | retcode = ip_ct_proto_gre_init(); | 646 | retcode = ip_ct_proto_gre_init(); |
773 | if (retcode < 0) | 647 | if (retcode < 0) |
774 | return retcode; | 648 | return retcode; |
diff --git a/net/ipv4/netfilter/ip_conntrack_netbios_ns.c b/net/ipv4/netfilter/ip_conntrack_netbios_ns.c index a566a81325b2..3d0b438783db 100644 --- a/net/ipv4/netfilter/ip_conntrack_netbios_ns.c +++ b/net/ipv4/netfilter/ip_conntrack_netbios_ns.c | |||
@@ -21,6 +21,7 @@ | |||
21 | #include <linux/skbuff.h> | 21 | #include <linux/skbuff.h> |
22 | #include <linux/netdevice.h> | 22 | #include <linux/netdevice.h> |
23 | #include <linux/inetdevice.h> | 23 | #include <linux/inetdevice.h> |
24 | #include <linux/if_addr.h> | ||
24 | #include <linux/in.h> | 25 | #include <linux/in.h> |
25 | #include <linux/ip.h> | 26 | #include <linux/ip.h> |
26 | #include <net/route.h> | 27 | #include <net/route.h> |
diff --git a/net/ipv4/netfilter/ip_conntrack_netlink.c b/net/ipv4/netfilter/ip_conntrack_netlink.c index 0d4cc92391fa..52eddea27e93 100644 --- a/net/ipv4/netfilter/ip_conntrack_netlink.c +++ b/net/ipv4/netfilter/ip_conntrack_netlink.c | |||
@@ -329,11 +329,7 @@ static int ctnetlink_conntrack_event(struct notifier_block *this, | |||
329 | /* dump everything */ | 329 | /* dump everything */ |
330 | events = ~0UL; | 330 | events = ~0UL; |
331 | group = NFNLGRP_CONNTRACK_NEW; | 331 | group = NFNLGRP_CONNTRACK_NEW; |
332 | } else if (events & (IPCT_STATUS | | 332 | } else if (events & (IPCT_STATUS | IPCT_PROTOINFO)) { |
333 | IPCT_PROTOINFO | | ||
334 | IPCT_HELPER | | ||
335 | IPCT_HELPINFO | | ||
336 | IPCT_NATINFO)) { | ||
337 | type = IPCTNL_MSG_CT_NEW; | 333 | type = IPCTNL_MSG_CT_NEW; |
338 | group = NFNLGRP_CONNTRACK_UPDATE; | 334 | group = NFNLGRP_CONNTRACK_UPDATE; |
339 | } else | 335 | } else |
@@ -385,6 +381,10 @@ static int ctnetlink_conntrack_event(struct notifier_block *this, | |||
385 | ctnetlink_dump_counters(skb, ct, IP_CT_DIR_REPLY) < 0) | 381 | ctnetlink_dump_counters(skb, ct, IP_CT_DIR_REPLY) < 0) |
386 | goto nfattr_failure; | 382 | goto nfattr_failure; |
387 | 383 | ||
384 | if (events & IPCT_MARK | ||
385 | && ctnetlink_dump_mark(skb, ct) < 0) | ||
386 | goto nfattr_failure; | ||
387 | |||
388 | nlh->nlmsg_len = skb->tail - b; | 388 | nlh->nlmsg_len = skb->tail - b; |
389 | nfnetlink_send(skb, 0, group, 0); | 389 | nfnetlink_send(skb, 0, group, 0); |
390 | return NOTIFY_DONE; | 390 | return NOTIFY_DONE; |
@@ -436,6 +436,11 @@ restart: | |||
436 | cb->args[1] = (unsigned long)ct; | 436 | cb->args[1] = (unsigned long)ct; |
437 | goto out; | 437 | goto out; |
438 | } | 438 | } |
439 | #ifdef CONFIG_NF_CT_ACCT | ||
440 | if (NFNL_MSG_TYPE(cb->nlh->nlmsg_type) == | ||
441 | IPCTNL_MSG_CT_GET_CTRZERO) | ||
442 | memset(&ct->counters, 0, sizeof(ct->counters)); | ||
443 | #endif | ||
439 | } | 444 | } |
440 | if (cb->args[1]) { | 445 | if (cb->args[1]) { |
441 | cb->args[1] = 0; | 446 | cb->args[1] = 0; |
@@ -451,46 +456,6 @@ out: | |||
451 | return skb->len; | 456 | return skb->len; |
452 | } | 457 | } |
453 | 458 | ||
454 | #ifdef CONFIG_IP_NF_CT_ACCT | ||
455 | static int | ||
456 | ctnetlink_dump_table_w(struct sk_buff *skb, struct netlink_callback *cb) | ||
457 | { | ||
458 | struct ip_conntrack *ct = NULL; | ||
459 | struct ip_conntrack_tuple_hash *h; | ||
460 | struct list_head *i; | ||
461 | u_int32_t *id = (u_int32_t *) &cb->args[1]; | ||
462 | |||
463 | DEBUGP("entered %s, last bucket=%u id=%u\n", __FUNCTION__, | ||
464 | cb->args[0], *id); | ||
465 | |||
466 | write_lock_bh(&ip_conntrack_lock); | ||
467 | for (; cb->args[0] < ip_conntrack_htable_size; cb->args[0]++, *id = 0) { | ||
468 | list_for_each_prev(i, &ip_conntrack_hash[cb->args[0]]) { | ||
469 | h = (struct ip_conntrack_tuple_hash *) i; | ||
470 | if (DIRECTION(h) != IP_CT_DIR_ORIGINAL) | ||
471 | continue; | ||
472 | ct = tuplehash_to_ctrack(h); | ||
473 | if (ct->id <= *id) | ||
474 | continue; | ||
475 | if (ctnetlink_fill_info(skb, NETLINK_CB(cb->skb).pid, | ||
476 | cb->nlh->nlmsg_seq, | ||
477 | IPCTNL_MSG_CT_NEW, | ||
478 | 1, ct) < 0) | ||
479 | goto out; | ||
480 | *id = ct->id; | ||
481 | |||
482 | memset(&ct->counters, 0, sizeof(ct->counters)); | ||
483 | } | ||
484 | } | ||
485 | out: | ||
486 | write_unlock_bh(&ip_conntrack_lock); | ||
487 | |||
488 | DEBUGP("leaving, last bucket=%lu id=%u\n", cb->args[0], *id); | ||
489 | |||
490 | return skb->len; | ||
491 | } | ||
492 | #endif | ||
493 | |||
494 | static const size_t cta_min_ip[CTA_IP_MAX] = { | 459 | static const size_t cta_min_ip[CTA_IP_MAX] = { |
495 | [CTA_IP_V4_SRC-1] = sizeof(u_int32_t), | 460 | [CTA_IP_V4_SRC-1] = sizeof(u_int32_t), |
496 | [CTA_IP_V4_DST-1] = sizeof(u_int32_t), | 461 | [CTA_IP_V4_DST-1] = sizeof(u_int32_t), |
@@ -775,22 +740,14 @@ ctnetlink_get_conntrack(struct sock *ctnl, struct sk_buff *skb, | |||
775 | if (msg->nfgen_family != AF_INET) | 740 | if (msg->nfgen_family != AF_INET) |
776 | return -EAFNOSUPPORT; | 741 | return -EAFNOSUPPORT; |
777 | 742 | ||
778 | if (NFNL_MSG_TYPE(nlh->nlmsg_type) == | 743 | #ifndef CONFIG_IP_NF_CT_ACCT |
779 | IPCTNL_MSG_CT_GET_CTRZERO) { | 744 | if (NFNL_MSG_TYPE(nlh->nlmsg_type) == IPCTNL_MSG_CT_GET_CTRZERO) |
780 | #ifdef CONFIG_IP_NF_CT_ACCT | ||
781 | if ((*errp = netlink_dump_start(ctnl, skb, nlh, | ||
782 | ctnetlink_dump_table_w, | ||
783 | ctnetlink_done)) != 0) | ||
784 | return -EINVAL; | ||
785 | #else | ||
786 | return -ENOTSUPP; | 745 | return -ENOTSUPP; |
787 | #endif | 746 | #endif |
788 | } else { | 747 | if ((*errp = netlink_dump_start(ctnl, skb, nlh, |
789 | if ((*errp = netlink_dump_start(ctnl, skb, nlh, | 748 | ctnetlink_dump_table, |
790 | ctnetlink_dump_table, | 749 | ctnetlink_done)) != 0) |
791 | ctnetlink_done)) != 0) | ||
792 | return -EINVAL; | 750 | return -EINVAL; |
793 | } | ||
794 | 751 | ||
795 | rlen = NLMSG_ALIGN(nlh->nlmsg_len); | 752 | rlen = NLMSG_ALIGN(nlh->nlmsg_len); |
796 | if (rlen > skb->len) | 753 | if (rlen > skb->len) |
@@ -1253,6 +1210,9 @@ static int ctnetlink_expect_event(struct notifier_block *this, | |||
1253 | } else | 1210 | } else |
1254 | return NOTIFY_DONE; | 1211 | return NOTIFY_DONE; |
1255 | 1212 | ||
1213 | if (!nfnetlink_has_listeners(NFNLGRP_CONNTRACK_EXP_NEW)) | ||
1214 | return NOTIFY_DONE; | ||
1215 | |||
1256 | skb = alloc_skb(NLMSG_GOODSIZE, GFP_ATOMIC); | 1216 | skb = alloc_skb(NLMSG_GOODSIZE, GFP_ATOMIC); |
1257 | if (!skb) | 1217 | if (!skb) |
1258 | return NOTIFY_DONE; | 1218 | return NOTIFY_DONE; |
diff --git a/net/ipv4/netfilter/ip_conntrack_proto_generic.c b/net/ipv4/netfilter/ip_conntrack_proto_generic.c index f891308b5e4c..36f2b5e5d80a 100644 --- a/net/ipv4/netfilter/ip_conntrack_proto_generic.c +++ b/net/ipv4/netfilter/ip_conntrack_proto_generic.c | |||
@@ -12,7 +12,7 @@ | |||
12 | #include <linux/netfilter.h> | 12 | #include <linux/netfilter.h> |
13 | #include <linux/netfilter_ipv4/ip_conntrack_protocol.h> | 13 | #include <linux/netfilter_ipv4/ip_conntrack_protocol.h> |
14 | 14 | ||
15 | unsigned int ip_ct_generic_timeout = 600*HZ; | 15 | unsigned int ip_ct_generic_timeout __read_mostly = 600*HZ; |
16 | 16 | ||
17 | static int generic_pkt_to_tuple(const struct sk_buff *skb, | 17 | static int generic_pkt_to_tuple(const struct sk_buff *skb, |
18 | unsigned int dataoff, | 18 | unsigned int dataoff, |
diff --git a/net/ipv4/netfilter/ip_conntrack_proto_gre.c b/net/ipv4/netfilter/ip_conntrack_proto_gre.c index 4ee016c427b4..5fe026f467d3 100644 --- a/net/ipv4/netfilter/ip_conntrack_proto_gre.c +++ b/net/ipv4/netfilter/ip_conntrack_proto_gre.c | |||
@@ -1,15 +1,15 @@ | |||
1 | /* | 1 | /* |
2 | * ip_conntrack_proto_gre.c - Version 3.0 | 2 | * ip_conntrack_proto_gre.c - Version 3.0 |
3 | * | 3 | * |
4 | * Connection tracking protocol helper module for GRE. | 4 | * Connection tracking protocol helper module for GRE. |
5 | * | 5 | * |
6 | * GRE is a generic encapsulation protocol, which is generally not very | 6 | * GRE is a generic encapsulation protocol, which is generally not very |
7 | * suited for NAT, as it has no protocol-specific part as port numbers. | 7 | * suited for NAT, as it has no protocol-specific part as port numbers. |
8 | * | 8 | * |
9 | * It has an optional key field, which may help us distinguishing two | 9 | * It has an optional key field, which may help us distinguishing two |
10 | * connections between the same two hosts. | 10 | * connections between the same two hosts. |
11 | * | 11 | * |
12 | * GRE is defined in RFC 1701 and RFC 1702, as well as RFC 2784 | 12 | * GRE is defined in RFC 1701 and RFC 1702, as well as RFC 2784 |
13 | * | 13 | * |
14 | * PPTP is built on top of a modified version of GRE, and has a mandatory | 14 | * PPTP is built on top of a modified version of GRE, and has a mandatory |
15 | * field called "CallID", which serves us for the same purpose as the key | 15 | * field called "CallID", which serves us for the same purpose as the key |
@@ -37,7 +37,6 @@ static DEFINE_RWLOCK(ip_ct_gre_lock); | |||
37 | #define ASSERT_READ_LOCK(x) | 37 | #define ASSERT_READ_LOCK(x) |
38 | #define ASSERT_WRITE_LOCK(x) | 38 | #define ASSERT_WRITE_LOCK(x) |
39 | 39 | ||
40 | #include <linux/netfilter_ipv4/listhelp.h> | ||
41 | #include <linux/netfilter_ipv4/ip_conntrack_protocol.h> | 40 | #include <linux/netfilter_ipv4/ip_conntrack_protocol.h> |
42 | #include <linux/netfilter_ipv4/ip_conntrack_helper.h> | 41 | #include <linux/netfilter_ipv4/ip_conntrack_helper.h> |
43 | #include <linux/netfilter_ipv4/ip_conntrack_core.h> | 42 | #include <linux/netfilter_ipv4/ip_conntrack_core.h> |
@@ -62,7 +61,7 @@ MODULE_DESCRIPTION("netfilter connection tracking protocol helper for GRE"); | |||
62 | #define DEBUGP(x, args...) | 61 | #define DEBUGP(x, args...) |
63 | #define DUMP_TUPLE_GRE(x) | 62 | #define DUMP_TUPLE_GRE(x) |
64 | #endif | 63 | #endif |
65 | 64 | ||
66 | /* GRE KEYMAP HANDLING FUNCTIONS */ | 65 | /* GRE KEYMAP HANDLING FUNCTIONS */ |
67 | static LIST_HEAD(gre_keymap_list); | 66 | static LIST_HEAD(gre_keymap_list); |
68 | 67 | ||
@@ -82,12 +81,14 @@ static __be16 gre_keymap_lookup(struct ip_conntrack_tuple *t) | |||
82 | __be16 key = 0; | 81 | __be16 key = 0; |
83 | 82 | ||
84 | read_lock_bh(&ip_ct_gre_lock); | 83 | read_lock_bh(&ip_ct_gre_lock); |
85 | km = LIST_FIND(&gre_keymap_list, gre_key_cmpfn, | 84 | list_for_each_entry(km, &gre_keymap_list, list) { |
86 | struct ip_ct_gre_keymap *, t); | 85 | if (gre_key_cmpfn(km, t)) { |
87 | if (km) | 86 | key = km->tuple.src.u.gre.key; |
88 | key = km->tuple.src.u.gre.key; | 87 | break; |
88 | } | ||
89 | } | ||
89 | read_unlock_bh(&ip_ct_gre_lock); | 90 | read_unlock_bh(&ip_ct_gre_lock); |
90 | 91 | ||
91 | DEBUGP("lookup src key 0x%x up key for ", key); | 92 | DEBUGP("lookup src key 0x%x up key for ", key); |
92 | DUMP_TUPLE_GRE(t); | 93 | DUMP_TUPLE_GRE(t); |
93 | 94 | ||
@@ -99,28 +100,25 @@ int | |||
99 | ip_ct_gre_keymap_add(struct ip_conntrack *ct, | 100 | ip_ct_gre_keymap_add(struct ip_conntrack *ct, |
100 | struct ip_conntrack_tuple *t, int reply) | 101 | struct ip_conntrack_tuple *t, int reply) |
101 | { | 102 | { |
102 | struct ip_ct_gre_keymap **exist_km, *km, *old; | 103 | struct ip_ct_gre_keymap **exist_km, *km; |
103 | 104 | ||
104 | if (!ct->helper || strcmp(ct->helper->name, "pptp")) { | 105 | if (!ct->helper || strcmp(ct->helper->name, "pptp")) { |
105 | DEBUGP("refusing to add GRE keymap to non-pptp session\n"); | 106 | DEBUGP("refusing to add GRE keymap to non-pptp session\n"); |
106 | return -1; | 107 | return -1; |
107 | } | 108 | } |
108 | 109 | ||
109 | if (!reply) | 110 | if (!reply) |
110 | exist_km = &ct->help.ct_pptp_info.keymap_orig; | 111 | exist_km = &ct->help.ct_pptp_info.keymap_orig; |
111 | else | 112 | else |
112 | exist_km = &ct->help.ct_pptp_info.keymap_reply; | 113 | exist_km = &ct->help.ct_pptp_info.keymap_reply; |
113 | 114 | ||
114 | if (*exist_km) { | 115 | if (*exist_km) { |
115 | /* check whether it's a retransmission */ | 116 | /* check whether it's a retransmission */ |
116 | old = LIST_FIND(&gre_keymap_list, gre_key_cmpfn, | 117 | list_for_each_entry(km, &gre_keymap_list, list) { |
117 | struct ip_ct_gre_keymap *, t); | 118 | if (gre_key_cmpfn(km, t) && km == *exist_km) |
118 | if (old == *exist_km) { | 119 | return 0; |
119 | DEBUGP("retransmission\n"); | ||
120 | return 0; | ||
121 | } | 120 | } |
122 | 121 | DEBUGP("trying to override keymap_%s for ct %p\n", | |
123 | DEBUGP("trying to override keymap_%s for ct %p\n", | ||
124 | reply? "reply":"orig", ct); | 122 | reply? "reply":"orig", ct); |
125 | return -EEXIST; | 123 | return -EEXIST; |
126 | } | 124 | } |
@@ -136,7 +134,7 @@ ip_ct_gre_keymap_add(struct ip_conntrack *ct, | |||
136 | DUMP_TUPLE_GRE(&km->tuple); | 134 | DUMP_TUPLE_GRE(&km->tuple); |
137 | 135 | ||
138 | write_lock_bh(&ip_ct_gre_lock); | 136 | write_lock_bh(&ip_ct_gre_lock); |
139 | list_append(&gre_keymap_list, km); | 137 | list_add_tail(&km->list, &gre_keymap_list); |
140 | write_unlock_bh(&ip_ct_gre_lock); | 138 | write_unlock_bh(&ip_ct_gre_lock); |
141 | 139 | ||
142 | return 0; | 140 | return 0; |
@@ -154,7 +152,7 @@ void ip_ct_gre_keymap_destroy(struct ip_conntrack *ct) | |||
154 | 152 | ||
155 | write_lock_bh(&ip_ct_gre_lock); | 153 | write_lock_bh(&ip_ct_gre_lock); |
156 | if (ct->help.ct_pptp_info.keymap_orig) { | 154 | if (ct->help.ct_pptp_info.keymap_orig) { |
157 | DEBUGP("removing %p from list\n", | 155 | DEBUGP("removing %p from list\n", |
158 | ct->help.ct_pptp_info.keymap_orig); | 156 | ct->help.ct_pptp_info.keymap_orig); |
159 | list_del(&ct->help.ct_pptp_info.keymap_orig->list); | 157 | list_del(&ct->help.ct_pptp_info.keymap_orig->list); |
160 | kfree(ct->help.ct_pptp_info.keymap_orig); | 158 | kfree(ct->help.ct_pptp_info.keymap_orig); |
@@ -222,7 +220,7 @@ static int gre_pkt_to_tuple(const struct sk_buff *skb, | |||
222 | static int gre_print_tuple(struct seq_file *s, | 220 | static int gre_print_tuple(struct seq_file *s, |
223 | const struct ip_conntrack_tuple *tuple) | 221 | const struct ip_conntrack_tuple *tuple) |
224 | { | 222 | { |
225 | return seq_printf(s, "srckey=0x%x dstkey=0x%x ", | 223 | return seq_printf(s, "srckey=0x%x dstkey=0x%x ", |
226 | ntohs(tuple->src.u.gre.key), | 224 | ntohs(tuple->src.u.gre.key), |
227 | ntohs(tuple->dst.u.gre.key)); | 225 | ntohs(tuple->dst.u.gre.key)); |
228 | } | 226 | } |
@@ -252,14 +250,14 @@ static int gre_packet(struct ip_conntrack *ct, | |||
252 | } else | 250 | } else |
253 | ip_ct_refresh_acct(ct, conntrackinfo, skb, | 251 | ip_ct_refresh_acct(ct, conntrackinfo, skb, |
254 | ct->proto.gre.timeout); | 252 | ct->proto.gre.timeout); |
255 | 253 | ||
256 | return NF_ACCEPT; | 254 | return NF_ACCEPT; |
257 | } | 255 | } |
258 | 256 | ||
259 | /* Called when a new connection for this protocol found. */ | 257 | /* Called when a new connection for this protocol found. */ |
260 | static int gre_new(struct ip_conntrack *ct, | 258 | static int gre_new(struct ip_conntrack *ct, |
261 | const struct sk_buff *skb) | 259 | const struct sk_buff *skb) |
262 | { | 260 | { |
263 | DEBUGP(": "); | 261 | DEBUGP(": "); |
264 | DUMP_TUPLE_GRE(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple); | 262 | DUMP_TUPLE_GRE(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple); |
265 | 263 | ||
@@ -285,9 +283,9 @@ static void gre_destroy(struct ip_conntrack *ct) | |||
285 | } | 283 | } |
286 | 284 | ||
287 | /* protocol helper struct */ | 285 | /* protocol helper struct */ |
288 | static struct ip_conntrack_protocol gre = { | 286 | static struct ip_conntrack_protocol gre = { |
289 | .proto = IPPROTO_GRE, | 287 | .proto = IPPROTO_GRE, |
290 | .name = "gre", | 288 | .name = "gre", |
291 | .pkt_to_tuple = gre_pkt_to_tuple, | 289 | .pkt_to_tuple = gre_pkt_to_tuple, |
292 | .invert_tuple = gre_invert_tuple, | 290 | .invert_tuple = gre_invert_tuple, |
293 | .print_tuple = gre_print_tuple, | 291 | .print_tuple = gre_print_tuple, |
@@ -325,7 +323,7 @@ void ip_ct_proto_gre_fini(void) | |||
325 | } | 323 | } |
326 | write_unlock_bh(&ip_ct_gre_lock); | 324 | write_unlock_bh(&ip_ct_gre_lock); |
327 | 325 | ||
328 | ip_conntrack_protocol_unregister(&gre); | 326 | ip_conntrack_protocol_unregister(&gre); |
329 | } | 327 | } |
330 | 328 | ||
331 | EXPORT_SYMBOL(ip_ct_gre_keymap_add); | 329 | EXPORT_SYMBOL(ip_ct_gre_keymap_add); |
diff --git a/net/ipv4/netfilter/ip_conntrack_proto_icmp.c b/net/ipv4/netfilter/ip_conntrack_proto_icmp.c index 23f1c504586d..09c40ebe3345 100644 --- a/net/ipv4/netfilter/ip_conntrack_proto_icmp.c +++ b/net/ipv4/netfilter/ip_conntrack_proto_icmp.c | |||
@@ -21,7 +21,7 @@ | |||
21 | #include <linux/netfilter_ipv4/ip_conntrack_core.h> | 21 | #include <linux/netfilter_ipv4/ip_conntrack_core.h> |
22 | #include <linux/netfilter_ipv4/ip_conntrack_protocol.h> | 22 | #include <linux/netfilter_ipv4/ip_conntrack_protocol.h> |
23 | 23 | ||
24 | unsigned int ip_ct_icmp_timeout = 30*HZ; | 24 | unsigned int ip_ct_icmp_timeout __read_mostly = 30*HZ; |
25 | 25 | ||
26 | #if 0 | 26 | #if 0 |
27 | #define DEBUGP printk | 27 | #define DEBUGP printk |
diff --git a/net/ipv4/netfilter/ip_conntrack_proto_sctp.c b/net/ipv4/netfilter/ip_conntrack_proto_sctp.c index 2d3612cd5f18..b908a4842e18 100644 --- a/net/ipv4/netfilter/ip_conntrack_proto_sctp.c +++ b/net/ipv4/netfilter/ip_conntrack_proto_sctp.c | |||
@@ -58,13 +58,13 @@ static const char *sctp_conntrack_names[] = { | |||
58 | #define HOURS * 60 MINS | 58 | #define HOURS * 60 MINS |
59 | #define DAYS * 24 HOURS | 59 | #define DAYS * 24 HOURS |
60 | 60 | ||
61 | static unsigned int ip_ct_sctp_timeout_closed = 10 SECS; | 61 | static unsigned int ip_ct_sctp_timeout_closed __read_mostly = 10 SECS; |
62 | static unsigned int ip_ct_sctp_timeout_cookie_wait = 3 SECS; | 62 | static unsigned int ip_ct_sctp_timeout_cookie_wait __read_mostly = 3 SECS; |
63 | static unsigned int ip_ct_sctp_timeout_cookie_echoed = 3 SECS; | 63 | static unsigned int ip_ct_sctp_timeout_cookie_echoed __read_mostly = 3 SECS; |
64 | static unsigned int ip_ct_sctp_timeout_established = 5 DAYS; | 64 | static unsigned int ip_ct_sctp_timeout_established __read_mostly = 5 DAYS; |
65 | static unsigned int ip_ct_sctp_timeout_shutdown_sent = 300 SECS / 1000; | 65 | static unsigned int ip_ct_sctp_timeout_shutdown_sent __read_mostly = 300 SECS / 1000; |
66 | static unsigned int ip_ct_sctp_timeout_shutdown_recd = 300 SECS / 1000; | 66 | static unsigned int ip_ct_sctp_timeout_shutdown_recd __read_mostly = 300 SECS / 1000; |
67 | static unsigned int ip_ct_sctp_timeout_shutdown_ack_sent = 3 SECS; | 67 | static unsigned int ip_ct_sctp_timeout_shutdown_ack_sent __read_mostly = 3 SECS; |
68 | 68 | ||
69 | static const unsigned int * sctp_timeouts[] | 69 | static const unsigned int * sctp_timeouts[] |
70 | = { NULL, /* SCTP_CONNTRACK_NONE */ | 70 | = { NULL, /* SCTP_CONNTRACK_NONE */ |
diff --git a/net/ipv4/netfilter/ip_conntrack_proto_tcp.c b/net/ipv4/netfilter/ip_conntrack_proto_tcp.c index fb920e76ec10..03ae9a04cb37 100644 --- a/net/ipv4/netfilter/ip_conntrack_proto_tcp.c +++ b/net/ipv4/netfilter/ip_conntrack_proto_tcp.c | |||
@@ -48,19 +48,19 @@ static DEFINE_RWLOCK(tcp_lock); | |||
48 | /* "Be conservative in what you do, | 48 | /* "Be conservative in what you do, |
49 | be liberal in what you accept from others." | 49 | be liberal in what you accept from others." |
50 | If it's non-zero, we mark only out of window RST segments as INVALID. */ | 50 | If it's non-zero, we mark only out of window RST segments as INVALID. */ |
51 | int ip_ct_tcp_be_liberal = 0; | 51 | int ip_ct_tcp_be_liberal __read_mostly = 0; |
52 | 52 | ||
53 | /* When connection is picked up from the middle, how many packets are required | 53 | /* When connection is picked up from the middle, how many packets are required |
54 | to pass in each direction when we assume we are in sync - if any side uses | 54 | to pass in each direction when we assume we are in sync - if any side uses |
55 | window scaling, we lost the game. | 55 | window scaling, we lost the game. |
56 | If it is set to zero, we disable picking up already established | 56 | If it is set to zero, we disable picking up already established |
57 | connections. */ | 57 | connections. */ |
58 | int ip_ct_tcp_loose = 3; | 58 | int ip_ct_tcp_loose __read_mostly = 3; |
59 | 59 | ||
60 | /* Max number of the retransmitted packets without receiving an (acceptable) | 60 | /* Max number of the retransmitted packets without receiving an (acceptable) |
61 | ACK from the destination. If this number is reached, a shorter timer | 61 | ACK from the destination. If this number is reached, a shorter timer |
62 | will be started. */ | 62 | will be started. */ |
63 | int ip_ct_tcp_max_retrans = 3; | 63 | int ip_ct_tcp_max_retrans __read_mostly = 3; |
64 | 64 | ||
65 | /* FIXME: Examine ipfilter's timeouts and conntrack transitions more | 65 | /* FIXME: Examine ipfilter's timeouts and conntrack transitions more |
66 | closely. They're more complex. --RR */ | 66 | closely. They're more complex. --RR */ |
@@ -83,19 +83,19 @@ static const char *tcp_conntrack_names[] = { | |||
83 | #define HOURS * 60 MINS | 83 | #define HOURS * 60 MINS |
84 | #define DAYS * 24 HOURS | 84 | #define DAYS * 24 HOURS |
85 | 85 | ||
86 | unsigned int ip_ct_tcp_timeout_syn_sent = 2 MINS; | 86 | unsigned int ip_ct_tcp_timeout_syn_sent __read_mostly = 2 MINS; |
87 | unsigned int ip_ct_tcp_timeout_syn_recv = 60 SECS; | 87 | unsigned int ip_ct_tcp_timeout_syn_recv __read_mostly = 60 SECS; |
88 | unsigned int ip_ct_tcp_timeout_established = 5 DAYS; | 88 | unsigned int ip_ct_tcp_timeout_established __read_mostly = 5 DAYS; |
89 | unsigned int ip_ct_tcp_timeout_fin_wait = 2 MINS; | 89 | unsigned int ip_ct_tcp_timeout_fin_wait __read_mostly = 2 MINS; |
90 | unsigned int ip_ct_tcp_timeout_close_wait = 60 SECS; | 90 | unsigned int ip_ct_tcp_timeout_close_wait __read_mostly = 60 SECS; |
91 | unsigned int ip_ct_tcp_timeout_last_ack = 30 SECS; | 91 | unsigned int ip_ct_tcp_timeout_last_ack __read_mostly = 30 SECS; |
92 | unsigned int ip_ct_tcp_timeout_time_wait = 2 MINS; | 92 | unsigned int ip_ct_tcp_timeout_time_wait __read_mostly = 2 MINS; |
93 | unsigned int ip_ct_tcp_timeout_close = 10 SECS; | 93 | unsigned int ip_ct_tcp_timeout_close __read_mostly = 10 SECS; |
94 | 94 | ||
95 | /* RFC1122 says the R2 limit should be at least 100 seconds. | 95 | /* RFC1122 says the R2 limit should be at least 100 seconds. |
96 | Linux uses 15 packets as limit, which corresponds | 96 | Linux uses 15 packets as limit, which corresponds |
97 | to ~13-30min depending on RTO. */ | 97 | to ~13-30min depending on RTO. */ |
98 | unsigned int ip_ct_tcp_timeout_max_retrans = 5 MINS; | 98 | unsigned int ip_ct_tcp_timeout_max_retrans __read_mostly = 5 MINS; |
99 | 99 | ||
100 | static const unsigned int * tcp_timeouts[] | 100 | static const unsigned int * tcp_timeouts[] |
101 | = { NULL, /* TCP_CONNTRACK_NONE */ | 101 | = { NULL, /* TCP_CONNTRACK_NONE */ |
@@ -731,13 +731,15 @@ static int tcp_in_window(struct ip_ct_tcp *state, | |||
731 | if (state->last_dir == dir | 731 | if (state->last_dir == dir |
732 | && state->last_seq == seq | 732 | && state->last_seq == seq |
733 | && state->last_ack == ack | 733 | && state->last_ack == ack |
734 | && state->last_end == end) | 734 | && state->last_end == end |
735 | && state->last_win == win) | ||
735 | state->retrans++; | 736 | state->retrans++; |
736 | else { | 737 | else { |
737 | state->last_dir = dir; | 738 | state->last_dir = dir; |
738 | state->last_seq = seq; | 739 | state->last_seq = seq; |
739 | state->last_ack = ack; | 740 | state->last_ack = ack; |
740 | state->last_end = end; | 741 | state->last_end = end; |
742 | state->last_win = win; | ||
741 | state->retrans = 0; | 743 | state->retrans = 0; |
742 | } | 744 | } |
743 | } | 745 | } |
@@ -865,8 +867,7 @@ static int tcp_error(struct sk_buff *skb, | |||
865 | 867 | ||
866 | /* Checksum invalid? Ignore. | 868 | /* Checksum invalid? Ignore. |
867 | * We skip checking packets on the outgoing path | 869 | * We skip checking packets on the outgoing path |
868 | * because the semantic of CHECKSUM_HW is different there | 870 | * because it is assumed to be correct. |
869 | * and moreover root might send raw packets. | ||
870 | */ | 871 | */ |
871 | /* FIXME: Source route IP option packets --RR */ | 872 | /* FIXME: Source route IP option packets --RR */ |
872 | if (ip_conntrack_checksum && hooknum == NF_IP_PRE_ROUTING && | 873 | if (ip_conntrack_checksum && hooknum == NF_IP_PRE_ROUTING && |
diff --git a/net/ipv4/netfilter/ip_conntrack_proto_udp.c b/net/ipv4/netfilter/ip_conntrack_proto_udp.c index 9b2c16b4d2ff..d0e8a16970ec 100644 --- a/net/ipv4/netfilter/ip_conntrack_proto_udp.c +++ b/net/ipv4/netfilter/ip_conntrack_proto_udp.c | |||
@@ -18,8 +18,8 @@ | |||
18 | #include <linux/netfilter_ipv4.h> | 18 | #include <linux/netfilter_ipv4.h> |
19 | #include <linux/netfilter_ipv4/ip_conntrack_protocol.h> | 19 | #include <linux/netfilter_ipv4/ip_conntrack_protocol.h> |
20 | 20 | ||
21 | unsigned int ip_ct_udp_timeout = 30*HZ; | 21 | unsigned int ip_ct_udp_timeout __read_mostly = 30*HZ; |
22 | unsigned int ip_ct_udp_timeout_stream = 180*HZ; | 22 | unsigned int ip_ct_udp_timeout_stream __read_mostly = 180*HZ; |
23 | 23 | ||
24 | static int udp_pkt_to_tuple(const struct sk_buff *skb, | 24 | static int udp_pkt_to_tuple(const struct sk_buff *skb, |
25 | unsigned int dataoff, | 25 | unsigned int dataoff, |
@@ -117,8 +117,7 @@ static int udp_error(struct sk_buff *skb, enum ip_conntrack_info *ctinfo, | |||
117 | 117 | ||
118 | /* Checksum invalid? Ignore. | 118 | /* Checksum invalid? Ignore. |
119 | * We skip checking packets on the outgoing path | 119 | * We skip checking packets on the outgoing path |
120 | * because the semantic of CHECKSUM_HW is different there | 120 | * because the checksum is assumed to be correct. |
121 | * and moreover root might send raw packets. | ||
122 | * FIXME: Source route IP option packets --RR */ | 121 | * FIXME: Source route IP option packets --RR */ |
123 | if (ip_conntrack_checksum && hooknum == NF_IP_PRE_ROUTING && | 122 | if (ip_conntrack_checksum && hooknum == NF_IP_PRE_ROUTING && |
124 | nf_ip_checksum(skb, hooknum, iph->ihl * 4, IPPROTO_UDP)) { | 123 | nf_ip_checksum(skb, hooknum, iph->ihl * 4, IPPROTO_UDP)) { |
diff --git a/net/ipv4/netfilter/ip_conntrack_sip.c b/net/ipv4/netfilter/ip_conntrack_sip.c index 4f222d6be009..2893e9c74850 100644 --- a/net/ipv4/netfilter/ip_conntrack_sip.c +++ b/net/ipv4/netfilter/ip_conntrack_sip.c | |||
@@ -8,7 +8,6 @@ | |||
8 | * published by the Free Software Foundation. | 8 | * published by the Free Software Foundation. |
9 | */ | 9 | */ |
10 | 10 | ||
11 | #include <linux/config.h> | ||
12 | #include <linux/module.h> | 11 | #include <linux/module.h> |
13 | #include <linux/ctype.h> | 12 | #include <linux/ctype.h> |
14 | #include <linux/skbuff.h> | 13 | #include <linux/skbuff.h> |
diff --git a/net/ipv4/netfilter/ip_conntrack_standalone.c b/net/ipv4/netfilter/ip_conntrack_standalone.c index 7a9fa04a467a..02135756562e 100644 --- a/net/ipv4/netfilter/ip_conntrack_standalone.c +++ b/net/ipv4/netfilter/ip_conntrack_standalone.c | |||
@@ -35,7 +35,6 @@ | |||
35 | #include <linux/netfilter_ipv4/ip_conntrack_protocol.h> | 35 | #include <linux/netfilter_ipv4/ip_conntrack_protocol.h> |
36 | #include <linux/netfilter_ipv4/ip_conntrack_core.h> | 36 | #include <linux/netfilter_ipv4/ip_conntrack_core.h> |
37 | #include <linux/netfilter_ipv4/ip_conntrack_helper.h> | 37 | #include <linux/netfilter_ipv4/ip_conntrack_helper.h> |
38 | #include <linux/netfilter_ipv4/listhelp.h> | ||
39 | 38 | ||
40 | #if 0 | 39 | #if 0 |
41 | #define DEBUGP printk | 40 | #define DEBUGP printk |
@@ -534,7 +533,7 @@ static struct nf_hook_ops ip_conntrack_ops[] = { | |||
534 | 533 | ||
535 | /* Sysctl support */ | 534 | /* Sysctl support */ |
536 | 535 | ||
537 | int ip_conntrack_checksum = 1; | 536 | int ip_conntrack_checksum __read_mostly = 1; |
538 | 537 | ||
539 | #ifdef CONFIG_SYSCTL | 538 | #ifdef CONFIG_SYSCTL |
540 | 539 | ||
@@ -563,7 +562,7 @@ extern unsigned int ip_ct_udp_timeout_stream; | |||
563 | /* From ip_conntrack_proto_icmp.c */ | 562 | /* From ip_conntrack_proto_icmp.c */ |
564 | extern unsigned int ip_ct_icmp_timeout; | 563 | extern unsigned int ip_ct_icmp_timeout; |
565 | 564 | ||
566 | /* From ip_conntrack_proto_icmp.c */ | 565 | /* From ip_conntrack_proto_generic.c */ |
567 | extern unsigned int ip_ct_generic_timeout; | 566 | extern unsigned int ip_ct_generic_timeout; |
568 | 567 | ||
569 | /* Log invalid packets of a given protocol */ | 568 | /* Log invalid packets of a given protocol */ |
diff --git a/net/ipv4/netfilter/ip_nat_core.c b/net/ipv4/netfilter/ip_nat_core.c index 1741d555ad0d..71f3e09cbc84 100644 --- a/net/ipv4/netfilter/ip_nat_core.c +++ b/net/ipv4/netfilter/ip_nat_core.c | |||
@@ -22,9 +22,6 @@ | |||
22 | #include <linux/udp.h> | 22 | #include <linux/udp.h> |
23 | #include <linux/jhash.h> | 23 | #include <linux/jhash.h> |
24 | 24 | ||
25 | #define ASSERT_READ_LOCK(x) | ||
26 | #define ASSERT_WRITE_LOCK(x) | ||
27 | |||
28 | #include <linux/netfilter_ipv4/ip_conntrack.h> | 25 | #include <linux/netfilter_ipv4/ip_conntrack.h> |
29 | #include <linux/netfilter_ipv4/ip_conntrack_core.h> | 26 | #include <linux/netfilter_ipv4/ip_conntrack_core.h> |
30 | #include <linux/netfilter_ipv4/ip_conntrack_protocol.h> | 27 | #include <linux/netfilter_ipv4/ip_conntrack_protocol.h> |
@@ -33,7 +30,6 @@ | |||
33 | #include <linux/netfilter_ipv4/ip_nat_core.h> | 30 | #include <linux/netfilter_ipv4/ip_nat_core.h> |
34 | #include <linux/netfilter_ipv4/ip_nat_helper.h> | 31 | #include <linux/netfilter_ipv4/ip_nat_helper.h> |
35 | #include <linux/netfilter_ipv4/ip_conntrack_helper.h> | 32 | #include <linux/netfilter_ipv4/ip_conntrack_helper.h> |
36 | #include <linux/netfilter_ipv4/listhelp.h> | ||
37 | 33 | ||
38 | #if 0 | 34 | #if 0 |
39 | #define DEBUGP printk | 35 | #define DEBUGP printk |
@@ -101,18 +97,6 @@ static void ip_nat_cleanup_conntrack(struct ip_conntrack *conn) | |||
101 | write_unlock_bh(&ip_nat_lock); | 97 | write_unlock_bh(&ip_nat_lock); |
102 | } | 98 | } |
103 | 99 | ||
104 | /* We do checksum mangling, so if they were wrong before they're still | ||
105 | * wrong. Also works for incomplete packets (eg. ICMP dest | ||
106 | * unreachables.) */ | ||
107 | u_int16_t | ||
108 | ip_nat_cheat_check(u_int32_t oldvalinv, u_int32_t newval, u_int16_t oldcheck) | ||
109 | { | ||
110 | u_int32_t diffs[] = { oldvalinv, newval }; | ||
111 | return csum_fold(csum_partial((char *)diffs, sizeof(diffs), | ||
112 | oldcheck^0xFFFF)); | ||
113 | } | ||
114 | EXPORT_SYMBOL(ip_nat_cheat_check); | ||
115 | |||
116 | /* Is this tuple already taken? (not by us) */ | 100 | /* Is this tuple already taken? (not by us) */ |
117 | int | 101 | int |
118 | ip_nat_used_tuple(const struct ip_conntrack_tuple *tuple, | 102 | ip_nat_used_tuple(const struct ip_conntrack_tuple *tuple, |
@@ -378,12 +362,12 @@ manip_pkt(u_int16_t proto, | |||
378 | iph = (void *)(*pskb)->data + iphdroff; | 362 | iph = (void *)(*pskb)->data + iphdroff; |
379 | 363 | ||
380 | if (maniptype == IP_NAT_MANIP_SRC) { | 364 | if (maniptype == IP_NAT_MANIP_SRC) { |
381 | iph->check = ip_nat_cheat_check(~iph->saddr, target->src.ip, | 365 | iph->check = nf_csum_update(~iph->saddr, target->src.ip, |
382 | iph->check); | 366 | iph->check); |
383 | iph->saddr = target->src.ip; | 367 | iph->saddr = target->src.ip; |
384 | } else { | 368 | } else { |
385 | iph->check = ip_nat_cheat_check(~iph->daddr, target->dst.ip, | 369 | iph->check = nf_csum_update(~iph->daddr, target->dst.ip, |
386 | iph->check); | 370 | iph->check); |
387 | iph->daddr = target->dst.ip; | 371 | iph->daddr = target->dst.ip; |
388 | } | 372 | } |
389 | return 1; | 373 | return 1; |
@@ -423,10 +407,10 @@ unsigned int ip_nat_packet(struct ip_conntrack *ct, | |||
423 | EXPORT_SYMBOL_GPL(ip_nat_packet); | 407 | EXPORT_SYMBOL_GPL(ip_nat_packet); |
424 | 408 | ||
425 | /* Dir is direction ICMP is coming from (opposite to packet it contains) */ | 409 | /* Dir is direction ICMP is coming from (opposite to packet it contains) */ |
426 | int ip_nat_icmp_reply_translation(struct sk_buff **pskb, | 410 | int ip_nat_icmp_reply_translation(struct ip_conntrack *ct, |
427 | struct ip_conntrack *ct, | 411 | enum ip_conntrack_info ctinfo, |
428 | enum ip_nat_manip_type manip, | 412 | unsigned int hooknum, |
429 | enum ip_conntrack_dir dir) | 413 | struct sk_buff **pskb) |
430 | { | 414 | { |
431 | struct { | 415 | struct { |
432 | struct icmphdr icmp; | 416 | struct icmphdr icmp; |
@@ -434,7 +418,9 @@ int ip_nat_icmp_reply_translation(struct sk_buff **pskb, | |||
434 | } *inside; | 418 | } *inside; |
435 | struct ip_conntrack_tuple inner, target; | 419 | struct ip_conntrack_tuple inner, target; |
436 | int hdrlen = (*pskb)->nh.iph->ihl * 4; | 420 | int hdrlen = (*pskb)->nh.iph->ihl * 4; |
421 | enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo); | ||
437 | unsigned long statusbit; | 422 | unsigned long statusbit; |
423 | enum ip_nat_manip_type manip = HOOK2MANIP(hooknum); | ||
438 | 424 | ||
439 | if (!skb_make_writable(pskb, hdrlen + sizeof(*inside))) | 425 | if (!skb_make_writable(pskb, hdrlen + sizeof(*inside))) |
440 | return 0; | 426 | return 0; |
@@ -443,12 +429,8 @@ int ip_nat_icmp_reply_translation(struct sk_buff **pskb, | |||
443 | 429 | ||
444 | /* We're actually going to mangle it beyond trivial checksum | 430 | /* We're actually going to mangle it beyond trivial checksum |
445 | adjustment, so make sure the current checksum is correct. */ | 431 | adjustment, so make sure the current checksum is correct. */ |
446 | if ((*pskb)->ip_summed != CHECKSUM_UNNECESSARY) { | 432 | if (nf_ip_checksum(*pskb, hooknum, hdrlen, 0)) |
447 | hdrlen = (*pskb)->nh.iph->ihl * 4; | 433 | return 0; |
448 | if ((u16)csum_fold(skb_checksum(*pskb, hdrlen, | ||
449 | (*pskb)->len - hdrlen, 0))) | ||
450 | return 0; | ||
451 | } | ||
452 | 434 | ||
453 | /* Must be RELATED */ | 435 | /* Must be RELATED */ |
454 | IP_NF_ASSERT((*pskb)->nfctinfo == IP_CT_RELATED || | 436 | IP_NF_ASSERT((*pskb)->nfctinfo == IP_CT_RELATED || |
@@ -487,12 +469,14 @@ int ip_nat_icmp_reply_translation(struct sk_buff **pskb, | |||
487 | !manip)) | 469 | !manip)) |
488 | return 0; | 470 | return 0; |
489 | 471 | ||
490 | /* Reloading "inside" here since manip_pkt inner. */ | 472 | if ((*pskb)->ip_summed != CHECKSUM_PARTIAL) { |
491 | inside = (void *)(*pskb)->data + (*pskb)->nh.iph->ihl*4; | 473 | /* Reloading "inside" here since manip_pkt inner. */ |
492 | inside->icmp.checksum = 0; | 474 | inside = (void *)(*pskb)->data + (*pskb)->nh.iph->ihl*4; |
493 | inside->icmp.checksum = csum_fold(skb_checksum(*pskb, hdrlen, | 475 | inside->icmp.checksum = 0; |
494 | (*pskb)->len - hdrlen, | 476 | inside->icmp.checksum = csum_fold(skb_checksum(*pskb, hdrlen, |
495 | 0)); | 477 | (*pskb)->len - hdrlen, |
478 | 0)); | ||
479 | } | ||
496 | 480 | ||
497 | /* Change outer to look the reply to an incoming packet | 481 | /* Change outer to look the reply to an incoming packet |
498 | * (proto 0 means don't invert per-proto part). */ | 482 | * (proto 0 means don't invert per-proto part). */ |
diff --git a/net/ipv4/netfilter/ip_nat_helper.c b/net/ipv4/netfilter/ip_nat_helper.c index cbcaa45370ae..7f6a75984f6c 100644 --- a/net/ipv4/netfilter/ip_nat_helper.c +++ b/net/ipv4/netfilter/ip_nat_helper.c | |||
@@ -27,16 +27,12 @@ | |||
27 | #include <net/tcp.h> | 27 | #include <net/tcp.h> |
28 | #include <net/udp.h> | 28 | #include <net/udp.h> |
29 | 29 | ||
30 | #define ASSERT_READ_LOCK(x) | ||
31 | #define ASSERT_WRITE_LOCK(x) | ||
32 | |||
33 | #include <linux/netfilter_ipv4/ip_conntrack.h> | 30 | #include <linux/netfilter_ipv4/ip_conntrack.h> |
34 | #include <linux/netfilter_ipv4/ip_conntrack_helper.h> | 31 | #include <linux/netfilter_ipv4/ip_conntrack_helper.h> |
35 | #include <linux/netfilter_ipv4/ip_nat.h> | 32 | #include <linux/netfilter_ipv4/ip_nat.h> |
36 | #include <linux/netfilter_ipv4/ip_nat_protocol.h> | 33 | #include <linux/netfilter_ipv4/ip_nat_protocol.h> |
37 | #include <linux/netfilter_ipv4/ip_nat_core.h> | 34 | #include <linux/netfilter_ipv4/ip_nat_core.h> |
38 | #include <linux/netfilter_ipv4/ip_nat_helper.h> | 35 | #include <linux/netfilter_ipv4/ip_nat_helper.h> |
39 | #include <linux/netfilter_ipv4/listhelp.h> | ||
40 | 36 | ||
41 | #if 0 | 37 | #if 0 |
42 | #define DEBUGP printk | 38 | #define DEBUGP printk |
@@ -165,7 +161,7 @@ ip_nat_mangle_tcp_packet(struct sk_buff **pskb, | |||
165 | { | 161 | { |
166 | struct iphdr *iph; | 162 | struct iphdr *iph; |
167 | struct tcphdr *tcph; | 163 | struct tcphdr *tcph; |
168 | int datalen; | 164 | int oldlen, datalen; |
169 | 165 | ||
170 | if (!skb_make_writable(pskb, (*pskb)->len)) | 166 | if (!skb_make_writable(pskb, (*pskb)->len)) |
171 | return 0; | 167 | return 0; |
@@ -180,13 +176,22 @@ ip_nat_mangle_tcp_packet(struct sk_buff **pskb, | |||
180 | iph = (*pskb)->nh.iph; | 176 | iph = (*pskb)->nh.iph; |
181 | tcph = (void *)iph + iph->ihl*4; | 177 | tcph = (void *)iph + iph->ihl*4; |
182 | 178 | ||
179 | oldlen = (*pskb)->len - iph->ihl*4; | ||
183 | mangle_contents(*pskb, iph->ihl*4 + tcph->doff*4, | 180 | mangle_contents(*pskb, iph->ihl*4 + tcph->doff*4, |
184 | match_offset, match_len, rep_buffer, rep_len); | 181 | match_offset, match_len, rep_buffer, rep_len); |
185 | 182 | ||
186 | datalen = (*pskb)->len - iph->ihl*4; | 183 | datalen = (*pskb)->len - iph->ihl*4; |
187 | tcph->check = 0; | 184 | if ((*pskb)->ip_summed != CHECKSUM_PARTIAL) { |
188 | tcph->check = tcp_v4_check(tcph, datalen, iph->saddr, iph->daddr, | 185 | tcph->check = 0; |
189 | csum_partial((char *)tcph, datalen, 0)); | 186 | tcph->check = tcp_v4_check(tcph, datalen, |
187 | iph->saddr, iph->daddr, | ||
188 | csum_partial((char *)tcph, | ||
189 | datalen, 0)); | ||
190 | } else | ||
191 | tcph->check = nf_proto_csum_update(*pskb, | ||
192 | htons(oldlen) ^ 0xFFFF, | ||
193 | htons(datalen), | ||
194 | tcph->check, 1); | ||
190 | 195 | ||
191 | if (rep_len != match_len) { | 196 | if (rep_len != match_len) { |
192 | set_bit(IPS_SEQ_ADJUST_BIT, &ct->status); | 197 | set_bit(IPS_SEQ_ADJUST_BIT, &ct->status); |
@@ -221,6 +226,7 @@ ip_nat_mangle_udp_packet(struct sk_buff **pskb, | |||
221 | { | 226 | { |
222 | struct iphdr *iph; | 227 | struct iphdr *iph; |
223 | struct udphdr *udph; | 228 | struct udphdr *udph; |
229 | int datalen, oldlen; | ||
224 | 230 | ||
225 | /* UDP helpers might accidentally mangle the wrong packet */ | 231 | /* UDP helpers might accidentally mangle the wrong packet */ |
226 | iph = (*pskb)->nh.iph; | 232 | iph = (*pskb)->nh.iph; |
@@ -238,22 +244,32 @@ ip_nat_mangle_udp_packet(struct sk_buff **pskb, | |||
238 | 244 | ||
239 | iph = (*pskb)->nh.iph; | 245 | iph = (*pskb)->nh.iph; |
240 | udph = (void *)iph + iph->ihl*4; | 246 | udph = (void *)iph + iph->ihl*4; |
247 | |||
248 | oldlen = (*pskb)->len - iph->ihl*4; | ||
241 | mangle_contents(*pskb, iph->ihl*4 + sizeof(*udph), | 249 | mangle_contents(*pskb, iph->ihl*4 + sizeof(*udph), |
242 | match_offset, match_len, rep_buffer, rep_len); | 250 | match_offset, match_len, rep_buffer, rep_len); |
243 | 251 | ||
244 | /* update the length of the UDP packet */ | 252 | /* update the length of the UDP packet */ |
245 | udph->len = htons((*pskb)->len - iph->ihl*4); | 253 | datalen = (*pskb)->len - iph->ihl*4; |
254 | udph->len = htons(datalen); | ||
246 | 255 | ||
247 | /* fix udp checksum if udp checksum was previously calculated */ | 256 | /* fix udp checksum if udp checksum was previously calculated */ |
248 | if (udph->check) { | 257 | if (!udph->check && (*pskb)->ip_summed != CHECKSUM_PARTIAL) |
249 | int datalen = (*pskb)->len - iph->ihl * 4; | 258 | return 1; |
259 | |||
260 | if ((*pskb)->ip_summed != CHECKSUM_PARTIAL) { | ||
250 | udph->check = 0; | 261 | udph->check = 0; |
251 | udph->check = csum_tcpudp_magic(iph->saddr, iph->daddr, | 262 | udph->check = csum_tcpudp_magic(iph->saddr, iph->daddr, |
252 | datalen, IPPROTO_UDP, | 263 | datalen, IPPROTO_UDP, |
253 | csum_partial((char *)udph, | 264 | csum_partial((char *)udph, |
254 | datalen, 0)); | 265 | datalen, 0)); |
255 | } | 266 | if (!udph->check) |
256 | 267 | udph->check = -1; | |
268 | } else | ||
269 | udph->check = nf_proto_csum_update(*pskb, | ||
270 | htons(oldlen) ^ 0xFFFF, | ||
271 | htons(datalen), | ||
272 | udph->check, 1); | ||
257 | return 1; | 273 | return 1; |
258 | } | 274 | } |
259 | EXPORT_SYMBOL(ip_nat_mangle_udp_packet); | 275 | EXPORT_SYMBOL(ip_nat_mangle_udp_packet); |
@@ -293,11 +309,14 @@ sack_adjust(struct sk_buff *skb, | |||
293 | ntohl(sack->start_seq), new_start_seq, | 309 | ntohl(sack->start_seq), new_start_seq, |
294 | ntohl(sack->end_seq), new_end_seq); | 310 | ntohl(sack->end_seq), new_end_seq); |
295 | 311 | ||
296 | tcph->check = | 312 | tcph->check = nf_proto_csum_update(skb, |
297 | ip_nat_cheat_check(~sack->start_seq, new_start_seq, | 313 | ~sack->start_seq, |
298 | ip_nat_cheat_check(~sack->end_seq, | 314 | new_start_seq, |
299 | new_end_seq, | 315 | tcph->check, 0); |
300 | tcph->check)); | 316 | tcph->check = nf_proto_csum_update(skb, |
317 | ~sack->end_seq, | ||
318 | new_end_seq, | ||
319 | tcph->check, 0); | ||
301 | sack->start_seq = new_start_seq; | 320 | sack->start_seq = new_start_seq; |
302 | sack->end_seq = new_end_seq; | 321 | sack->end_seq = new_end_seq; |
303 | sackoff += sizeof(*sack); | 322 | sackoff += sizeof(*sack); |
@@ -381,10 +400,10 @@ ip_nat_seq_adjust(struct sk_buff **pskb, | |||
381 | newack = ntohl(tcph->ack_seq) - other_way->offset_before; | 400 | newack = ntohl(tcph->ack_seq) - other_way->offset_before; |
382 | newack = htonl(newack); | 401 | newack = htonl(newack); |
383 | 402 | ||
384 | tcph->check = ip_nat_cheat_check(~tcph->seq, newseq, | 403 | tcph->check = nf_proto_csum_update(*pskb, ~tcph->seq, newseq, |
385 | ip_nat_cheat_check(~tcph->ack_seq, | 404 | tcph->check, 0); |
386 | newack, | 405 | tcph->check = nf_proto_csum_update(*pskb, ~tcph->ack_seq, newack, |
387 | tcph->check)); | 406 | tcph->check, 0); |
388 | 407 | ||
389 | DEBUGP("Adjusting sequence number from %u->%u, ack from %u->%u\n", | 408 | DEBUGP("Adjusting sequence number from %u->%u, ack from %u->%u\n", |
390 | ntohl(tcph->seq), ntohl(newseq), ntohl(tcph->ack_seq), | 409 | ntohl(tcph->seq), ntohl(newseq), ntohl(tcph->ack_seq), |
diff --git a/net/ipv4/netfilter/ip_nat_helper_pptp.c b/net/ipv4/netfilter/ip_nat_helper_pptp.c index 1d149964dc38..2ff578807123 100644 --- a/net/ipv4/netfilter/ip_nat_helper_pptp.c +++ b/net/ipv4/netfilter/ip_nat_helper_pptp.c | |||
@@ -32,7 +32,7 @@ | |||
32 | * 2005-06-10 - Version 3.0 | 32 | * 2005-06-10 - Version 3.0 |
33 | * - kernel >= 2.6.11 version, | 33 | * - kernel >= 2.6.11 version, |
34 | * funded by Oxcoda NetBox Blue (http://www.netboxblue.com/) | 34 | * funded by Oxcoda NetBox Blue (http://www.netboxblue.com/) |
35 | * | 35 | * |
36 | */ | 36 | */ |
37 | 37 | ||
38 | #include <linux/module.h> | 38 | #include <linux/module.h> |
@@ -85,19 +85,17 @@ static void pptp_nat_expected(struct ip_conntrack *ct, | |||
85 | DEBUGP("we are PNS->PAC\n"); | 85 | DEBUGP("we are PNS->PAC\n"); |
86 | /* therefore, build tuple for PAC->PNS */ | 86 | /* therefore, build tuple for PAC->PNS */ |
87 | t.src.ip = master->tuplehash[IP_CT_DIR_REPLY].tuple.src.ip; | 87 | t.src.ip = master->tuplehash[IP_CT_DIR_REPLY].tuple.src.ip; |
88 | t.src.u.gre.key = htons(master->help.ct_pptp_info.pac_call_id); | 88 | t.src.u.gre.key = master->help.ct_pptp_info.pac_call_id; |
89 | t.dst.ip = master->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip; | 89 | t.dst.ip = master->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip; |
90 | t.dst.u.gre.key = htons(master->help.ct_pptp_info.pns_call_id); | 90 | t.dst.u.gre.key = master->help.ct_pptp_info.pns_call_id; |
91 | t.dst.protonum = IPPROTO_GRE; | 91 | t.dst.protonum = IPPROTO_GRE; |
92 | } else { | 92 | } else { |
93 | DEBUGP("we are PAC->PNS\n"); | 93 | DEBUGP("we are PAC->PNS\n"); |
94 | /* build tuple for PNS->PAC */ | 94 | /* build tuple for PNS->PAC */ |
95 | t.src.ip = master->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip; | 95 | t.src.ip = master->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip; |
96 | t.src.u.gre.key = | 96 | t.src.u.gre.key = master->nat.help.nat_pptp_info.pns_call_id; |
97 | htons(master->nat.help.nat_pptp_info.pns_call_id); | ||
98 | t.dst.ip = master->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip; | 97 | t.dst.ip = master->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip; |
99 | t.dst.u.gre.key = | 98 | t.dst.u.gre.key = master->nat.help.nat_pptp_info.pac_call_id; |
100 | htons(master->nat.help.nat_pptp_info.pac_call_id); | ||
101 | t.dst.protonum = IPPROTO_GRE; | 99 | t.dst.protonum = IPPROTO_GRE; |
102 | } | 100 | } |
103 | 101 | ||
@@ -149,51 +147,52 @@ pptp_outbound_pkt(struct sk_buff **pskb, | |||
149 | { | 147 | { |
150 | struct ip_ct_pptp_master *ct_pptp_info = &ct->help.ct_pptp_info; | 148 | struct ip_ct_pptp_master *ct_pptp_info = &ct->help.ct_pptp_info; |
151 | struct ip_nat_pptp *nat_pptp_info = &ct->nat.help.nat_pptp_info; | 149 | struct ip_nat_pptp *nat_pptp_info = &ct->nat.help.nat_pptp_info; |
152 | u_int16_t msg, new_callid; | 150 | u_int16_t msg; |
151 | __be16 new_callid; | ||
153 | unsigned int cid_off; | 152 | unsigned int cid_off; |
154 | 153 | ||
155 | new_callid = htons(ct_pptp_info->pns_call_id); | 154 | new_callid = ct_pptp_info->pns_call_id; |
156 | 155 | ||
157 | switch (msg = ntohs(ctlh->messageType)) { | 156 | switch (msg = ntohs(ctlh->messageType)) { |
158 | case PPTP_OUT_CALL_REQUEST: | 157 | case PPTP_OUT_CALL_REQUEST: |
159 | cid_off = offsetof(union pptp_ctrl_union, ocreq.callID); | 158 | cid_off = offsetof(union pptp_ctrl_union, ocreq.callID); |
160 | /* FIXME: ideally we would want to reserve a call ID | 159 | /* FIXME: ideally we would want to reserve a call ID |
161 | * here. current netfilter NAT core is not able to do | 160 | * here. current netfilter NAT core is not able to do |
162 | * this :( For now we use TCP source port. This breaks | 161 | * this :( For now we use TCP source port. This breaks |
163 | * multiple calls within one control session */ | 162 | * multiple calls within one control session */ |
164 | 163 | ||
165 | /* save original call ID in nat_info */ | 164 | /* save original call ID in nat_info */ |
166 | nat_pptp_info->pns_call_id = ct_pptp_info->pns_call_id; | 165 | nat_pptp_info->pns_call_id = ct_pptp_info->pns_call_id; |
167 | 166 | ||
168 | /* don't use tcph->source since we are at a DSTmanip | 167 | /* don't use tcph->source since we are at a DSTmanip |
169 | * hook (e.g. PREROUTING) and pkt is not mangled yet */ | 168 | * hook (e.g. PREROUTING) and pkt is not mangled yet */ |
170 | new_callid = ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u.tcp.port; | 169 | new_callid = ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u.tcp.port; |
171 | 170 | ||
172 | /* save new call ID in ct info */ | 171 | /* save new call ID in ct info */ |
173 | ct_pptp_info->pns_call_id = ntohs(new_callid); | 172 | ct_pptp_info->pns_call_id = new_callid; |
174 | break; | 173 | break; |
175 | case PPTP_IN_CALL_REPLY: | 174 | case PPTP_IN_CALL_REPLY: |
176 | cid_off = offsetof(union pptp_ctrl_union, icreq.callID); | 175 | cid_off = offsetof(union pptp_ctrl_union, icack.callID); |
177 | break; | 176 | break; |
178 | case PPTP_CALL_CLEAR_REQUEST: | 177 | case PPTP_CALL_CLEAR_REQUEST: |
179 | cid_off = offsetof(union pptp_ctrl_union, clrreq.callID); | 178 | cid_off = offsetof(union pptp_ctrl_union, clrreq.callID); |
180 | break; | 179 | break; |
181 | default: | 180 | default: |
182 | DEBUGP("unknown outbound packet 0x%04x:%s\n", msg, | 181 | DEBUGP("unknown outbound packet 0x%04x:%s\n", msg, |
183 | (msg <= PPTP_MSG_MAX)? | 182 | (msg <= PPTP_MSG_MAX)? |
184 | pptp_msg_name[msg]:pptp_msg_name[0]); | 183 | pptp_msg_name[msg]:pptp_msg_name[0]); |
185 | /* fall through */ | 184 | /* fall through */ |
186 | 185 | ||
187 | case PPTP_SET_LINK_INFO: | 186 | case PPTP_SET_LINK_INFO: |
188 | /* only need to NAT in case PAC is behind NAT box */ | 187 | /* only need to NAT in case PAC is behind NAT box */ |
189 | case PPTP_START_SESSION_REQUEST: | 188 | case PPTP_START_SESSION_REQUEST: |
190 | case PPTP_START_SESSION_REPLY: | 189 | case PPTP_START_SESSION_REPLY: |
191 | case PPTP_STOP_SESSION_REQUEST: | 190 | case PPTP_STOP_SESSION_REQUEST: |
192 | case PPTP_STOP_SESSION_REPLY: | 191 | case PPTP_STOP_SESSION_REPLY: |
193 | case PPTP_ECHO_REQUEST: | 192 | case PPTP_ECHO_REQUEST: |
194 | case PPTP_ECHO_REPLY: | 193 | case PPTP_ECHO_REPLY: |
195 | /* no need to alter packet */ | 194 | /* no need to alter packet */ |
196 | return NF_ACCEPT; | 195 | return NF_ACCEPT; |
197 | } | 196 | } |
198 | 197 | ||
199 | /* only OUT_CALL_REQUEST, IN_CALL_REPLY, CALL_CLEAR_REQUEST pass | 198 | /* only OUT_CALL_REQUEST, IN_CALL_REPLY, CALL_CLEAR_REQUEST pass |
@@ -212,80 +211,28 @@ pptp_outbound_pkt(struct sk_buff **pskb, | |||
212 | return NF_ACCEPT; | 211 | return NF_ACCEPT; |
213 | } | 212 | } |
214 | 213 | ||
215 | static int | 214 | static void |
216 | pptp_exp_gre(struct ip_conntrack_expect *expect_orig, | 215 | pptp_exp_gre(struct ip_conntrack_expect *expect_orig, |
217 | struct ip_conntrack_expect *expect_reply) | 216 | struct ip_conntrack_expect *expect_reply) |
218 | { | 217 | { |
219 | struct ip_ct_pptp_master *ct_pptp_info = | ||
220 | &expect_orig->master->help.ct_pptp_info; | ||
221 | struct ip_nat_pptp *nat_pptp_info = | ||
222 | &expect_orig->master->nat.help.nat_pptp_info; | ||
223 | |||
224 | struct ip_conntrack *ct = expect_orig->master; | 218 | struct ip_conntrack *ct = expect_orig->master; |
225 | 219 | struct ip_ct_pptp_master *ct_pptp_info = &ct->help.ct_pptp_info; | |
226 | struct ip_conntrack_tuple inv_t; | 220 | struct ip_nat_pptp *nat_pptp_info = &ct->nat.help.nat_pptp_info; |
227 | struct ip_conntrack_tuple *orig_t, *reply_t; | ||
228 | 221 | ||
229 | /* save original PAC call ID in nat_info */ | 222 | /* save original PAC call ID in nat_info */ |
230 | nat_pptp_info->pac_call_id = ct_pptp_info->pac_call_id; | 223 | nat_pptp_info->pac_call_id = ct_pptp_info->pac_call_id; |
231 | 224 | ||
232 | /* alter expectation */ | ||
233 | orig_t = &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple; | ||
234 | reply_t = &ct->tuplehash[IP_CT_DIR_REPLY].tuple; | ||
235 | |||
236 | /* alter expectation for PNS->PAC direction */ | 225 | /* alter expectation for PNS->PAC direction */ |
237 | invert_tuplepr(&inv_t, &expect_orig->tuple); | 226 | expect_orig->saved_proto.gre.key = ct_pptp_info->pns_call_id; |
238 | expect_orig->saved_proto.gre.key = htons(ct_pptp_info->pns_call_id); | 227 | expect_orig->tuple.src.u.gre.key = nat_pptp_info->pns_call_id; |
239 | expect_orig->tuple.src.u.gre.key = htons(nat_pptp_info->pns_call_id); | 228 | expect_orig->tuple.dst.u.gre.key = ct_pptp_info->pac_call_id; |
240 | expect_orig->tuple.dst.u.gre.key = htons(ct_pptp_info->pac_call_id); | ||
241 | expect_orig->dir = IP_CT_DIR_ORIGINAL; | 229 | expect_orig->dir = IP_CT_DIR_ORIGINAL; |
242 | inv_t.src.ip = reply_t->src.ip; | ||
243 | inv_t.dst.ip = reply_t->dst.ip; | ||
244 | inv_t.src.u.gre.key = htons(nat_pptp_info->pac_call_id); | ||
245 | inv_t.dst.u.gre.key = htons(ct_pptp_info->pns_call_id); | ||
246 | |||
247 | if (!ip_conntrack_expect_related(expect_orig)) { | ||
248 | DEBUGP("successfully registered expect\n"); | ||
249 | } else { | ||
250 | DEBUGP("can't expect_related(expect_orig)\n"); | ||
251 | return 1; | ||
252 | } | ||
253 | 230 | ||
254 | /* alter expectation for PAC->PNS direction */ | 231 | /* alter expectation for PAC->PNS direction */ |
255 | invert_tuplepr(&inv_t, &expect_reply->tuple); | 232 | expect_reply->saved_proto.gre.key = nat_pptp_info->pns_call_id; |
256 | expect_reply->saved_proto.gre.key = htons(nat_pptp_info->pns_call_id); | 233 | expect_reply->tuple.src.u.gre.key = nat_pptp_info->pac_call_id; |
257 | expect_reply->tuple.src.u.gre.key = htons(nat_pptp_info->pac_call_id); | 234 | expect_reply->tuple.dst.u.gre.key = ct_pptp_info->pns_call_id; |
258 | expect_reply->tuple.dst.u.gre.key = htons(ct_pptp_info->pns_call_id); | ||
259 | expect_reply->dir = IP_CT_DIR_REPLY; | 235 | expect_reply->dir = IP_CT_DIR_REPLY; |
260 | inv_t.src.ip = orig_t->src.ip; | ||
261 | inv_t.dst.ip = orig_t->dst.ip; | ||
262 | inv_t.src.u.gre.key = htons(nat_pptp_info->pns_call_id); | ||
263 | inv_t.dst.u.gre.key = htons(ct_pptp_info->pac_call_id); | ||
264 | |||
265 | if (!ip_conntrack_expect_related(expect_reply)) { | ||
266 | DEBUGP("successfully registered expect\n"); | ||
267 | } else { | ||
268 | DEBUGP("can't expect_related(expect_reply)\n"); | ||
269 | ip_conntrack_unexpect_related(expect_orig); | ||
270 | return 1; | ||
271 | } | ||
272 | |||
273 | if (ip_ct_gre_keymap_add(ct, &expect_reply->tuple, 0) < 0) { | ||
274 | DEBUGP("can't register original keymap\n"); | ||
275 | ip_conntrack_unexpect_related(expect_orig); | ||
276 | ip_conntrack_unexpect_related(expect_reply); | ||
277 | return 1; | ||
278 | } | ||
279 | |||
280 | if (ip_ct_gre_keymap_add(ct, &inv_t, 1) < 0) { | ||
281 | DEBUGP("can't register reply keymap\n"); | ||
282 | ip_conntrack_unexpect_related(expect_orig); | ||
283 | ip_conntrack_unexpect_related(expect_reply); | ||
284 | ip_ct_gre_keymap_destroy(ct); | ||
285 | return 1; | ||
286 | } | ||
287 | |||
288 | return 0; | ||
289 | } | 236 | } |
290 | 237 | ||
291 | /* inbound packets == from PAC to PNS */ | 238 | /* inbound packets == from PAC to PNS */ |
@@ -297,15 +244,15 @@ pptp_inbound_pkt(struct sk_buff **pskb, | |||
297 | union pptp_ctrl_union *pptpReq) | 244 | union pptp_ctrl_union *pptpReq) |
298 | { | 245 | { |
299 | struct ip_nat_pptp *nat_pptp_info = &ct->nat.help.nat_pptp_info; | 246 | struct ip_nat_pptp *nat_pptp_info = &ct->nat.help.nat_pptp_info; |
300 | u_int16_t msg, new_cid = 0, new_pcid; | 247 | u_int16_t msg; |
301 | unsigned int pcid_off, cid_off = 0; | 248 | __be16 new_pcid; |
249 | unsigned int pcid_off; | ||
302 | 250 | ||
303 | new_pcid = htons(nat_pptp_info->pns_call_id); | 251 | new_pcid = nat_pptp_info->pns_call_id; |
304 | 252 | ||
305 | switch (msg = ntohs(ctlh->messageType)) { | 253 | switch (msg = ntohs(ctlh->messageType)) { |
306 | case PPTP_OUT_CALL_REPLY: | 254 | case PPTP_OUT_CALL_REPLY: |
307 | pcid_off = offsetof(union pptp_ctrl_union, ocack.peersCallID); | 255 | pcid_off = offsetof(union pptp_ctrl_union, ocack.peersCallID); |
308 | cid_off = offsetof(union pptp_ctrl_union, ocack.callID); | ||
309 | break; | 256 | break; |
310 | case PPTP_IN_CALL_CONNECT: | 257 | case PPTP_IN_CALL_CONNECT: |
311 | pcid_off = offsetof(union pptp_ctrl_union, iccon.peersCallID); | 258 | pcid_off = offsetof(union pptp_ctrl_union, iccon.peersCallID); |
@@ -324,7 +271,7 @@ pptp_inbound_pkt(struct sk_buff **pskb, | |||
324 | break; | 271 | break; |
325 | 272 | ||
326 | default: | 273 | default: |
327 | DEBUGP("unknown inbound packet %s\n", (msg <= PPTP_MSG_MAX)? | 274 | DEBUGP("unknown inbound packet %s\n", (msg <= PPTP_MSG_MAX)? |
328 | pptp_msg_name[msg]:pptp_msg_name[0]); | 275 | pptp_msg_name[msg]:pptp_msg_name[0]); |
329 | /* fall through */ | 276 | /* fall through */ |
330 | 277 | ||
@@ -351,17 +298,6 @@ pptp_inbound_pkt(struct sk_buff **pskb, | |||
351 | sizeof(new_pcid), (char *)&new_pcid, | 298 | sizeof(new_pcid), (char *)&new_pcid, |
352 | sizeof(new_pcid)) == 0) | 299 | sizeof(new_pcid)) == 0) |
353 | return NF_DROP; | 300 | return NF_DROP; |
354 | |||
355 | if (new_cid) { | ||
356 | DEBUGP("altering call id from 0x%04x to 0x%04x\n", | ||
357 | ntohs(REQ_CID(pptpReq, cid_off)), ntohs(new_cid)); | ||
358 | if (ip_nat_mangle_tcp_packet(pskb, ct, ctinfo, | ||
359 | cid_off + sizeof(struct pptp_pkt_hdr) + | ||
360 | sizeof(struct PptpControlHeader), | ||
361 | sizeof(new_cid), (char *)&new_cid, | ||
362 | sizeof(new_cid)) == 0) | ||
363 | return NF_DROP; | ||
364 | } | ||
365 | return NF_ACCEPT; | 301 | return NF_ACCEPT; |
366 | } | 302 | } |
367 | 303 | ||
diff --git a/net/ipv4/netfilter/ip_nat_proto_gre.c b/net/ipv4/netfilter/ip_nat_proto_gre.c index 38acfdf540eb..bf91f9312b3c 100644 --- a/net/ipv4/netfilter/ip_nat_proto_gre.c +++ b/net/ipv4/netfilter/ip_nat_proto_gre.c | |||
@@ -6,10 +6,10 @@ | |||
6 | * GRE is a generic encapsulation protocol, which is generally not very | 6 | * GRE is a generic encapsulation protocol, which is generally not very |
7 | * suited for NAT, as it has no protocol-specific part as port numbers. | 7 | * suited for NAT, as it has no protocol-specific part as port numbers. |
8 | * | 8 | * |
9 | * It has an optional key field, which may help us distinguishing two | 9 | * It has an optional key field, which may help us distinguishing two |
10 | * connections between the same two hosts. | 10 | * connections between the same two hosts. |
11 | * | 11 | * |
12 | * GRE is defined in RFC 1701 and RFC 1702, as well as RFC 2784 | 12 | * GRE is defined in RFC 1701 and RFC 1702, as well as RFC 2784 |
13 | * | 13 | * |
14 | * PPTP is built on top of a modified version of GRE, and has a mandatory | 14 | * PPTP is built on top of a modified version of GRE, and has a mandatory |
15 | * field called "CallID", which serves us for the same purpose as the key | 15 | * field called "CallID", which serves us for the same purpose as the key |
@@ -60,14 +60,14 @@ gre_in_range(const struct ip_conntrack_tuple *tuple, | |||
60 | } | 60 | } |
61 | 61 | ||
62 | /* generate unique tuple ... */ | 62 | /* generate unique tuple ... */ |
63 | static int | 63 | static int |
64 | gre_unique_tuple(struct ip_conntrack_tuple *tuple, | 64 | gre_unique_tuple(struct ip_conntrack_tuple *tuple, |
65 | const struct ip_nat_range *range, | 65 | const struct ip_nat_range *range, |
66 | enum ip_nat_manip_type maniptype, | 66 | enum ip_nat_manip_type maniptype, |
67 | const struct ip_conntrack *conntrack) | 67 | const struct ip_conntrack *conntrack) |
68 | { | 68 | { |
69 | static u_int16_t key; | 69 | static u_int16_t key; |
70 | u_int16_t *keyptr; | 70 | __be16 *keyptr; |
71 | unsigned int min, i, range_size; | 71 | unsigned int min, i, range_size; |
72 | 72 | ||
73 | if (maniptype == IP_NAT_MANIP_SRC) | 73 | if (maniptype == IP_NAT_MANIP_SRC) |
@@ -84,7 +84,7 @@ gre_unique_tuple(struct ip_conntrack_tuple *tuple, | |||
84 | range_size = ntohs(range->max.gre.key) - min + 1; | 84 | range_size = ntohs(range->max.gre.key) - min + 1; |
85 | } | 85 | } |
86 | 86 | ||
87 | DEBUGP("min = %u, range_size = %u\n", min, range_size); | 87 | DEBUGP("min = %u, range_size = %u\n", min, range_size); |
88 | 88 | ||
89 | for (i = 0; i < range_size; i++, key++) { | 89 | for (i = 0; i < range_size; i++, key++) { |
90 | *keyptr = htons(min + key % range_size); | 90 | *keyptr = htons(min + key % range_size); |
@@ -117,7 +117,7 @@ gre_manip_pkt(struct sk_buff **pskb, | |||
117 | greh = (void *)(*pskb)->data + hdroff; | 117 | greh = (void *)(*pskb)->data + hdroff; |
118 | pgreh = (struct gre_hdr_pptp *) greh; | 118 | pgreh = (struct gre_hdr_pptp *) greh; |
119 | 119 | ||
120 | /* we only have destination manip of a packet, since 'source key' | 120 | /* we only have destination manip of a packet, since 'source key' |
121 | * is not present in the packet itself */ | 121 | * is not present in the packet itself */ |
122 | if (maniptype == IP_NAT_MANIP_DST) { | 122 | if (maniptype == IP_NAT_MANIP_DST) { |
123 | /* key manipulation is always dest */ | 123 | /* key manipulation is always dest */ |
@@ -129,15 +129,16 @@ gre_manip_pkt(struct sk_buff **pskb, | |||
129 | } | 129 | } |
130 | if (greh->csum) { | 130 | if (greh->csum) { |
131 | /* FIXME: Never tested this code... */ | 131 | /* FIXME: Never tested this code... */ |
132 | *(gre_csum(greh)) = | 132 | *(gre_csum(greh)) = |
133 | ip_nat_cheat_check(~*(gre_key(greh)), | 133 | nf_proto_csum_update(*pskb, |
134 | ~*(gre_key(greh)), | ||
134 | tuple->dst.u.gre.key, | 135 | tuple->dst.u.gre.key, |
135 | *(gre_csum(greh))); | 136 | *(gre_csum(greh)), 0); |
136 | } | 137 | } |
137 | *(gre_key(greh)) = tuple->dst.u.gre.key; | 138 | *(gre_key(greh)) = tuple->dst.u.gre.key; |
138 | break; | 139 | break; |
139 | case GRE_VERSION_PPTP: | 140 | case GRE_VERSION_PPTP: |
140 | DEBUGP("call_id -> 0x%04x\n", | 141 | DEBUGP("call_id -> 0x%04x\n", |
141 | ntohs(tuple->dst.u.gre.key)); | 142 | ntohs(tuple->dst.u.gre.key)); |
142 | pgreh->call_id = tuple->dst.u.gre.key; | 143 | pgreh->call_id = tuple->dst.u.gre.key; |
143 | break; | 144 | break; |
@@ -151,8 +152,8 @@ gre_manip_pkt(struct sk_buff **pskb, | |||
151 | } | 152 | } |
152 | 153 | ||
153 | /* nat helper struct */ | 154 | /* nat helper struct */ |
154 | static struct ip_nat_protocol gre = { | 155 | static struct ip_nat_protocol gre = { |
155 | .name = "GRE", | 156 | .name = "GRE", |
156 | .protonum = IPPROTO_GRE, | 157 | .protonum = IPPROTO_GRE, |
157 | .manip_pkt = gre_manip_pkt, | 158 | .manip_pkt = gre_manip_pkt, |
158 | .in_range = gre_in_range, | 159 | .in_range = gre_in_range, |
@@ -163,7 +164,7 @@ static struct ip_nat_protocol gre = { | |||
163 | .nfattr_to_range = ip_nat_port_nfattr_to_range, | 164 | .nfattr_to_range = ip_nat_port_nfattr_to_range, |
164 | #endif | 165 | #endif |
165 | }; | 166 | }; |
166 | 167 | ||
167 | int __init ip_nat_proto_gre_init(void) | 168 | int __init ip_nat_proto_gre_init(void) |
168 | { | 169 | { |
169 | return ip_nat_protocol_register(&gre); | 170 | return ip_nat_protocol_register(&gre); |
diff --git a/net/ipv4/netfilter/ip_nat_proto_icmp.c b/net/ipv4/netfilter/ip_nat_proto_icmp.c index 31a3f4ccb99c..ec50cc295317 100644 --- a/net/ipv4/netfilter/ip_nat_proto_icmp.c +++ b/net/ipv4/netfilter/ip_nat_proto_icmp.c | |||
@@ -66,10 +66,10 @@ icmp_manip_pkt(struct sk_buff **pskb, | |||
66 | return 0; | 66 | return 0; |
67 | 67 | ||
68 | hdr = (struct icmphdr *)((*pskb)->data + hdroff); | 68 | hdr = (struct icmphdr *)((*pskb)->data + hdroff); |
69 | 69 | hdr->checksum = nf_proto_csum_update(*pskb, | |
70 | hdr->checksum = ip_nat_cheat_check(hdr->un.echo.id ^ 0xFFFF, | 70 | hdr->un.echo.id ^ 0xFFFF, |
71 | tuple->src.u.icmp.id, | 71 | tuple->src.u.icmp.id, |
72 | hdr->checksum); | 72 | hdr->checksum, 0); |
73 | hdr->un.echo.id = tuple->src.u.icmp.id; | 73 | hdr->un.echo.id = tuple->src.u.icmp.id; |
74 | return 1; | 74 | return 1; |
75 | } | 75 | } |
diff --git a/net/ipv4/netfilter/ip_nat_proto_tcp.c b/net/ipv4/netfilter/ip_nat_proto_tcp.c index a3d14079eba6..72a6307bd2db 100644 --- a/net/ipv4/netfilter/ip_nat_proto_tcp.c +++ b/net/ipv4/netfilter/ip_nat_proto_tcp.c | |||
@@ -129,10 +129,9 @@ tcp_manip_pkt(struct sk_buff **pskb, | |||
129 | if (hdrsize < sizeof(*hdr)) | 129 | if (hdrsize < sizeof(*hdr)) |
130 | return 1; | 130 | return 1; |
131 | 131 | ||
132 | hdr->check = ip_nat_cheat_check(~oldip, newip, | 132 | hdr->check = nf_proto_csum_update(*pskb, ~oldip, newip, hdr->check, 1); |
133 | ip_nat_cheat_check(oldport ^ 0xFFFF, | 133 | hdr->check = nf_proto_csum_update(*pskb, oldport ^ 0xFFFF, newport, |
134 | newport, | 134 | hdr->check, 0); |
135 | hdr->check)); | ||
136 | return 1; | 135 | return 1; |
137 | } | 136 | } |
138 | 137 | ||
diff --git a/net/ipv4/netfilter/ip_nat_proto_udp.c b/net/ipv4/netfilter/ip_nat_proto_udp.c index ec6053fdc867..5da196ae758c 100644 --- a/net/ipv4/netfilter/ip_nat_proto_udp.c +++ b/net/ipv4/netfilter/ip_nat_proto_udp.c | |||
@@ -113,11 +113,16 @@ udp_manip_pkt(struct sk_buff **pskb, | |||
113 | newport = tuple->dst.u.udp.port; | 113 | newport = tuple->dst.u.udp.port; |
114 | portptr = &hdr->dest; | 114 | portptr = &hdr->dest; |
115 | } | 115 | } |
116 | if (hdr->check) /* 0 is a special case meaning no checksum */ | 116 | |
117 | hdr->check = ip_nat_cheat_check(~oldip, newip, | 117 | if (hdr->check || (*pskb)->ip_summed == CHECKSUM_PARTIAL) { |
118 | ip_nat_cheat_check(*portptr ^ 0xFFFF, | 118 | hdr->check = nf_proto_csum_update(*pskb, ~oldip, newip, |
119 | newport, | 119 | hdr->check, 1); |
120 | hdr->check)); | 120 | hdr->check = nf_proto_csum_update(*pskb, |
121 | *portptr ^ 0xFFFF, newport, | ||
122 | hdr->check, 0); | ||
123 | if (!hdr->check) | ||
124 | hdr->check = -1; | ||
125 | } | ||
121 | *portptr = newport; | 126 | *portptr = newport; |
122 | return 1; | 127 | return 1; |
123 | } | 128 | } |
diff --git a/net/ipv4/netfilter/ip_nat_rule.c b/net/ipv4/netfilter/ip_nat_rule.c index 1aba926c1cb0..7b703839aa58 100644 --- a/net/ipv4/netfilter/ip_nat_rule.c +++ b/net/ipv4/netfilter/ip_nat_rule.c | |||
@@ -19,14 +19,10 @@ | |||
19 | #include <net/route.h> | 19 | #include <net/route.h> |
20 | #include <linux/bitops.h> | 20 | #include <linux/bitops.h> |
21 | 21 | ||
22 | #define ASSERT_READ_LOCK(x) | ||
23 | #define ASSERT_WRITE_LOCK(x) | ||
24 | |||
25 | #include <linux/netfilter_ipv4/ip_tables.h> | 22 | #include <linux/netfilter_ipv4/ip_tables.h> |
26 | #include <linux/netfilter_ipv4/ip_nat.h> | 23 | #include <linux/netfilter_ipv4/ip_nat.h> |
27 | #include <linux/netfilter_ipv4/ip_nat_core.h> | 24 | #include <linux/netfilter_ipv4/ip_nat_core.h> |
28 | #include <linux/netfilter_ipv4/ip_nat_rule.h> | 25 | #include <linux/netfilter_ipv4/ip_nat_rule.h> |
29 | #include <linux/netfilter_ipv4/listhelp.h> | ||
30 | 26 | ||
31 | #if 0 | 27 | #if 0 |
32 | #define DEBUGP printk | 28 | #define DEBUGP printk |
@@ -104,8 +100,7 @@ static unsigned int ipt_snat_target(struct sk_buff **pskb, | |||
104 | const struct net_device *out, | 100 | const struct net_device *out, |
105 | unsigned int hooknum, | 101 | unsigned int hooknum, |
106 | const struct ipt_target *target, | 102 | const struct ipt_target *target, |
107 | const void *targinfo, | 103 | const void *targinfo) |
108 | void *userinfo) | ||
109 | { | 104 | { |
110 | struct ip_conntrack *ct; | 105 | struct ip_conntrack *ct; |
111 | enum ip_conntrack_info ctinfo; | 106 | enum ip_conntrack_info ctinfo; |
@@ -147,8 +142,7 @@ static unsigned int ipt_dnat_target(struct sk_buff **pskb, | |||
147 | const struct net_device *out, | 142 | const struct net_device *out, |
148 | unsigned int hooknum, | 143 | unsigned int hooknum, |
149 | const struct ipt_target *target, | 144 | const struct ipt_target *target, |
150 | const void *targinfo, | 145 | const void *targinfo) |
151 | void *userinfo) | ||
152 | { | 146 | { |
153 | struct ip_conntrack *ct; | 147 | struct ip_conntrack *ct; |
154 | enum ip_conntrack_info ctinfo; | 148 | enum ip_conntrack_info ctinfo; |
@@ -174,7 +168,6 @@ static int ipt_snat_checkentry(const char *tablename, | |||
174 | const void *entry, | 168 | const void *entry, |
175 | const struct ipt_target *target, | 169 | const struct ipt_target *target, |
176 | void *targinfo, | 170 | void *targinfo, |
177 | unsigned int targinfosize, | ||
178 | unsigned int hook_mask) | 171 | unsigned int hook_mask) |
179 | { | 172 | { |
180 | struct ip_nat_multi_range_compat *mr = targinfo; | 173 | struct ip_nat_multi_range_compat *mr = targinfo; |
@@ -191,7 +184,6 @@ static int ipt_dnat_checkentry(const char *tablename, | |||
191 | const void *entry, | 184 | const void *entry, |
192 | const struct ipt_target *target, | 185 | const struct ipt_target *target, |
193 | void *targinfo, | 186 | void *targinfo, |
194 | unsigned int targinfosize, | ||
195 | unsigned int hook_mask) | 187 | unsigned int hook_mask) |
196 | { | 188 | { |
197 | struct ip_nat_multi_range_compat *mr = targinfo; | 189 | struct ip_nat_multi_range_compat *mr = targinfo; |
@@ -255,7 +247,7 @@ int ip_nat_rule_find(struct sk_buff **pskb, | |||
255 | { | 247 | { |
256 | int ret; | 248 | int ret; |
257 | 249 | ||
258 | ret = ipt_do_table(pskb, hooknum, in, out, &nat_table, NULL); | 250 | ret = ipt_do_table(pskb, hooknum, in, out, &nat_table); |
259 | 251 | ||
260 | if (ret == NF_ACCEPT) { | 252 | if (ret == NF_ACCEPT) { |
261 | if (!ip_nat_initialized(ct, HOOK2MANIP(hooknum))) | 253 | if (!ip_nat_initialized(ct, HOOK2MANIP(hooknum))) |
diff --git a/net/ipv4/netfilter/ip_nat_standalone.c b/net/ipv4/netfilter/ip_nat_standalone.c index 17de077a7901..9c577db62047 100644 --- a/net/ipv4/netfilter/ip_nat_standalone.c +++ b/net/ipv4/netfilter/ip_nat_standalone.c | |||
@@ -30,9 +30,6 @@ | |||
30 | #include <net/checksum.h> | 30 | #include <net/checksum.h> |
31 | #include <linux/spinlock.h> | 31 | #include <linux/spinlock.h> |
32 | 32 | ||
33 | #define ASSERT_READ_LOCK(x) | ||
34 | #define ASSERT_WRITE_LOCK(x) | ||
35 | |||
36 | #include <linux/netfilter_ipv4/ip_nat.h> | 33 | #include <linux/netfilter_ipv4/ip_nat.h> |
37 | #include <linux/netfilter_ipv4/ip_nat_rule.h> | 34 | #include <linux/netfilter_ipv4/ip_nat_rule.h> |
38 | #include <linux/netfilter_ipv4/ip_nat_protocol.h> | 35 | #include <linux/netfilter_ipv4/ip_nat_protocol.h> |
@@ -40,7 +37,6 @@ | |||
40 | #include <linux/netfilter_ipv4/ip_nat_helper.h> | 37 | #include <linux/netfilter_ipv4/ip_nat_helper.h> |
41 | #include <linux/netfilter_ipv4/ip_tables.h> | 38 | #include <linux/netfilter_ipv4/ip_tables.h> |
42 | #include <linux/netfilter_ipv4/ip_conntrack_core.h> | 39 | #include <linux/netfilter_ipv4/ip_conntrack_core.h> |
43 | #include <linux/netfilter_ipv4/listhelp.h> | ||
44 | 40 | ||
45 | #if 0 | 41 | #if 0 |
46 | #define DEBUGP printk | 42 | #define DEBUGP printk |
@@ -110,11 +106,6 @@ ip_nat_fn(unsigned int hooknum, | |||
110 | IP_NF_ASSERT(!((*pskb)->nh.iph->frag_off | 106 | IP_NF_ASSERT(!((*pskb)->nh.iph->frag_off |
111 | & htons(IP_MF|IP_OFFSET))); | 107 | & htons(IP_MF|IP_OFFSET))); |
112 | 108 | ||
113 | /* If we had a hardware checksum before, it's now invalid */ | ||
114 | if ((*pskb)->ip_summed == CHECKSUM_HW) | ||
115 | if (skb_checksum_help(*pskb, (out == NULL))) | ||
116 | return NF_DROP; | ||
117 | |||
118 | ct = ip_conntrack_get(*pskb, &ctinfo); | 109 | ct = ip_conntrack_get(*pskb, &ctinfo); |
119 | /* Can't track? It's not due to stress, or conntrack would | 110 | /* Can't track? It's not due to stress, or conntrack would |
120 | have dropped it. Hence it's the user's responsibilty to | 111 | have dropped it. Hence it's the user's responsibilty to |
@@ -145,8 +136,8 @@ ip_nat_fn(unsigned int hooknum, | |||
145 | case IP_CT_RELATED: | 136 | case IP_CT_RELATED: |
146 | case IP_CT_RELATED+IP_CT_IS_REPLY: | 137 | case IP_CT_RELATED+IP_CT_IS_REPLY: |
147 | if ((*pskb)->nh.iph->protocol == IPPROTO_ICMP) { | 138 | if ((*pskb)->nh.iph->protocol == IPPROTO_ICMP) { |
148 | if (!ip_nat_icmp_reply_translation(pskb, ct, maniptype, | 139 | if (!ip_nat_icmp_reply_translation(ct, ctinfo, |
149 | CTINFO2DIR(ctinfo))) | 140 | hooknum, pskb)) |
150 | return NF_DROP; | 141 | return NF_DROP; |
151 | else | 142 | else |
152 | return NF_ACCEPT; | 143 | return NF_ACCEPT; |
diff --git a/net/ipv4/netfilter/ip_queue.c b/net/ipv4/netfilter/ip_queue.c index 198ac36db861..7edad790478a 100644 --- a/net/ipv4/netfilter/ip_queue.c +++ b/net/ipv4/netfilter/ip_queue.c | |||
@@ -52,15 +52,15 @@ struct ipq_queue_entry { | |||
52 | 52 | ||
53 | typedef int (*ipq_cmpfn)(struct ipq_queue_entry *, unsigned long); | 53 | typedef int (*ipq_cmpfn)(struct ipq_queue_entry *, unsigned long); |
54 | 54 | ||
55 | static unsigned char copy_mode = IPQ_COPY_NONE; | 55 | static unsigned char copy_mode __read_mostly = IPQ_COPY_NONE; |
56 | static unsigned int queue_maxlen = IPQ_QMAX_DEFAULT; | 56 | static unsigned int queue_maxlen __read_mostly = IPQ_QMAX_DEFAULT; |
57 | static DEFINE_RWLOCK(queue_lock); | 57 | static DEFINE_RWLOCK(queue_lock); |
58 | static int peer_pid; | 58 | static int peer_pid __read_mostly; |
59 | static unsigned int copy_range; | 59 | static unsigned int copy_range __read_mostly; |
60 | static unsigned int queue_total; | 60 | static unsigned int queue_total; |
61 | static unsigned int queue_dropped = 0; | 61 | static unsigned int queue_dropped = 0; |
62 | static unsigned int queue_user_dropped = 0; | 62 | static unsigned int queue_user_dropped = 0; |
63 | static struct sock *ipqnl; | 63 | static struct sock *ipqnl __read_mostly; |
64 | static LIST_HEAD(queue_list); | 64 | static LIST_HEAD(queue_list); |
65 | static DEFINE_MUTEX(ipqnl_mutex); | 65 | static DEFINE_MUTEX(ipqnl_mutex); |
66 | 66 | ||
@@ -208,9 +208,9 @@ ipq_build_packet_message(struct ipq_queue_entry *entry, int *errp) | |||
208 | break; | 208 | break; |
209 | 209 | ||
210 | case IPQ_COPY_PACKET: | 210 | case IPQ_COPY_PACKET: |
211 | if (entry->skb->ip_summed == CHECKSUM_HW && | 211 | if ((entry->skb->ip_summed == CHECKSUM_PARTIAL || |
212 | (*errp = skb_checksum_help(entry->skb, | 212 | entry->skb->ip_summed == CHECKSUM_COMPLETE) && |
213 | entry->info->outdev == NULL))) { | 213 | (*errp = skb_checksum_help(entry->skb))) { |
214 | read_unlock_bh(&queue_lock); | 214 | read_unlock_bh(&queue_lock); |
215 | return NULL; | 215 | return NULL; |
216 | } | 216 | } |
diff --git a/net/ipv4/netfilter/ip_tables.c b/net/ipv4/netfilter/ip_tables.c index 048514f15f2f..800067d69a9a 100644 --- a/net/ipv4/netfilter/ip_tables.c +++ b/net/ipv4/netfilter/ip_tables.c | |||
@@ -180,8 +180,7 @@ ipt_error(struct sk_buff **pskb, | |||
180 | const struct net_device *out, | 180 | const struct net_device *out, |
181 | unsigned int hooknum, | 181 | unsigned int hooknum, |
182 | const struct xt_target *target, | 182 | const struct xt_target *target, |
183 | const void *targinfo, | 183 | const void *targinfo) |
184 | void *userinfo) | ||
185 | { | 184 | { |
186 | if (net_ratelimit()) | 185 | if (net_ratelimit()) |
187 | printk("ip_tables: error: `%s'\n", (char *)targinfo); | 186 | printk("ip_tables: error: `%s'\n", (char *)targinfo); |
@@ -217,8 +216,7 @@ ipt_do_table(struct sk_buff **pskb, | |||
217 | unsigned int hook, | 216 | unsigned int hook, |
218 | const struct net_device *in, | 217 | const struct net_device *in, |
219 | const struct net_device *out, | 218 | const struct net_device *out, |
220 | struct ipt_table *table, | 219 | struct ipt_table *table) |
221 | void *userdata) | ||
222 | { | 220 | { |
223 | static const char nulldevname[IFNAMSIZ] __attribute__((aligned(sizeof(long)))); | 221 | static const char nulldevname[IFNAMSIZ] __attribute__((aligned(sizeof(long)))); |
224 | u_int16_t offset; | 222 | u_int16_t offset; |
@@ -308,8 +306,7 @@ ipt_do_table(struct sk_buff **pskb, | |||
308 | in, out, | 306 | in, out, |
309 | hook, | 307 | hook, |
310 | t->u.kernel.target, | 308 | t->u.kernel.target, |
311 | t->data, | 309 | t->data); |
312 | userdata); | ||
313 | 310 | ||
314 | #ifdef CONFIG_NETFILTER_DEBUG | 311 | #ifdef CONFIG_NETFILTER_DEBUG |
315 | if (((struct ipt_entry *)table_base)->comefrom | 312 | if (((struct ipt_entry *)table_base)->comefrom |
@@ -467,8 +464,7 @@ cleanup_match(struct ipt_entry_match *m, unsigned int *i) | |||
467 | return 1; | 464 | return 1; |
468 | 465 | ||
469 | if (m->u.kernel.match->destroy) | 466 | if (m->u.kernel.match->destroy) |
470 | m->u.kernel.match->destroy(m->u.kernel.match, m->data, | 467 | m->u.kernel.match->destroy(m->u.kernel.match, m->data); |
471 | m->u.match_size - sizeof(*m)); | ||
472 | module_put(m->u.kernel.match->me); | 468 | module_put(m->u.kernel.match->me); |
473 | return 0; | 469 | return 0; |
474 | } | 470 | } |
@@ -521,7 +517,6 @@ check_match(struct ipt_entry_match *m, | |||
521 | 517 | ||
522 | if (m->u.kernel.match->checkentry | 518 | if (m->u.kernel.match->checkentry |
523 | && !m->u.kernel.match->checkentry(name, ip, match, m->data, | 519 | && !m->u.kernel.match->checkentry(name, ip, match, m->data, |
524 | m->u.match_size - sizeof(*m), | ||
525 | hookmask)) { | 520 | hookmask)) { |
526 | duprintf("ip_tables: check failed for `%s'.\n", | 521 | duprintf("ip_tables: check failed for `%s'.\n", |
527 | m->u.kernel.match->name); | 522 | m->u.kernel.match->name); |
@@ -578,12 +573,10 @@ check_entry(struct ipt_entry *e, const char *name, unsigned int size, | |||
578 | if (t->u.kernel.target == &ipt_standard_target) { | 573 | if (t->u.kernel.target == &ipt_standard_target) { |
579 | if (!standard_check(t, size)) { | 574 | if (!standard_check(t, size)) { |
580 | ret = -EINVAL; | 575 | ret = -EINVAL; |
581 | goto cleanup_matches; | 576 | goto err; |
582 | } | 577 | } |
583 | } else if (t->u.kernel.target->checkentry | 578 | } else if (t->u.kernel.target->checkentry |
584 | && !t->u.kernel.target->checkentry(name, e, target, t->data, | 579 | && !t->u.kernel.target->checkentry(name, e, target, t->data, |
585 | t->u.target_size | ||
586 | - sizeof(*t), | ||
587 | e->comefrom)) { | 580 | e->comefrom)) { |
588 | duprintf("ip_tables: check failed for `%s'.\n", | 581 | duprintf("ip_tables: check failed for `%s'.\n", |
589 | t->u.kernel.target->name); | 582 | t->u.kernel.target->name); |
@@ -655,8 +648,7 @@ cleanup_entry(struct ipt_entry *e, unsigned int *i) | |||
655 | IPT_MATCH_ITERATE(e, cleanup_match, NULL); | 648 | IPT_MATCH_ITERATE(e, cleanup_match, NULL); |
656 | t = ipt_get_target(e); | 649 | t = ipt_get_target(e); |
657 | if (t->u.kernel.target->destroy) | 650 | if (t->u.kernel.target->destroy) |
658 | t->u.kernel.target->destroy(t->u.kernel.target, t->data, | 651 | t->u.kernel.target->destroy(t->u.kernel.target, t->data); |
659 | t->u.target_size - sizeof(*t)); | ||
660 | module_put(t->u.kernel.target->me); | 652 | module_put(t->u.kernel.target->me); |
661 | return 0; | 653 | return 0; |
662 | } | 654 | } |
@@ -950,73 +942,28 @@ static short compat_calc_jump(u_int16_t offset) | |||
950 | return delta; | 942 | return delta; |
951 | } | 943 | } |
952 | 944 | ||
953 | struct compat_ipt_standard_target | 945 | static void compat_standard_from_user(void *dst, void *src) |
954 | { | 946 | { |
955 | struct compat_xt_entry_target target; | 947 | int v = *(compat_int_t *)src; |
956 | compat_int_t verdict; | ||
957 | }; | ||
958 | |||
959 | struct compat_ipt_standard | ||
960 | { | ||
961 | struct compat_ipt_entry entry; | ||
962 | struct compat_ipt_standard_target target; | ||
963 | }; | ||
964 | 948 | ||
965 | #define IPT_ST_LEN XT_ALIGN(sizeof(struct ipt_standard_target)) | 949 | if (v > 0) |
966 | #define IPT_ST_COMPAT_LEN COMPAT_XT_ALIGN(sizeof(struct compat_ipt_standard_target)) | 950 | v += compat_calc_jump(v); |
967 | #define IPT_ST_OFFSET (IPT_ST_LEN - IPT_ST_COMPAT_LEN) | 951 | memcpy(dst, &v, sizeof(v)); |
952 | } | ||
968 | 953 | ||
969 | static int compat_ipt_standard_fn(void *target, | 954 | static int compat_standard_to_user(void __user *dst, void *src) |
970 | void **dstptr, int *size, int convert) | ||
971 | { | 955 | { |
972 | struct compat_ipt_standard_target compat_st, *pcompat_st; | 956 | compat_int_t cv = *(int *)src; |
973 | struct ipt_standard_target st, *pst; | ||
974 | int ret; | ||
975 | 957 | ||
976 | ret = 0; | 958 | if (cv > 0) |
977 | switch (convert) { | 959 | cv -= compat_calc_jump(cv); |
978 | case COMPAT_TO_USER: | 960 | return copy_to_user(dst, &cv, sizeof(cv)) ? -EFAULT : 0; |
979 | pst = target; | ||
980 | memcpy(&compat_st.target, &pst->target, | ||
981 | sizeof(compat_st.target)); | ||
982 | compat_st.verdict = pst->verdict; | ||
983 | if (compat_st.verdict > 0) | ||
984 | compat_st.verdict -= | ||
985 | compat_calc_jump(compat_st.verdict); | ||
986 | compat_st.target.u.user.target_size = IPT_ST_COMPAT_LEN; | ||
987 | if (copy_to_user(*dstptr, &compat_st, IPT_ST_COMPAT_LEN)) | ||
988 | ret = -EFAULT; | ||
989 | *size -= IPT_ST_OFFSET; | ||
990 | *dstptr += IPT_ST_COMPAT_LEN; | ||
991 | break; | ||
992 | case COMPAT_FROM_USER: | ||
993 | pcompat_st = target; | ||
994 | memcpy(&st.target, &pcompat_st->target, IPT_ST_COMPAT_LEN); | ||
995 | st.verdict = pcompat_st->verdict; | ||
996 | if (st.verdict > 0) | ||
997 | st.verdict += compat_calc_jump(st.verdict); | ||
998 | st.target.u.user.target_size = IPT_ST_LEN; | ||
999 | memcpy(*dstptr, &st, IPT_ST_LEN); | ||
1000 | *size += IPT_ST_OFFSET; | ||
1001 | *dstptr += IPT_ST_LEN; | ||
1002 | break; | ||
1003 | case COMPAT_CALC_SIZE: | ||
1004 | *size += IPT_ST_OFFSET; | ||
1005 | break; | ||
1006 | default: | ||
1007 | ret = -ENOPROTOOPT; | ||
1008 | break; | ||
1009 | } | ||
1010 | return ret; | ||
1011 | } | 961 | } |
1012 | 962 | ||
1013 | static inline int | 963 | static inline int |
1014 | compat_calc_match(struct ipt_entry_match *m, int * size) | 964 | compat_calc_match(struct ipt_entry_match *m, int * size) |
1015 | { | 965 | { |
1016 | if (m->u.kernel.match->compat) | 966 | *size += xt_compat_match_offset(m->u.kernel.match); |
1017 | m->u.kernel.match->compat(m, NULL, size, COMPAT_CALC_SIZE); | ||
1018 | else | ||
1019 | xt_compat_match(m, NULL, size, COMPAT_CALC_SIZE); | ||
1020 | return 0; | 967 | return 0; |
1021 | } | 968 | } |
1022 | 969 | ||
@@ -1031,10 +978,7 @@ static int compat_calc_entry(struct ipt_entry *e, struct xt_table_info *info, | |||
1031 | entry_offset = (void *)e - base; | 978 | entry_offset = (void *)e - base; |
1032 | IPT_MATCH_ITERATE(e, compat_calc_match, &off); | 979 | IPT_MATCH_ITERATE(e, compat_calc_match, &off); |
1033 | t = ipt_get_target(e); | 980 | t = ipt_get_target(e); |
1034 | if (t->u.kernel.target->compat) | 981 | off += xt_compat_target_offset(t->u.kernel.target); |
1035 | t->u.kernel.target->compat(t, NULL, &off, COMPAT_CALC_SIZE); | ||
1036 | else | ||
1037 | xt_compat_target(t, NULL, &off, COMPAT_CALC_SIZE); | ||
1038 | newinfo->size -= off; | 982 | newinfo->size -= off; |
1039 | ret = compat_add_offset(entry_offset, off); | 983 | ret = compat_add_offset(entry_offset, off); |
1040 | if (ret) | 984 | if (ret) |
@@ -1420,17 +1364,13 @@ struct compat_ipt_replace { | |||
1420 | }; | 1364 | }; |
1421 | 1365 | ||
1422 | static inline int compat_copy_match_to_user(struct ipt_entry_match *m, | 1366 | static inline int compat_copy_match_to_user(struct ipt_entry_match *m, |
1423 | void __user **dstptr, compat_uint_t *size) | 1367 | void * __user *dstptr, compat_uint_t *size) |
1424 | { | 1368 | { |
1425 | if (m->u.kernel.match->compat) | 1369 | return xt_compat_match_to_user(m, dstptr, size); |
1426 | return m->u.kernel.match->compat(m, dstptr, size, | ||
1427 | COMPAT_TO_USER); | ||
1428 | else | ||
1429 | return xt_compat_match(m, dstptr, size, COMPAT_TO_USER); | ||
1430 | } | 1370 | } |
1431 | 1371 | ||
1432 | static int compat_copy_entry_to_user(struct ipt_entry *e, | 1372 | static int compat_copy_entry_to_user(struct ipt_entry *e, |
1433 | void __user **dstptr, compat_uint_t *size) | 1373 | void * __user *dstptr, compat_uint_t *size) |
1434 | { | 1374 | { |
1435 | struct ipt_entry_target __user *t; | 1375 | struct ipt_entry_target __user *t; |
1436 | struct compat_ipt_entry __user *ce; | 1376 | struct compat_ipt_entry __user *ce; |
@@ -1450,11 +1390,7 @@ static int compat_copy_entry_to_user(struct ipt_entry *e, | |||
1450 | if (ret) | 1390 | if (ret) |
1451 | goto out; | 1391 | goto out; |
1452 | t = ipt_get_target(e); | 1392 | t = ipt_get_target(e); |
1453 | if (t->u.kernel.target->compat) | 1393 | ret = xt_compat_target_to_user(t, dstptr, size); |
1454 | ret = t->u.kernel.target->compat(t, dstptr, size, | ||
1455 | COMPAT_TO_USER); | ||
1456 | else | ||
1457 | ret = xt_compat_target(t, dstptr, size, COMPAT_TO_USER); | ||
1458 | if (ret) | 1394 | if (ret) |
1459 | goto out; | 1395 | goto out; |
1460 | ret = -EFAULT; | 1396 | ret = -EFAULT; |
@@ -1486,11 +1422,7 @@ compat_check_calc_match(struct ipt_entry_match *m, | |||
1486 | return match ? PTR_ERR(match) : -ENOENT; | 1422 | return match ? PTR_ERR(match) : -ENOENT; |
1487 | } | 1423 | } |
1488 | m->u.kernel.match = match; | 1424 | m->u.kernel.match = match; |
1489 | 1425 | *size += xt_compat_match_offset(match); | |
1490 | if (m->u.kernel.match->compat) | ||
1491 | m->u.kernel.match->compat(m, NULL, size, COMPAT_CALC_SIZE); | ||
1492 | else | ||
1493 | xt_compat_match(m, NULL, size, COMPAT_CALC_SIZE); | ||
1494 | 1426 | ||
1495 | (*i)++; | 1427 | (*i)++; |
1496 | return 0; | 1428 | return 0; |
@@ -1537,7 +1469,7 @@ check_compat_entry_size_and_hooks(struct ipt_entry *e, | |||
1537 | ret = IPT_MATCH_ITERATE(e, compat_check_calc_match, name, &e->ip, | 1469 | ret = IPT_MATCH_ITERATE(e, compat_check_calc_match, name, &e->ip, |
1538 | e->comefrom, &off, &j); | 1470 | e->comefrom, &off, &j); |
1539 | if (ret != 0) | 1471 | if (ret != 0) |
1540 | goto out; | 1472 | goto cleanup_matches; |
1541 | 1473 | ||
1542 | t = ipt_get_target(e); | 1474 | t = ipt_get_target(e); |
1543 | target = try_then_request_module(xt_find_target(AF_INET, | 1475 | target = try_then_request_module(xt_find_target(AF_INET, |
@@ -1547,14 +1479,11 @@ check_compat_entry_size_and_hooks(struct ipt_entry *e, | |||
1547 | if (IS_ERR(target) || !target) { | 1479 | if (IS_ERR(target) || !target) { |
1548 | duprintf("check_entry: `%s' not found\n", t->u.user.name); | 1480 | duprintf("check_entry: `%s' not found\n", t->u.user.name); |
1549 | ret = target ? PTR_ERR(target) : -ENOENT; | 1481 | ret = target ? PTR_ERR(target) : -ENOENT; |
1550 | goto out; | 1482 | goto cleanup_matches; |
1551 | } | 1483 | } |
1552 | t->u.kernel.target = target; | 1484 | t->u.kernel.target = target; |
1553 | 1485 | ||
1554 | if (t->u.kernel.target->compat) | 1486 | off += xt_compat_target_offset(target); |
1555 | t->u.kernel.target->compat(t, NULL, &off, COMPAT_CALC_SIZE); | ||
1556 | else | ||
1557 | xt_compat_target(t, NULL, &off, COMPAT_CALC_SIZE); | ||
1558 | *size += off; | 1487 | *size += off; |
1559 | ret = compat_add_offset(entry_offset, off); | 1488 | ret = compat_add_offset(entry_offset, off); |
1560 | if (ret) | 1489 | if (ret) |
@@ -1574,14 +1503,17 @@ check_compat_entry_size_and_hooks(struct ipt_entry *e, | |||
1574 | 1503 | ||
1575 | (*i)++; | 1504 | (*i)++; |
1576 | return 0; | 1505 | return 0; |
1506 | |||
1577 | out: | 1507 | out: |
1508 | module_put(t->u.kernel.target->me); | ||
1509 | cleanup_matches: | ||
1578 | IPT_MATCH_ITERATE(e, cleanup_match, &j); | 1510 | IPT_MATCH_ITERATE(e, cleanup_match, &j); |
1579 | return ret; | 1511 | return ret; |
1580 | } | 1512 | } |
1581 | 1513 | ||
1582 | static inline int compat_copy_match_from_user(struct ipt_entry_match *m, | 1514 | static inline int compat_copy_match_from_user(struct ipt_entry_match *m, |
1583 | void **dstptr, compat_uint_t *size, const char *name, | 1515 | void **dstptr, compat_uint_t *size, const char *name, |
1584 | const struct ipt_ip *ip, unsigned int hookmask) | 1516 | const struct ipt_ip *ip, unsigned int hookmask, int *i) |
1585 | { | 1517 | { |
1586 | struct ipt_entry_match *dm; | 1518 | struct ipt_entry_match *dm; |
1587 | struct ipt_match *match; | 1519 | struct ipt_match *match; |
@@ -1589,26 +1521,28 @@ static inline int compat_copy_match_from_user(struct ipt_entry_match *m, | |||
1589 | 1521 | ||
1590 | dm = (struct ipt_entry_match *)*dstptr; | 1522 | dm = (struct ipt_entry_match *)*dstptr; |
1591 | match = m->u.kernel.match; | 1523 | match = m->u.kernel.match; |
1592 | if (match->compat) | 1524 | xt_compat_match_from_user(m, dstptr, size); |
1593 | match->compat(m, dstptr, size, COMPAT_FROM_USER); | ||
1594 | else | ||
1595 | xt_compat_match(m, dstptr, size, COMPAT_FROM_USER); | ||
1596 | 1525 | ||
1597 | ret = xt_check_match(match, AF_INET, dm->u.match_size - sizeof(*dm), | 1526 | ret = xt_check_match(match, AF_INET, dm->u.match_size - sizeof(*dm), |
1598 | name, hookmask, ip->proto, | 1527 | name, hookmask, ip->proto, |
1599 | ip->invflags & IPT_INV_PROTO); | 1528 | ip->invflags & IPT_INV_PROTO); |
1600 | if (ret) | 1529 | if (ret) |
1601 | return ret; | 1530 | goto err; |
1602 | 1531 | ||
1603 | if (m->u.kernel.match->checkentry | 1532 | if (m->u.kernel.match->checkentry |
1604 | && !m->u.kernel.match->checkentry(name, ip, match, dm->data, | 1533 | && !m->u.kernel.match->checkentry(name, ip, match, dm->data, |
1605 | dm->u.match_size - sizeof(*dm), | ||
1606 | hookmask)) { | 1534 | hookmask)) { |
1607 | duprintf("ip_tables: check failed for `%s'.\n", | 1535 | duprintf("ip_tables: check failed for `%s'.\n", |
1608 | m->u.kernel.match->name); | 1536 | m->u.kernel.match->name); |
1609 | return -EINVAL; | 1537 | ret = -EINVAL; |
1538 | goto err; | ||
1610 | } | 1539 | } |
1540 | (*i)++; | ||
1611 | return 0; | 1541 | return 0; |
1542 | |||
1543 | err: | ||
1544 | module_put(m->u.kernel.match->me); | ||
1545 | return ret; | ||
1612 | } | 1546 | } |
1613 | 1547 | ||
1614 | static int compat_copy_entry_from_user(struct ipt_entry *e, void **dstptr, | 1548 | static int compat_copy_entry_from_user(struct ipt_entry *e, void **dstptr, |
@@ -1619,25 +1553,23 @@ static int compat_copy_entry_from_user(struct ipt_entry *e, void **dstptr, | |||
1619 | struct ipt_target *target; | 1553 | struct ipt_target *target; |
1620 | struct ipt_entry *de; | 1554 | struct ipt_entry *de; |
1621 | unsigned int origsize; | 1555 | unsigned int origsize; |
1622 | int ret, h; | 1556 | int ret, h, j; |
1623 | 1557 | ||
1624 | ret = 0; | 1558 | ret = 0; |
1625 | origsize = *size; | 1559 | origsize = *size; |
1626 | de = (struct ipt_entry *)*dstptr; | 1560 | de = (struct ipt_entry *)*dstptr; |
1627 | memcpy(de, e, sizeof(struct ipt_entry)); | 1561 | memcpy(de, e, sizeof(struct ipt_entry)); |
1628 | 1562 | ||
1563 | j = 0; | ||
1629 | *dstptr += sizeof(struct compat_ipt_entry); | 1564 | *dstptr += sizeof(struct compat_ipt_entry); |
1630 | ret = IPT_MATCH_ITERATE(e, compat_copy_match_from_user, dstptr, size, | 1565 | ret = IPT_MATCH_ITERATE(e, compat_copy_match_from_user, dstptr, size, |
1631 | name, &de->ip, de->comefrom); | 1566 | name, &de->ip, de->comefrom, &j); |
1632 | if (ret) | 1567 | if (ret) |
1633 | goto out; | 1568 | goto cleanup_matches; |
1634 | de->target_offset = e->target_offset - (origsize - *size); | 1569 | de->target_offset = e->target_offset - (origsize - *size); |
1635 | t = ipt_get_target(e); | 1570 | t = ipt_get_target(e); |
1636 | target = t->u.kernel.target; | 1571 | target = t->u.kernel.target; |
1637 | if (target->compat) | 1572 | xt_compat_target_from_user(t, dstptr, size); |
1638 | target->compat(t, dstptr, size, COMPAT_FROM_USER); | ||
1639 | else | ||
1640 | xt_compat_target(t, dstptr, size, COMPAT_FROM_USER); | ||
1641 | 1573 | ||
1642 | de->next_offset = e->next_offset - (origsize - *size); | 1574 | de->next_offset = e->next_offset - (origsize - *size); |
1643 | for (h = 0; h < NF_IP_NUMHOOKS; h++) { | 1575 | for (h = 0; h < NF_IP_NUMHOOKS; h++) { |
@@ -1653,22 +1585,26 @@ static int compat_copy_entry_from_user(struct ipt_entry *e, void **dstptr, | |||
1653 | name, e->comefrom, e->ip.proto, | 1585 | name, e->comefrom, e->ip.proto, |
1654 | e->ip.invflags & IPT_INV_PROTO); | 1586 | e->ip.invflags & IPT_INV_PROTO); |
1655 | if (ret) | 1587 | if (ret) |
1656 | goto out; | 1588 | goto err; |
1657 | 1589 | ||
1658 | ret = -EINVAL; | 1590 | ret = -EINVAL; |
1659 | if (t->u.kernel.target == &ipt_standard_target) { | 1591 | if (t->u.kernel.target == &ipt_standard_target) { |
1660 | if (!standard_check(t, *size)) | 1592 | if (!standard_check(t, *size)) |
1661 | goto out; | 1593 | goto err; |
1662 | } else if (t->u.kernel.target->checkentry | 1594 | } else if (t->u.kernel.target->checkentry |
1663 | && !t->u.kernel.target->checkentry(name, de, target, | 1595 | && !t->u.kernel.target->checkentry(name, de, target, |
1664 | t->data, t->u.target_size - sizeof(*t), | 1596 | t->data, de->comefrom)) { |
1665 | de->comefrom)) { | ||
1666 | duprintf("ip_tables: compat: check failed for `%s'.\n", | 1597 | duprintf("ip_tables: compat: check failed for `%s'.\n", |
1667 | t->u.kernel.target->name); | 1598 | t->u.kernel.target->name); |
1668 | goto out; | 1599 | goto err; |
1669 | } | 1600 | } |
1670 | ret = 0; | 1601 | ret = 0; |
1671 | out: | 1602 | return ret; |
1603 | |||
1604 | err: | ||
1605 | module_put(t->u.kernel.target->me); | ||
1606 | cleanup_matches: | ||
1607 | IPT_MATCH_ITERATE(e, cleanup_match, &j); | ||
1672 | return ret; | 1608 | return ret; |
1673 | } | 1609 | } |
1674 | 1610 | ||
@@ -1989,6 +1925,8 @@ compat_get_entries(struct compat_ipt_get_entries __user *uptr, int *len) | |||
1989 | return ret; | 1925 | return ret; |
1990 | } | 1926 | } |
1991 | 1927 | ||
1928 | static int do_ipt_get_ctl(struct sock *, int, void __user *, int *); | ||
1929 | |||
1992 | static int | 1930 | static int |
1993 | compat_do_ipt_get_ctl(struct sock *sk, int cmd, void __user *user, int *len) | 1931 | compat_do_ipt_get_ctl(struct sock *sk, int cmd, void __user *user, int *len) |
1994 | { | 1932 | { |
@@ -2002,8 +1940,7 @@ compat_do_ipt_get_ctl(struct sock *sk, int cmd, void __user *user, int *len) | |||
2002 | ret = compat_get_entries(user, len); | 1940 | ret = compat_get_entries(user, len); |
2003 | break; | 1941 | break; |
2004 | default: | 1942 | default: |
2005 | duprintf("compat_do_ipt_get_ctl: unknown request %i\n", cmd); | 1943 | ret = do_ipt_get_ctl(sk, cmd, user, len); |
2006 | ret = -EINVAL; | ||
2007 | } | 1944 | } |
2008 | return ret; | 1945 | return ret; |
2009 | } | 1946 | } |
@@ -2185,7 +2122,6 @@ icmp_checkentry(const char *tablename, | |||
2185 | const void *info, | 2122 | const void *info, |
2186 | const struct xt_match *match, | 2123 | const struct xt_match *match, |
2187 | void *matchinfo, | 2124 | void *matchinfo, |
2188 | unsigned int matchsize, | ||
2189 | unsigned int hook_mask) | 2125 | unsigned int hook_mask) |
2190 | { | 2126 | { |
2191 | const struct ipt_icmp *icmpinfo = matchinfo; | 2127 | const struct ipt_icmp *icmpinfo = matchinfo; |
@@ -2200,7 +2136,9 @@ static struct ipt_target ipt_standard_target = { | |||
2200 | .targetsize = sizeof(int), | 2136 | .targetsize = sizeof(int), |
2201 | .family = AF_INET, | 2137 | .family = AF_INET, |
2202 | #ifdef CONFIG_COMPAT | 2138 | #ifdef CONFIG_COMPAT |
2203 | .compat = &compat_ipt_standard_fn, | 2139 | .compatsize = sizeof(compat_int_t), |
2140 | .compat_from_user = compat_standard_from_user, | ||
2141 | .compat_to_user = compat_standard_to_user, | ||
2204 | #endif | 2142 | #endif |
2205 | }; | 2143 | }; |
2206 | 2144 | ||
diff --git a/net/ipv4/netfilter/ipt_CLUSTERIP.c b/net/ipv4/netfilter/ipt_CLUSTERIP.c index d994c5f5744c..41589665fc5d 100644 --- a/net/ipv4/netfilter/ipt_CLUSTERIP.c +++ b/net/ipv4/netfilter/ipt_CLUSTERIP.c | |||
@@ -302,8 +302,7 @@ target(struct sk_buff **pskb, | |||
302 | const struct net_device *out, | 302 | const struct net_device *out, |
303 | unsigned int hooknum, | 303 | unsigned int hooknum, |
304 | const struct xt_target *target, | 304 | const struct xt_target *target, |
305 | const void *targinfo, | 305 | const void *targinfo) |
306 | void *userinfo) | ||
307 | { | 306 | { |
308 | const struct ipt_clusterip_tgt_info *cipinfo = targinfo; | 307 | const struct ipt_clusterip_tgt_info *cipinfo = targinfo; |
309 | enum ip_conntrack_info ctinfo; | 308 | enum ip_conntrack_info ctinfo; |
@@ -373,7 +372,6 @@ checkentry(const char *tablename, | |||
373 | const void *e_void, | 372 | const void *e_void, |
374 | const struct xt_target *target, | 373 | const struct xt_target *target, |
375 | void *targinfo, | 374 | void *targinfo, |
376 | unsigned int targinfosize, | ||
377 | unsigned int hook_mask) | 375 | unsigned int hook_mask) |
378 | { | 376 | { |
379 | struct ipt_clusterip_tgt_info *cipinfo = targinfo; | 377 | struct ipt_clusterip_tgt_info *cipinfo = targinfo; |
@@ -450,8 +448,7 @@ checkentry(const char *tablename, | |||
450 | } | 448 | } |
451 | 449 | ||
452 | /* drop reference count of cluster config when rule is deleted */ | 450 | /* drop reference count of cluster config when rule is deleted */ |
453 | static void destroy(const struct xt_target *target, void *targinfo, | 451 | static void destroy(const struct xt_target *target, void *targinfo) |
454 | unsigned int targinfosize) | ||
455 | { | 452 | { |
456 | struct ipt_clusterip_tgt_info *cipinfo = targinfo; | 453 | struct ipt_clusterip_tgt_info *cipinfo = targinfo; |
457 | 454 | ||
diff --git a/net/ipv4/netfilter/ipt_DSCP.c b/net/ipv4/netfilter/ipt_DSCP.c deleted file mode 100644 index c8e971288dfe..000000000000 --- a/net/ipv4/netfilter/ipt_DSCP.c +++ /dev/null | |||
@@ -1,96 +0,0 @@ | |||
1 | /* iptables module for setting the IPv4 DSCP field, Version 1.8 | ||
2 | * | ||
3 | * (C) 2002 by Harald Welte <laforge@netfilter.org> | ||
4 | * based on ipt_FTOS.c (C) 2000 by Matthew G. Marsh <mgm@paktronix.com> | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License version 2 as | ||
8 | * published by the Free Software Foundation. | ||
9 | * | ||
10 | * See RFC2474 for a description of the DSCP field within the IP Header. | ||
11 | * | ||
12 | * ipt_DSCP.c,v 1.8 2002/08/06 18:41:57 laforge Exp | ||
13 | */ | ||
14 | |||
15 | #include <linux/module.h> | ||
16 | #include <linux/skbuff.h> | ||
17 | #include <linux/ip.h> | ||
18 | #include <net/checksum.h> | ||
19 | |||
20 | #include <linux/netfilter_ipv4/ip_tables.h> | ||
21 | #include <linux/netfilter_ipv4/ipt_DSCP.h> | ||
22 | |||
23 | MODULE_AUTHOR("Harald Welte <laforge@netfilter.org>"); | ||
24 | MODULE_DESCRIPTION("iptables DSCP modification module"); | ||
25 | MODULE_LICENSE("GPL"); | ||
26 | |||
27 | static unsigned int | ||
28 | target(struct sk_buff **pskb, | ||
29 | const struct net_device *in, | ||
30 | const struct net_device *out, | ||
31 | unsigned int hooknum, | ||
32 | const struct xt_target *target, | ||
33 | const void *targinfo, | ||
34 | void *userinfo) | ||
35 | { | ||
36 | const struct ipt_DSCP_info *dinfo = targinfo; | ||
37 | u_int8_t sh_dscp = ((dinfo->dscp << IPT_DSCP_SHIFT) & IPT_DSCP_MASK); | ||
38 | |||
39 | |||
40 | if (((*pskb)->nh.iph->tos & IPT_DSCP_MASK) != sh_dscp) { | ||
41 | u_int16_t diffs[2]; | ||
42 | |||
43 | if (!skb_make_writable(pskb, sizeof(struct iphdr))) | ||
44 | return NF_DROP; | ||
45 | |||
46 | diffs[0] = htons((*pskb)->nh.iph->tos) ^ 0xFFFF; | ||
47 | (*pskb)->nh.iph->tos = ((*pskb)->nh.iph->tos & ~IPT_DSCP_MASK) | ||
48 | | sh_dscp; | ||
49 | diffs[1] = htons((*pskb)->nh.iph->tos); | ||
50 | (*pskb)->nh.iph->check | ||
51 | = csum_fold(csum_partial((char *)diffs, | ||
52 | sizeof(diffs), | ||
53 | (*pskb)->nh.iph->check | ||
54 | ^ 0xFFFF)); | ||
55 | } | ||
56 | return IPT_CONTINUE; | ||
57 | } | ||
58 | |||
59 | static int | ||
60 | checkentry(const char *tablename, | ||
61 | const void *e_void, | ||
62 | const struct xt_target *target, | ||
63 | void *targinfo, | ||
64 | unsigned int targinfosize, | ||
65 | unsigned int hook_mask) | ||
66 | { | ||
67 | const u_int8_t dscp = ((struct ipt_DSCP_info *)targinfo)->dscp; | ||
68 | |||
69 | if ((dscp > IPT_DSCP_MAX)) { | ||
70 | printk(KERN_WARNING "DSCP: dscp %x out of range\n", dscp); | ||
71 | return 0; | ||
72 | } | ||
73 | return 1; | ||
74 | } | ||
75 | |||
76 | static struct ipt_target ipt_dscp_reg = { | ||
77 | .name = "DSCP", | ||
78 | .target = target, | ||
79 | .targetsize = sizeof(struct ipt_DSCP_info), | ||
80 | .table = "mangle", | ||
81 | .checkentry = checkentry, | ||
82 | .me = THIS_MODULE, | ||
83 | }; | ||
84 | |||
85 | static int __init ipt_dscp_init(void) | ||
86 | { | ||
87 | return ipt_register_target(&ipt_dscp_reg); | ||
88 | } | ||
89 | |||
90 | static void __exit ipt_dscp_fini(void) | ||
91 | { | ||
92 | ipt_unregister_target(&ipt_dscp_reg); | ||
93 | } | ||
94 | |||
95 | module_init(ipt_dscp_init); | ||
96 | module_exit(ipt_dscp_fini); | ||
diff --git a/net/ipv4/netfilter/ipt_ECN.c b/net/ipv4/netfilter/ipt_ECN.c index 4adf5c9d34f5..23f9c7ebe7eb 100644 --- a/net/ipv4/netfilter/ipt_ECN.c +++ b/net/ipv4/netfilter/ipt_ECN.c | |||
@@ -27,32 +27,28 @@ MODULE_DESCRIPTION("iptables ECN modification module"); | |||
27 | static inline int | 27 | static inline int |
28 | set_ect_ip(struct sk_buff **pskb, const struct ipt_ECN_info *einfo) | 28 | set_ect_ip(struct sk_buff **pskb, const struct ipt_ECN_info *einfo) |
29 | { | 29 | { |
30 | if (((*pskb)->nh.iph->tos & IPT_ECN_IP_MASK) | 30 | struct iphdr *iph = (*pskb)->nh.iph; |
31 | != (einfo->ip_ect & IPT_ECN_IP_MASK)) { | 31 | u_int16_t oldtos; |
32 | u_int16_t diffs[2]; | ||
33 | 32 | ||
33 | if ((iph->tos & IPT_ECN_IP_MASK) != (einfo->ip_ect & IPT_ECN_IP_MASK)) { | ||
34 | if (!skb_make_writable(pskb, sizeof(struct iphdr))) | 34 | if (!skb_make_writable(pskb, sizeof(struct iphdr))) |
35 | return 0; | 35 | return 0; |
36 | 36 | iph = (*pskb)->nh.iph; | |
37 | diffs[0] = htons((*pskb)->nh.iph->tos) ^ 0xFFFF; | 37 | oldtos = iph->tos; |
38 | (*pskb)->nh.iph->tos &= ~IPT_ECN_IP_MASK; | 38 | iph->tos &= ~IPT_ECN_IP_MASK; |
39 | (*pskb)->nh.iph->tos |= (einfo->ip_ect & IPT_ECN_IP_MASK); | 39 | iph->tos |= (einfo->ip_ect & IPT_ECN_IP_MASK); |
40 | diffs[1] = htons((*pskb)->nh.iph->tos); | 40 | iph->check = nf_csum_update(oldtos ^ 0xFFFF, iph->tos, |
41 | (*pskb)->nh.iph->check | 41 | iph->check); |
42 | = csum_fold(csum_partial((char *)diffs, | ||
43 | sizeof(diffs), | ||
44 | (*pskb)->nh.iph->check | ||
45 | ^0xFFFF)); | ||
46 | } | 42 | } |
47 | return 1; | 43 | return 1; |
48 | } | 44 | } |
49 | 45 | ||
50 | /* Return 0 if there was an error. */ | 46 | /* Return 0 if there was an error. */ |
51 | static inline int | 47 | static inline int |
52 | set_ect_tcp(struct sk_buff **pskb, const struct ipt_ECN_info *einfo, int inward) | 48 | set_ect_tcp(struct sk_buff **pskb, const struct ipt_ECN_info *einfo) |
53 | { | 49 | { |
54 | struct tcphdr _tcph, *tcph; | 50 | struct tcphdr _tcph, *tcph; |
55 | u_int16_t diffs[2]; | 51 | u_int16_t oldval; |
56 | 52 | ||
57 | /* Not enought header? */ | 53 | /* Not enought header? */ |
58 | tcph = skb_header_pointer(*pskb, (*pskb)->nh.iph->ihl*4, | 54 | tcph = skb_header_pointer(*pskb, (*pskb)->nh.iph->ihl*4, |
@@ -70,22 +66,16 @@ set_ect_tcp(struct sk_buff **pskb, const struct ipt_ECN_info *einfo, int inward) | |||
70 | return 0; | 66 | return 0; |
71 | tcph = (void *)(*pskb)->nh.iph + (*pskb)->nh.iph->ihl*4; | 67 | tcph = (void *)(*pskb)->nh.iph + (*pskb)->nh.iph->ihl*4; |
72 | 68 | ||
73 | if ((*pskb)->ip_summed == CHECKSUM_HW && | 69 | oldval = ((u_int16_t *)tcph)[6]; |
74 | skb_checksum_help(*pskb, inward)) | ||
75 | return 0; | ||
76 | |||
77 | diffs[0] = ((u_int16_t *)tcph)[6]; | ||
78 | if (einfo->operation & IPT_ECN_OP_SET_ECE) | 70 | if (einfo->operation & IPT_ECN_OP_SET_ECE) |
79 | tcph->ece = einfo->proto.tcp.ece; | 71 | tcph->ece = einfo->proto.tcp.ece; |
80 | if (einfo->operation & IPT_ECN_OP_SET_CWR) | 72 | if (einfo->operation & IPT_ECN_OP_SET_CWR) |
81 | tcph->cwr = einfo->proto.tcp.cwr; | 73 | tcph->cwr = einfo->proto.tcp.cwr; |
82 | diffs[1] = ((u_int16_t *)tcph)[6]; | ||
83 | diffs[0] = diffs[0] ^ 0xFFFF; | ||
84 | 74 | ||
85 | if ((*pskb)->ip_summed != CHECKSUM_UNNECESSARY) | 75 | tcph->check = nf_proto_csum_update((*pskb), |
86 | tcph->check = csum_fold(csum_partial((char *)diffs, | 76 | oldval ^ 0xFFFF, |
87 | sizeof(diffs), | 77 | ((u_int16_t *)tcph)[6], |
88 | tcph->check^0xFFFF)); | 78 | tcph->check, 0); |
89 | return 1; | 79 | return 1; |
90 | } | 80 | } |
91 | 81 | ||
@@ -95,8 +85,7 @@ target(struct sk_buff **pskb, | |||
95 | const struct net_device *out, | 85 | const struct net_device *out, |
96 | unsigned int hooknum, | 86 | unsigned int hooknum, |
97 | const struct xt_target *target, | 87 | const struct xt_target *target, |
98 | const void *targinfo, | 88 | const void *targinfo) |
99 | void *userinfo) | ||
100 | { | 89 | { |
101 | const struct ipt_ECN_info *einfo = targinfo; | 90 | const struct ipt_ECN_info *einfo = targinfo; |
102 | 91 | ||
@@ -106,7 +95,7 @@ target(struct sk_buff **pskb, | |||
106 | 95 | ||
107 | if (einfo->operation & (IPT_ECN_OP_SET_ECE | IPT_ECN_OP_SET_CWR) | 96 | if (einfo->operation & (IPT_ECN_OP_SET_ECE | IPT_ECN_OP_SET_CWR) |
108 | && (*pskb)->nh.iph->protocol == IPPROTO_TCP) | 97 | && (*pskb)->nh.iph->protocol == IPPROTO_TCP) |
109 | if (!set_ect_tcp(pskb, einfo, (out == NULL))) | 98 | if (!set_ect_tcp(pskb, einfo)) |
110 | return NF_DROP; | 99 | return NF_DROP; |
111 | 100 | ||
112 | return IPT_CONTINUE; | 101 | return IPT_CONTINUE; |
@@ -117,7 +106,6 @@ checkentry(const char *tablename, | |||
117 | const void *e_void, | 106 | const void *e_void, |
118 | const struct xt_target *target, | 107 | const struct xt_target *target, |
119 | void *targinfo, | 108 | void *targinfo, |
120 | unsigned int targinfosize, | ||
121 | unsigned int hook_mask) | 109 | unsigned int hook_mask) |
122 | { | 110 | { |
123 | const struct ipt_ECN_info *einfo = (struct ipt_ECN_info *)targinfo; | 111 | const struct ipt_ECN_info *einfo = (struct ipt_ECN_info *)targinfo; |
diff --git a/net/ipv4/netfilter/ipt_LOG.c b/net/ipv4/netfilter/ipt_LOG.c index b98f7b08b084..7dc820df8bc5 100644 --- a/net/ipv4/netfilter/ipt_LOG.c +++ b/net/ipv4/netfilter/ipt_LOG.c | |||
@@ -416,8 +416,7 @@ ipt_log_target(struct sk_buff **pskb, | |||
416 | const struct net_device *out, | 416 | const struct net_device *out, |
417 | unsigned int hooknum, | 417 | unsigned int hooknum, |
418 | const struct xt_target *target, | 418 | const struct xt_target *target, |
419 | const void *targinfo, | 419 | const void *targinfo) |
420 | void *userinfo) | ||
421 | { | 420 | { |
422 | const struct ipt_log_info *loginfo = targinfo; | 421 | const struct ipt_log_info *loginfo = targinfo; |
423 | struct nf_loginfo li; | 422 | struct nf_loginfo li; |
@@ -440,7 +439,6 @@ static int ipt_log_checkentry(const char *tablename, | |||
440 | const void *e, | 439 | const void *e, |
441 | const struct xt_target *target, | 440 | const struct xt_target *target, |
442 | void *targinfo, | 441 | void *targinfo, |
443 | unsigned int targinfosize, | ||
444 | unsigned int hook_mask) | 442 | unsigned int hook_mask) |
445 | { | 443 | { |
446 | const struct ipt_log_info *loginfo = targinfo; | 444 | const struct ipt_log_info *loginfo = targinfo; |
diff --git a/net/ipv4/netfilter/ipt_MASQUERADE.c b/net/ipv4/netfilter/ipt_MASQUERADE.c index ebd94f2abf0d..bc65168a3437 100644 --- a/net/ipv4/netfilter/ipt_MASQUERADE.c +++ b/net/ipv4/netfilter/ipt_MASQUERADE.c | |||
@@ -42,7 +42,6 @@ masquerade_check(const char *tablename, | |||
42 | const void *e, | 42 | const void *e, |
43 | const struct xt_target *target, | 43 | const struct xt_target *target, |
44 | void *targinfo, | 44 | void *targinfo, |
45 | unsigned int targinfosize, | ||
46 | unsigned int hook_mask) | 45 | unsigned int hook_mask) |
47 | { | 46 | { |
48 | const struct ip_nat_multi_range_compat *mr = targinfo; | 47 | const struct ip_nat_multi_range_compat *mr = targinfo; |
@@ -64,8 +63,7 @@ masquerade_target(struct sk_buff **pskb, | |||
64 | const struct net_device *out, | 63 | const struct net_device *out, |
65 | unsigned int hooknum, | 64 | unsigned int hooknum, |
66 | const struct xt_target *target, | 65 | const struct xt_target *target, |
67 | const void *targinfo, | 66 | const void *targinfo) |
68 | void *userinfo) | ||
69 | { | 67 | { |
70 | struct ip_conntrack *ct; | 68 | struct ip_conntrack *ct; |
71 | enum ip_conntrack_info ctinfo; | 69 | enum ip_conntrack_info ctinfo; |
diff --git a/net/ipv4/netfilter/ipt_NETMAP.c b/net/ipv4/netfilter/ipt_NETMAP.c index 736c4b5a86a7..beb2914225ff 100644 --- a/net/ipv4/netfilter/ipt_NETMAP.c +++ b/net/ipv4/netfilter/ipt_NETMAP.c | |||
@@ -33,7 +33,6 @@ check(const char *tablename, | |||
33 | const void *e, | 33 | const void *e, |
34 | const struct xt_target *target, | 34 | const struct xt_target *target, |
35 | void *targinfo, | 35 | void *targinfo, |
36 | unsigned int targinfosize, | ||
37 | unsigned int hook_mask) | 36 | unsigned int hook_mask) |
38 | { | 37 | { |
39 | const struct ip_nat_multi_range_compat *mr = targinfo; | 38 | const struct ip_nat_multi_range_compat *mr = targinfo; |
@@ -55,8 +54,7 @@ target(struct sk_buff **pskb, | |||
55 | const struct net_device *out, | 54 | const struct net_device *out, |
56 | unsigned int hooknum, | 55 | unsigned int hooknum, |
57 | const struct xt_target *target, | 56 | const struct xt_target *target, |
58 | const void *targinfo, | 57 | const void *targinfo) |
59 | void *userinfo) | ||
60 | { | 58 | { |
61 | struct ip_conntrack *ct; | 59 | struct ip_conntrack *ct; |
62 | enum ip_conntrack_info ctinfo; | 60 | enum ip_conntrack_info ctinfo; |
diff --git a/net/ipv4/netfilter/ipt_REDIRECT.c b/net/ipv4/netfilter/ipt_REDIRECT.c index f290463232de..f03d43671c6d 100644 --- a/net/ipv4/netfilter/ipt_REDIRECT.c +++ b/net/ipv4/netfilter/ipt_REDIRECT.c | |||
@@ -36,7 +36,6 @@ redirect_check(const char *tablename, | |||
36 | const void *e, | 36 | const void *e, |
37 | const struct xt_target *target, | 37 | const struct xt_target *target, |
38 | void *targinfo, | 38 | void *targinfo, |
39 | unsigned int targinfosize, | ||
40 | unsigned int hook_mask) | 39 | unsigned int hook_mask) |
41 | { | 40 | { |
42 | const struct ip_nat_multi_range_compat *mr = targinfo; | 41 | const struct ip_nat_multi_range_compat *mr = targinfo; |
@@ -58,8 +57,7 @@ redirect_target(struct sk_buff **pskb, | |||
58 | const struct net_device *out, | 57 | const struct net_device *out, |
59 | unsigned int hooknum, | 58 | unsigned int hooknum, |
60 | const struct xt_target *target, | 59 | const struct xt_target *target, |
61 | const void *targinfo, | 60 | const void *targinfo) |
62 | void *userinfo) | ||
63 | { | 61 | { |
64 | struct ip_conntrack *ct; | 62 | struct ip_conntrack *ct; |
65 | enum ip_conntrack_info ctinfo; | 63 | enum ip_conntrack_info ctinfo; |
diff --git a/net/ipv4/netfilter/ipt_REJECT.c b/net/ipv4/netfilter/ipt_REJECT.c index 269bc2067cb8..b81821edd893 100644 --- a/net/ipv4/netfilter/ipt_REJECT.c +++ b/net/ipv4/netfilter/ipt_REJECT.c | |||
@@ -90,6 +90,7 @@ static inline struct rtable *route_reverse(struct sk_buff *skb, | |||
90 | fl.proto = IPPROTO_TCP; | 90 | fl.proto = IPPROTO_TCP; |
91 | fl.fl_ip_sport = tcph->dest; | 91 | fl.fl_ip_sport = tcph->dest; |
92 | fl.fl_ip_dport = tcph->source; | 92 | fl.fl_ip_dport = tcph->source; |
93 | security_skb_classify_flow(skb, &fl); | ||
93 | 94 | ||
94 | xfrm_lookup((struct dst_entry **)&rt, &fl, NULL, 0); | 95 | xfrm_lookup((struct dst_entry **)&rt, &fl, NULL, 0); |
95 | 96 | ||
@@ -184,6 +185,7 @@ static void send_reset(struct sk_buff *oldskb, int hook) | |||
184 | tcph->urg_ptr = 0; | 185 | tcph->urg_ptr = 0; |
185 | 186 | ||
186 | /* Adjust TCP checksum */ | 187 | /* Adjust TCP checksum */ |
188 | nskb->ip_summed = CHECKSUM_NONE; | ||
187 | tcph->check = 0; | 189 | tcph->check = 0; |
188 | tcph->check = tcp_v4_check(tcph, sizeof(struct tcphdr), | 190 | tcph->check = tcp_v4_check(tcph, sizeof(struct tcphdr), |
189 | nskb->nh.iph->saddr, | 191 | nskb->nh.iph->saddr, |
@@ -226,8 +228,7 @@ static unsigned int reject(struct sk_buff **pskb, | |||
226 | const struct net_device *out, | 228 | const struct net_device *out, |
227 | unsigned int hooknum, | 229 | unsigned int hooknum, |
228 | const struct xt_target *target, | 230 | const struct xt_target *target, |
229 | const void *targinfo, | 231 | const void *targinfo) |
230 | void *userinfo) | ||
231 | { | 232 | { |
232 | const struct ipt_reject_info *reject = targinfo; | 233 | const struct ipt_reject_info *reject = targinfo; |
233 | 234 | ||
@@ -275,7 +276,6 @@ static int check(const char *tablename, | |||
275 | const void *e_void, | 276 | const void *e_void, |
276 | const struct xt_target *target, | 277 | const struct xt_target *target, |
277 | void *targinfo, | 278 | void *targinfo, |
278 | unsigned int targinfosize, | ||
279 | unsigned int hook_mask) | 279 | unsigned int hook_mask) |
280 | { | 280 | { |
281 | const struct ipt_reject_info *rejinfo = targinfo; | 281 | const struct ipt_reject_info *rejinfo = targinfo; |
diff --git a/net/ipv4/netfilter/ipt_SAME.c b/net/ipv4/netfilter/ipt_SAME.c index 7169b09b5a67..efbcb1198832 100644 --- a/net/ipv4/netfilter/ipt_SAME.c +++ b/net/ipv4/netfilter/ipt_SAME.c | |||
@@ -52,7 +52,6 @@ same_check(const char *tablename, | |||
52 | const void *e, | 52 | const void *e, |
53 | const struct xt_target *target, | 53 | const struct xt_target *target, |
54 | void *targinfo, | 54 | void *targinfo, |
55 | unsigned int targinfosize, | ||
56 | unsigned int hook_mask) | 55 | unsigned int hook_mask) |
57 | { | 56 | { |
58 | unsigned int count, countess, rangeip, index = 0; | 57 | unsigned int count, countess, rangeip, index = 0; |
@@ -116,8 +115,7 @@ same_check(const char *tablename, | |||
116 | } | 115 | } |
117 | 116 | ||
118 | static void | 117 | static void |
119 | same_destroy(const struct xt_target *target, void *targinfo, | 118 | same_destroy(const struct xt_target *target, void *targinfo) |
120 | unsigned int targinfosize) | ||
121 | { | 119 | { |
122 | struct ipt_same_info *mr = targinfo; | 120 | struct ipt_same_info *mr = targinfo; |
123 | 121 | ||
@@ -133,8 +131,7 @@ same_target(struct sk_buff **pskb, | |||
133 | const struct net_device *out, | 131 | const struct net_device *out, |
134 | unsigned int hooknum, | 132 | unsigned int hooknum, |
135 | const struct xt_target *target, | 133 | const struct xt_target *target, |
136 | const void *targinfo, | 134 | const void *targinfo) |
137 | void *userinfo) | ||
138 | { | 135 | { |
139 | struct ip_conntrack *ct; | 136 | struct ip_conntrack *ct; |
140 | enum ip_conntrack_info ctinfo; | 137 | enum ip_conntrack_info ctinfo; |
diff --git a/net/ipv4/netfilter/ipt_TCPMSS.c b/net/ipv4/netfilter/ipt_TCPMSS.c index ef2fe5b3f0d8..4246c4321e5b 100644 --- a/net/ipv4/netfilter/ipt_TCPMSS.c +++ b/net/ipv4/netfilter/ipt_TCPMSS.c | |||
@@ -21,26 +21,14 @@ MODULE_LICENSE("GPL"); | |||
21 | MODULE_AUTHOR("Marc Boucher <marc@mbsi.ca>"); | 21 | MODULE_AUTHOR("Marc Boucher <marc@mbsi.ca>"); |
22 | MODULE_DESCRIPTION("iptables TCP MSS modification module"); | 22 | MODULE_DESCRIPTION("iptables TCP MSS modification module"); |
23 | 23 | ||
24 | #if 0 | ||
25 | #define DEBUGP printk | ||
26 | #else | ||
27 | #define DEBUGP(format, args...) | ||
28 | #endif | ||
29 | |||
30 | static u_int16_t | ||
31 | cheat_check(u_int32_t oldvalinv, u_int32_t newval, u_int16_t oldcheck) | ||
32 | { | ||
33 | u_int32_t diffs[] = { oldvalinv, newval }; | ||
34 | return csum_fold(csum_partial((char *)diffs, sizeof(diffs), | ||
35 | oldcheck^0xFFFF)); | ||
36 | } | ||
37 | |||
38 | static inline unsigned int | 24 | static inline unsigned int |
39 | optlen(const u_int8_t *opt, unsigned int offset) | 25 | optlen(const u_int8_t *opt, unsigned int offset) |
40 | { | 26 | { |
41 | /* Beware zero-length options: make finite progress */ | 27 | /* Beware zero-length options: make finite progress */ |
42 | if (opt[offset] <= TCPOPT_NOP || opt[offset+1] == 0) return 1; | 28 | if (opt[offset] <= TCPOPT_NOP || opt[offset+1] == 0) |
43 | else return opt[offset+1]; | 29 | return 1; |
30 | else | ||
31 | return opt[offset+1]; | ||
44 | } | 32 | } |
45 | 33 | ||
46 | static unsigned int | 34 | static unsigned int |
@@ -49,8 +37,7 @@ ipt_tcpmss_target(struct sk_buff **pskb, | |||
49 | const struct net_device *out, | 37 | const struct net_device *out, |
50 | unsigned int hooknum, | 38 | unsigned int hooknum, |
51 | const struct xt_target *target, | 39 | const struct xt_target *target, |
52 | const void *targinfo, | 40 | const void *targinfo) |
53 | void *userinfo) | ||
54 | { | 41 | { |
55 | const struct ipt_tcpmss_info *tcpmssinfo = targinfo; | 42 | const struct ipt_tcpmss_info *tcpmssinfo = targinfo; |
56 | struct tcphdr *tcph; | 43 | struct tcphdr *tcph; |
@@ -62,13 +49,8 @@ ipt_tcpmss_target(struct sk_buff **pskb, | |||
62 | if (!skb_make_writable(pskb, (*pskb)->len)) | 49 | if (!skb_make_writable(pskb, (*pskb)->len)) |
63 | return NF_DROP; | 50 | return NF_DROP; |
64 | 51 | ||
65 | if ((*pskb)->ip_summed == CHECKSUM_HW && | ||
66 | skb_checksum_help(*pskb, out == NULL)) | ||
67 | return NF_DROP; | ||
68 | |||
69 | iph = (*pskb)->nh.iph; | 52 | iph = (*pskb)->nh.iph; |
70 | tcplen = (*pskb)->len - iph->ihl*4; | 53 | tcplen = (*pskb)->len - iph->ihl*4; |
71 | |||
72 | tcph = (void *)iph + iph->ihl*4; | 54 | tcph = (void *)iph + iph->ihl*4; |
73 | 55 | ||
74 | /* Since it passed flags test in tcp match, we know it is is | 56 | /* Since it passed flags test in tcp match, we know it is is |
@@ -84,54 +66,41 @@ ipt_tcpmss_target(struct sk_buff **pskb, | |||
84 | return NF_DROP; | 66 | return NF_DROP; |
85 | } | 67 | } |
86 | 68 | ||
87 | if(tcpmssinfo->mss == IPT_TCPMSS_CLAMP_PMTU) { | 69 | if (tcpmssinfo->mss == IPT_TCPMSS_CLAMP_PMTU) { |
88 | if(!(*pskb)->dst) { | 70 | if (dst_mtu((*pskb)->dst) <= sizeof(struct iphdr) + |
71 | sizeof(struct tcphdr)) { | ||
89 | if (net_ratelimit()) | 72 | if (net_ratelimit()) |
90 | printk(KERN_ERR | 73 | printk(KERN_ERR "ipt_tcpmss_target: " |
91 | "ipt_tcpmss_target: no dst?! can't determine path-MTU\n"); | 74 | "unknown or invalid path-MTU (%d)\n", |
75 | dst_mtu((*pskb)->dst)); | ||
92 | return NF_DROP; /* or IPT_CONTINUE ?? */ | 76 | return NF_DROP; /* or IPT_CONTINUE ?? */ |
93 | } | 77 | } |
94 | 78 | ||
95 | if(dst_mtu((*pskb)->dst) <= (sizeof(struct iphdr) + sizeof(struct tcphdr))) { | 79 | newmss = dst_mtu((*pskb)->dst) - sizeof(struct iphdr) - |
96 | if (net_ratelimit()) | 80 | sizeof(struct tcphdr); |
97 | printk(KERN_ERR | ||
98 | "ipt_tcpmss_target: unknown or invalid path-MTU (%d)\n", dst_mtu((*pskb)->dst)); | ||
99 | return NF_DROP; /* or IPT_CONTINUE ?? */ | ||
100 | } | ||
101 | |||
102 | newmss = dst_mtu((*pskb)->dst) - sizeof(struct iphdr) - sizeof(struct tcphdr); | ||
103 | } else | 81 | } else |
104 | newmss = tcpmssinfo->mss; | 82 | newmss = tcpmssinfo->mss; |
105 | 83 | ||
106 | opt = (u_int8_t *)tcph; | 84 | opt = (u_int8_t *)tcph; |
107 | for (i = sizeof(struct tcphdr); i < tcph->doff*4; i += optlen(opt, i)){ | 85 | for (i = sizeof(struct tcphdr); i < tcph->doff*4; i += optlen(opt, i)) { |
108 | if ((opt[i] == TCPOPT_MSS) && | 86 | if (opt[i] == TCPOPT_MSS && tcph->doff*4 - i >= TCPOLEN_MSS && |
109 | ((tcph->doff*4 - i) >= TCPOLEN_MSS) && | 87 | opt[i+1] == TCPOLEN_MSS) { |
110 | (opt[i+1] == TCPOLEN_MSS)) { | ||
111 | u_int16_t oldmss; | 88 | u_int16_t oldmss; |
112 | 89 | ||
113 | oldmss = (opt[i+2] << 8) | opt[i+3]; | 90 | oldmss = (opt[i+2] << 8) | opt[i+3]; |
114 | 91 | ||
115 | if((tcpmssinfo->mss == IPT_TCPMSS_CLAMP_PMTU) && | 92 | if (tcpmssinfo->mss == IPT_TCPMSS_CLAMP_PMTU && |
116 | (oldmss <= newmss)) | 93 | oldmss <= newmss) |
117 | return IPT_CONTINUE; | 94 | return IPT_CONTINUE; |
118 | 95 | ||
119 | opt[i+2] = (newmss & 0xff00) >> 8; | 96 | opt[i+2] = (newmss & 0xff00) >> 8; |
120 | opt[i+3] = (newmss & 0x00ff); | 97 | opt[i+3] = (newmss & 0x00ff); |
121 | 98 | ||
122 | tcph->check = cheat_check(htons(oldmss)^0xFFFF, | 99 | tcph->check = nf_proto_csum_update(*pskb, |
123 | htons(newmss), | 100 | htons(oldmss)^0xFFFF, |
124 | tcph->check); | 101 | htons(newmss), |
125 | 102 | tcph->check, 0); | |
126 | DEBUGP(KERN_INFO "ipt_tcpmss_target: %u.%u.%u.%u:%hu" | 103 | return IPT_CONTINUE; |
127 | "->%u.%u.%u.%u:%hu changed TCP MSS option" | ||
128 | " (from %u to %u)\n", | ||
129 | NIPQUAD((*pskb)->nh.iph->saddr), | ||
130 | ntohs(tcph->source), | ||
131 | NIPQUAD((*pskb)->nh.iph->daddr), | ||
132 | ntohs(tcph->dest), | ||
133 | oldmss, newmss); | ||
134 | goto retmodified; | ||
135 | } | 104 | } |
136 | } | 105 | } |
137 | 106 | ||
@@ -143,13 +112,8 @@ ipt_tcpmss_target(struct sk_buff **pskb, | |||
143 | 112 | ||
144 | newskb = skb_copy_expand(*pskb, skb_headroom(*pskb), | 113 | newskb = skb_copy_expand(*pskb, skb_headroom(*pskb), |
145 | TCPOLEN_MSS, GFP_ATOMIC); | 114 | TCPOLEN_MSS, GFP_ATOMIC); |
146 | if (!newskb) { | 115 | if (!newskb) |
147 | if (net_ratelimit()) | ||
148 | printk(KERN_ERR "ipt_tcpmss_target:" | ||
149 | " unable to allocate larger skb\n"); | ||
150 | return NF_DROP; | 116 | return NF_DROP; |
151 | } | ||
152 | |||
153 | kfree_skb(*pskb); | 117 | kfree_skb(*pskb); |
154 | *pskb = newskb; | 118 | *pskb = newskb; |
155 | iph = (*pskb)->nh.iph; | 119 | iph = (*pskb)->nh.iph; |
@@ -161,36 +125,29 @@ ipt_tcpmss_target(struct sk_buff **pskb, | |||
161 | opt = (u_int8_t *)tcph + sizeof(struct tcphdr); | 125 | opt = (u_int8_t *)tcph + sizeof(struct tcphdr); |
162 | memmove(opt + TCPOLEN_MSS, opt, tcplen - sizeof(struct tcphdr)); | 126 | memmove(opt + TCPOLEN_MSS, opt, tcplen - sizeof(struct tcphdr)); |
163 | 127 | ||
164 | tcph->check = cheat_check(htons(tcplen) ^ 0xFFFF, | 128 | tcph->check = nf_proto_csum_update(*pskb, |
165 | htons(tcplen + TCPOLEN_MSS), tcph->check); | 129 | htons(tcplen) ^ 0xFFFF, |
166 | tcplen += TCPOLEN_MSS; | 130 | htons(tcplen + TCPOLEN_MSS), |
167 | 131 | tcph->check, 1); | |
168 | opt[0] = TCPOPT_MSS; | 132 | opt[0] = TCPOPT_MSS; |
169 | opt[1] = TCPOLEN_MSS; | 133 | opt[1] = TCPOLEN_MSS; |
170 | opt[2] = (newmss & 0xff00) >> 8; | 134 | opt[2] = (newmss & 0xff00) >> 8; |
171 | opt[3] = (newmss & 0x00ff); | 135 | opt[3] = (newmss & 0x00ff); |
172 | 136 | ||
173 | tcph->check = cheat_check(~0, *((u_int32_t *)opt), tcph->check); | 137 | tcph->check = nf_proto_csum_update(*pskb, ~0, *((u_int32_t *)opt), |
138 | tcph->check, 0); | ||
174 | 139 | ||
175 | oldval = ((u_int16_t *)tcph)[6]; | 140 | oldval = ((u_int16_t *)tcph)[6]; |
176 | tcph->doff += TCPOLEN_MSS/4; | 141 | tcph->doff += TCPOLEN_MSS/4; |
177 | tcph->check = cheat_check(oldval ^ 0xFFFF, | 142 | tcph->check = nf_proto_csum_update(*pskb, |
178 | ((u_int16_t *)tcph)[6], tcph->check); | 143 | oldval ^ 0xFFFF, |
144 | ((u_int16_t *)tcph)[6], | ||
145 | tcph->check, 0); | ||
179 | 146 | ||
180 | newtotlen = htons(ntohs(iph->tot_len) + TCPOLEN_MSS); | 147 | newtotlen = htons(ntohs(iph->tot_len) + TCPOLEN_MSS); |
181 | iph->check = cheat_check(iph->tot_len ^ 0xFFFF, | 148 | iph->check = nf_csum_update(iph->tot_len ^ 0xFFFF, |
182 | newtotlen, iph->check); | 149 | newtotlen, iph->check); |
183 | iph->tot_len = newtotlen; | 150 | iph->tot_len = newtotlen; |
184 | |||
185 | DEBUGP(KERN_INFO "ipt_tcpmss_target: %u.%u.%u.%u:%hu" | ||
186 | "->%u.%u.%u.%u:%hu added TCP MSS option (%u)\n", | ||
187 | NIPQUAD((*pskb)->nh.iph->saddr), | ||
188 | ntohs(tcph->source), | ||
189 | NIPQUAD((*pskb)->nh.iph->daddr), | ||
190 | ntohs(tcph->dest), | ||
191 | newmss); | ||
192 | |||
193 | retmodified: | ||
194 | return IPT_CONTINUE; | 151 | return IPT_CONTINUE; |
195 | } | 152 | } |
196 | 153 | ||
@@ -200,9 +157,9 @@ static inline int find_syn_match(const struct ipt_entry_match *m) | |||
200 | { | 157 | { |
201 | const struct ipt_tcp *tcpinfo = (const struct ipt_tcp *)m->data; | 158 | const struct ipt_tcp *tcpinfo = (const struct ipt_tcp *)m->data; |
202 | 159 | ||
203 | if (strcmp(m->u.kernel.match->name, "tcp") == 0 | 160 | if (strcmp(m->u.kernel.match->name, "tcp") == 0 && |
204 | && (tcpinfo->flg_cmp & TH_SYN) | 161 | tcpinfo->flg_cmp & TH_SYN && |
205 | && !(tcpinfo->invflags & IPT_TCP_INV_FLAGS)) | 162 | !(tcpinfo->invflags & IPT_TCP_INV_FLAGS)) |
206 | return 1; | 163 | return 1; |
207 | 164 | ||
208 | return 0; | 165 | return 0; |
@@ -214,17 +171,17 @@ ipt_tcpmss_checkentry(const char *tablename, | |||
214 | const void *e_void, | 171 | const void *e_void, |
215 | const struct xt_target *target, | 172 | const struct xt_target *target, |
216 | void *targinfo, | 173 | void *targinfo, |
217 | unsigned int targinfosize, | ||
218 | unsigned int hook_mask) | 174 | unsigned int hook_mask) |
219 | { | 175 | { |
220 | const struct ipt_tcpmss_info *tcpmssinfo = targinfo; | 176 | const struct ipt_tcpmss_info *tcpmssinfo = targinfo; |
221 | const struct ipt_entry *e = e_void; | 177 | const struct ipt_entry *e = e_void; |
222 | 178 | ||
223 | if((tcpmssinfo->mss == IPT_TCPMSS_CLAMP_PMTU) && | 179 | if (tcpmssinfo->mss == IPT_TCPMSS_CLAMP_PMTU && |
224 | ((hook_mask & ~((1 << NF_IP_FORWARD) | 180 | (hook_mask & ~((1 << NF_IP_FORWARD) | |
225 | | (1 << NF_IP_LOCAL_OUT) | 181 | (1 << NF_IP_LOCAL_OUT) | |
226 | | (1 << NF_IP_POST_ROUTING))) != 0)) { | 182 | (1 << NF_IP_POST_ROUTING))) != 0) { |
227 | printk("TCPMSS: path-MTU clamping only supported in FORWARD, OUTPUT and POSTROUTING hooks\n"); | 183 | printk("TCPMSS: path-MTU clamping only supported in " |
184 | "FORWARD, OUTPUT and POSTROUTING hooks\n"); | ||
228 | return 0; | 185 | return 0; |
229 | } | 186 | } |
230 | 187 | ||
diff --git a/net/ipv4/netfilter/ipt_TOS.c b/net/ipv4/netfilter/ipt_TOS.c index 1c7a5ca399b3..471a4c438b0a 100644 --- a/net/ipv4/netfilter/ipt_TOS.c +++ b/net/ipv4/netfilter/ipt_TOS.c | |||
@@ -26,27 +26,20 @@ target(struct sk_buff **pskb, | |||
26 | const struct net_device *out, | 26 | const struct net_device *out, |
27 | unsigned int hooknum, | 27 | unsigned int hooknum, |
28 | const struct xt_target *target, | 28 | const struct xt_target *target, |
29 | const void *targinfo, | 29 | const void *targinfo) |
30 | void *userinfo) | ||
31 | { | 30 | { |
32 | const struct ipt_tos_target_info *tosinfo = targinfo; | 31 | const struct ipt_tos_target_info *tosinfo = targinfo; |
32 | struct iphdr *iph = (*pskb)->nh.iph; | ||
33 | u_int16_t oldtos; | ||
33 | 34 | ||
34 | if (((*pskb)->nh.iph->tos & IPTOS_TOS_MASK) != tosinfo->tos) { | 35 | if ((iph->tos & IPTOS_TOS_MASK) != tosinfo->tos) { |
35 | u_int16_t diffs[2]; | ||
36 | |||
37 | if (!skb_make_writable(pskb, sizeof(struct iphdr))) | 36 | if (!skb_make_writable(pskb, sizeof(struct iphdr))) |
38 | return NF_DROP; | 37 | return NF_DROP; |
39 | 38 | iph = (*pskb)->nh.iph; | |
40 | diffs[0] = htons((*pskb)->nh.iph->tos) ^ 0xFFFF; | 39 | oldtos = iph->tos; |
41 | (*pskb)->nh.iph->tos | 40 | iph->tos = (iph->tos & IPTOS_PREC_MASK) | tosinfo->tos; |
42 | = ((*pskb)->nh.iph->tos & IPTOS_PREC_MASK) | 41 | iph->check = nf_csum_update(oldtos ^ 0xFFFF, iph->tos, |
43 | | tosinfo->tos; | 42 | iph->check); |
44 | diffs[1] = htons((*pskb)->nh.iph->tos); | ||
45 | (*pskb)->nh.iph->check | ||
46 | = csum_fold(csum_partial((char *)diffs, | ||
47 | sizeof(diffs), | ||
48 | (*pskb)->nh.iph->check | ||
49 | ^0xFFFF)); | ||
50 | } | 43 | } |
51 | return IPT_CONTINUE; | 44 | return IPT_CONTINUE; |
52 | } | 45 | } |
@@ -56,7 +49,6 @@ checkentry(const char *tablename, | |||
56 | const void *e_void, | 49 | const void *e_void, |
57 | const struct xt_target *target, | 50 | const struct xt_target *target, |
58 | void *targinfo, | 51 | void *targinfo, |
59 | unsigned int targinfosize, | ||
60 | unsigned int hook_mask) | 52 | unsigned int hook_mask) |
61 | { | 53 | { |
62 | const u_int8_t tos = ((struct ipt_tos_target_info *)targinfo)->tos; | 54 | const u_int8_t tos = ((struct ipt_tos_target_info *)targinfo)->tos; |
diff --git a/net/ipv4/netfilter/ipt_TTL.c b/net/ipv4/netfilter/ipt_TTL.c index f48892ae0be5..96e79cc6d0f2 100644 --- a/net/ipv4/netfilter/ipt_TTL.c +++ b/net/ipv4/netfilter/ipt_TTL.c | |||
@@ -23,11 +23,10 @@ static unsigned int | |||
23 | ipt_ttl_target(struct sk_buff **pskb, | 23 | ipt_ttl_target(struct sk_buff **pskb, |
24 | const struct net_device *in, const struct net_device *out, | 24 | const struct net_device *in, const struct net_device *out, |
25 | unsigned int hooknum, const struct xt_target *target, | 25 | unsigned int hooknum, const struct xt_target *target, |
26 | const void *targinfo, void *userinfo) | 26 | const void *targinfo) |
27 | { | 27 | { |
28 | struct iphdr *iph; | 28 | struct iphdr *iph; |
29 | const struct ipt_TTL_info *info = targinfo; | 29 | const struct ipt_TTL_info *info = targinfo; |
30 | u_int16_t diffs[2]; | ||
31 | int new_ttl; | 30 | int new_ttl; |
32 | 31 | ||
33 | if (!skb_make_writable(pskb, (*pskb)->len)) | 32 | if (!skb_make_writable(pskb, (*pskb)->len)) |
@@ -55,12 +54,10 @@ ipt_ttl_target(struct sk_buff **pskb, | |||
55 | } | 54 | } |
56 | 55 | ||
57 | if (new_ttl != iph->ttl) { | 56 | if (new_ttl != iph->ttl) { |
58 | diffs[0] = htons(((unsigned)iph->ttl) << 8) ^ 0xFFFF; | 57 | iph->check = nf_csum_update(ntohs((iph->ttl << 8)) ^ 0xFFFF, |
58 | ntohs(new_ttl << 8), | ||
59 | iph->check); | ||
59 | iph->ttl = new_ttl; | 60 | iph->ttl = new_ttl; |
60 | diffs[1] = htons(((unsigned)iph->ttl) << 8); | ||
61 | iph->check = csum_fold(csum_partial((char *)diffs, | ||
62 | sizeof(diffs), | ||
63 | iph->check^0xFFFF)); | ||
64 | } | 61 | } |
65 | 62 | ||
66 | return IPT_CONTINUE; | 63 | return IPT_CONTINUE; |
@@ -70,7 +67,6 @@ static int ipt_ttl_checkentry(const char *tablename, | |||
70 | const void *e, | 67 | const void *e, |
71 | const struct xt_target *target, | 68 | const struct xt_target *target, |
72 | void *targinfo, | 69 | void *targinfo, |
73 | unsigned int targinfosize, | ||
74 | unsigned int hook_mask) | 70 | unsigned int hook_mask) |
75 | { | 71 | { |
76 | struct ipt_TTL_info *info = targinfo; | 72 | struct ipt_TTL_info *info = targinfo; |
diff --git a/net/ipv4/netfilter/ipt_ULOG.c b/net/ipv4/netfilter/ipt_ULOG.c index d46fd677fa11..2b104ea54f48 100644 --- a/net/ipv4/netfilter/ipt_ULOG.c +++ b/net/ipv4/netfilter/ipt_ULOG.c | |||
@@ -308,7 +308,7 @@ static unsigned int ipt_ulog_target(struct sk_buff **pskb, | |||
308 | const struct net_device *out, | 308 | const struct net_device *out, |
309 | unsigned int hooknum, | 309 | unsigned int hooknum, |
310 | const struct xt_target *target, | 310 | const struct xt_target *target, |
311 | const void *targinfo, void *userinfo) | 311 | const void *targinfo) |
312 | { | 312 | { |
313 | struct ipt_ulog_info *loginfo = (struct ipt_ulog_info *) targinfo; | 313 | struct ipt_ulog_info *loginfo = (struct ipt_ulog_info *) targinfo; |
314 | 314 | ||
@@ -346,7 +346,6 @@ static int ipt_ulog_checkentry(const char *tablename, | |||
346 | const void *e, | 346 | const void *e, |
347 | const struct xt_target *target, | 347 | const struct xt_target *target, |
348 | void *targinfo, | 348 | void *targinfo, |
349 | unsigned int targinfosize, | ||
350 | unsigned int hookmask) | 349 | unsigned int hookmask) |
351 | { | 350 | { |
352 | struct ipt_ulog_info *loginfo = (struct ipt_ulog_info *) targinfo; | 351 | struct ipt_ulog_info *loginfo = (struct ipt_ulog_info *) targinfo; |
diff --git a/net/ipv4/netfilter/ipt_ah.c b/net/ipv4/netfilter/ipt_ah.c index 2927135873d7..1798f86bc534 100644 --- a/net/ipv4/netfilter/ipt_ah.c +++ b/net/ipv4/netfilter/ipt_ah.c | |||
@@ -74,7 +74,6 @@ checkentry(const char *tablename, | |||
74 | const void *ip_void, | 74 | const void *ip_void, |
75 | const struct xt_match *match, | 75 | const struct xt_match *match, |
76 | void *matchinfo, | 76 | void *matchinfo, |
77 | unsigned int matchinfosize, | ||
78 | unsigned int hook_mask) | 77 | unsigned int hook_mask) |
79 | { | 78 | { |
80 | const struct ipt_ah *ahinfo = matchinfo; | 79 | const struct ipt_ah *ahinfo = matchinfo; |
diff --git a/net/ipv4/netfilter/ipt_dscp.c b/net/ipv4/netfilter/ipt_dscp.c deleted file mode 100644 index 47177591aeb6..000000000000 --- a/net/ipv4/netfilter/ipt_dscp.c +++ /dev/null | |||
@@ -1,54 +0,0 @@ | |||
1 | /* IP tables module for matching the value of the IPv4 DSCP field | ||
2 | * | ||
3 | * ipt_dscp.c,v 1.3 2002/08/05 19:00:21 laforge Exp | ||
4 | * | ||
5 | * (C) 2002 by Harald Welte <laforge@netfilter.org> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License version 2 as | ||
9 | * published by the Free Software Foundation. | ||
10 | */ | ||
11 | |||
12 | #include <linux/module.h> | ||
13 | #include <linux/skbuff.h> | ||
14 | |||
15 | #include <linux/netfilter_ipv4/ipt_dscp.h> | ||
16 | #include <linux/netfilter_ipv4/ip_tables.h> | ||
17 | |||
18 | MODULE_AUTHOR("Harald Welte <laforge@netfilter.org>"); | ||
19 | MODULE_DESCRIPTION("iptables DSCP matching module"); | ||
20 | MODULE_LICENSE("GPL"); | ||
21 | |||
22 | static int match(const struct sk_buff *skb, | ||
23 | const struct net_device *in, const struct net_device *out, | ||
24 | const struct xt_match *match, const void *matchinfo, | ||
25 | int offset, unsigned int protoff, int *hotdrop) | ||
26 | { | ||
27 | const struct ipt_dscp_info *info = matchinfo; | ||
28 | const struct iphdr *iph = skb->nh.iph; | ||
29 | |||
30 | u_int8_t sh_dscp = ((info->dscp << IPT_DSCP_SHIFT) & IPT_DSCP_MASK); | ||
31 | |||
32 | return ((iph->tos&IPT_DSCP_MASK) == sh_dscp) ^ info->invert; | ||
33 | } | ||
34 | |||
35 | static struct ipt_match dscp_match = { | ||
36 | .name = "dscp", | ||
37 | .match = match, | ||
38 | .matchsize = sizeof(struct ipt_dscp_info), | ||
39 | .me = THIS_MODULE, | ||
40 | }; | ||
41 | |||
42 | static int __init ipt_dscp_init(void) | ||
43 | { | ||
44 | return ipt_register_match(&dscp_match); | ||
45 | } | ||
46 | |||
47 | static void __exit ipt_dscp_fini(void) | ||
48 | { | ||
49 | ipt_unregister_match(&dscp_match); | ||
50 | |||
51 | } | ||
52 | |||
53 | module_init(ipt_dscp_init); | ||
54 | module_exit(ipt_dscp_fini); | ||
diff --git a/net/ipv4/netfilter/ipt_ecn.c b/net/ipv4/netfilter/ipt_ecn.c index b28250414933..dafbdec0efc0 100644 --- a/net/ipv4/netfilter/ipt_ecn.c +++ b/net/ipv4/netfilter/ipt_ecn.c | |||
@@ -88,8 +88,7 @@ static int match(const struct sk_buff *skb, | |||
88 | 88 | ||
89 | static int checkentry(const char *tablename, const void *ip_void, | 89 | static int checkentry(const char *tablename, const void *ip_void, |
90 | const struct xt_match *match, | 90 | const struct xt_match *match, |
91 | void *matchinfo, unsigned int matchsize, | 91 | void *matchinfo, unsigned int hook_mask) |
92 | unsigned int hook_mask) | ||
93 | { | 92 | { |
94 | const struct ipt_ecn_info *info = matchinfo; | 93 | const struct ipt_ecn_info *info = matchinfo; |
95 | const struct ipt_ip *ip = ip_void; | 94 | const struct ipt_ip *ip = ip_void; |
diff --git a/net/ipv4/netfilter/ipt_hashlimit.c b/net/ipv4/netfilter/ipt_hashlimit.c index 3bd2368e1fc9..4f73a61aa3dd 100644 --- a/net/ipv4/netfilter/ipt_hashlimit.c +++ b/net/ipv4/netfilter/ipt_hashlimit.c | |||
@@ -478,7 +478,6 @@ hashlimit_checkentry(const char *tablename, | |||
478 | const void *inf, | 478 | const void *inf, |
479 | const struct xt_match *match, | 479 | const struct xt_match *match, |
480 | void *matchinfo, | 480 | void *matchinfo, |
481 | unsigned int matchsize, | ||
482 | unsigned int hook_mask) | 481 | unsigned int hook_mask) |
483 | { | 482 | { |
484 | struct ipt_hashlimit_info *r = matchinfo; | 483 | struct ipt_hashlimit_info *r = matchinfo; |
@@ -529,18 +528,46 @@ hashlimit_checkentry(const char *tablename, | |||
529 | } | 528 | } |
530 | 529 | ||
531 | static void | 530 | static void |
532 | hashlimit_destroy(const struct xt_match *match, void *matchinfo, | 531 | hashlimit_destroy(const struct xt_match *match, void *matchinfo) |
533 | unsigned int matchsize) | ||
534 | { | 532 | { |
535 | struct ipt_hashlimit_info *r = matchinfo; | 533 | struct ipt_hashlimit_info *r = matchinfo; |
536 | 534 | ||
537 | htable_put(r->hinfo); | 535 | htable_put(r->hinfo); |
538 | } | 536 | } |
539 | 537 | ||
538 | #ifdef CONFIG_COMPAT | ||
539 | struct compat_ipt_hashlimit_info { | ||
540 | char name[IFNAMSIZ]; | ||
541 | struct hashlimit_cfg cfg; | ||
542 | compat_uptr_t hinfo; | ||
543 | compat_uptr_t master; | ||
544 | }; | ||
545 | |||
546 | static void compat_from_user(void *dst, void *src) | ||
547 | { | ||
548 | int off = offsetof(struct compat_ipt_hashlimit_info, hinfo); | ||
549 | |||
550 | memcpy(dst, src, off); | ||
551 | memset(dst + off, 0, sizeof(struct compat_ipt_hashlimit_info) - off); | ||
552 | } | ||
553 | |||
554 | static int compat_to_user(void __user *dst, void *src) | ||
555 | { | ||
556 | int off = offsetof(struct compat_ipt_hashlimit_info, hinfo); | ||
557 | |||
558 | return copy_to_user(dst, src, off) ? -EFAULT : 0; | ||
559 | } | ||
560 | #endif | ||
561 | |||
540 | static struct ipt_match ipt_hashlimit = { | 562 | static struct ipt_match ipt_hashlimit = { |
541 | .name = "hashlimit", | 563 | .name = "hashlimit", |
542 | .match = hashlimit_match, | 564 | .match = hashlimit_match, |
543 | .matchsize = sizeof(struct ipt_hashlimit_info), | 565 | .matchsize = sizeof(struct ipt_hashlimit_info), |
566 | #ifdef CONFIG_COMPAT | ||
567 | .compatsize = sizeof(struct compat_ipt_hashlimit_info), | ||
568 | .compat_from_user = compat_from_user, | ||
569 | .compat_to_user = compat_to_user, | ||
570 | #endif | ||
544 | .checkentry = hashlimit_checkentry, | 571 | .checkentry = hashlimit_checkentry, |
545 | .destroy = hashlimit_destroy, | 572 | .destroy = hashlimit_destroy, |
546 | .me = THIS_MODULE | 573 | .me = THIS_MODULE |
diff --git a/net/ipv4/netfilter/ipt_owner.c b/net/ipv4/netfilter/ipt_owner.c index 5ac6ac023b5e..78c336f12a9e 100644 --- a/net/ipv4/netfilter/ipt_owner.c +++ b/net/ipv4/netfilter/ipt_owner.c | |||
@@ -56,7 +56,6 @@ checkentry(const char *tablename, | |||
56 | const void *ip, | 56 | const void *ip, |
57 | const struct xt_match *match, | 57 | const struct xt_match *match, |
58 | void *matchinfo, | 58 | void *matchinfo, |
59 | unsigned int matchsize, | ||
60 | unsigned int hook_mask) | 59 | unsigned int hook_mask) |
61 | { | 60 | { |
62 | const struct ipt_owner_info *info = matchinfo; | 61 | const struct ipt_owner_info *info = matchinfo; |
diff --git a/net/ipv4/netfilter/ipt_recent.c b/net/ipv4/netfilter/ipt_recent.c index 61a2139f9cfd..32ae8d7ac506 100644 --- a/net/ipv4/netfilter/ipt_recent.c +++ b/net/ipv4/netfilter/ipt_recent.c | |||
@@ -35,14 +35,20 @@ static unsigned int ip_list_tot = 100; | |||
35 | static unsigned int ip_pkt_list_tot = 20; | 35 | static unsigned int ip_pkt_list_tot = 20; |
36 | static unsigned int ip_list_hash_size = 0; | 36 | static unsigned int ip_list_hash_size = 0; |
37 | static unsigned int ip_list_perms = 0644; | 37 | static unsigned int ip_list_perms = 0644; |
38 | static unsigned int ip_list_uid = 0; | ||
39 | static unsigned int ip_list_gid = 0; | ||
38 | module_param(ip_list_tot, uint, 0400); | 40 | module_param(ip_list_tot, uint, 0400); |
39 | module_param(ip_pkt_list_tot, uint, 0400); | 41 | module_param(ip_pkt_list_tot, uint, 0400); |
40 | module_param(ip_list_hash_size, uint, 0400); | 42 | module_param(ip_list_hash_size, uint, 0400); |
41 | module_param(ip_list_perms, uint, 0400); | 43 | module_param(ip_list_perms, uint, 0400); |
44 | module_param(ip_list_uid, uint, 0400); | ||
45 | module_param(ip_list_gid, uint, 0400); | ||
42 | MODULE_PARM_DESC(ip_list_tot, "number of IPs to remember per list"); | 46 | MODULE_PARM_DESC(ip_list_tot, "number of IPs to remember per list"); |
43 | MODULE_PARM_DESC(ip_pkt_list_tot, "number of packets per IP to remember (max. 255)"); | 47 | MODULE_PARM_DESC(ip_pkt_list_tot, "number of packets per IP to remember (max. 255)"); |
44 | MODULE_PARM_DESC(ip_list_hash_size, "size of hash table used to look up IPs"); | 48 | MODULE_PARM_DESC(ip_list_hash_size, "size of hash table used to look up IPs"); |
45 | MODULE_PARM_DESC(ip_list_perms, "permissions on /proc/net/ipt_recent/* files"); | 49 | MODULE_PARM_DESC(ip_list_perms, "permissions on /proc/net/ipt_recent/* files"); |
50 | MODULE_PARM_DESC(ip_list_uid,"owner of /proc/net/ipt_recent/* files"); | ||
51 | MODULE_PARM_DESC(ip_list_gid,"owning group of /proc/net/ipt_recent/* files"); | ||
46 | 52 | ||
47 | 53 | ||
48 | struct recent_entry { | 54 | struct recent_entry { |
@@ -232,7 +238,7 @@ out: | |||
232 | static int | 238 | static int |
233 | ipt_recent_checkentry(const char *tablename, const void *ip, | 239 | ipt_recent_checkentry(const char *tablename, const void *ip, |
234 | const struct xt_match *match, void *matchinfo, | 240 | const struct xt_match *match, void *matchinfo, |
235 | unsigned int matchsize, unsigned int hook_mask) | 241 | unsigned int hook_mask) |
236 | { | 242 | { |
237 | const struct ipt_recent_info *info = matchinfo; | 243 | const struct ipt_recent_info *info = matchinfo; |
238 | struct recent_table *t; | 244 | struct recent_table *t; |
@@ -274,6 +280,8 @@ ipt_recent_checkentry(const char *tablename, const void *ip, | |||
274 | goto out; | 280 | goto out; |
275 | } | 281 | } |
276 | t->proc->proc_fops = &recent_fops; | 282 | t->proc->proc_fops = &recent_fops; |
283 | t->proc->uid = ip_list_uid; | ||
284 | t->proc->gid = ip_list_gid; | ||
277 | t->proc->data = t; | 285 | t->proc->data = t; |
278 | #endif | 286 | #endif |
279 | spin_lock_bh(&recent_lock); | 287 | spin_lock_bh(&recent_lock); |
@@ -286,8 +294,7 @@ out: | |||
286 | } | 294 | } |
287 | 295 | ||
288 | static void | 296 | static void |
289 | ipt_recent_destroy(const struct xt_match *match, void *matchinfo, | 297 | ipt_recent_destroy(const struct xt_match *match, void *matchinfo) |
290 | unsigned int matchsize) | ||
291 | { | 298 | { |
292 | const struct ipt_recent_info *info = matchinfo; | 299 | const struct ipt_recent_info *info = matchinfo; |
293 | struct recent_table *t; | 300 | struct recent_table *t; |
diff --git a/net/ipv4/netfilter/iptable_filter.c b/net/ipv4/netfilter/iptable_filter.c index 7f417484bfbf..e2e7dd8d7903 100644 --- a/net/ipv4/netfilter/iptable_filter.c +++ b/net/ipv4/netfilter/iptable_filter.c | |||
@@ -90,7 +90,7 @@ ipt_hook(unsigned int hook, | |||
90 | const struct net_device *out, | 90 | const struct net_device *out, |
91 | int (*okfn)(struct sk_buff *)) | 91 | int (*okfn)(struct sk_buff *)) |
92 | { | 92 | { |
93 | return ipt_do_table(pskb, hook, in, out, &packet_filter, NULL); | 93 | return ipt_do_table(pskb, hook, in, out, &packet_filter); |
94 | } | 94 | } |
95 | 95 | ||
96 | static unsigned int | 96 | static unsigned int |
@@ -108,7 +108,7 @@ ipt_local_out_hook(unsigned int hook, | |||
108 | return NF_ACCEPT; | 108 | return NF_ACCEPT; |
109 | } | 109 | } |
110 | 110 | ||
111 | return ipt_do_table(pskb, hook, in, out, &packet_filter, NULL); | 111 | return ipt_do_table(pskb, hook, in, out, &packet_filter); |
112 | } | 112 | } |
113 | 113 | ||
114 | static struct nf_hook_ops ipt_ops[] = { | 114 | static struct nf_hook_ops ipt_ops[] = { |
diff --git a/net/ipv4/netfilter/iptable_mangle.c b/net/ipv4/netfilter/iptable_mangle.c index 4e7998beda63..79336cb42527 100644 --- a/net/ipv4/netfilter/iptable_mangle.c +++ b/net/ipv4/netfilter/iptable_mangle.c | |||
@@ -119,7 +119,7 @@ ipt_route_hook(unsigned int hook, | |||
119 | const struct net_device *out, | 119 | const struct net_device *out, |
120 | int (*okfn)(struct sk_buff *)) | 120 | int (*okfn)(struct sk_buff *)) |
121 | { | 121 | { |
122 | return ipt_do_table(pskb, hook, in, out, &packet_mangler, NULL); | 122 | return ipt_do_table(pskb, hook, in, out, &packet_mangler); |
123 | } | 123 | } |
124 | 124 | ||
125 | static unsigned int | 125 | static unsigned int |
@@ -148,7 +148,7 @@ ipt_local_hook(unsigned int hook, | |||
148 | daddr = (*pskb)->nh.iph->daddr; | 148 | daddr = (*pskb)->nh.iph->daddr; |
149 | tos = (*pskb)->nh.iph->tos; | 149 | tos = (*pskb)->nh.iph->tos; |
150 | 150 | ||
151 | ret = ipt_do_table(pskb, hook, in, out, &packet_mangler, NULL); | 151 | ret = ipt_do_table(pskb, hook, in, out, &packet_mangler); |
152 | /* Reroute for ANY change. */ | 152 | /* Reroute for ANY change. */ |
153 | if (ret != NF_DROP && ret != NF_STOLEN && ret != NF_QUEUE | 153 | if (ret != NF_DROP && ret != NF_STOLEN && ret != NF_QUEUE |
154 | && ((*pskb)->nh.iph->saddr != saddr | 154 | && ((*pskb)->nh.iph->saddr != saddr |
diff --git a/net/ipv4/netfilter/iptable_raw.c b/net/ipv4/netfilter/iptable_raw.c index 7912cce1e1b8..bcbeb4aeacd9 100644 --- a/net/ipv4/netfilter/iptable_raw.c +++ b/net/ipv4/netfilter/iptable_raw.c | |||
@@ -95,7 +95,7 @@ ipt_hook(unsigned int hook, | |||
95 | const struct net_device *out, | 95 | const struct net_device *out, |
96 | int (*okfn)(struct sk_buff *)) | 96 | int (*okfn)(struct sk_buff *)) |
97 | { | 97 | { |
98 | return ipt_do_table(pskb, hook, in, out, &packet_raw, NULL); | 98 | return ipt_do_table(pskb, hook, in, out, &packet_raw); |
99 | } | 99 | } |
100 | 100 | ||
101 | /* 'raw' is the very first table. */ | 101 | /* 'raw' is the very first table. */ |
diff --git a/net/ipv4/netfilter/nf_conntrack_proto_icmp.c b/net/ipv4/netfilter/nf_conntrack_proto_icmp.c index 663a73ee3f2f..790f00d500c3 100644 --- a/net/ipv4/netfilter/nf_conntrack_proto_icmp.c +++ b/net/ipv4/netfilter/nf_conntrack_proto_icmp.c | |||
@@ -25,7 +25,7 @@ | |||
25 | #include <net/netfilter/nf_conntrack_protocol.h> | 25 | #include <net/netfilter/nf_conntrack_protocol.h> |
26 | #include <net/netfilter/nf_conntrack_core.h> | 26 | #include <net/netfilter/nf_conntrack_core.h> |
27 | 27 | ||
28 | unsigned long nf_ct_icmp_timeout = 30*HZ; | 28 | unsigned long nf_ct_icmp_timeout __read_mostly = 30*HZ; |
29 | 29 | ||
30 | #if 0 | 30 | #if 0 |
31 | #define DEBUGP printk | 31 | #define DEBUGP printk |
diff --git a/net/ipv4/proc.c b/net/ipv4/proc.c index d61e2a9d394d..9c6cbe3d9fb8 100644 --- a/net/ipv4/proc.c +++ b/net/ipv4/proc.c | |||
@@ -173,6 +173,8 @@ static const struct snmp_mib snmp4_udp_list[] = { | |||
173 | SNMP_MIB_ITEM("NoPorts", UDP_MIB_NOPORTS), | 173 | SNMP_MIB_ITEM("NoPorts", UDP_MIB_NOPORTS), |
174 | SNMP_MIB_ITEM("InErrors", UDP_MIB_INERRORS), | 174 | SNMP_MIB_ITEM("InErrors", UDP_MIB_INERRORS), |
175 | SNMP_MIB_ITEM("OutDatagrams", UDP_MIB_OUTDATAGRAMS), | 175 | SNMP_MIB_ITEM("OutDatagrams", UDP_MIB_OUTDATAGRAMS), |
176 | SNMP_MIB_ITEM("RcvbufErrors", UDP_MIB_RCVBUFERRORS), | ||
177 | SNMP_MIB_ITEM("SndbufErrors", UDP_MIB_SNDBUFERRORS), | ||
176 | SNMP_MIB_SENTINEL | 178 | SNMP_MIB_SENTINEL |
177 | }; | 179 | }; |
178 | 180 | ||
diff --git a/net/ipv4/raw.c b/net/ipv4/raw.c index 62b2762a2420..0e935b4c8741 100644 --- a/net/ipv4/raw.c +++ b/net/ipv4/raw.c | |||
@@ -38,8 +38,7 @@ | |||
38 | * as published by the Free Software Foundation; either version | 38 | * as published by the Free Software Foundation; either version |
39 | * 2 of the License, or (at your option) any later version. | 39 | * 2 of the License, or (at your option) any later version. |
40 | */ | 40 | */ |
41 | 41 | ||
42 | #include <linux/config.h> | ||
43 | #include <linux/types.h> | 42 | #include <linux/types.h> |
44 | #include <asm/atomic.h> | 43 | #include <asm/atomic.h> |
45 | #include <asm/byteorder.h> | 44 | #include <asm/byteorder.h> |
@@ -484,6 +483,7 @@ static int raw_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, | |||
484 | if (!inet->hdrincl) | 483 | if (!inet->hdrincl) |
485 | raw_probe_proto_opt(&fl, msg); | 484 | raw_probe_proto_opt(&fl, msg); |
486 | 485 | ||
486 | security_sk_classify_flow(sk, &fl); | ||
487 | err = ip_route_output_flow(&rt, &fl, sk, !(msg->msg_flags&MSG_DONTWAIT)); | 487 | err = ip_route_output_flow(&rt, &fl, sk, !(msg->msg_flags&MSG_DONTWAIT)); |
488 | } | 488 | } |
489 | if (err) | 489 | if (err) |
diff --git a/net/ipv4/route.c b/net/ipv4/route.c index b873cbcdd0b8..20ffe8e88c0f 100644 --- a/net/ipv4/route.c +++ b/net/ipv4/route.c | |||
@@ -2639,51 +2639,54 @@ static int rt_fill_info(struct sk_buff *skb, u32 pid, u32 seq, int event, | |||
2639 | { | 2639 | { |
2640 | struct rtable *rt = (struct rtable*)skb->dst; | 2640 | struct rtable *rt = (struct rtable*)skb->dst; |
2641 | struct rtmsg *r; | 2641 | struct rtmsg *r; |
2642 | struct nlmsghdr *nlh; | 2642 | struct nlmsghdr *nlh; |
2643 | unsigned char *b = skb->tail; | ||
2644 | struct rta_cacheinfo ci; | 2643 | struct rta_cacheinfo ci; |
2645 | #ifdef CONFIG_IP_MROUTE | 2644 | |
2646 | struct rtattr *eptr; | 2645 | nlh = nlmsg_put(skb, pid, seq, event, sizeof(*r), flags); |
2647 | #endif | 2646 | if (nlh == NULL) |
2648 | nlh = NLMSG_NEW(skb, pid, seq, event, sizeof(*r), flags); | 2647 | return -ENOBUFS; |
2649 | r = NLMSG_DATA(nlh); | 2648 | |
2649 | r = nlmsg_data(nlh); | ||
2650 | r->rtm_family = AF_INET; | 2650 | r->rtm_family = AF_INET; |
2651 | r->rtm_dst_len = 32; | 2651 | r->rtm_dst_len = 32; |
2652 | r->rtm_src_len = 0; | 2652 | r->rtm_src_len = 0; |
2653 | r->rtm_tos = rt->fl.fl4_tos; | 2653 | r->rtm_tos = rt->fl.fl4_tos; |
2654 | r->rtm_table = RT_TABLE_MAIN; | 2654 | r->rtm_table = RT_TABLE_MAIN; |
2655 | NLA_PUT_U32(skb, RTA_TABLE, RT_TABLE_MAIN); | ||
2655 | r->rtm_type = rt->rt_type; | 2656 | r->rtm_type = rt->rt_type; |
2656 | r->rtm_scope = RT_SCOPE_UNIVERSE; | 2657 | r->rtm_scope = RT_SCOPE_UNIVERSE; |
2657 | r->rtm_protocol = RTPROT_UNSPEC; | 2658 | r->rtm_protocol = RTPROT_UNSPEC; |
2658 | r->rtm_flags = (rt->rt_flags & ~0xFFFF) | RTM_F_CLONED; | 2659 | r->rtm_flags = (rt->rt_flags & ~0xFFFF) | RTM_F_CLONED; |
2659 | if (rt->rt_flags & RTCF_NOTIFY) | 2660 | if (rt->rt_flags & RTCF_NOTIFY) |
2660 | r->rtm_flags |= RTM_F_NOTIFY; | 2661 | r->rtm_flags |= RTM_F_NOTIFY; |
2661 | RTA_PUT(skb, RTA_DST, 4, &rt->rt_dst); | 2662 | |
2663 | NLA_PUT_U32(skb, RTA_DST, rt->rt_dst); | ||
2664 | |||
2662 | if (rt->fl.fl4_src) { | 2665 | if (rt->fl.fl4_src) { |
2663 | r->rtm_src_len = 32; | 2666 | r->rtm_src_len = 32; |
2664 | RTA_PUT(skb, RTA_SRC, 4, &rt->fl.fl4_src); | 2667 | NLA_PUT_U32(skb, RTA_SRC, rt->fl.fl4_src); |
2665 | } | 2668 | } |
2666 | if (rt->u.dst.dev) | 2669 | if (rt->u.dst.dev) |
2667 | RTA_PUT(skb, RTA_OIF, sizeof(int), &rt->u.dst.dev->ifindex); | 2670 | NLA_PUT_U32(skb, RTA_OIF, rt->u.dst.dev->ifindex); |
2668 | #ifdef CONFIG_NET_CLS_ROUTE | 2671 | #ifdef CONFIG_NET_CLS_ROUTE |
2669 | if (rt->u.dst.tclassid) | 2672 | if (rt->u.dst.tclassid) |
2670 | RTA_PUT(skb, RTA_FLOW, 4, &rt->u.dst.tclassid); | 2673 | NLA_PUT_U32(skb, RTA_FLOW, rt->u.dst.tclassid); |
2671 | #endif | 2674 | #endif |
2672 | #ifdef CONFIG_IP_ROUTE_MULTIPATH_CACHED | 2675 | #ifdef CONFIG_IP_ROUTE_MULTIPATH_CACHED |
2673 | if (rt->rt_multipath_alg != IP_MP_ALG_NONE) { | 2676 | if (rt->rt_multipath_alg != IP_MP_ALG_NONE) |
2674 | __u32 alg = rt->rt_multipath_alg; | 2677 | NLA_PUT_U32(skb, RTA_MP_ALGO, rt->rt_multipath_alg); |
2675 | |||
2676 | RTA_PUT(skb, RTA_MP_ALGO, 4, &alg); | ||
2677 | } | ||
2678 | #endif | 2678 | #endif |
2679 | if (rt->fl.iif) | 2679 | if (rt->fl.iif) |
2680 | RTA_PUT(skb, RTA_PREFSRC, 4, &rt->rt_spec_dst); | 2680 | NLA_PUT_U32(skb, RTA_PREFSRC, rt->rt_spec_dst); |
2681 | else if (rt->rt_src != rt->fl.fl4_src) | 2681 | else if (rt->rt_src != rt->fl.fl4_src) |
2682 | RTA_PUT(skb, RTA_PREFSRC, 4, &rt->rt_src); | 2682 | NLA_PUT_U32(skb, RTA_PREFSRC, rt->rt_src); |
2683 | |||
2683 | if (rt->rt_dst != rt->rt_gateway) | 2684 | if (rt->rt_dst != rt->rt_gateway) |
2684 | RTA_PUT(skb, RTA_GATEWAY, 4, &rt->rt_gateway); | 2685 | NLA_PUT_U32(skb, RTA_GATEWAY, rt->rt_gateway); |
2686 | |||
2685 | if (rtnetlink_put_metrics(skb, rt->u.dst.metrics) < 0) | 2687 | if (rtnetlink_put_metrics(skb, rt->u.dst.metrics) < 0) |
2686 | goto rtattr_failure; | 2688 | goto nla_put_failure; |
2689 | |||
2687 | ci.rta_lastuse = jiffies_to_clock_t(jiffies - rt->u.dst.lastuse); | 2690 | ci.rta_lastuse = jiffies_to_clock_t(jiffies - rt->u.dst.lastuse); |
2688 | ci.rta_used = rt->u.dst.__use; | 2691 | ci.rta_used = rt->u.dst.__use; |
2689 | ci.rta_clntref = atomic_read(&rt->u.dst.__refcnt); | 2692 | ci.rta_clntref = atomic_read(&rt->u.dst.__refcnt); |
@@ -2700,10 +2703,7 @@ static int rt_fill_info(struct sk_buff *skb, u32 pid, u32 seq, int event, | |||
2700 | ci.rta_tsage = xtime.tv_sec - rt->peer->tcp_ts_stamp; | 2703 | ci.rta_tsage = xtime.tv_sec - rt->peer->tcp_ts_stamp; |
2701 | } | 2704 | } |
2702 | } | 2705 | } |
2703 | #ifdef CONFIG_IP_MROUTE | 2706 | |
2704 | eptr = (struct rtattr*)skb->tail; | ||
2705 | #endif | ||
2706 | RTA_PUT(skb, RTA_CACHEINFO, sizeof(ci), &ci); | ||
2707 | if (rt->fl.iif) { | 2707 | if (rt->fl.iif) { |
2708 | #ifdef CONFIG_IP_MROUTE | 2708 | #ifdef CONFIG_IP_MROUTE |
2709 | u32 dst = rt->rt_dst; | 2709 | u32 dst = rt->rt_dst; |
@@ -2715,41 +2715,46 @@ static int rt_fill_info(struct sk_buff *skb, u32 pid, u32 seq, int event, | |||
2715 | if (!nowait) { | 2715 | if (!nowait) { |
2716 | if (err == 0) | 2716 | if (err == 0) |
2717 | return 0; | 2717 | return 0; |
2718 | goto nlmsg_failure; | 2718 | goto nla_put_failure; |
2719 | } else { | 2719 | } else { |
2720 | if (err == -EMSGSIZE) | 2720 | if (err == -EMSGSIZE) |
2721 | goto nlmsg_failure; | 2721 | goto nla_put_failure; |
2722 | ((struct rta_cacheinfo*)RTA_DATA(eptr))->rta_error = err; | 2722 | ci.rta_error = err; |
2723 | } | 2723 | } |
2724 | } | 2724 | } |
2725 | } else | 2725 | } else |
2726 | #endif | 2726 | #endif |
2727 | RTA_PUT(skb, RTA_IIF, sizeof(int), &rt->fl.iif); | 2727 | NLA_PUT_U32(skb, RTA_IIF, rt->fl.iif); |
2728 | } | 2728 | } |
2729 | 2729 | ||
2730 | nlh->nlmsg_len = skb->tail - b; | 2730 | NLA_PUT(skb, RTA_CACHEINFO, sizeof(ci), &ci); |
2731 | return skb->len; | 2731 | |
2732 | return nlmsg_end(skb, nlh); | ||
2732 | 2733 | ||
2733 | nlmsg_failure: | 2734 | nla_put_failure: |
2734 | rtattr_failure: | 2735 | return nlmsg_cancel(skb, nlh); |
2735 | skb_trim(skb, b - skb->data); | ||
2736 | return -1; | ||
2737 | } | 2736 | } |
2738 | 2737 | ||
2739 | int inet_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr* nlh, void *arg) | 2738 | int inet_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr* nlh, void *arg) |
2740 | { | 2739 | { |
2741 | struct rtattr **rta = arg; | 2740 | struct rtmsg *rtm; |
2742 | struct rtmsg *rtm = NLMSG_DATA(nlh); | 2741 | struct nlattr *tb[RTA_MAX+1]; |
2743 | struct rtable *rt = NULL; | 2742 | struct rtable *rt = NULL; |
2744 | u32 dst = 0; | 2743 | u32 dst, src, iif; |
2745 | u32 src = 0; | 2744 | int err; |
2746 | int iif = 0; | ||
2747 | int err = -ENOBUFS; | ||
2748 | struct sk_buff *skb; | 2745 | struct sk_buff *skb; |
2749 | 2746 | ||
2747 | err = nlmsg_parse(nlh, sizeof(*rtm), tb, RTA_MAX, rtm_ipv4_policy); | ||
2748 | if (err < 0) | ||
2749 | goto errout; | ||
2750 | |||
2751 | rtm = nlmsg_data(nlh); | ||
2752 | |||
2750 | skb = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL); | 2753 | skb = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL); |
2751 | if (!skb) | 2754 | if (skb == NULL) { |
2752 | goto out; | 2755 | err = -ENOBUFS; |
2756 | goto errout; | ||
2757 | } | ||
2753 | 2758 | ||
2754 | /* Reserve room for dummy headers, this skb can pass | 2759 | /* Reserve room for dummy headers, this skb can pass |
2755 | through good chunk of routing engine. | 2760 | through good chunk of routing engine. |
@@ -2760,62 +2765,61 @@ int inet_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr* nlh, void *arg) | |||
2760 | skb->nh.iph->protocol = IPPROTO_ICMP; | 2765 | skb->nh.iph->protocol = IPPROTO_ICMP; |
2761 | skb_reserve(skb, MAX_HEADER + sizeof(struct iphdr)); | 2766 | skb_reserve(skb, MAX_HEADER + sizeof(struct iphdr)); |
2762 | 2767 | ||
2763 | if (rta[RTA_SRC - 1]) | 2768 | src = tb[RTA_SRC] ? nla_get_u32(tb[RTA_SRC]) : 0; |
2764 | memcpy(&src, RTA_DATA(rta[RTA_SRC - 1]), 4); | 2769 | dst = tb[RTA_DST] ? nla_get_u32(tb[RTA_DST]) : 0; |
2765 | if (rta[RTA_DST - 1]) | 2770 | iif = tb[RTA_IIF] ? nla_get_u32(tb[RTA_IIF]) : 0; |
2766 | memcpy(&dst, RTA_DATA(rta[RTA_DST - 1]), 4); | ||
2767 | if (rta[RTA_IIF - 1]) | ||
2768 | memcpy(&iif, RTA_DATA(rta[RTA_IIF - 1]), sizeof(int)); | ||
2769 | 2771 | ||
2770 | if (iif) { | 2772 | if (iif) { |
2771 | struct net_device *dev = __dev_get_by_index(iif); | 2773 | struct net_device *dev; |
2772 | err = -ENODEV; | 2774 | |
2773 | if (!dev) | 2775 | dev = __dev_get_by_index(iif); |
2774 | goto out_free; | 2776 | if (dev == NULL) { |
2777 | err = -ENODEV; | ||
2778 | goto errout_free; | ||
2779 | } | ||
2780 | |||
2775 | skb->protocol = htons(ETH_P_IP); | 2781 | skb->protocol = htons(ETH_P_IP); |
2776 | skb->dev = dev; | 2782 | skb->dev = dev; |
2777 | local_bh_disable(); | 2783 | local_bh_disable(); |
2778 | err = ip_route_input(skb, dst, src, rtm->rtm_tos, dev); | 2784 | err = ip_route_input(skb, dst, src, rtm->rtm_tos, dev); |
2779 | local_bh_enable(); | 2785 | local_bh_enable(); |
2780 | rt = (struct rtable*)skb->dst; | 2786 | |
2781 | if (!err && rt->u.dst.error) | 2787 | rt = (struct rtable*) skb->dst; |
2788 | if (err == 0 && rt->u.dst.error) | ||
2782 | err = -rt->u.dst.error; | 2789 | err = -rt->u.dst.error; |
2783 | } else { | 2790 | } else { |
2784 | struct flowi fl = { .nl_u = { .ip4_u = { .daddr = dst, | 2791 | struct flowi fl = { |
2785 | .saddr = src, | 2792 | .nl_u = { |
2786 | .tos = rtm->rtm_tos } } }; | 2793 | .ip4_u = { |
2787 | int oif = 0; | 2794 | .daddr = dst, |
2788 | if (rta[RTA_OIF - 1]) | 2795 | .saddr = src, |
2789 | memcpy(&oif, RTA_DATA(rta[RTA_OIF - 1]), sizeof(int)); | 2796 | .tos = rtm->rtm_tos, |
2790 | fl.oif = oif; | 2797 | }, |
2798 | }, | ||
2799 | .oif = tb[RTA_OIF] ? nla_get_u32(tb[RTA_OIF]) : 0, | ||
2800 | }; | ||
2791 | err = ip_route_output_key(&rt, &fl); | 2801 | err = ip_route_output_key(&rt, &fl); |
2792 | } | 2802 | } |
2803 | |||
2793 | if (err) | 2804 | if (err) |
2794 | goto out_free; | 2805 | goto errout_free; |
2795 | 2806 | ||
2796 | skb->dst = &rt->u.dst; | 2807 | skb->dst = &rt->u.dst; |
2797 | if (rtm->rtm_flags & RTM_F_NOTIFY) | 2808 | if (rtm->rtm_flags & RTM_F_NOTIFY) |
2798 | rt->rt_flags |= RTCF_NOTIFY; | 2809 | rt->rt_flags |= RTCF_NOTIFY; |
2799 | 2810 | ||
2800 | NETLINK_CB(skb).dst_pid = NETLINK_CB(in_skb).pid; | ||
2801 | |||
2802 | err = rt_fill_info(skb, NETLINK_CB(in_skb).pid, nlh->nlmsg_seq, | 2811 | err = rt_fill_info(skb, NETLINK_CB(in_skb).pid, nlh->nlmsg_seq, |
2803 | RTM_NEWROUTE, 0, 0); | 2812 | RTM_NEWROUTE, 0, 0); |
2804 | if (!err) | 2813 | if (err <= 0) |
2805 | goto out_free; | 2814 | goto errout_free; |
2806 | if (err < 0) { | ||
2807 | err = -EMSGSIZE; | ||
2808 | goto out_free; | ||
2809 | } | ||
2810 | 2815 | ||
2811 | err = netlink_unicast(rtnl, skb, NETLINK_CB(in_skb).pid, MSG_DONTWAIT); | 2816 | err = rtnl_unicast(skb, NETLINK_CB(in_skb).pid); |
2812 | if (err > 0) | 2817 | errout: |
2813 | err = 0; | 2818 | return err; |
2814 | out: return err; | ||
2815 | 2819 | ||
2816 | out_free: | 2820 | errout_free: |
2817 | kfree_skb(skb); | 2821 | kfree_skb(skb); |
2818 | goto out; | 2822 | goto errout; |
2819 | } | 2823 | } |
2820 | 2824 | ||
2821 | int ip_rt_dump(struct sk_buff *skb, struct netlink_callback *cb) | 2825 | int ip_rt_dump(struct sk_buff *skb, struct netlink_callback *cb) |
@@ -3143,13 +3147,9 @@ int __init ip_rt_init(void) | |||
3143 | } | 3147 | } |
3144 | #endif | 3148 | #endif |
3145 | 3149 | ||
3146 | ipv4_dst_ops.kmem_cachep = kmem_cache_create("ip_dst_cache", | 3150 | ipv4_dst_ops.kmem_cachep = |
3147 | sizeof(struct rtable), | 3151 | kmem_cache_create("ip_dst_cache", sizeof(struct rtable), 0, |
3148 | 0, SLAB_HWCACHE_ALIGN, | 3152 | SLAB_HWCACHE_ALIGN|SLAB_PANIC, NULL, NULL); |
3149 | NULL, NULL); | ||
3150 | |||
3151 | if (!ipv4_dst_ops.kmem_cachep) | ||
3152 | panic("IP: failed to allocate ip_dst_cache\n"); | ||
3153 | 3153 | ||
3154 | rt_hash_table = (struct rt_hash_bucket *) | 3154 | rt_hash_table = (struct rt_hash_bucket *) |
3155 | alloc_large_system_hash("IP route cache", | 3155 | alloc_large_system_hash("IP route cache", |
diff --git a/net/ipv4/syncookies.c b/net/ipv4/syncookies.c index e20be3331f67..661e0a4bca72 100644 --- a/net/ipv4/syncookies.c +++ b/net/ipv4/syncookies.c | |||
@@ -214,6 +214,10 @@ struct sock *cookie_v4_check(struct sock *sk, struct sk_buff *skb, | |||
214 | if (!req) | 214 | if (!req) |
215 | goto out; | 215 | goto out; |
216 | 216 | ||
217 | if (security_inet_conn_request(sk, skb, req)) { | ||
218 | reqsk_free(req); | ||
219 | goto out; | ||
220 | } | ||
217 | ireq = inet_rsk(req); | 221 | ireq = inet_rsk(req); |
218 | treq = tcp_rsk(req); | 222 | treq = tcp_rsk(req); |
219 | treq->rcv_isn = htonl(skb->h.th->seq) - 1; | 223 | treq->rcv_isn = htonl(skb->h.th->seq) - 1; |
@@ -259,6 +263,7 @@ struct sock *cookie_v4_check(struct sock *sk, struct sk_buff *skb, | |||
259 | .uli_u = { .ports = | 263 | .uli_u = { .ports = |
260 | { .sport = skb->h.th->dest, | 264 | { .sport = skb->h.th->dest, |
261 | .dport = skb->h.th->source } } }; | 265 | .dport = skb->h.th->source } } }; |
266 | security_req_classify_flow(req, &fl); | ||
262 | if (ip_route_output_key(&rt, &fl)) { | 267 | if (ip_route_output_key(&rt, &fl)) { |
263 | reqsk_free(req); | 268 | reqsk_free(req); |
264 | goto out; | 269 | goto out; |
diff --git a/net/ipv4/sysctl_net_ipv4.c b/net/ipv4/sysctl_net_ipv4.c index 70cea9d08a38..19b2071ff319 100644 --- a/net/ipv4/sysctl_net_ipv4.c +++ b/net/ipv4/sysctl_net_ipv4.c | |||
@@ -17,6 +17,7 @@ | |||
17 | #include <net/ip.h> | 17 | #include <net/ip.h> |
18 | #include <net/route.h> | 18 | #include <net/route.h> |
19 | #include <net/tcp.h> | 19 | #include <net/tcp.h> |
20 | #include <net/cipso_ipv4.h> | ||
20 | 21 | ||
21 | /* From af_inet.c */ | 22 | /* From af_inet.c */ |
22 | extern int sysctl_ip_nonlocal_bind; | 23 | extern int sysctl_ip_nonlocal_bind; |
@@ -697,6 +698,40 @@ ctl_table ipv4_table[] = { | |||
697 | .mode = 0644, | 698 | .mode = 0644, |
698 | .proc_handler = &proc_dointvec | 699 | .proc_handler = &proc_dointvec |
699 | }, | 700 | }, |
701 | #ifdef CONFIG_NETLABEL | ||
702 | { | ||
703 | .ctl_name = NET_CIPSOV4_CACHE_ENABLE, | ||
704 | .procname = "cipso_cache_enable", | ||
705 | .data = &cipso_v4_cache_enabled, | ||
706 | .maxlen = sizeof(int), | ||
707 | .mode = 0644, | ||
708 | .proc_handler = &proc_dointvec, | ||
709 | }, | ||
710 | { | ||
711 | .ctl_name = NET_CIPSOV4_CACHE_BUCKET_SIZE, | ||
712 | .procname = "cipso_cache_bucket_size", | ||
713 | .data = &cipso_v4_cache_bucketsize, | ||
714 | .maxlen = sizeof(int), | ||
715 | .mode = 0644, | ||
716 | .proc_handler = &proc_dointvec, | ||
717 | }, | ||
718 | { | ||
719 | .ctl_name = NET_CIPSOV4_RBM_OPTFMT, | ||
720 | .procname = "cipso_rbm_optfmt", | ||
721 | .data = &cipso_v4_rbm_optfmt, | ||
722 | .maxlen = sizeof(int), | ||
723 | .mode = 0644, | ||
724 | .proc_handler = &proc_dointvec, | ||
725 | }, | ||
726 | { | ||
727 | .ctl_name = NET_CIPSOV4_RBM_STRICTVALID, | ||
728 | .procname = "cipso_rbm_strictvalid", | ||
729 | .data = &cipso_v4_rbm_strictvalid, | ||
730 | .maxlen = sizeof(int), | ||
731 | .mode = 0644, | ||
732 | .proc_handler = &proc_dointvec, | ||
733 | }, | ||
734 | #endif /* CONFIG_NETLABEL */ | ||
700 | { .ctl_name = 0 } | 735 | { .ctl_name = 0 } |
701 | }; | 736 | }; |
702 | 737 | ||
diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c index 934396bb1376..66e9a729f6df 100644 --- a/net/ipv4/tcp.c +++ b/net/ipv4/tcp.c | |||
@@ -268,7 +268,7 @@ | |||
268 | #include <asm/uaccess.h> | 268 | #include <asm/uaccess.h> |
269 | #include <asm/ioctls.h> | 269 | #include <asm/ioctls.h> |
270 | 270 | ||
271 | int sysctl_tcp_fin_timeout = TCP_FIN_TIMEOUT; | 271 | int sysctl_tcp_fin_timeout __read_mostly = TCP_FIN_TIMEOUT; |
272 | 272 | ||
273 | DEFINE_SNMP_STAT(struct tcp_mib, tcp_statistics) __read_mostly; | 273 | DEFINE_SNMP_STAT(struct tcp_mib, tcp_statistics) __read_mostly; |
274 | 274 | ||
@@ -568,7 +568,7 @@ new_segment: | |||
568 | skb->truesize += copy; | 568 | skb->truesize += copy; |
569 | sk->sk_wmem_queued += copy; | 569 | sk->sk_wmem_queued += copy; |
570 | sk->sk_forward_alloc -= copy; | 570 | sk->sk_forward_alloc -= copy; |
571 | skb->ip_summed = CHECKSUM_HW; | 571 | skb->ip_summed = CHECKSUM_PARTIAL; |
572 | tp->write_seq += copy; | 572 | tp->write_seq += copy; |
573 | TCP_SKB_CB(skb)->end_seq += copy; | 573 | TCP_SKB_CB(skb)->end_seq += copy; |
574 | skb_shinfo(skb)->gso_segs = 0; | 574 | skb_shinfo(skb)->gso_segs = 0; |
@@ -723,7 +723,7 @@ new_segment: | |||
723 | * Check whether we can use HW checksum. | 723 | * Check whether we can use HW checksum. |
724 | */ | 724 | */ |
725 | if (sk->sk_route_caps & NETIF_F_ALL_CSUM) | 725 | if (sk->sk_route_caps & NETIF_F_ALL_CSUM) |
726 | skb->ip_summed = CHECKSUM_HW; | 726 | skb->ip_summed = CHECKSUM_PARTIAL; |
727 | 727 | ||
728 | skb_entail(sk, tp, skb); | 728 | skb_entail(sk, tp, skb); |
729 | copy = size_goal; | 729 | copy = size_goal; |
@@ -955,8 +955,11 @@ void tcp_cleanup_rbuf(struct sock *sk, int copied) | |||
955 | * receive buffer and there was a small segment | 955 | * receive buffer and there was a small segment |
956 | * in queue. | 956 | * in queue. |
957 | */ | 957 | */ |
958 | (copied > 0 && (icsk->icsk_ack.pending & ICSK_ACK_PUSHED) && | 958 | (copied > 0 && |
959 | !icsk->icsk_ack.pingpong && !atomic_read(&sk->sk_rmem_alloc))) | 959 | ((icsk->icsk_ack.pending & ICSK_ACK_PUSHED2) || |
960 | ((icsk->icsk_ack.pending & ICSK_ACK_PUSHED) && | ||
961 | !icsk->icsk_ack.pingpong)) && | ||
962 | !atomic_read(&sk->sk_rmem_alloc))) | ||
960 | time_to_ack = 1; | 963 | time_to_ack = 1; |
961 | } | 964 | } |
962 | 965 | ||
@@ -2205,7 +2208,7 @@ struct sk_buff *tcp_tso_segment(struct sk_buff *skb, int features) | |||
2205 | th->fin = th->psh = 0; | 2208 | th->fin = th->psh = 0; |
2206 | 2209 | ||
2207 | th->check = ~csum_fold(th->check + delta); | 2210 | th->check = ~csum_fold(th->check + delta); |
2208 | if (skb->ip_summed != CHECKSUM_HW) | 2211 | if (skb->ip_summed != CHECKSUM_PARTIAL) |
2209 | th->check = csum_fold(csum_partial(skb->h.raw, thlen, | 2212 | th->check = csum_fold(csum_partial(skb->h.raw, thlen, |
2210 | skb->csum)); | 2213 | skb->csum)); |
2211 | 2214 | ||
@@ -2219,7 +2222,7 @@ struct sk_buff *tcp_tso_segment(struct sk_buff *skb, int features) | |||
2219 | 2222 | ||
2220 | delta = htonl(oldlen + (skb->tail - skb->h.raw) + skb->data_len); | 2223 | delta = htonl(oldlen + (skb->tail - skb->h.raw) + skb->data_len); |
2221 | th->check = ~csum_fold(th->check + delta); | 2224 | th->check = ~csum_fold(th->check + delta); |
2222 | if (skb->ip_summed != CHECKSUM_HW) | 2225 | if (skb->ip_summed != CHECKSUM_PARTIAL) |
2223 | th->check = csum_fold(csum_partial(skb->h.raw, thlen, | 2226 | th->check = csum_fold(csum_partial(skb->h.raw, thlen, |
2224 | skb->csum)); | 2227 | skb->csum)); |
2225 | 2228 | ||
@@ -2254,9 +2257,7 @@ void __init tcp_init(void) | |||
2254 | tcp_hashinfo.bind_bucket_cachep = | 2257 | tcp_hashinfo.bind_bucket_cachep = |
2255 | kmem_cache_create("tcp_bind_bucket", | 2258 | kmem_cache_create("tcp_bind_bucket", |
2256 | sizeof(struct inet_bind_bucket), 0, | 2259 | sizeof(struct inet_bind_bucket), 0, |
2257 | SLAB_HWCACHE_ALIGN, NULL, NULL); | 2260 | SLAB_HWCACHE_ALIGN|SLAB_PANIC, NULL, NULL); |
2258 | if (!tcp_hashinfo.bind_bucket_cachep) | ||
2259 | panic("tcp_init: Cannot alloc tcp_bind_bucket cache."); | ||
2260 | 2261 | ||
2261 | /* Size and allocate the main established and bind bucket | 2262 | /* Size and allocate the main established and bind bucket |
2262 | * hash tables. | 2263 | * hash tables. |
diff --git a/net/ipv4/tcp_bic.c b/net/ipv4/tcp_bic.c index b0134ab08379..5730333cd0ac 100644 --- a/net/ipv4/tcp_bic.c +++ b/net/ipv4/tcp_bic.c | |||
@@ -231,7 +231,7 @@ static struct tcp_congestion_ops bictcp = { | |||
231 | 231 | ||
232 | static int __init bictcp_register(void) | 232 | static int __init bictcp_register(void) |
233 | { | 233 | { |
234 | BUG_ON(sizeof(struct bictcp) > ICSK_CA_PRIV_SIZE); | 234 | BUILD_BUG_ON(sizeof(struct bictcp) > ICSK_CA_PRIV_SIZE); |
235 | return tcp_register_congestion_control(&bictcp); | 235 | return tcp_register_congestion_control(&bictcp); |
236 | } | 236 | } |
237 | 237 | ||
diff --git a/net/ipv4/tcp_cubic.c b/net/ipv4/tcp_cubic.c index 2be27980ca78..a60ef38d75c6 100644 --- a/net/ipv4/tcp_cubic.c +++ b/net/ipv4/tcp_cubic.c | |||
@@ -358,7 +358,7 @@ static struct tcp_congestion_ops cubictcp = { | |||
358 | 358 | ||
359 | static int __init cubictcp_register(void) | 359 | static int __init cubictcp_register(void) |
360 | { | 360 | { |
361 | BUG_ON(sizeof(struct bictcp) > ICSK_CA_PRIV_SIZE); | 361 | BUILD_BUG_ON(sizeof(struct bictcp) > ICSK_CA_PRIV_SIZE); |
362 | 362 | ||
363 | /* Precompute a bunch of the scaling factors that are used per-packet | 363 | /* Precompute a bunch of the scaling factors that are used per-packet |
364 | * based on SRTT of 100ms | 364 | * based on SRTT of 100ms |
diff --git a/net/ipv4/tcp_highspeed.c b/net/ipv4/tcp_highspeed.c index fa3e1aad660c..c4fc811bf377 100644 --- a/net/ipv4/tcp_highspeed.c +++ b/net/ipv4/tcp_highspeed.c | |||
@@ -189,7 +189,7 @@ static struct tcp_congestion_ops tcp_highspeed = { | |||
189 | 189 | ||
190 | static int __init hstcp_register(void) | 190 | static int __init hstcp_register(void) |
191 | { | 191 | { |
192 | BUG_ON(sizeof(struct hstcp) > ICSK_CA_PRIV_SIZE); | 192 | BUILD_BUG_ON(sizeof(struct hstcp) > ICSK_CA_PRIV_SIZE); |
193 | return tcp_register_congestion_control(&tcp_highspeed); | 193 | return tcp_register_congestion_control(&tcp_highspeed); |
194 | } | 194 | } |
195 | 195 | ||
diff --git a/net/ipv4/tcp_htcp.c b/net/ipv4/tcp_htcp.c index 6edfe5e4510e..682e7d5b6f2f 100644 --- a/net/ipv4/tcp_htcp.c +++ b/net/ipv4/tcp_htcp.c | |||
@@ -286,7 +286,7 @@ static struct tcp_congestion_ops htcp = { | |||
286 | 286 | ||
287 | static int __init htcp_register(void) | 287 | static int __init htcp_register(void) |
288 | { | 288 | { |
289 | BUG_ON(sizeof(struct htcp) > ICSK_CA_PRIV_SIZE); | 289 | BUILD_BUG_ON(sizeof(struct htcp) > ICSK_CA_PRIV_SIZE); |
290 | BUILD_BUG_ON(BETA_MIN >= BETA_MAX); | 290 | BUILD_BUG_ON(BETA_MIN >= BETA_MAX); |
291 | return tcp_register_congestion_control(&htcp); | 291 | return tcp_register_congestion_control(&htcp); |
292 | } | 292 | } |
diff --git a/net/ipv4/tcp_hybla.c b/net/ipv4/tcp_hybla.c index 7406e0c5fb8e..59e691d26f64 100644 --- a/net/ipv4/tcp_hybla.c +++ b/net/ipv4/tcp_hybla.c | |||
@@ -170,7 +170,7 @@ static struct tcp_congestion_ops tcp_hybla = { | |||
170 | 170 | ||
171 | static int __init hybla_register(void) | 171 | static int __init hybla_register(void) |
172 | { | 172 | { |
173 | BUG_ON(sizeof(struct hybla) > ICSK_CA_PRIV_SIZE); | 173 | BUILD_BUG_ON(sizeof(struct hybla) > ICSK_CA_PRIV_SIZE); |
174 | return tcp_register_congestion_control(&tcp_hybla); | 174 | return tcp_register_congestion_control(&tcp_hybla); |
175 | } | 175 | } |
176 | 176 | ||
diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index 159fa3f1ba67..b3def0df14fb 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c | |||
@@ -72,24 +72,24 @@ | |||
72 | #include <asm/unaligned.h> | 72 | #include <asm/unaligned.h> |
73 | #include <net/netdma.h> | 73 | #include <net/netdma.h> |
74 | 74 | ||
75 | int sysctl_tcp_timestamps = 1; | 75 | int sysctl_tcp_timestamps __read_mostly = 1; |
76 | int sysctl_tcp_window_scaling = 1; | 76 | int sysctl_tcp_window_scaling __read_mostly = 1; |
77 | int sysctl_tcp_sack = 1; | 77 | int sysctl_tcp_sack __read_mostly = 1; |
78 | int sysctl_tcp_fack = 1; | 78 | int sysctl_tcp_fack __read_mostly = 1; |
79 | int sysctl_tcp_reordering = TCP_FASTRETRANS_THRESH; | 79 | int sysctl_tcp_reordering __read_mostly = TCP_FASTRETRANS_THRESH; |
80 | int sysctl_tcp_ecn; | 80 | int sysctl_tcp_ecn __read_mostly; |
81 | int sysctl_tcp_dsack = 1; | 81 | int sysctl_tcp_dsack __read_mostly = 1; |
82 | int sysctl_tcp_app_win = 31; | 82 | int sysctl_tcp_app_win __read_mostly = 31; |
83 | int sysctl_tcp_adv_win_scale = 2; | 83 | int sysctl_tcp_adv_win_scale __read_mostly = 2; |
84 | 84 | ||
85 | int sysctl_tcp_stdurg; | 85 | int sysctl_tcp_stdurg __read_mostly; |
86 | int sysctl_tcp_rfc1337; | 86 | int sysctl_tcp_rfc1337 __read_mostly; |
87 | int sysctl_tcp_max_orphans = NR_FILE; | 87 | int sysctl_tcp_max_orphans __read_mostly = NR_FILE; |
88 | int sysctl_tcp_frto; | 88 | int sysctl_tcp_frto __read_mostly; |
89 | int sysctl_tcp_nometrics_save; | 89 | int sysctl_tcp_nometrics_save __read_mostly; |
90 | 90 | ||
91 | int sysctl_tcp_moderate_rcvbuf = 1; | 91 | int sysctl_tcp_moderate_rcvbuf __read_mostly = 1; |
92 | int sysctl_tcp_abc; | 92 | int sysctl_tcp_abc __read_mostly; |
93 | 93 | ||
94 | #define FLAG_DATA 0x01 /* Incoming frame contained data. */ | 94 | #define FLAG_DATA 0x01 /* Incoming frame contained data. */ |
95 | #define FLAG_WIN_UPDATE 0x02 /* Incoming ACK was a window update. */ | 95 | #define FLAG_WIN_UPDATE 0x02 /* Incoming ACK was a window update. */ |
@@ -127,7 +127,7 @@ static void tcp_measure_rcv_mss(struct sock *sk, | |||
127 | /* skb->len may jitter because of SACKs, even if peer | 127 | /* skb->len may jitter because of SACKs, even if peer |
128 | * sends good full-sized frames. | 128 | * sends good full-sized frames. |
129 | */ | 129 | */ |
130 | len = skb->len; | 130 | len = skb_shinfo(skb)->gso_size ?: skb->len; |
131 | if (len >= icsk->icsk_ack.rcv_mss) { | 131 | if (len >= icsk->icsk_ack.rcv_mss) { |
132 | icsk->icsk_ack.rcv_mss = len; | 132 | icsk->icsk_ack.rcv_mss = len; |
133 | } else { | 133 | } else { |
@@ -156,6 +156,8 @@ static void tcp_measure_rcv_mss(struct sock *sk, | |||
156 | return; | 156 | return; |
157 | } | 157 | } |
158 | } | 158 | } |
159 | if (icsk->icsk_ack.pending & ICSK_ACK_PUSHED) | ||
160 | icsk->icsk_ack.pending |= ICSK_ACK_PUSHED2; | ||
159 | icsk->icsk_ack.pending |= ICSK_ACK_PUSHED; | 161 | icsk->icsk_ack.pending |= ICSK_ACK_PUSHED; |
160 | } | 162 | } |
161 | } | 163 | } |
diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index 4b04c3edd4a9..39b179856082 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c | |||
@@ -78,8 +78,8 @@ | |||
78 | #include <linux/proc_fs.h> | 78 | #include <linux/proc_fs.h> |
79 | #include <linux/seq_file.h> | 79 | #include <linux/seq_file.h> |
80 | 80 | ||
81 | int sysctl_tcp_tw_reuse; | 81 | int sysctl_tcp_tw_reuse __read_mostly; |
82 | int sysctl_tcp_low_latency; | 82 | int sysctl_tcp_low_latency __read_mostly; |
83 | 83 | ||
84 | /* Check TCP sequence numbers in ICMP packets. */ | 84 | /* Check TCP sequence numbers in ICMP packets. */ |
85 | #define ICMP_MIN_LENGTH 8 | 85 | #define ICMP_MIN_LENGTH 8 |
@@ -484,7 +484,7 @@ void tcp_v4_send_check(struct sock *sk, int len, struct sk_buff *skb) | |||
484 | struct inet_sock *inet = inet_sk(sk); | 484 | struct inet_sock *inet = inet_sk(sk); |
485 | struct tcphdr *th = skb->h.th; | 485 | struct tcphdr *th = skb->h.th; |
486 | 486 | ||
487 | if (skb->ip_summed == CHECKSUM_HW) { | 487 | if (skb->ip_summed == CHECKSUM_PARTIAL) { |
488 | th->check = ~tcp_v4_check(th, len, inet->saddr, inet->daddr, 0); | 488 | th->check = ~tcp_v4_check(th, len, inet->saddr, inet->daddr, 0); |
489 | skb->csum = offsetof(struct tcphdr, check); | 489 | skb->csum = offsetof(struct tcphdr, check); |
490 | } else { | 490 | } else { |
@@ -509,7 +509,7 @@ int tcp_v4_gso_send_check(struct sk_buff *skb) | |||
509 | th->check = 0; | 509 | th->check = 0; |
510 | th->check = ~tcp_v4_check(th, skb->len, iph->saddr, iph->daddr, 0); | 510 | th->check = ~tcp_v4_check(th, skb->len, iph->saddr, iph->daddr, 0); |
511 | skb->csum = offsetof(struct tcphdr, check); | 511 | skb->csum = offsetof(struct tcphdr, check); |
512 | skb->ip_summed = CHECKSUM_HW; | 512 | skb->ip_summed = CHECKSUM_PARTIAL; |
513 | return 0; | 513 | return 0; |
514 | } | 514 | } |
515 | 515 | ||
@@ -798,6 +798,9 @@ int tcp_v4_conn_request(struct sock *sk, struct sk_buff *skb) | |||
798 | 798 | ||
799 | tcp_openreq_init(req, &tmp_opt, skb); | 799 | tcp_openreq_init(req, &tmp_opt, skb); |
800 | 800 | ||
801 | if (security_inet_conn_request(sk, skb, req)) | ||
802 | goto drop_and_free; | ||
803 | |||
801 | ireq = inet_rsk(req); | 804 | ireq = inet_rsk(req); |
802 | ireq->loc_addr = daddr; | 805 | ireq->loc_addr = daddr; |
803 | ireq->rmt_addr = saddr; | 806 | ireq->rmt_addr = saddr; |
@@ -948,9 +951,9 @@ static struct sock *tcp_v4_hnd_req(struct sock *sk, struct sk_buff *skb) | |||
948 | if (req) | 951 | if (req) |
949 | return tcp_check_req(sk, skb, req, prev); | 952 | return tcp_check_req(sk, skb, req, prev); |
950 | 953 | ||
951 | nsk = __inet_lookup_established(&tcp_hashinfo, skb->nh.iph->saddr, | 954 | nsk = inet_lookup_established(&tcp_hashinfo, skb->nh.iph->saddr, |
952 | th->source, skb->nh.iph->daddr, | 955 | th->source, skb->nh.iph->daddr, |
953 | ntohs(th->dest), inet_iif(skb)); | 956 | th->dest, inet_iif(skb)); |
954 | 957 | ||
955 | if (nsk) { | 958 | if (nsk) { |
956 | if (nsk->sk_state != TCP_TIME_WAIT) { | 959 | if (nsk->sk_state != TCP_TIME_WAIT) { |
@@ -970,7 +973,7 @@ static struct sock *tcp_v4_hnd_req(struct sock *sk, struct sk_buff *skb) | |||
970 | 973 | ||
971 | static int tcp_v4_checksum_init(struct sk_buff *skb) | 974 | static int tcp_v4_checksum_init(struct sk_buff *skb) |
972 | { | 975 | { |
973 | if (skb->ip_summed == CHECKSUM_HW) { | 976 | if (skb->ip_summed == CHECKSUM_COMPLETE) { |
974 | if (!tcp_v4_check(skb->h.th, skb->len, skb->nh.iph->saddr, | 977 | if (!tcp_v4_check(skb->h.th, skb->len, skb->nh.iph->saddr, |
975 | skb->nh.iph->daddr, skb->csum)) { | 978 | skb->nh.iph->daddr, skb->csum)) { |
976 | skb->ip_summed = CHECKSUM_UNNECESSARY; | 979 | skb->ip_summed = CHECKSUM_UNNECESSARY; |
@@ -1087,7 +1090,7 @@ int tcp_v4_rcv(struct sk_buff *skb) | |||
1087 | TCP_SKB_CB(skb)->sacked = 0; | 1090 | TCP_SKB_CB(skb)->sacked = 0; |
1088 | 1091 | ||
1089 | sk = __inet_lookup(&tcp_hashinfo, skb->nh.iph->saddr, th->source, | 1092 | sk = __inet_lookup(&tcp_hashinfo, skb->nh.iph->saddr, th->source, |
1090 | skb->nh.iph->daddr, ntohs(th->dest), | 1093 | skb->nh.iph->daddr, th->dest, |
1091 | inet_iif(skb)); | 1094 | inet_iif(skb)); |
1092 | 1095 | ||
1093 | if (!sk) | 1096 | if (!sk) |
@@ -1101,7 +1104,7 @@ process: | |||
1101 | goto discard_and_relse; | 1104 | goto discard_and_relse; |
1102 | nf_reset(skb); | 1105 | nf_reset(skb); |
1103 | 1106 | ||
1104 | if (sk_filter(sk, skb, 0)) | 1107 | if (sk_filter(sk, skb)) |
1105 | goto discard_and_relse; | 1108 | goto discard_and_relse; |
1106 | 1109 | ||
1107 | skb->dev = NULL; | 1110 | skb->dev = NULL; |
@@ -1165,7 +1168,7 @@ do_time_wait: | |||
1165 | case TCP_TW_SYN: { | 1168 | case TCP_TW_SYN: { |
1166 | struct sock *sk2 = inet_lookup_listener(&tcp_hashinfo, | 1169 | struct sock *sk2 = inet_lookup_listener(&tcp_hashinfo, |
1167 | skb->nh.iph->daddr, | 1170 | skb->nh.iph->daddr, |
1168 | ntohs(th->dest), | 1171 | th->dest, |
1169 | inet_iif(skb)); | 1172 | inet_iif(skb)); |
1170 | if (sk2) { | 1173 | if (sk2) { |
1171 | inet_twsk_deschedule((struct inet_timewait_sock *)sk, | 1174 | inet_twsk_deschedule((struct inet_timewait_sock *)sk, |
diff --git a/net/ipv4/tcp_lp.c b/net/ipv4/tcp_lp.c index 48f28d617ce6..308fb7e071c5 100644 --- a/net/ipv4/tcp_lp.c +++ b/net/ipv4/tcp_lp.c | |||
@@ -35,7 +35,6 @@ | |||
35 | * Version: $Id: tcp_lp.c,v 1.24 2006/09/05 20:22:53 hswong3i Exp $ | 35 | * Version: $Id: tcp_lp.c,v 1.24 2006/09/05 20:22:53 hswong3i Exp $ |
36 | */ | 36 | */ |
37 | 37 | ||
38 | #include <linux/config.h> | ||
39 | #include <linux/module.h> | 38 | #include <linux/module.h> |
40 | #include <net/tcp.h> | 39 | #include <net/tcp.h> |
41 | 40 | ||
@@ -328,7 +327,7 @@ static struct tcp_congestion_ops tcp_lp = { | |||
328 | 327 | ||
329 | static int __init tcp_lp_register(void) | 328 | static int __init tcp_lp_register(void) |
330 | { | 329 | { |
331 | BUG_ON(sizeof(struct lp) > ICSK_CA_PRIV_SIZE); | 330 | BUILD_BUG_ON(sizeof(struct lp) > ICSK_CA_PRIV_SIZE); |
332 | return tcp_register_congestion_control(&tcp_lp); | 331 | return tcp_register_congestion_control(&tcp_lp); |
333 | } | 332 | } |
334 | 333 | ||
diff --git a/net/ipv4/tcp_minisocks.c b/net/ipv4/tcp_minisocks.c index 624e2b2c7f53..0163d9826907 100644 --- a/net/ipv4/tcp_minisocks.c +++ b/net/ipv4/tcp_minisocks.c | |||
@@ -34,8 +34,8 @@ | |||
34 | #define SYNC_INIT 1 | 34 | #define SYNC_INIT 1 |
35 | #endif | 35 | #endif |
36 | 36 | ||
37 | int sysctl_tcp_syncookies = SYNC_INIT; | 37 | int sysctl_tcp_syncookies __read_mostly = SYNC_INIT; |
38 | int sysctl_tcp_abort_on_overflow; | 38 | int sysctl_tcp_abort_on_overflow __read_mostly; |
39 | 39 | ||
40 | struct inet_timewait_death_row tcp_death_row = { | 40 | struct inet_timewait_death_row tcp_death_row = { |
41 | .sysctl_max_tw_buckets = NR_FILE * 2, | 41 | .sysctl_max_tw_buckets = NR_FILE * 2, |
diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c index b4f3ffe1b3b4..061edfae0c29 100644 --- a/net/ipv4/tcp_output.c +++ b/net/ipv4/tcp_output.c | |||
@@ -43,24 +43,24 @@ | |||
43 | #include <linux/smp_lock.h> | 43 | #include <linux/smp_lock.h> |
44 | 44 | ||
45 | /* People can turn this off for buggy TCP's found in printers etc. */ | 45 | /* People can turn this off for buggy TCP's found in printers etc. */ |
46 | int sysctl_tcp_retrans_collapse = 1; | 46 | int sysctl_tcp_retrans_collapse __read_mostly = 1; |
47 | 47 | ||
48 | /* People can turn this on to work with those rare, broken TCPs that | 48 | /* People can turn this on to work with those rare, broken TCPs that |
49 | * interpret the window field as a signed quantity. | 49 | * interpret the window field as a signed quantity. |
50 | */ | 50 | */ |
51 | int sysctl_tcp_workaround_signed_windows = 0; | 51 | int sysctl_tcp_workaround_signed_windows __read_mostly = 0; |
52 | 52 | ||
53 | /* This limits the percentage of the congestion window which we | 53 | /* This limits the percentage of the congestion window which we |
54 | * will allow a single TSO frame to consume. Building TSO frames | 54 | * will allow a single TSO frame to consume. Building TSO frames |
55 | * which are too large can cause TCP streams to be bursty. | 55 | * which are too large can cause TCP streams to be bursty. |
56 | */ | 56 | */ |
57 | int sysctl_tcp_tso_win_divisor = 3; | 57 | int sysctl_tcp_tso_win_divisor __read_mostly = 3; |
58 | 58 | ||
59 | int sysctl_tcp_mtu_probing = 0; | 59 | int sysctl_tcp_mtu_probing __read_mostly = 0; |
60 | int sysctl_tcp_base_mss = 512; | 60 | int sysctl_tcp_base_mss __read_mostly = 512; |
61 | 61 | ||
62 | /* By default, RFC2861 behavior. */ | 62 | /* By default, RFC2861 behavior. */ |
63 | int sysctl_tcp_slow_start_after_idle = 1; | 63 | int sysctl_tcp_slow_start_after_idle __read_mostly = 1; |
64 | 64 | ||
65 | static void update_send_head(struct sock *sk, struct tcp_sock *tp, | 65 | static void update_send_head(struct sock *sk, struct tcp_sock *tp, |
66 | struct sk_buff *skb) | 66 | struct sk_buff *skb) |
@@ -577,7 +577,7 @@ int tcp_fragment(struct sock *sk, struct sk_buff *skb, u32 len, unsigned int mss | |||
577 | TCP_SKB_CB(buff)->sacked = TCP_SKB_CB(skb)->sacked; | 577 | TCP_SKB_CB(buff)->sacked = TCP_SKB_CB(skb)->sacked; |
578 | TCP_SKB_CB(skb)->sacked &= ~TCPCB_AT_TAIL; | 578 | TCP_SKB_CB(skb)->sacked &= ~TCPCB_AT_TAIL; |
579 | 579 | ||
580 | if (!skb_shinfo(skb)->nr_frags && skb->ip_summed != CHECKSUM_HW) { | 580 | if (!skb_shinfo(skb)->nr_frags && skb->ip_summed != CHECKSUM_PARTIAL) { |
581 | /* Copy and checksum data tail into the new buffer. */ | 581 | /* Copy and checksum data tail into the new buffer. */ |
582 | buff->csum = csum_partial_copy_nocheck(skb->data + len, skb_put(buff, nsize), | 582 | buff->csum = csum_partial_copy_nocheck(skb->data + len, skb_put(buff, nsize), |
583 | nsize, 0); | 583 | nsize, 0); |
@@ -586,7 +586,7 @@ int tcp_fragment(struct sock *sk, struct sk_buff *skb, u32 len, unsigned int mss | |||
586 | 586 | ||
587 | skb->csum = csum_block_sub(skb->csum, buff->csum, len); | 587 | skb->csum = csum_block_sub(skb->csum, buff->csum, len); |
588 | } else { | 588 | } else { |
589 | skb->ip_summed = CHECKSUM_HW; | 589 | skb->ip_summed = CHECKSUM_PARTIAL; |
590 | skb_split(skb, buff, len); | 590 | skb_split(skb, buff, len); |
591 | } | 591 | } |
592 | 592 | ||
@@ -689,7 +689,7 @@ int tcp_trim_head(struct sock *sk, struct sk_buff *skb, u32 len) | |||
689 | __pskb_trim_head(skb, len - skb_headlen(skb)); | 689 | __pskb_trim_head(skb, len - skb_headlen(skb)); |
690 | 690 | ||
691 | TCP_SKB_CB(skb)->seq += len; | 691 | TCP_SKB_CB(skb)->seq += len; |
692 | skb->ip_summed = CHECKSUM_HW; | 692 | skb->ip_summed = CHECKSUM_PARTIAL; |
693 | 693 | ||
694 | skb->truesize -= len; | 694 | skb->truesize -= len; |
695 | sk->sk_wmem_queued -= len; | 695 | sk->sk_wmem_queued -= len; |
@@ -1062,7 +1062,7 @@ static int tso_fragment(struct sock *sk, struct sk_buff *skb, unsigned int len, | |||
1062 | /* This packet was never sent out yet, so no SACK bits. */ | 1062 | /* This packet was never sent out yet, so no SACK bits. */ |
1063 | TCP_SKB_CB(buff)->sacked = 0; | 1063 | TCP_SKB_CB(buff)->sacked = 0; |
1064 | 1064 | ||
1065 | buff->ip_summed = skb->ip_summed = CHECKSUM_HW; | 1065 | buff->ip_summed = skb->ip_summed = CHECKSUM_PARTIAL; |
1066 | skb_split(skb, buff, len); | 1066 | skb_split(skb, buff, len); |
1067 | 1067 | ||
1068 | /* Fix up tso_factor for both original and new SKB. */ | 1068 | /* Fix up tso_factor for both original and new SKB. */ |
@@ -1206,8 +1206,7 @@ static int tcp_mtu_probe(struct sock *sk) | |||
1206 | TCP_SKB_CB(nskb)->flags = TCPCB_FLAG_ACK; | 1206 | TCP_SKB_CB(nskb)->flags = TCPCB_FLAG_ACK; |
1207 | TCP_SKB_CB(nskb)->sacked = 0; | 1207 | TCP_SKB_CB(nskb)->sacked = 0; |
1208 | nskb->csum = 0; | 1208 | nskb->csum = 0; |
1209 | if (skb->ip_summed == CHECKSUM_HW) | 1209 | nskb->ip_summed = skb->ip_summed; |
1210 | nskb->ip_summed = CHECKSUM_HW; | ||
1211 | 1210 | ||
1212 | len = 0; | 1211 | len = 0; |
1213 | while (len < probe_size) { | 1212 | while (len < probe_size) { |
@@ -1231,7 +1230,7 @@ static int tcp_mtu_probe(struct sock *sk) | |||
1231 | ~(TCPCB_FLAG_FIN|TCPCB_FLAG_PSH); | 1230 | ~(TCPCB_FLAG_FIN|TCPCB_FLAG_PSH); |
1232 | if (!skb_shinfo(skb)->nr_frags) { | 1231 | if (!skb_shinfo(skb)->nr_frags) { |
1233 | skb_pull(skb, copy); | 1232 | skb_pull(skb, copy); |
1234 | if (skb->ip_summed != CHECKSUM_HW) | 1233 | if (skb->ip_summed != CHECKSUM_PARTIAL) |
1235 | skb->csum = csum_partial(skb->data, skb->len, 0); | 1234 | skb->csum = csum_partial(skb->data, skb->len, 0); |
1236 | } else { | 1235 | } else { |
1237 | __pskb_trim_head(skb, copy); | 1236 | __pskb_trim_head(skb, copy); |
@@ -1572,10 +1571,9 @@ static void tcp_retrans_try_collapse(struct sock *sk, struct sk_buff *skb, int m | |||
1572 | 1571 | ||
1573 | memcpy(skb_put(skb, next_skb_size), next_skb->data, next_skb_size); | 1572 | memcpy(skb_put(skb, next_skb_size), next_skb->data, next_skb_size); |
1574 | 1573 | ||
1575 | if (next_skb->ip_summed == CHECKSUM_HW) | 1574 | skb->ip_summed = next_skb->ip_summed; |
1576 | skb->ip_summed = CHECKSUM_HW; | ||
1577 | 1575 | ||
1578 | if (skb->ip_summed != CHECKSUM_HW) | 1576 | if (skb->ip_summed != CHECKSUM_PARTIAL) |
1579 | skb->csum = csum_block_add(skb->csum, next_skb->csum, skb_size); | 1577 | skb->csum = csum_block_add(skb->csum, next_skb->csum, skb_size); |
1580 | 1578 | ||
1581 | /* Update sequence range on original skb. */ | 1579 | /* Update sequence range on original skb. */ |
diff --git a/net/ipv4/tcp_timer.c b/net/ipv4/tcp_timer.c index 7c1bde3cd6cb..fb09ade5897b 100644 --- a/net/ipv4/tcp_timer.c +++ b/net/ipv4/tcp_timer.c | |||
@@ -23,14 +23,14 @@ | |||
23 | #include <linux/module.h> | 23 | #include <linux/module.h> |
24 | #include <net/tcp.h> | 24 | #include <net/tcp.h> |
25 | 25 | ||
26 | int sysctl_tcp_syn_retries = TCP_SYN_RETRIES; | 26 | int sysctl_tcp_syn_retries __read_mostly = TCP_SYN_RETRIES; |
27 | int sysctl_tcp_synack_retries = TCP_SYNACK_RETRIES; | 27 | int sysctl_tcp_synack_retries __read_mostly = TCP_SYNACK_RETRIES; |
28 | int sysctl_tcp_keepalive_time = TCP_KEEPALIVE_TIME; | 28 | int sysctl_tcp_keepalive_time __read_mostly = TCP_KEEPALIVE_TIME; |
29 | int sysctl_tcp_keepalive_probes = TCP_KEEPALIVE_PROBES; | 29 | int sysctl_tcp_keepalive_probes __read_mostly = TCP_KEEPALIVE_PROBES; |
30 | int sysctl_tcp_keepalive_intvl = TCP_KEEPALIVE_INTVL; | 30 | int sysctl_tcp_keepalive_intvl __read_mostly = TCP_KEEPALIVE_INTVL; |
31 | int sysctl_tcp_retries1 = TCP_RETR1; | 31 | int sysctl_tcp_retries1 __read_mostly = TCP_RETR1; |
32 | int sysctl_tcp_retries2 = TCP_RETR2; | 32 | int sysctl_tcp_retries2 __read_mostly = TCP_RETR2; |
33 | int sysctl_tcp_orphan_retries; | 33 | int sysctl_tcp_orphan_retries __read_mostly; |
34 | 34 | ||
35 | static void tcp_write_timer(unsigned long); | 35 | static void tcp_write_timer(unsigned long); |
36 | static void tcp_delack_timer(unsigned long); | 36 | static void tcp_delack_timer(unsigned long); |
diff --git a/net/ipv4/tcp_vegas.c b/net/ipv4/tcp_vegas.c index 490360b5b4bf..a3b7aa015a2f 100644 --- a/net/ipv4/tcp_vegas.c +++ b/net/ipv4/tcp_vegas.c | |||
@@ -370,7 +370,7 @@ static struct tcp_congestion_ops tcp_vegas = { | |||
370 | 370 | ||
371 | static int __init tcp_vegas_register(void) | 371 | static int __init tcp_vegas_register(void) |
372 | { | 372 | { |
373 | BUG_ON(sizeof(struct vegas) > ICSK_CA_PRIV_SIZE); | 373 | BUILD_BUG_ON(sizeof(struct vegas) > ICSK_CA_PRIV_SIZE); |
374 | tcp_register_congestion_control(&tcp_vegas); | 374 | tcp_register_congestion_control(&tcp_vegas); |
375 | return 0; | 375 | return 0; |
376 | } | 376 | } |
diff --git a/net/ipv4/tcp_veno.c b/net/ipv4/tcp_veno.c index 11b42a7135c1..ce57bf302f6c 100644 --- a/net/ipv4/tcp_veno.c +++ b/net/ipv4/tcp_veno.c | |||
@@ -9,7 +9,6 @@ | |||
9 | * See http://www.ntu.edu.sg/home5/ZHOU0022/papers/CPFu03a.pdf | 9 | * See http://www.ntu.edu.sg/home5/ZHOU0022/papers/CPFu03a.pdf |
10 | */ | 10 | */ |
11 | 11 | ||
12 | #include <linux/config.h> | ||
13 | #include <linux/mm.h> | 12 | #include <linux/mm.h> |
14 | #include <linux/module.h> | 13 | #include <linux/module.h> |
15 | #include <linux/skbuff.h> | 14 | #include <linux/skbuff.h> |
@@ -213,7 +212,7 @@ static struct tcp_congestion_ops tcp_veno = { | |||
213 | 212 | ||
214 | static int __init tcp_veno_register(void) | 213 | static int __init tcp_veno_register(void) |
215 | { | 214 | { |
216 | BUG_ON(sizeof(struct veno) > ICSK_CA_PRIV_SIZE); | 215 | BUILD_BUG_ON(sizeof(struct veno) > ICSK_CA_PRIV_SIZE); |
217 | tcp_register_congestion_control(&tcp_veno); | 216 | tcp_register_congestion_control(&tcp_veno); |
218 | return 0; | 217 | return 0; |
219 | } | 218 | } |
diff --git a/net/ipv4/tcp_westwood.c b/net/ipv4/tcp_westwood.c index 5446312ffd2a..4f42a86c77f3 100644 --- a/net/ipv4/tcp_westwood.c +++ b/net/ipv4/tcp_westwood.c | |||
@@ -289,7 +289,7 @@ static struct tcp_congestion_ops tcp_westwood = { | |||
289 | 289 | ||
290 | static int __init tcp_westwood_register(void) | 290 | static int __init tcp_westwood_register(void) |
291 | { | 291 | { |
292 | BUG_ON(sizeof(struct westwood) > ICSK_CA_PRIV_SIZE); | 292 | BUILD_BUG_ON(sizeof(struct westwood) > ICSK_CA_PRIV_SIZE); |
293 | return tcp_register_congestion_control(&tcp_westwood); | 293 | return tcp_register_congestion_control(&tcp_westwood); |
294 | } | 294 | } |
295 | 295 | ||
diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c index f136cec96d95..77e265d7bb8f 100644 --- a/net/ipv4/udp.c +++ b/net/ipv4/udp.c | |||
@@ -118,14 +118,33 @@ DEFINE_SNMP_STAT(struct udp_mib, udp_statistics) __read_mostly; | |||
118 | struct hlist_head udp_hash[UDP_HTABLE_SIZE]; | 118 | struct hlist_head udp_hash[UDP_HTABLE_SIZE]; |
119 | DEFINE_RWLOCK(udp_hash_lock); | 119 | DEFINE_RWLOCK(udp_hash_lock); |
120 | 120 | ||
121 | /* Shared by v4/v6 udp. */ | 121 | static int udp_port_rover; |
122 | int udp_port_rover; | ||
123 | 122 | ||
124 | static int udp_v4_get_port(struct sock *sk, unsigned short snum) | 123 | static inline int udp_lport_inuse(u16 num) |
124 | { | ||
125 | struct sock *sk; | ||
126 | struct hlist_node *node; | ||
127 | |||
128 | sk_for_each(sk, node, &udp_hash[num & (UDP_HTABLE_SIZE - 1)]) | ||
129 | if (inet_sk(sk)->num == num) | ||
130 | return 1; | ||
131 | return 0; | ||
132 | } | ||
133 | |||
134 | /** | ||
135 | * udp_get_port - common port lookup for IPv4 and IPv6 | ||
136 | * | ||
137 | * @sk: socket struct in question | ||
138 | * @snum: port number to look up | ||
139 | * @saddr_comp: AF-dependent comparison of bound local IP addresses | ||
140 | */ | ||
141 | int udp_get_port(struct sock *sk, unsigned short snum, | ||
142 | int (*saddr_cmp)(const struct sock *sk1, const struct sock *sk2)) | ||
125 | { | 143 | { |
126 | struct hlist_node *node; | 144 | struct hlist_node *node; |
145 | struct hlist_head *head; | ||
127 | struct sock *sk2; | 146 | struct sock *sk2; |
128 | struct inet_sock *inet = inet_sk(sk); | 147 | int error = 1; |
129 | 148 | ||
130 | write_lock_bh(&udp_hash_lock); | 149 | write_lock_bh(&udp_hash_lock); |
131 | if (snum == 0) { | 150 | if (snum == 0) { |
@@ -137,11 +156,10 @@ static int udp_v4_get_port(struct sock *sk, unsigned short snum) | |||
137 | best_size_so_far = 32767; | 156 | best_size_so_far = 32767; |
138 | best = result = udp_port_rover; | 157 | best = result = udp_port_rover; |
139 | for (i = 0; i < UDP_HTABLE_SIZE; i++, result++) { | 158 | for (i = 0; i < UDP_HTABLE_SIZE; i++, result++) { |
140 | struct hlist_head *list; | ||
141 | int size; | 159 | int size; |
142 | 160 | ||
143 | list = &udp_hash[result & (UDP_HTABLE_SIZE - 1)]; | 161 | head = &udp_hash[result & (UDP_HTABLE_SIZE - 1)]; |
144 | if (hlist_empty(list)) { | 162 | if (hlist_empty(head)) { |
145 | if (result > sysctl_local_port_range[1]) | 163 | if (result > sysctl_local_port_range[1]) |
146 | result = sysctl_local_port_range[0] + | 164 | result = sysctl_local_port_range[0] + |
147 | ((result - sysctl_local_port_range[0]) & | 165 | ((result - sysctl_local_port_range[0]) & |
@@ -149,12 +167,11 @@ static int udp_v4_get_port(struct sock *sk, unsigned short snum) | |||
149 | goto gotit; | 167 | goto gotit; |
150 | } | 168 | } |
151 | size = 0; | 169 | size = 0; |
152 | sk_for_each(sk2, node, list) | 170 | sk_for_each(sk2, node, head) |
153 | if (++size >= best_size_so_far) | 171 | if (++size < best_size_so_far) { |
154 | goto next; | 172 | best_size_so_far = size; |
155 | best_size_so_far = size; | 173 | best = result; |
156 | best = result; | 174 | } |
157 | next:; | ||
158 | } | 175 | } |
159 | result = best; | 176 | result = best; |
160 | for(i = 0; i < (1 << 16) / UDP_HTABLE_SIZE; i++, result += UDP_HTABLE_SIZE) { | 177 | for(i = 0; i < (1 << 16) / UDP_HTABLE_SIZE; i++, result += UDP_HTABLE_SIZE) { |
@@ -170,38 +187,44 @@ static int udp_v4_get_port(struct sock *sk, unsigned short snum) | |||
170 | gotit: | 187 | gotit: |
171 | udp_port_rover = snum = result; | 188 | udp_port_rover = snum = result; |
172 | } else { | 189 | } else { |
173 | sk_for_each(sk2, node, | 190 | head = &udp_hash[snum & (UDP_HTABLE_SIZE - 1)]; |
174 | &udp_hash[snum & (UDP_HTABLE_SIZE - 1)]) { | 191 | |
175 | struct inet_sock *inet2 = inet_sk(sk2); | 192 | sk_for_each(sk2, node, head) |
176 | 193 | if (inet_sk(sk2)->num == snum && | |
177 | if (inet2->num == snum && | 194 | sk2 != sk && |
178 | sk2 != sk && | 195 | (!sk2->sk_reuse || !sk->sk_reuse) && |
179 | !ipv6_only_sock(sk2) && | 196 | (!sk2->sk_bound_dev_if || !sk->sk_bound_dev_if |
180 | (!sk2->sk_bound_dev_if || | 197 | || sk2->sk_bound_dev_if == sk->sk_bound_dev_if) && |
181 | !sk->sk_bound_dev_if || | 198 | (*saddr_cmp)(sk, sk2) ) |
182 | sk2->sk_bound_dev_if == sk->sk_bound_dev_if) && | ||
183 | (!inet2->rcv_saddr || | ||
184 | !inet->rcv_saddr || | ||
185 | inet2->rcv_saddr == inet->rcv_saddr) && | ||
186 | (!sk2->sk_reuse || !sk->sk_reuse)) | ||
187 | goto fail; | 199 | goto fail; |
188 | } | ||
189 | } | 200 | } |
190 | inet->num = snum; | 201 | inet_sk(sk)->num = snum; |
191 | if (sk_unhashed(sk)) { | 202 | if (sk_unhashed(sk)) { |
192 | struct hlist_head *h = &udp_hash[snum & (UDP_HTABLE_SIZE - 1)]; | 203 | head = &udp_hash[snum & (UDP_HTABLE_SIZE - 1)]; |
193 | 204 | sk_add_node(sk, head); | |
194 | sk_add_node(sk, h); | ||
195 | sock_prot_inc_use(sk->sk_prot); | 205 | sock_prot_inc_use(sk->sk_prot); |
196 | } | 206 | } |
197 | write_unlock_bh(&udp_hash_lock); | 207 | error = 0; |
198 | return 0; | ||
199 | |||
200 | fail: | 208 | fail: |
201 | write_unlock_bh(&udp_hash_lock); | 209 | write_unlock_bh(&udp_hash_lock); |
202 | return 1; | 210 | return error; |
211 | } | ||
212 | |||
213 | static inline int ipv4_rcv_saddr_equal(const struct sock *sk1, const struct sock *sk2) | ||
214 | { | ||
215 | struct inet_sock *inet1 = inet_sk(sk1), *inet2 = inet_sk(sk2); | ||
216 | |||
217 | return ( !ipv6_only_sock(sk2) && | ||
218 | (!inet1->rcv_saddr || !inet2->rcv_saddr || | ||
219 | inet1->rcv_saddr == inet2->rcv_saddr )); | ||
203 | } | 220 | } |
204 | 221 | ||
222 | static inline int udp_v4_get_port(struct sock *sk, unsigned short snum) | ||
223 | { | ||
224 | return udp_get_port(sk, snum, ipv4_rcv_saddr_equal); | ||
225 | } | ||
226 | |||
227 | |||
205 | static void udp_v4_hash(struct sock *sk) | 228 | static void udp_v4_hash(struct sock *sk) |
206 | { | 229 | { |
207 | BUG(); | 230 | BUG(); |
@@ -429,7 +452,7 @@ static int udp_push_pending_frames(struct sock *sk, struct udp_sock *up) | |||
429 | /* | 452 | /* |
430 | * Only one fragment on the socket. | 453 | * Only one fragment on the socket. |
431 | */ | 454 | */ |
432 | if (skb->ip_summed == CHECKSUM_HW) { | 455 | if (skb->ip_summed == CHECKSUM_PARTIAL) { |
433 | skb->csum = offsetof(struct udphdr, check); | 456 | skb->csum = offsetof(struct udphdr, check); |
434 | uh->check = ~csum_tcpudp_magic(fl->fl4_src, fl->fl4_dst, | 457 | uh->check = ~csum_tcpudp_magic(fl->fl4_src, fl->fl4_dst, |
435 | up->len, IPPROTO_UDP, 0); | 458 | up->len, IPPROTO_UDP, 0); |
@@ -448,7 +471,7 @@ static int udp_push_pending_frames(struct sock *sk, struct udp_sock *up) | |||
448 | * fragments on the socket so that all csums of sk_buffs | 471 | * fragments on the socket so that all csums of sk_buffs |
449 | * should be together. | 472 | * should be together. |
450 | */ | 473 | */ |
451 | if (skb->ip_summed == CHECKSUM_HW) { | 474 | if (skb->ip_summed == CHECKSUM_PARTIAL) { |
452 | int offset = (unsigned char *)uh - skb->data; | 475 | int offset = (unsigned char *)uh - skb->data; |
453 | skb->csum = skb_checksum(skb, offset, skb->len - offset, 0); | 476 | skb->csum = skb_checksum(skb, offset, skb->len - offset, 0); |
454 | 477 | ||
@@ -603,6 +626,7 @@ int udp_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, | |||
603 | .uli_u = { .ports = | 626 | .uli_u = { .ports = |
604 | { .sport = inet->sport, | 627 | { .sport = inet->sport, |
605 | .dport = dport } } }; | 628 | .dport = dport } } }; |
629 | security_sk_classify_flow(sk, &fl); | ||
606 | err = ip_route_output_flow(&rt, &fl, sk, !(msg->msg_flags&MSG_DONTWAIT)); | 630 | err = ip_route_output_flow(&rt, &fl, sk, !(msg->msg_flags&MSG_DONTWAIT)); |
607 | if (err) | 631 | if (err) |
608 | goto out; | 632 | goto out; |
@@ -661,6 +685,16 @@ out: | |||
661 | UDP_INC_STATS_USER(UDP_MIB_OUTDATAGRAMS); | 685 | UDP_INC_STATS_USER(UDP_MIB_OUTDATAGRAMS); |
662 | return len; | 686 | return len; |
663 | } | 687 | } |
688 | /* | ||
689 | * ENOBUFS = no kernel mem, SOCK_NOSPACE = no sndbuf space. Reporting | ||
690 | * ENOBUFS might not be good (it's not tunable per se), but otherwise | ||
691 | * we don't have a good statistic (IpOutDiscards but it can be too many | ||
692 | * things). We could add another new stat but at least for now that | ||
693 | * seems like overkill. | ||
694 | */ | ||
695 | if (err == -ENOBUFS || test_bit(SOCK_NOSPACE, &sk->sk_socket->flags)) { | ||
696 | UDP_INC_STATS_USER(UDP_MIB_SNDBUFERRORS); | ||
697 | } | ||
664 | return err; | 698 | return err; |
665 | 699 | ||
666 | do_confirm: | 700 | do_confirm: |
@@ -980,6 +1014,7 @@ static int udp_encap_rcv(struct sock * sk, struct sk_buff *skb) | |||
980 | static int udp_queue_rcv_skb(struct sock * sk, struct sk_buff *skb) | 1014 | static int udp_queue_rcv_skb(struct sock * sk, struct sk_buff *skb) |
981 | { | 1015 | { |
982 | struct udp_sock *up = udp_sk(sk); | 1016 | struct udp_sock *up = udp_sk(sk); |
1017 | int rc; | ||
983 | 1018 | ||
984 | /* | 1019 | /* |
985 | * Charge it to the socket, dropping if the queue is full. | 1020 | * Charge it to the socket, dropping if the queue is full. |
@@ -1026,7 +1061,10 @@ static int udp_queue_rcv_skb(struct sock * sk, struct sk_buff *skb) | |||
1026 | skb->ip_summed = CHECKSUM_UNNECESSARY; | 1061 | skb->ip_summed = CHECKSUM_UNNECESSARY; |
1027 | } | 1062 | } |
1028 | 1063 | ||
1029 | if (sock_queue_rcv_skb(sk,skb)<0) { | 1064 | if ((rc = sock_queue_rcv_skb(sk,skb)) < 0) { |
1065 | /* Note that an ENOMEM error is charged twice */ | ||
1066 | if (rc == -ENOMEM) | ||
1067 | UDP_INC_STATS_BH(UDP_MIB_RCVBUFERRORS); | ||
1030 | UDP_INC_STATS_BH(UDP_MIB_INERRORS); | 1068 | UDP_INC_STATS_BH(UDP_MIB_INERRORS); |
1031 | kfree_skb(skb); | 1069 | kfree_skb(skb); |
1032 | return -1; | 1070 | return -1; |
@@ -1087,7 +1125,7 @@ static void udp_checksum_init(struct sk_buff *skb, struct udphdr *uh, | |||
1087 | { | 1125 | { |
1088 | if (uh->check == 0) { | 1126 | if (uh->check == 0) { |
1089 | skb->ip_summed = CHECKSUM_UNNECESSARY; | 1127 | skb->ip_summed = CHECKSUM_UNNECESSARY; |
1090 | } else if (skb->ip_summed == CHECKSUM_HW) { | 1128 | } else if (skb->ip_summed == CHECKSUM_COMPLETE) { |
1091 | if (!udp_check(uh, ulen, saddr, daddr, skb->csum)) | 1129 | if (!udp_check(uh, ulen, saddr, daddr, skb->csum)) |
1092 | skb->ip_summed = CHECKSUM_UNNECESSARY; | 1130 | skb->ip_summed = CHECKSUM_UNNECESSARY; |
1093 | } | 1131 | } |
@@ -1581,7 +1619,7 @@ EXPORT_SYMBOL(udp_disconnect); | |||
1581 | EXPORT_SYMBOL(udp_hash); | 1619 | EXPORT_SYMBOL(udp_hash); |
1582 | EXPORT_SYMBOL(udp_hash_lock); | 1620 | EXPORT_SYMBOL(udp_hash_lock); |
1583 | EXPORT_SYMBOL(udp_ioctl); | 1621 | EXPORT_SYMBOL(udp_ioctl); |
1584 | EXPORT_SYMBOL(udp_port_rover); | 1622 | EXPORT_SYMBOL(udp_get_port); |
1585 | EXPORT_SYMBOL(udp_prot); | 1623 | EXPORT_SYMBOL(udp_prot); |
1586 | EXPORT_SYMBOL(udp_sendmsg); | 1624 | EXPORT_SYMBOL(udp_sendmsg); |
1587 | EXPORT_SYMBOL(udp_poll); | 1625 | EXPORT_SYMBOL(udp_poll); |
diff --git a/net/ipv4/xfrm4_input.c b/net/ipv4/xfrm4_input.c index 817ed84511a6..040e8475f295 100644 --- a/net/ipv4/xfrm4_input.c +++ b/net/ipv4/xfrm4_input.c | |||
@@ -106,7 +106,7 @@ int xfrm4_rcv_encap(struct sk_buff *skb, __u16 encap_type) | |||
106 | if (x->mode->input(x, skb)) | 106 | if (x->mode->input(x, skb)) |
107 | goto drop; | 107 | goto drop; |
108 | 108 | ||
109 | if (x->props.mode) { | 109 | if (x->props.mode == XFRM_MODE_TUNNEL) { |
110 | decaps = 1; | 110 | decaps = 1; |
111 | break; | 111 | break; |
112 | } | 112 | } |
diff --git a/net/ipv4/xfrm4_mode_transport.c b/net/ipv4/xfrm4_mode_transport.c index a9e6b3dd19c9..92676b7e4034 100644 --- a/net/ipv4/xfrm4_mode_transport.c +++ b/net/ipv4/xfrm4_mode_transport.c | |||
@@ -21,9 +21,8 @@ | |||
21 | * On exit, skb->h will be set to the start of the payload to be processed | 21 | * On exit, skb->h will be set to the start of the payload to be processed |
22 | * by x->type->output and skb->nh will be set to the top IP header. | 22 | * by x->type->output and skb->nh will be set to the top IP header. |
23 | */ | 23 | */ |
24 | static int xfrm4_transport_output(struct sk_buff *skb) | 24 | static int xfrm4_transport_output(struct xfrm_state *x, struct sk_buff *skb) |
25 | { | 25 | { |
26 | struct xfrm_state *x; | ||
27 | struct iphdr *iph; | 26 | struct iphdr *iph; |
28 | int ihl; | 27 | int ihl; |
29 | 28 | ||
@@ -33,7 +32,6 @@ static int xfrm4_transport_output(struct sk_buff *skb) | |||
33 | ihl = iph->ihl * 4; | 32 | ihl = iph->ihl * 4; |
34 | skb->h.raw += ihl; | 33 | skb->h.raw += ihl; |
35 | 34 | ||
36 | x = skb->dst->xfrm; | ||
37 | skb->nh.raw = memmove(skb_push(skb, x->props.header_len), iph, ihl); | 35 | skb->nh.raw = memmove(skb_push(skb, x->props.header_len), iph, ihl); |
38 | return 0; | 36 | return 0; |
39 | } | 37 | } |
diff --git a/net/ipv4/xfrm4_mode_tunnel.c b/net/ipv4/xfrm4_mode_tunnel.c index 13cafbe56ce3..e23c21d31a53 100644 --- a/net/ipv4/xfrm4_mode_tunnel.c +++ b/net/ipv4/xfrm4_mode_tunnel.c | |||
@@ -33,10 +33,9 @@ static inline void ipip_ecn_decapsulate(struct sk_buff *skb) | |||
33 | * On exit, skb->h will be set to the start of the payload to be processed | 33 | * On exit, skb->h will be set to the start of the payload to be processed |
34 | * by x->type->output and skb->nh will be set to the top IP header. | 34 | * by x->type->output and skb->nh will be set to the top IP header. |
35 | */ | 35 | */ |
36 | static int xfrm4_tunnel_output(struct sk_buff *skb) | 36 | static int xfrm4_tunnel_output(struct xfrm_state *x, struct sk_buff *skb) |
37 | { | 37 | { |
38 | struct dst_entry *dst = skb->dst; | 38 | struct dst_entry *dst = skb->dst; |
39 | struct xfrm_state *x = dst->xfrm; | ||
40 | struct iphdr *iph, *top_iph; | 39 | struct iphdr *iph, *top_iph; |
41 | int flags; | 40 | int flags; |
42 | 41 | ||
diff --git a/net/ipv4/xfrm4_output.c b/net/ipv4/xfrm4_output.c index d16f863cf687..04403fb01a58 100644 --- a/net/ipv4/xfrm4_output.c +++ b/net/ipv4/xfrm4_output.c | |||
@@ -48,13 +48,13 @@ static int xfrm4_output_one(struct sk_buff *skb) | |||
48 | struct xfrm_state *x = dst->xfrm; | 48 | struct xfrm_state *x = dst->xfrm; |
49 | int err; | 49 | int err; |
50 | 50 | ||
51 | if (skb->ip_summed == CHECKSUM_HW) { | 51 | if (skb->ip_summed == CHECKSUM_PARTIAL) { |
52 | err = skb_checksum_help(skb, 0); | 52 | err = skb_checksum_help(skb); |
53 | if (err) | 53 | if (err) |
54 | goto error_nolock; | 54 | goto error_nolock; |
55 | } | 55 | } |
56 | 56 | ||
57 | if (x->props.mode) { | 57 | if (x->props.mode == XFRM_MODE_TUNNEL) { |
58 | err = xfrm4_tunnel_check_size(skb); | 58 | err = xfrm4_tunnel_check_size(skb); |
59 | if (err) | 59 | if (err) |
60 | goto error_nolock; | 60 | goto error_nolock; |
@@ -66,7 +66,7 @@ static int xfrm4_output_one(struct sk_buff *skb) | |||
66 | if (err) | 66 | if (err) |
67 | goto error; | 67 | goto error; |
68 | 68 | ||
69 | err = x->mode->output(skb); | 69 | err = x->mode->output(x, skb); |
70 | if (err) | 70 | if (err) |
71 | goto error; | 71 | goto error; |
72 | 72 | ||
@@ -85,7 +85,7 @@ static int xfrm4_output_one(struct sk_buff *skb) | |||
85 | } | 85 | } |
86 | dst = skb->dst; | 86 | dst = skb->dst; |
87 | x = dst->xfrm; | 87 | x = dst->xfrm; |
88 | } while (x && !x->props.mode); | 88 | } while (x && (x->props.mode != XFRM_MODE_TUNNEL)); |
89 | 89 | ||
90 | IPCB(skb)->flags |= IPSKB_XFRM_TRANSFORMED; | 90 | IPCB(skb)->flags |= IPSKB_XFRM_TRANSFORMED; |
91 | err = 0; | 91 | err = 0; |
diff --git a/net/ipv4/xfrm4_policy.c b/net/ipv4/xfrm4_policy.c index 8f50eae47d03..eabcd27b1767 100644 --- a/net/ipv4/xfrm4_policy.c +++ b/net/ipv4/xfrm4_policy.c | |||
@@ -21,6 +21,25 @@ static int xfrm4_dst_lookup(struct xfrm_dst **dst, struct flowi *fl) | |||
21 | return __ip_route_output_key((struct rtable**)dst, fl); | 21 | return __ip_route_output_key((struct rtable**)dst, fl); |
22 | } | 22 | } |
23 | 23 | ||
24 | static int xfrm4_get_saddr(xfrm_address_t *saddr, xfrm_address_t *daddr) | ||
25 | { | ||
26 | struct rtable *rt; | ||
27 | struct flowi fl_tunnel = { | ||
28 | .nl_u = { | ||
29 | .ip4_u = { | ||
30 | .daddr = daddr->a4, | ||
31 | }, | ||
32 | }, | ||
33 | }; | ||
34 | |||
35 | if (!xfrm4_dst_lookup((struct xfrm_dst **)&rt, &fl_tunnel)) { | ||
36 | saddr->a4 = rt->rt_src; | ||
37 | dst_release(&rt->u.dst); | ||
38 | return 0; | ||
39 | } | ||
40 | return -EHOSTUNREACH; | ||
41 | } | ||
42 | |||
24 | static struct dst_entry * | 43 | static struct dst_entry * |
25 | __xfrm4_find_bundle(struct flowi *fl, struct xfrm_policy *policy) | 44 | __xfrm4_find_bundle(struct flowi *fl, struct xfrm_policy *policy) |
26 | { | 45 | { |
@@ -33,7 +52,7 @@ __xfrm4_find_bundle(struct flowi *fl, struct xfrm_policy *policy) | |||
33 | xdst->u.rt.fl.fl4_dst == fl->fl4_dst && | 52 | xdst->u.rt.fl.fl4_dst == fl->fl4_dst && |
34 | xdst->u.rt.fl.fl4_src == fl->fl4_src && | 53 | xdst->u.rt.fl.fl4_src == fl->fl4_src && |
35 | xdst->u.rt.fl.fl4_tos == fl->fl4_tos && | 54 | xdst->u.rt.fl.fl4_tos == fl->fl4_tos && |
36 | xfrm_bundle_ok(xdst, fl, AF_INET)) { | 55 | xfrm_bundle_ok(xdst, fl, AF_INET, 0)) { |
37 | dst_clone(dst); | 56 | dst_clone(dst); |
38 | break; | 57 | break; |
39 | } | 58 | } |
@@ -93,10 +112,11 @@ __xfrm4_bundle_create(struct xfrm_policy *policy, struct xfrm_state **xfrm, int | |||
93 | 112 | ||
94 | xdst = (struct xfrm_dst *)dst1; | 113 | xdst = (struct xfrm_dst *)dst1; |
95 | xdst->route = &rt->u.dst; | 114 | xdst->route = &rt->u.dst; |
115 | xdst->genid = xfrm[i]->genid; | ||
96 | 116 | ||
97 | dst1->next = dst_prev; | 117 | dst1->next = dst_prev; |
98 | dst_prev = dst1; | 118 | dst_prev = dst1; |
99 | if (xfrm[i]->props.mode) { | 119 | if (xfrm[i]->props.mode != XFRM_MODE_TRANSPORT) { |
100 | remote = xfrm[i]->id.daddr.a4; | 120 | remote = xfrm[i]->id.daddr.a4; |
101 | local = xfrm[i]->props.saddr.a4; | 121 | local = xfrm[i]->props.saddr.a4; |
102 | tunnel = 1; | 122 | tunnel = 1; |
@@ -135,6 +155,7 @@ __xfrm4_bundle_create(struct xfrm_policy *policy, struct xfrm_state **xfrm, int | |||
135 | dst_prev->flags |= DST_HOST; | 155 | dst_prev->flags |= DST_HOST; |
136 | dst_prev->lastuse = jiffies; | 156 | dst_prev->lastuse = jiffies; |
137 | dst_prev->header_len = header_len; | 157 | dst_prev->header_len = header_len; |
158 | dst_prev->nfheader_len = 0; | ||
138 | dst_prev->trailer_len = trailer_len; | 159 | dst_prev->trailer_len = trailer_len; |
139 | memcpy(&dst_prev->metrics, &x->route->metrics, sizeof(dst_prev->metrics)); | 160 | memcpy(&dst_prev->metrics, &x->route->metrics, sizeof(dst_prev->metrics)); |
140 | 161 | ||
@@ -296,6 +317,7 @@ static struct xfrm_policy_afinfo xfrm4_policy_afinfo = { | |||
296 | .family = AF_INET, | 317 | .family = AF_INET, |
297 | .dst_ops = &xfrm4_dst_ops, | 318 | .dst_ops = &xfrm4_dst_ops, |
298 | .dst_lookup = xfrm4_dst_lookup, | 319 | .dst_lookup = xfrm4_dst_lookup, |
320 | .get_saddr = xfrm4_get_saddr, | ||
299 | .find_bundle = __xfrm4_find_bundle, | 321 | .find_bundle = __xfrm4_find_bundle, |
300 | .bundle_create = __xfrm4_bundle_create, | 322 | .bundle_create = __xfrm4_bundle_create, |
301 | .decode_session = _decode_session4, | 323 | .decode_session = _decode_session4, |
diff --git a/net/ipv4/xfrm4_state.c b/net/ipv4/xfrm4_state.c index 81e1751c966e..fe2034494d08 100644 --- a/net/ipv4/xfrm4_state.c +++ b/net/ipv4/xfrm4_state.c | |||
@@ -42,99 +42,15 @@ __xfrm4_init_tempsel(struct xfrm_state *x, struct flowi *fl, | |||
42 | x->props.saddr = tmpl->saddr; | 42 | x->props.saddr = tmpl->saddr; |
43 | if (x->props.saddr.a4 == 0) | 43 | if (x->props.saddr.a4 == 0) |
44 | x->props.saddr.a4 = saddr->a4; | 44 | x->props.saddr.a4 = saddr->a4; |
45 | if (tmpl->mode && x->props.saddr.a4 == 0) { | ||
46 | struct rtable *rt; | ||
47 | struct flowi fl_tunnel = { | ||
48 | .nl_u = { | ||
49 | .ip4_u = { | ||
50 | .daddr = x->id.daddr.a4, | ||
51 | } | ||
52 | } | ||
53 | }; | ||
54 | if (!xfrm_dst_lookup((struct xfrm_dst **)&rt, | ||
55 | &fl_tunnel, AF_INET)) { | ||
56 | x->props.saddr.a4 = rt->rt_src; | ||
57 | dst_release(&rt->u.dst); | ||
58 | } | ||
59 | } | ||
60 | x->props.mode = tmpl->mode; | 45 | x->props.mode = tmpl->mode; |
61 | x->props.reqid = tmpl->reqid; | 46 | x->props.reqid = tmpl->reqid; |
62 | x->props.family = AF_INET; | 47 | x->props.family = AF_INET; |
63 | } | 48 | } |
64 | 49 | ||
65 | static struct xfrm_state * | ||
66 | __xfrm4_state_lookup(xfrm_address_t *daddr, u32 spi, u8 proto) | ||
67 | { | ||
68 | unsigned h = __xfrm4_spi_hash(daddr, spi, proto); | ||
69 | struct xfrm_state *x; | ||
70 | |||
71 | list_for_each_entry(x, xfrm4_state_afinfo.state_byspi+h, byspi) { | ||
72 | if (x->props.family == AF_INET && | ||
73 | spi == x->id.spi && | ||
74 | daddr->a4 == x->id.daddr.a4 && | ||
75 | proto == x->id.proto) { | ||
76 | xfrm_state_hold(x); | ||
77 | return x; | ||
78 | } | ||
79 | } | ||
80 | return NULL; | ||
81 | } | ||
82 | |||
83 | static struct xfrm_state * | ||
84 | __xfrm4_find_acq(u8 mode, u32 reqid, u8 proto, | ||
85 | xfrm_address_t *daddr, xfrm_address_t *saddr, | ||
86 | int create) | ||
87 | { | ||
88 | struct xfrm_state *x, *x0; | ||
89 | unsigned h = __xfrm4_dst_hash(daddr); | ||
90 | |||
91 | x0 = NULL; | ||
92 | |||
93 | list_for_each_entry(x, xfrm4_state_afinfo.state_bydst+h, bydst) { | ||
94 | if (x->props.family == AF_INET && | ||
95 | daddr->a4 == x->id.daddr.a4 && | ||
96 | mode == x->props.mode && | ||
97 | proto == x->id.proto && | ||
98 | saddr->a4 == x->props.saddr.a4 && | ||
99 | reqid == x->props.reqid && | ||
100 | x->km.state == XFRM_STATE_ACQ && | ||
101 | !x->id.spi) { | ||
102 | x0 = x; | ||
103 | break; | ||
104 | } | ||
105 | } | ||
106 | if (!x0 && create && (x0 = xfrm_state_alloc()) != NULL) { | ||
107 | x0->sel.daddr.a4 = daddr->a4; | ||
108 | x0->sel.saddr.a4 = saddr->a4; | ||
109 | x0->sel.prefixlen_d = 32; | ||
110 | x0->sel.prefixlen_s = 32; | ||
111 | x0->props.saddr.a4 = saddr->a4; | ||
112 | x0->km.state = XFRM_STATE_ACQ; | ||
113 | x0->id.daddr.a4 = daddr->a4; | ||
114 | x0->id.proto = proto; | ||
115 | x0->props.family = AF_INET; | ||
116 | x0->props.mode = mode; | ||
117 | x0->props.reqid = reqid; | ||
118 | x0->props.family = AF_INET; | ||
119 | x0->lft.hard_add_expires_seconds = XFRM_ACQ_EXPIRES; | ||
120 | xfrm_state_hold(x0); | ||
121 | x0->timer.expires = jiffies + XFRM_ACQ_EXPIRES*HZ; | ||
122 | add_timer(&x0->timer); | ||
123 | xfrm_state_hold(x0); | ||
124 | list_add_tail(&x0->bydst, xfrm4_state_afinfo.state_bydst+h); | ||
125 | wake_up(&km_waitq); | ||
126 | } | ||
127 | if (x0) | ||
128 | xfrm_state_hold(x0); | ||
129 | return x0; | ||
130 | } | ||
131 | |||
132 | static struct xfrm_state_afinfo xfrm4_state_afinfo = { | 50 | static struct xfrm_state_afinfo xfrm4_state_afinfo = { |
133 | .family = AF_INET, | 51 | .family = AF_INET, |
134 | .init_flags = xfrm4_init_flags, | 52 | .init_flags = xfrm4_init_flags, |
135 | .init_tempsel = __xfrm4_init_tempsel, | 53 | .init_tempsel = __xfrm4_init_tempsel, |
136 | .state_lookup = __xfrm4_state_lookup, | ||
137 | .find_acq = __xfrm4_find_acq, | ||
138 | }; | 54 | }; |
139 | 55 | ||
140 | void __init xfrm4_state_init(void) | 56 | void __init xfrm4_state_init(void) |
diff --git a/net/ipv4/xfrm4_tunnel.c b/net/ipv4/xfrm4_tunnel.c index f8ceaa127c83..f110af5b1319 100644 --- a/net/ipv4/xfrm4_tunnel.c +++ b/net/ipv4/xfrm4_tunnel.c | |||
@@ -28,7 +28,7 @@ static int ipip_xfrm_rcv(struct xfrm_state *x, struct sk_buff *skb) | |||
28 | 28 | ||
29 | static int ipip_init_state(struct xfrm_state *x) | 29 | static int ipip_init_state(struct xfrm_state *x) |
30 | { | 30 | { |
31 | if (!x->props.mode) | 31 | if (x->props.mode != XFRM_MODE_TUNNEL) |
32 | return -EINVAL; | 32 | return -EINVAL; |
33 | 33 | ||
34 | if (x->encap) | 34 | if (x->encap) |
diff --git a/net/ipv6/Kconfig b/net/ipv6/Kconfig index 0ba06c0c5d39..a2d211da2aba 100644 --- a/net/ipv6/Kconfig +++ b/net/ipv6/Kconfig | |||
@@ -98,6 +98,15 @@ config INET6_IPCOMP | |||
98 | 98 | ||
99 | If unsure, say Y. | 99 | If unsure, say Y. |
100 | 100 | ||
101 | config IPV6_MIP6 | ||
102 | bool "IPv6: Mobility (EXPERIMENTAL)" | ||
103 | depends on IPV6 && EXPERIMENTAL | ||
104 | select XFRM | ||
105 | ---help--- | ||
106 | Support for IPv6 Mobility described in RFC 3775. | ||
107 | |||
108 | If unsure, say N. | ||
109 | |||
101 | config INET6_XFRM_TUNNEL | 110 | config INET6_XFRM_TUNNEL |
102 | tristate | 111 | tristate |
103 | select INET6_TUNNEL | 112 | select INET6_TUNNEL |
@@ -127,6 +136,13 @@ config INET6_XFRM_MODE_TUNNEL | |||
127 | 136 | ||
128 | If unsure, say Y. | 137 | If unsure, say Y. |
129 | 138 | ||
139 | config INET6_XFRM_MODE_ROUTEOPTIMIZATION | ||
140 | tristate "IPv6: MIPv6 route optimization mode (EXPERIMENTAL)" | ||
141 | depends on IPV6 && EXPERIMENTAL | ||
142 | select XFRM | ||
143 | ---help--- | ||
144 | Support for MIPv6 route optimization mode. | ||
145 | |||
130 | config IPV6_TUNNEL | 146 | config IPV6_TUNNEL |
131 | tristate "IPv6: IPv6-in-IPv6 tunnel" | 147 | tristate "IPv6: IPv6-in-IPv6 tunnel" |
132 | select INET6_TUNNEL | 148 | select INET6_TUNNEL |
@@ -136,3 +152,31 @@ config IPV6_TUNNEL | |||
136 | 152 | ||
137 | If unsure, say N. | 153 | If unsure, say N. |
138 | 154 | ||
155 | config IPV6_SUBTREES | ||
156 | bool "IPv6: source address based routing" | ||
157 | depends on IPV6 && EXPERIMENTAL | ||
158 | ---help--- | ||
159 | Enable routing by source address or prefix. | ||
160 | |||
161 | The destination address is still the primary routing key, so mixing | ||
162 | normal and source prefix specific routes in the same routing table | ||
163 | may sometimes lead to unintended routing behavior. This can be | ||
164 | avoided by defining different routing tables for the normal and | ||
165 | source prefix specific routes. | ||
166 | |||
167 | If unsure, say N. | ||
168 | |||
169 | config IPV6_MULTIPLE_TABLES | ||
170 | bool "IPv6: Multiple Routing Tables" | ||
171 | depends on IPV6 && EXPERIMENTAL | ||
172 | select FIB_RULES | ||
173 | ---help--- | ||
174 | Support multiple routing tables. | ||
175 | |||
176 | config IPV6_ROUTE_FWMARK | ||
177 | bool "IPv6: use netfilter MARK value as routing key" | ||
178 | depends on IPV6_MULTIPLE_TABLES && NETFILTER | ||
179 | ---help--- | ||
180 | If you say Y here, you will be able to specify different routes for | ||
181 | packets with different mark values (see iptables(8), MARK target). | ||
182 | |||
diff --git a/net/ipv6/Makefile b/net/ipv6/Makefile index 386e0a626948..0213c6612b58 100644 --- a/net/ipv6/Makefile +++ b/net/ipv6/Makefile | |||
@@ -13,6 +13,9 @@ ipv6-objs := af_inet6.o anycast.o ip6_output.o ip6_input.o addrconf.o sit.o \ | |||
13 | ipv6-$(CONFIG_XFRM) += xfrm6_policy.o xfrm6_state.o xfrm6_input.o \ | 13 | ipv6-$(CONFIG_XFRM) += xfrm6_policy.o xfrm6_state.o xfrm6_input.o \ |
14 | xfrm6_output.o | 14 | xfrm6_output.o |
15 | ipv6-$(CONFIG_NETFILTER) += netfilter.o | 15 | ipv6-$(CONFIG_NETFILTER) += netfilter.o |
16 | ipv6-$(CONFIG_IPV6_MULTIPLE_TABLES) += fib6_rules.o | ||
17 | ipv6-$(CONFIG_IPV6_MIP6) += mip6.o | ||
18 | |||
16 | ipv6-objs += $(ipv6-y) | 19 | ipv6-objs += $(ipv6-y) |
17 | 20 | ||
18 | obj-$(CONFIG_INET6_AH) += ah6.o | 21 | obj-$(CONFIG_INET6_AH) += ah6.o |
@@ -22,6 +25,7 @@ obj-$(CONFIG_INET6_XFRM_TUNNEL) += xfrm6_tunnel.o | |||
22 | obj-$(CONFIG_INET6_TUNNEL) += tunnel6.o | 25 | obj-$(CONFIG_INET6_TUNNEL) += tunnel6.o |
23 | obj-$(CONFIG_INET6_XFRM_MODE_TRANSPORT) += xfrm6_mode_transport.o | 26 | obj-$(CONFIG_INET6_XFRM_MODE_TRANSPORT) += xfrm6_mode_transport.o |
24 | obj-$(CONFIG_INET6_XFRM_MODE_TUNNEL) += xfrm6_mode_tunnel.o | 27 | obj-$(CONFIG_INET6_XFRM_MODE_TUNNEL) += xfrm6_mode_tunnel.o |
28 | obj-$(CONFIG_INET6_XFRM_MODE_ROUTEOPTIMIZATION) += xfrm6_mode_ro.o | ||
25 | obj-$(CONFIG_NETFILTER) += netfilter/ | 29 | obj-$(CONFIG_NETFILTER) += netfilter/ |
26 | 30 | ||
27 | obj-$(CONFIG_IPV6_TUNNEL) += ip6_tunnel.o | 31 | obj-$(CONFIG_IPV6_TUNNEL) += ip6_tunnel.o |
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index c7852b38e03e..c18676352397 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c | |||
@@ -48,6 +48,7 @@ | |||
48 | #include <linux/net.h> | 48 | #include <linux/net.h> |
49 | #include <linux/in6.h> | 49 | #include <linux/in6.h> |
50 | #include <linux/netdevice.h> | 50 | #include <linux/netdevice.h> |
51 | #include <linux/if_addr.h> | ||
51 | #include <linux/if_arp.h> | 52 | #include <linux/if_arp.h> |
52 | #include <linux/if_arcnet.h> | 53 | #include <linux/if_arcnet.h> |
53 | #include <linux/if_infiniband.h> | 54 | #include <linux/if_infiniband.h> |
@@ -72,6 +73,7 @@ | |||
72 | #include <net/addrconf.h> | 73 | #include <net/addrconf.h> |
73 | #include <net/tcp.h> | 74 | #include <net/tcp.h> |
74 | #include <net/ip.h> | 75 | #include <net/ip.h> |
76 | #include <net/netlink.h> | ||
75 | #include <linux/if_tunnel.h> | 77 | #include <linux/if_tunnel.h> |
76 | #include <linux/rtnetlink.h> | 78 | #include <linux/rtnetlink.h> |
77 | 79 | ||
@@ -117,9 +119,6 @@ static int ipv6_count_addresses(struct inet6_dev *idev); | |||
117 | static struct inet6_ifaddr *inet6_addr_lst[IN6_ADDR_HSIZE]; | 119 | static struct inet6_ifaddr *inet6_addr_lst[IN6_ADDR_HSIZE]; |
118 | static DEFINE_RWLOCK(addrconf_hash_lock); | 120 | static DEFINE_RWLOCK(addrconf_hash_lock); |
119 | 121 | ||
120 | /* Protects inet6 devices */ | ||
121 | DEFINE_RWLOCK(addrconf_lock); | ||
122 | |||
123 | static void addrconf_verify(unsigned long); | 122 | static void addrconf_verify(unsigned long); |
124 | 123 | ||
125 | static DEFINE_TIMER(addr_chk_timer, addrconf_verify, 0, 0); | 124 | static DEFINE_TIMER(addr_chk_timer, addrconf_verify, 0, 0); |
@@ -144,7 +143,7 @@ static int ipv6_chk_same_addr(const struct in6_addr *addr, struct net_device *de | |||
144 | 143 | ||
145 | static ATOMIC_NOTIFIER_HEAD(inet6addr_chain); | 144 | static ATOMIC_NOTIFIER_HEAD(inet6addr_chain); |
146 | 145 | ||
147 | struct ipv6_devconf ipv6_devconf = { | 146 | struct ipv6_devconf ipv6_devconf __read_mostly = { |
148 | .forwarding = 0, | 147 | .forwarding = 0, |
149 | .hop_limit = IPV6_DEFAULT_HOPLIMIT, | 148 | .hop_limit = IPV6_DEFAULT_HOPLIMIT, |
150 | .mtu6 = IPV6_MIN_MTU, | 149 | .mtu6 = IPV6_MIN_MTU, |
@@ -173,9 +172,10 @@ struct ipv6_devconf ipv6_devconf = { | |||
173 | .accept_ra_rt_info_max_plen = 0, | 172 | .accept_ra_rt_info_max_plen = 0, |
174 | #endif | 173 | #endif |
175 | #endif | 174 | #endif |
175 | .proxy_ndp = 0, | ||
176 | }; | 176 | }; |
177 | 177 | ||
178 | static struct ipv6_devconf ipv6_devconf_dflt = { | 178 | static struct ipv6_devconf ipv6_devconf_dflt __read_mostly = { |
179 | .forwarding = 0, | 179 | .forwarding = 0, |
180 | .hop_limit = IPV6_DEFAULT_HOPLIMIT, | 180 | .hop_limit = IPV6_DEFAULT_HOPLIMIT, |
181 | .mtu6 = IPV6_MIN_MTU, | 181 | .mtu6 = IPV6_MIN_MTU, |
@@ -203,6 +203,7 @@ static struct ipv6_devconf ipv6_devconf_dflt = { | |||
203 | .accept_ra_rt_info_max_plen = 0, | 203 | .accept_ra_rt_info_max_plen = 0, |
204 | #endif | 204 | #endif |
205 | #endif | 205 | #endif |
206 | .proxy_ndp = 0, | ||
206 | }; | 207 | }; |
207 | 208 | ||
208 | /* IPv6 Wildcard Address and Loopback Address defined by RFC2553 */ | 209 | /* IPv6 Wildcard Address and Loopback Address defined by RFC2553 */ |
@@ -314,6 +315,12 @@ static void addrconf_mod_timer(struct inet6_ifaddr *ifp, | |||
314 | 315 | ||
315 | /* Nobody refers to this device, we may destroy it. */ | 316 | /* Nobody refers to this device, we may destroy it. */ |
316 | 317 | ||
318 | static void in6_dev_finish_destroy_rcu(struct rcu_head *head) | ||
319 | { | ||
320 | struct inet6_dev *idev = container_of(head, struct inet6_dev, rcu); | ||
321 | kfree(idev); | ||
322 | } | ||
323 | |||
317 | void in6_dev_finish_destroy(struct inet6_dev *idev) | 324 | void in6_dev_finish_destroy(struct inet6_dev *idev) |
318 | { | 325 | { |
319 | struct net_device *dev = idev->dev; | 326 | struct net_device *dev = idev->dev; |
@@ -328,7 +335,7 @@ void in6_dev_finish_destroy(struct inet6_dev *idev) | |||
328 | return; | 335 | return; |
329 | } | 336 | } |
330 | snmp6_free_dev(idev); | 337 | snmp6_free_dev(idev); |
331 | kfree(idev); | 338 | call_rcu(&idev->rcu, in6_dev_finish_destroy_rcu); |
332 | } | 339 | } |
333 | 340 | ||
334 | static struct inet6_dev * ipv6_add_dev(struct net_device *dev) | 341 | static struct inet6_dev * ipv6_add_dev(struct net_device *dev) |
@@ -404,9 +411,8 @@ static struct inet6_dev * ipv6_add_dev(struct net_device *dev) | |||
404 | if (netif_carrier_ok(dev)) | 411 | if (netif_carrier_ok(dev)) |
405 | ndev->if_flags |= IF_READY; | 412 | ndev->if_flags |= IF_READY; |
406 | 413 | ||
407 | write_lock_bh(&addrconf_lock); | 414 | /* protected by rtnl_lock */ |
408 | dev->ip6_ptr = ndev; | 415 | rcu_assign_pointer(dev->ip6_ptr, ndev); |
409 | write_unlock_bh(&addrconf_lock); | ||
410 | 416 | ||
411 | ipv6_mc_init_dev(ndev); | 417 | ipv6_mc_init_dev(ndev); |
412 | ndev->tstamp = jiffies; | 418 | ndev->tstamp = jiffies; |
@@ -470,7 +476,7 @@ static void addrconf_forward_change(void) | |||
470 | 476 | ||
471 | read_lock(&dev_base_lock); | 477 | read_lock(&dev_base_lock); |
472 | for (dev=dev_base; dev; dev=dev->next) { | 478 | for (dev=dev_base; dev; dev=dev->next) { |
473 | read_lock(&addrconf_lock); | 479 | rcu_read_lock(); |
474 | idev = __in6_dev_get(dev); | 480 | idev = __in6_dev_get(dev); |
475 | if (idev) { | 481 | if (idev) { |
476 | int changed = (!idev->cnf.forwarding) ^ (!ipv6_devconf.forwarding); | 482 | int changed = (!idev->cnf.forwarding) ^ (!ipv6_devconf.forwarding); |
@@ -478,7 +484,7 @@ static void addrconf_forward_change(void) | |||
478 | if (changed) | 484 | if (changed) |
479 | dev_forward_change(idev); | 485 | dev_forward_change(idev); |
480 | } | 486 | } |
481 | read_unlock(&addrconf_lock); | 487 | rcu_read_unlock(); |
482 | } | 488 | } |
483 | read_unlock(&dev_base_lock); | 489 | read_unlock(&dev_base_lock); |
484 | } | 490 | } |
@@ -539,7 +545,7 @@ ipv6_add_addr(struct inet6_dev *idev, const struct in6_addr *addr, int pfxlen, | |||
539 | int hash; | 545 | int hash; |
540 | int err = 0; | 546 | int err = 0; |
541 | 547 | ||
542 | read_lock_bh(&addrconf_lock); | 548 | rcu_read_lock_bh(); |
543 | if (idev->dead) { | 549 | if (idev->dead) { |
544 | err = -ENODEV; /*XXX*/ | 550 | err = -ENODEV; /*XXX*/ |
545 | goto out2; | 551 | goto out2; |
@@ -608,7 +614,7 @@ ipv6_add_addr(struct inet6_dev *idev, const struct in6_addr *addr, int pfxlen, | |||
608 | in6_ifa_hold(ifa); | 614 | in6_ifa_hold(ifa); |
609 | write_unlock(&idev->lock); | 615 | write_unlock(&idev->lock); |
610 | out2: | 616 | out2: |
611 | read_unlock_bh(&addrconf_lock); | 617 | rcu_read_unlock_bh(); |
612 | 618 | ||
613 | if (likely(err == 0)) | 619 | if (likely(err == 0)) |
614 | atomic_notifier_call_chain(&inet6addr_chain, NETDEV_UP, ifa); | 620 | atomic_notifier_call_chain(&inet6addr_chain, NETDEV_UP, ifa); |
@@ -734,7 +740,7 @@ static void ipv6_del_addr(struct inet6_ifaddr *ifp) | |||
734 | 740 | ||
735 | if (rt && ((rt->rt6i_flags & (RTF_GATEWAY | RTF_DEFAULT)) == 0)) { | 741 | if (rt && ((rt->rt6i_flags & (RTF_GATEWAY | RTF_DEFAULT)) == 0)) { |
736 | if (onlink == 0) { | 742 | if (onlink == 0) { |
737 | ip6_del_rt(rt, NULL, NULL, NULL); | 743 | ip6_del_rt(rt); |
738 | rt = NULL; | 744 | rt = NULL; |
739 | } else if (!(rt->rt6i_flags & RTF_EXPIRES)) { | 745 | } else if (!(rt->rt6i_flags & RTF_EXPIRES)) { |
740 | rt->rt6i_expires = expires; | 746 | rt->rt6i_expires = expires; |
@@ -911,7 +917,7 @@ int ipv6_dev_get_saddr(struct net_device *daddr_dev, | |||
911 | memset(&hiscore, 0, sizeof(hiscore)); | 917 | memset(&hiscore, 0, sizeof(hiscore)); |
912 | 918 | ||
913 | read_lock(&dev_base_lock); | 919 | read_lock(&dev_base_lock); |
914 | read_lock(&addrconf_lock); | 920 | rcu_read_lock(); |
915 | 921 | ||
916 | for (dev = dev_base; dev; dev=dev->next) { | 922 | for (dev = dev_base; dev; dev=dev->next) { |
917 | struct inet6_dev *idev; | 923 | struct inet6_dev *idev; |
@@ -1032,9 +1038,27 @@ int ipv6_dev_get_saddr(struct net_device *daddr_dev, | |||
1032 | continue; | 1038 | continue; |
1033 | } | 1039 | } |
1034 | 1040 | ||
1035 | /* Rule 4: Prefer home address -- not implemented yet */ | 1041 | /* Rule 4: Prefer home address */ |
1042 | #ifdef CONFIG_IPV6_MIP6 | ||
1043 | if (hiscore.rule < 4) { | ||
1044 | if (ifa_result->flags & IFA_F_HOMEADDRESS) | ||
1045 | hiscore.attrs |= IPV6_SADDR_SCORE_HOA; | ||
1046 | hiscore.rule++; | ||
1047 | } | ||
1048 | if (ifa->flags & IFA_F_HOMEADDRESS) { | ||
1049 | score.attrs |= IPV6_SADDR_SCORE_HOA; | ||
1050 | if (!(ifa_result->flags & IFA_F_HOMEADDRESS)) { | ||
1051 | score.rule = 4; | ||
1052 | goto record_it; | ||
1053 | } | ||
1054 | } else { | ||
1055 | if (hiscore.attrs & IPV6_SADDR_SCORE_HOA) | ||
1056 | continue; | ||
1057 | } | ||
1058 | #else | ||
1036 | if (hiscore.rule < 4) | 1059 | if (hiscore.rule < 4) |
1037 | hiscore.rule++; | 1060 | hiscore.rule++; |
1061 | #endif | ||
1038 | 1062 | ||
1039 | /* Rule 5: Prefer outgoing interface */ | 1063 | /* Rule 5: Prefer outgoing interface */ |
1040 | if (hiscore.rule < 5) { | 1064 | if (hiscore.rule < 5) { |
@@ -1123,7 +1147,7 @@ record_it: | |||
1123 | } | 1147 | } |
1124 | read_unlock_bh(&idev->lock); | 1148 | read_unlock_bh(&idev->lock); |
1125 | } | 1149 | } |
1126 | read_unlock(&addrconf_lock); | 1150 | rcu_read_unlock(); |
1127 | read_unlock(&dev_base_lock); | 1151 | read_unlock(&dev_base_lock); |
1128 | 1152 | ||
1129 | if (!ifa_result) | 1153 | if (!ifa_result) |
@@ -1147,7 +1171,7 @@ int ipv6_get_lladdr(struct net_device *dev, struct in6_addr *addr) | |||
1147 | struct inet6_dev *idev; | 1171 | struct inet6_dev *idev; |
1148 | int err = -EADDRNOTAVAIL; | 1172 | int err = -EADDRNOTAVAIL; |
1149 | 1173 | ||
1150 | read_lock(&addrconf_lock); | 1174 | rcu_read_lock(); |
1151 | if ((idev = __in6_dev_get(dev)) != NULL) { | 1175 | if ((idev = __in6_dev_get(dev)) != NULL) { |
1152 | struct inet6_ifaddr *ifp; | 1176 | struct inet6_ifaddr *ifp; |
1153 | 1177 | ||
@@ -1161,7 +1185,7 @@ int ipv6_get_lladdr(struct net_device *dev, struct in6_addr *addr) | |||
1161 | } | 1185 | } |
1162 | read_unlock_bh(&idev->lock); | 1186 | read_unlock_bh(&idev->lock); |
1163 | } | 1187 | } |
1164 | read_unlock(&addrconf_lock); | 1188 | rcu_read_unlock(); |
1165 | return err; | 1189 | return err; |
1166 | } | 1190 | } |
1167 | 1191 | ||
@@ -1462,7 +1486,7 @@ static void ipv6_regen_rndid(unsigned long data) | |||
1462 | struct inet6_dev *idev = (struct inet6_dev *) data; | 1486 | struct inet6_dev *idev = (struct inet6_dev *) data; |
1463 | unsigned long expires; | 1487 | unsigned long expires; |
1464 | 1488 | ||
1465 | read_lock_bh(&addrconf_lock); | 1489 | rcu_read_lock_bh(); |
1466 | write_lock_bh(&idev->lock); | 1490 | write_lock_bh(&idev->lock); |
1467 | 1491 | ||
1468 | if (idev->dead) | 1492 | if (idev->dead) |
@@ -1486,7 +1510,7 @@ static void ipv6_regen_rndid(unsigned long data) | |||
1486 | 1510 | ||
1487 | out: | 1511 | out: |
1488 | write_unlock_bh(&idev->lock); | 1512 | write_unlock_bh(&idev->lock); |
1489 | read_unlock_bh(&addrconf_lock); | 1513 | rcu_read_unlock_bh(); |
1490 | in6_dev_put(idev); | 1514 | in6_dev_put(idev); |
1491 | } | 1515 | } |
1492 | 1516 | ||
@@ -1507,59 +1531,56 @@ static void | |||
1507 | addrconf_prefix_route(struct in6_addr *pfx, int plen, struct net_device *dev, | 1531 | addrconf_prefix_route(struct in6_addr *pfx, int plen, struct net_device *dev, |
1508 | unsigned long expires, u32 flags) | 1532 | unsigned long expires, u32 flags) |
1509 | { | 1533 | { |
1510 | struct in6_rtmsg rtmsg; | 1534 | struct fib6_config cfg = { |
1535 | .fc_table = RT6_TABLE_PREFIX, | ||
1536 | .fc_metric = IP6_RT_PRIO_ADDRCONF, | ||
1537 | .fc_ifindex = dev->ifindex, | ||
1538 | .fc_expires = expires, | ||
1539 | .fc_dst_len = plen, | ||
1540 | .fc_flags = RTF_UP | flags, | ||
1541 | }; | ||
1511 | 1542 | ||
1512 | memset(&rtmsg, 0, sizeof(rtmsg)); | 1543 | ipv6_addr_copy(&cfg.fc_dst, pfx); |
1513 | ipv6_addr_copy(&rtmsg.rtmsg_dst, pfx); | ||
1514 | rtmsg.rtmsg_dst_len = plen; | ||
1515 | rtmsg.rtmsg_metric = IP6_RT_PRIO_ADDRCONF; | ||
1516 | rtmsg.rtmsg_ifindex = dev->ifindex; | ||
1517 | rtmsg.rtmsg_info = expires; | ||
1518 | rtmsg.rtmsg_flags = RTF_UP|flags; | ||
1519 | rtmsg.rtmsg_type = RTMSG_NEWROUTE; | ||
1520 | 1544 | ||
1521 | /* Prevent useless cloning on PtP SIT. | 1545 | /* Prevent useless cloning on PtP SIT. |
1522 | This thing is done here expecting that the whole | 1546 | This thing is done here expecting that the whole |
1523 | class of non-broadcast devices need not cloning. | 1547 | class of non-broadcast devices need not cloning. |
1524 | */ | 1548 | */ |
1525 | if (dev->type == ARPHRD_SIT && (dev->flags&IFF_POINTOPOINT)) | 1549 | if (dev->type == ARPHRD_SIT && (dev->flags & IFF_POINTOPOINT)) |
1526 | rtmsg.rtmsg_flags |= RTF_NONEXTHOP; | 1550 | cfg.fc_flags |= RTF_NONEXTHOP; |
1527 | 1551 | ||
1528 | ip6_route_add(&rtmsg, NULL, NULL, NULL); | 1552 | ip6_route_add(&cfg); |
1529 | } | 1553 | } |
1530 | 1554 | ||
1531 | /* Create "default" multicast route to the interface */ | 1555 | /* Create "default" multicast route to the interface */ |
1532 | 1556 | ||
1533 | static void addrconf_add_mroute(struct net_device *dev) | 1557 | static void addrconf_add_mroute(struct net_device *dev) |
1534 | { | 1558 | { |
1535 | struct in6_rtmsg rtmsg; | 1559 | struct fib6_config cfg = { |
1560 | .fc_table = RT6_TABLE_LOCAL, | ||
1561 | .fc_metric = IP6_RT_PRIO_ADDRCONF, | ||
1562 | .fc_ifindex = dev->ifindex, | ||
1563 | .fc_dst_len = 8, | ||
1564 | .fc_flags = RTF_UP, | ||
1565 | }; | ||
1566 | |||
1567 | ipv6_addr_set(&cfg.fc_dst, htonl(0xFF000000), 0, 0, 0); | ||
1536 | 1568 | ||
1537 | memset(&rtmsg, 0, sizeof(rtmsg)); | 1569 | ip6_route_add(&cfg); |
1538 | ipv6_addr_set(&rtmsg.rtmsg_dst, | ||
1539 | htonl(0xFF000000), 0, 0, 0); | ||
1540 | rtmsg.rtmsg_dst_len = 8; | ||
1541 | rtmsg.rtmsg_metric = IP6_RT_PRIO_ADDRCONF; | ||
1542 | rtmsg.rtmsg_ifindex = dev->ifindex; | ||
1543 | rtmsg.rtmsg_flags = RTF_UP; | ||
1544 | rtmsg.rtmsg_type = RTMSG_NEWROUTE; | ||
1545 | ip6_route_add(&rtmsg, NULL, NULL, NULL); | ||
1546 | } | 1570 | } |
1547 | 1571 | ||
1548 | static void sit_route_add(struct net_device *dev) | 1572 | static void sit_route_add(struct net_device *dev) |
1549 | { | 1573 | { |
1550 | struct in6_rtmsg rtmsg; | 1574 | struct fib6_config cfg = { |
1551 | 1575 | .fc_table = RT6_TABLE_MAIN, | |
1552 | memset(&rtmsg, 0, sizeof(rtmsg)); | 1576 | .fc_metric = IP6_RT_PRIO_ADDRCONF, |
1553 | 1577 | .fc_ifindex = dev->ifindex, | |
1554 | rtmsg.rtmsg_type = RTMSG_NEWROUTE; | 1578 | .fc_dst_len = 96, |
1555 | rtmsg.rtmsg_metric = IP6_RT_PRIO_ADDRCONF; | 1579 | .fc_flags = RTF_UP | RTF_NONEXTHOP, |
1580 | }; | ||
1556 | 1581 | ||
1557 | /* prefix length - 96 bits "::d.d.d.d" */ | 1582 | /* prefix length - 96 bits "::d.d.d.d" */ |
1558 | rtmsg.rtmsg_dst_len = 96; | 1583 | ip6_route_add(&cfg); |
1559 | rtmsg.rtmsg_flags = RTF_UP|RTF_NONEXTHOP; | ||
1560 | rtmsg.rtmsg_ifindex = dev->ifindex; | ||
1561 | |||
1562 | ip6_route_add(&rtmsg, NULL, NULL, NULL); | ||
1563 | } | 1584 | } |
1564 | 1585 | ||
1565 | static void addrconf_add_lroute(struct net_device *dev) | 1586 | static void addrconf_add_lroute(struct net_device *dev) |
@@ -1660,7 +1681,7 @@ void addrconf_prefix_rcv(struct net_device *dev, u8 *opt, int len) | |||
1660 | if (rt && ((rt->rt6i_flags & (RTF_GATEWAY | RTF_DEFAULT)) == 0)) { | 1681 | if (rt && ((rt->rt6i_flags & (RTF_GATEWAY | RTF_DEFAULT)) == 0)) { |
1661 | if (rt->rt6i_flags&RTF_EXPIRES) { | 1682 | if (rt->rt6i_flags&RTF_EXPIRES) { |
1662 | if (valid_lft == 0) { | 1683 | if (valid_lft == 0) { |
1663 | ip6_del_rt(rt, NULL, NULL, NULL); | 1684 | ip6_del_rt(rt); |
1664 | rt = NULL; | 1685 | rt = NULL; |
1665 | } else { | 1686 | } else { |
1666 | rt->rt6i_expires = jiffies + rt_expires; | 1687 | rt->rt6i_expires = jiffies + rt_expires; |
@@ -1870,12 +1891,11 @@ err_exit: | |||
1870 | * Manual configuration of address on an interface | 1891 | * Manual configuration of address on an interface |
1871 | */ | 1892 | */ |
1872 | static int inet6_addr_add(int ifindex, struct in6_addr *pfx, int plen, | 1893 | static int inet6_addr_add(int ifindex, struct in6_addr *pfx, int plen, |
1873 | __u32 prefered_lft, __u32 valid_lft) | 1894 | __u8 ifa_flags, __u32 prefered_lft, __u32 valid_lft) |
1874 | { | 1895 | { |
1875 | struct inet6_ifaddr *ifp; | 1896 | struct inet6_ifaddr *ifp; |
1876 | struct inet6_dev *idev; | 1897 | struct inet6_dev *idev; |
1877 | struct net_device *dev; | 1898 | struct net_device *dev; |
1878 | __u8 ifa_flags = 0; | ||
1879 | int scope; | 1899 | int scope; |
1880 | 1900 | ||
1881 | ASSERT_RTNL(); | 1901 | ASSERT_RTNL(); |
@@ -1887,9 +1907,6 @@ static int inet6_addr_add(int ifindex, struct in6_addr *pfx, int plen, | |||
1887 | if ((dev = __dev_get_by_index(ifindex)) == NULL) | 1907 | if ((dev = __dev_get_by_index(ifindex)) == NULL) |
1888 | return -ENODEV; | 1908 | return -ENODEV; |
1889 | 1909 | ||
1890 | if (!(dev->flags&IFF_UP)) | ||
1891 | return -ENETDOWN; | ||
1892 | |||
1893 | if ((idev = addrconf_add_dev(dev)) == NULL) | 1910 | if ((idev = addrconf_add_dev(dev)) == NULL) |
1894 | return -ENOBUFS; | 1911 | return -ENOBUFS; |
1895 | 1912 | ||
@@ -1971,7 +1988,7 @@ int addrconf_add_ifaddr(void __user *arg) | |||
1971 | 1988 | ||
1972 | rtnl_lock(); | 1989 | rtnl_lock(); |
1973 | err = inet6_addr_add(ireq.ifr6_ifindex, &ireq.ifr6_addr, ireq.ifr6_prefixlen, | 1990 | err = inet6_addr_add(ireq.ifr6_ifindex, &ireq.ifr6_addr, ireq.ifr6_prefixlen, |
1974 | INFINITY_LIFE_TIME, INFINITY_LIFE_TIME); | 1991 | IFA_F_PERMANENT, INFINITY_LIFE_TIME, INFINITY_LIFE_TIME); |
1975 | rtnl_unlock(); | 1992 | rtnl_unlock(); |
1976 | return err; | 1993 | return err; |
1977 | } | 1994 | } |
@@ -2344,10 +2361,10 @@ static int addrconf_ifdown(struct net_device *dev, int how) | |||
2344 | Do not dev_put! | 2361 | Do not dev_put! |
2345 | */ | 2362 | */ |
2346 | if (how == 1) { | 2363 | if (how == 1) { |
2347 | write_lock_bh(&addrconf_lock); | ||
2348 | dev->ip6_ptr = NULL; | ||
2349 | idev->dead = 1; | 2364 | idev->dead = 1; |
2350 | write_unlock_bh(&addrconf_lock); | 2365 | |
2366 | /* protected by rtnl_lock */ | ||
2367 | rcu_assign_pointer(dev->ip6_ptr, NULL); | ||
2351 | 2368 | ||
2352 | /* Step 1.5: remove snmp6 entry */ | 2369 | /* Step 1.5: remove snmp6 entry */ |
2353 | snmp6_unregister_dev(idev); | 2370 | snmp6_unregister_dev(idev); |
@@ -2514,7 +2531,8 @@ static void addrconf_dad_start(struct inet6_ifaddr *ifp, u32 flags) | |||
2514 | spin_lock_bh(&ifp->lock); | 2531 | spin_lock_bh(&ifp->lock); |
2515 | 2532 | ||
2516 | if (dev->flags&(IFF_NOARP|IFF_LOOPBACK) || | 2533 | if (dev->flags&(IFF_NOARP|IFF_LOOPBACK) || |
2517 | !(ifp->flags&IFA_F_TENTATIVE)) { | 2534 | !(ifp->flags&IFA_F_TENTATIVE) || |
2535 | ifp->flags & IFA_F_NODAD) { | ||
2518 | ifp->flags &= ~IFA_F_TENTATIVE; | 2536 | ifp->flags &= ~IFA_F_TENTATIVE; |
2519 | spin_unlock_bh(&ifp->lock); | 2537 | spin_unlock_bh(&ifp->lock); |
2520 | read_unlock_bh(&idev->lock); | 2538 | read_unlock_bh(&idev->lock); |
@@ -2759,6 +2777,26 @@ void if6_proc_exit(void) | |||
2759 | } | 2777 | } |
2760 | #endif /* CONFIG_PROC_FS */ | 2778 | #endif /* CONFIG_PROC_FS */ |
2761 | 2779 | ||
2780 | #ifdef CONFIG_IPV6_MIP6 | ||
2781 | /* Check if address is a home address configured on any interface. */ | ||
2782 | int ipv6_chk_home_addr(struct in6_addr *addr) | ||
2783 | { | ||
2784 | int ret = 0; | ||
2785 | struct inet6_ifaddr * ifp; | ||
2786 | u8 hash = ipv6_addr_hash(addr); | ||
2787 | read_lock_bh(&addrconf_hash_lock); | ||
2788 | for (ifp = inet6_addr_lst[hash]; ifp; ifp = ifp->lst_next) { | ||
2789 | if (ipv6_addr_cmp(&ifp->addr, addr) == 0 && | ||
2790 | (ifp->flags & IFA_F_HOMEADDRESS)) { | ||
2791 | ret = 1; | ||
2792 | break; | ||
2793 | } | ||
2794 | } | ||
2795 | read_unlock_bh(&addrconf_hash_lock); | ||
2796 | return ret; | ||
2797 | } | ||
2798 | #endif | ||
2799 | |||
2762 | /* | 2800 | /* |
2763 | * Periodic address status verification | 2801 | * Periodic address status verification |
2764 | */ | 2802 | */ |
@@ -2869,66 +2907,68 @@ restart: | |||
2869 | spin_unlock_bh(&addrconf_verify_lock); | 2907 | spin_unlock_bh(&addrconf_verify_lock); |
2870 | } | 2908 | } |
2871 | 2909 | ||
2910 | static struct in6_addr *extract_addr(struct nlattr *addr, struct nlattr *local) | ||
2911 | { | ||
2912 | struct in6_addr *pfx = NULL; | ||
2913 | |||
2914 | if (addr) | ||
2915 | pfx = nla_data(addr); | ||
2916 | |||
2917 | if (local) { | ||
2918 | if (pfx && nla_memcmp(local, pfx, sizeof(*pfx))) | ||
2919 | pfx = NULL; | ||
2920 | else | ||
2921 | pfx = nla_data(local); | ||
2922 | } | ||
2923 | |||
2924 | return pfx; | ||
2925 | } | ||
2926 | |||
2927 | static struct nla_policy ifa_ipv6_policy[IFA_MAX+1] __read_mostly = { | ||
2928 | [IFA_ADDRESS] = { .len = sizeof(struct in6_addr) }, | ||
2929 | [IFA_LOCAL] = { .len = sizeof(struct in6_addr) }, | ||
2930 | [IFA_CACHEINFO] = { .len = sizeof(struct ifa_cacheinfo) }, | ||
2931 | }; | ||
2932 | |||
2872 | static int | 2933 | static int |
2873 | inet6_rtm_deladdr(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) | 2934 | inet6_rtm_deladdr(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) |
2874 | { | 2935 | { |
2875 | struct rtattr **rta = arg; | 2936 | struct ifaddrmsg *ifm; |
2876 | struct ifaddrmsg *ifm = NLMSG_DATA(nlh); | 2937 | struct nlattr *tb[IFA_MAX+1]; |
2877 | struct in6_addr *pfx; | 2938 | struct in6_addr *pfx; |
2939 | int err; | ||
2878 | 2940 | ||
2879 | pfx = NULL; | 2941 | err = nlmsg_parse(nlh, sizeof(*ifm), tb, IFA_MAX, ifa_ipv6_policy); |
2880 | if (rta[IFA_ADDRESS-1]) { | 2942 | if (err < 0) |
2881 | if (RTA_PAYLOAD(rta[IFA_ADDRESS-1]) < sizeof(*pfx)) | 2943 | return err; |
2882 | return -EINVAL; | 2944 | |
2883 | pfx = RTA_DATA(rta[IFA_ADDRESS-1]); | 2945 | ifm = nlmsg_data(nlh); |
2884 | } | 2946 | pfx = extract_addr(tb[IFA_ADDRESS], tb[IFA_LOCAL]); |
2885 | if (rta[IFA_LOCAL-1]) { | ||
2886 | if (RTA_PAYLOAD(rta[IFA_LOCAL-1]) < sizeof(*pfx) || | ||
2887 | (pfx && memcmp(pfx, RTA_DATA(rta[IFA_LOCAL-1]), sizeof(*pfx)))) | ||
2888 | return -EINVAL; | ||
2889 | pfx = RTA_DATA(rta[IFA_LOCAL-1]); | ||
2890 | } | ||
2891 | if (pfx == NULL) | 2947 | if (pfx == NULL) |
2892 | return -EINVAL; | 2948 | return -EINVAL; |
2893 | 2949 | ||
2894 | return inet6_addr_del(ifm->ifa_index, pfx, ifm->ifa_prefixlen); | 2950 | return inet6_addr_del(ifm->ifa_index, pfx, ifm->ifa_prefixlen); |
2895 | } | 2951 | } |
2896 | 2952 | ||
2897 | static int | 2953 | static int inet6_addr_modify(struct inet6_ifaddr *ifp, u8 ifa_flags, |
2898 | inet6_addr_modify(int ifindex, struct in6_addr *pfx, | 2954 | u32 prefered_lft, u32 valid_lft) |
2899 | __u32 prefered_lft, __u32 valid_lft) | ||
2900 | { | 2955 | { |
2901 | struct inet6_ifaddr *ifp = NULL; | ||
2902 | struct net_device *dev; | ||
2903 | int ifa_flags = 0; | ||
2904 | |||
2905 | if ((dev = __dev_get_by_index(ifindex)) == NULL) | ||
2906 | return -ENODEV; | ||
2907 | |||
2908 | if (!(dev->flags&IFF_UP)) | ||
2909 | return -ENETDOWN; | ||
2910 | |||
2911 | if (!valid_lft || (prefered_lft > valid_lft)) | 2956 | if (!valid_lft || (prefered_lft > valid_lft)) |
2912 | return -EINVAL; | 2957 | return -EINVAL; |
2913 | 2958 | ||
2914 | ifp = ipv6_get_ifaddr(pfx, dev, 1); | ||
2915 | if (ifp == NULL) | ||
2916 | return -ENOENT; | ||
2917 | |||
2918 | if (valid_lft == INFINITY_LIFE_TIME) | 2959 | if (valid_lft == INFINITY_LIFE_TIME) |
2919 | ifa_flags = IFA_F_PERMANENT; | 2960 | ifa_flags |= IFA_F_PERMANENT; |
2920 | else if (valid_lft >= 0x7FFFFFFF/HZ) | 2961 | else if (valid_lft >= 0x7FFFFFFF/HZ) |
2921 | valid_lft = 0x7FFFFFFF/HZ; | 2962 | valid_lft = 0x7FFFFFFF/HZ; |
2922 | 2963 | ||
2923 | if (prefered_lft == 0) | 2964 | if (prefered_lft == 0) |
2924 | ifa_flags = IFA_F_DEPRECATED; | 2965 | ifa_flags |= IFA_F_DEPRECATED; |
2925 | else if ((prefered_lft >= 0x7FFFFFFF/HZ) && | 2966 | else if ((prefered_lft >= 0x7FFFFFFF/HZ) && |
2926 | (prefered_lft != INFINITY_LIFE_TIME)) | 2967 | (prefered_lft != INFINITY_LIFE_TIME)) |
2927 | prefered_lft = 0x7FFFFFFF/HZ; | 2968 | prefered_lft = 0x7FFFFFFF/HZ; |
2928 | 2969 | ||
2929 | spin_lock_bh(&ifp->lock); | 2970 | spin_lock_bh(&ifp->lock); |
2930 | ifp->flags = (ifp->flags & ~(IFA_F_DEPRECATED|IFA_F_PERMANENT)) | ifa_flags; | 2971 | ifp->flags = (ifp->flags & ~(IFA_F_DEPRECATED | IFA_F_PERMANENT | IFA_F_NODAD | IFA_F_HOMEADDRESS)) | ifa_flags; |
2931 | |||
2932 | ifp->tstamp = jiffies; | 2972 | ifp->tstamp = jiffies; |
2933 | ifp->valid_lft = valid_lft; | 2973 | ifp->valid_lft = valid_lft; |
2934 | ifp->prefered_lft = prefered_lft; | 2974 | ifp->prefered_lft = prefered_lft; |
@@ -2936,7 +2976,6 @@ inet6_addr_modify(int ifindex, struct in6_addr *pfx, | |||
2936 | spin_unlock_bh(&ifp->lock); | 2976 | spin_unlock_bh(&ifp->lock); |
2937 | if (!(ifp->flags&IFA_F_TENTATIVE)) | 2977 | if (!(ifp->flags&IFA_F_TENTATIVE)) |
2938 | ipv6_ifa_notify(0, ifp); | 2978 | ipv6_ifa_notify(0, ifp); |
2939 | in6_ifa_put(ifp); | ||
2940 | 2979 | ||
2941 | addrconf_verify(0); | 2980 | addrconf_verify(0); |
2942 | 2981 | ||
@@ -2946,172 +2985,189 @@ inet6_addr_modify(int ifindex, struct in6_addr *pfx, | |||
2946 | static int | 2985 | static int |
2947 | inet6_rtm_newaddr(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) | 2986 | inet6_rtm_newaddr(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) |
2948 | { | 2987 | { |
2949 | struct rtattr **rta = arg; | 2988 | struct ifaddrmsg *ifm; |
2950 | struct ifaddrmsg *ifm = NLMSG_DATA(nlh); | 2989 | struct nlattr *tb[IFA_MAX+1]; |
2951 | struct in6_addr *pfx; | 2990 | struct in6_addr *pfx; |
2952 | __u32 valid_lft = INFINITY_LIFE_TIME, prefered_lft = INFINITY_LIFE_TIME; | 2991 | struct inet6_ifaddr *ifa; |
2992 | struct net_device *dev; | ||
2993 | u32 valid_lft = INFINITY_LIFE_TIME, preferred_lft = INFINITY_LIFE_TIME; | ||
2994 | u8 ifa_flags; | ||
2995 | int err; | ||
2953 | 2996 | ||
2954 | pfx = NULL; | 2997 | err = nlmsg_parse(nlh, sizeof(*ifm), tb, IFA_MAX, ifa_ipv6_policy); |
2955 | if (rta[IFA_ADDRESS-1]) { | 2998 | if (err < 0) |
2956 | if (RTA_PAYLOAD(rta[IFA_ADDRESS-1]) < sizeof(*pfx)) | 2999 | return err; |
2957 | return -EINVAL; | 3000 | |
2958 | pfx = RTA_DATA(rta[IFA_ADDRESS-1]); | 3001 | ifm = nlmsg_data(nlh); |
2959 | } | 3002 | pfx = extract_addr(tb[IFA_ADDRESS], tb[IFA_LOCAL]); |
2960 | if (rta[IFA_LOCAL-1]) { | ||
2961 | if (RTA_PAYLOAD(rta[IFA_LOCAL-1]) < sizeof(*pfx) || | ||
2962 | (pfx && memcmp(pfx, RTA_DATA(rta[IFA_LOCAL-1]), sizeof(*pfx)))) | ||
2963 | return -EINVAL; | ||
2964 | pfx = RTA_DATA(rta[IFA_LOCAL-1]); | ||
2965 | } | ||
2966 | if (pfx == NULL) | 3003 | if (pfx == NULL) |
2967 | return -EINVAL; | 3004 | return -EINVAL; |
2968 | 3005 | ||
2969 | if (rta[IFA_CACHEINFO-1]) { | 3006 | if (tb[IFA_CACHEINFO]) { |
2970 | struct ifa_cacheinfo *ci; | 3007 | struct ifa_cacheinfo *ci; |
2971 | if (RTA_PAYLOAD(rta[IFA_CACHEINFO-1]) < sizeof(*ci)) | 3008 | |
2972 | return -EINVAL; | 3009 | ci = nla_data(tb[IFA_CACHEINFO]); |
2973 | ci = RTA_DATA(rta[IFA_CACHEINFO-1]); | ||
2974 | valid_lft = ci->ifa_valid; | 3010 | valid_lft = ci->ifa_valid; |
2975 | prefered_lft = ci->ifa_prefered; | 3011 | preferred_lft = ci->ifa_prefered; |
3012 | } else { | ||
3013 | preferred_lft = INFINITY_LIFE_TIME; | ||
3014 | valid_lft = INFINITY_LIFE_TIME; | ||
2976 | } | 3015 | } |
2977 | 3016 | ||
2978 | if (nlh->nlmsg_flags & NLM_F_REPLACE) { | 3017 | dev = __dev_get_by_index(ifm->ifa_index); |
2979 | int ret; | 3018 | if (dev == NULL) |
2980 | ret = inet6_addr_modify(ifm->ifa_index, pfx, | 3019 | return -ENODEV; |
2981 | prefered_lft, valid_lft); | 3020 | |
2982 | if (ret == 0 || !(nlh->nlmsg_flags & NLM_F_CREATE)) | 3021 | /* We ignore other flags so far. */ |
2983 | return ret; | 3022 | ifa_flags = ifm->ifa_flags & (IFA_F_NODAD | IFA_F_HOMEADDRESS); |
3023 | |||
3024 | ifa = ipv6_get_ifaddr(pfx, dev, 1); | ||
3025 | if (ifa == NULL) { | ||
3026 | /* | ||
3027 | * It would be best to check for !NLM_F_CREATE here but | ||
3028 | * userspace alreay relies on not having to provide this. | ||
3029 | */ | ||
3030 | return inet6_addr_add(ifm->ifa_index, pfx, ifm->ifa_prefixlen, | ||
3031 | ifa_flags, preferred_lft, valid_lft); | ||
2984 | } | 3032 | } |
2985 | 3033 | ||
2986 | return inet6_addr_add(ifm->ifa_index, pfx, ifm->ifa_prefixlen, | 3034 | if (nlh->nlmsg_flags & NLM_F_EXCL || |
2987 | prefered_lft, valid_lft); | 3035 | !(nlh->nlmsg_flags & NLM_F_REPLACE)) |
3036 | err = -EEXIST; | ||
3037 | else | ||
3038 | err = inet6_addr_modify(ifa, ifa_flags, preferred_lft, valid_lft); | ||
3039 | |||
3040 | in6_ifa_put(ifa); | ||
3041 | |||
3042 | return err; | ||
3043 | } | ||
3044 | |||
3045 | static void put_ifaddrmsg(struct nlmsghdr *nlh, u8 prefixlen, u8 flags, | ||
3046 | u8 scope, int ifindex) | ||
3047 | { | ||
3048 | struct ifaddrmsg *ifm; | ||
2988 | 3049 | ||
3050 | ifm = nlmsg_data(nlh); | ||
3051 | ifm->ifa_family = AF_INET6; | ||
3052 | ifm->ifa_prefixlen = prefixlen; | ||
3053 | ifm->ifa_flags = flags; | ||
3054 | ifm->ifa_scope = scope; | ||
3055 | ifm->ifa_index = ifindex; | ||
2989 | } | 3056 | } |
2990 | 3057 | ||
2991 | /* Maximum length of ifa_cacheinfo attributes */ | 3058 | static int put_cacheinfo(struct sk_buff *skb, unsigned long cstamp, |
2992 | #define INET6_IFADDR_RTA_SPACE \ | 3059 | unsigned long tstamp, u32 preferred, u32 valid) |
2993 | RTA_SPACE(16) /* IFA_ADDRESS */ + \ | 3060 | { |
2994 | RTA_SPACE(sizeof(struct ifa_cacheinfo)) /* CACHEINFO */ | 3061 | struct ifa_cacheinfo ci; |
3062 | |||
3063 | ci.cstamp = (u32)(TIME_DELTA(cstamp, INITIAL_JIFFIES) / HZ * 100 | ||
3064 | + TIME_DELTA(cstamp, INITIAL_JIFFIES) % HZ * 100 / HZ); | ||
3065 | ci.tstamp = (u32)(TIME_DELTA(tstamp, INITIAL_JIFFIES) / HZ * 100 | ||
3066 | + TIME_DELTA(tstamp, INITIAL_JIFFIES) % HZ * 100 / HZ); | ||
3067 | ci.ifa_prefered = preferred; | ||
3068 | ci.ifa_valid = valid; | ||
3069 | |||
3070 | return nla_put(skb, IFA_CACHEINFO, sizeof(ci), &ci); | ||
3071 | } | ||
3072 | |||
3073 | static inline int rt_scope(int ifa_scope) | ||
3074 | { | ||
3075 | if (ifa_scope & IFA_HOST) | ||
3076 | return RT_SCOPE_HOST; | ||
3077 | else if (ifa_scope & IFA_LINK) | ||
3078 | return RT_SCOPE_LINK; | ||
3079 | else if (ifa_scope & IFA_SITE) | ||
3080 | return RT_SCOPE_SITE; | ||
3081 | else | ||
3082 | return RT_SCOPE_UNIVERSE; | ||
3083 | } | ||
3084 | |||
3085 | static inline int inet6_ifaddr_msgsize(void) | ||
3086 | { | ||
3087 | return nlmsg_total_size(sizeof(struct ifaddrmsg) + | ||
3088 | nla_total_size(16) + | ||
3089 | nla_total_size(sizeof(struct ifa_cacheinfo)) + | ||
3090 | 128); | ||
3091 | } | ||
2995 | 3092 | ||
2996 | static int inet6_fill_ifaddr(struct sk_buff *skb, struct inet6_ifaddr *ifa, | 3093 | static int inet6_fill_ifaddr(struct sk_buff *skb, struct inet6_ifaddr *ifa, |
2997 | u32 pid, u32 seq, int event, unsigned int flags) | 3094 | u32 pid, u32 seq, int event, unsigned int flags) |
2998 | { | 3095 | { |
2999 | struct ifaddrmsg *ifm; | ||
3000 | struct nlmsghdr *nlh; | 3096 | struct nlmsghdr *nlh; |
3001 | struct ifa_cacheinfo ci; | 3097 | u32 preferred, valid; |
3002 | unsigned char *b = skb->tail; | 3098 | |
3099 | nlh = nlmsg_put(skb, pid, seq, event, sizeof(struct ifaddrmsg), flags); | ||
3100 | if (nlh == NULL) | ||
3101 | return -ENOBUFS; | ||
3102 | |||
3103 | put_ifaddrmsg(nlh, ifa->prefix_len, ifa->flags, rt_scope(ifa->scope), | ||
3104 | ifa->idev->dev->ifindex); | ||
3003 | 3105 | ||
3004 | nlh = NLMSG_NEW(skb, pid, seq, event, sizeof(*ifm), flags); | ||
3005 | ifm = NLMSG_DATA(nlh); | ||
3006 | ifm->ifa_family = AF_INET6; | ||
3007 | ifm->ifa_prefixlen = ifa->prefix_len; | ||
3008 | ifm->ifa_flags = ifa->flags; | ||
3009 | ifm->ifa_scope = RT_SCOPE_UNIVERSE; | ||
3010 | if (ifa->scope&IFA_HOST) | ||
3011 | ifm->ifa_scope = RT_SCOPE_HOST; | ||
3012 | else if (ifa->scope&IFA_LINK) | ||
3013 | ifm->ifa_scope = RT_SCOPE_LINK; | ||
3014 | else if (ifa->scope&IFA_SITE) | ||
3015 | ifm->ifa_scope = RT_SCOPE_SITE; | ||
3016 | ifm->ifa_index = ifa->idev->dev->ifindex; | ||
3017 | RTA_PUT(skb, IFA_ADDRESS, 16, &ifa->addr); | ||
3018 | if (!(ifa->flags&IFA_F_PERMANENT)) { | 3106 | if (!(ifa->flags&IFA_F_PERMANENT)) { |
3019 | ci.ifa_prefered = ifa->prefered_lft; | 3107 | preferred = ifa->prefered_lft; |
3020 | ci.ifa_valid = ifa->valid_lft; | 3108 | valid = ifa->valid_lft; |
3021 | if (ci.ifa_prefered != INFINITY_LIFE_TIME) { | 3109 | if (preferred != INFINITY_LIFE_TIME) { |
3022 | long tval = (jiffies - ifa->tstamp)/HZ; | 3110 | long tval = (jiffies - ifa->tstamp)/HZ; |
3023 | ci.ifa_prefered -= tval; | 3111 | preferred -= tval; |
3024 | if (ci.ifa_valid != INFINITY_LIFE_TIME) | 3112 | if (valid != INFINITY_LIFE_TIME) |
3025 | ci.ifa_valid -= tval; | 3113 | valid -= tval; |
3026 | } | 3114 | } |
3027 | } else { | 3115 | } else { |
3028 | ci.ifa_prefered = INFINITY_LIFE_TIME; | 3116 | preferred = INFINITY_LIFE_TIME; |
3029 | ci.ifa_valid = INFINITY_LIFE_TIME; | 3117 | valid = INFINITY_LIFE_TIME; |
3030 | } | 3118 | } |
3031 | ci.cstamp = (__u32)(TIME_DELTA(ifa->cstamp, INITIAL_JIFFIES) / HZ * 100 | ||
3032 | + TIME_DELTA(ifa->cstamp, INITIAL_JIFFIES) % HZ * 100 / HZ); | ||
3033 | ci.tstamp = (__u32)(TIME_DELTA(ifa->tstamp, INITIAL_JIFFIES) / HZ * 100 | ||
3034 | + TIME_DELTA(ifa->tstamp, INITIAL_JIFFIES) % HZ * 100 / HZ); | ||
3035 | RTA_PUT(skb, IFA_CACHEINFO, sizeof(ci), &ci); | ||
3036 | nlh->nlmsg_len = skb->tail - b; | ||
3037 | return skb->len; | ||
3038 | 3119 | ||
3039 | nlmsg_failure: | 3120 | if (nla_put(skb, IFA_ADDRESS, 16, &ifa->addr) < 0 || |
3040 | rtattr_failure: | 3121 | put_cacheinfo(skb, ifa->cstamp, ifa->tstamp, preferred, valid) < 0) |
3041 | skb_trim(skb, b - skb->data); | 3122 | return nlmsg_cancel(skb, nlh); |
3042 | return -1; | 3123 | |
3124 | return nlmsg_end(skb, nlh); | ||
3043 | } | 3125 | } |
3044 | 3126 | ||
3045 | static int inet6_fill_ifmcaddr(struct sk_buff *skb, struct ifmcaddr6 *ifmca, | 3127 | static int inet6_fill_ifmcaddr(struct sk_buff *skb, struct ifmcaddr6 *ifmca, |
3046 | u32 pid, u32 seq, int event, u16 flags) | 3128 | u32 pid, u32 seq, int event, u16 flags) |
3047 | { | 3129 | { |
3048 | struct ifaddrmsg *ifm; | ||
3049 | struct nlmsghdr *nlh; | 3130 | struct nlmsghdr *nlh; |
3050 | struct ifa_cacheinfo ci; | 3131 | u8 scope = RT_SCOPE_UNIVERSE; |
3051 | unsigned char *b = skb->tail; | 3132 | int ifindex = ifmca->idev->dev->ifindex; |
3052 | |||
3053 | nlh = NLMSG_NEW(skb, pid, seq, event, sizeof(*ifm), flags); | ||
3054 | ifm = NLMSG_DATA(nlh); | ||
3055 | ifm->ifa_family = AF_INET6; | ||
3056 | ifm->ifa_prefixlen = 128; | ||
3057 | ifm->ifa_flags = IFA_F_PERMANENT; | ||
3058 | ifm->ifa_scope = RT_SCOPE_UNIVERSE; | ||
3059 | if (ipv6_addr_scope(&ifmca->mca_addr)&IFA_SITE) | ||
3060 | ifm->ifa_scope = RT_SCOPE_SITE; | ||
3061 | ifm->ifa_index = ifmca->idev->dev->ifindex; | ||
3062 | RTA_PUT(skb, IFA_MULTICAST, 16, &ifmca->mca_addr); | ||
3063 | ci.cstamp = (__u32)(TIME_DELTA(ifmca->mca_cstamp, INITIAL_JIFFIES) / HZ | ||
3064 | * 100 + TIME_DELTA(ifmca->mca_cstamp, INITIAL_JIFFIES) % HZ | ||
3065 | * 100 / HZ); | ||
3066 | ci.tstamp = (__u32)(TIME_DELTA(ifmca->mca_tstamp, INITIAL_JIFFIES) / HZ | ||
3067 | * 100 + TIME_DELTA(ifmca->mca_tstamp, INITIAL_JIFFIES) % HZ | ||
3068 | * 100 / HZ); | ||
3069 | ci.ifa_prefered = INFINITY_LIFE_TIME; | ||
3070 | ci.ifa_valid = INFINITY_LIFE_TIME; | ||
3071 | RTA_PUT(skb, IFA_CACHEINFO, sizeof(ci), &ci); | ||
3072 | nlh->nlmsg_len = skb->tail - b; | ||
3073 | return skb->len; | ||
3074 | 3133 | ||
3075 | nlmsg_failure: | 3134 | if (ipv6_addr_scope(&ifmca->mca_addr) & IFA_SITE) |
3076 | rtattr_failure: | 3135 | scope = RT_SCOPE_SITE; |
3077 | skb_trim(skb, b - skb->data); | 3136 | |
3078 | return -1; | 3137 | nlh = nlmsg_put(skb, pid, seq, event, sizeof(struct ifaddrmsg), flags); |
3138 | if (nlh == NULL) | ||
3139 | return -ENOBUFS; | ||
3140 | |||
3141 | put_ifaddrmsg(nlh, 128, IFA_F_PERMANENT, scope, ifindex); | ||
3142 | if (nla_put(skb, IFA_MULTICAST, 16, &ifmca->mca_addr) < 0 || | ||
3143 | put_cacheinfo(skb, ifmca->mca_cstamp, ifmca->mca_tstamp, | ||
3144 | INFINITY_LIFE_TIME, INFINITY_LIFE_TIME) < 0) | ||
3145 | return nlmsg_cancel(skb, nlh); | ||
3146 | |||
3147 | return nlmsg_end(skb, nlh); | ||
3079 | } | 3148 | } |
3080 | 3149 | ||
3081 | static int inet6_fill_ifacaddr(struct sk_buff *skb, struct ifacaddr6 *ifaca, | 3150 | static int inet6_fill_ifacaddr(struct sk_buff *skb, struct ifacaddr6 *ifaca, |
3082 | u32 pid, u32 seq, int event, unsigned int flags) | 3151 | u32 pid, u32 seq, int event, unsigned int flags) |
3083 | { | 3152 | { |
3084 | struct ifaddrmsg *ifm; | ||
3085 | struct nlmsghdr *nlh; | 3153 | struct nlmsghdr *nlh; |
3086 | struct ifa_cacheinfo ci; | 3154 | u8 scope = RT_SCOPE_UNIVERSE; |
3087 | unsigned char *b = skb->tail; | 3155 | int ifindex = ifaca->aca_idev->dev->ifindex; |
3088 | |||
3089 | nlh = NLMSG_NEW(skb, pid, seq, event, sizeof(*ifm), flags); | ||
3090 | ifm = NLMSG_DATA(nlh); | ||
3091 | ifm->ifa_family = AF_INET6; | ||
3092 | ifm->ifa_prefixlen = 128; | ||
3093 | ifm->ifa_flags = IFA_F_PERMANENT; | ||
3094 | ifm->ifa_scope = RT_SCOPE_UNIVERSE; | ||
3095 | if (ipv6_addr_scope(&ifaca->aca_addr)&IFA_SITE) | ||
3096 | ifm->ifa_scope = RT_SCOPE_SITE; | ||
3097 | ifm->ifa_index = ifaca->aca_idev->dev->ifindex; | ||
3098 | RTA_PUT(skb, IFA_ANYCAST, 16, &ifaca->aca_addr); | ||
3099 | ci.cstamp = (__u32)(TIME_DELTA(ifaca->aca_cstamp, INITIAL_JIFFIES) / HZ | ||
3100 | * 100 + TIME_DELTA(ifaca->aca_cstamp, INITIAL_JIFFIES) % HZ | ||
3101 | * 100 / HZ); | ||
3102 | ci.tstamp = (__u32)(TIME_DELTA(ifaca->aca_tstamp, INITIAL_JIFFIES) / HZ | ||
3103 | * 100 + TIME_DELTA(ifaca->aca_tstamp, INITIAL_JIFFIES) % HZ | ||
3104 | * 100 / HZ); | ||
3105 | ci.ifa_prefered = INFINITY_LIFE_TIME; | ||
3106 | ci.ifa_valid = INFINITY_LIFE_TIME; | ||
3107 | RTA_PUT(skb, IFA_CACHEINFO, sizeof(ci), &ci); | ||
3108 | nlh->nlmsg_len = skb->tail - b; | ||
3109 | return skb->len; | ||
3110 | 3156 | ||
3111 | nlmsg_failure: | 3157 | if (ipv6_addr_scope(&ifaca->aca_addr) & IFA_SITE) |
3112 | rtattr_failure: | 3158 | scope = RT_SCOPE_SITE; |
3113 | skb_trim(skb, b - skb->data); | 3159 | |
3114 | return -1; | 3160 | nlh = nlmsg_put(skb, pid, seq, event, sizeof(struct ifaddrmsg), flags); |
3161 | if (nlh == NULL) | ||
3162 | return -ENOBUFS; | ||
3163 | |||
3164 | put_ifaddrmsg(nlh, 128, IFA_F_PERMANENT, scope, ifindex); | ||
3165 | if (nla_put(skb, IFA_ANYCAST, 16, &ifaca->aca_addr) < 0 || | ||
3166 | put_cacheinfo(skb, ifaca->aca_cstamp, ifaca->aca_tstamp, | ||
3167 | INFINITY_LIFE_TIME, INFINITY_LIFE_TIME) < 0) | ||
3168 | return nlmsg_cancel(skb, nlh); | ||
3169 | |||
3170 | return nlmsg_end(skb, nlh); | ||
3115 | } | 3171 | } |
3116 | 3172 | ||
3117 | enum addr_type_t | 3173 | enum addr_type_t |
@@ -3222,79 +3278,74 @@ static int inet6_dump_ifacaddr(struct sk_buff *skb, struct netlink_callback *cb) | |||
3222 | return inet6_dump_addr(skb, cb, type); | 3278 | return inet6_dump_addr(skb, cb, type); |
3223 | } | 3279 | } |
3224 | 3280 | ||
3225 | static int inet6_rtm_getaddr(struct sk_buff *in_skb, | 3281 | static int inet6_rtm_getaddr(struct sk_buff *in_skb, struct nlmsghdr* nlh, |
3226 | struct nlmsghdr* nlh, void *arg) | 3282 | void *arg) |
3227 | { | 3283 | { |
3228 | struct rtattr **rta = arg; | 3284 | struct ifaddrmsg *ifm; |
3229 | struct ifaddrmsg *ifm = NLMSG_DATA(nlh); | 3285 | struct nlattr *tb[IFA_MAX+1]; |
3230 | struct in6_addr *addr = NULL; | 3286 | struct in6_addr *addr = NULL; |
3231 | struct net_device *dev = NULL; | 3287 | struct net_device *dev = NULL; |
3232 | struct inet6_ifaddr *ifa; | 3288 | struct inet6_ifaddr *ifa; |
3233 | struct sk_buff *skb; | 3289 | struct sk_buff *skb; |
3234 | int size = NLMSG_SPACE(sizeof(struct ifaddrmsg) + INET6_IFADDR_RTA_SPACE); | ||
3235 | int err; | 3290 | int err; |
3236 | 3291 | ||
3237 | if (rta[IFA_ADDRESS-1]) { | 3292 | err = nlmsg_parse(nlh, sizeof(*ifm), tb, IFA_MAX, ifa_ipv6_policy); |
3238 | if (RTA_PAYLOAD(rta[IFA_ADDRESS-1]) < sizeof(*addr)) | 3293 | if (err < 0) |
3239 | return -EINVAL; | 3294 | goto errout; |
3240 | addr = RTA_DATA(rta[IFA_ADDRESS-1]); | 3295 | |
3241 | } | 3296 | addr = extract_addr(tb[IFA_ADDRESS], tb[IFA_LOCAL]); |
3242 | if (rta[IFA_LOCAL-1]) { | 3297 | if (addr == NULL) { |
3243 | if (RTA_PAYLOAD(rta[IFA_LOCAL-1]) < sizeof(*addr) || | 3298 | err = -EINVAL; |
3244 | (addr && memcmp(addr, RTA_DATA(rta[IFA_LOCAL-1]), sizeof(*addr)))) | 3299 | goto errout; |
3245 | return -EINVAL; | ||
3246 | addr = RTA_DATA(rta[IFA_LOCAL-1]); | ||
3247 | } | 3300 | } |
3248 | if (addr == NULL) | ||
3249 | return -EINVAL; | ||
3250 | 3301 | ||
3302 | ifm = nlmsg_data(nlh); | ||
3251 | if (ifm->ifa_index) | 3303 | if (ifm->ifa_index) |
3252 | dev = __dev_get_by_index(ifm->ifa_index); | 3304 | dev = __dev_get_by_index(ifm->ifa_index); |
3253 | 3305 | ||
3254 | if ((ifa = ipv6_get_ifaddr(addr, dev, 1)) == NULL) | 3306 | if ((ifa = ipv6_get_ifaddr(addr, dev, 1)) == NULL) { |
3255 | return -EADDRNOTAVAIL; | 3307 | err = -EADDRNOTAVAIL; |
3308 | goto errout; | ||
3309 | } | ||
3256 | 3310 | ||
3257 | if ((skb = alloc_skb(size, GFP_KERNEL)) == NULL) { | 3311 | if ((skb = nlmsg_new(inet6_ifaddr_msgsize(), GFP_KERNEL)) == NULL) { |
3258 | err = -ENOBUFS; | 3312 | err = -ENOBUFS; |
3259 | goto out; | 3313 | goto errout_ifa; |
3260 | } | 3314 | } |
3261 | 3315 | ||
3262 | NETLINK_CB(skb).dst_pid = NETLINK_CB(in_skb).pid; | ||
3263 | err = inet6_fill_ifaddr(skb, ifa, NETLINK_CB(in_skb).pid, | 3316 | err = inet6_fill_ifaddr(skb, ifa, NETLINK_CB(in_skb).pid, |
3264 | nlh->nlmsg_seq, RTM_NEWADDR, 0); | 3317 | nlh->nlmsg_seq, RTM_NEWADDR, 0); |
3265 | if (err < 0) { | 3318 | if (err < 0) { |
3266 | err = -EMSGSIZE; | 3319 | kfree_skb(skb); |
3267 | goto out_free; | 3320 | goto errout_ifa; |
3268 | } | 3321 | } |
3269 | 3322 | ||
3270 | err = netlink_unicast(rtnl, skb, NETLINK_CB(in_skb).pid, MSG_DONTWAIT); | 3323 | err = rtnl_unicast(skb, NETLINK_CB(in_skb).pid); |
3271 | if (err > 0) | 3324 | errout_ifa: |
3272 | err = 0; | ||
3273 | out: | ||
3274 | in6_ifa_put(ifa); | 3325 | in6_ifa_put(ifa); |
3326 | errout: | ||
3275 | return err; | 3327 | return err; |
3276 | out_free: | ||
3277 | kfree_skb(skb); | ||
3278 | goto out; | ||
3279 | } | 3328 | } |
3280 | 3329 | ||
3281 | static void inet6_ifa_notify(int event, struct inet6_ifaddr *ifa) | 3330 | static void inet6_ifa_notify(int event, struct inet6_ifaddr *ifa) |
3282 | { | 3331 | { |
3283 | struct sk_buff *skb; | 3332 | struct sk_buff *skb; |
3284 | int size = NLMSG_SPACE(sizeof(struct ifaddrmsg) + INET6_IFADDR_RTA_SPACE); | 3333 | int err = -ENOBUFS; |
3285 | 3334 | ||
3286 | skb = alloc_skb(size, GFP_ATOMIC); | 3335 | skb = nlmsg_new(inet6_ifaddr_msgsize(), GFP_ATOMIC); |
3287 | if (!skb) { | 3336 | if (skb == NULL) |
3288 | netlink_set_err(rtnl, 0, RTNLGRP_IPV6_IFADDR, ENOBUFS); | 3337 | goto errout; |
3289 | return; | 3338 | |
3290 | } | 3339 | err = inet6_fill_ifaddr(skb, ifa, 0, 0, event, 0); |
3291 | if (inet6_fill_ifaddr(skb, ifa, current->pid, 0, event, 0) < 0) { | 3340 | if (err < 0) { |
3292 | kfree_skb(skb); | 3341 | kfree_skb(skb); |
3293 | netlink_set_err(rtnl, 0, RTNLGRP_IPV6_IFADDR, EINVAL); | 3342 | goto errout; |
3294 | return; | ||
3295 | } | 3343 | } |
3296 | NETLINK_CB(skb).dst_group = RTNLGRP_IPV6_IFADDR; | 3344 | |
3297 | netlink_broadcast(rtnl, skb, 0, RTNLGRP_IPV6_IFADDR, GFP_ATOMIC); | 3345 | err = rtnl_notify(skb, 0, RTNLGRP_IPV6_IFADDR, NULL, GFP_ATOMIC); |
3346 | errout: | ||
3347 | if (err < 0) | ||
3348 | rtnl_set_sk_err(RTNLGRP_IPV6_IFADDR, err); | ||
3298 | } | 3349 | } |
3299 | 3350 | ||
3300 | static void inline ipv6_store_devconf(struct ipv6_devconf *cnf, | 3351 | static void inline ipv6_store_devconf(struct ipv6_devconf *cnf, |
@@ -3329,6 +3380,7 @@ static void inline ipv6_store_devconf(struct ipv6_devconf *cnf, | |||
3329 | array[DEVCONF_ACCEPT_RA_RT_INFO_MAX_PLEN] = cnf->accept_ra_rt_info_max_plen; | 3380 | array[DEVCONF_ACCEPT_RA_RT_INFO_MAX_PLEN] = cnf->accept_ra_rt_info_max_plen; |
3330 | #endif | 3381 | #endif |
3331 | #endif | 3382 | #endif |
3383 | array[DEVCONF_PROXY_NDP] = cnf->proxy_ndp; | ||
3332 | } | 3384 | } |
3333 | 3385 | ||
3334 | /* Maximum length of ifinfomsg attributes */ | 3386 | /* Maximum length of ifinfomsg attributes */ |
@@ -3435,20 +3487,23 @@ static int inet6_dump_ifinfo(struct sk_buff *skb, struct netlink_callback *cb) | |||
3435 | void inet6_ifinfo_notify(int event, struct inet6_dev *idev) | 3487 | void inet6_ifinfo_notify(int event, struct inet6_dev *idev) |
3436 | { | 3488 | { |
3437 | struct sk_buff *skb; | 3489 | struct sk_buff *skb; |
3438 | int size = NLMSG_SPACE(sizeof(struct ifinfomsg) + INET6_IFINFO_RTA_SPACE); | 3490 | int payload = sizeof(struct ifinfomsg) + INET6_IFINFO_RTA_SPACE; |
3491 | int err = -ENOBUFS; | ||
3439 | 3492 | ||
3440 | skb = alloc_skb(size, GFP_ATOMIC); | 3493 | skb = nlmsg_new(nlmsg_total_size(payload), GFP_ATOMIC); |
3441 | if (!skb) { | 3494 | if (skb == NULL) |
3442 | netlink_set_err(rtnl, 0, RTNLGRP_IPV6_IFINFO, ENOBUFS); | 3495 | goto errout; |
3443 | return; | 3496 | |
3444 | } | 3497 | err = inet6_fill_ifinfo(skb, idev, 0, 0, event, 0); |
3445 | if (inet6_fill_ifinfo(skb, idev, current->pid, 0, event, 0) < 0) { | 3498 | if (err < 0) { |
3446 | kfree_skb(skb); | 3499 | kfree_skb(skb); |
3447 | netlink_set_err(rtnl, 0, RTNLGRP_IPV6_IFINFO, EINVAL); | 3500 | goto errout; |
3448 | return; | ||
3449 | } | 3501 | } |
3450 | NETLINK_CB(skb).dst_group = RTNLGRP_IPV6_IFINFO; | 3502 | |
3451 | netlink_broadcast(rtnl, skb, 0, RTNLGRP_IPV6_IFINFO, GFP_ATOMIC); | 3503 | err = rtnl_notify(skb, 0, RTNLGRP_IPV6_IFADDR, NULL, GFP_ATOMIC); |
3504 | errout: | ||
3505 | if (err < 0) | ||
3506 | rtnl_set_sk_err(RTNLGRP_IPV6_IFADDR, err); | ||
3452 | } | 3507 | } |
3453 | 3508 | ||
3454 | /* Maximum length of prefix_cacheinfo attributes */ | 3509 | /* Maximum length of prefix_cacheinfo attributes */ |
@@ -3500,20 +3555,23 @@ static void inet6_prefix_notify(int event, struct inet6_dev *idev, | |||
3500 | struct prefix_info *pinfo) | 3555 | struct prefix_info *pinfo) |
3501 | { | 3556 | { |
3502 | struct sk_buff *skb; | 3557 | struct sk_buff *skb; |
3503 | int size = NLMSG_SPACE(sizeof(struct prefixmsg) + INET6_PREFIX_RTA_SPACE); | 3558 | int payload = sizeof(struct prefixmsg) + INET6_PREFIX_RTA_SPACE; |
3559 | int err = -ENOBUFS; | ||
3504 | 3560 | ||
3505 | skb = alloc_skb(size, GFP_ATOMIC); | 3561 | skb = nlmsg_new(nlmsg_total_size(payload), GFP_ATOMIC); |
3506 | if (!skb) { | 3562 | if (skb == NULL) |
3507 | netlink_set_err(rtnl, 0, RTNLGRP_IPV6_PREFIX, ENOBUFS); | 3563 | goto errout; |
3508 | return; | 3564 | |
3509 | } | 3565 | err = inet6_fill_prefix(skb, idev, pinfo, 0, 0, event, 0); |
3510 | if (inet6_fill_prefix(skb, idev, pinfo, current->pid, 0, event, 0) < 0) { | 3566 | if (err < 0) { |
3511 | kfree_skb(skb); | 3567 | kfree_skb(skb); |
3512 | netlink_set_err(rtnl, 0, RTNLGRP_IPV6_PREFIX, EINVAL); | 3568 | goto errout; |
3513 | return; | ||
3514 | } | 3569 | } |
3515 | NETLINK_CB(skb).dst_group = RTNLGRP_IPV6_PREFIX; | 3570 | |
3516 | netlink_broadcast(rtnl, skb, 0, RTNLGRP_IPV6_PREFIX, GFP_ATOMIC); | 3571 | err = rtnl_notify(skb, 0, RTNLGRP_IPV6_PREFIX, NULL, GFP_ATOMIC); |
3572 | errout: | ||
3573 | if (err < 0) | ||
3574 | rtnl_set_sk_err(RTNLGRP_IPV6_PREFIX, err); | ||
3517 | } | 3575 | } |
3518 | 3576 | ||
3519 | static struct rtnetlink_link inet6_rtnetlink_table[RTM_NR_MSGTYPES] = { | 3577 | static struct rtnetlink_link inet6_rtnetlink_table[RTM_NR_MSGTYPES] = { |
@@ -3528,6 +3586,9 @@ static struct rtnetlink_link inet6_rtnetlink_table[RTM_NR_MSGTYPES] = { | |||
3528 | [RTM_DELROUTE - RTM_BASE] = { .doit = inet6_rtm_delroute, }, | 3586 | [RTM_DELROUTE - RTM_BASE] = { .doit = inet6_rtm_delroute, }, |
3529 | [RTM_GETROUTE - RTM_BASE] = { .doit = inet6_rtm_getroute, | 3587 | [RTM_GETROUTE - RTM_BASE] = { .doit = inet6_rtm_getroute, |
3530 | .dumpit = inet6_dump_fib, }, | 3588 | .dumpit = inet6_dump_fib, }, |
3589 | #ifdef CONFIG_IPV6_MULTIPLE_TABLES | ||
3590 | [RTM_GETRULE - RTM_BASE] = { .dumpit = fib6_rules_dump, }, | ||
3591 | #endif | ||
3531 | }; | 3592 | }; |
3532 | 3593 | ||
3533 | static void __ipv6_ifa_notify(int event, struct inet6_ifaddr *ifp) | 3594 | static void __ipv6_ifa_notify(int event, struct inet6_ifaddr *ifp) |
@@ -3536,7 +3597,7 @@ static void __ipv6_ifa_notify(int event, struct inet6_ifaddr *ifp) | |||
3536 | 3597 | ||
3537 | switch (event) { | 3598 | switch (event) { |
3538 | case RTM_NEWADDR: | 3599 | case RTM_NEWADDR: |
3539 | ip6_ins_rt(ifp->rt, NULL, NULL, NULL); | 3600 | ip6_ins_rt(ifp->rt); |
3540 | if (ifp->idev->cnf.forwarding) | 3601 | if (ifp->idev->cnf.forwarding) |
3541 | addrconf_join_anycast(ifp); | 3602 | addrconf_join_anycast(ifp); |
3542 | break; | 3603 | break; |
@@ -3545,7 +3606,7 @@ static void __ipv6_ifa_notify(int event, struct inet6_ifaddr *ifp) | |||
3545 | addrconf_leave_anycast(ifp); | 3606 | addrconf_leave_anycast(ifp); |
3546 | addrconf_leave_solict(ifp->idev, &ifp->addr); | 3607 | addrconf_leave_solict(ifp->idev, &ifp->addr); |
3547 | dst_hold(&ifp->rt->u.dst); | 3608 | dst_hold(&ifp->rt->u.dst); |
3548 | if (ip6_del_rt(ifp->rt, NULL, NULL, NULL)) | 3609 | if (ip6_del_rt(ifp->rt)) |
3549 | dst_free(&ifp->rt->u.dst); | 3610 | dst_free(&ifp->rt->u.dst); |
3550 | break; | 3611 | break; |
3551 | } | 3612 | } |
@@ -3553,10 +3614,10 @@ static void __ipv6_ifa_notify(int event, struct inet6_ifaddr *ifp) | |||
3553 | 3614 | ||
3554 | static void ipv6_ifa_notify(int event, struct inet6_ifaddr *ifp) | 3615 | static void ipv6_ifa_notify(int event, struct inet6_ifaddr *ifp) |
3555 | { | 3616 | { |
3556 | read_lock_bh(&addrconf_lock); | 3617 | rcu_read_lock_bh(); |
3557 | if (likely(ifp->idev->dead == 0)) | 3618 | if (likely(ifp->idev->dead == 0)) |
3558 | __ipv6_ifa_notify(event, ifp); | 3619 | __ipv6_ifa_notify(event, ifp); |
3559 | read_unlock_bh(&addrconf_lock); | 3620 | rcu_read_unlock_bh(); |
3560 | } | 3621 | } |
3561 | 3622 | ||
3562 | #ifdef CONFIG_SYSCTL | 3623 | #ifdef CONFIG_SYSCTL |
@@ -3653,7 +3714,7 @@ static struct addrconf_sysctl_table | |||
3653 | ctl_table addrconf_conf_dir[2]; | 3714 | ctl_table addrconf_conf_dir[2]; |
3654 | ctl_table addrconf_proto_dir[2]; | 3715 | ctl_table addrconf_proto_dir[2]; |
3655 | ctl_table addrconf_root_dir[2]; | 3716 | ctl_table addrconf_root_dir[2]; |
3656 | } addrconf_sysctl = { | 3717 | } addrconf_sysctl __read_mostly = { |
3657 | .sysctl_header = NULL, | 3718 | .sysctl_header = NULL, |
3658 | .addrconf_vars = { | 3719 | .addrconf_vars = { |
3659 | { | 3720 | { |
@@ -3843,6 +3904,14 @@ static struct addrconf_sysctl_table | |||
3843 | #endif | 3904 | #endif |
3844 | #endif | 3905 | #endif |
3845 | { | 3906 | { |
3907 | .ctl_name = NET_IPV6_PROXY_NDP, | ||
3908 | .procname = "proxy_ndp", | ||
3909 | .data = &ipv6_devconf.proxy_ndp, | ||
3910 | .maxlen = sizeof(int), | ||
3911 | .mode = 0644, | ||
3912 | .proc_handler = &proc_dointvec, | ||
3913 | }, | ||
3914 | { | ||
3846 | .ctl_name = 0, /* sentinel */ | 3915 | .ctl_name = 0, /* sentinel */ |
3847 | } | 3916 | } |
3848 | }, | 3917 | }, |
diff --git a/net/ipv6/af_inet6.c b/net/ipv6/af_inet6.c index ac85e9c532c2..bf6e8aff19d4 100644 --- a/net/ipv6/af_inet6.c +++ b/net/ipv6/af_inet6.c | |||
@@ -59,6 +59,9 @@ | |||
59 | #ifdef CONFIG_IPV6_TUNNEL | 59 | #ifdef CONFIG_IPV6_TUNNEL |
60 | #include <net/ip6_tunnel.h> | 60 | #include <net/ip6_tunnel.h> |
61 | #endif | 61 | #endif |
62 | #ifdef CONFIG_IPV6_MIP6 | ||
63 | #include <net/mip6.h> | ||
64 | #endif | ||
62 | 65 | ||
63 | #include <asm/uaccess.h> | 66 | #include <asm/uaccess.h> |
64 | #include <asm/system.h> | 67 | #include <asm/system.h> |
@@ -67,7 +70,7 @@ MODULE_AUTHOR("Cast of dozens"); | |||
67 | MODULE_DESCRIPTION("IPv6 protocol stack for Linux"); | 70 | MODULE_DESCRIPTION("IPv6 protocol stack for Linux"); |
68 | MODULE_LICENSE("GPL"); | 71 | MODULE_LICENSE("GPL"); |
69 | 72 | ||
70 | int sysctl_ipv6_bindv6only; | 73 | int sysctl_ipv6_bindv6only __read_mostly; |
71 | 74 | ||
72 | /* The inetsw table contains everything that inet_create needs to | 75 | /* The inetsw table contains everything that inet_create needs to |
73 | * build a new socket. | 76 | * build a new socket. |
@@ -637,6 +640,7 @@ int inet6_sk_rebuild_header(struct sock *sk) | |||
637 | fl.oif = sk->sk_bound_dev_if; | 640 | fl.oif = sk->sk_bound_dev_if; |
638 | fl.fl_ip_dport = inet->dport; | 641 | fl.fl_ip_dport = inet->dport; |
639 | fl.fl_ip_sport = inet->sport; | 642 | fl.fl_ip_sport = inet->sport; |
643 | security_sk_classify_flow(sk, &fl); | ||
640 | 644 | ||
641 | if (np->opt && np->opt->srcrt) { | 645 | if (np->opt && np->opt->srcrt) { |
642 | struct rt0_hdr *rt0 = (struct rt0_hdr *) np->opt->srcrt; | 646 | struct rt0_hdr *rt0 = (struct rt0_hdr *) np->opt->srcrt; |
@@ -658,7 +662,7 @@ int inet6_sk_rebuild_header(struct sock *sk) | |||
658 | return err; | 662 | return err; |
659 | } | 663 | } |
660 | 664 | ||
661 | __ip6_dst_store(sk, dst, NULL); | 665 | __ip6_dst_store(sk, dst, NULL, NULL); |
662 | } | 666 | } |
663 | 667 | ||
664 | return 0; | 668 | return 0; |
@@ -757,6 +761,8 @@ static int __init inet6_init(void) | |||
757 | struct list_head *r; | 761 | struct list_head *r; |
758 | int err; | 762 | int err; |
759 | 763 | ||
764 | BUILD_BUG_ON(sizeof(struct inet6_skb_parm) > sizeof(dummy_skb->cb)); | ||
765 | |||
760 | #ifdef MODULE | 766 | #ifdef MODULE |
761 | #if 0 /* FIXME --RR */ | 767 | #if 0 /* FIXME --RR */ |
762 | if (!mod_member_present(&__this_module, can_unload)) | 768 | if (!mod_member_present(&__this_module, can_unload)) |
@@ -766,11 +772,6 @@ static int __init inet6_init(void) | |||
766 | #endif | 772 | #endif |
767 | #endif | 773 | #endif |
768 | 774 | ||
769 | if (sizeof(struct inet6_skb_parm) > sizeof(dummy_skb->cb)) { | ||
770 | printk(KERN_CRIT "inet6_proto_init: size fault\n"); | ||
771 | return -EINVAL; | ||
772 | } | ||
773 | |||
774 | err = proto_register(&tcpv6_prot, 1); | 775 | err = proto_register(&tcpv6_prot, 1); |
775 | if (err) | 776 | if (err) |
776 | goto out; | 777 | goto out; |
@@ -856,6 +857,9 @@ static int __init inet6_init(void) | |||
856 | ipv6_frag_init(); | 857 | ipv6_frag_init(); |
857 | ipv6_nodata_init(); | 858 | ipv6_nodata_init(); |
858 | ipv6_destopt_init(); | 859 | ipv6_destopt_init(); |
860 | #ifdef CONFIG_IPV6_MIP6 | ||
861 | mip6_init(); | ||
862 | #endif | ||
859 | 863 | ||
860 | /* Init v6 transport protocols. */ | 864 | /* Init v6 transport protocols. */ |
861 | udpv6_init(); | 865 | udpv6_init(); |
@@ -919,6 +923,9 @@ static void __exit inet6_exit(void) | |||
919 | tcp6_proc_exit(); | 923 | tcp6_proc_exit(); |
920 | raw6_proc_exit(); | 924 | raw6_proc_exit(); |
921 | #endif | 925 | #endif |
926 | #ifdef CONFIG_IPV6_MIP6 | ||
927 | mip6_fini(); | ||
928 | #endif | ||
922 | /* Cleanup code parts. */ | 929 | /* Cleanup code parts. */ |
923 | sit_cleanup(); | 930 | sit_cleanup(); |
924 | ip6_flowlabel_cleanup(); | 931 | ip6_flowlabel_cleanup(); |
diff --git a/net/ipv6/ah6.c b/net/ipv6/ah6.c index 00ffa7bc6c9f..b0d83e8e4252 100644 --- a/net/ipv6/ah6.c +++ b/net/ipv6/ah6.c | |||
@@ -74,6 +74,66 @@ bad: | |||
74 | return 0; | 74 | return 0; |
75 | } | 75 | } |
76 | 76 | ||
77 | #ifdef CONFIG_IPV6_MIP6 | ||
78 | /** | ||
79 | * ipv6_rearrange_destopt - rearrange IPv6 destination options header | ||
80 | * @iph: IPv6 header | ||
81 | * @destopt: destionation options header | ||
82 | */ | ||
83 | static void ipv6_rearrange_destopt(struct ipv6hdr *iph, struct ipv6_opt_hdr *destopt) | ||
84 | { | ||
85 | u8 *opt = (u8 *)destopt; | ||
86 | int len = ipv6_optlen(destopt); | ||
87 | int off = 0; | ||
88 | int optlen = 0; | ||
89 | |||
90 | off += 2; | ||
91 | len -= 2; | ||
92 | |||
93 | while (len > 0) { | ||
94 | |||
95 | switch (opt[off]) { | ||
96 | |||
97 | case IPV6_TLV_PAD0: | ||
98 | optlen = 1; | ||
99 | break; | ||
100 | default: | ||
101 | if (len < 2) | ||
102 | goto bad; | ||
103 | optlen = opt[off+1]+2; | ||
104 | if (len < optlen) | ||
105 | goto bad; | ||
106 | |||
107 | /* Rearrange the source address in @iph and the | ||
108 | * addresses in home address option for final source. | ||
109 | * See 11.3.2 of RFC 3775 for details. | ||
110 | */ | ||
111 | if (opt[off] == IPV6_TLV_HAO) { | ||
112 | struct in6_addr final_addr; | ||
113 | struct ipv6_destopt_hao *hao; | ||
114 | |||
115 | hao = (struct ipv6_destopt_hao *)&opt[off]; | ||
116 | if (hao->length != sizeof(hao->addr)) { | ||
117 | if (net_ratelimit()) | ||
118 | printk(KERN_WARNING "destopt hao: invalid header length: %u\n", hao->length); | ||
119 | goto bad; | ||
120 | } | ||
121 | ipv6_addr_copy(&final_addr, &hao->addr); | ||
122 | ipv6_addr_copy(&hao->addr, &iph->saddr); | ||
123 | ipv6_addr_copy(&iph->saddr, &final_addr); | ||
124 | } | ||
125 | break; | ||
126 | } | ||
127 | |||
128 | off += optlen; | ||
129 | len -= optlen; | ||
130 | } | ||
131 | /* Note: ok if len == 0 */ | ||
132 | bad: | ||
133 | return; | ||
134 | } | ||
135 | #endif | ||
136 | |||
77 | /** | 137 | /** |
78 | * ipv6_rearrange_rthdr - rearrange IPv6 routing header | 138 | * ipv6_rearrange_rthdr - rearrange IPv6 routing header |
79 | * @iph: IPv6 header | 139 | * @iph: IPv6 header |
@@ -113,7 +173,7 @@ static void ipv6_rearrange_rthdr(struct ipv6hdr *iph, struct ipv6_rt_hdr *rthdr) | |||
113 | ipv6_addr_copy(&iph->daddr, &final_addr); | 173 | ipv6_addr_copy(&iph->daddr, &final_addr); |
114 | } | 174 | } |
115 | 175 | ||
116 | static int ipv6_clear_mutable_options(struct ipv6hdr *iph, int len) | 176 | static int ipv6_clear_mutable_options(struct ipv6hdr *iph, int len, int dir) |
117 | { | 177 | { |
118 | union { | 178 | union { |
119 | struct ipv6hdr *iph; | 179 | struct ipv6hdr *iph; |
@@ -128,8 +188,12 @@ static int ipv6_clear_mutable_options(struct ipv6hdr *iph, int len) | |||
128 | 188 | ||
129 | while (exthdr.raw < end) { | 189 | while (exthdr.raw < end) { |
130 | switch (nexthdr) { | 190 | switch (nexthdr) { |
131 | case NEXTHDR_HOP: | ||
132 | case NEXTHDR_DEST: | 191 | case NEXTHDR_DEST: |
192 | #ifdef CONFIG_IPV6_MIP6 | ||
193 | if (dir == XFRM_POLICY_OUT) | ||
194 | ipv6_rearrange_destopt(iph, exthdr.opth); | ||
195 | #endif | ||
196 | case NEXTHDR_HOP: | ||
133 | if (!zero_out_mutable_opts(exthdr.opth)) { | 197 | if (!zero_out_mutable_opts(exthdr.opth)) { |
134 | LIMIT_NETDEBUG( | 198 | LIMIT_NETDEBUG( |
135 | KERN_WARNING "overrun %sopts\n", | 199 | KERN_WARNING "overrun %sopts\n", |
@@ -164,6 +228,9 @@ static int ah6_output(struct xfrm_state *x, struct sk_buff *skb) | |||
164 | u8 nexthdr; | 228 | u8 nexthdr; |
165 | char tmp_base[8]; | 229 | char tmp_base[8]; |
166 | struct { | 230 | struct { |
231 | #ifdef CONFIG_IPV6_MIP6 | ||
232 | struct in6_addr saddr; | ||
233 | #endif | ||
167 | struct in6_addr daddr; | 234 | struct in6_addr daddr; |
168 | char hdrs[0]; | 235 | char hdrs[0]; |
169 | } *tmp_ext; | 236 | } *tmp_ext; |
@@ -188,10 +255,15 @@ static int ah6_output(struct xfrm_state *x, struct sk_buff *skb) | |||
188 | err = -ENOMEM; | 255 | err = -ENOMEM; |
189 | goto error; | 256 | goto error; |
190 | } | 257 | } |
258 | #ifdef CONFIG_IPV6_MIP6 | ||
259 | memcpy(tmp_ext, &top_iph->saddr, extlen); | ||
260 | #else | ||
191 | memcpy(tmp_ext, &top_iph->daddr, extlen); | 261 | memcpy(tmp_ext, &top_iph->daddr, extlen); |
262 | #endif | ||
192 | err = ipv6_clear_mutable_options(top_iph, | 263 | err = ipv6_clear_mutable_options(top_iph, |
193 | extlen - sizeof(*tmp_ext) + | 264 | extlen - sizeof(*tmp_ext) + |
194 | sizeof(*top_iph)); | 265 | sizeof(*top_iph), |
266 | XFRM_POLICY_OUT); | ||
195 | if (err) | 267 | if (err) |
196 | goto error_free_iph; | 268 | goto error_free_iph; |
197 | } | 269 | } |
@@ -222,7 +294,11 @@ static int ah6_output(struct xfrm_state *x, struct sk_buff *skb) | |||
222 | 294 | ||
223 | memcpy(top_iph, tmp_base, sizeof(tmp_base)); | 295 | memcpy(top_iph, tmp_base, sizeof(tmp_base)); |
224 | if (tmp_ext) { | 296 | if (tmp_ext) { |
297 | #ifdef CONFIG_IPV6_MIP6 | ||
298 | memcpy(&top_iph->saddr, tmp_ext, extlen); | ||
299 | #else | ||
225 | memcpy(&top_iph->daddr, tmp_ext, extlen); | 300 | memcpy(&top_iph->daddr, tmp_ext, extlen); |
301 | #endif | ||
226 | error_free_iph: | 302 | error_free_iph: |
227 | kfree(tmp_ext); | 303 | kfree(tmp_ext); |
228 | } | 304 | } |
@@ -282,7 +358,7 @@ static int ah6_input(struct xfrm_state *x, struct sk_buff *skb) | |||
282 | if (!tmp_hdr) | 358 | if (!tmp_hdr) |
283 | goto out; | 359 | goto out; |
284 | memcpy(tmp_hdr, skb->nh.raw, hdr_len); | 360 | memcpy(tmp_hdr, skb->nh.raw, hdr_len); |
285 | if (ipv6_clear_mutable_options(skb->nh.ipv6h, hdr_len)) | 361 | if (ipv6_clear_mutable_options(skb->nh.ipv6h, hdr_len, XFRM_POLICY_IN)) |
286 | goto free_out; | 362 | goto free_out; |
287 | skb->nh.ipv6h->priority = 0; | 363 | skb->nh.ipv6h->priority = 0; |
288 | skb->nh.ipv6h->flow_lbl[0] = 0; | 364 | skb->nh.ipv6h->flow_lbl[0] = 0; |
@@ -398,7 +474,7 @@ static int ah6_init_state(struct xfrm_state *x) | |||
398 | goto error; | 474 | goto error; |
399 | 475 | ||
400 | x->props.header_len = XFRM_ALIGN8(sizeof(struct ipv6_auth_hdr) + ahp->icv_trunc_len); | 476 | x->props.header_len = XFRM_ALIGN8(sizeof(struct ipv6_auth_hdr) + ahp->icv_trunc_len); |
401 | if (x->props.mode) | 477 | if (x->props.mode == XFRM_MODE_TUNNEL) |
402 | x->props.header_len += sizeof(struct ipv6hdr); | 478 | x->props.header_len += sizeof(struct ipv6hdr); |
403 | x->data = ahp; | 479 | x->data = ahp; |
404 | 480 | ||
@@ -435,7 +511,8 @@ static struct xfrm_type ah6_type = | |||
435 | .init_state = ah6_init_state, | 511 | .init_state = ah6_init_state, |
436 | .destructor = ah6_destroy, | 512 | .destructor = ah6_destroy, |
437 | .input = ah6_input, | 513 | .input = ah6_input, |
438 | .output = ah6_output | 514 | .output = ah6_output, |
515 | .hdr_offset = xfrm6_find_1stfragopt, | ||
439 | }; | 516 | }; |
440 | 517 | ||
441 | static struct inet6_protocol ah6_protocol = { | 518 | static struct inet6_protocol ah6_protocol = { |
diff --git a/net/ipv6/anycast.c b/net/ipv6/anycast.c index f6881d7a0385..a9604764e015 100644 --- a/net/ipv6/anycast.c +++ b/net/ipv6/anycast.c | |||
@@ -56,7 +56,7 @@ ip6_onlink(struct in6_addr *addr, struct net_device *dev) | |||
56 | int onlink; | 56 | int onlink; |
57 | 57 | ||
58 | onlink = 0; | 58 | onlink = 0; |
59 | read_lock(&addrconf_lock); | 59 | rcu_read_lock(); |
60 | idev = __in6_dev_get(dev); | 60 | idev = __in6_dev_get(dev); |
61 | if (idev) { | 61 | if (idev) { |
62 | read_lock_bh(&idev->lock); | 62 | read_lock_bh(&idev->lock); |
@@ -68,7 +68,7 @@ ip6_onlink(struct in6_addr *addr, struct net_device *dev) | |||
68 | } | 68 | } |
69 | read_unlock_bh(&idev->lock); | 69 | read_unlock_bh(&idev->lock); |
70 | } | 70 | } |
71 | read_unlock(&addrconf_lock); | 71 | rcu_read_unlock(); |
72 | return onlink; | 72 | return onlink; |
73 | } | 73 | } |
74 | 74 | ||
@@ -335,7 +335,7 @@ int ipv6_dev_ac_inc(struct net_device *dev, struct in6_addr *addr) | |||
335 | write_unlock_bh(&idev->lock); | 335 | write_unlock_bh(&idev->lock); |
336 | 336 | ||
337 | dst_hold(&rt->u.dst); | 337 | dst_hold(&rt->u.dst); |
338 | if (ip6_ins_rt(rt, NULL, NULL, NULL)) | 338 | if (ip6_ins_rt(rt)) |
339 | dst_release(&rt->u.dst); | 339 | dst_release(&rt->u.dst); |
340 | 340 | ||
341 | addrconf_join_solict(dev, &aca->aca_addr); | 341 | addrconf_join_solict(dev, &aca->aca_addr); |
@@ -378,7 +378,7 @@ int __ipv6_dev_ac_dec(struct inet6_dev *idev, struct in6_addr *addr) | |||
378 | addrconf_leave_solict(idev, &aca->aca_addr); | 378 | addrconf_leave_solict(idev, &aca->aca_addr); |
379 | 379 | ||
380 | dst_hold(&aca->aca_rt->u.dst); | 380 | dst_hold(&aca->aca_rt->u.dst); |
381 | if (ip6_del_rt(aca->aca_rt, NULL, NULL, NULL)) | 381 | if (ip6_del_rt(aca->aca_rt)) |
382 | dst_free(&aca->aca_rt->u.dst); | 382 | dst_free(&aca->aca_rt->u.dst); |
383 | else | 383 | else |
384 | dst_release(&aca->aca_rt->u.dst); | 384 | dst_release(&aca->aca_rt->u.dst); |
diff --git a/net/ipv6/datagram.c b/net/ipv6/datagram.c index 3b55b4c8e2d1..7206747022fc 100644 --- a/net/ipv6/datagram.c +++ b/net/ipv6/datagram.c | |||
@@ -156,6 +156,8 @@ ipv4_connected: | |||
156 | if (!fl.oif && (addr_type&IPV6_ADDR_MULTICAST)) | 156 | if (!fl.oif && (addr_type&IPV6_ADDR_MULTICAST)) |
157 | fl.oif = np->mcast_oif; | 157 | fl.oif = np->mcast_oif; |
158 | 158 | ||
159 | security_sk_classify_flow(sk, &fl); | ||
160 | |||
159 | if (flowlabel) { | 161 | if (flowlabel) { |
160 | if (flowlabel->opt && flowlabel->opt->srcrt) { | 162 | if (flowlabel->opt && flowlabel->opt->srcrt) { |
161 | struct rt0_hdr *rt0 = (struct rt0_hdr *) flowlabel->opt->srcrt; | 163 | struct rt0_hdr *rt0 = (struct rt0_hdr *) flowlabel->opt->srcrt; |
@@ -191,7 +193,12 @@ ipv4_connected: | |||
191 | 193 | ||
192 | ip6_dst_store(sk, dst, | 194 | ip6_dst_store(sk, dst, |
193 | ipv6_addr_equal(&fl.fl6_dst, &np->daddr) ? | 195 | ipv6_addr_equal(&fl.fl6_dst, &np->daddr) ? |
194 | &np->daddr : NULL); | 196 | &np->daddr : NULL, |
197 | #ifdef CONFIG_IPV6_SUBTREES | ||
198 | ipv6_addr_equal(&fl.fl6_src, &np->saddr) ? | ||
199 | &np->saddr : | ||
200 | #endif | ||
201 | NULL); | ||
195 | 202 | ||
196 | sk->sk_state = TCP_ESTABLISHED; | 203 | sk->sk_state = TCP_ESTABLISHED; |
197 | out: | 204 | out: |
@@ -641,10 +648,13 @@ int datagram_send_ctl(struct msghdr *msg, struct flowi *fl, | |||
641 | 648 | ||
642 | rthdr = (struct ipv6_rt_hdr *)CMSG_DATA(cmsg); | 649 | rthdr = (struct ipv6_rt_hdr *)CMSG_DATA(cmsg); |
643 | 650 | ||
644 | /* | 651 | switch (rthdr->type) { |
645 | * TYPE 0 | 652 | case IPV6_SRCRT_TYPE_0: |
646 | */ | 653 | #ifdef CONFIG_IPV6_MIP6 |
647 | if (rthdr->type) { | 654 | case IPV6_SRCRT_TYPE_2: |
655 | #endif | ||
656 | break; | ||
657 | default: | ||
648 | err = -EINVAL; | 658 | err = -EINVAL; |
649 | goto exit_f; | 659 | goto exit_f; |
650 | } | 660 | } |
diff --git a/net/ipv6/esp6.c b/net/ipv6/esp6.c index 2ebfd281e721..e78680a9985b 100644 --- a/net/ipv6/esp6.c +++ b/net/ipv6/esp6.c | |||
@@ -99,8 +99,13 @@ static int esp6_output(struct xfrm_state *x, struct sk_buff *skb) | |||
99 | esph->seq_no = htonl(++x->replay.oseq); | 99 | esph->seq_no = htonl(++x->replay.oseq); |
100 | xfrm_aevent_doreplay(x); | 100 | xfrm_aevent_doreplay(x); |
101 | 101 | ||
102 | if (esp->conf.ivlen) | 102 | if (esp->conf.ivlen) { |
103 | if (unlikely(!esp->conf.ivinitted)) { | ||
104 | get_random_bytes(esp->conf.ivec, esp->conf.ivlen); | ||
105 | esp->conf.ivinitted = 1; | ||
106 | } | ||
103 | crypto_blkcipher_set_iv(tfm, esp->conf.ivec, esp->conf.ivlen); | 107 | crypto_blkcipher_set_iv(tfm, esp->conf.ivec, esp->conf.ivlen); |
108 | } | ||
104 | 109 | ||
105 | do { | 110 | do { |
106 | struct scatterlist *sg = &esp->sgbuf[0]; | 111 | struct scatterlist *sg = &esp->sgbuf[0]; |
@@ -237,7 +242,7 @@ static u32 esp6_get_max_size(struct xfrm_state *x, int mtu) | |||
237 | struct esp_data *esp = x->data; | 242 | struct esp_data *esp = x->data; |
238 | u32 blksize = ALIGN(crypto_blkcipher_blocksize(esp->conf.tfm), 4); | 243 | u32 blksize = ALIGN(crypto_blkcipher_blocksize(esp->conf.tfm), 4); |
239 | 244 | ||
240 | if (x->props.mode) { | 245 | if (x->props.mode == XFRM_MODE_TUNNEL) { |
241 | mtu = ALIGN(mtu + 2, blksize); | 246 | mtu = ALIGN(mtu + 2, blksize); |
242 | } else { | 247 | } else { |
243 | /* The worst case. */ | 248 | /* The worst case. */ |
@@ -353,12 +358,12 @@ static int esp6_init_state(struct xfrm_state *x) | |||
353 | esp->conf.ivec = kmalloc(esp->conf.ivlen, GFP_KERNEL); | 358 | esp->conf.ivec = kmalloc(esp->conf.ivlen, GFP_KERNEL); |
354 | if (unlikely(esp->conf.ivec == NULL)) | 359 | if (unlikely(esp->conf.ivec == NULL)) |
355 | goto error; | 360 | goto error; |
356 | get_random_bytes(esp->conf.ivec, esp->conf.ivlen); | 361 | esp->conf.ivinitted = 0; |
357 | } | 362 | } |
358 | if (crypto_blkcipher_setkey(tfm, esp->conf.key, esp->conf.key_len)) | 363 | if (crypto_blkcipher_setkey(tfm, esp->conf.key, esp->conf.key_len)) |
359 | goto error; | 364 | goto error; |
360 | x->props.header_len = sizeof(struct ipv6_esp_hdr) + esp->conf.ivlen; | 365 | x->props.header_len = sizeof(struct ipv6_esp_hdr) + esp->conf.ivlen; |
361 | if (x->props.mode) | 366 | if (x->props.mode == XFRM_MODE_TUNNEL) |
362 | x->props.header_len += sizeof(struct ipv6hdr); | 367 | x->props.header_len += sizeof(struct ipv6hdr); |
363 | x->data = esp; | 368 | x->data = esp; |
364 | return 0; | 369 | return 0; |
@@ -379,7 +384,8 @@ static struct xfrm_type esp6_type = | |||
379 | .destructor = esp6_destroy, | 384 | .destructor = esp6_destroy, |
380 | .get_max_size = esp6_get_max_size, | 385 | .get_max_size = esp6_get_max_size, |
381 | .input = esp6_input, | 386 | .input = esp6_input, |
382 | .output = esp6_output | 387 | .output = esp6_output, |
388 | .hdr_offset = xfrm6_find_1stfragopt, | ||
383 | }; | 389 | }; |
384 | 390 | ||
385 | static struct inet6_protocol esp6_protocol = { | 391 | static struct inet6_protocol esp6_protocol = { |
diff --git a/net/ipv6/exthdrs.c b/net/ipv6/exthdrs.c index 86dac106873b..88c96b10684c 100644 --- a/net/ipv6/exthdrs.c +++ b/net/ipv6/exthdrs.c | |||
@@ -43,9 +43,54 @@ | |||
43 | #include <net/ndisc.h> | 43 | #include <net/ndisc.h> |
44 | #include <net/ip6_route.h> | 44 | #include <net/ip6_route.h> |
45 | #include <net/addrconf.h> | 45 | #include <net/addrconf.h> |
46 | #ifdef CONFIG_IPV6_MIP6 | ||
47 | #include <net/xfrm.h> | ||
48 | #endif | ||
46 | 49 | ||
47 | #include <asm/uaccess.h> | 50 | #include <asm/uaccess.h> |
48 | 51 | ||
52 | int ipv6_find_tlv(struct sk_buff *skb, int offset, int type) | ||
53 | { | ||
54 | int packet_len = skb->tail - skb->nh.raw; | ||
55 | struct ipv6_opt_hdr *hdr; | ||
56 | int len; | ||
57 | |||
58 | if (offset + 2 > packet_len) | ||
59 | goto bad; | ||
60 | hdr = (struct ipv6_opt_hdr*)(skb->nh.raw + offset); | ||
61 | len = ((hdr->hdrlen + 1) << 3); | ||
62 | |||
63 | if (offset + len > packet_len) | ||
64 | goto bad; | ||
65 | |||
66 | offset += 2; | ||
67 | len -= 2; | ||
68 | |||
69 | while (len > 0) { | ||
70 | int opttype = skb->nh.raw[offset]; | ||
71 | int optlen; | ||
72 | |||
73 | if (opttype == type) | ||
74 | return offset; | ||
75 | |||
76 | switch (opttype) { | ||
77 | case IPV6_TLV_PAD0: | ||
78 | optlen = 1; | ||
79 | break; | ||
80 | default: | ||
81 | optlen = skb->nh.raw[offset + 1] + 2; | ||
82 | if (optlen > len) | ||
83 | goto bad; | ||
84 | break; | ||
85 | } | ||
86 | offset += optlen; | ||
87 | len -= optlen; | ||
88 | } | ||
89 | /* not_found */ | ||
90 | bad: | ||
91 | return -1; | ||
92 | } | ||
93 | |||
49 | /* | 94 | /* |
50 | * Parsing tlv encoded headers. | 95 | * Parsing tlv encoded headers. |
51 | * | 96 | * |
@@ -56,7 +101,7 @@ | |||
56 | 101 | ||
57 | struct tlvtype_proc { | 102 | struct tlvtype_proc { |
58 | int type; | 103 | int type; |
59 | int (*func)(struct sk_buff *skb, int offset); | 104 | int (*func)(struct sk_buff **skbp, int offset); |
60 | }; | 105 | }; |
61 | 106 | ||
62 | /********************* | 107 | /********************* |
@@ -65,8 +110,10 @@ struct tlvtype_proc { | |||
65 | 110 | ||
66 | /* An unknown option is detected, decide what to do */ | 111 | /* An unknown option is detected, decide what to do */ |
67 | 112 | ||
68 | static int ip6_tlvopt_unknown(struct sk_buff *skb, int optoff) | 113 | static int ip6_tlvopt_unknown(struct sk_buff **skbp, int optoff) |
69 | { | 114 | { |
115 | struct sk_buff *skb = *skbp; | ||
116 | |||
70 | switch ((skb->nh.raw[optoff] & 0xC0) >> 6) { | 117 | switch ((skb->nh.raw[optoff] & 0xC0) >> 6) { |
71 | case 0: /* ignore */ | 118 | case 0: /* ignore */ |
72 | return 1; | 119 | return 1; |
@@ -91,8 +138,9 @@ static int ip6_tlvopt_unknown(struct sk_buff *skb, int optoff) | |||
91 | 138 | ||
92 | /* Parse tlv encoded option header (hop-by-hop or destination) */ | 139 | /* Parse tlv encoded option header (hop-by-hop or destination) */ |
93 | 140 | ||
94 | static int ip6_parse_tlv(struct tlvtype_proc *procs, struct sk_buff *skb) | 141 | static int ip6_parse_tlv(struct tlvtype_proc *procs, struct sk_buff **skbp) |
95 | { | 142 | { |
143 | struct sk_buff *skb = *skbp; | ||
96 | struct tlvtype_proc *curr; | 144 | struct tlvtype_proc *curr; |
97 | int off = skb->h.raw - skb->nh.raw; | 145 | int off = skb->h.raw - skb->nh.raw; |
98 | int len = ((skb->h.raw[1]+1)<<3); | 146 | int len = ((skb->h.raw[1]+1)<<3); |
@@ -122,13 +170,13 @@ static int ip6_parse_tlv(struct tlvtype_proc *procs, struct sk_buff *skb) | |||
122 | /* type specific length/alignment | 170 | /* type specific length/alignment |
123 | checks will be performed in the | 171 | checks will be performed in the |
124 | func(). */ | 172 | func(). */ |
125 | if (curr->func(skb, off) == 0) | 173 | if (curr->func(skbp, off) == 0) |
126 | return 0; | 174 | return 0; |
127 | break; | 175 | break; |
128 | } | 176 | } |
129 | } | 177 | } |
130 | if (curr->type < 0) { | 178 | if (curr->type < 0) { |
131 | if (ip6_tlvopt_unknown(skb, off) == 0) | 179 | if (ip6_tlvopt_unknown(skbp, off) == 0) |
132 | return 0; | 180 | return 0; |
133 | } | 181 | } |
134 | break; | 182 | break; |
@@ -147,8 +195,85 @@ bad: | |||
147 | Destination options header. | 195 | Destination options header. |
148 | *****************************/ | 196 | *****************************/ |
149 | 197 | ||
198 | #ifdef CONFIG_IPV6_MIP6 | ||
199 | static int ipv6_dest_hao(struct sk_buff **skbp, int optoff) | ||
200 | { | ||
201 | struct sk_buff *skb = *skbp; | ||
202 | struct ipv6_destopt_hao *hao; | ||
203 | struct inet6_skb_parm *opt = IP6CB(skb); | ||
204 | struct ipv6hdr *ipv6h = (struct ipv6hdr *)skb->nh.raw; | ||
205 | struct in6_addr tmp_addr; | ||
206 | int ret; | ||
207 | |||
208 | if (opt->dsthao) { | ||
209 | LIMIT_NETDEBUG(KERN_DEBUG "hao duplicated\n"); | ||
210 | goto discard; | ||
211 | } | ||
212 | opt->dsthao = opt->dst1; | ||
213 | opt->dst1 = 0; | ||
214 | |||
215 | hao = (struct ipv6_destopt_hao *)(skb->nh.raw + optoff); | ||
216 | |||
217 | if (hao->length != 16) { | ||
218 | LIMIT_NETDEBUG( | ||
219 | KERN_DEBUG "hao invalid option length = %d\n", hao->length); | ||
220 | goto discard; | ||
221 | } | ||
222 | |||
223 | if (!(ipv6_addr_type(&hao->addr) & IPV6_ADDR_UNICAST)) { | ||
224 | LIMIT_NETDEBUG( | ||
225 | KERN_DEBUG "hao is not an unicast addr: " NIP6_FMT "\n", NIP6(hao->addr)); | ||
226 | goto discard; | ||
227 | } | ||
228 | |||
229 | ret = xfrm6_input_addr(skb, (xfrm_address_t *)&ipv6h->daddr, | ||
230 | (xfrm_address_t *)&hao->addr, IPPROTO_DSTOPTS); | ||
231 | if (unlikely(ret < 0)) | ||
232 | goto discard; | ||
233 | |||
234 | if (skb_cloned(skb)) { | ||
235 | struct sk_buff *skb2 = skb_copy(skb, GFP_ATOMIC); | ||
236 | struct inet6_skb_parm *opt2; | ||
237 | |||
238 | if (skb2 == NULL) | ||
239 | goto discard; | ||
240 | |||
241 | opt2 = IP6CB(skb2); | ||
242 | memcpy(opt2, opt, sizeof(*opt2)); | ||
243 | |||
244 | kfree_skb(skb); | ||
245 | |||
246 | /* update all variable using below by copied skbuff */ | ||
247 | *skbp = skb = skb2; | ||
248 | hao = (struct ipv6_destopt_hao *)(skb2->nh.raw + optoff); | ||
249 | ipv6h = (struct ipv6hdr *)skb2->nh.raw; | ||
250 | } | ||
251 | |||
252 | if (skb->ip_summed == CHECKSUM_COMPLETE) | ||
253 | skb->ip_summed = CHECKSUM_NONE; | ||
254 | |||
255 | ipv6_addr_copy(&tmp_addr, &ipv6h->saddr); | ||
256 | ipv6_addr_copy(&ipv6h->saddr, &hao->addr); | ||
257 | ipv6_addr_copy(&hao->addr, &tmp_addr); | ||
258 | |||
259 | if (skb->tstamp.off_sec == 0) | ||
260 | __net_timestamp(skb); | ||
261 | |||
262 | return 1; | ||
263 | |||
264 | discard: | ||
265 | kfree_skb(skb); | ||
266 | return 0; | ||
267 | } | ||
268 | #endif | ||
269 | |||
150 | static struct tlvtype_proc tlvprocdestopt_lst[] = { | 270 | static struct tlvtype_proc tlvprocdestopt_lst[] = { |
151 | /* No destination options are defined now */ | 271 | #ifdef CONFIG_IPV6_MIP6 |
272 | { | ||
273 | .type = IPV6_TLV_HAO, | ||
274 | .func = ipv6_dest_hao, | ||
275 | }, | ||
276 | #endif | ||
152 | {-1, NULL} | 277 | {-1, NULL} |
153 | }; | 278 | }; |
154 | 279 | ||
@@ -156,6 +281,9 @@ static int ipv6_destopt_rcv(struct sk_buff **skbp) | |||
156 | { | 281 | { |
157 | struct sk_buff *skb = *skbp; | 282 | struct sk_buff *skb = *skbp; |
158 | struct inet6_skb_parm *opt = IP6CB(skb); | 283 | struct inet6_skb_parm *opt = IP6CB(skb); |
284 | #ifdef CONFIG_IPV6_MIP6 | ||
285 | __u16 dstbuf; | ||
286 | #endif | ||
159 | 287 | ||
160 | if (!pskb_may_pull(skb, (skb->h.raw-skb->data)+8) || | 288 | if (!pskb_may_pull(skb, (skb->h.raw-skb->data)+8) || |
161 | !pskb_may_pull(skb, (skb->h.raw-skb->data)+((skb->h.raw[1]+1)<<3))) { | 289 | !pskb_may_pull(skb, (skb->h.raw-skb->data)+((skb->h.raw[1]+1)<<3))) { |
@@ -166,10 +294,19 @@ static int ipv6_destopt_rcv(struct sk_buff **skbp) | |||
166 | 294 | ||
167 | opt->lastopt = skb->h.raw - skb->nh.raw; | 295 | opt->lastopt = skb->h.raw - skb->nh.raw; |
168 | opt->dst1 = skb->h.raw - skb->nh.raw; | 296 | opt->dst1 = skb->h.raw - skb->nh.raw; |
297 | #ifdef CONFIG_IPV6_MIP6 | ||
298 | dstbuf = opt->dst1; | ||
299 | #endif | ||
169 | 300 | ||
170 | if (ip6_parse_tlv(tlvprocdestopt_lst, skb)) { | 301 | if (ip6_parse_tlv(tlvprocdestopt_lst, skbp)) { |
302 | skb = *skbp; | ||
171 | skb->h.raw += ((skb->h.raw[1]+1)<<3); | 303 | skb->h.raw += ((skb->h.raw[1]+1)<<3); |
304 | opt = IP6CB(skb); | ||
305 | #ifdef CONFIG_IPV6_MIP6 | ||
306 | opt->nhoff = dstbuf; | ||
307 | #else | ||
172 | opt->nhoff = opt->dst1; | 308 | opt->nhoff = opt->dst1; |
309 | #endif | ||
173 | return 1; | 310 | return 1; |
174 | } | 311 | } |
175 | 312 | ||
@@ -219,7 +356,7 @@ static int ipv6_rthdr_rcv(struct sk_buff **skbp) | |||
219 | { | 356 | { |
220 | struct sk_buff *skb = *skbp; | 357 | struct sk_buff *skb = *skbp; |
221 | struct inet6_skb_parm *opt = IP6CB(skb); | 358 | struct inet6_skb_parm *opt = IP6CB(skb); |
222 | struct in6_addr *addr; | 359 | struct in6_addr *addr = NULL; |
223 | struct in6_addr daddr; | 360 | struct in6_addr daddr; |
224 | int n, i; | 361 | int n, i; |
225 | 362 | ||
@@ -244,6 +381,23 @@ static int ipv6_rthdr_rcv(struct sk_buff **skbp) | |||
244 | 381 | ||
245 | looped_back: | 382 | looped_back: |
246 | if (hdr->segments_left == 0) { | 383 | if (hdr->segments_left == 0) { |
384 | switch (hdr->type) { | ||
385 | #ifdef CONFIG_IPV6_MIP6 | ||
386 | case IPV6_SRCRT_TYPE_2: | ||
387 | /* Silently discard type 2 header unless it was | ||
388 | * processed by own | ||
389 | */ | ||
390 | if (!addr) { | ||
391 | IP6_INC_STATS_BH(IPSTATS_MIB_INADDRERRORS); | ||
392 | kfree_skb(skb); | ||
393 | return -1; | ||
394 | } | ||
395 | break; | ||
396 | #endif | ||
397 | default: | ||
398 | break; | ||
399 | } | ||
400 | |||
247 | opt->lastopt = skb->h.raw - skb->nh.raw; | 401 | opt->lastopt = skb->h.raw - skb->nh.raw; |
248 | opt->srcrt = skb->h.raw - skb->nh.raw; | 402 | opt->srcrt = skb->h.raw - skb->nh.raw; |
249 | skb->h.raw += (hdr->hdrlen + 1) << 3; | 403 | skb->h.raw += (hdr->hdrlen + 1) << 3; |
@@ -253,17 +407,29 @@ looped_back: | |||
253 | return 1; | 407 | return 1; |
254 | } | 408 | } |
255 | 409 | ||
256 | if (hdr->type != IPV6_SRCRT_TYPE_0) { | 410 | switch (hdr->type) { |
411 | case IPV6_SRCRT_TYPE_0: | ||
412 | if (hdr->hdrlen & 0x01) { | ||
413 | IP6_INC_STATS_BH(IPSTATS_MIB_INHDRERRORS); | ||
414 | icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, (&hdr->hdrlen) - skb->nh.raw); | ||
415 | return -1; | ||
416 | } | ||
417 | break; | ||
418 | #ifdef CONFIG_IPV6_MIP6 | ||
419 | case IPV6_SRCRT_TYPE_2: | ||
420 | /* Silently discard invalid RTH type 2 */ | ||
421 | if (hdr->hdrlen != 2 || hdr->segments_left != 1) { | ||
422 | IP6_INC_STATS_BH(IPSTATS_MIB_INHDRERRORS); | ||
423 | kfree_skb(skb); | ||
424 | return -1; | ||
425 | } | ||
426 | break; | ||
427 | #endif | ||
428 | default: | ||
257 | IP6_INC_STATS_BH(IPSTATS_MIB_INHDRERRORS); | 429 | IP6_INC_STATS_BH(IPSTATS_MIB_INHDRERRORS); |
258 | icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, (&hdr->type) - skb->nh.raw); | 430 | icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, (&hdr->type) - skb->nh.raw); |
259 | return -1; | 431 | return -1; |
260 | } | 432 | } |
261 | |||
262 | if (hdr->hdrlen & 0x01) { | ||
263 | IP6_INC_STATS_BH(IPSTATS_MIB_INHDRERRORS); | ||
264 | icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, (&hdr->hdrlen) - skb->nh.raw); | ||
265 | return -1; | ||
266 | } | ||
267 | 433 | ||
268 | /* | 434 | /* |
269 | * This is the routing header forwarding algorithm from | 435 | * This is the routing header forwarding algorithm from |
@@ -294,7 +460,7 @@ looped_back: | |||
294 | hdr = (struct ipv6_rt_hdr *) skb2->h.raw; | 460 | hdr = (struct ipv6_rt_hdr *) skb2->h.raw; |
295 | } | 461 | } |
296 | 462 | ||
297 | if (skb->ip_summed == CHECKSUM_HW) | 463 | if (skb->ip_summed == CHECKSUM_COMPLETE) |
298 | skb->ip_summed = CHECKSUM_NONE; | 464 | skb->ip_summed = CHECKSUM_NONE; |
299 | 465 | ||
300 | i = n - --hdr->segments_left; | 466 | i = n - --hdr->segments_left; |
@@ -303,6 +469,27 @@ looped_back: | |||
303 | addr = rthdr->addr; | 469 | addr = rthdr->addr; |
304 | addr += i - 1; | 470 | addr += i - 1; |
305 | 471 | ||
472 | switch (hdr->type) { | ||
473 | #ifdef CONFIG_IPV6_MIP6 | ||
474 | case IPV6_SRCRT_TYPE_2: | ||
475 | if (xfrm6_input_addr(skb, (xfrm_address_t *)addr, | ||
476 | (xfrm_address_t *)&skb->nh.ipv6h->saddr, | ||
477 | IPPROTO_ROUTING) < 0) { | ||
478 | IP6_INC_STATS_BH(IPSTATS_MIB_INADDRERRORS); | ||
479 | kfree_skb(skb); | ||
480 | return -1; | ||
481 | } | ||
482 | if (!ipv6_chk_home_addr(addr)) { | ||
483 | IP6_INC_STATS_BH(IPSTATS_MIB_INADDRERRORS); | ||
484 | kfree_skb(skb); | ||
485 | return -1; | ||
486 | } | ||
487 | break; | ||
488 | #endif | ||
489 | default: | ||
490 | break; | ||
491 | } | ||
492 | |||
306 | if (ipv6_addr_is_multicast(addr)) { | 493 | if (ipv6_addr_is_multicast(addr)) { |
307 | IP6_INC_STATS_BH(IPSTATS_MIB_INADDRERRORS); | 494 | IP6_INC_STATS_BH(IPSTATS_MIB_INADDRERRORS); |
308 | kfree_skb(skb); | 495 | kfree_skb(skb); |
@@ -421,8 +608,10 @@ EXPORT_SYMBOL_GPL(ipv6_invert_rthdr); | |||
421 | 608 | ||
422 | /* Router Alert as of RFC 2711 */ | 609 | /* Router Alert as of RFC 2711 */ |
423 | 610 | ||
424 | static int ipv6_hop_ra(struct sk_buff *skb, int optoff) | 611 | static int ipv6_hop_ra(struct sk_buff **skbp, int optoff) |
425 | { | 612 | { |
613 | struct sk_buff *skb = *skbp; | ||
614 | |||
426 | if (skb->nh.raw[optoff+1] == 2) { | 615 | if (skb->nh.raw[optoff+1] == 2) { |
427 | IP6CB(skb)->ra = optoff; | 616 | IP6CB(skb)->ra = optoff; |
428 | return 1; | 617 | return 1; |
@@ -435,8 +624,9 @@ static int ipv6_hop_ra(struct sk_buff *skb, int optoff) | |||
435 | 624 | ||
436 | /* Jumbo payload */ | 625 | /* Jumbo payload */ |
437 | 626 | ||
438 | static int ipv6_hop_jumbo(struct sk_buff *skb, int optoff) | 627 | static int ipv6_hop_jumbo(struct sk_buff **skbp, int optoff) |
439 | { | 628 | { |
629 | struct sk_buff *skb = *skbp; | ||
440 | u32 pkt_len; | 630 | u32 pkt_len; |
441 | 631 | ||
442 | if (skb->nh.raw[optoff+1] != 4 || (optoff&3) != 2) { | 632 | if (skb->nh.raw[optoff+1] != 4 || (optoff&3) != 2) { |
@@ -485,8 +675,9 @@ static struct tlvtype_proc tlvprochopopt_lst[] = { | |||
485 | { -1, } | 675 | { -1, } |
486 | }; | 676 | }; |
487 | 677 | ||
488 | int ipv6_parse_hopopts(struct sk_buff *skb) | 678 | int ipv6_parse_hopopts(struct sk_buff **skbp) |
489 | { | 679 | { |
680 | struct sk_buff *skb = *skbp; | ||
490 | struct inet6_skb_parm *opt = IP6CB(skb); | 681 | struct inet6_skb_parm *opt = IP6CB(skb); |
491 | 682 | ||
492 | /* | 683 | /* |
@@ -502,8 +693,10 @@ int ipv6_parse_hopopts(struct sk_buff *skb) | |||
502 | } | 693 | } |
503 | 694 | ||
504 | opt->hop = sizeof(struct ipv6hdr); | 695 | opt->hop = sizeof(struct ipv6hdr); |
505 | if (ip6_parse_tlv(tlvprochopopt_lst, skb)) { | 696 | if (ip6_parse_tlv(tlvprochopopt_lst, skbp)) { |
697 | skb = *skbp; | ||
506 | skb->h.raw += (skb->h.raw[1]+1)<<3; | 698 | skb->h.raw += (skb->h.raw[1]+1)<<3; |
699 | opt = IP6CB(skb); | ||
507 | opt->nhoff = sizeof(struct ipv6hdr); | 700 | opt->nhoff = sizeof(struct ipv6hdr); |
508 | return 1; | 701 | return 1; |
509 | } | 702 | } |
diff --git a/net/ipv6/fib6_rules.c b/net/ipv6/fib6_rules.c new file mode 100644 index 000000000000..34f5bfaddfc2 --- /dev/null +++ b/net/ipv6/fib6_rules.c | |||
@@ -0,0 +1,305 @@ | |||
1 | /* | ||
2 | * net/ipv6/fib6_rules.c IPv6 Routing Policy Rules | ||
3 | * | ||
4 | * Copyright (C)2003-2006 Helsinki University of Technology | ||
5 | * Copyright (C)2003-2006 USAGI/WIDE Project | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or | ||
8 | * modify it under the terms of the GNU General Public License as | ||
9 | * published by the Free Software Foundation, version 2. | ||
10 | * | ||
11 | * Authors | ||
12 | * Thomas Graf <tgraf@suug.ch> | ||
13 | * Ville Nuorvala <vnuorval@tcs.hut.fi> | ||
14 | */ | ||
15 | |||
16 | #include <linux/config.h> | ||
17 | #include <linux/netdevice.h> | ||
18 | |||
19 | #include <net/fib_rules.h> | ||
20 | #include <net/ipv6.h> | ||
21 | #include <net/ip6_route.h> | ||
22 | #include <net/netlink.h> | ||
23 | |||
24 | struct fib6_rule | ||
25 | { | ||
26 | struct fib_rule common; | ||
27 | struct rt6key src; | ||
28 | struct rt6key dst; | ||
29 | #ifdef CONFIG_IPV6_ROUTE_FWMARK | ||
30 | u32 fwmark; | ||
31 | u32 fwmask; | ||
32 | #endif | ||
33 | u8 tclass; | ||
34 | }; | ||
35 | |||
36 | static struct fib_rules_ops fib6_rules_ops; | ||
37 | |||
38 | static struct fib6_rule main_rule = { | ||
39 | .common = { | ||
40 | .refcnt = ATOMIC_INIT(2), | ||
41 | .pref = 0x7FFE, | ||
42 | .action = FR_ACT_TO_TBL, | ||
43 | .table = RT6_TABLE_MAIN, | ||
44 | }, | ||
45 | }; | ||
46 | |||
47 | static struct fib6_rule local_rule = { | ||
48 | .common = { | ||
49 | .refcnt = ATOMIC_INIT(2), | ||
50 | .pref = 0, | ||
51 | .action = FR_ACT_TO_TBL, | ||
52 | .table = RT6_TABLE_LOCAL, | ||
53 | .flags = FIB_RULE_PERMANENT, | ||
54 | }, | ||
55 | }; | ||
56 | |||
57 | static LIST_HEAD(fib6_rules); | ||
58 | |||
59 | struct dst_entry *fib6_rule_lookup(struct flowi *fl, int flags, | ||
60 | pol_lookup_t lookup) | ||
61 | { | ||
62 | struct fib_lookup_arg arg = { | ||
63 | .lookup_ptr = lookup, | ||
64 | }; | ||
65 | |||
66 | fib_rules_lookup(&fib6_rules_ops, fl, flags, &arg); | ||
67 | if (arg.rule) | ||
68 | fib_rule_put(arg.rule); | ||
69 | |||
70 | if (arg.result) | ||
71 | return (struct dst_entry *) arg.result; | ||
72 | |||
73 | dst_hold(&ip6_null_entry.u.dst); | ||
74 | return &ip6_null_entry.u.dst; | ||
75 | } | ||
76 | |||
77 | static int fib6_rule_action(struct fib_rule *rule, struct flowi *flp, | ||
78 | int flags, struct fib_lookup_arg *arg) | ||
79 | { | ||
80 | struct rt6_info *rt = NULL; | ||
81 | struct fib6_table *table; | ||
82 | pol_lookup_t lookup = arg->lookup_ptr; | ||
83 | |||
84 | switch (rule->action) { | ||
85 | case FR_ACT_TO_TBL: | ||
86 | break; | ||
87 | case FR_ACT_UNREACHABLE: | ||
88 | rt = &ip6_null_entry; | ||
89 | goto discard_pkt; | ||
90 | default: | ||
91 | case FR_ACT_BLACKHOLE: | ||
92 | rt = &ip6_blk_hole_entry; | ||
93 | goto discard_pkt; | ||
94 | case FR_ACT_PROHIBIT: | ||
95 | rt = &ip6_prohibit_entry; | ||
96 | goto discard_pkt; | ||
97 | } | ||
98 | |||
99 | table = fib6_get_table(rule->table); | ||
100 | if (table) | ||
101 | rt = lookup(table, flp, flags); | ||
102 | |||
103 | if (rt != &ip6_null_entry) | ||
104 | goto out; | ||
105 | dst_release(&rt->u.dst); | ||
106 | rt = NULL; | ||
107 | goto out; | ||
108 | |||
109 | discard_pkt: | ||
110 | dst_hold(&rt->u.dst); | ||
111 | out: | ||
112 | arg->result = rt; | ||
113 | return rt == NULL ? -EAGAIN : 0; | ||
114 | } | ||
115 | |||
116 | |||
117 | static int fib6_rule_match(struct fib_rule *rule, struct flowi *fl, int flags) | ||
118 | { | ||
119 | struct fib6_rule *r = (struct fib6_rule *) rule; | ||
120 | |||
121 | if (!ipv6_prefix_equal(&fl->fl6_dst, &r->dst.addr, r->dst.plen)) | ||
122 | return 0; | ||
123 | |||
124 | if ((flags & RT6_LOOKUP_F_HAS_SADDR) && | ||
125 | !ipv6_prefix_equal(&fl->fl6_src, &r->src.addr, r->src.plen)) | ||
126 | return 0; | ||
127 | |||
128 | if (r->tclass && r->tclass != ((ntohl(fl->fl6_flowlabel) >> 20) & 0xff)) | ||
129 | return 0; | ||
130 | |||
131 | #ifdef CONFIG_IPV6_ROUTE_FWMARK | ||
132 | if ((r->fwmark ^ fl->fl6_fwmark) & r->fwmask) | ||
133 | return 0; | ||
134 | #endif | ||
135 | |||
136 | return 1; | ||
137 | } | ||
138 | |||
139 | static struct nla_policy fib6_rule_policy[FRA_MAX+1] __read_mostly = { | ||
140 | [FRA_IFNAME] = { .type = NLA_STRING, .len = IFNAMSIZ - 1 }, | ||
141 | [FRA_PRIORITY] = { .type = NLA_U32 }, | ||
142 | [FRA_SRC] = { .len = sizeof(struct in6_addr) }, | ||
143 | [FRA_DST] = { .len = sizeof(struct in6_addr) }, | ||
144 | [FRA_FWMARK] = { .type = NLA_U32 }, | ||
145 | [FRA_FWMASK] = { .type = NLA_U32 }, | ||
146 | [FRA_TABLE] = { .type = NLA_U32 }, | ||
147 | }; | ||
148 | |||
149 | static int fib6_rule_configure(struct fib_rule *rule, struct sk_buff *skb, | ||
150 | struct nlmsghdr *nlh, struct fib_rule_hdr *frh, | ||
151 | struct nlattr **tb) | ||
152 | { | ||
153 | int err = -EINVAL; | ||
154 | struct fib6_rule *rule6 = (struct fib6_rule *) rule; | ||
155 | |||
156 | if (frh->src_len > 128 || frh->dst_len > 128 || | ||
157 | (frh->tos & ~IPV6_FLOWINFO_MASK)) | ||
158 | goto errout; | ||
159 | |||
160 | if (rule->action == FR_ACT_TO_TBL) { | ||
161 | if (rule->table == RT6_TABLE_UNSPEC) | ||
162 | goto errout; | ||
163 | |||
164 | if (fib6_new_table(rule->table) == NULL) { | ||
165 | err = -ENOBUFS; | ||
166 | goto errout; | ||
167 | } | ||
168 | } | ||
169 | |||
170 | if (tb[FRA_SRC]) | ||
171 | nla_memcpy(&rule6->src.addr, tb[FRA_SRC], | ||
172 | sizeof(struct in6_addr)); | ||
173 | |||
174 | if (tb[FRA_DST]) | ||
175 | nla_memcpy(&rule6->dst.addr, tb[FRA_DST], | ||
176 | sizeof(struct in6_addr)); | ||
177 | |||
178 | #ifdef CONFIG_IPV6_ROUTE_FWMARK | ||
179 | if (tb[FRA_FWMARK]) { | ||
180 | rule6->fwmark = nla_get_u32(tb[FRA_FWMARK]); | ||
181 | if (rule6->fwmark) { | ||
182 | /* | ||
183 | * if the mark value is non-zero, | ||
184 | * all bits are compared by default | ||
185 | * unless a mask is explicitly specified. | ||
186 | */ | ||
187 | rule6->fwmask = 0xFFFFFFFF; | ||
188 | } | ||
189 | } | ||
190 | |||
191 | if (tb[FRA_FWMASK]) | ||
192 | rule6->fwmask = nla_get_u32(tb[FRA_FWMASK]); | ||
193 | #endif | ||
194 | |||
195 | rule6->src.plen = frh->src_len; | ||
196 | rule6->dst.plen = frh->dst_len; | ||
197 | rule6->tclass = frh->tos; | ||
198 | |||
199 | err = 0; | ||
200 | errout: | ||
201 | return err; | ||
202 | } | ||
203 | |||
204 | static int fib6_rule_compare(struct fib_rule *rule, struct fib_rule_hdr *frh, | ||
205 | struct nlattr **tb) | ||
206 | { | ||
207 | struct fib6_rule *rule6 = (struct fib6_rule *) rule; | ||
208 | |||
209 | if (frh->src_len && (rule6->src.plen != frh->src_len)) | ||
210 | return 0; | ||
211 | |||
212 | if (frh->dst_len && (rule6->dst.plen != frh->dst_len)) | ||
213 | return 0; | ||
214 | |||
215 | if (frh->tos && (rule6->tclass != frh->tos)) | ||
216 | return 0; | ||
217 | |||
218 | if (tb[FRA_SRC] && | ||
219 | nla_memcmp(tb[FRA_SRC], &rule6->src.addr, sizeof(struct in6_addr))) | ||
220 | return 0; | ||
221 | |||
222 | if (tb[FRA_DST] && | ||
223 | nla_memcmp(tb[FRA_DST], &rule6->dst.addr, sizeof(struct in6_addr))) | ||
224 | return 0; | ||
225 | |||
226 | #ifdef CONFIG_IPV6_ROUTE_FWMARK | ||
227 | if (tb[FRA_FWMARK] && (rule6->fwmark != nla_get_u32(tb[FRA_FWMARK]))) | ||
228 | return 0; | ||
229 | |||
230 | if (tb[FRA_FWMASK] && (rule6->fwmask != nla_get_u32(tb[FRA_FWMASK]))) | ||
231 | return 0; | ||
232 | #endif | ||
233 | |||
234 | return 1; | ||
235 | } | ||
236 | |||
237 | static int fib6_rule_fill(struct fib_rule *rule, struct sk_buff *skb, | ||
238 | struct nlmsghdr *nlh, struct fib_rule_hdr *frh) | ||
239 | { | ||
240 | struct fib6_rule *rule6 = (struct fib6_rule *) rule; | ||
241 | |||
242 | frh->family = AF_INET6; | ||
243 | frh->dst_len = rule6->dst.plen; | ||
244 | frh->src_len = rule6->src.plen; | ||
245 | frh->tos = rule6->tclass; | ||
246 | |||
247 | if (rule6->dst.plen) | ||
248 | NLA_PUT(skb, FRA_DST, sizeof(struct in6_addr), | ||
249 | &rule6->dst.addr); | ||
250 | |||
251 | if (rule6->src.plen) | ||
252 | NLA_PUT(skb, FRA_SRC, sizeof(struct in6_addr), | ||
253 | &rule6->src.addr); | ||
254 | |||
255 | #ifdef CONFIG_IPV6_ROUTE_FWMARK | ||
256 | if (rule6->fwmark) | ||
257 | NLA_PUT_U32(skb, FRA_FWMARK, rule6->fwmark); | ||
258 | |||
259 | if (rule6->fwmask || rule6->fwmark) | ||
260 | NLA_PUT_U32(skb, FRA_FWMASK, rule6->fwmask); | ||
261 | #endif | ||
262 | |||
263 | return 0; | ||
264 | |||
265 | nla_put_failure: | ||
266 | return -ENOBUFS; | ||
267 | } | ||
268 | |||
269 | int fib6_rules_dump(struct sk_buff *skb, struct netlink_callback *cb) | ||
270 | { | ||
271 | return fib_rules_dump(skb, cb, AF_INET6); | ||
272 | } | ||
273 | |||
274 | static u32 fib6_rule_default_pref(void) | ||
275 | { | ||
276 | return 0x3FFF; | ||
277 | } | ||
278 | |||
279 | static struct fib_rules_ops fib6_rules_ops = { | ||
280 | .family = AF_INET6, | ||
281 | .rule_size = sizeof(struct fib6_rule), | ||
282 | .action = fib6_rule_action, | ||
283 | .match = fib6_rule_match, | ||
284 | .configure = fib6_rule_configure, | ||
285 | .compare = fib6_rule_compare, | ||
286 | .fill = fib6_rule_fill, | ||
287 | .default_pref = fib6_rule_default_pref, | ||
288 | .nlgroup = RTNLGRP_IPV6_RULE, | ||
289 | .policy = fib6_rule_policy, | ||
290 | .rules_list = &fib6_rules, | ||
291 | .owner = THIS_MODULE, | ||
292 | }; | ||
293 | |||
294 | void __init fib6_rules_init(void) | ||
295 | { | ||
296 | list_add_tail(&local_rule.common.list, &fib6_rules); | ||
297 | list_add_tail(&main_rule.common.list, &fib6_rules); | ||
298 | |||
299 | fib_rules_register(&fib6_rules_ops); | ||
300 | } | ||
301 | |||
302 | void fib6_rules_cleanup(void) | ||
303 | { | ||
304 | fib_rules_unregister(&fib6_rules_ops); | ||
305 | } | ||
diff --git a/net/ipv6/icmp.c b/net/ipv6/icmp.c index 356a8a7ef22a..4ec876066b3f 100644 --- a/net/ipv6/icmp.c +++ b/net/ipv6/icmp.c | |||
@@ -151,7 +151,7 @@ static int is_ineligible(struct sk_buff *skb) | |||
151 | return 0; | 151 | return 0; |
152 | } | 152 | } |
153 | 153 | ||
154 | static int sysctl_icmpv6_time = 1*HZ; | 154 | static int sysctl_icmpv6_time __read_mostly = 1*HZ; |
155 | 155 | ||
156 | /* | 156 | /* |
157 | * Check the ICMP output rate limit | 157 | * Check the ICMP output rate limit |
@@ -273,6 +273,29 @@ static int icmpv6_getfrag(void *from, char *to, int offset, int len, int odd, st | |||
273 | return 0; | 273 | return 0; |
274 | } | 274 | } |
275 | 275 | ||
276 | #ifdef CONFIG_IPV6_MIP6 | ||
277 | static void mip6_addr_swap(struct sk_buff *skb) | ||
278 | { | ||
279 | struct ipv6hdr *iph = skb->nh.ipv6h; | ||
280 | struct inet6_skb_parm *opt = IP6CB(skb); | ||
281 | struct ipv6_destopt_hao *hao; | ||
282 | struct in6_addr tmp; | ||
283 | int off; | ||
284 | |||
285 | if (opt->dsthao) { | ||
286 | off = ipv6_find_tlv(skb, opt->dsthao, IPV6_TLV_HAO); | ||
287 | if (likely(off >= 0)) { | ||
288 | hao = (struct ipv6_destopt_hao *)(skb->nh.raw + off); | ||
289 | ipv6_addr_copy(&tmp, &iph->saddr); | ||
290 | ipv6_addr_copy(&iph->saddr, &hao->addr); | ||
291 | ipv6_addr_copy(&hao->addr, &tmp); | ||
292 | } | ||
293 | } | ||
294 | } | ||
295 | #else | ||
296 | static inline void mip6_addr_swap(struct sk_buff *skb) {} | ||
297 | #endif | ||
298 | |||
276 | /* | 299 | /* |
277 | * Send an ICMP message in response to a packet in error | 300 | * Send an ICMP message in response to a packet in error |
278 | */ | 301 | */ |
@@ -350,6 +373,8 @@ void icmpv6_send(struct sk_buff *skb, int type, int code, __u32 info, | |||
350 | return; | 373 | return; |
351 | } | 374 | } |
352 | 375 | ||
376 | mip6_addr_swap(skb); | ||
377 | |||
353 | memset(&fl, 0, sizeof(fl)); | 378 | memset(&fl, 0, sizeof(fl)); |
354 | fl.proto = IPPROTO_ICMPV6; | 379 | fl.proto = IPPROTO_ICMPV6; |
355 | ipv6_addr_copy(&fl.fl6_dst, &hdr->saddr); | 380 | ipv6_addr_copy(&fl.fl6_dst, &hdr->saddr); |
@@ -358,6 +383,7 @@ void icmpv6_send(struct sk_buff *skb, int type, int code, __u32 info, | |||
358 | fl.oif = iif; | 383 | fl.oif = iif; |
359 | fl.fl_icmp_type = type; | 384 | fl.fl_icmp_type = type; |
360 | fl.fl_icmp_code = code; | 385 | fl.fl_icmp_code = code; |
386 | security_skb_classify_flow(skb, &fl); | ||
361 | 387 | ||
362 | if (icmpv6_xmit_lock()) | 388 | if (icmpv6_xmit_lock()) |
363 | return; | 389 | return; |
@@ -472,6 +498,7 @@ static void icmpv6_echo_reply(struct sk_buff *skb) | |||
472 | ipv6_addr_copy(&fl.fl6_src, saddr); | 498 | ipv6_addr_copy(&fl.fl6_src, saddr); |
473 | fl.oif = skb->dev->ifindex; | 499 | fl.oif = skb->dev->ifindex; |
474 | fl.fl_icmp_type = ICMPV6_ECHO_REPLY; | 500 | fl.fl_icmp_type = ICMPV6_ECHO_REPLY; |
501 | security_skb_classify_flow(skb, &fl); | ||
475 | 502 | ||
476 | if (icmpv6_xmit_lock()) | 503 | if (icmpv6_xmit_lock()) |
477 | return; | 504 | return; |
@@ -604,7 +631,7 @@ static int icmpv6_rcv(struct sk_buff **pskb) | |||
604 | 631 | ||
605 | /* Perform checksum. */ | 632 | /* Perform checksum. */ |
606 | switch (skb->ip_summed) { | 633 | switch (skb->ip_summed) { |
607 | case CHECKSUM_HW: | 634 | case CHECKSUM_COMPLETE: |
608 | if (!csum_ipv6_magic(saddr, daddr, skb->len, IPPROTO_ICMPV6, | 635 | if (!csum_ipv6_magic(saddr, daddr, skb->len, IPPROTO_ICMPV6, |
609 | skb->csum)) | 636 | skb->csum)) |
610 | break; | 637 | break; |
diff --git a/net/ipv6/inet6_connection_sock.c b/net/ipv6/inet6_connection_sock.c index bf491077b822..827f41d1478b 100644 --- a/net/ipv6/inet6_connection_sock.c +++ b/net/ipv6/inet6_connection_sock.c | |||
@@ -157,6 +157,7 @@ int inet6_csk_xmit(struct sk_buff *skb, int ipfragok) | |||
157 | fl.oif = sk->sk_bound_dev_if; | 157 | fl.oif = sk->sk_bound_dev_if; |
158 | fl.fl_ip_sport = inet->sport; | 158 | fl.fl_ip_sport = inet->sport; |
159 | fl.fl_ip_dport = inet->dport; | 159 | fl.fl_ip_dport = inet->dport; |
160 | security_sk_classify_flow(sk, &fl); | ||
160 | 161 | ||
161 | if (np->opt && np->opt->srcrt) { | 162 | if (np->opt && np->opt->srcrt) { |
162 | struct rt0_hdr *rt0 = (struct rt0_hdr *)np->opt->srcrt; | 163 | struct rt0_hdr *rt0 = (struct rt0_hdr *)np->opt->srcrt; |
@@ -185,7 +186,7 @@ int inet6_csk_xmit(struct sk_buff *skb, int ipfragok) | |||
185 | return err; | 186 | return err; |
186 | } | 187 | } |
187 | 188 | ||
188 | __ip6_dst_store(sk, dst, NULL); | 189 | __ip6_dst_store(sk, dst, NULL, NULL); |
189 | } | 190 | } |
190 | 191 | ||
191 | skb->dst = dst_clone(dst); | 192 | skb->dst = dst_clone(dst); |
diff --git a/net/ipv6/ip6_fib.c b/net/ipv6/ip6_fib.c index 764221220afd..8fcae7a6510b 100644 --- a/net/ipv6/ip6_fib.c +++ b/net/ipv6/ip6_fib.c | |||
@@ -18,6 +18,7 @@ | |||
18 | * Yuji SEKIYA @USAGI: Support default route on router node; | 18 | * Yuji SEKIYA @USAGI: Support default route on router node; |
19 | * remove ip6_null_entry from the top of | 19 | * remove ip6_null_entry from the top of |
20 | * routing table. | 20 | * routing table. |
21 | * Ville Nuorvala: Fixed routing subtrees. | ||
21 | */ | 22 | */ |
22 | #include <linux/errno.h> | 23 | #include <linux/errno.h> |
23 | #include <linux/types.h> | 24 | #include <linux/types.h> |
@@ -26,6 +27,7 @@ | |||
26 | #include <linux/netdevice.h> | 27 | #include <linux/netdevice.h> |
27 | #include <linux/in6.h> | 28 | #include <linux/in6.h> |
28 | #include <linux/init.h> | 29 | #include <linux/init.h> |
30 | #include <linux/list.h> | ||
29 | 31 | ||
30 | #ifdef CONFIG_PROC_FS | 32 | #ifdef CONFIG_PROC_FS |
31 | #include <linux/proc_fs.h> | 33 | #include <linux/proc_fs.h> |
@@ -68,19 +70,19 @@ struct fib6_cleaner_t | |||
68 | void *arg; | 70 | void *arg; |
69 | }; | 71 | }; |
70 | 72 | ||
71 | DEFINE_RWLOCK(fib6_walker_lock); | 73 | static DEFINE_RWLOCK(fib6_walker_lock); |
72 | |||
73 | 74 | ||
74 | #ifdef CONFIG_IPV6_SUBTREES | 75 | #ifdef CONFIG_IPV6_SUBTREES |
75 | #define FWS_INIT FWS_S | 76 | #define FWS_INIT FWS_S |
76 | #define SUBTREE(fn) ((fn)->subtree) | ||
77 | #else | 77 | #else |
78 | #define FWS_INIT FWS_L | 78 | #define FWS_INIT FWS_L |
79 | #define SUBTREE(fn) NULL | ||
80 | #endif | 79 | #endif |
81 | 80 | ||
82 | static void fib6_prune_clones(struct fib6_node *fn, struct rt6_info *rt); | 81 | static void fib6_prune_clones(struct fib6_node *fn, struct rt6_info *rt); |
82 | static struct rt6_info * fib6_find_prefix(struct fib6_node *fn); | ||
83 | static struct fib6_node * fib6_repair_tree(struct fib6_node *fn); | 83 | static struct fib6_node * fib6_repair_tree(struct fib6_node *fn); |
84 | static int fib6_walk(struct fib6_walker_t *w); | ||
85 | static int fib6_walk_continue(struct fib6_walker_t *w); | ||
84 | 86 | ||
85 | /* | 87 | /* |
86 | * A routing update causes an increase of the serial number on the | 88 | * A routing update causes an increase of the serial number on the |
@@ -93,13 +95,31 @@ static __u32 rt_sernum; | |||
93 | 95 | ||
94 | static DEFINE_TIMER(ip6_fib_timer, fib6_run_gc, 0, 0); | 96 | static DEFINE_TIMER(ip6_fib_timer, fib6_run_gc, 0, 0); |
95 | 97 | ||
96 | struct fib6_walker_t fib6_walker_list = { | 98 | static struct fib6_walker_t fib6_walker_list = { |
97 | .prev = &fib6_walker_list, | 99 | .prev = &fib6_walker_list, |
98 | .next = &fib6_walker_list, | 100 | .next = &fib6_walker_list, |
99 | }; | 101 | }; |
100 | 102 | ||
101 | #define FOR_WALKERS(w) for ((w)=fib6_walker_list.next; (w) != &fib6_walker_list; (w)=(w)->next) | 103 | #define FOR_WALKERS(w) for ((w)=fib6_walker_list.next; (w) != &fib6_walker_list; (w)=(w)->next) |
102 | 104 | ||
105 | static inline void fib6_walker_link(struct fib6_walker_t *w) | ||
106 | { | ||
107 | write_lock_bh(&fib6_walker_lock); | ||
108 | w->next = fib6_walker_list.next; | ||
109 | w->prev = &fib6_walker_list; | ||
110 | w->next->prev = w; | ||
111 | w->prev->next = w; | ||
112 | write_unlock_bh(&fib6_walker_lock); | ||
113 | } | ||
114 | |||
115 | static inline void fib6_walker_unlink(struct fib6_walker_t *w) | ||
116 | { | ||
117 | write_lock_bh(&fib6_walker_lock); | ||
118 | w->next->prev = w->prev; | ||
119 | w->prev->next = w->next; | ||
120 | w->prev = w->next = w; | ||
121 | write_unlock_bh(&fib6_walker_lock); | ||
122 | } | ||
103 | static __inline__ u32 fib6_new_sernum(void) | 123 | static __inline__ u32 fib6_new_sernum(void) |
104 | { | 124 | { |
105 | u32 n = ++rt_sernum; | 125 | u32 n = ++rt_sernum; |
@@ -147,6 +167,253 @@ static __inline__ void rt6_release(struct rt6_info *rt) | |||
147 | dst_free(&rt->u.dst); | 167 | dst_free(&rt->u.dst); |
148 | } | 168 | } |
149 | 169 | ||
170 | static struct fib6_table fib6_main_tbl = { | ||
171 | .tb6_id = RT6_TABLE_MAIN, | ||
172 | .tb6_lock = RW_LOCK_UNLOCKED, | ||
173 | .tb6_root = { | ||
174 | .leaf = &ip6_null_entry, | ||
175 | .fn_flags = RTN_ROOT | RTN_TL_ROOT | RTN_RTINFO, | ||
176 | }, | ||
177 | }; | ||
178 | |||
179 | #ifdef CONFIG_IPV6_MULTIPLE_TABLES | ||
180 | #define FIB_TABLE_HASHSZ 256 | ||
181 | #else | ||
182 | #define FIB_TABLE_HASHSZ 1 | ||
183 | #endif | ||
184 | static struct hlist_head fib_table_hash[FIB_TABLE_HASHSZ]; | ||
185 | |||
186 | static void fib6_link_table(struct fib6_table *tb) | ||
187 | { | ||
188 | unsigned int h; | ||
189 | |||
190 | h = tb->tb6_id & (FIB_TABLE_HASHSZ - 1); | ||
191 | |||
192 | /* | ||
193 | * No protection necessary, this is the only list mutatation | ||
194 | * operation, tables never disappear once they exist. | ||
195 | */ | ||
196 | hlist_add_head_rcu(&tb->tb6_hlist, &fib_table_hash[h]); | ||
197 | } | ||
198 | |||
199 | #ifdef CONFIG_IPV6_MULTIPLE_TABLES | ||
200 | static struct fib6_table fib6_local_tbl = { | ||
201 | .tb6_id = RT6_TABLE_LOCAL, | ||
202 | .tb6_lock = RW_LOCK_UNLOCKED, | ||
203 | .tb6_root = { | ||
204 | .leaf = &ip6_null_entry, | ||
205 | .fn_flags = RTN_ROOT | RTN_TL_ROOT | RTN_RTINFO, | ||
206 | }, | ||
207 | }; | ||
208 | |||
209 | static struct fib6_table *fib6_alloc_table(u32 id) | ||
210 | { | ||
211 | struct fib6_table *table; | ||
212 | |||
213 | table = kzalloc(sizeof(*table), GFP_ATOMIC); | ||
214 | if (table != NULL) { | ||
215 | table->tb6_id = id; | ||
216 | table->tb6_lock = RW_LOCK_UNLOCKED; | ||
217 | table->tb6_root.leaf = &ip6_null_entry; | ||
218 | table->tb6_root.fn_flags = RTN_ROOT | RTN_TL_ROOT | RTN_RTINFO; | ||
219 | } | ||
220 | |||
221 | return table; | ||
222 | } | ||
223 | |||
224 | struct fib6_table *fib6_new_table(u32 id) | ||
225 | { | ||
226 | struct fib6_table *tb; | ||
227 | |||
228 | if (id == 0) | ||
229 | id = RT6_TABLE_MAIN; | ||
230 | tb = fib6_get_table(id); | ||
231 | if (tb) | ||
232 | return tb; | ||
233 | |||
234 | tb = fib6_alloc_table(id); | ||
235 | if (tb != NULL) | ||
236 | fib6_link_table(tb); | ||
237 | |||
238 | return tb; | ||
239 | } | ||
240 | |||
241 | struct fib6_table *fib6_get_table(u32 id) | ||
242 | { | ||
243 | struct fib6_table *tb; | ||
244 | struct hlist_node *node; | ||
245 | unsigned int h; | ||
246 | |||
247 | if (id == 0) | ||
248 | id = RT6_TABLE_MAIN; | ||
249 | h = id & (FIB_TABLE_HASHSZ - 1); | ||
250 | rcu_read_lock(); | ||
251 | hlist_for_each_entry_rcu(tb, node, &fib_table_hash[h], tb6_hlist) { | ||
252 | if (tb->tb6_id == id) { | ||
253 | rcu_read_unlock(); | ||
254 | return tb; | ||
255 | } | ||
256 | } | ||
257 | rcu_read_unlock(); | ||
258 | |||
259 | return NULL; | ||
260 | } | ||
261 | |||
262 | static void __init fib6_tables_init(void) | ||
263 | { | ||
264 | fib6_link_table(&fib6_main_tbl); | ||
265 | fib6_link_table(&fib6_local_tbl); | ||
266 | } | ||
267 | |||
268 | #else | ||
269 | |||
270 | struct fib6_table *fib6_new_table(u32 id) | ||
271 | { | ||
272 | return fib6_get_table(id); | ||
273 | } | ||
274 | |||
275 | struct fib6_table *fib6_get_table(u32 id) | ||
276 | { | ||
277 | return &fib6_main_tbl; | ||
278 | } | ||
279 | |||
280 | struct dst_entry *fib6_rule_lookup(struct flowi *fl, int flags, | ||
281 | pol_lookup_t lookup) | ||
282 | { | ||
283 | return (struct dst_entry *) lookup(&fib6_main_tbl, fl, flags); | ||
284 | } | ||
285 | |||
286 | static void __init fib6_tables_init(void) | ||
287 | { | ||
288 | fib6_link_table(&fib6_main_tbl); | ||
289 | } | ||
290 | |||
291 | #endif | ||
292 | |||
293 | static int fib6_dump_node(struct fib6_walker_t *w) | ||
294 | { | ||
295 | int res; | ||
296 | struct rt6_info *rt; | ||
297 | |||
298 | for (rt = w->leaf; rt; rt = rt->u.next) { | ||
299 | res = rt6_dump_route(rt, w->args); | ||
300 | if (res < 0) { | ||
301 | /* Frame is full, suspend walking */ | ||
302 | w->leaf = rt; | ||
303 | return 1; | ||
304 | } | ||
305 | BUG_TRAP(res!=0); | ||
306 | } | ||
307 | w->leaf = NULL; | ||
308 | return 0; | ||
309 | } | ||
310 | |||
311 | static void fib6_dump_end(struct netlink_callback *cb) | ||
312 | { | ||
313 | struct fib6_walker_t *w = (void*)cb->args[2]; | ||
314 | |||
315 | if (w) { | ||
316 | cb->args[2] = 0; | ||
317 | kfree(w); | ||
318 | } | ||
319 | cb->done = (void*)cb->args[3]; | ||
320 | cb->args[1] = 3; | ||
321 | } | ||
322 | |||
323 | static int fib6_dump_done(struct netlink_callback *cb) | ||
324 | { | ||
325 | fib6_dump_end(cb); | ||
326 | return cb->done ? cb->done(cb) : 0; | ||
327 | } | ||
328 | |||
329 | static int fib6_dump_table(struct fib6_table *table, struct sk_buff *skb, | ||
330 | struct netlink_callback *cb) | ||
331 | { | ||
332 | struct fib6_walker_t *w; | ||
333 | int res; | ||
334 | |||
335 | w = (void *)cb->args[2]; | ||
336 | w->root = &table->tb6_root; | ||
337 | |||
338 | if (cb->args[4] == 0) { | ||
339 | read_lock_bh(&table->tb6_lock); | ||
340 | res = fib6_walk(w); | ||
341 | read_unlock_bh(&table->tb6_lock); | ||
342 | if (res > 0) | ||
343 | cb->args[4] = 1; | ||
344 | } else { | ||
345 | read_lock_bh(&table->tb6_lock); | ||
346 | res = fib6_walk_continue(w); | ||
347 | read_unlock_bh(&table->tb6_lock); | ||
348 | if (res != 0) { | ||
349 | if (res < 0) | ||
350 | fib6_walker_unlink(w); | ||
351 | goto end; | ||
352 | } | ||
353 | fib6_walker_unlink(w); | ||
354 | cb->args[4] = 0; | ||
355 | } | ||
356 | end: | ||
357 | return res; | ||
358 | } | ||
359 | |||
360 | int inet6_dump_fib(struct sk_buff *skb, struct netlink_callback *cb) | ||
361 | { | ||
362 | unsigned int h, s_h; | ||
363 | unsigned int e = 0, s_e; | ||
364 | struct rt6_rtnl_dump_arg arg; | ||
365 | struct fib6_walker_t *w; | ||
366 | struct fib6_table *tb; | ||
367 | struct hlist_node *node; | ||
368 | int res = 0; | ||
369 | |||
370 | s_h = cb->args[0]; | ||
371 | s_e = cb->args[1]; | ||
372 | |||
373 | w = (void *)cb->args[2]; | ||
374 | if (w == NULL) { | ||
375 | /* New dump: | ||
376 | * | ||
377 | * 1. hook callback destructor. | ||
378 | */ | ||
379 | cb->args[3] = (long)cb->done; | ||
380 | cb->done = fib6_dump_done; | ||
381 | |||
382 | /* | ||
383 | * 2. allocate and initialize walker. | ||
384 | */ | ||
385 | w = kzalloc(sizeof(*w), GFP_ATOMIC); | ||
386 | if (w == NULL) | ||
387 | return -ENOMEM; | ||
388 | w->func = fib6_dump_node; | ||
389 | cb->args[2] = (long)w; | ||
390 | } | ||
391 | |||
392 | arg.skb = skb; | ||
393 | arg.cb = cb; | ||
394 | w->args = &arg; | ||
395 | |||
396 | for (h = s_h; h < FIB_TABLE_HASHSZ; h++, s_e = 0) { | ||
397 | e = 0; | ||
398 | hlist_for_each_entry(tb, node, &fib_table_hash[h], tb6_hlist) { | ||
399 | if (e < s_e) | ||
400 | goto next; | ||
401 | res = fib6_dump_table(tb, skb, cb); | ||
402 | if (res != 0) | ||
403 | goto out; | ||
404 | next: | ||
405 | e++; | ||
406 | } | ||
407 | } | ||
408 | out: | ||
409 | cb->args[1] = e; | ||
410 | cb->args[0] = h; | ||
411 | |||
412 | res = res < 0 ? res : skb->len; | ||
413 | if (res <= 0) | ||
414 | fib6_dump_end(cb); | ||
415 | return res; | ||
416 | } | ||
150 | 417 | ||
151 | /* | 418 | /* |
152 | * Routing Table | 419 | * Routing Table |
@@ -343,7 +610,7 @@ insert_above: | |||
343 | */ | 610 | */ |
344 | 611 | ||
345 | static int fib6_add_rt2node(struct fib6_node *fn, struct rt6_info *rt, | 612 | static int fib6_add_rt2node(struct fib6_node *fn, struct rt6_info *rt, |
346 | struct nlmsghdr *nlh, struct netlink_skb_parms *req) | 613 | struct nl_info *info) |
347 | { | 614 | { |
348 | struct rt6_info *iter = NULL; | 615 | struct rt6_info *iter = NULL; |
349 | struct rt6_info **ins; | 616 | struct rt6_info **ins; |
@@ -398,7 +665,7 @@ out: | |||
398 | *ins = rt; | 665 | *ins = rt; |
399 | rt->rt6i_node = fn; | 666 | rt->rt6i_node = fn; |
400 | atomic_inc(&rt->rt6i_ref); | 667 | atomic_inc(&rt->rt6i_ref); |
401 | inet6_rt_notify(RTM_NEWROUTE, rt, nlh, req); | 668 | inet6_rt_notify(RTM_NEWROUTE, rt, info); |
402 | rt6_stats.fib_rt_entries++; | 669 | rt6_stats.fib_rt_entries++; |
403 | 670 | ||
404 | if ((fn->fn_flags & RTN_RTINFO) == 0) { | 671 | if ((fn->fn_flags & RTN_RTINFO) == 0) { |
@@ -428,10 +695,9 @@ void fib6_force_start_gc(void) | |||
428 | * with source addr info in sub-trees | 695 | * with source addr info in sub-trees |
429 | */ | 696 | */ |
430 | 697 | ||
431 | int fib6_add(struct fib6_node *root, struct rt6_info *rt, | 698 | int fib6_add(struct fib6_node *root, struct rt6_info *rt, struct nl_info *info) |
432 | struct nlmsghdr *nlh, void *_rtattr, struct netlink_skb_parms *req) | ||
433 | { | 699 | { |
434 | struct fib6_node *fn; | 700 | struct fib6_node *fn, *pn = NULL; |
435 | int err = -ENOMEM; | 701 | int err = -ENOMEM; |
436 | 702 | ||
437 | fn = fib6_add_1(root, &rt->rt6i_dst.addr, sizeof(struct in6_addr), | 703 | fn = fib6_add_1(root, &rt->rt6i_dst.addr, sizeof(struct in6_addr), |
@@ -440,6 +706,8 @@ int fib6_add(struct fib6_node *root, struct rt6_info *rt, | |||
440 | if (fn == NULL) | 706 | if (fn == NULL) |
441 | goto out; | 707 | goto out; |
442 | 708 | ||
709 | pn = fn; | ||
710 | |||
443 | #ifdef CONFIG_IPV6_SUBTREES | 711 | #ifdef CONFIG_IPV6_SUBTREES |
444 | if (rt->rt6i_src.plen) { | 712 | if (rt->rt6i_src.plen) { |
445 | struct fib6_node *sn; | 713 | struct fib6_node *sn; |
@@ -485,10 +753,6 @@ int fib6_add(struct fib6_node *root, struct rt6_info *rt, | |||
485 | /* Now link new subtree to main tree */ | 753 | /* Now link new subtree to main tree */ |
486 | sfn->parent = fn; | 754 | sfn->parent = fn; |
487 | fn->subtree = sfn; | 755 | fn->subtree = sfn; |
488 | if (fn->leaf == NULL) { | ||
489 | fn->leaf = rt; | ||
490 | atomic_inc(&rt->rt6i_ref); | ||
491 | } | ||
492 | } else { | 756 | } else { |
493 | sn = fib6_add_1(fn->subtree, &rt->rt6i_src.addr, | 757 | sn = fib6_add_1(fn->subtree, &rt->rt6i_src.addr, |
494 | sizeof(struct in6_addr), rt->rt6i_src.plen, | 758 | sizeof(struct in6_addr), rt->rt6i_src.plen, |
@@ -498,21 +762,42 @@ int fib6_add(struct fib6_node *root, struct rt6_info *rt, | |||
498 | goto st_failure; | 762 | goto st_failure; |
499 | } | 763 | } |
500 | 764 | ||
765 | if (fn->leaf == NULL) { | ||
766 | fn->leaf = rt; | ||
767 | atomic_inc(&rt->rt6i_ref); | ||
768 | } | ||
501 | fn = sn; | 769 | fn = sn; |
502 | } | 770 | } |
503 | #endif | 771 | #endif |
504 | 772 | ||
505 | err = fib6_add_rt2node(fn, rt, nlh, req); | 773 | err = fib6_add_rt2node(fn, rt, info); |
506 | 774 | ||
507 | if (err == 0) { | 775 | if (err == 0) { |
508 | fib6_start_gc(rt); | 776 | fib6_start_gc(rt); |
509 | if (!(rt->rt6i_flags&RTF_CACHE)) | 777 | if (!(rt->rt6i_flags&RTF_CACHE)) |
510 | fib6_prune_clones(fn, rt); | 778 | fib6_prune_clones(pn, rt); |
511 | } | 779 | } |
512 | 780 | ||
513 | out: | 781 | out: |
514 | if (err) | 782 | if (err) { |
783 | #ifdef CONFIG_IPV6_SUBTREES | ||
784 | /* | ||
785 | * If fib6_add_1 has cleared the old leaf pointer in the | ||
786 | * super-tree leaf node we have to find a new one for it. | ||
787 | */ | ||
788 | if (pn != fn && !pn->leaf && !(pn->fn_flags & RTN_RTINFO)) { | ||
789 | pn->leaf = fib6_find_prefix(pn); | ||
790 | #if RT6_DEBUG >= 2 | ||
791 | if (!pn->leaf) { | ||
792 | BUG_TRAP(pn->leaf != NULL); | ||
793 | pn->leaf = &ip6_null_entry; | ||
794 | } | ||
795 | #endif | ||
796 | atomic_inc(&pn->leaf->rt6i_ref); | ||
797 | } | ||
798 | #endif | ||
515 | dst_free(&rt->u.dst); | 799 | dst_free(&rt->u.dst); |
800 | } | ||
516 | return err; | 801 | return err; |
517 | 802 | ||
518 | #ifdef CONFIG_IPV6_SUBTREES | 803 | #ifdef CONFIG_IPV6_SUBTREES |
@@ -543,6 +828,9 @@ static struct fib6_node * fib6_lookup_1(struct fib6_node *root, | |||
543 | struct fib6_node *fn; | 828 | struct fib6_node *fn; |
544 | int dir; | 829 | int dir; |
545 | 830 | ||
831 | if (unlikely(args->offset == 0)) | ||
832 | return NULL; | ||
833 | |||
546 | /* | 834 | /* |
547 | * Descend on a tree | 835 | * Descend on a tree |
548 | */ | 836 | */ |
@@ -564,33 +852,26 @@ static struct fib6_node * fib6_lookup_1(struct fib6_node *root, | |||
564 | break; | 852 | break; |
565 | } | 853 | } |
566 | 854 | ||
567 | while ((fn->fn_flags & RTN_ROOT) == 0) { | 855 | while(fn) { |
568 | #ifdef CONFIG_IPV6_SUBTREES | 856 | if (FIB6_SUBTREE(fn) || fn->fn_flags & RTN_RTINFO) { |
569 | if (fn->subtree) { | ||
570 | struct fib6_node *st; | ||
571 | struct lookup_args *narg; | ||
572 | |||
573 | narg = args + 1; | ||
574 | |||
575 | if (narg->addr) { | ||
576 | st = fib6_lookup_1(fn->subtree, narg); | ||
577 | |||
578 | if (st && !(st->fn_flags & RTN_ROOT)) | ||
579 | return st; | ||
580 | } | ||
581 | } | ||
582 | #endif | ||
583 | |||
584 | if (fn->fn_flags & RTN_RTINFO) { | ||
585 | struct rt6key *key; | 857 | struct rt6key *key; |
586 | 858 | ||
587 | key = (struct rt6key *) ((u8 *) fn->leaf + | 859 | key = (struct rt6key *) ((u8 *) fn->leaf + |
588 | args->offset); | 860 | args->offset); |
589 | 861 | ||
590 | if (ipv6_prefix_equal(&key->addr, args->addr, key->plen)) | 862 | if (ipv6_prefix_equal(&key->addr, args->addr, key->plen)) { |
591 | return fn; | 863 | #ifdef CONFIG_IPV6_SUBTREES |
864 | if (fn->subtree) | ||
865 | fn = fib6_lookup_1(fn->subtree, args + 1); | ||
866 | #endif | ||
867 | if (!fn || fn->fn_flags & RTN_RTINFO) | ||
868 | return fn; | ||
869 | } | ||
592 | } | 870 | } |
593 | 871 | ||
872 | if (fn->fn_flags & RTN_ROOT) | ||
873 | break; | ||
874 | |||
594 | fn = fn->parent; | 875 | fn = fn->parent; |
595 | } | 876 | } |
596 | 877 | ||
@@ -600,18 +881,24 @@ static struct fib6_node * fib6_lookup_1(struct fib6_node *root, | |||
600 | struct fib6_node * fib6_lookup(struct fib6_node *root, struct in6_addr *daddr, | 881 | struct fib6_node * fib6_lookup(struct fib6_node *root, struct in6_addr *daddr, |
601 | struct in6_addr *saddr) | 882 | struct in6_addr *saddr) |
602 | { | 883 | { |
603 | struct lookup_args args[2]; | ||
604 | struct fib6_node *fn; | 884 | struct fib6_node *fn; |
605 | 885 | struct lookup_args args[] = { | |
606 | args[0].offset = offsetof(struct rt6_info, rt6i_dst); | 886 | { |
607 | args[0].addr = daddr; | 887 | .offset = offsetof(struct rt6_info, rt6i_dst), |
608 | 888 | .addr = daddr, | |
889 | }, | ||
609 | #ifdef CONFIG_IPV6_SUBTREES | 890 | #ifdef CONFIG_IPV6_SUBTREES |
610 | args[1].offset = offsetof(struct rt6_info, rt6i_src); | 891 | { |
611 | args[1].addr = saddr; | 892 | .offset = offsetof(struct rt6_info, rt6i_src), |
893 | .addr = saddr, | ||
894 | }, | ||
612 | #endif | 895 | #endif |
896 | { | ||
897 | .offset = 0, /* sentinel */ | ||
898 | } | ||
899 | }; | ||
613 | 900 | ||
614 | fn = fib6_lookup_1(root, args); | 901 | fn = fib6_lookup_1(root, daddr ? args : args + 1); |
615 | 902 | ||
616 | if (fn == NULL || fn->fn_flags & RTN_TL_ROOT) | 903 | if (fn == NULL || fn->fn_flags & RTN_TL_ROOT) |
617 | fn = root; | 904 | fn = root; |
@@ -667,10 +954,8 @@ struct fib6_node * fib6_locate(struct fib6_node *root, | |||
667 | #ifdef CONFIG_IPV6_SUBTREES | 954 | #ifdef CONFIG_IPV6_SUBTREES |
668 | if (src_len) { | 955 | if (src_len) { |
669 | BUG_TRAP(saddr!=NULL); | 956 | BUG_TRAP(saddr!=NULL); |
670 | if (fn == NULL) | 957 | if (fn && fn->subtree) |
671 | fn = fn->subtree; | 958 | fn = fib6_locate_1(fn->subtree, saddr, src_len, |
672 | if (fn) | ||
673 | fn = fib6_locate_1(fn, saddr, src_len, | ||
674 | offsetof(struct rt6_info, rt6i_src)); | 959 | offsetof(struct rt6_info, rt6i_src)); |
675 | } | 960 | } |
676 | #endif | 961 | #endif |
@@ -699,7 +984,7 @@ static struct rt6_info * fib6_find_prefix(struct fib6_node *fn) | |||
699 | if(fn->right) | 984 | if(fn->right) |
700 | return fn->right->leaf; | 985 | return fn->right->leaf; |
701 | 986 | ||
702 | fn = SUBTREE(fn); | 987 | fn = FIB6_SUBTREE(fn); |
703 | } | 988 | } |
704 | return NULL; | 989 | return NULL; |
705 | } | 990 | } |
@@ -730,7 +1015,7 @@ static struct fib6_node * fib6_repair_tree(struct fib6_node *fn) | |||
730 | if (fn->right) child = fn->right, children |= 1; | 1015 | if (fn->right) child = fn->right, children |= 1; |
731 | if (fn->left) child = fn->left, children |= 2; | 1016 | if (fn->left) child = fn->left, children |= 2; |
732 | 1017 | ||
733 | if (children == 3 || SUBTREE(fn) | 1018 | if (children == 3 || FIB6_SUBTREE(fn) |
734 | #ifdef CONFIG_IPV6_SUBTREES | 1019 | #ifdef CONFIG_IPV6_SUBTREES |
735 | /* Subtree root (i.e. fn) may have one child */ | 1020 | /* Subtree root (i.e. fn) may have one child */ |
736 | || (children && fn->fn_flags&RTN_ROOT) | 1021 | || (children && fn->fn_flags&RTN_ROOT) |
@@ -749,9 +1034,9 @@ static struct fib6_node * fib6_repair_tree(struct fib6_node *fn) | |||
749 | 1034 | ||
750 | pn = fn->parent; | 1035 | pn = fn->parent; |
751 | #ifdef CONFIG_IPV6_SUBTREES | 1036 | #ifdef CONFIG_IPV6_SUBTREES |
752 | if (SUBTREE(pn) == fn) { | 1037 | if (FIB6_SUBTREE(pn) == fn) { |
753 | BUG_TRAP(fn->fn_flags&RTN_ROOT); | 1038 | BUG_TRAP(fn->fn_flags&RTN_ROOT); |
754 | SUBTREE(pn) = NULL; | 1039 | FIB6_SUBTREE(pn) = NULL; |
755 | nstate = FWS_L; | 1040 | nstate = FWS_L; |
756 | } else { | 1041 | } else { |
757 | BUG_TRAP(!(fn->fn_flags&RTN_ROOT)); | 1042 | BUG_TRAP(!(fn->fn_flags&RTN_ROOT)); |
@@ -799,7 +1084,7 @@ static struct fib6_node * fib6_repair_tree(struct fib6_node *fn) | |||
799 | read_unlock(&fib6_walker_lock); | 1084 | read_unlock(&fib6_walker_lock); |
800 | 1085 | ||
801 | node_free(fn); | 1086 | node_free(fn); |
802 | if (pn->fn_flags&RTN_RTINFO || SUBTREE(pn)) | 1087 | if (pn->fn_flags&RTN_RTINFO || FIB6_SUBTREE(pn)) |
803 | return pn; | 1088 | return pn; |
804 | 1089 | ||
805 | rt6_release(pn->leaf); | 1090 | rt6_release(pn->leaf); |
@@ -809,7 +1094,7 @@ static struct fib6_node * fib6_repair_tree(struct fib6_node *fn) | |||
809 | } | 1094 | } |
810 | 1095 | ||
811 | static void fib6_del_route(struct fib6_node *fn, struct rt6_info **rtp, | 1096 | static void fib6_del_route(struct fib6_node *fn, struct rt6_info **rtp, |
812 | struct nlmsghdr *nlh, void *_rtattr, struct netlink_skb_parms *req) | 1097 | struct nl_info *info) |
813 | { | 1098 | { |
814 | struct fib6_walker_t *w; | 1099 | struct fib6_walker_t *w; |
815 | struct rt6_info *rt = *rtp; | 1100 | struct rt6_info *rt = *rtp; |
@@ -865,11 +1150,11 @@ static void fib6_del_route(struct fib6_node *fn, struct rt6_info **rtp, | |||
865 | if (atomic_read(&rt->rt6i_ref) != 1) BUG(); | 1150 | if (atomic_read(&rt->rt6i_ref) != 1) BUG(); |
866 | } | 1151 | } |
867 | 1152 | ||
868 | inet6_rt_notify(RTM_DELROUTE, rt, nlh, req); | 1153 | inet6_rt_notify(RTM_DELROUTE, rt, info); |
869 | rt6_release(rt); | 1154 | rt6_release(rt); |
870 | } | 1155 | } |
871 | 1156 | ||
872 | int fib6_del(struct rt6_info *rt, struct nlmsghdr *nlh, void *_rtattr, struct netlink_skb_parms *req) | 1157 | int fib6_del(struct rt6_info *rt, struct nl_info *info) |
873 | { | 1158 | { |
874 | struct fib6_node *fn = rt->rt6i_node; | 1159 | struct fib6_node *fn = rt->rt6i_node; |
875 | struct rt6_info **rtp; | 1160 | struct rt6_info **rtp; |
@@ -885,8 +1170,18 @@ int fib6_del(struct rt6_info *rt, struct nlmsghdr *nlh, void *_rtattr, struct ne | |||
885 | 1170 | ||
886 | BUG_TRAP(fn->fn_flags&RTN_RTINFO); | 1171 | BUG_TRAP(fn->fn_flags&RTN_RTINFO); |
887 | 1172 | ||
888 | if (!(rt->rt6i_flags&RTF_CACHE)) | 1173 | if (!(rt->rt6i_flags&RTF_CACHE)) { |
889 | fib6_prune_clones(fn, rt); | 1174 | struct fib6_node *pn = fn; |
1175 | #ifdef CONFIG_IPV6_SUBTREES | ||
1176 | /* clones of this route might be in another subtree */ | ||
1177 | if (rt->rt6i_src.plen) { | ||
1178 | while (!(pn->fn_flags&RTN_ROOT)) | ||
1179 | pn = pn->parent; | ||
1180 | pn = pn->parent; | ||
1181 | } | ||
1182 | #endif | ||
1183 | fib6_prune_clones(pn, rt); | ||
1184 | } | ||
890 | 1185 | ||
891 | /* | 1186 | /* |
892 | * Walk the leaf entries looking for ourself | 1187 | * Walk the leaf entries looking for ourself |
@@ -894,7 +1189,7 @@ int fib6_del(struct rt6_info *rt, struct nlmsghdr *nlh, void *_rtattr, struct ne | |||
894 | 1189 | ||
895 | for (rtp = &fn->leaf; *rtp; rtp = &(*rtp)->u.next) { | 1190 | for (rtp = &fn->leaf; *rtp; rtp = &(*rtp)->u.next) { |
896 | if (*rtp == rt) { | 1191 | if (*rtp == rt) { |
897 | fib6_del_route(fn, rtp, nlh, _rtattr, req); | 1192 | fib6_del_route(fn, rtp, info); |
898 | return 0; | 1193 | return 0; |
899 | } | 1194 | } |
900 | } | 1195 | } |
@@ -925,7 +1220,7 @@ int fib6_del(struct rt6_info *rt, struct nlmsghdr *nlh, void *_rtattr, struct ne | |||
925 | * <0 -> walk is terminated by an error. | 1220 | * <0 -> walk is terminated by an error. |
926 | */ | 1221 | */ |
927 | 1222 | ||
928 | int fib6_walk_continue(struct fib6_walker_t *w) | 1223 | static int fib6_walk_continue(struct fib6_walker_t *w) |
929 | { | 1224 | { |
930 | struct fib6_node *fn, *pn; | 1225 | struct fib6_node *fn, *pn; |
931 | 1226 | ||
@@ -942,8 +1237,8 @@ int fib6_walk_continue(struct fib6_walker_t *w) | |||
942 | switch (w->state) { | 1237 | switch (w->state) { |
943 | #ifdef CONFIG_IPV6_SUBTREES | 1238 | #ifdef CONFIG_IPV6_SUBTREES |
944 | case FWS_S: | 1239 | case FWS_S: |
945 | if (SUBTREE(fn)) { | 1240 | if (FIB6_SUBTREE(fn)) { |
946 | w->node = SUBTREE(fn); | 1241 | w->node = FIB6_SUBTREE(fn); |
947 | continue; | 1242 | continue; |
948 | } | 1243 | } |
949 | w->state = FWS_L; | 1244 | w->state = FWS_L; |
@@ -977,7 +1272,7 @@ int fib6_walk_continue(struct fib6_walker_t *w) | |||
977 | pn = fn->parent; | 1272 | pn = fn->parent; |
978 | w->node = pn; | 1273 | w->node = pn; |
979 | #ifdef CONFIG_IPV6_SUBTREES | 1274 | #ifdef CONFIG_IPV6_SUBTREES |
980 | if (SUBTREE(pn) == fn) { | 1275 | if (FIB6_SUBTREE(pn) == fn) { |
981 | BUG_TRAP(fn->fn_flags&RTN_ROOT); | 1276 | BUG_TRAP(fn->fn_flags&RTN_ROOT); |
982 | w->state = FWS_L; | 1277 | w->state = FWS_L; |
983 | continue; | 1278 | continue; |
@@ -999,7 +1294,7 @@ int fib6_walk_continue(struct fib6_walker_t *w) | |||
999 | } | 1294 | } |
1000 | } | 1295 | } |
1001 | 1296 | ||
1002 | int fib6_walk(struct fib6_walker_t *w) | 1297 | static int fib6_walk(struct fib6_walker_t *w) |
1003 | { | 1298 | { |
1004 | int res; | 1299 | int res; |
1005 | 1300 | ||
@@ -1023,7 +1318,7 @@ static int fib6_clean_node(struct fib6_walker_t *w) | |||
1023 | res = c->func(rt, c->arg); | 1318 | res = c->func(rt, c->arg); |
1024 | if (res < 0) { | 1319 | if (res < 0) { |
1025 | w->leaf = rt; | 1320 | w->leaf = rt; |
1026 | res = fib6_del(rt, NULL, NULL, NULL); | 1321 | res = fib6_del(rt, NULL); |
1027 | if (res) { | 1322 | if (res) { |
1028 | #if RT6_DEBUG >= 2 | 1323 | #if RT6_DEBUG >= 2 |
1029 | printk(KERN_DEBUG "fib6_clean_node: del failed: rt=%p@%p err=%d\n", rt, rt->rt6i_node, res); | 1324 | printk(KERN_DEBUG "fib6_clean_node: del failed: rt=%p@%p err=%d\n", rt, rt->rt6i_node, res); |
@@ -1049,9 +1344,9 @@ static int fib6_clean_node(struct fib6_walker_t *w) | |||
1049 | * ignoring pure split nodes) will be scanned. | 1344 | * ignoring pure split nodes) will be scanned. |
1050 | */ | 1345 | */ |
1051 | 1346 | ||
1052 | void fib6_clean_tree(struct fib6_node *root, | 1347 | static void fib6_clean_tree(struct fib6_node *root, |
1053 | int (*func)(struct rt6_info *, void *arg), | 1348 | int (*func)(struct rt6_info *, void *arg), |
1054 | int prune, void *arg) | 1349 | int prune, void *arg) |
1055 | { | 1350 | { |
1056 | struct fib6_cleaner_t c; | 1351 | struct fib6_cleaner_t c; |
1057 | 1352 | ||
@@ -1064,6 +1359,25 @@ void fib6_clean_tree(struct fib6_node *root, | |||
1064 | fib6_walk(&c.w); | 1359 | fib6_walk(&c.w); |
1065 | } | 1360 | } |
1066 | 1361 | ||
1362 | void fib6_clean_all(int (*func)(struct rt6_info *, void *arg), | ||
1363 | int prune, void *arg) | ||
1364 | { | ||
1365 | struct fib6_table *table; | ||
1366 | struct hlist_node *node; | ||
1367 | unsigned int h; | ||
1368 | |||
1369 | rcu_read_lock(); | ||
1370 | for (h = 0; h < FIB_TABLE_HASHSZ; h++) { | ||
1371 | hlist_for_each_entry_rcu(table, node, &fib_table_hash[h], | ||
1372 | tb6_hlist) { | ||
1373 | write_lock_bh(&table->tb6_lock); | ||
1374 | fib6_clean_tree(&table->tb6_root, func, prune, arg); | ||
1375 | write_unlock_bh(&table->tb6_lock); | ||
1376 | } | ||
1377 | } | ||
1378 | rcu_read_unlock(); | ||
1379 | } | ||
1380 | |||
1067 | static int fib6_prune_clone(struct rt6_info *rt, void *arg) | 1381 | static int fib6_prune_clone(struct rt6_info *rt, void *arg) |
1068 | { | 1382 | { |
1069 | if (rt->rt6i_flags & RTF_CACHE) { | 1383 | if (rt->rt6i_flags & RTF_CACHE) { |
@@ -1142,11 +1456,8 @@ void fib6_run_gc(unsigned long dummy) | |||
1142 | } | 1456 | } |
1143 | gc_args.more = 0; | 1457 | gc_args.more = 0; |
1144 | 1458 | ||
1145 | |||
1146 | write_lock_bh(&rt6_lock); | ||
1147 | ndisc_dst_gc(&gc_args.more); | 1459 | ndisc_dst_gc(&gc_args.more); |
1148 | fib6_clean_tree(&ip6_routing_table, fib6_age, 0, NULL); | 1460 | fib6_clean_all(fib6_age, 0, NULL); |
1149 | write_unlock_bh(&rt6_lock); | ||
1150 | 1461 | ||
1151 | if (gc_args.more) | 1462 | if (gc_args.more) |
1152 | mod_timer(&ip6_fib_timer, jiffies + ip6_rt_gc_interval); | 1463 | mod_timer(&ip6_fib_timer, jiffies + ip6_rt_gc_interval); |
@@ -1161,10 +1472,10 @@ void __init fib6_init(void) | |||
1161 | { | 1472 | { |
1162 | fib6_node_kmem = kmem_cache_create("fib6_nodes", | 1473 | fib6_node_kmem = kmem_cache_create("fib6_nodes", |
1163 | sizeof(struct fib6_node), | 1474 | sizeof(struct fib6_node), |
1164 | 0, SLAB_HWCACHE_ALIGN, | 1475 | 0, SLAB_HWCACHE_ALIGN|SLAB_PANIC, |
1165 | NULL, NULL); | 1476 | NULL, NULL); |
1166 | if (!fib6_node_kmem) | 1477 | |
1167 | panic("cannot create fib6_nodes cache"); | 1478 | fib6_tables_init(); |
1168 | } | 1479 | } |
1169 | 1480 | ||
1170 | void fib6_gc_cleanup(void) | 1481 | void fib6_gc_cleanup(void) |
diff --git a/net/ipv6/ip6_input.c b/net/ipv6/ip6_input.c index 25c2a9e03895..6b8e6d76a58b 100644 --- a/net/ipv6/ip6_input.c +++ b/net/ipv6/ip6_input.c | |||
@@ -111,7 +111,7 @@ int ipv6_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt | |||
111 | } | 111 | } |
112 | 112 | ||
113 | if (hdr->nexthdr == NEXTHDR_HOP) { | 113 | if (hdr->nexthdr == NEXTHDR_HOP) { |
114 | if (ipv6_parse_hopopts(skb) < 0) { | 114 | if (ipv6_parse_hopopts(&skb) < 0) { |
115 | IP6_INC_STATS_BH(IPSTATS_MIB_INHDRERRORS); | 115 | IP6_INC_STATS_BH(IPSTATS_MIB_INHDRERRORS); |
116 | return 0; | 116 | return 0; |
117 | } | 117 | } |
diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c index 4fb47a252913..66716911962e 100644 --- a/net/ipv6/ip6_output.c +++ b/net/ipv6/ip6_output.c | |||
@@ -308,6 +308,56 @@ static int ip6_call_ra_chain(struct sk_buff *skb, int sel) | |||
308 | return 0; | 308 | return 0; |
309 | } | 309 | } |
310 | 310 | ||
311 | static int ip6_forward_proxy_check(struct sk_buff *skb) | ||
312 | { | ||
313 | struct ipv6hdr *hdr = skb->nh.ipv6h; | ||
314 | u8 nexthdr = hdr->nexthdr; | ||
315 | int offset; | ||
316 | |||
317 | if (ipv6_ext_hdr(nexthdr)) { | ||
318 | offset = ipv6_skip_exthdr(skb, sizeof(*hdr), &nexthdr); | ||
319 | if (offset < 0) | ||
320 | return 0; | ||
321 | } else | ||
322 | offset = sizeof(struct ipv6hdr); | ||
323 | |||
324 | if (nexthdr == IPPROTO_ICMPV6) { | ||
325 | struct icmp6hdr *icmp6; | ||
326 | |||
327 | if (!pskb_may_pull(skb, skb->nh.raw + offset + 1 - skb->data)) | ||
328 | return 0; | ||
329 | |||
330 | icmp6 = (struct icmp6hdr *)(skb->nh.raw + offset); | ||
331 | |||
332 | switch (icmp6->icmp6_type) { | ||
333 | case NDISC_ROUTER_SOLICITATION: | ||
334 | case NDISC_ROUTER_ADVERTISEMENT: | ||
335 | case NDISC_NEIGHBOUR_SOLICITATION: | ||
336 | case NDISC_NEIGHBOUR_ADVERTISEMENT: | ||
337 | case NDISC_REDIRECT: | ||
338 | /* For reaction involving unicast neighbor discovery | ||
339 | * message destined to the proxied address, pass it to | ||
340 | * input function. | ||
341 | */ | ||
342 | return 1; | ||
343 | default: | ||
344 | break; | ||
345 | } | ||
346 | } | ||
347 | |||
348 | /* | ||
349 | * The proxying router can't forward traffic sent to a link-local | ||
350 | * address, so signal the sender and discard the packet. This | ||
351 | * behavior is clarified by the MIPv6 specification. | ||
352 | */ | ||
353 | if (ipv6_addr_type(&hdr->daddr) & IPV6_ADDR_LINKLOCAL) { | ||
354 | dst_link_failure(skb); | ||
355 | return -1; | ||
356 | } | ||
357 | |||
358 | return 0; | ||
359 | } | ||
360 | |||
311 | static inline int ip6_forward_finish(struct sk_buff *skb) | 361 | static inline int ip6_forward_finish(struct sk_buff *skb) |
312 | { | 362 | { |
313 | return dst_output(skb); | 363 | return dst_output(skb); |
@@ -362,6 +412,18 @@ int ip6_forward(struct sk_buff *skb) | |||
362 | return -ETIMEDOUT; | 412 | return -ETIMEDOUT; |
363 | } | 413 | } |
364 | 414 | ||
415 | /* XXX: idev->cnf.proxy_ndp? */ | ||
416 | if (ipv6_devconf.proxy_ndp && | ||
417 | pneigh_lookup(&nd_tbl, &hdr->daddr, skb->dev, 0)) { | ||
418 | int proxied = ip6_forward_proxy_check(skb); | ||
419 | if (proxied > 0) | ||
420 | return ip6_input(skb); | ||
421 | else if (proxied < 0) { | ||
422 | IP6_INC_STATS(IPSTATS_MIB_INDISCARDS); | ||
423 | goto drop; | ||
424 | } | ||
425 | } | ||
426 | |||
365 | if (!xfrm6_route_forward(skb)) { | 427 | if (!xfrm6_route_forward(skb)) { |
366 | IP6_INC_STATS(IPSTATS_MIB_INDISCARDS); | 428 | IP6_INC_STATS(IPSTATS_MIB_INDISCARDS); |
367 | goto drop; | 429 | goto drop; |
@@ -475,17 +537,25 @@ int ip6_find_1stfragopt(struct sk_buff *skb, u8 **nexthdr) | |||
475 | switch (**nexthdr) { | 537 | switch (**nexthdr) { |
476 | 538 | ||
477 | case NEXTHDR_HOP: | 539 | case NEXTHDR_HOP: |
540 | break; | ||
478 | case NEXTHDR_ROUTING: | 541 | case NEXTHDR_ROUTING: |
542 | found_rhdr = 1; | ||
543 | break; | ||
479 | case NEXTHDR_DEST: | 544 | case NEXTHDR_DEST: |
480 | if (**nexthdr == NEXTHDR_ROUTING) found_rhdr = 1; | 545 | #ifdef CONFIG_IPV6_MIP6 |
481 | if (**nexthdr == NEXTHDR_DEST && found_rhdr) return offset; | 546 | if (ipv6_find_tlv(skb, offset, IPV6_TLV_HAO) >= 0) |
482 | offset += ipv6_optlen(exthdr); | 547 | break; |
483 | *nexthdr = &exthdr->nexthdr; | 548 | #endif |
484 | exthdr = (struct ipv6_opt_hdr*)(skb->nh.raw + offset); | 549 | if (found_rhdr) |
550 | return offset; | ||
485 | break; | 551 | break; |
486 | default : | 552 | default : |
487 | return offset; | 553 | return offset; |
488 | } | 554 | } |
555 | |||
556 | offset += ipv6_optlen(exthdr); | ||
557 | *nexthdr = &exthdr->nexthdr; | ||
558 | exthdr = (struct ipv6_opt_hdr*)(skb->nh.raw + offset); | ||
489 | } | 559 | } |
490 | 560 | ||
491 | return offset; | 561 | return offset; |
@@ -726,6 +796,14 @@ fail: | |||
726 | return err; | 796 | return err; |
727 | } | 797 | } |
728 | 798 | ||
799 | static inline int ip6_rt_check(struct rt6key *rt_key, | ||
800 | struct in6_addr *fl_addr, | ||
801 | struct in6_addr *addr_cache) | ||
802 | { | ||
803 | return ((rt_key->plen != 128 || !ipv6_addr_equal(fl_addr, &rt_key->addr)) && | ||
804 | (addr_cache == NULL || !ipv6_addr_equal(fl_addr, addr_cache))); | ||
805 | } | ||
806 | |||
729 | static struct dst_entry *ip6_sk_dst_check(struct sock *sk, | 807 | static struct dst_entry *ip6_sk_dst_check(struct sock *sk, |
730 | struct dst_entry *dst, | 808 | struct dst_entry *dst, |
731 | struct flowi *fl) | 809 | struct flowi *fl) |
@@ -741,8 +819,8 @@ static struct dst_entry *ip6_sk_dst_check(struct sock *sk, | |||
741 | * that we do not support routing by source, TOS, | 819 | * that we do not support routing by source, TOS, |
742 | * and MSG_DONTROUTE --ANK (980726) | 820 | * and MSG_DONTROUTE --ANK (980726) |
743 | * | 821 | * |
744 | * 1. If route was host route, check that | 822 | * 1. ip6_rt_check(): If route was host route, |
745 | * cached destination is current. | 823 | * check that cached destination is current. |
746 | * If it is network route, we still may | 824 | * If it is network route, we still may |
747 | * check its validity using saved pointer | 825 | * check its validity using saved pointer |
748 | * to the last used address: daddr_cache. | 826 | * to the last used address: daddr_cache. |
@@ -753,11 +831,11 @@ static struct dst_entry *ip6_sk_dst_check(struct sock *sk, | |||
753 | * sockets. | 831 | * sockets. |
754 | * 2. oif also should be the same. | 832 | * 2. oif also should be the same. |
755 | */ | 833 | */ |
756 | if (((rt->rt6i_dst.plen != 128 || | 834 | if (ip6_rt_check(&rt->rt6i_dst, &fl->fl6_dst, np->daddr_cache) || |
757 | !ipv6_addr_equal(&fl->fl6_dst, &rt->rt6i_dst.addr)) | 835 | #ifdef CONFIG_IPV6_SUBTREES |
758 | && (np->daddr_cache == NULL || | 836 | ip6_rt_check(&rt->rt6i_src, &fl->fl6_src, np->saddr_cache) || |
759 | !ipv6_addr_equal(&fl->fl6_dst, np->daddr_cache))) | 837 | #endif |
760 | || (fl->oif && fl->oif != dst->dev->ifindex)) { | 838 | (fl->oif && fl->oif != dst->dev->ifindex)) { |
761 | dst_release(dst); | 839 | dst_release(dst); |
762 | dst = NULL; | 840 | dst = NULL; |
763 | } | 841 | } |
@@ -866,7 +944,7 @@ static inline int ip6_ufo_append_data(struct sock *sk, | |||
866 | /* initialize protocol header pointer */ | 944 | /* initialize protocol header pointer */ |
867 | skb->h.raw = skb->data + fragheaderlen; | 945 | skb->h.raw = skb->data + fragheaderlen; |
868 | 946 | ||
869 | skb->ip_summed = CHECKSUM_HW; | 947 | skb->ip_summed = CHECKSUM_PARTIAL; |
870 | skb->csum = 0; | 948 | skb->csum = 0; |
871 | sk->sk_sndmsg_off = 0; | 949 | sk->sk_sndmsg_off = 0; |
872 | } | 950 | } |
@@ -963,7 +1041,7 @@ int ip6_append_data(struct sock *sk, int getfrag(void *from, char *to, | |||
963 | 1041 | ||
964 | hh_len = LL_RESERVED_SPACE(rt->u.dst.dev); | 1042 | hh_len = LL_RESERVED_SPACE(rt->u.dst.dev); |
965 | 1043 | ||
966 | fragheaderlen = sizeof(struct ipv6hdr) + (opt ? opt->opt_nflen : 0); | 1044 | fragheaderlen = sizeof(struct ipv6hdr) + rt->u.dst.nfheader_len + (opt ? opt->opt_nflen : 0); |
967 | maxfraglen = ((mtu - fragheaderlen) & ~7) + fragheaderlen - sizeof(struct frag_hdr); | 1045 | maxfraglen = ((mtu - fragheaderlen) & ~7) + fragheaderlen - sizeof(struct frag_hdr); |
968 | 1046 | ||
969 | if (mtu <= sizeof(struct ipv6hdr) + IPV6_MAXPLEN) { | 1047 | if (mtu <= sizeof(struct ipv6hdr) + IPV6_MAXPLEN) { |
diff --git a/net/ipv6/ipcomp6.c b/net/ipv6/ipcomp6.c index a81e9e9d93bd..ad9c6e824e62 100644 --- a/net/ipv6/ipcomp6.c +++ b/net/ipv6/ipcomp6.c | |||
@@ -212,7 +212,7 @@ static struct xfrm_state *ipcomp6_tunnel_create(struct xfrm_state *x) | |||
212 | memcpy(t->id.daddr.a6, x->id.daddr.a6, sizeof(struct in6_addr)); | 212 | memcpy(t->id.daddr.a6, x->id.daddr.a6, sizeof(struct in6_addr)); |
213 | memcpy(&t->sel, &x->sel, sizeof(t->sel)); | 213 | memcpy(&t->sel, &x->sel, sizeof(t->sel)); |
214 | t->props.family = AF_INET6; | 214 | t->props.family = AF_INET6; |
215 | t->props.mode = 1; | 215 | t->props.mode = XFRM_MODE_TUNNEL; |
216 | memcpy(t->props.saddr.a6, x->props.saddr.a6, sizeof(struct in6_addr)); | 216 | memcpy(t->props.saddr.a6, x->props.saddr.a6, sizeof(struct in6_addr)); |
217 | 217 | ||
218 | if (xfrm_init_state(t)) | 218 | if (xfrm_init_state(t)) |
@@ -417,7 +417,7 @@ static int ipcomp6_init_state(struct xfrm_state *x) | |||
417 | goto out; | 417 | goto out; |
418 | 418 | ||
419 | x->props.header_len = 0; | 419 | x->props.header_len = 0; |
420 | if (x->props.mode) | 420 | if (x->props.mode == XFRM_MODE_TUNNEL) |
421 | x->props.header_len += sizeof(struct ipv6hdr); | 421 | x->props.header_len += sizeof(struct ipv6hdr); |
422 | 422 | ||
423 | mutex_lock(&ipcomp6_resource_mutex); | 423 | mutex_lock(&ipcomp6_resource_mutex); |
@@ -429,7 +429,7 @@ static int ipcomp6_init_state(struct xfrm_state *x) | |||
429 | goto error; | 429 | goto error; |
430 | mutex_unlock(&ipcomp6_resource_mutex); | 430 | mutex_unlock(&ipcomp6_resource_mutex); |
431 | 431 | ||
432 | if (x->props.mode) { | 432 | if (x->props.mode == XFRM_MODE_TUNNEL) { |
433 | err = ipcomp6_tunnel_attach(x); | 433 | err = ipcomp6_tunnel_attach(x); |
434 | if (err) | 434 | if (err) |
435 | goto error_tunnel; | 435 | goto error_tunnel; |
@@ -461,6 +461,7 @@ static struct xfrm_type ipcomp6_type = | |||
461 | .destructor = ipcomp6_destroy, | 461 | .destructor = ipcomp6_destroy, |
462 | .input = ipcomp6_input, | 462 | .input = ipcomp6_input, |
463 | .output = ipcomp6_output, | 463 | .output = ipcomp6_output, |
464 | .hdr_offset = xfrm6_find_1stfragopt, | ||
464 | }; | 465 | }; |
465 | 466 | ||
466 | static struct inet6_protocol ipcomp6_protocol = | 467 | static struct inet6_protocol ipcomp6_protocol = |
diff --git a/net/ipv6/ipv6_sockglue.c b/net/ipv6/ipv6_sockglue.c index a5eaaf693abf..4f3bb7fcc8b5 100644 --- a/net/ipv6/ipv6_sockglue.c +++ b/net/ipv6/ipv6_sockglue.c | |||
@@ -407,8 +407,16 @@ static int do_ipv6_setsockopt(struct sock *sk, int level, int optname, | |||
407 | /* routing header option needs extra check */ | 407 | /* routing header option needs extra check */ |
408 | if (optname == IPV6_RTHDR && opt->srcrt) { | 408 | if (optname == IPV6_RTHDR && opt->srcrt) { |
409 | struct ipv6_rt_hdr *rthdr = opt->srcrt; | 409 | struct ipv6_rt_hdr *rthdr = opt->srcrt; |
410 | if (rthdr->type) | 410 | switch (rthdr->type) { |
411 | case IPV6_SRCRT_TYPE_0: | ||
412 | #ifdef CONFIG_IPV6_MIP6 | ||
413 | case IPV6_SRCRT_TYPE_2: | ||
414 | #endif | ||
415 | break; | ||
416 | default: | ||
411 | goto sticky_done; | 417 | goto sticky_done; |
418 | } | ||
419 | |||
412 | if ((rthdr->hdrlen & 1) || | 420 | if ((rthdr->hdrlen & 1) || |
413 | (rthdr->hdrlen >> 1) != rthdr->segments_left) | 421 | (rthdr->hdrlen >> 1) != rthdr->segments_left) |
414 | goto sticky_done; | 422 | goto sticky_done; |
diff --git a/net/ipv6/ipv6_syms.c b/net/ipv6/ipv6_syms.c index dd4d1ce77769..0e8e0676a033 100644 --- a/net/ipv6/ipv6_syms.c +++ b/net/ipv6/ipv6_syms.c | |||
@@ -14,7 +14,6 @@ EXPORT_SYMBOL(ndisc_mc_map); | |||
14 | EXPORT_SYMBOL(register_inet6addr_notifier); | 14 | EXPORT_SYMBOL(register_inet6addr_notifier); |
15 | EXPORT_SYMBOL(unregister_inet6addr_notifier); | 15 | EXPORT_SYMBOL(unregister_inet6addr_notifier); |
16 | EXPORT_SYMBOL(ip6_route_output); | 16 | EXPORT_SYMBOL(ip6_route_output); |
17 | EXPORT_SYMBOL(addrconf_lock); | ||
18 | EXPORT_SYMBOL(ipv6_setsockopt); | 17 | EXPORT_SYMBOL(ipv6_setsockopt); |
19 | EXPORT_SYMBOL(ipv6_getsockopt); | 18 | EXPORT_SYMBOL(ipv6_getsockopt); |
20 | EXPORT_SYMBOL(inet6_register_protosw); | 19 | EXPORT_SYMBOL(inet6_register_protosw); |
@@ -31,6 +30,8 @@ EXPORT_SYMBOL(ipv6_chk_addr); | |||
31 | EXPORT_SYMBOL(in6_dev_finish_destroy); | 30 | EXPORT_SYMBOL(in6_dev_finish_destroy); |
32 | #ifdef CONFIG_XFRM | 31 | #ifdef CONFIG_XFRM |
33 | EXPORT_SYMBOL(xfrm6_rcv); | 32 | EXPORT_SYMBOL(xfrm6_rcv); |
33 | EXPORT_SYMBOL(xfrm6_input_addr); | ||
34 | EXPORT_SYMBOL(xfrm6_find_1stfragopt); | ||
34 | #endif | 35 | #endif |
35 | EXPORT_SYMBOL(rt6_lookup); | 36 | EXPORT_SYMBOL(rt6_lookup); |
36 | EXPORT_SYMBOL(ipv6_push_nfrag_opts); | 37 | EXPORT_SYMBOL(ipv6_push_nfrag_opts); |
diff --git a/net/ipv6/mcast.c b/net/ipv6/mcast.c index 639eb20c9f1f..3b114e3fa2f8 100644 --- a/net/ipv6/mcast.c +++ b/net/ipv6/mcast.c | |||
@@ -171,7 +171,7 @@ static int ip6_mc_leave_src(struct sock *sk, struct ipv6_mc_socklist *iml, | |||
171 | 171 | ||
172 | #define IPV6_MLD_MAX_MSF 64 | 172 | #define IPV6_MLD_MAX_MSF 64 |
173 | 173 | ||
174 | int sysctl_mld_max_msf = IPV6_MLD_MAX_MSF; | 174 | int sysctl_mld_max_msf __read_mostly = IPV6_MLD_MAX_MSF; |
175 | 175 | ||
176 | /* | 176 | /* |
177 | * socket join on multicast group | 177 | * socket join on multicast group |
diff --git a/net/ipv6/mip6.c b/net/ipv6/mip6.c new file mode 100644 index 000000000000..99d116caecda --- /dev/null +++ b/net/ipv6/mip6.c | |||
@@ -0,0 +1,519 @@ | |||
1 | /* | ||
2 | * Copyright (C)2003-2006 Helsinki University of Technology | ||
3 | * Copyright (C)2003-2006 USAGI/WIDE Project | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or modify | ||
6 | * it under the terms of the GNU General Public License as published by | ||
7 | * the Free Software Foundation; either version 2 of the License, or | ||
8 | * (at your option) any later version. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | * GNU General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License | ||
16 | * along with this program; if not, write to the Free Software | ||
17 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
18 | */ | ||
19 | /* | ||
20 | * Authors: | ||
21 | * Noriaki TAKAMIYA @USAGI | ||
22 | * Masahide NAKAMURA @USAGI | ||
23 | */ | ||
24 | |||
25 | #include <linux/config.h> | ||
26 | #include <linux/module.h> | ||
27 | #include <linux/skbuff.h> | ||
28 | #include <linux/time.h> | ||
29 | #include <linux/ipv6.h> | ||
30 | #include <linux/icmpv6.h> | ||
31 | #include <net/sock.h> | ||
32 | #include <net/ipv6.h> | ||
33 | #include <net/ip6_checksum.h> | ||
34 | #include <net/xfrm.h> | ||
35 | #include <net/mip6.h> | ||
36 | |||
37 | static xfrm_address_t *mip6_xfrm_addr(struct xfrm_state *x, xfrm_address_t *addr) | ||
38 | { | ||
39 | return x->coaddr; | ||
40 | } | ||
41 | |||
42 | static inline unsigned int calc_padlen(unsigned int len, unsigned int n) | ||
43 | { | ||
44 | return (n - len + 16) & 0x7; | ||
45 | } | ||
46 | |||
47 | static inline void *mip6_padn(__u8 *data, __u8 padlen) | ||
48 | { | ||
49 | if (!data) | ||
50 | return NULL; | ||
51 | if (padlen == 1) { | ||
52 | data[0] = MIP6_OPT_PAD_1; | ||
53 | } else if (padlen > 1) { | ||
54 | data[0] = MIP6_OPT_PAD_N; | ||
55 | data[1] = padlen - 2; | ||
56 | if (padlen > 2) | ||
57 | memset(data+2, 0, data[1]); | ||
58 | } | ||
59 | return data + padlen; | ||
60 | } | ||
61 | |||
62 | static inline void mip6_param_prob(struct sk_buff *skb, int code, int pos) | ||
63 | { | ||
64 | icmpv6_send(skb, ICMPV6_PARAMPROB, code, pos, skb->dev); | ||
65 | } | ||
66 | |||
67 | static int mip6_mh_len(int type) | ||
68 | { | ||
69 | int len = 0; | ||
70 | |||
71 | switch (type) { | ||
72 | case IP6_MH_TYPE_BRR: | ||
73 | len = 0; | ||
74 | break; | ||
75 | case IP6_MH_TYPE_HOTI: | ||
76 | case IP6_MH_TYPE_COTI: | ||
77 | case IP6_MH_TYPE_BU: | ||
78 | case IP6_MH_TYPE_BACK: | ||
79 | len = 1; | ||
80 | break; | ||
81 | case IP6_MH_TYPE_HOT: | ||
82 | case IP6_MH_TYPE_COT: | ||
83 | case IP6_MH_TYPE_BERROR: | ||
84 | len = 2; | ||
85 | break; | ||
86 | } | ||
87 | return len; | ||
88 | } | ||
89 | |||
90 | int mip6_mh_filter(struct sock *sk, struct sk_buff *skb) | ||
91 | { | ||
92 | struct ip6_mh *mh; | ||
93 | int mhlen; | ||
94 | |||
95 | if (!pskb_may_pull(skb, (skb->h.raw - skb->data) + 8) || | ||
96 | !pskb_may_pull(skb, (skb->h.raw - skb->data) + ((skb->h.raw[1] + 1) << 3))) | ||
97 | return -1; | ||
98 | |||
99 | mh = (struct ip6_mh *)skb->h.raw; | ||
100 | |||
101 | if (mh->ip6mh_hdrlen < mip6_mh_len(mh->ip6mh_type)) { | ||
102 | LIMIT_NETDEBUG(KERN_DEBUG "mip6: MH message too short: %d vs >=%d\n", | ||
103 | mh->ip6mh_hdrlen, mip6_mh_len(mh->ip6mh_type)); | ||
104 | mip6_param_prob(skb, 0, (&mh->ip6mh_hdrlen) - skb->nh.raw); | ||
105 | return -1; | ||
106 | } | ||
107 | mhlen = (mh->ip6mh_hdrlen + 1) << 3; | ||
108 | |||
109 | if (skb->ip_summed == CHECKSUM_COMPLETE) { | ||
110 | skb->ip_summed = CHECKSUM_UNNECESSARY; | ||
111 | if (csum_ipv6_magic(&skb->nh.ipv6h->saddr, | ||
112 | &skb->nh.ipv6h->daddr, | ||
113 | mhlen, IPPROTO_MH, | ||
114 | skb->csum)) { | ||
115 | LIMIT_NETDEBUG(KERN_DEBUG "mip6: MH hw checksum failed\n"); | ||
116 | skb->ip_summed = CHECKSUM_NONE; | ||
117 | } | ||
118 | } | ||
119 | if (skb->ip_summed == CHECKSUM_NONE) { | ||
120 | if (csum_ipv6_magic(&skb->nh.ipv6h->saddr, | ||
121 | &skb->nh.ipv6h->daddr, | ||
122 | mhlen, IPPROTO_MH, | ||
123 | skb_checksum(skb, 0, mhlen, 0))) { | ||
124 | LIMIT_NETDEBUG(KERN_DEBUG "mip6: MH checksum failed " | ||
125 | "[" NIP6_FMT " > " NIP6_FMT "]\n", | ||
126 | NIP6(skb->nh.ipv6h->saddr), | ||
127 | NIP6(skb->nh.ipv6h->daddr)); | ||
128 | return -1; | ||
129 | } | ||
130 | skb->ip_summed = CHECKSUM_UNNECESSARY; | ||
131 | } | ||
132 | |||
133 | if (mh->ip6mh_proto != IPPROTO_NONE) { | ||
134 | LIMIT_NETDEBUG(KERN_DEBUG "mip6: MH invalid payload proto = %d\n", | ||
135 | mh->ip6mh_proto); | ||
136 | mip6_param_prob(skb, 0, (&mh->ip6mh_proto) - skb->nh.raw); | ||
137 | return -1; | ||
138 | } | ||
139 | |||
140 | return 0; | ||
141 | } | ||
142 | |||
143 | struct mip6_report_rate_limiter { | ||
144 | spinlock_t lock; | ||
145 | struct timeval stamp; | ||
146 | int iif; | ||
147 | struct in6_addr src; | ||
148 | struct in6_addr dst; | ||
149 | }; | ||
150 | |||
151 | static struct mip6_report_rate_limiter mip6_report_rl = { | ||
152 | .lock = SPIN_LOCK_UNLOCKED | ||
153 | }; | ||
154 | |||
155 | static int mip6_destopt_input(struct xfrm_state *x, struct sk_buff *skb) | ||
156 | { | ||
157 | struct ipv6hdr *iph = skb->nh.ipv6h; | ||
158 | struct ipv6_destopt_hdr *destopt = (struct ipv6_destopt_hdr *)skb->data; | ||
159 | |||
160 | if (!ipv6_addr_equal(&iph->saddr, (struct in6_addr *)x->coaddr) && | ||
161 | !ipv6_addr_any((struct in6_addr *)x->coaddr)) | ||
162 | return -ENOENT; | ||
163 | |||
164 | return destopt->nexthdr; | ||
165 | } | ||
166 | |||
167 | /* Destination Option Header is inserted. | ||
168 | * IP Header's src address is replaced with Home Address Option in | ||
169 | * Destination Option Header. | ||
170 | */ | ||
171 | static int mip6_destopt_output(struct xfrm_state *x, struct sk_buff *skb) | ||
172 | { | ||
173 | struct ipv6hdr *iph; | ||
174 | struct ipv6_destopt_hdr *dstopt; | ||
175 | struct ipv6_destopt_hao *hao; | ||
176 | u8 nexthdr; | ||
177 | int len; | ||
178 | |||
179 | iph = (struct ipv6hdr *)skb->data; | ||
180 | iph->payload_len = htons(skb->len - sizeof(*iph)); | ||
181 | |||
182 | nexthdr = *skb->nh.raw; | ||
183 | *skb->nh.raw = IPPROTO_DSTOPTS; | ||
184 | |||
185 | dstopt = (struct ipv6_destopt_hdr *)skb->h.raw; | ||
186 | dstopt->nexthdr = nexthdr; | ||
187 | |||
188 | hao = mip6_padn((char *)(dstopt + 1), | ||
189 | calc_padlen(sizeof(*dstopt), 6)); | ||
190 | |||
191 | hao->type = IPV6_TLV_HAO; | ||
192 | hao->length = sizeof(*hao) - 2; | ||
193 | BUG_TRAP(hao->length == 16); | ||
194 | |||
195 | len = ((char *)hao - (char *)dstopt) + sizeof(*hao); | ||
196 | |||
197 | memcpy(&hao->addr, &iph->saddr, sizeof(hao->addr)); | ||
198 | memcpy(&iph->saddr, x->coaddr, sizeof(iph->saddr)); | ||
199 | |||
200 | BUG_TRAP(len == x->props.header_len); | ||
201 | dstopt->hdrlen = (x->props.header_len >> 3) - 1; | ||
202 | |||
203 | return 0; | ||
204 | } | ||
205 | |||
206 | static inline int mip6_report_rl_allow(struct timeval *stamp, | ||
207 | struct in6_addr *dst, | ||
208 | struct in6_addr *src, int iif) | ||
209 | { | ||
210 | int allow = 0; | ||
211 | |||
212 | spin_lock_bh(&mip6_report_rl.lock); | ||
213 | if (mip6_report_rl.stamp.tv_sec != stamp->tv_sec || | ||
214 | mip6_report_rl.stamp.tv_usec != stamp->tv_usec || | ||
215 | mip6_report_rl.iif != iif || | ||
216 | !ipv6_addr_equal(&mip6_report_rl.src, src) || | ||
217 | !ipv6_addr_equal(&mip6_report_rl.dst, dst)) { | ||
218 | mip6_report_rl.stamp.tv_sec = stamp->tv_sec; | ||
219 | mip6_report_rl.stamp.tv_usec = stamp->tv_usec; | ||
220 | mip6_report_rl.iif = iif; | ||
221 | ipv6_addr_copy(&mip6_report_rl.src, src); | ||
222 | ipv6_addr_copy(&mip6_report_rl.dst, dst); | ||
223 | allow = 1; | ||
224 | } | ||
225 | spin_unlock_bh(&mip6_report_rl.lock); | ||
226 | return allow; | ||
227 | } | ||
228 | |||
229 | static int mip6_destopt_reject(struct xfrm_state *x, struct sk_buff *skb, struct flowi *fl) | ||
230 | { | ||
231 | struct inet6_skb_parm *opt = (struct inet6_skb_parm *)skb->cb; | ||
232 | struct ipv6_destopt_hao *hao = NULL; | ||
233 | struct xfrm_selector sel; | ||
234 | int offset; | ||
235 | struct timeval stamp; | ||
236 | int err = 0; | ||
237 | |||
238 | if (unlikely(fl->proto == IPPROTO_MH && | ||
239 | fl->fl_mh_type <= IP6_MH_TYPE_MAX)) | ||
240 | goto out; | ||
241 | |||
242 | if (likely(opt->dsthao)) { | ||
243 | offset = ipv6_find_tlv(skb, opt->dsthao, IPV6_TLV_HAO); | ||
244 | if (likely(offset >= 0)) | ||
245 | hao = (struct ipv6_destopt_hao *)(skb->nh.raw + offset); | ||
246 | } | ||
247 | |||
248 | skb_get_timestamp(skb, &stamp); | ||
249 | |||
250 | if (!mip6_report_rl_allow(&stamp, &skb->nh.ipv6h->daddr, | ||
251 | hao ? &hao->addr : &skb->nh.ipv6h->saddr, | ||
252 | opt->iif)) | ||
253 | goto out; | ||
254 | |||
255 | memset(&sel, 0, sizeof(sel)); | ||
256 | memcpy(&sel.daddr, (xfrm_address_t *)&skb->nh.ipv6h->daddr, | ||
257 | sizeof(sel.daddr)); | ||
258 | sel.prefixlen_d = 128; | ||
259 | memcpy(&sel.saddr, (xfrm_address_t *)&skb->nh.ipv6h->saddr, | ||
260 | sizeof(sel.saddr)); | ||
261 | sel.prefixlen_s = 128; | ||
262 | sel.family = AF_INET6; | ||
263 | sel.proto = fl->proto; | ||
264 | sel.dport = xfrm_flowi_dport(fl); | ||
265 | if (sel.dport) | ||
266 | sel.dport_mask = ~((__u16)0); | ||
267 | sel.sport = xfrm_flowi_sport(fl); | ||
268 | if (sel.sport) | ||
269 | sel.sport_mask = ~((__u16)0); | ||
270 | sel.ifindex = fl->oif; | ||
271 | |||
272 | err = km_report(IPPROTO_DSTOPTS, &sel, | ||
273 | (hao ? (xfrm_address_t *)&hao->addr : NULL)); | ||
274 | |||
275 | out: | ||
276 | return err; | ||
277 | } | ||
278 | |||
279 | static int mip6_destopt_offset(struct xfrm_state *x, struct sk_buff *skb, | ||
280 | u8 **nexthdr) | ||
281 | { | ||
282 | u16 offset = sizeof(struct ipv6hdr); | ||
283 | struct ipv6_opt_hdr *exthdr = (struct ipv6_opt_hdr*)(skb->nh.ipv6h + 1); | ||
284 | unsigned int packet_len = skb->tail - skb->nh.raw; | ||
285 | int found_rhdr = 0; | ||
286 | |||
287 | *nexthdr = &skb->nh.ipv6h->nexthdr; | ||
288 | |||
289 | while (offset + 1 <= packet_len) { | ||
290 | |||
291 | switch (**nexthdr) { | ||
292 | case NEXTHDR_HOP: | ||
293 | break; | ||
294 | case NEXTHDR_ROUTING: | ||
295 | found_rhdr = 1; | ||
296 | break; | ||
297 | case NEXTHDR_DEST: | ||
298 | /* | ||
299 | * HAO MUST NOT appear more than once. | ||
300 | * XXX: It is better to try to find by the end of | ||
301 | * XXX: packet if HAO exists. | ||
302 | */ | ||
303 | if (ipv6_find_tlv(skb, offset, IPV6_TLV_HAO) >= 0) { | ||
304 | LIMIT_NETDEBUG(KERN_WARNING "mip6: hao exists already, override\n"); | ||
305 | return offset; | ||
306 | } | ||
307 | |||
308 | if (found_rhdr) | ||
309 | return offset; | ||
310 | |||
311 | break; | ||
312 | default: | ||
313 | return offset; | ||
314 | } | ||
315 | |||
316 | offset += ipv6_optlen(exthdr); | ||
317 | *nexthdr = &exthdr->nexthdr; | ||
318 | exthdr = (struct ipv6_opt_hdr*)(skb->nh.raw + offset); | ||
319 | } | ||
320 | |||
321 | return offset; | ||
322 | } | ||
323 | |||
324 | static int mip6_destopt_init_state(struct xfrm_state *x) | ||
325 | { | ||
326 | if (x->id.spi) { | ||
327 | printk(KERN_INFO "%s: spi is not 0: %u\n", __FUNCTION__, | ||
328 | x->id.spi); | ||
329 | return -EINVAL; | ||
330 | } | ||
331 | if (x->props.mode != XFRM_MODE_ROUTEOPTIMIZATION) { | ||
332 | printk(KERN_INFO "%s: state's mode is not %u: %u\n", | ||
333 | __FUNCTION__, XFRM_MODE_ROUTEOPTIMIZATION, x->props.mode); | ||
334 | return -EINVAL; | ||
335 | } | ||
336 | |||
337 | x->props.header_len = sizeof(struct ipv6_destopt_hdr) + | ||
338 | calc_padlen(sizeof(struct ipv6_destopt_hdr), 6) + | ||
339 | sizeof(struct ipv6_destopt_hao); | ||
340 | BUG_TRAP(x->props.header_len == 24); | ||
341 | |||
342 | return 0; | ||
343 | } | ||
344 | |||
345 | /* | ||
346 | * Do nothing about destroying since it has no specific operation for | ||
347 | * destination options header unlike IPsec protocols. | ||
348 | */ | ||
349 | static void mip6_destopt_destroy(struct xfrm_state *x) | ||
350 | { | ||
351 | } | ||
352 | |||
353 | static struct xfrm_type mip6_destopt_type = | ||
354 | { | ||
355 | .description = "MIP6DESTOPT", | ||
356 | .owner = THIS_MODULE, | ||
357 | .proto = IPPROTO_DSTOPTS, | ||
358 | .flags = XFRM_TYPE_NON_FRAGMENT, | ||
359 | .init_state = mip6_destopt_init_state, | ||
360 | .destructor = mip6_destopt_destroy, | ||
361 | .input = mip6_destopt_input, | ||
362 | .output = mip6_destopt_output, | ||
363 | .reject = mip6_destopt_reject, | ||
364 | .hdr_offset = mip6_destopt_offset, | ||
365 | .local_addr = mip6_xfrm_addr, | ||
366 | }; | ||
367 | |||
368 | static int mip6_rthdr_input(struct xfrm_state *x, struct sk_buff *skb) | ||
369 | { | ||
370 | struct rt2_hdr *rt2 = (struct rt2_hdr *)skb->data; | ||
371 | |||
372 | if (!ipv6_addr_equal(&rt2->addr, (struct in6_addr *)x->coaddr) && | ||
373 | !ipv6_addr_any((struct in6_addr *)x->coaddr)) | ||
374 | return -ENOENT; | ||
375 | |||
376 | return rt2->rt_hdr.nexthdr; | ||
377 | } | ||
378 | |||
379 | /* Routing Header type 2 is inserted. | ||
380 | * IP Header's dst address is replaced with Routing Header's Home Address. | ||
381 | */ | ||
382 | static int mip6_rthdr_output(struct xfrm_state *x, struct sk_buff *skb) | ||
383 | { | ||
384 | struct ipv6hdr *iph; | ||
385 | struct rt2_hdr *rt2; | ||
386 | u8 nexthdr; | ||
387 | |||
388 | iph = (struct ipv6hdr *)skb->data; | ||
389 | iph->payload_len = htons(skb->len - sizeof(*iph)); | ||
390 | |||
391 | nexthdr = *skb->nh.raw; | ||
392 | *skb->nh.raw = IPPROTO_ROUTING; | ||
393 | |||
394 | rt2 = (struct rt2_hdr *)skb->h.raw; | ||
395 | rt2->rt_hdr.nexthdr = nexthdr; | ||
396 | rt2->rt_hdr.hdrlen = (x->props.header_len >> 3) - 1; | ||
397 | rt2->rt_hdr.type = IPV6_SRCRT_TYPE_2; | ||
398 | rt2->rt_hdr.segments_left = 1; | ||
399 | memset(&rt2->reserved, 0, sizeof(rt2->reserved)); | ||
400 | |||
401 | BUG_TRAP(rt2->rt_hdr.hdrlen == 2); | ||
402 | |||
403 | memcpy(&rt2->addr, &iph->daddr, sizeof(rt2->addr)); | ||
404 | memcpy(&iph->daddr, x->coaddr, sizeof(iph->daddr)); | ||
405 | |||
406 | return 0; | ||
407 | } | ||
408 | |||
409 | static int mip6_rthdr_offset(struct xfrm_state *x, struct sk_buff *skb, | ||
410 | u8 **nexthdr) | ||
411 | { | ||
412 | u16 offset = sizeof(struct ipv6hdr); | ||
413 | struct ipv6_opt_hdr *exthdr = (struct ipv6_opt_hdr*)(skb->nh.ipv6h + 1); | ||
414 | unsigned int packet_len = skb->tail - skb->nh.raw; | ||
415 | int found_rhdr = 0; | ||
416 | |||
417 | *nexthdr = &skb->nh.ipv6h->nexthdr; | ||
418 | |||
419 | while (offset + 1 <= packet_len) { | ||
420 | |||
421 | switch (**nexthdr) { | ||
422 | case NEXTHDR_HOP: | ||
423 | break; | ||
424 | case NEXTHDR_ROUTING: | ||
425 | if (offset + 3 <= packet_len) { | ||
426 | struct ipv6_rt_hdr *rt; | ||
427 | rt = (struct ipv6_rt_hdr *)(skb->nh.raw + offset); | ||
428 | if (rt->type != 0) | ||
429 | return offset; | ||
430 | } | ||
431 | found_rhdr = 1; | ||
432 | break; | ||
433 | case NEXTHDR_DEST: | ||
434 | if (ipv6_find_tlv(skb, offset, IPV6_TLV_HAO) >= 0) | ||
435 | return offset; | ||
436 | |||
437 | if (found_rhdr) | ||
438 | return offset; | ||
439 | |||
440 | break; | ||
441 | default: | ||
442 | return offset; | ||
443 | } | ||
444 | |||
445 | offset += ipv6_optlen(exthdr); | ||
446 | *nexthdr = &exthdr->nexthdr; | ||
447 | exthdr = (struct ipv6_opt_hdr*)(skb->nh.raw + offset); | ||
448 | } | ||
449 | |||
450 | return offset; | ||
451 | } | ||
452 | |||
453 | static int mip6_rthdr_init_state(struct xfrm_state *x) | ||
454 | { | ||
455 | if (x->id.spi) { | ||
456 | printk(KERN_INFO "%s: spi is not 0: %u\n", __FUNCTION__, | ||
457 | x->id.spi); | ||
458 | return -EINVAL; | ||
459 | } | ||
460 | if (x->props.mode != XFRM_MODE_ROUTEOPTIMIZATION) { | ||
461 | printk(KERN_INFO "%s: state's mode is not %u: %u\n", | ||
462 | __FUNCTION__, XFRM_MODE_ROUTEOPTIMIZATION, x->props.mode); | ||
463 | return -EINVAL; | ||
464 | } | ||
465 | |||
466 | x->props.header_len = sizeof(struct rt2_hdr); | ||
467 | |||
468 | return 0; | ||
469 | } | ||
470 | |||
471 | /* | ||
472 | * Do nothing about destroying since it has no specific operation for routing | ||
473 | * header type 2 unlike IPsec protocols. | ||
474 | */ | ||
475 | static void mip6_rthdr_destroy(struct xfrm_state *x) | ||
476 | { | ||
477 | } | ||
478 | |||
479 | static struct xfrm_type mip6_rthdr_type = | ||
480 | { | ||
481 | .description = "MIP6RT", | ||
482 | .owner = THIS_MODULE, | ||
483 | .proto = IPPROTO_ROUTING, | ||
484 | .flags = XFRM_TYPE_NON_FRAGMENT, | ||
485 | .init_state = mip6_rthdr_init_state, | ||
486 | .destructor = mip6_rthdr_destroy, | ||
487 | .input = mip6_rthdr_input, | ||
488 | .output = mip6_rthdr_output, | ||
489 | .hdr_offset = mip6_rthdr_offset, | ||
490 | .remote_addr = mip6_xfrm_addr, | ||
491 | }; | ||
492 | |||
493 | int __init mip6_init(void) | ||
494 | { | ||
495 | printk(KERN_INFO "Mobile IPv6\n"); | ||
496 | |||
497 | if (xfrm_register_type(&mip6_destopt_type, AF_INET6) < 0) { | ||
498 | printk(KERN_INFO "%s: can't add xfrm type(destopt)\n", __FUNCTION__); | ||
499 | goto mip6_destopt_xfrm_fail; | ||
500 | } | ||
501 | if (xfrm_register_type(&mip6_rthdr_type, AF_INET6) < 0) { | ||
502 | printk(KERN_INFO "%s: can't add xfrm type(rthdr)\n", __FUNCTION__); | ||
503 | goto mip6_rthdr_xfrm_fail; | ||
504 | } | ||
505 | return 0; | ||
506 | |||
507 | mip6_rthdr_xfrm_fail: | ||
508 | xfrm_unregister_type(&mip6_destopt_type, AF_INET6); | ||
509 | mip6_destopt_xfrm_fail: | ||
510 | return -EAGAIN; | ||
511 | } | ||
512 | |||
513 | void __exit mip6_fini(void) | ||
514 | { | ||
515 | if (xfrm_unregister_type(&mip6_rthdr_type, AF_INET6) < 0) | ||
516 | printk(KERN_INFO "%s: can't remove xfrm type(rthdr)\n", __FUNCTION__); | ||
517 | if (xfrm_unregister_type(&mip6_destopt_type, AF_INET6) < 0) | ||
518 | printk(KERN_INFO "%s: can't remove xfrm type(destopt)\n", __FUNCTION__); | ||
519 | } | ||
diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c index b50055b9278d..0304b5fe8d6a 100644 --- a/net/ipv6/ndisc.c +++ b/net/ipv6/ndisc.c | |||
@@ -62,6 +62,7 @@ | |||
62 | #include <linux/sysctl.h> | 62 | #include <linux/sysctl.h> |
63 | #endif | 63 | #endif |
64 | 64 | ||
65 | #include <linux/if_addr.h> | ||
65 | #include <linux/if_arp.h> | 66 | #include <linux/if_arp.h> |
66 | #include <linux/ipv6.h> | 67 | #include <linux/ipv6.h> |
67 | #include <linux/icmpv6.h> | 68 | #include <linux/icmpv6.h> |
@@ -411,7 +412,8 @@ static void pndisc_destructor(struct pneigh_entry *n) | |||
411 | */ | 412 | */ |
412 | 413 | ||
413 | static inline void ndisc_flow_init(struct flowi *fl, u8 type, | 414 | static inline void ndisc_flow_init(struct flowi *fl, u8 type, |
414 | struct in6_addr *saddr, struct in6_addr *daddr) | 415 | struct in6_addr *saddr, struct in6_addr *daddr, |
416 | int oif) | ||
415 | { | 417 | { |
416 | memset(fl, 0, sizeof(*fl)); | 418 | memset(fl, 0, sizeof(*fl)); |
417 | ipv6_addr_copy(&fl->fl6_src, saddr); | 419 | ipv6_addr_copy(&fl->fl6_src, saddr); |
@@ -419,6 +421,8 @@ static inline void ndisc_flow_init(struct flowi *fl, u8 type, | |||
419 | fl->proto = IPPROTO_ICMPV6; | 421 | fl->proto = IPPROTO_ICMPV6; |
420 | fl->fl_icmp_type = type; | 422 | fl->fl_icmp_type = type; |
421 | fl->fl_icmp_code = 0; | 423 | fl->fl_icmp_code = 0; |
424 | fl->oif = oif; | ||
425 | security_sk_classify_flow(ndisc_socket->sk, fl); | ||
422 | } | 426 | } |
423 | 427 | ||
424 | static void ndisc_send_na(struct net_device *dev, struct neighbour *neigh, | 428 | static void ndisc_send_na(struct net_device *dev, struct neighbour *neigh, |
@@ -450,7 +454,8 @@ static void ndisc_send_na(struct net_device *dev, struct neighbour *neigh, | |||
450 | src_addr = &tmpaddr; | 454 | src_addr = &tmpaddr; |
451 | } | 455 | } |
452 | 456 | ||
453 | ndisc_flow_init(&fl, NDISC_NEIGHBOUR_ADVERTISEMENT, src_addr, daddr); | 457 | ndisc_flow_init(&fl, NDISC_NEIGHBOUR_ADVERTISEMENT, src_addr, daddr, |
458 | dev->ifindex); | ||
454 | 459 | ||
455 | dst = ndisc_dst_alloc(dev, neigh, daddr, ip6_output); | 460 | dst = ndisc_dst_alloc(dev, neigh, daddr, ip6_output); |
456 | if (!dst) | 461 | if (!dst) |
@@ -491,7 +496,7 @@ static void ndisc_send_na(struct net_device *dev, struct neighbour *neigh, | |||
491 | msg->icmph.icmp6_unused = 0; | 496 | msg->icmph.icmp6_unused = 0; |
492 | msg->icmph.icmp6_router = router; | 497 | msg->icmph.icmp6_router = router; |
493 | msg->icmph.icmp6_solicited = solicited; | 498 | msg->icmph.icmp6_solicited = solicited; |
494 | msg->icmph.icmp6_override = !!override; | 499 | msg->icmph.icmp6_override = override; |
495 | 500 | ||
496 | /* Set the target address. */ | 501 | /* Set the target address. */ |
497 | ipv6_addr_copy(&msg->target, solicited_addr); | 502 | ipv6_addr_copy(&msg->target, solicited_addr); |
@@ -540,7 +545,8 @@ void ndisc_send_ns(struct net_device *dev, struct neighbour *neigh, | |||
540 | saddr = &addr_buf; | 545 | saddr = &addr_buf; |
541 | } | 546 | } |
542 | 547 | ||
543 | ndisc_flow_init(&fl, NDISC_NEIGHBOUR_SOLICITATION, saddr, daddr); | 548 | ndisc_flow_init(&fl, NDISC_NEIGHBOUR_SOLICITATION, saddr, daddr, |
549 | dev->ifindex); | ||
544 | 550 | ||
545 | dst = ndisc_dst_alloc(dev, neigh, daddr, ip6_output); | 551 | dst = ndisc_dst_alloc(dev, neigh, daddr, ip6_output); |
546 | if (!dst) | 552 | if (!dst) |
@@ -615,7 +621,8 @@ void ndisc_send_rs(struct net_device *dev, struct in6_addr *saddr, | |||
615 | int len; | 621 | int len; |
616 | int err; | 622 | int err; |
617 | 623 | ||
618 | ndisc_flow_init(&fl, NDISC_ROUTER_SOLICITATION, saddr, daddr); | 624 | ndisc_flow_init(&fl, NDISC_ROUTER_SOLICITATION, saddr, daddr, |
625 | dev->ifindex); | ||
619 | 626 | ||
620 | dst = ndisc_dst_alloc(dev, NULL, daddr, ip6_output); | 627 | dst = ndisc_dst_alloc(dev, NULL, daddr, ip6_output); |
621 | if (!dst) | 628 | if (!dst) |
@@ -729,8 +736,10 @@ static void ndisc_recv_ns(struct sk_buff *skb) | |||
729 | struct inet6_ifaddr *ifp; | 736 | struct inet6_ifaddr *ifp; |
730 | struct inet6_dev *idev = NULL; | 737 | struct inet6_dev *idev = NULL; |
731 | struct neighbour *neigh; | 738 | struct neighbour *neigh; |
739 | struct pneigh_entry *pneigh = NULL; | ||
732 | int dad = ipv6_addr_any(saddr); | 740 | int dad = ipv6_addr_any(saddr); |
733 | int inc; | 741 | int inc; |
742 | int is_router; | ||
734 | 743 | ||
735 | if (ipv6_addr_is_multicast(&msg->target)) { | 744 | if (ipv6_addr_is_multicast(&msg->target)) { |
736 | ND_PRINTK2(KERN_WARNING | 745 | ND_PRINTK2(KERN_WARNING |
@@ -815,7 +824,9 @@ static void ndisc_recv_ns(struct sk_buff *skb) | |||
815 | 824 | ||
816 | if (ipv6_chk_acast_addr(dev, &msg->target) || | 825 | if (ipv6_chk_acast_addr(dev, &msg->target) || |
817 | (idev->cnf.forwarding && | 826 | (idev->cnf.forwarding && |
818 | pneigh_lookup(&nd_tbl, &msg->target, dev, 0))) { | 827 | (ipv6_devconf.proxy_ndp || idev->cnf.proxy_ndp) && |
828 | (pneigh = pneigh_lookup(&nd_tbl, | ||
829 | &msg->target, dev, 0)) != NULL)) { | ||
819 | if (!(NEIGH_CB(skb)->flags & LOCALLY_ENQUEUED) && | 830 | if (!(NEIGH_CB(skb)->flags & LOCALLY_ENQUEUED) && |
820 | skb->pkt_type != PACKET_HOST && | 831 | skb->pkt_type != PACKET_HOST && |
821 | inc != 0 && | 832 | inc != 0 && |
@@ -836,12 +847,14 @@ static void ndisc_recv_ns(struct sk_buff *skb) | |||
836 | goto out; | 847 | goto out; |
837 | } | 848 | } |
838 | 849 | ||
850 | is_router = !!(pneigh ? pneigh->flags & NTF_ROUTER : idev->cnf.forwarding); | ||
851 | |||
839 | if (dad) { | 852 | if (dad) { |
840 | struct in6_addr maddr; | 853 | struct in6_addr maddr; |
841 | 854 | ||
842 | ipv6_addr_all_nodes(&maddr); | 855 | ipv6_addr_all_nodes(&maddr); |
843 | ndisc_send_na(dev, NULL, &maddr, &msg->target, | 856 | ndisc_send_na(dev, NULL, &maddr, &msg->target, |
844 | idev->cnf.forwarding, 0, (ifp != NULL), 1); | 857 | is_router, 0, (ifp != NULL), 1); |
845 | goto out; | 858 | goto out; |
846 | } | 859 | } |
847 | 860 | ||
@@ -862,7 +875,7 @@ static void ndisc_recv_ns(struct sk_buff *skb) | |||
862 | NEIGH_UPDATE_F_OVERRIDE); | 875 | NEIGH_UPDATE_F_OVERRIDE); |
863 | if (neigh || !dev->hard_header) { | 876 | if (neigh || !dev->hard_header) { |
864 | ndisc_send_na(dev, neigh, saddr, &msg->target, | 877 | ndisc_send_na(dev, neigh, saddr, &msg->target, |
865 | idev->cnf.forwarding, | 878 | is_router, |
866 | 1, (ifp != NULL && inc), inc); | 879 | 1, (ifp != NULL && inc), inc); |
867 | if (neigh) | 880 | if (neigh) |
868 | neigh_release(neigh); | 881 | neigh_release(neigh); |
@@ -945,6 +958,20 @@ static void ndisc_recv_na(struct sk_buff *skb) | |||
945 | if (neigh->nud_state & NUD_FAILED) | 958 | if (neigh->nud_state & NUD_FAILED) |
946 | goto out; | 959 | goto out; |
947 | 960 | ||
961 | /* | ||
962 | * Don't update the neighbor cache entry on a proxy NA from | ||
963 | * ourselves because either the proxied node is off link or it | ||
964 | * has already sent a NA to us. | ||
965 | */ | ||
966 | if (lladdr && !memcmp(lladdr, dev->dev_addr, dev->addr_len) && | ||
967 | ipv6_devconf.forwarding && ipv6_devconf.proxy_ndp && | ||
968 | pneigh_lookup(&nd_tbl, &msg->target, dev, 0)) { | ||
969 | /* XXX: idev->cnf.prixy_ndp */ | ||
970 | WARN_ON(skb->dst != NULL && | ||
971 | ((struct rt6_info *)skb->dst)->rt6i_idev); | ||
972 | goto out; | ||
973 | } | ||
974 | |||
948 | neigh_update(neigh, lladdr, | 975 | neigh_update(neigh, lladdr, |
949 | msg->icmph.icmp6_solicited ? NUD_REACHABLE : NUD_STALE, | 976 | msg->icmph.icmp6_solicited ? NUD_REACHABLE : NUD_STALE, |
950 | NEIGH_UPDATE_F_WEAK_OVERRIDE| | 977 | NEIGH_UPDATE_F_WEAK_OVERRIDE| |
@@ -959,7 +986,7 @@ static void ndisc_recv_na(struct sk_buff *skb) | |||
959 | struct rt6_info *rt; | 986 | struct rt6_info *rt; |
960 | rt = rt6_get_dflt_router(saddr, dev); | 987 | rt = rt6_get_dflt_router(saddr, dev); |
961 | if (rt) | 988 | if (rt) |
962 | ip6_del_rt(rt, NULL, NULL, NULL); | 989 | ip6_del_rt(rt); |
963 | } | 990 | } |
964 | 991 | ||
965 | out: | 992 | out: |
@@ -1112,7 +1139,7 @@ static void ndisc_router_discovery(struct sk_buff *skb) | |||
1112 | 1139 | ||
1113 | if (rt && lifetime == 0) { | 1140 | if (rt && lifetime == 0) { |
1114 | neigh_clone(neigh); | 1141 | neigh_clone(neigh); |
1115 | ip6_del_rt(rt, NULL, NULL, NULL); | 1142 | ip6_del_rt(rt); |
1116 | rt = NULL; | 1143 | rt = NULL; |
1117 | } | 1144 | } |
1118 | 1145 | ||
@@ -1344,7 +1371,8 @@ static void ndisc_redirect_rcv(struct sk_buff *skb) | |||
1344 | 1371 | ||
1345 | neigh = __neigh_lookup(&nd_tbl, target, skb->dev, 1); | 1372 | neigh = __neigh_lookup(&nd_tbl, target, skb->dev, 1); |
1346 | if (neigh) { | 1373 | if (neigh) { |
1347 | rt6_redirect(dest, &skb->nh.ipv6h->saddr, neigh, lladdr, | 1374 | rt6_redirect(dest, &skb->nh.ipv6h->daddr, |
1375 | &skb->nh.ipv6h->saddr, neigh, lladdr, | ||
1348 | on_link); | 1376 | on_link); |
1349 | neigh_release(neigh); | 1377 | neigh_release(neigh); |
1350 | } | 1378 | } |
@@ -1380,7 +1408,8 @@ void ndisc_send_redirect(struct sk_buff *skb, struct neighbour *neigh, | |||
1380 | return; | 1408 | return; |
1381 | } | 1409 | } |
1382 | 1410 | ||
1383 | ndisc_flow_init(&fl, NDISC_REDIRECT, &saddr_buf, &skb->nh.ipv6h->saddr); | 1411 | ndisc_flow_init(&fl, NDISC_REDIRECT, &saddr_buf, &skb->nh.ipv6h->saddr, |
1412 | dev->ifindex); | ||
1384 | 1413 | ||
1385 | dst = ip6_route_output(NULL, &fl); | 1414 | dst = ip6_route_output(NULL, &fl); |
1386 | if (dst == NULL) | 1415 | if (dst == NULL) |
diff --git a/net/ipv6/netfilter.c b/net/ipv6/netfilter.c index 395a417ba955..580b1aba6722 100644 --- a/net/ipv6/netfilter.c +++ b/net/ipv6/netfilter.c | |||
@@ -87,7 +87,7 @@ unsigned int nf_ip6_checksum(struct sk_buff *skb, unsigned int hook, | |||
87 | unsigned int csum = 0; | 87 | unsigned int csum = 0; |
88 | 88 | ||
89 | switch (skb->ip_summed) { | 89 | switch (skb->ip_summed) { |
90 | case CHECKSUM_HW: | 90 | case CHECKSUM_COMPLETE: |
91 | if (hook != NF_IP6_PRE_ROUTING && hook != NF_IP6_LOCAL_IN) | 91 | if (hook != NF_IP6_PRE_ROUTING && hook != NF_IP6_LOCAL_IN) |
92 | break; | 92 | break; |
93 | if (!csum_ipv6_magic(&ip6h->saddr, &ip6h->daddr, | 93 | if (!csum_ipv6_magic(&ip6h->saddr, &ip6h->daddr, |
diff --git a/net/ipv6/netfilter/Makefile b/net/ipv6/netfilter/Makefile index eeeb57d4c9c5..ac1dfebde175 100644 --- a/net/ipv6/netfilter/Makefile +++ b/net/ipv6/netfilter/Makefile | |||
@@ -5,7 +5,7 @@ | |||
5 | # Link order matters here. | 5 | # Link order matters here. |
6 | obj-$(CONFIG_IP6_NF_IPTABLES) += ip6_tables.o | 6 | obj-$(CONFIG_IP6_NF_IPTABLES) += ip6_tables.o |
7 | obj-$(CONFIG_IP6_NF_MATCH_RT) += ip6t_rt.o | 7 | obj-$(CONFIG_IP6_NF_MATCH_RT) += ip6t_rt.o |
8 | obj-$(CONFIG_IP6_NF_MATCH_OPTS) += ip6t_hbh.o ip6t_dst.o | 8 | obj-$(CONFIG_IP6_NF_MATCH_OPTS) += ip6t_hbh.o |
9 | obj-$(CONFIG_IP6_NF_MATCH_IPV6HEADER) += ip6t_ipv6header.o | 9 | obj-$(CONFIG_IP6_NF_MATCH_IPV6HEADER) += ip6t_ipv6header.o |
10 | obj-$(CONFIG_IP6_NF_MATCH_FRAG) += ip6t_frag.o | 10 | obj-$(CONFIG_IP6_NF_MATCH_FRAG) += ip6t_frag.o |
11 | obj-$(CONFIG_IP6_NF_MATCH_AH) += ip6t_ah.o | 11 | obj-$(CONFIG_IP6_NF_MATCH_AH) += ip6t_ah.o |
diff --git a/net/ipv6/netfilter/ip6_queue.c b/net/ipv6/netfilter/ip6_queue.c index 968a14be0d05..9510c24ca8d2 100644 --- a/net/ipv6/netfilter/ip6_queue.c +++ b/net/ipv6/netfilter/ip6_queue.c | |||
@@ -56,15 +56,15 @@ struct ipq_queue_entry { | |||
56 | 56 | ||
57 | typedef int (*ipq_cmpfn)(struct ipq_queue_entry *, unsigned long); | 57 | typedef int (*ipq_cmpfn)(struct ipq_queue_entry *, unsigned long); |
58 | 58 | ||
59 | static unsigned char copy_mode = IPQ_COPY_NONE; | 59 | static unsigned char copy_mode __read_mostly = IPQ_COPY_NONE; |
60 | static unsigned int queue_maxlen = IPQ_QMAX_DEFAULT; | 60 | static unsigned int queue_maxlen __read_mostly = IPQ_QMAX_DEFAULT; |
61 | static DEFINE_RWLOCK(queue_lock); | 61 | static DEFINE_RWLOCK(queue_lock); |
62 | static int peer_pid; | 62 | static int peer_pid __read_mostly; |
63 | static unsigned int copy_range; | 63 | static unsigned int copy_range __read_mostly; |
64 | static unsigned int queue_total; | 64 | static unsigned int queue_total; |
65 | static unsigned int queue_dropped = 0; | 65 | static unsigned int queue_dropped = 0; |
66 | static unsigned int queue_user_dropped = 0; | 66 | static unsigned int queue_user_dropped = 0; |
67 | static struct sock *ipqnl; | 67 | static struct sock *ipqnl __read_mostly; |
68 | static LIST_HEAD(queue_list); | 68 | static LIST_HEAD(queue_list); |
69 | static DEFINE_MUTEX(ipqnl_mutex); | 69 | static DEFINE_MUTEX(ipqnl_mutex); |
70 | 70 | ||
@@ -206,9 +206,9 @@ ipq_build_packet_message(struct ipq_queue_entry *entry, int *errp) | |||
206 | break; | 206 | break; |
207 | 207 | ||
208 | case IPQ_COPY_PACKET: | 208 | case IPQ_COPY_PACKET: |
209 | if (entry->skb->ip_summed == CHECKSUM_HW && | 209 | if ((entry->skb->ip_summed == CHECKSUM_PARTIAL || |
210 | (*errp = skb_checksum_help(entry->skb, | 210 | entry->skb->ip_summed == CHECKSUM_COMPLETE) && |
211 | entry->info->outdev == NULL))) { | 211 | (*errp = skb_checksum_help(entry->skb))) { |
212 | read_unlock_bh(&queue_lock); | 212 | read_unlock_bh(&queue_lock); |
213 | return NULL; | 213 | return NULL; |
214 | } | 214 | } |
diff --git a/net/ipv6/netfilter/ip6_tables.c b/net/ipv6/netfilter/ip6_tables.c index c9d6b23cd3f7..4ab368fa0b8f 100644 --- a/net/ipv6/netfilter/ip6_tables.c +++ b/net/ipv6/netfilter/ip6_tables.c | |||
@@ -70,9 +70,6 @@ do { \ | |||
70 | #define IP_NF_ASSERT(x) | 70 | #define IP_NF_ASSERT(x) |
71 | #endif | 71 | #endif |
72 | 72 | ||
73 | |||
74 | #include <linux/netfilter_ipv4/listhelp.h> | ||
75 | |||
76 | #if 0 | 73 | #if 0 |
77 | /* All the better to debug you with... */ | 74 | /* All the better to debug you with... */ |
78 | #define static | 75 | #define static |
@@ -220,8 +217,7 @@ ip6t_error(struct sk_buff **pskb, | |||
220 | const struct net_device *out, | 217 | const struct net_device *out, |
221 | unsigned int hooknum, | 218 | unsigned int hooknum, |
222 | const struct xt_target *target, | 219 | const struct xt_target *target, |
223 | const void *targinfo, | 220 | const void *targinfo) |
224 | void *userinfo) | ||
225 | { | 221 | { |
226 | if (net_ratelimit()) | 222 | if (net_ratelimit()) |
227 | printk("ip6_tables: error: `%s'\n", (char *)targinfo); | 223 | printk("ip6_tables: error: `%s'\n", (char *)targinfo); |
@@ -258,8 +254,7 @@ ip6t_do_table(struct sk_buff **pskb, | |||
258 | unsigned int hook, | 254 | unsigned int hook, |
259 | const struct net_device *in, | 255 | const struct net_device *in, |
260 | const struct net_device *out, | 256 | const struct net_device *out, |
261 | struct xt_table *table, | 257 | struct xt_table *table) |
262 | void *userdata) | ||
263 | { | 258 | { |
264 | static const char nulldevname[IFNAMSIZ] __attribute__((aligned(sizeof(long)))); | 259 | static const char nulldevname[IFNAMSIZ] __attribute__((aligned(sizeof(long)))); |
265 | int offset = 0; | 260 | int offset = 0; |
@@ -349,8 +344,7 @@ ip6t_do_table(struct sk_buff **pskb, | |||
349 | in, out, | 344 | in, out, |
350 | hook, | 345 | hook, |
351 | t->u.kernel.target, | 346 | t->u.kernel.target, |
352 | t->data, | 347 | t->data); |
353 | userdata); | ||
354 | 348 | ||
355 | #ifdef CONFIG_NETFILTER_DEBUG | 349 | #ifdef CONFIG_NETFILTER_DEBUG |
356 | if (((struct ip6t_entry *)table_base)->comefrom | 350 | if (((struct ip6t_entry *)table_base)->comefrom |
@@ -507,8 +501,7 @@ cleanup_match(struct ip6t_entry_match *m, unsigned int *i) | |||
507 | return 1; | 501 | return 1; |
508 | 502 | ||
509 | if (m->u.kernel.match->destroy) | 503 | if (m->u.kernel.match->destroy) |
510 | m->u.kernel.match->destroy(m->u.kernel.match, m->data, | 504 | m->u.kernel.match->destroy(m->u.kernel.match, m->data); |
511 | m->u.match_size - sizeof(*m)); | ||
512 | module_put(m->u.kernel.match->me); | 505 | module_put(m->u.kernel.match->me); |
513 | return 0; | 506 | return 0; |
514 | } | 507 | } |
@@ -561,7 +554,6 @@ check_match(struct ip6t_entry_match *m, | |||
561 | 554 | ||
562 | if (m->u.kernel.match->checkentry | 555 | if (m->u.kernel.match->checkentry |
563 | && !m->u.kernel.match->checkentry(name, ipv6, match, m->data, | 556 | && !m->u.kernel.match->checkentry(name, ipv6, match, m->data, |
564 | m->u.match_size - sizeof(*m), | ||
565 | hookmask)) { | 557 | hookmask)) { |
566 | duprintf("ip_tables: check failed for `%s'.\n", | 558 | duprintf("ip_tables: check failed for `%s'.\n", |
567 | m->u.kernel.match->name); | 559 | m->u.kernel.match->name); |
@@ -618,12 +610,10 @@ check_entry(struct ip6t_entry *e, const char *name, unsigned int size, | |||
618 | if (t->u.kernel.target == &ip6t_standard_target) { | 610 | if (t->u.kernel.target == &ip6t_standard_target) { |
619 | if (!standard_check(t, size)) { | 611 | if (!standard_check(t, size)) { |
620 | ret = -EINVAL; | 612 | ret = -EINVAL; |
621 | goto cleanup_matches; | 613 | goto err; |
622 | } | 614 | } |
623 | } else if (t->u.kernel.target->checkentry | 615 | } else if (t->u.kernel.target->checkentry |
624 | && !t->u.kernel.target->checkentry(name, e, target, t->data, | 616 | && !t->u.kernel.target->checkentry(name, e, target, t->data, |
625 | t->u.target_size | ||
626 | - sizeof(*t), | ||
627 | e->comefrom)) { | 617 | e->comefrom)) { |
628 | duprintf("ip_tables: check failed for `%s'.\n", | 618 | duprintf("ip_tables: check failed for `%s'.\n", |
629 | t->u.kernel.target->name); | 619 | t->u.kernel.target->name); |
@@ -695,8 +685,7 @@ cleanup_entry(struct ip6t_entry *e, unsigned int *i) | |||
695 | IP6T_MATCH_ITERATE(e, cleanup_match, NULL); | 685 | IP6T_MATCH_ITERATE(e, cleanup_match, NULL); |
696 | t = ip6t_get_target(e); | 686 | t = ip6t_get_target(e); |
697 | if (t->u.kernel.target->destroy) | 687 | if (t->u.kernel.target->destroy) |
698 | t->u.kernel.target->destroy(t->u.kernel.target, t->data, | 688 | t->u.kernel.target->destroy(t->u.kernel.target, t->data); |
699 | t->u.target_size - sizeof(*t)); | ||
700 | module_put(t->u.kernel.target->me); | 689 | module_put(t->u.kernel.target->me); |
701 | return 0; | 690 | return 0; |
702 | } | 691 | } |
@@ -1352,7 +1341,6 @@ icmp6_checkentry(const char *tablename, | |||
1352 | const void *entry, | 1341 | const void *entry, |
1353 | const struct xt_match *match, | 1342 | const struct xt_match *match, |
1354 | void *matchinfo, | 1343 | void *matchinfo, |
1355 | unsigned int matchsize, | ||
1356 | unsigned int hook_mask) | 1344 | unsigned int hook_mask) |
1357 | { | 1345 | { |
1358 | const struct ip6t_icmp *icmpinfo = matchinfo; | 1346 | const struct ip6t_icmp *icmpinfo = matchinfo; |
diff --git a/net/ipv6/netfilter/ip6t_HL.c b/net/ipv6/netfilter/ip6t_HL.c index b8eff8ee69b1..435750f664dd 100644 --- a/net/ipv6/netfilter/ip6t_HL.c +++ b/net/ipv6/netfilter/ip6t_HL.c | |||
@@ -22,11 +22,10 @@ static unsigned int ip6t_hl_target(struct sk_buff **pskb, | |||
22 | const struct net_device *out, | 22 | const struct net_device *out, |
23 | unsigned int hooknum, | 23 | unsigned int hooknum, |
24 | const struct xt_target *target, | 24 | const struct xt_target *target, |
25 | const void *targinfo, void *userinfo) | 25 | const void *targinfo) |
26 | { | 26 | { |
27 | struct ipv6hdr *ip6h; | 27 | struct ipv6hdr *ip6h; |
28 | const struct ip6t_HL_info *info = targinfo; | 28 | const struct ip6t_HL_info *info = targinfo; |
29 | u_int16_t diffs[2]; | ||
30 | int new_hl; | 29 | int new_hl; |
31 | 30 | ||
32 | if (!skb_make_writable(pskb, (*pskb)->len)) | 31 | if (!skb_make_writable(pskb, (*pskb)->len)) |
@@ -53,11 +52,8 @@ static unsigned int ip6t_hl_target(struct sk_buff **pskb, | |||
53 | break; | 52 | break; |
54 | } | 53 | } |
55 | 54 | ||
56 | if (new_hl != ip6h->hop_limit) { | 55 | if (new_hl != ip6h->hop_limit) |
57 | diffs[0] = htons(((unsigned)ip6h->hop_limit) << 8) ^ 0xFFFF; | ||
58 | ip6h->hop_limit = new_hl; | 56 | ip6h->hop_limit = new_hl; |
59 | diffs[1] = htons(((unsigned)ip6h->hop_limit) << 8); | ||
60 | } | ||
61 | 57 | ||
62 | return IP6T_CONTINUE; | 58 | return IP6T_CONTINUE; |
63 | } | 59 | } |
@@ -66,7 +62,6 @@ static int ip6t_hl_checkentry(const char *tablename, | |||
66 | const void *entry, | 62 | const void *entry, |
67 | const struct xt_target *target, | 63 | const struct xt_target *target, |
68 | void *targinfo, | 64 | void *targinfo, |
69 | unsigned int targinfosize, | ||
70 | unsigned int hook_mask) | 65 | unsigned int hook_mask) |
71 | { | 66 | { |
72 | struct ip6t_HL_info *info = targinfo; | 67 | struct ip6t_HL_info *info = targinfo; |
diff --git a/net/ipv6/netfilter/ip6t_LOG.c b/net/ipv6/netfilter/ip6t_LOG.c index 73c6300109d6..0cf537d30185 100644 --- a/net/ipv6/netfilter/ip6t_LOG.c +++ b/net/ipv6/netfilter/ip6t_LOG.c | |||
@@ -427,8 +427,7 @@ ip6t_log_target(struct sk_buff **pskb, | |||
427 | const struct net_device *out, | 427 | const struct net_device *out, |
428 | unsigned int hooknum, | 428 | unsigned int hooknum, |
429 | const struct xt_target *target, | 429 | const struct xt_target *target, |
430 | const void *targinfo, | 430 | const void *targinfo) |
431 | void *userinfo) | ||
432 | { | 431 | { |
433 | const struct ip6t_log_info *loginfo = targinfo; | 432 | const struct ip6t_log_info *loginfo = targinfo; |
434 | struct nf_loginfo li; | 433 | struct nf_loginfo li; |
@@ -452,7 +451,6 @@ static int ip6t_log_checkentry(const char *tablename, | |||
452 | const void *entry, | 451 | const void *entry, |
453 | const struct xt_target *target, | 452 | const struct xt_target *target, |
454 | void *targinfo, | 453 | void *targinfo, |
455 | unsigned int targinfosize, | ||
456 | unsigned int hook_mask) | 454 | unsigned int hook_mask) |
457 | { | 455 | { |
458 | const struct ip6t_log_info *loginfo = targinfo; | 456 | const struct ip6t_log_info *loginfo = targinfo; |
diff --git a/net/ipv6/netfilter/ip6t_REJECT.c b/net/ipv6/netfilter/ip6t_REJECT.c index 8629ba195d2d..311eae82feb3 100644 --- a/net/ipv6/netfilter/ip6t_REJECT.c +++ b/net/ipv6/netfilter/ip6t_REJECT.c | |||
@@ -96,6 +96,7 @@ static void send_reset(struct sk_buff *oldskb) | |||
96 | ipv6_addr_copy(&fl.fl6_dst, &oip6h->saddr); | 96 | ipv6_addr_copy(&fl.fl6_dst, &oip6h->saddr); |
97 | fl.fl_ip_sport = otcph.dest; | 97 | fl.fl_ip_sport = otcph.dest; |
98 | fl.fl_ip_dport = otcph.source; | 98 | fl.fl_ip_dport = otcph.source; |
99 | security_skb_classify_flow(oldskb, &fl); | ||
99 | dst = ip6_route_output(NULL, &fl); | 100 | dst = ip6_route_output(NULL, &fl); |
100 | if (dst == NULL) | 101 | if (dst == NULL) |
101 | return; | 102 | return; |
@@ -179,8 +180,7 @@ static unsigned int reject6_target(struct sk_buff **pskb, | |||
179 | const struct net_device *out, | 180 | const struct net_device *out, |
180 | unsigned int hooknum, | 181 | unsigned int hooknum, |
181 | const struct xt_target *target, | 182 | const struct xt_target *target, |
182 | const void *targinfo, | 183 | const void *targinfo) |
183 | void *userinfo) | ||
184 | { | 184 | { |
185 | const struct ip6t_reject_info *reject = targinfo; | 185 | const struct ip6t_reject_info *reject = targinfo; |
186 | 186 | ||
@@ -223,7 +223,6 @@ static int check(const char *tablename, | |||
223 | const void *entry, | 223 | const void *entry, |
224 | const struct xt_target *target, | 224 | const struct xt_target *target, |
225 | void *targinfo, | 225 | void *targinfo, |
226 | unsigned int targinfosize, | ||
227 | unsigned int hook_mask) | 226 | unsigned int hook_mask) |
228 | { | 227 | { |
229 | const struct ip6t_reject_info *rejinfo = targinfo; | 228 | const struct ip6t_reject_info *rejinfo = targinfo; |
@@ -256,9 +255,7 @@ static struct ip6t_target ip6t_reject_reg = { | |||
256 | 255 | ||
257 | static int __init ip6t_reject_init(void) | 256 | static int __init ip6t_reject_init(void) |
258 | { | 257 | { |
259 | if (ip6t_register_target(&ip6t_reject_reg)) | 258 | return ip6t_register_target(&ip6t_reject_reg); |
260 | return -EINVAL; | ||
261 | return 0; | ||
262 | } | 259 | } |
263 | 260 | ||
264 | static void __exit ip6t_reject_fini(void) | 261 | static void __exit ip6t_reject_fini(void) |
diff --git a/net/ipv6/netfilter/ip6t_ah.c b/net/ipv6/netfilter/ip6t_ah.c index 2f7bb20c758b..ec1b1608156c 100644 --- a/net/ipv6/netfilter/ip6t_ah.c +++ b/net/ipv6/netfilter/ip6t_ah.c | |||
@@ -102,7 +102,6 @@ checkentry(const char *tablename, | |||
102 | const void *entry, | 102 | const void *entry, |
103 | const struct xt_match *match, | 103 | const struct xt_match *match, |
104 | void *matchinfo, | 104 | void *matchinfo, |
105 | unsigned int matchinfosize, | ||
106 | unsigned int hook_mask) | 105 | unsigned int hook_mask) |
107 | { | 106 | { |
108 | const struct ip6t_ah *ahinfo = matchinfo; | 107 | const struct ip6t_ah *ahinfo = matchinfo; |
diff --git a/net/ipv6/netfilter/ip6t_dst.c b/net/ipv6/netfilter/ip6t_dst.c deleted file mode 100644 index 9422413d0571..000000000000 --- a/net/ipv6/netfilter/ip6t_dst.c +++ /dev/null | |||
@@ -1,220 +0,0 @@ | |||
1 | /* Kernel module to match Hop-by-Hop and Destination parameters. */ | ||
2 | |||
3 | /* (C) 2001-2002 Andras Kis-Szabo <kisza@sch.bme.hu> | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or modify | ||
6 | * it under the terms of the GNU General Public License version 2 as | ||
7 | * published by the Free Software Foundation. | ||
8 | */ | ||
9 | |||
10 | #include <linux/module.h> | ||
11 | #include <linux/skbuff.h> | ||
12 | #include <linux/ipv6.h> | ||
13 | #include <linux/types.h> | ||
14 | #include <net/checksum.h> | ||
15 | #include <net/ipv6.h> | ||
16 | |||
17 | #include <asm/byteorder.h> | ||
18 | |||
19 | #include <linux/netfilter_ipv6/ip6_tables.h> | ||
20 | #include <linux/netfilter_ipv6/ip6t_opts.h> | ||
21 | |||
22 | #define HOPBYHOP 0 | ||
23 | |||
24 | MODULE_LICENSE("GPL"); | ||
25 | #if HOPBYHOP | ||
26 | MODULE_DESCRIPTION("IPv6 HbH match"); | ||
27 | #else | ||
28 | MODULE_DESCRIPTION("IPv6 DST match"); | ||
29 | #endif | ||
30 | MODULE_AUTHOR("Andras Kis-Szabo <kisza@sch.bme.hu>"); | ||
31 | |||
32 | #if 0 | ||
33 | #define DEBUGP printk | ||
34 | #else | ||
35 | #define DEBUGP(format, args...) | ||
36 | #endif | ||
37 | |||
38 | /* | ||
39 | * (Type & 0xC0) >> 6 | ||
40 | * 0 -> ignorable | ||
41 | * 1 -> must drop the packet | ||
42 | * 2 -> send ICMP PARM PROB regardless and drop packet | ||
43 | * 3 -> Send ICMP if not a multicast address and drop packet | ||
44 | * (Type & 0x20) >> 5 | ||
45 | * 0 -> invariant | ||
46 | * 1 -> can change the routing | ||
47 | * (Type & 0x1F) Type | ||
48 | * 0 -> Pad1 (only 1 byte!) | ||
49 | * 1 -> PadN LENGTH info (total length = length + 2) | ||
50 | * C0 | 2 -> JUMBO 4 x x x x ( xxxx > 64k ) | ||
51 | * 5 -> RTALERT 2 x x | ||
52 | */ | ||
53 | |||
54 | static int | ||
55 | match(const struct sk_buff *skb, | ||
56 | const struct net_device *in, | ||
57 | const struct net_device *out, | ||
58 | const struct xt_match *match, | ||
59 | const void *matchinfo, | ||
60 | int offset, | ||
61 | unsigned int protoff, | ||
62 | int *hotdrop) | ||
63 | { | ||
64 | struct ipv6_opt_hdr _optsh, *oh; | ||
65 | const struct ip6t_opts *optinfo = matchinfo; | ||
66 | unsigned int temp; | ||
67 | unsigned int ptr; | ||
68 | unsigned int hdrlen = 0; | ||
69 | unsigned int ret = 0; | ||
70 | u8 _opttype, *tp = NULL; | ||
71 | u8 _optlen, *lp = NULL; | ||
72 | unsigned int optlen; | ||
73 | |||
74 | #if HOPBYHOP | ||
75 | if (ipv6_find_hdr(skb, &ptr, NEXTHDR_HOP, NULL) < 0) | ||
76 | #else | ||
77 | if (ipv6_find_hdr(skb, &ptr, NEXTHDR_DEST, NULL) < 0) | ||
78 | #endif | ||
79 | return 0; | ||
80 | |||
81 | oh = skb_header_pointer(skb, ptr, sizeof(_optsh), &_optsh); | ||
82 | if (oh == NULL) { | ||
83 | *hotdrop = 1; | ||
84 | return 0; | ||
85 | } | ||
86 | |||
87 | hdrlen = ipv6_optlen(oh); | ||
88 | if (skb->len - ptr < hdrlen) { | ||
89 | /* Packet smaller than it's length field */ | ||
90 | return 0; | ||
91 | } | ||
92 | |||
93 | DEBUGP("IPv6 OPTS LEN %u %u ", hdrlen, oh->hdrlen); | ||
94 | |||
95 | DEBUGP("len %02X %04X %02X ", | ||
96 | optinfo->hdrlen, hdrlen, | ||
97 | (!(optinfo->flags & IP6T_OPTS_LEN) || | ||
98 | ((optinfo->hdrlen == hdrlen) ^ | ||
99 | !!(optinfo->invflags & IP6T_OPTS_INV_LEN)))); | ||
100 | |||
101 | ret = (oh != NULL) && | ||
102 | (!(optinfo->flags & IP6T_OPTS_LEN) || | ||
103 | ((optinfo->hdrlen == hdrlen) ^ | ||
104 | !!(optinfo->invflags & IP6T_OPTS_INV_LEN))); | ||
105 | |||
106 | ptr += 2; | ||
107 | hdrlen -= 2; | ||
108 | if (!(optinfo->flags & IP6T_OPTS_OPTS)) { | ||
109 | return ret; | ||
110 | } else if (optinfo->flags & IP6T_OPTS_NSTRICT) { | ||
111 | DEBUGP("Not strict - not implemented"); | ||
112 | } else { | ||
113 | DEBUGP("Strict "); | ||
114 | DEBUGP("#%d ", optinfo->optsnr); | ||
115 | for (temp = 0; temp < optinfo->optsnr; temp++) { | ||
116 | /* type field exists ? */ | ||
117 | if (hdrlen < 1) | ||
118 | break; | ||
119 | tp = skb_header_pointer(skb, ptr, sizeof(_opttype), | ||
120 | &_opttype); | ||
121 | if (tp == NULL) | ||
122 | break; | ||
123 | |||
124 | /* Type check */ | ||
125 | if (*tp != (optinfo->opts[temp] & 0xFF00) >> 8) { | ||
126 | DEBUGP("Tbad %02X %02X\n", | ||
127 | *tp, | ||
128 | (optinfo->opts[temp] & 0xFF00) >> 8); | ||
129 | return 0; | ||
130 | } else { | ||
131 | DEBUGP("Tok "); | ||
132 | } | ||
133 | /* Length check */ | ||
134 | if (*tp) { | ||
135 | u16 spec_len; | ||
136 | |||
137 | /* length field exists ? */ | ||
138 | if (hdrlen < 2) | ||
139 | break; | ||
140 | lp = skb_header_pointer(skb, ptr + 1, | ||
141 | sizeof(_optlen), | ||
142 | &_optlen); | ||
143 | if (lp == NULL) | ||
144 | break; | ||
145 | spec_len = optinfo->opts[temp] & 0x00FF; | ||
146 | |||
147 | if (spec_len != 0x00FF && spec_len != *lp) { | ||
148 | DEBUGP("Lbad %02X %04X\n", *lp, | ||
149 | spec_len); | ||
150 | return 0; | ||
151 | } | ||
152 | DEBUGP("Lok "); | ||
153 | optlen = *lp + 2; | ||
154 | } else { | ||
155 | DEBUGP("Pad1\n"); | ||
156 | optlen = 1; | ||
157 | } | ||
158 | |||
159 | /* Step to the next */ | ||
160 | DEBUGP("len%04X \n", optlen); | ||
161 | |||
162 | if ((ptr > skb->len - optlen || hdrlen < optlen) && | ||
163 | (temp < optinfo->optsnr - 1)) { | ||
164 | DEBUGP("new pointer is too large! \n"); | ||
165 | break; | ||
166 | } | ||
167 | ptr += optlen; | ||
168 | hdrlen -= optlen; | ||
169 | } | ||
170 | if (temp == optinfo->optsnr) | ||
171 | return ret; | ||
172 | else | ||
173 | return 0; | ||
174 | } | ||
175 | |||
176 | return 0; | ||
177 | } | ||
178 | |||
179 | /* Called when user tries to insert an entry of this type. */ | ||
180 | static int | ||
181 | checkentry(const char *tablename, | ||
182 | const void *info, | ||
183 | const struct xt_match *match, | ||
184 | void *matchinfo, | ||
185 | unsigned int matchinfosize, | ||
186 | unsigned int hook_mask) | ||
187 | { | ||
188 | const struct ip6t_opts *optsinfo = matchinfo; | ||
189 | |||
190 | if (optsinfo->invflags & ~IP6T_OPTS_INV_MASK) { | ||
191 | DEBUGP("ip6t_opts: unknown flags %X\n", optsinfo->invflags); | ||
192 | return 0; | ||
193 | } | ||
194 | return 1; | ||
195 | } | ||
196 | |||
197 | static struct ip6t_match opts_match = { | ||
198 | #if HOPBYHOP | ||
199 | .name = "hbh", | ||
200 | #else | ||
201 | .name = "dst", | ||
202 | #endif | ||
203 | .match = match, | ||
204 | .matchsize = sizeof(struct ip6t_opts), | ||
205 | .checkentry = checkentry, | ||
206 | .me = THIS_MODULE, | ||
207 | }; | ||
208 | |||
209 | static int __init ip6t_dst_init(void) | ||
210 | { | ||
211 | return ip6t_register_match(&opts_match); | ||
212 | } | ||
213 | |||
214 | static void __exit ip6t_dst_fini(void) | ||
215 | { | ||
216 | ip6t_unregister_match(&opts_match); | ||
217 | } | ||
218 | |||
219 | module_init(ip6t_dst_init); | ||
220 | module_exit(ip6t_dst_fini); | ||
diff --git a/net/ipv6/netfilter/ip6t_frag.c b/net/ipv6/netfilter/ip6t_frag.c index 06768c84bd31..78d9c8b9e28a 100644 --- a/net/ipv6/netfilter/ip6t_frag.c +++ b/net/ipv6/netfilter/ip6t_frag.c | |||
@@ -119,7 +119,6 @@ checkentry(const char *tablename, | |||
119 | const void *ip, | 119 | const void *ip, |
120 | const struct xt_match *match, | 120 | const struct xt_match *match, |
121 | void *matchinfo, | 121 | void *matchinfo, |
122 | unsigned int matchinfosize, | ||
123 | unsigned int hook_mask) | 122 | unsigned int hook_mask) |
124 | { | 123 | { |
125 | const struct ip6t_frag *fraginfo = matchinfo; | 124 | const struct ip6t_frag *fraginfo = matchinfo; |
diff --git a/net/ipv6/netfilter/ip6t_hbh.c b/net/ipv6/netfilter/ip6t_hbh.c index 374f1be85c0d..d32a205e3af2 100644 --- a/net/ipv6/netfilter/ip6t_hbh.c +++ b/net/ipv6/netfilter/ip6t_hbh.c | |||
@@ -19,15 +19,10 @@ | |||
19 | #include <linux/netfilter_ipv6/ip6_tables.h> | 19 | #include <linux/netfilter_ipv6/ip6_tables.h> |
20 | #include <linux/netfilter_ipv6/ip6t_opts.h> | 20 | #include <linux/netfilter_ipv6/ip6t_opts.h> |
21 | 21 | ||
22 | #define HOPBYHOP 1 | ||
23 | |||
24 | MODULE_LICENSE("GPL"); | 22 | MODULE_LICENSE("GPL"); |
25 | #if HOPBYHOP | 23 | MODULE_DESCRIPTION("IPv6 opts match"); |
26 | MODULE_DESCRIPTION("IPv6 HbH match"); | ||
27 | #else | ||
28 | MODULE_DESCRIPTION("IPv6 DST match"); | ||
29 | #endif | ||
30 | MODULE_AUTHOR("Andras Kis-Szabo <kisza@sch.bme.hu>"); | 24 | MODULE_AUTHOR("Andras Kis-Szabo <kisza@sch.bme.hu>"); |
25 | MODULE_ALIAS("ip6t_dst"); | ||
31 | 26 | ||
32 | #if 0 | 27 | #if 0 |
33 | #define DEBUGP printk | 28 | #define DEBUGP printk |
@@ -71,11 +66,7 @@ match(const struct sk_buff *skb, | |||
71 | u8 _optlen, *lp = NULL; | 66 | u8 _optlen, *lp = NULL; |
72 | unsigned int optlen; | 67 | unsigned int optlen; |
73 | 68 | ||
74 | #if HOPBYHOP | 69 | if (ipv6_find_hdr(skb, &ptr, match->data, NULL) < 0) |
75 | if (ipv6_find_hdr(skb, &ptr, NEXTHDR_HOP, NULL) < 0) | ||
76 | #else | ||
77 | if (ipv6_find_hdr(skb, &ptr, NEXTHDR_DEST, NULL) < 0) | ||
78 | #endif | ||
79 | return 0; | 70 | return 0; |
80 | 71 | ||
81 | oh = skb_header_pointer(skb, ptr, sizeof(_optsh), &_optsh); | 72 | oh = skb_header_pointer(skb, ptr, sizeof(_optsh), &_optsh); |
@@ -182,7 +173,6 @@ checkentry(const char *tablename, | |||
182 | const void *entry, | 173 | const void *entry, |
183 | const struct xt_match *match, | 174 | const struct xt_match *match, |
184 | void *matchinfo, | 175 | void *matchinfo, |
185 | unsigned int matchinfosize, | ||
186 | unsigned int hook_mask) | 176 | unsigned int hook_mask) |
187 | { | 177 | { |
188 | const struct ip6t_opts *optsinfo = matchinfo; | 178 | const struct ip6t_opts *optsinfo = matchinfo; |
@@ -194,26 +184,35 @@ checkentry(const char *tablename, | |||
194 | return 1; | 184 | return 1; |
195 | } | 185 | } |
196 | 186 | ||
197 | static struct ip6t_match opts_match = { | 187 | static struct xt_match opts_match[] = { |
198 | #if HOPBYHOP | 188 | { |
199 | .name = "hbh", | 189 | .name = "hbh", |
200 | #else | 190 | .family = AF_INET6, |
201 | .name = "dst", | 191 | .match = match, |
202 | #endif | 192 | .matchsize = sizeof(struct ip6t_opts), |
203 | .match = match, | 193 | .checkentry = checkentry, |
204 | .matchsize = sizeof(struct ip6t_opts), | 194 | .me = THIS_MODULE, |
205 | .checkentry = checkentry, | 195 | .data = NEXTHDR_HOP, |
206 | .me = THIS_MODULE, | 196 | }, |
197 | { | ||
198 | .name = "dst", | ||
199 | .family = AF_INET6, | ||
200 | .match = match, | ||
201 | .matchsize = sizeof(struct ip6t_opts), | ||
202 | .checkentry = checkentry, | ||
203 | .me = THIS_MODULE, | ||
204 | .data = NEXTHDR_DEST, | ||
205 | }, | ||
207 | }; | 206 | }; |
208 | 207 | ||
209 | static int __init ip6t_hbh_init(void) | 208 | static int __init ip6t_hbh_init(void) |
210 | { | 209 | { |
211 | return ip6t_register_match(&opts_match); | 210 | return xt_register_matches(opts_match, ARRAY_SIZE(opts_match)); |
212 | } | 211 | } |
213 | 212 | ||
214 | static void __exit ip6t_hbh_fini(void) | 213 | static void __exit ip6t_hbh_fini(void) |
215 | { | 214 | { |
216 | ip6t_unregister_match(&opts_match); | 215 | xt_unregister_matches(opts_match, ARRAY_SIZE(opts_match)); |
217 | } | 216 | } |
218 | 217 | ||
219 | module_init(ip6t_hbh_init); | 218 | module_init(ip6t_hbh_init); |
diff --git a/net/ipv6/netfilter/ip6t_ipv6header.c b/net/ipv6/netfilter/ip6t_ipv6header.c index 9375eeb1369f..3093c398002f 100644 --- a/net/ipv6/netfilter/ip6t_ipv6header.c +++ b/net/ipv6/netfilter/ip6t_ipv6header.c | |||
@@ -128,7 +128,6 @@ ipv6header_checkentry(const char *tablename, | |||
128 | const void *ip, | 128 | const void *ip, |
129 | const struct xt_match *match, | 129 | const struct xt_match *match, |
130 | void *matchinfo, | 130 | void *matchinfo, |
131 | unsigned int matchsize, | ||
132 | unsigned int hook_mask) | 131 | unsigned int hook_mask) |
133 | { | 132 | { |
134 | const struct ip6t_ipv6header_info *info = matchinfo; | 133 | const struct ip6t_ipv6header_info *info = matchinfo; |
diff --git a/net/ipv6/netfilter/ip6t_owner.c b/net/ipv6/netfilter/ip6t_owner.c index 5d047990cd44..4eb9bbc4ebc3 100644 --- a/net/ipv6/netfilter/ip6t_owner.c +++ b/net/ipv6/netfilter/ip6t_owner.c | |||
@@ -57,7 +57,6 @@ checkentry(const char *tablename, | |||
57 | const void *ip, | 57 | const void *ip, |
58 | const struct xt_match *match, | 58 | const struct xt_match *match, |
59 | void *matchinfo, | 59 | void *matchinfo, |
60 | unsigned int matchsize, | ||
61 | unsigned int hook_mask) | 60 | unsigned int hook_mask) |
62 | { | 61 | { |
63 | const struct ip6t_owner_info *info = matchinfo; | 62 | const struct ip6t_owner_info *info = matchinfo; |
diff --git a/net/ipv6/netfilter/ip6t_rt.c b/net/ipv6/netfilter/ip6t_rt.c index fbb0184a41d8..bcb2e168a5bc 100644 --- a/net/ipv6/netfilter/ip6t_rt.c +++ b/net/ipv6/netfilter/ip6t_rt.c | |||
@@ -197,7 +197,6 @@ checkentry(const char *tablename, | |||
197 | const void *entry, | 197 | const void *entry, |
198 | const struct xt_match *match, | 198 | const struct xt_match *match, |
199 | void *matchinfo, | 199 | void *matchinfo, |
200 | unsigned int matchinfosize, | ||
201 | unsigned int hook_mask) | 200 | unsigned int hook_mask) |
202 | { | 201 | { |
203 | const struct ip6t_rt *rtinfo = matchinfo; | 202 | const struct ip6t_rt *rtinfo = matchinfo; |
diff --git a/net/ipv6/netfilter/ip6table_filter.c b/net/ipv6/netfilter/ip6table_filter.c index 60976c0c58e8..2fc07c74decf 100644 --- a/net/ipv6/netfilter/ip6table_filter.c +++ b/net/ipv6/netfilter/ip6table_filter.c | |||
@@ -108,7 +108,7 @@ ip6t_hook(unsigned int hook, | |||
108 | const struct net_device *out, | 108 | const struct net_device *out, |
109 | int (*okfn)(struct sk_buff *)) | 109 | int (*okfn)(struct sk_buff *)) |
110 | { | 110 | { |
111 | return ip6t_do_table(pskb, hook, in, out, &packet_filter, NULL); | 111 | return ip6t_do_table(pskb, hook, in, out, &packet_filter); |
112 | } | 112 | } |
113 | 113 | ||
114 | static unsigned int | 114 | static unsigned int |
@@ -128,7 +128,7 @@ ip6t_local_out_hook(unsigned int hook, | |||
128 | } | 128 | } |
129 | #endif | 129 | #endif |
130 | 130 | ||
131 | return ip6t_do_table(pskb, hook, in, out, &packet_filter, NULL); | 131 | return ip6t_do_table(pskb, hook, in, out, &packet_filter); |
132 | } | 132 | } |
133 | 133 | ||
134 | static struct nf_hook_ops ip6t_ops[] = { | 134 | static struct nf_hook_ops ip6t_ops[] = { |
diff --git a/net/ipv6/netfilter/ip6table_mangle.c b/net/ipv6/netfilter/ip6table_mangle.c index 03a13eab1dae..386ea260e767 100644 --- a/net/ipv6/netfilter/ip6table_mangle.c +++ b/net/ipv6/netfilter/ip6table_mangle.c | |||
@@ -138,7 +138,7 @@ ip6t_route_hook(unsigned int hook, | |||
138 | const struct net_device *out, | 138 | const struct net_device *out, |
139 | int (*okfn)(struct sk_buff *)) | 139 | int (*okfn)(struct sk_buff *)) |
140 | { | 140 | { |
141 | return ip6t_do_table(pskb, hook, in, out, &packet_mangler, NULL); | 141 | return ip6t_do_table(pskb, hook, in, out, &packet_mangler); |
142 | } | 142 | } |
143 | 143 | ||
144 | static unsigned int | 144 | static unsigned int |
@@ -174,18 +174,14 @@ ip6t_local_hook(unsigned int hook, | |||
174 | /* flowlabel and prio (includes version, which shouldn't change either */ | 174 | /* flowlabel and prio (includes version, which shouldn't change either */ |
175 | flowlabel = *((u_int32_t *) (*pskb)->nh.ipv6h); | 175 | flowlabel = *((u_int32_t *) (*pskb)->nh.ipv6h); |
176 | 176 | ||
177 | ret = ip6t_do_table(pskb, hook, in, out, &packet_mangler, NULL); | 177 | ret = ip6t_do_table(pskb, hook, in, out, &packet_mangler); |
178 | 178 | ||
179 | if (ret != NF_DROP && ret != NF_STOLEN | 179 | if (ret != NF_DROP && ret != NF_STOLEN |
180 | && (memcmp(&(*pskb)->nh.ipv6h->saddr, &saddr, sizeof(saddr)) | 180 | && (memcmp(&(*pskb)->nh.ipv6h->saddr, &saddr, sizeof(saddr)) |
181 | || memcmp(&(*pskb)->nh.ipv6h->daddr, &daddr, sizeof(daddr)) | 181 | || memcmp(&(*pskb)->nh.ipv6h->daddr, &daddr, sizeof(daddr)) |
182 | || (*pskb)->nfmark != nfmark | 182 | || (*pskb)->nfmark != nfmark |
183 | || (*pskb)->nh.ipv6h->hop_limit != hop_limit)) { | 183 | || (*pskb)->nh.ipv6h->hop_limit != hop_limit)) |
184 | 184 | return ip6_route_me_harder(*pskb) == 0 ? ret : NF_DROP; | |
185 | /* something which could affect routing has changed */ | ||
186 | |||
187 | DEBUGP("ip6table_mangle: we'd need to re-route a packet\n"); | ||
188 | } | ||
189 | 185 | ||
190 | return ret; | 186 | return ret; |
191 | } | 187 | } |
diff --git a/net/ipv6/netfilter/ip6table_raw.c b/net/ipv6/netfilter/ip6table_raw.c index 61a7c58e99f8..b4154da575c0 100644 --- a/net/ipv6/netfilter/ip6table_raw.c +++ b/net/ipv6/netfilter/ip6table_raw.c | |||
@@ -122,7 +122,7 @@ ip6t_hook(unsigned int hook, | |||
122 | const struct net_device *out, | 122 | const struct net_device *out, |
123 | int (*okfn)(struct sk_buff *)) | 123 | int (*okfn)(struct sk_buff *)) |
124 | { | 124 | { |
125 | return ip6t_do_table(pskb, hook, in, out, &packet_raw, NULL); | 125 | return ip6t_do_table(pskb, hook, in, out, &packet_raw); |
126 | } | 126 | } |
127 | 127 | ||
128 | static struct nf_hook_ops ip6t_ops[] = { | 128 | static struct nf_hook_ops ip6t_ops[] = { |
diff --git a/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c b/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c index c2ab38ff46af..e5e53fff9e38 100644 --- a/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c +++ b/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c | |||
@@ -335,7 +335,7 @@ static struct nf_hook_ops ipv6_conntrack_ops[] = { | |||
335 | /* From nf_conntrack_proto_icmpv6.c */ | 335 | /* From nf_conntrack_proto_icmpv6.c */ |
336 | extern unsigned int nf_ct_icmpv6_timeout; | 336 | extern unsigned int nf_ct_icmpv6_timeout; |
337 | 337 | ||
338 | /* From nf_conntrack_frag6.c */ | 338 | /* From nf_conntrack_reasm.c */ |
339 | extern unsigned int nf_ct_frag6_timeout; | 339 | extern unsigned int nf_ct_frag6_timeout; |
340 | extern unsigned int nf_ct_frag6_low_thresh; | 340 | extern unsigned int nf_ct_frag6_low_thresh; |
341 | extern unsigned int nf_ct_frag6_high_thresh; | 341 | extern unsigned int nf_ct_frag6_high_thresh; |
diff --git a/net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c b/net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c index ef18a7b7014b..34d447208ffd 100644 --- a/net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c +++ b/net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c | |||
@@ -33,7 +33,7 @@ | |||
33 | #include <net/netfilter/nf_conntrack_core.h> | 33 | #include <net/netfilter/nf_conntrack_core.h> |
34 | #include <net/netfilter/ipv6/nf_conntrack_icmpv6.h> | 34 | #include <net/netfilter/ipv6/nf_conntrack_icmpv6.h> |
35 | 35 | ||
36 | unsigned long nf_ct_icmpv6_timeout = 30*HZ; | 36 | unsigned long nf_ct_icmpv6_timeout __read_mostly = 30*HZ; |
37 | 37 | ||
38 | #if 0 | 38 | #if 0 |
39 | #define DEBUGP printk | 39 | #define DEBUGP printk |
diff --git a/net/ipv6/netfilter/nf_conntrack_reasm.c b/net/ipv6/netfilter/nf_conntrack_reasm.c index 00d5583807f7..bf93c1ea6be9 100644 --- a/net/ipv6/netfilter/nf_conntrack_reasm.c +++ b/net/ipv6/netfilter/nf_conntrack_reasm.c | |||
@@ -54,9 +54,9 @@ | |||
54 | #define NF_CT_FRAG6_LOW_THRESH 196608 /* == 192*1024 */ | 54 | #define NF_CT_FRAG6_LOW_THRESH 196608 /* == 192*1024 */ |
55 | #define NF_CT_FRAG6_TIMEOUT IPV6_FRAG_TIMEOUT | 55 | #define NF_CT_FRAG6_TIMEOUT IPV6_FRAG_TIMEOUT |
56 | 56 | ||
57 | unsigned int nf_ct_frag6_high_thresh = 256*1024; | 57 | unsigned int nf_ct_frag6_high_thresh __read_mostly = 256*1024; |
58 | unsigned int nf_ct_frag6_low_thresh = 192*1024; | 58 | unsigned int nf_ct_frag6_low_thresh __read_mostly = 192*1024; |
59 | unsigned long nf_ct_frag6_timeout = IPV6_FRAG_TIMEOUT; | 59 | unsigned long nf_ct_frag6_timeout __read_mostly = IPV6_FRAG_TIMEOUT; |
60 | 60 | ||
61 | struct nf_ct_frag6_skb_cb | 61 | struct nf_ct_frag6_skb_cb |
62 | { | 62 | { |
@@ -408,7 +408,7 @@ static int nf_ct_frag6_queue(struct nf_ct_frag6_queue *fq, struct sk_buff *skb, | |||
408 | return -1; | 408 | return -1; |
409 | } | 409 | } |
410 | 410 | ||
411 | if (skb->ip_summed == CHECKSUM_HW) | 411 | if (skb->ip_summed == CHECKSUM_COMPLETE) |
412 | skb->csum = csum_sub(skb->csum, | 412 | skb->csum = csum_sub(skb->csum, |
413 | csum_partial(skb->nh.raw, | 413 | csum_partial(skb->nh.raw, |
414 | (u8*)(fhdr + 1) - skb->nh.raw, | 414 | (u8*)(fhdr + 1) - skb->nh.raw, |
@@ -640,7 +640,7 @@ nf_ct_frag6_reasm(struct nf_ct_frag6_queue *fq, struct net_device *dev) | |||
640 | head->len += fp->len; | 640 | head->len += fp->len; |
641 | if (head->ip_summed != fp->ip_summed) | 641 | if (head->ip_summed != fp->ip_summed) |
642 | head->ip_summed = CHECKSUM_NONE; | 642 | head->ip_summed = CHECKSUM_NONE; |
643 | else if (head->ip_summed == CHECKSUM_HW) | 643 | else if (head->ip_summed == CHECKSUM_COMPLETE) |
644 | head->csum = csum_add(head->csum, fp->csum); | 644 | head->csum = csum_add(head->csum, fp->csum); |
645 | head->truesize += fp->truesize; | 645 | head->truesize += fp->truesize; |
646 | atomic_sub(fp->truesize, &nf_ct_frag6_mem); | 646 | atomic_sub(fp->truesize, &nf_ct_frag6_mem); |
@@ -652,7 +652,7 @@ nf_ct_frag6_reasm(struct nf_ct_frag6_queue *fq, struct net_device *dev) | |||
652 | head->nh.ipv6h->payload_len = htons(payload_len); | 652 | head->nh.ipv6h->payload_len = htons(payload_len); |
653 | 653 | ||
654 | /* Yes, and fold redundant checksum back. 8) */ | 654 | /* Yes, and fold redundant checksum back. 8) */ |
655 | if (head->ip_summed == CHECKSUM_HW) | 655 | if (head->ip_summed == CHECKSUM_COMPLETE) |
656 | head->csum = csum_partial(head->nh.raw, head->h.raw-head->nh.raw, head->csum); | 656 | head->csum = csum_partial(head->nh.raw, head->h.raw-head->nh.raw, head->csum); |
657 | 657 | ||
658 | fq->fragments = NULL; | 658 | fq->fragments = NULL; |
diff --git a/net/ipv6/raw.c b/net/ipv6/raw.c index 15b862d8acab..d09329ca3267 100644 --- a/net/ipv6/raw.c +++ b/net/ipv6/raw.c | |||
@@ -50,6 +50,9 @@ | |||
50 | #include <net/udp.h> | 50 | #include <net/udp.h> |
51 | #include <net/inet_common.h> | 51 | #include <net/inet_common.h> |
52 | #include <net/tcp_states.h> | 52 | #include <net/tcp_states.h> |
53 | #ifdef CONFIG_IPV6_MIP6 | ||
54 | #include <net/mip6.h> | ||
55 | #endif | ||
53 | 56 | ||
54 | #include <net/rawv6.h> | 57 | #include <net/rawv6.h> |
55 | #include <net/xfrm.h> | 58 | #include <net/xfrm.h> |
@@ -169,8 +172,32 @@ int ipv6_raw_deliver(struct sk_buff *skb, int nexthdr) | |||
169 | sk = __raw_v6_lookup(sk, nexthdr, daddr, saddr, IP6CB(skb)->iif); | 172 | sk = __raw_v6_lookup(sk, nexthdr, daddr, saddr, IP6CB(skb)->iif); |
170 | 173 | ||
171 | while (sk) { | 174 | while (sk) { |
175 | int filtered; | ||
176 | |||
172 | delivered = 1; | 177 | delivered = 1; |
173 | if (nexthdr != IPPROTO_ICMPV6 || !icmpv6_filter(sk, skb)) { | 178 | switch (nexthdr) { |
179 | case IPPROTO_ICMPV6: | ||
180 | filtered = icmpv6_filter(sk, skb); | ||
181 | break; | ||
182 | #ifdef CONFIG_IPV6_MIP6 | ||
183 | case IPPROTO_MH: | ||
184 | /* XXX: To validate MH only once for each packet, | ||
185 | * this is placed here. It should be after checking | ||
186 | * xfrm policy, however it doesn't. The checking xfrm | ||
187 | * policy is placed in rawv6_rcv() because it is | ||
188 | * required for each socket. | ||
189 | */ | ||
190 | filtered = mip6_mh_filter(sk, skb); | ||
191 | break; | ||
192 | #endif | ||
193 | default: | ||
194 | filtered = 0; | ||
195 | break; | ||
196 | } | ||
197 | |||
198 | if (filtered < 0) | ||
199 | break; | ||
200 | if (filtered == 0) { | ||
174 | struct sk_buff *clone = skb_clone(skb, GFP_ATOMIC); | 201 | struct sk_buff *clone = skb_clone(skb, GFP_ATOMIC); |
175 | 202 | ||
176 | /* Not releasing hash table! */ | 203 | /* Not releasing hash table! */ |
@@ -334,7 +361,7 @@ int rawv6_rcv(struct sock *sk, struct sk_buff *skb) | |||
334 | if (!rp->checksum) | 361 | if (!rp->checksum) |
335 | skb->ip_summed = CHECKSUM_UNNECESSARY; | 362 | skb->ip_summed = CHECKSUM_UNNECESSARY; |
336 | 363 | ||
337 | if (skb->ip_summed == CHECKSUM_HW) { | 364 | if (skb->ip_summed == CHECKSUM_COMPLETE) { |
338 | skb_postpull_rcsum(skb, skb->nh.raw, | 365 | skb_postpull_rcsum(skb, skb->nh.raw, |
339 | skb->h.raw - skb->nh.raw); | 366 | skb->h.raw - skb->nh.raw); |
340 | if (!csum_ipv6_magic(&skb->nh.ipv6h->saddr, | 367 | if (!csum_ipv6_magic(&skb->nh.ipv6h->saddr, |
@@ -582,6 +609,9 @@ static void rawv6_probe_proto_opt(struct flowi *fl, struct msghdr *msg) | |||
582 | struct iovec *iov; | 609 | struct iovec *iov; |
583 | u8 __user *type = NULL; | 610 | u8 __user *type = NULL; |
584 | u8 __user *code = NULL; | 611 | u8 __user *code = NULL; |
612 | #ifdef CONFIG_IPV6_MIP6 | ||
613 | u8 len = 0; | ||
614 | #endif | ||
585 | int probed = 0; | 615 | int probed = 0; |
586 | int i; | 616 | int i; |
587 | 617 | ||
@@ -613,6 +643,20 @@ static void rawv6_probe_proto_opt(struct flowi *fl, struct msghdr *msg) | |||
613 | probed = 1; | 643 | probed = 1; |
614 | } | 644 | } |
615 | break; | 645 | break; |
646 | #ifdef CONFIG_IPV6_MIP6 | ||
647 | case IPPROTO_MH: | ||
648 | if (iov->iov_base && iov->iov_len < 1) | ||
649 | break; | ||
650 | /* check if type field is readable or not. */ | ||
651 | if (iov->iov_len > 2 - len) { | ||
652 | u8 __user *p = iov->iov_base; | ||
653 | get_user(fl->fl_mh_type, &p[2 - len]); | ||
654 | probed = 1; | ||
655 | } else | ||
656 | len += iov->iov_len; | ||
657 | |||
658 | break; | ||
659 | #endif | ||
616 | default: | 660 | default: |
617 | probed = 1; | 661 | probed = 1; |
618 | break; | 662 | break; |
@@ -759,6 +803,7 @@ static int rawv6_sendmsg(struct kiocb *iocb, struct sock *sk, | |||
759 | 803 | ||
760 | if (!fl.oif && ipv6_addr_is_multicast(&fl.fl6_dst)) | 804 | if (!fl.oif && ipv6_addr_is_multicast(&fl.fl6_dst)) |
761 | fl.oif = np->mcast_oif; | 805 | fl.oif = np->mcast_oif; |
806 | security_sk_classify_flow(sk, &fl); | ||
762 | 807 | ||
763 | err = ip6_dst_lookup(sk, &dst, &fl); | 808 | err = ip6_dst_lookup(sk, &dst, &fl); |
764 | if (err) | 809 | if (err) |
diff --git a/net/ipv6/reassembly.c b/net/ipv6/reassembly.c index 4e299c69e1c6..f39bbedd1327 100644 --- a/net/ipv6/reassembly.c +++ b/net/ipv6/reassembly.c | |||
@@ -53,10 +53,10 @@ | |||
53 | #include <net/ndisc.h> | 53 | #include <net/ndisc.h> |
54 | #include <net/addrconf.h> | 54 | #include <net/addrconf.h> |
55 | 55 | ||
56 | int sysctl_ip6frag_high_thresh = 256*1024; | 56 | int sysctl_ip6frag_high_thresh __read_mostly = 256*1024; |
57 | int sysctl_ip6frag_low_thresh = 192*1024; | 57 | int sysctl_ip6frag_low_thresh __read_mostly = 192*1024; |
58 | 58 | ||
59 | int sysctl_ip6frag_time = IPV6_FRAG_TIMEOUT; | 59 | int sysctl_ip6frag_time __read_mostly = IPV6_FRAG_TIMEOUT; |
60 | 60 | ||
61 | struct ip6frag_skb_cb | 61 | struct ip6frag_skb_cb |
62 | { | 62 | { |
@@ -152,7 +152,7 @@ static unsigned int ip6qhashfn(u32 id, struct in6_addr *saddr, | |||
152 | } | 152 | } |
153 | 153 | ||
154 | static struct timer_list ip6_frag_secret_timer; | 154 | static struct timer_list ip6_frag_secret_timer; |
155 | int sysctl_ip6frag_secret_interval = 10 * 60 * HZ; | 155 | int sysctl_ip6frag_secret_interval __read_mostly = 10 * 60 * HZ; |
156 | 156 | ||
157 | static void ip6_frag_secret_rebuild(unsigned long dummy) | 157 | static void ip6_frag_secret_rebuild(unsigned long dummy) |
158 | { | 158 | { |
@@ -433,7 +433,7 @@ static void ip6_frag_queue(struct frag_queue *fq, struct sk_buff *skb, | |||
433 | return; | 433 | return; |
434 | } | 434 | } |
435 | 435 | ||
436 | if (skb->ip_summed == CHECKSUM_HW) | 436 | if (skb->ip_summed == CHECKSUM_COMPLETE) |
437 | skb->csum = csum_sub(skb->csum, | 437 | skb->csum = csum_sub(skb->csum, |
438 | csum_partial(skb->nh.raw, (u8*)(fhdr+1)-skb->nh.raw, 0)); | 438 | csum_partial(skb->nh.raw, (u8*)(fhdr+1)-skb->nh.raw, 0)); |
439 | 439 | ||
@@ -647,7 +647,7 @@ static int ip6_frag_reasm(struct frag_queue *fq, struct sk_buff **skb_in, | |||
647 | head->len += fp->len; | 647 | head->len += fp->len; |
648 | if (head->ip_summed != fp->ip_summed) | 648 | if (head->ip_summed != fp->ip_summed) |
649 | head->ip_summed = CHECKSUM_NONE; | 649 | head->ip_summed = CHECKSUM_NONE; |
650 | else if (head->ip_summed == CHECKSUM_HW) | 650 | else if (head->ip_summed == CHECKSUM_COMPLETE) |
651 | head->csum = csum_add(head->csum, fp->csum); | 651 | head->csum = csum_add(head->csum, fp->csum); |
652 | head->truesize += fp->truesize; | 652 | head->truesize += fp->truesize; |
653 | atomic_sub(fp->truesize, &ip6_frag_mem); | 653 | atomic_sub(fp->truesize, &ip6_frag_mem); |
@@ -662,7 +662,7 @@ static int ip6_frag_reasm(struct frag_queue *fq, struct sk_buff **skb_in, | |||
662 | *skb_in = head; | 662 | *skb_in = head; |
663 | 663 | ||
664 | /* Yes, and fold redundant checksum back. 8) */ | 664 | /* Yes, and fold redundant checksum back. 8) */ |
665 | if (head->ip_summed == CHECKSUM_HW) | 665 | if (head->ip_summed == CHECKSUM_COMPLETE) |
666 | head->csum = csum_partial(head->nh.raw, head->h.raw-head->nh.raw, head->csum); | 666 | head->csum = csum_partial(head->nh.raw, head->h.raw-head->nh.raw, head->csum); |
667 | 667 | ||
668 | IP6_INC_STATS_BH(IPSTATS_MIB_REASMOKS); | 668 | IP6_INC_STATS_BH(IPSTATS_MIB_REASMOKS); |
diff --git a/net/ipv6/route.c b/net/ipv6/route.c index d9baca062d24..d6b4b4f48d18 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c | |||
@@ -22,6 +22,8 @@ | |||
22 | * routers in REACHABLE, STALE, DELAY or PROBE states). | 22 | * routers in REACHABLE, STALE, DELAY or PROBE states). |
23 | * - always select the same router if it is (probably) | 23 | * - always select the same router if it is (probably) |
24 | * reachable. otherwise, round-robin the list. | 24 | * reachable. otherwise, round-robin the list. |
25 | * Ville Nuorvala | ||
26 | * Fixed routing subtrees. | ||
25 | */ | 27 | */ |
26 | 28 | ||
27 | #include <linux/capability.h> | 29 | #include <linux/capability.h> |
@@ -35,7 +37,6 @@ | |||
35 | #include <linux/netdevice.h> | 37 | #include <linux/netdevice.h> |
36 | #include <linux/in6.h> | 38 | #include <linux/in6.h> |
37 | #include <linux/init.h> | 39 | #include <linux/init.h> |
38 | #include <linux/netlink.h> | ||
39 | #include <linux/if_arp.h> | 40 | #include <linux/if_arp.h> |
40 | 41 | ||
41 | #ifdef CONFIG_PROC_FS | 42 | #ifdef CONFIG_PROC_FS |
@@ -54,6 +55,7 @@ | |||
54 | #include <net/dst.h> | 55 | #include <net/dst.h> |
55 | #include <net/xfrm.h> | 56 | #include <net/xfrm.h> |
56 | #include <net/netevent.h> | 57 | #include <net/netevent.h> |
58 | #include <net/netlink.h> | ||
57 | 59 | ||
58 | #include <asm/uaccess.h> | 60 | #include <asm/uaccess.h> |
59 | 61 | ||
@@ -74,9 +76,6 @@ | |||
74 | 76 | ||
75 | #define CLONE_OFFLINK_ROUTE 0 | 77 | #define CLONE_OFFLINK_ROUTE 0 |
76 | 78 | ||
77 | #define RT6_SELECT_F_IFACE 0x1 | ||
78 | #define RT6_SELECT_F_REACHABLE 0x2 | ||
79 | |||
80 | static int ip6_rt_max_size = 4096; | 79 | static int ip6_rt_max_size = 4096; |
81 | static int ip6_rt_gc_min_interval = HZ / 2; | 80 | static int ip6_rt_gc_min_interval = HZ / 2; |
82 | static int ip6_rt_gc_timeout = 60*HZ; | 81 | static int ip6_rt_gc_timeout = 60*HZ; |
@@ -140,15 +139,49 @@ struct rt6_info ip6_null_entry = { | |||
140 | .rt6i_ref = ATOMIC_INIT(1), | 139 | .rt6i_ref = ATOMIC_INIT(1), |
141 | }; | 140 | }; |
142 | 141 | ||
143 | struct fib6_node ip6_routing_table = { | 142 | #ifdef CONFIG_IPV6_MULTIPLE_TABLES |
144 | .leaf = &ip6_null_entry, | ||
145 | .fn_flags = RTN_ROOT | RTN_TL_ROOT | RTN_RTINFO, | ||
146 | }; | ||
147 | 143 | ||
148 | /* Protects all the ip6 fib */ | 144 | struct rt6_info ip6_prohibit_entry = { |
145 | .u = { | ||
146 | .dst = { | ||
147 | .__refcnt = ATOMIC_INIT(1), | ||
148 | .__use = 1, | ||
149 | .dev = &loopback_dev, | ||
150 | .obsolete = -1, | ||
151 | .error = -EACCES, | ||
152 | .metrics = { [RTAX_HOPLIMIT - 1] = 255, }, | ||
153 | .input = ip6_pkt_discard, | ||
154 | .output = ip6_pkt_discard_out, | ||
155 | .ops = &ip6_dst_ops, | ||
156 | .path = (struct dst_entry*)&ip6_prohibit_entry, | ||
157 | } | ||
158 | }, | ||
159 | .rt6i_flags = (RTF_REJECT | RTF_NONEXTHOP), | ||
160 | .rt6i_metric = ~(u32) 0, | ||
161 | .rt6i_ref = ATOMIC_INIT(1), | ||
162 | }; | ||
149 | 163 | ||
150 | DEFINE_RWLOCK(rt6_lock); | 164 | struct rt6_info ip6_blk_hole_entry = { |
165 | .u = { | ||
166 | .dst = { | ||
167 | .__refcnt = ATOMIC_INIT(1), | ||
168 | .__use = 1, | ||
169 | .dev = &loopback_dev, | ||
170 | .obsolete = -1, | ||
171 | .error = -EINVAL, | ||
172 | .metrics = { [RTAX_HOPLIMIT - 1] = 255, }, | ||
173 | .input = ip6_pkt_discard, | ||
174 | .output = ip6_pkt_discard_out, | ||
175 | .ops = &ip6_dst_ops, | ||
176 | .path = (struct dst_entry*)&ip6_blk_hole_entry, | ||
177 | } | ||
178 | }, | ||
179 | .rt6i_flags = (RTF_REJECT | RTF_NONEXTHOP), | ||
180 | .rt6i_metric = ~(u32) 0, | ||
181 | .rt6i_ref = ATOMIC_INIT(1), | ||
182 | }; | ||
151 | 183 | ||
184 | #endif | ||
152 | 185 | ||
153 | /* allocate dst with ip6_dst_ops */ | 186 | /* allocate dst with ip6_dst_ops */ |
154 | static __inline__ struct rt6_info *ip6_dst_alloc(void) | 187 | static __inline__ struct rt6_info *ip6_dst_alloc(void) |
@@ -188,8 +221,14 @@ static __inline__ int rt6_check_expired(const struct rt6_info *rt) | |||
188 | time_after(jiffies, rt->rt6i_expires)); | 221 | time_after(jiffies, rt->rt6i_expires)); |
189 | } | 222 | } |
190 | 223 | ||
224 | static inline int rt6_need_strict(struct in6_addr *daddr) | ||
225 | { | ||
226 | return (ipv6_addr_type(daddr) & | ||
227 | (IPV6_ADDR_MULTICAST | IPV6_ADDR_LINKLOCAL)); | ||
228 | } | ||
229 | |||
191 | /* | 230 | /* |
192 | * Route lookup. Any rt6_lock is implied. | 231 | * Route lookup. Any table->tb6_lock is implied. |
193 | */ | 232 | */ |
194 | 233 | ||
195 | static __inline__ struct rt6_info *rt6_device_match(struct rt6_info *rt, | 234 | static __inline__ struct rt6_info *rt6_device_match(struct rt6_info *rt, |
@@ -298,7 +337,7 @@ static int rt6_score_route(struct rt6_info *rt, int oif, | |||
298 | int m, n; | 337 | int m, n; |
299 | 338 | ||
300 | m = rt6_check_dev(rt, oif); | 339 | m = rt6_check_dev(rt, oif); |
301 | if (!m && (strict & RT6_SELECT_F_IFACE)) | 340 | if (!m && (strict & RT6_LOOKUP_F_IFACE)) |
302 | return -1; | 341 | return -1; |
303 | #ifdef CONFIG_IPV6_ROUTER_PREF | 342 | #ifdef CONFIG_IPV6_ROUTER_PREF |
304 | m |= IPV6_DECODE_PREF(IPV6_EXTRACT_PREF(rt->rt6i_flags)) << 2; | 343 | m |= IPV6_DECODE_PREF(IPV6_EXTRACT_PREF(rt->rt6i_flags)) << 2; |
@@ -306,7 +345,7 @@ static int rt6_score_route(struct rt6_info *rt, int oif, | |||
306 | n = rt6_check_neigh(rt); | 345 | n = rt6_check_neigh(rt); |
307 | if (n > 1) | 346 | if (n > 1) |
308 | m |= 16; | 347 | m |= 16; |
309 | else if (!n && strict & RT6_SELECT_F_REACHABLE) | 348 | else if (!n && strict & RT6_LOOKUP_F_REACHABLE) |
310 | return -1; | 349 | return -1; |
311 | return m; | 350 | return m; |
312 | } | 351 | } |
@@ -346,7 +385,7 @@ static struct rt6_info *rt6_select(struct rt6_info **head, int oif, | |||
346 | } | 385 | } |
347 | 386 | ||
348 | if (!match && | 387 | if (!match && |
349 | (strict & RT6_SELECT_F_REACHABLE) && | 388 | (strict & RT6_LOOKUP_F_REACHABLE) && |
350 | last && last != rt0) { | 389 | last && last != rt0) { |
351 | /* no entries matched; do round-robin */ | 390 | /* no entries matched; do round-robin */ |
352 | static DEFINE_SPINLOCK(lock); | 391 | static DEFINE_SPINLOCK(lock); |
@@ -417,7 +456,7 @@ int rt6_route_rcv(struct net_device *dev, u8 *opt, int len, | |||
417 | rt = rt6_get_route_info(prefix, rinfo->prefix_len, gwaddr, dev->ifindex); | 456 | rt = rt6_get_route_info(prefix, rinfo->prefix_len, gwaddr, dev->ifindex); |
418 | 457 | ||
419 | if (rt && !lifetime) { | 458 | if (rt && !lifetime) { |
420 | ip6_del_rt(rt, NULL, NULL, NULL); | 459 | ip6_del_rt(rt); |
421 | rt = NULL; | 460 | rt = NULL; |
422 | } | 461 | } |
423 | 462 | ||
@@ -441,44 +480,95 @@ int rt6_route_rcv(struct net_device *dev, u8 *opt, int len, | |||
441 | } | 480 | } |
442 | #endif | 481 | #endif |
443 | 482 | ||
444 | struct rt6_info *rt6_lookup(struct in6_addr *daddr, struct in6_addr *saddr, | 483 | #define BACKTRACK(saddr) \ |
445 | int oif, int strict) | 484 | do { \ |
485 | if (rt == &ip6_null_entry) { \ | ||
486 | struct fib6_node *pn; \ | ||
487 | while (fn) { \ | ||
488 | if (fn->fn_flags & RTN_TL_ROOT) \ | ||
489 | goto out; \ | ||
490 | pn = fn->parent; \ | ||
491 | if (FIB6_SUBTREE(pn) && FIB6_SUBTREE(pn) != fn) \ | ||
492 | fn = fib6_lookup(pn->subtree, NULL, saddr); \ | ||
493 | else \ | ||
494 | fn = pn; \ | ||
495 | if (fn->fn_flags & RTN_RTINFO) \ | ||
496 | goto restart; \ | ||
497 | } \ | ||
498 | } \ | ||
499 | } while(0) | ||
500 | |||
501 | static struct rt6_info *ip6_pol_route_lookup(struct fib6_table *table, | ||
502 | struct flowi *fl, int flags) | ||
446 | { | 503 | { |
447 | struct fib6_node *fn; | 504 | struct fib6_node *fn; |
448 | struct rt6_info *rt; | 505 | struct rt6_info *rt; |
449 | 506 | ||
450 | read_lock_bh(&rt6_lock); | 507 | read_lock_bh(&table->tb6_lock); |
451 | fn = fib6_lookup(&ip6_routing_table, daddr, saddr); | 508 | fn = fib6_lookup(&table->tb6_root, &fl->fl6_dst, &fl->fl6_src); |
452 | rt = rt6_device_match(fn->leaf, oif, strict); | 509 | restart: |
510 | rt = fn->leaf; | ||
511 | rt = rt6_device_match(rt, fl->oif, flags); | ||
512 | BACKTRACK(&fl->fl6_src); | ||
513 | out: | ||
453 | dst_hold(&rt->u.dst); | 514 | dst_hold(&rt->u.dst); |
454 | rt->u.dst.__use++; | 515 | read_unlock_bh(&table->tb6_lock); |
455 | read_unlock_bh(&rt6_lock); | ||
456 | 516 | ||
457 | rt->u.dst.lastuse = jiffies; | 517 | rt->u.dst.lastuse = jiffies; |
458 | if (rt->u.dst.error == 0) | 518 | rt->u.dst.__use++; |
459 | return rt; | 519 | |
460 | dst_release(&rt->u.dst); | 520 | return rt; |
521 | |||
522 | } | ||
523 | |||
524 | struct rt6_info *rt6_lookup(struct in6_addr *daddr, struct in6_addr *saddr, | ||
525 | int oif, int strict) | ||
526 | { | ||
527 | struct flowi fl = { | ||
528 | .oif = oif, | ||
529 | .nl_u = { | ||
530 | .ip6_u = { | ||
531 | .daddr = *daddr, | ||
532 | /* TODO: saddr */ | ||
533 | }, | ||
534 | }, | ||
535 | }; | ||
536 | struct dst_entry *dst; | ||
537 | int flags = strict ? RT6_LOOKUP_F_IFACE : 0; | ||
538 | |||
539 | dst = fib6_rule_lookup(&fl, flags, ip6_pol_route_lookup); | ||
540 | if (dst->error == 0) | ||
541 | return (struct rt6_info *) dst; | ||
542 | |||
543 | dst_release(dst); | ||
544 | |||
461 | return NULL; | 545 | return NULL; |
462 | } | 546 | } |
463 | 547 | ||
464 | /* ip6_ins_rt is called with FREE rt6_lock. | 548 | /* ip6_ins_rt is called with FREE table->tb6_lock. |
465 | It takes new route entry, the addition fails by any reason the | 549 | It takes new route entry, the addition fails by any reason the |
466 | route is freed. In any case, if caller does not hold it, it may | 550 | route is freed. In any case, if caller does not hold it, it may |
467 | be destroyed. | 551 | be destroyed. |
468 | */ | 552 | */ |
469 | 553 | ||
470 | int ip6_ins_rt(struct rt6_info *rt, struct nlmsghdr *nlh, | 554 | static int __ip6_ins_rt(struct rt6_info *rt, struct nl_info *info) |
471 | void *_rtattr, struct netlink_skb_parms *req) | ||
472 | { | 555 | { |
473 | int err; | 556 | int err; |
557 | struct fib6_table *table; | ||
474 | 558 | ||
475 | write_lock_bh(&rt6_lock); | 559 | table = rt->rt6i_table; |
476 | err = fib6_add(&ip6_routing_table, rt, nlh, _rtattr, req); | 560 | write_lock_bh(&table->tb6_lock); |
477 | write_unlock_bh(&rt6_lock); | 561 | err = fib6_add(&table->tb6_root, rt, info); |
562 | write_unlock_bh(&table->tb6_lock); | ||
478 | 563 | ||
479 | return err; | 564 | return err; |
480 | } | 565 | } |
481 | 566 | ||
567 | int ip6_ins_rt(struct rt6_info *rt) | ||
568 | { | ||
569 | return __ip6_ins_rt(rt, NULL); | ||
570 | } | ||
571 | |||
482 | static struct rt6_info *rt6_alloc_cow(struct rt6_info *ort, struct in6_addr *daddr, | 572 | static struct rt6_info *rt6_alloc_cow(struct rt6_info *ort, struct in6_addr *daddr, |
483 | struct in6_addr *saddr) | 573 | struct in6_addr *saddr) |
484 | { | 574 | { |
@@ -532,51 +622,39 @@ static struct rt6_info *rt6_alloc_clone(struct rt6_info *ort, struct in6_addr *d | |||
532 | return rt; | 622 | return rt; |
533 | } | 623 | } |
534 | 624 | ||
535 | #define BACKTRACK() \ | 625 | static struct rt6_info *ip6_pol_route_input(struct fib6_table *table, |
536 | if (rt == &ip6_null_entry) { \ | 626 | struct flowi *fl, int flags) |
537 | while ((fn = fn->parent) != NULL) { \ | ||
538 | if (fn->fn_flags & RTN_ROOT) { \ | ||
539 | goto out; \ | ||
540 | } \ | ||
541 | if (fn->fn_flags & RTN_RTINFO) \ | ||
542 | goto restart; \ | ||
543 | } \ | ||
544 | } | ||
545 | |||
546 | |||
547 | void ip6_route_input(struct sk_buff *skb) | ||
548 | { | 627 | { |
549 | struct fib6_node *fn; | 628 | struct fib6_node *fn; |
550 | struct rt6_info *rt, *nrt; | 629 | struct rt6_info *rt, *nrt; |
551 | int strict; | 630 | int strict = 0; |
552 | int attempts = 3; | 631 | int attempts = 3; |
553 | int err; | 632 | int err; |
554 | int reachable = RT6_SELECT_F_REACHABLE; | 633 | int reachable = RT6_LOOKUP_F_REACHABLE; |
555 | 634 | ||
556 | strict = ipv6_addr_type(&skb->nh.ipv6h->daddr) & (IPV6_ADDR_MULTICAST|IPV6_ADDR_LINKLOCAL) ? RT6_SELECT_F_IFACE : 0; | 635 | strict |= flags & RT6_LOOKUP_F_IFACE; |
557 | 636 | ||
558 | relookup: | 637 | relookup: |
559 | read_lock_bh(&rt6_lock); | 638 | read_lock_bh(&table->tb6_lock); |
560 | 639 | ||
561 | restart_2: | 640 | restart_2: |
562 | fn = fib6_lookup(&ip6_routing_table, &skb->nh.ipv6h->daddr, | 641 | fn = fib6_lookup(&table->tb6_root, &fl->fl6_dst, &fl->fl6_src); |
563 | &skb->nh.ipv6h->saddr); | ||
564 | 642 | ||
565 | restart: | 643 | restart: |
566 | rt = rt6_select(&fn->leaf, skb->dev->ifindex, strict | reachable); | 644 | rt = rt6_select(&fn->leaf, fl->iif, strict | reachable); |
567 | BACKTRACK(); | 645 | BACKTRACK(&fl->fl6_src); |
568 | if (rt == &ip6_null_entry || | 646 | if (rt == &ip6_null_entry || |
569 | rt->rt6i_flags & RTF_CACHE) | 647 | rt->rt6i_flags & RTF_CACHE) |
570 | goto out; | 648 | goto out; |
571 | 649 | ||
572 | dst_hold(&rt->u.dst); | 650 | dst_hold(&rt->u.dst); |
573 | read_unlock_bh(&rt6_lock); | 651 | read_unlock_bh(&table->tb6_lock); |
574 | 652 | ||
575 | if (!rt->rt6i_nexthop && !(rt->rt6i_flags & RTF_NONEXTHOP)) | 653 | if (!rt->rt6i_nexthop && !(rt->rt6i_flags & RTF_NONEXTHOP)) |
576 | nrt = rt6_alloc_cow(rt, &skb->nh.ipv6h->daddr, &skb->nh.ipv6h->saddr); | 654 | nrt = rt6_alloc_cow(rt, &fl->fl6_dst, &fl->fl6_src); |
577 | else { | 655 | else { |
578 | #if CLONE_OFFLINK_ROUTE | 656 | #if CLONE_OFFLINK_ROUTE |
579 | nrt = rt6_alloc_clone(rt, &skb->nh.ipv6h->daddr); | 657 | nrt = rt6_alloc_clone(rt, &fl->fl6_dst); |
580 | #else | 658 | #else |
581 | goto out2; | 659 | goto out2; |
582 | #endif | 660 | #endif |
@@ -587,7 +665,7 @@ restart: | |||
587 | 665 | ||
588 | dst_hold(&rt->u.dst); | 666 | dst_hold(&rt->u.dst); |
589 | if (nrt) { | 667 | if (nrt) { |
590 | err = ip6_ins_rt(nrt, NULL, NULL, &NETLINK_CB(skb)); | 668 | err = ip6_ins_rt(nrt); |
591 | if (!err) | 669 | if (!err) |
592 | goto out2; | 670 | goto out2; |
593 | } | 671 | } |
@@ -596,7 +674,7 @@ restart: | |||
596 | goto out2; | 674 | goto out2; |
597 | 675 | ||
598 | /* | 676 | /* |
599 | * Race condition! In the gap, when rt6_lock was | 677 | * Race condition! In the gap, when table->tb6_lock was |
600 | * released someone could insert this route. Relookup. | 678 | * released someone could insert this route. Relookup. |
601 | */ | 679 | */ |
602 | dst_release(&rt->u.dst); | 680 | dst_release(&rt->u.dst); |
@@ -608,40 +686,63 @@ out: | |||
608 | goto restart_2; | 686 | goto restart_2; |
609 | } | 687 | } |
610 | dst_hold(&rt->u.dst); | 688 | dst_hold(&rt->u.dst); |
611 | read_unlock_bh(&rt6_lock); | 689 | read_unlock_bh(&table->tb6_lock); |
612 | out2: | 690 | out2: |
613 | rt->u.dst.lastuse = jiffies; | 691 | rt->u.dst.lastuse = jiffies; |
614 | rt->u.dst.__use++; | 692 | rt->u.dst.__use++; |
615 | skb->dst = (struct dst_entry *) rt; | 693 | |
616 | return; | 694 | return rt; |
617 | } | 695 | } |
618 | 696 | ||
619 | struct dst_entry * ip6_route_output(struct sock *sk, struct flowi *fl) | 697 | void ip6_route_input(struct sk_buff *skb) |
698 | { | ||
699 | struct ipv6hdr *iph = skb->nh.ipv6h; | ||
700 | struct flowi fl = { | ||
701 | .iif = skb->dev->ifindex, | ||
702 | .nl_u = { | ||
703 | .ip6_u = { | ||
704 | .daddr = iph->daddr, | ||
705 | .saddr = iph->saddr, | ||
706 | #ifdef CONFIG_IPV6_ROUTE_FWMARK | ||
707 | .fwmark = skb->nfmark, | ||
708 | #endif | ||
709 | .flowlabel = (* (u32 *) iph)&IPV6_FLOWINFO_MASK, | ||
710 | }, | ||
711 | }, | ||
712 | .proto = iph->nexthdr, | ||
713 | }; | ||
714 | int flags = rt6_need_strict(&iph->daddr) ? RT6_LOOKUP_F_IFACE : 0; | ||
715 | |||
716 | skb->dst = fib6_rule_lookup(&fl, flags, ip6_pol_route_input); | ||
717 | } | ||
718 | |||
719 | static struct rt6_info *ip6_pol_route_output(struct fib6_table *table, | ||
720 | struct flowi *fl, int flags) | ||
620 | { | 721 | { |
621 | struct fib6_node *fn; | 722 | struct fib6_node *fn; |
622 | struct rt6_info *rt, *nrt; | 723 | struct rt6_info *rt, *nrt; |
623 | int strict; | 724 | int strict = 0; |
624 | int attempts = 3; | 725 | int attempts = 3; |
625 | int err; | 726 | int err; |
626 | int reachable = RT6_SELECT_F_REACHABLE; | 727 | int reachable = RT6_LOOKUP_F_REACHABLE; |
627 | 728 | ||
628 | strict = ipv6_addr_type(&fl->fl6_dst) & (IPV6_ADDR_MULTICAST|IPV6_ADDR_LINKLOCAL) ? RT6_SELECT_F_IFACE : 0; | 729 | strict |= flags & RT6_LOOKUP_F_IFACE; |
629 | 730 | ||
630 | relookup: | 731 | relookup: |
631 | read_lock_bh(&rt6_lock); | 732 | read_lock_bh(&table->tb6_lock); |
632 | 733 | ||
633 | restart_2: | 734 | restart_2: |
634 | fn = fib6_lookup(&ip6_routing_table, &fl->fl6_dst, &fl->fl6_src); | 735 | fn = fib6_lookup(&table->tb6_root, &fl->fl6_dst, &fl->fl6_src); |
635 | 736 | ||
636 | restart: | 737 | restart: |
637 | rt = rt6_select(&fn->leaf, fl->oif, strict | reachable); | 738 | rt = rt6_select(&fn->leaf, fl->oif, strict | reachable); |
638 | BACKTRACK(); | 739 | BACKTRACK(&fl->fl6_src); |
639 | if (rt == &ip6_null_entry || | 740 | if (rt == &ip6_null_entry || |
640 | rt->rt6i_flags & RTF_CACHE) | 741 | rt->rt6i_flags & RTF_CACHE) |
641 | goto out; | 742 | goto out; |
642 | 743 | ||
643 | dst_hold(&rt->u.dst); | 744 | dst_hold(&rt->u.dst); |
644 | read_unlock_bh(&rt6_lock); | 745 | read_unlock_bh(&table->tb6_lock); |
645 | 746 | ||
646 | if (!rt->rt6i_nexthop && !(rt->rt6i_flags & RTF_NONEXTHOP)) | 747 | if (!rt->rt6i_nexthop && !(rt->rt6i_flags & RTF_NONEXTHOP)) |
647 | nrt = rt6_alloc_cow(rt, &fl->fl6_dst, &fl->fl6_src); | 748 | nrt = rt6_alloc_cow(rt, &fl->fl6_dst, &fl->fl6_src); |
@@ -658,7 +759,7 @@ restart: | |||
658 | 759 | ||
659 | dst_hold(&rt->u.dst); | 760 | dst_hold(&rt->u.dst); |
660 | if (nrt) { | 761 | if (nrt) { |
661 | err = ip6_ins_rt(nrt, NULL, NULL, NULL); | 762 | err = ip6_ins_rt(nrt); |
662 | if (!err) | 763 | if (!err) |
663 | goto out2; | 764 | goto out2; |
664 | } | 765 | } |
@@ -667,7 +768,7 @@ restart: | |||
667 | goto out2; | 768 | goto out2; |
668 | 769 | ||
669 | /* | 770 | /* |
670 | * Race condition! In the gap, when rt6_lock was | 771 | * Race condition! In the gap, when table->tb6_lock was |
671 | * released someone could insert this route. Relookup. | 772 | * released someone could insert this route. Relookup. |
672 | */ | 773 | */ |
673 | dst_release(&rt->u.dst); | 774 | dst_release(&rt->u.dst); |
@@ -679,11 +780,21 @@ out: | |||
679 | goto restart_2; | 780 | goto restart_2; |
680 | } | 781 | } |
681 | dst_hold(&rt->u.dst); | 782 | dst_hold(&rt->u.dst); |
682 | read_unlock_bh(&rt6_lock); | 783 | read_unlock_bh(&table->tb6_lock); |
683 | out2: | 784 | out2: |
684 | rt->u.dst.lastuse = jiffies; | 785 | rt->u.dst.lastuse = jiffies; |
685 | rt->u.dst.__use++; | 786 | rt->u.dst.__use++; |
686 | return &rt->u.dst; | 787 | return rt; |
788 | } | ||
789 | |||
790 | struct dst_entry * ip6_route_output(struct sock *sk, struct flowi *fl) | ||
791 | { | ||
792 | int flags = 0; | ||
793 | |||
794 | if (rt6_need_strict(&fl->fl6_dst)) | ||
795 | flags |= RT6_LOOKUP_F_IFACE; | ||
796 | |||
797 | return fib6_rule_lookup(fl, flags, ip6_pol_route_output); | ||
687 | } | 798 | } |
688 | 799 | ||
689 | 800 | ||
@@ -709,7 +820,7 @@ static struct dst_entry *ip6_negative_advice(struct dst_entry *dst) | |||
709 | 820 | ||
710 | if (rt) { | 821 | if (rt) { |
711 | if (rt->rt6i_flags & RTF_CACHE) | 822 | if (rt->rt6i_flags & RTF_CACHE) |
712 | ip6_del_rt(rt, NULL, NULL, NULL); | 823 | ip6_del_rt(rt); |
713 | else | 824 | else |
714 | dst_release(dst); | 825 | dst_release(dst); |
715 | } | 826 | } |
@@ -747,8 +858,6 @@ static void ip6_rt_update_pmtu(struct dst_entry *dst, u32 mtu) | |||
747 | } | 858 | } |
748 | } | 859 | } |
749 | 860 | ||
750 | /* Protected by rt6_lock. */ | ||
751 | static struct dst_entry *ndisc_dst_gc_list; | ||
752 | static int ipv6_get_mtu(struct net_device *dev); | 861 | static int ipv6_get_mtu(struct net_device *dev); |
753 | 862 | ||
754 | static inline unsigned int ipv6_advmss(unsigned int mtu) | 863 | static inline unsigned int ipv6_advmss(unsigned int mtu) |
@@ -769,6 +878,9 @@ static inline unsigned int ipv6_advmss(unsigned int mtu) | |||
769 | return mtu; | 878 | return mtu; |
770 | } | 879 | } |
771 | 880 | ||
881 | static struct dst_entry *ndisc_dst_gc_list; | ||
882 | static DEFINE_SPINLOCK(ndisc_lock); | ||
883 | |||
772 | struct dst_entry *ndisc_dst_alloc(struct net_device *dev, | 884 | struct dst_entry *ndisc_dst_alloc(struct net_device *dev, |
773 | struct neighbour *neigh, | 885 | struct neighbour *neigh, |
774 | struct in6_addr *addr, | 886 | struct in6_addr *addr, |
@@ -809,10 +921,10 @@ struct dst_entry *ndisc_dst_alloc(struct net_device *dev, | |||
809 | rt->rt6i_dst.plen = 128; | 921 | rt->rt6i_dst.plen = 128; |
810 | #endif | 922 | #endif |
811 | 923 | ||
812 | write_lock_bh(&rt6_lock); | 924 | spin_lock_bh(&ndisc_lock); |
813 | rt->u.dst.next = ndisc_dst_gc_list; | 925 | rt->u.dst.next = ndisc_dst_gc_list; |
814 | ndisc_dst_gc_list = &rt->u.dst; | 926 | ndisc_dst_gc_list = &rt->u.dst; |
815 | write_unlock_bh(&rt6_lock); | 927 | spin_unlock_bh(&ndisc_lock); |
816 | 928 | ||
817 | fib6_force_start_gc(); | 929 | fib6_force_start_gc(); |
818 | 930 | ||
@@ -826,8 +938,11 @@ int ndisc_dst_gc(int *more) | |||
826 | int freed; | 938 | int freed; |
827 | 939 | ||
828 | next = NULL; | 940 | next = NULL; |
941 | freed = 0; | ||
942 | |||
943 | spin_lock_bh(&ndisc_lock); | ||
829 | pprev = &ndisc_dst_gc_list; | 944 | pprev = &ndisc_dst_gc_list; |
830 | freed = 0; | 945 | |
831 | while ((dst = *pprev) != NULL) { | 946 | while ((dst = *pprev) != NULL) { |
832 | if (!atomic_read(&dst->__refcnt)) { | 947 | if (!atomic_read(&dst->__refcnt)) { |
833 | *pprev = dst->next; | 948 | *pprev = dst->next; |
@@ -839,6 +954,8 @@ int ndisc_dst_gc(int *more) | |||
839 | } | 954 | } |
840 | } | 955 | } |
841 | 956 | ||
957 | spin_unlock_bh(&ndisc_lock); | ||
958 | |||
842 | return freed; | 959 | return freed; |
843 | } | 960 | } |
844 | 961 | ||
@@ -899,28 +1016,24 @@ int ipv6_get_hoplimit(struct net_device *dev) | |||
899 | * | 1016 | * |
900 | */ | 1017 | */ |
901 | 1018 | ||
902 | int ip6_route_add(struct in6_rtmsg *rtmsg, struct nlmsghdr *nlh, | 1019 | int ip6_route_add(struct fib6_config *cfg) |
903 | void *_rtattr, struct netlink_skb_parms *req) | ||
904 | { | 1020 | { |
905 | int err; | 1021 | int err; |
906 | struct rtmsg *r; | ||
907 | struct rtattr **rta; | ||
908 | struct rt6_info *rt = NULL; | 1022 | struct rt6_info *rt = NULL; |
909 | struct net_device *dev = NULL; | 1023 | struct net_device *dev = NULL; |
910 | struct inet6_dev *idev = NULL; | 1024 | struct inet6_dev *idev = NULL; |
1025 | struct fib6_table *table; | ||
911 | int addr_type; | 1026 | int addr_type; |
912 | 1027 | ||
913 | rta = (struct rtattr **) _rtattr; | 1028 | if (cfg->fc_dst_len > 128 || cfg->fc_src_len > 128) |
914 | |||
915 | if (rtmsg->rtmsg_dst_len > 128 || rtmsg->rtmsg_src_len > 128) | ||
916 | return -EINVAL; | 1029 | return -EINVAL; |
917 | #ifndef CONFIG_IPV6_SUBTREES | 1030 | #ifndef CONFIG_IPV6_SUBTREES |
918 | if (rtmsg->rtmsg_src_len) | 1031 | if (cfg->fc_src_len) |
919 | return -EINVAL; | 1032 | return -EINVAL; |
920 | #endif | 1033 | #endif |
921 | if (rtmsg->rtmsg_ifindex) { | 1034 | if (cfg->fc_ifindex) { |
922 | err = -ENODEV; | 1035 | err = -ENODEV; |
923 | dev = dev_get_by_index(rtmsg->rtmsg_ifindex); | 1036 | dev = dev_get_by_index(cfg->fc_ifindex); |
924 | if (!dev) | 1037 | if (!dev) |
925 | goto out; | 1038 | goto out; |
926 | idev = in6_dev_get(dev); | 1039 | idev = in6_dev_get(dev); |
@@ -928,8 +1041,14 @@ int ip6_route_add(struct in6_rtmsg *rtmsg, struct nlmsghdr *nlh, | |||
928 | goto out; | 1041 | goto out; |
929 | } | 1042 | } |
930 | 1043 | ||
931 | if (rtmsg->rtmsg_metric == 0) | 1044 | if (cfg->fc_metric == 0) |
932 | rtmsg->rtmsg_metric = IP6_RT_PRIO_USER; | 1045 | cfg->fc_metric = IP6_RT_PRIO_USER; |
1046 | |||
1047 | table = fib6_new_table(cfg->fc_table); | ||
1048 | if (table == NULL) { | ||
1049 | err = -ENOBUFS; | ||
1050 | goto out; | ||
1051 | } | ||
933 | 1052 | ||
934 | rt = ip6_dst_alloc(); | 1053 | rt = ip6_dst_alloc(); |
935 | 1054 | ||
@@ -939,14 +1058,13 @@ int ip6_route_add(struct in6_rtmsg *rtmsg, struct nlmsghdr *nlh, | |||
939 | } | 1058 | } |
940 | 1059 | ||
941 | rt->u.dst.obsolete = -1; | 1060 | rt->u.dst.obsolete = -1; |
942 | rt->rt6i_expires = jiffies + clock_t_to_jiffies(rtmsg->rtmsg_info); | 1061 | rt->rt6i_expires = jiffies + clock_t_to_jiffies(cfg->fc_expires); |
943 | if (nlh && (r = NLMSG_DATA(nlh))) { | ||
944 | rt->rt6i_protocol = r->rtm_protocol; | ||
945 | } else { | ||
946 | rt->rt6i_protocol = RTPROT_BOOT; | ||
947 | } | ||
948 | 1062 | ||
949 | addr_type = ipv6_addr_type(&rtmsg->rtmsg_dst); | 1063 | if (cfg->fc_protocol == RTPROT_UNSPEC) |
1064 | cfg->fc_protocol = RTPROT_BOOT; | ||
1065 | rt->rt6i_protocol = cfg->fc_protocol; | ||
1066 | |||
1067 | addr_type = ipv6_addr_type(&cfg->fc_dst); | ||
950 | 1068 | ||
951 | if (addr_type & IPV6_ADDR_MULTICAST) | 1069 | if (addr_type & IPV6_ADDR_MULTICAST) |
952 | rt->u.dst.input = ip6_mc_input; | 1070 | rt->u.dst.input = ip6_mc_input; |
@@ -955,24 +1073,22 @@ int ip6_route_add(struct in6_rtmsg *rtmsg, struct nlmsghdr *nlh, | |||
955 | 1073 | ||
956 | rt->u.dst.output = ip6_output; | 1074 | rt->u.dst.output = ip6_output; |
957 | 1075 | ||
958 | ipv6_addr_prefix(&rt->rt6i_dst.addr, | 1076 | ipv6_addr_prefix(&rt->rt6i_dst.addr, &cfg->fc_dst, cfg->fc_dst_len); |
959 | &rtmsg->rtmsg_dst, rtmsg->rtmsg_dst_len); | 1077 | rt->rt6i_dst.plen = cfg->fc_dst_len; |
960 | rt->rt6i_dst.plen = rtmsg->rtmsg_dst_len; | ||
961 | if (rt->rt6i_dst.plen == 128) | 1078 | if (rt->rt6i_dst.plen == 128) |
962 | rt->u.dst.flags = DST_HOST; | 1079 | rt->u.dst.flags = DST_HOST; |
963 | 1080 | ||
964 | #ifdef CONFIG_IPV6_SUBTREES | 1081 | #ifdef CONFIG_IPV6_SUBTREES |
965 | ipv6_addr_prefix(&rt->rt6i_src.addr, | 1082 | ipv6_addr_prefix(&rt->rt6i_src.addr, &cfg->fc_src, cfg->fc_src_len); |
966 | &rtmsg->rtmsg_src, rtmsg->rtmsg_src_len); | 1083 | rt->rt6i_src.plen = cfg->fc_src_len; |
967 | rt->rt6i_src.plen = rtmsg->rtmsg_src_len; | ||
968 | #endif | 1084 | #endif |
969 | 1085 | ||
970 | rt->rt6i_metric = rtmsg->rtmsg_metric; | 1086 | rt->rt6i_metric = cfg->fc_metric; |
971 | 1087 | ||
972 | /* We cannot add true routes via loopback here, | 1088 | /* We cannot add true routes via loopback here, |
973 | they would result in kernel looping; promote them to reject routes | 1089 | they would result in kernel looping; promote them to reject routes |
974 | */ | 1090 | */ |
975 | if ((rtmsg->rtmsg_flags&RTF_REJECT) || | 1091 | if ((cfg->fc_flags & RTF_REJECT) || |
976 | (dev && (dev->flags&IFF_LOOPBACK) && !(addr_type&IPV6_ADDR_LOOPBACK))) { | 1092 | (dev && (dev->flags&IFF_LOOPBACK) && !(addr_type&IPV6_ADDR_LOOPBACK))) { |
977 | /* hold loopback dev/idev if we haven't done so. */ | 1093 | /* hold loopback dev/idev if we haven't done so. */ |
978 | if (dev != &loopback_dev) { | 1094 | if (dev != &loopback_dev) { |
@@ -995,12 +1111,12 @@ int ip6_route_add(struct in6_rtmsg *rtmsg, struct nlmsghdr *nlh, | |||
995 | goto install_route; | 1111 | goto install_route; |
996 | } | 1112 | } |
997 | 1113 | ||
998 | if (rtmsg->rtmsg_flags & RTF_GATEWAY) { | 1114 | if (cfg->fc_flags & RTF_GATEWAY) { |
999 | struct in6_addr *gw_addr; | 1115 | struct in6_addr *gw_addr; |
1000 | int gwa_type; | 1116 | int gwa_type; |
1001 | 1117 | ||
1002 | gw_addr = &rtmsg->rtmsg_gateway; | 1118 | gw_addr = &cfg->fc_gateway; |
1003 | ipv6_addr_copy(&rt->rt6i_gateway, &rtmsg->rtmsg_gateway); | 1119 | ipv6_addr_copy(&rt->rt6i_gateway, gw_addr); |
1004 | gwa_type = ipv6_addr_type(gw_addr); | 1120 | gwa_type = ipv6_addr_type(gw_addr); |
1005 | 1121 | ||
1006 | if (gwa_type != (IPV6_ADDR_LINKLOCAL|IPV6_ADDR_UNICAST)) { | 1122 | if (gwa_type != (IPV6_ADDR_LINKLOCAL|IPV6_ADDR_UNICAST)) { |
@@ -1017,7 +1133,7 @@ int ip6_route_add(struct in6_rtmsg *rtmsg, struct nlmsghdr *nlh, | |||
1017 | if (!(gwa_type&IPV6_ADDR_UNICAST)) | 1133 | if (!(gwa_type&IPV6_ADDR_UNICAST)) |
1018 | goto out; | 1134 | goto out; |
1019 | 1135 | ||
1020 | grt = rt6_lookup(gw_addr, NULL, rtmsg->rtmsg_ifindex, 1); | 1136 | grt = rt6_lookup(gw_addr, NULL, cfg->fc_ifindex, 1); |
1021 | 1137 | ||
1022 | err = -EHOSTUNREACH; | 1138 | err = -EHOSTUNREACH; |
1023 | if (grt == NULL) | 1139 | if (grt == NULL) |
@@ -1049,7 +1165,7 @@ int ip6_route_add(struct in6_rtmsg *rtmsg, struct nlmsghdr *nlh, | |||
1049 | if (dev == NULL) | 1165 | if (dev == NULL) |
1050 | goto out; | 1166 | goto out; |
1051 | 1167 | ||
1052 | if (rtmsg->rtmsg_flags & (RTF_GATEWAY|RTF_NONEXTHOP)) { | 1168 | if (cfg->fc_flags & (RTF_GATEWAY | RTF_NONEXTHOP)) { |
1053 | rt->rt6i_nexthop = __neigh_lookup_errno(&nd_tbl, &rt->rt6i_gateway, dev); | 1169 | rt->rt6i_nexthop = __neigh_lookup_errno(&nd_tbl, &rt->rt6i_gateway, dev); |
1054 | if (IS_ERR(rt->rt6i_nexthop)) { | 1170 | if (IS_ERR(rt->rt6i_nexthop)) { |
1055 | err = PTR_ERR(rt->rt6i_nexthop); | 1171 | err = PTR_ERR(rt->rt6i_nexthop); |
@@ -1058,24 +1174,24 @@ int ip6_route_add(struct in6_rtmsg *rtmsg, struct nlmsghdr *nlh, | |||
1058 | } | 1174 | } |
1059 | } | 1175 | } |
1060 | 1176 | ||
1061 | rt->rt6i_flags = rtmsg->rtmsg_flags; | 1177 | rt->rt6i_flags = cfg->fc_flags; |
1062 | 1178 | ||
1063 | install_route: | 1179 | install_route: |
1064 | if (rta && rta[RTA_METRICS-1]) { | 1180 | if (cfg->fc_mx) { |
1065 | int attrlen = RTA_PAYLOAD(rta[RTA_METRICS-1]); | 1181 | struct nlattr *nla; |
1066 | struct rtattr *attr = RTA_DATA(rta[RTA_METRICS-1]); | 1182 | int remaining; |
1067 | 1183 | ||
1068 | while (RTA_OK(attr, attrlen)) { | 1184 | nla_for_each_attr(nla, cfg->fc_mx, cfg->fc_mx_len, remaining) { |
1069 | unsigned flavor = attr->rta_type; | 1185 | int type = nla->nla_type; |
1070 | if (flavor) { | 1186 | |
1071 | if (flavor > RTAX_MAX) { | 1187 | if (type) { |
1188 | if (type > RTAX_MAX) { | ||
1072 | err = -EINVAL; | 1189 | err = -EINVAL; |
1073 | goto out; | 1190 | goto out; |
1074 | } | 1191 | } |
1075 | rt->u.dst.metrics[flavor-1] = | 1192 | |
1076 | *(u32 *)RTA_DATA(attr); | 1193 | rt->u.dst.metrics[type - 1] = nla_get_u32(nla); |
1077 | } | 1194 | } |
1078 | attr = RTA_NEXT(attr, attrlen); | ||
1079 | } | 1195 | } |
1080 | } | 1196 | } |
1081 | 1197 | ||
@@ -1087,7 +1203,8 @@ install_route: | |||
1087 | rt->u.dst.metrics[RTAX_ADVMSS-1] = ipv6_advmss(dst_mtu(&rt->u.dst)); | 1203 | rt->u.dst.metrics[RTAX_ADVMSS-1] = ipv6_advmss(dst_mtu(&rt->u.dst)); |
1088 | rt->u.dst.dev = dev; | 1204 | rt->u.dst.dev = dev; |
1089 | rt->rt6i_idev = idev; | 1205 | rt->rt6i_idev = idev; |
1090 | return ip6_ins_rt(rt, nlh, _rtattr, req); | 1206 | rt->rt6i_table = table; |
1207 | return __ip6_ins_rt(rt, &cfg->fc_nlinfo); | ||
1091 | 1208 | ||
1092 | out: | 1209 | out: |
1093 | if (dev) | 1210 | if (dev) |
@@ -1099,51 +1216,65 @@ out: | |||
1099 | return err; | 1216 | return err; |
1100 | } | 1217 | } |
1101 | 1218 | ||
1102 | int ip6_del_rt(struct rt6_info *rt, struct nlmsghdr *nlh, void *_rtattr, struct netlink_skb_parms *req) | 1219 | static int __ip6_del_rt(struct rt6_info *rt, struct nl_info *info) |
1103 | { | 1220 | { |
1104 | int err; | 1221 | int err; |
1222 | struct fib6_table *table; | ||
1105 | 1223 | ||
1106 | write_lock_bh(&rt6_lock); | 1224 | if (rt == &ip6_null_entry) |
1225 | return -ENOENT; | ||
1107 | 1226 | ||
1108 | err = fib6_del(rt, nlh, _rtattr, req); | 1227 | table = rt->rt6i_table; |
1228 | write_lock_bh(&table->tb6_lock); | ||
1229 | |||
1230 | err = fib6_del(rt, info); | ||
1109 | dst_release(&rt->u.dst); | 1231 | dst_release(&rt->u.dst); |
1110 | 1232 | ||
1111 | write_unlock_bh(&rt6_lock); | 1233 | write_unlock_bh(&table->tb6_lock); |
1112 | 1234 | ||
1113 | return err; | 1235 | return err; |
1114 | } | 1236 | } |
1115 | 1237 | ||
1116 | static int ip6_route_del(struct in6_rtmsg *rtmsg, struct nlmsghdr *nlh, void *_rtattr, struct netlink_skb_parms *req) | 1238 | int ip6_del_rt(struct rt6_info *rt) |
1117 | { | 1239 | { |
1240 | return __ip6_del_rt(rt, NULL); | ||
1241 | } | ||
1242 | |||
1243 | static int ip6_route_del(struct fib6_config *cfg) | ||
1244 | { | ||
1245 | struct fib6_table *table; | ||
1118 | struct fib6_node *fn; | 1246 | struct fib6_node *fn; |
1119 | struct rt6_info *rt; | 1247 | struct rt6_info *rt; |
1120 | int err = -ESRCH; | 1248 | int err = -ESRCH; |
1121 | 1249 | ||
1122 | read_lock_bh(&rt6_lock); | 1250 | table = fib6_get_table(cfg->fc_table); |
1251 | if (table == NULL) | ||
1252 | return err; | ||
1123 | 1253 | ||
1124 | fn = fib6_locate(&ip6_routing_table, | 1254 | read_lock_bh(&table->tb6_lock); |
1125 | &rtmsg->rtmsg_dst, rtmsg->rtmsg_dst_len, | 1255 | |
1126 | &rtmsg->rtmsg_src, rtmsg->rtmsg_src_len); | 1256 | fn = fib6_locate(&table->tb6_root, |
1257 | &cfg->fc_dst, cfg->fc_dst_len, | ||
1258 | &cfg->fc_src, cfg->fc_src_len); | ||
1127 | 1259 | ||
1128 | if (fn) { | 1260 | if (fn) { |
1129 | for (rt = fn->leaf; rt; rt = rt->u.next) { | 1261 | for (rt = fn->leaf; rt; rt = rt->u.next) { |
1130 | if (rtmsg->rtmsg_ifindex && | 1262 | if (cfg->fc_ifindex && |
1131 | (rt->rt6i_dev == NULL || | 1263 | (rt->rt6i_dev == NULL || |
1132 | rt->rt6i_dev->ifindex != rtmsg->rtmsg_ifindex)) | 1264 | rt->rt6i_dev->ifindex != cfg->fc_ifindex)) |
1133 | continue; | 1265 | continue; |
1134 | if (rtmsg->rtmsg_flags&RTF_GATEWAY && | 1266 | if (cfg->fc_flags & RTF_GATEWAY && |
1135 | !ipv6_addr_equal(&rtmsg->rtmsg_gateway, &rt->rt6i_gateway)) | 1267 | !ipv6_addr_equal(&cfg->fc_gateway, &rt->rt6i_gateway)) |
1136 | continue; | 1268 | continue; |
1137 | if (rtmsg->rtmsg_metric && | 1269 | if (cfg->fc_metric && cfg->fc_metric != rt->rt6i_metric) |
1138 | rtmsg->rtmsg_metric != rt->rt6i_metric) | ||
1139 | continue; | 1270 | continue; |
1140 | dst_hold(&rt->u.dst); | 1271 | dst_hold(&rt->u.dst); |
1141 | read_unlock_bh(&rt6_lock); | 1272 | read_unlock_bh(&table->tb6_lock); |
1142 | 1273 | ||
1143 | return ip6_del_rt(rt, nlh, _rtattr, req); | 1274 | return __ip6_del_rt(rt, &cfg->fc_nlinfo); |
1144 | } | 1275 | } |
1145 | } | 1276 | } |
1146 | read_unlock_bh(&rt6_lock); | 1277 | read_unlock_bh(&table->tb6_lock); |
1147 | 1278 | ||
1148 | return err; | 1279 | return err; |
1149 | } | 1280 | } |
@@ -1151,13 +1282,18 @@ static int ip6_route_del(struct in6_rtmsg *rtmsg, struct nlmsghdr *nlh, void *_r | |||
1151 | /* | 1282 | /* |
1152 | * Handle redirects | 1283 | * Handle redirects |
1153 | */ | 1284 | */ |
1154 | void rt6_redirect(struct in6_addr *dest, struct in6_addr *saddr, | 1285 | struct ip6rd_flowi { |
1155 | struct neighbour *neigh, u8 *lladdr, int on_link) | 1286 | struct flowi fl; |
1287 | struct in6_addr gateway; | ||
1288 | }; | ||
1289 | |||
1290 | static struct rt6_info *__ip6_route_redirect(struct fib6_table *table, | ||
1291 | struct flowi *fl, | ||
1292 | int flags) | ||
1156 | { | 1293 | { |
1157 | struct rt6_info *rt, *nrt = NULL; | 1294 | struct ip6rd_flowi *rdfl = (struct ip6rd_flowi *)fl; |
1158 | int strict; | 1295 | struct rt6_info *rt; |
1159 | struct fib6_node *fn; | 1296 | struct fib6_node *fn; |
1160 | struct netevent_redirect netevent; | ||
1161 | 1297 | ||
1162 | /* | 1298 | /* |
1163 | * Get the "current" route for this destination and | 1299 | * Get the "current" route for this destination and |
@@ -1169,10 +1305,9 @@ void rt6_redirect(struct in6_addr *dest, struct in6_addr *saddr, | |||
1169 | * is a bit fuzzy and one might need to check all possible | 1305 | * is a bit fuzzy and one might need to check all possible |
1170 | * routes. | 1306 | * routes. |
1171 | */ | 1307 | */ |
1172 | strict = ipv6_addr_type(dest) & (IPV6_ADDR_MULTICAST | IPV6_ADDR_LINKLOCAL); | ||
1173 | 1308 | ||
1174 | read_lock_bh(&rt6_lock); | 1309 | read_lock_bh(&table->tb6_lock); |
1175 | fn = fib6_lookup(&ip6_routing_table, dest, NULL); | 1310 | fn = fib6_lookup(&table->tb6_root, &fl->fl6_dst, &fl->fl6_src); |
1176 | restart: | 1311 | restart: |
1177 | for (rt = fn->leaf; rt; rt = rt->u.next) { | 1312 | for (rt = fn->leaf; rt; rt = rt->u.next) { |
1178 | /* | 1313 | /* |
@@ -1187,29 +1322,60 @@ restart: | |||
1187 | continue; | 1322 | continue; |
1188 | if (!(rt->rt6i_flags & RTF_GATEWAY)) | 1323 | if (!(rt->rt6i_flags & RTF_GATEWAY)) |
1189 | continue; | 1324 | continue; |
1190 | if (neigh->dev != rt->rt6i_dev) | 1325 | if (fl->oif != rt->rt6i_dev->ifindex) |
1191 | continue; | 1326 | continue; |
1192 | if (!ipv6_addr_equal(saddr, &rt->rt6i_gateway)) | 1327 | if (!ipv6_addr_equal(&rdfl->gateway, &rt->rt6i_gateway)) |
1193 | continue; | 1328 | continue; |
1194 | break; | 1329 | break; |
1195 | } | 1330 | } |
1196 | if (rt) | ||
1197 | dst_hold(&rt->u.dst); | ||
1198 | else if (strict) { | ||
1199 | while ((fn = fn->parent) != NULL) { | ||
1200 | if (fn->fn_flags & RTN_ROOT) | ||
1201 | break; | ||
1202 | if (fn->fn_flags & RTN_RTINFO) | ||
1203 | goto restart; | ||
1204 | } | ||
1205 | } | ||
1206 | read_unlock_bh(&rt6_lock); | ||
1207 | 1331 | ||
1208 | if (!rt) { | 1332 | if (!rt) |
1333 | rt = &ip6_null_entry; | ||
1334 | BACKTRACK(&fl->fl6_src); | ||
1335 | out: | ||
1336 | dst_hold(&rt->u.dst); | ||
1337 | |||
1338 | read_unlock_bh(&table->tb6_lock); | ||
1339 | |||
1340 | return rt; | ||
1341 | }; | ||
1342 | |||
1343 | static struct rt6_info *ip6_route_redirect(struct in6_addr *dest, | ||
1344 | struct in6_addr *src, | ||
1345 | struct in6_addr *gateway, | ||
1346 | struct net_device *dev) | ||
1347 | { | ||
1348 | struct ip6rd_flowi rdfl = { | ||
1349 | .fl = { | ||
1350 | .oif = dev->ifindex, | ||
1351 | .nl_u = { | ||
1352 | .ip6_u = { | ||
1353 | .daddr = *dest, | ||
1354 | .saddr = *src, | ||
1355 | }, | ||
1356 | }, | ||
1357 | }, | ||
1358 | .gateway = *gateway, | ||
1359 | }; | ||
1360 | int flags = rt6_need_strict(dest) ? RT6_LOOKUP_F_IFACE : 0; | ||
1361 | |||
1362 | return (struct rt6_info *)fib6_rule_lookup((struct flowi *)&rdfl, flags, __ip6_route_redirect); | ||
1363 | } | ||
1364 | |||
1365 | void rt6_redirect(struct in6_addr *dest, struct in6_addr *src, | ||
1366 | struct in6_addr *saddr, | ||
1367 | struct neighbour *neigh, u8 *lladdr, int on_link) | ||
1368 | { | ||
1369 | struct rt6_info *rt, *nrt = NULL; | ||
1370 | struct netevent_redirect netevent; | ||
1371 | |||
1372 | rt = ip6_route_redirect(dest, src, saddr, neigh->dev); | ||
1373 | |||
1374 | if (rt == &ip6_null_entry) { | ||
1209 | if (net_ratelimit()) | 1375 | if (net_ratelimit()) |
1210 | printk(KERN_DEBUG "rt6_redirect: source isn't a valid nexthop " | 1376 | printk(KERN_DEBUG "rt6_redirect: source isn't a valid nexthop " |
1211 | "for redirect target\n"); | 1377 | "for redirect target\n"); |
1212 | return; | 1378 | goto out; |
1213 | } | 1379 | } |
1214 | 1380 | ||
1215 | /* | 1381 | /* |
@@ -1252,7 +1418,7 @@ restart: | |||
1252 | nrt->u.dst.metrics[RTAX_MTU-1] = ipv6_get_mtu(neigh->dev); | 1418 | nrt->u.dst.metrics[RTAX_MTU-1] = ipv6_get_mtu(neigh->dev); |
1253 | nrt->u.dst.metrics[RTAX_ADVMSS-1] = ipv6_advmss(dst_mtu(&nrt->u.dst)); | 1419 | nrt->u.dst.metrics[RTAX_ADVMSS-1] = ipv6_advmss(dst_mtu(&nrt->u.dst)); |
1254 | 1420 | ||
1255 | if (ip6_ins_rt(nrt, NULL, NULL, NULL)) | 1421 | if (ip6_ins_rt(nrt)) |
1256 | goto out; | 1422 | goto out; |
1257 | 1423 | ||
1258 | netevent.old = &rt->u.dst; | 1424 | netevent.old = &rt->u.dst; |
@@ -1260,7 +1426,7 @@ restart: | |||
1260 | call_netevent_notifiers(NETEVENT_REDIRECT, &netevent); | 1426 | call_netevent_notifiers(NETEVENT_REDIRECT, &netevent); |
1261 | 1427 | ||
1262 | if (rt->rt6i_flags&RTF_CACHE) { | 1428 | if (rt->rt6i_flags&RTF_CACHE) { |
1263 | ip6_del_rt(rt, NULL, NULL, NULL); | 1429 | ip6_del_rt(rt); |
1264 | return; | 1430 | return; |
1265 | } | 1431 | } |
1266 | 1432 | ||
@@ -1342,7 +1508,7 @@ void rt6_pmtu_discovery(struct in6_addr *daddr, struct in6_addr *saddr, | |||
1342 | dst_set_expires(&nrt->u.dst, ip6_rt_mtu_expires); | 1508 | dst_set_expires(&nrt->u.dst, ip6_rt_mtu_expires); |
1343 | nrt->rt6i_flags |= RTF_DYNAMIC|RTF_EXPIRES; | 1509 | nrt->rt6i_flags |= RTF_DYNAMIC|RTF_EXPIRES; |
1344 | 1510 | ||
1345 | ip6_ins_rt(nrt, NULL, NULL, NULL); | 1511 | ip6_ins_rt(nrt); |
1346 | } | 1512 | } |
1347 | out: | 1513 | out: |
1348 | dst_release(&rt->u.dst); | 1514 | dst_release(&rt->u.dst); |
@@ -1378,6 +1544,7 @@ static struct rt6_info * ip6_rt_copy(struct rt6_info *ort) | |||
1378 | #ifdef CONFIG_IPV6_SUBTREES | 1544 | #ifdef CONFIG_IPV6_SUBTREES |
1379 | memcpy(&rt->rt6i_src, &ort->rt6i_src, sizeof(struct rt6key)); | 1545 | memcpy(&rt->rt6i_src, &ort->rt6i_src, sizeof(struct rt6key)); |
1380 | #endif | 1546 | #endif |
1547 | rt->rt6i_table = ort->rt6i_table; | ||
1381 | } | 1548 | } |
1382 | return rt; | 1549 | return rt; |
1383 | } | 1550 | } |
@@ -1388,9 +1555,14 @@ static struct rt6_info *rt6_get_route_info(struct in6_addr *prefix, int prefixle | |||
1388 | { | 1555 | { |
1389 | struct fib6_node *fn; | 1556 | struct fib6_node *fn; |
1390 | struct rt6_info *rt = NULL; | 1557 | struct rt6_info *rt = NULL; |
1558 | struct fib6_table *table; | ||
1559 | |||
1560 | table = fib6_get_table(RT6_TABLE_INFO); | ||
1561 | if (table == NULL) | ||
1562 | return NULL; | ||
1391 | 1563 | ||
1392 | write_lock_bh(&rt6_lock); | 1564 | write_lock_bh(&table->tb6_lock); |
1393 | fn = fib6_locate(&ip6_routing_table, prefix ,prefixlen, NULL, 0); | 1565 | fn = fib6_locate(&table->tb6_root, prefix ,prefixlen, NULL, 0); |
1394 | if (!fn) | 1566 | if (!fn) |
1395 | goto out; | 1567 | goto out; |
1396 | 1568 | ||
@@ -1405,7 +1577,7 @@ static struct rt6_info *rt6_get_route_info(struct in6_addr *prefix, int prefixle | |||
1405 | break; | 1577 | break; |
1406 | } | 1578 | } |
1407 | out: | 1579 | out: |
1408 | write_unlock_bh(&rt6_lock); | 1580 | write_unlock_bh(&table->tb6_lock); |
1409 | return rt; | 1581 | return rt; |
1410 | } | 1582 | } |
1411 | 1583 | ||
@@ -1413,21 +1585,23 @@ static struct rt6_info *rt6_add_route_info(struct in6_addr *prefix, int prefixle | |||
1413 | struct in6_addr *gwaddr, int ifindex, | 1585 | struct in6_addr *gwaddr, int ifindex, |
1414 | unsigned pref) | 1586 | unsigned pref) |
1415 | { | 1587 | { |
1416 | struct in6_rtmsg rtmsg; | 1588 | struct fib6_config cfg = { |
1589 | .fc_table = RT6_TABLE_INFO, | ||
1590 | .fc_metric = 1024, | ||
1591 | .fc_ifindex = ifindex, | ||
1592 | .fc_dst_len = prefixlen, | ||
1593 | .fc_flags = RTF_GATEWAY | RTF_ADDRCONF | RTF_ROUTEINFO | | ||
1594 | RTF_UP | RTF_PREF(pref), | ||
1595 | }; | ||
1596 | |||
1597 | ipv6_addr_copy(&cfg.fc_dst, prefix); | ||
1598 | ipv6_addr_copy(&cfg.fc_gateway, gwaddr); | ||
1417 | 1599 | ||
1418 | memset(&rtmsg, 0, sizeof(rtmsg)); | ||
1419 | rtmsg.rtmsg_type = RTMSG_NEWROUTE; | ||
1420 | ipv6_addr_copy(&rtmsg.rtmsg_dst, prefix); | ||
1421 | rtmsg.rtmsg_dst_len = prefixlen; | ||
1422 | ipv6_addr_copy(&rtmsg.rtmsg_gateway, gwaddr); | ||
1423 | rtmsg.rtmsg_metric = 1024; | ||
1424 | rtmsg.rtmsg_flags = RTF_GATEWAY | RTF_ADDRCONF | RTF_ROUTEINFO | RTF_UP | RTF_PREF(pref); | ||
1425 | /* We should treat it as a default route if prefix length is 0. */ | 1600 | /* We should treat it as a default route if prefix length is 0. */ |
1426 | if (!prefixlen) | 1601 | if (!prefixlen) |
1427 | rtmsg.rtmsg_flags |= RTF_DEFAULT; | 1602 | cfg.fc_flags |= RTF_DEFAULT; |
1428 | rtmsg.rtmsg_ifindex = ifindex; | ||
1429 | 1603 | ||
1430 | ip6_route_add(&rtmsg, NULL, NULL, NULL); | 1604 | ip6_route_add(&cfg); |
1431 | 1605 | ||
1432 | return rt6_get_route_info(prefix, prefixlen, gwaddr, ifindex); | 1606 | return rt6_get_route_info(prefix, prefixlen, gwaddr, ifindex); |
1433 | } | 1607 | } |
@@ -1436,12 +1610,14 @@ static struct rt6_info *rt6_add_route_info(struct in6_addr *prefix, int prefixle | |||
1436 | struct rt6_info *rt6_get_dflt_router(struct in6_addr *addr, struct net_device *dev) | 1610 | struct rt6_info *rt6_get_dflt_router(struct in6_addr *addr, struct net_device *dev) |
1437 | { | 1611 | { |
1438 | struct rt6_info *rt; | 1612 | struct rt6_info *rt; |
1439 | struct fib6_node *fn; | 1613 | struct fib6_table *table; |
1440 | 1614 | ||
1441 | fn = &ip6_routing_table; | 1615 | table = fib6_get_table(RT6_TABLE_DFLT); |
1616 | if (table == NULL) | ||
1617 | return NULL; | ||
1442 | 1618 | ||
1443 | write_lock_bh(&rt6_lock); | 1619 | write_lock_bh(&table->tb6_lock); |
1444 | for (rt = fn->leaf; rt; rt=rt->u.next) { | 1620 | for (rt = table->tb6_root.leaf; rt; rt=rt->u.next) { |
1445 | if (dev == rt->rt6i_dev && | 1621 | if (dev == rt->rt6i_dev && |
1446 | ((rt->rt6i_flags & (RTF_ADDRCONF | RTF_DEFAULT)) == (RTF_ADDRCONF | RTF_DEFAULT)) && | 1622 | ((rt->rt6i_flags & (RTF_ADDRCONF | RTF_DEFAULT)) == (RTF_ADDRCONF | RTF_DEFAULT)) && |
1447 | ipv6_addr_equal(&rt->rt6i_gateway, addr)) | 1623 | ipv6_addr_equal(&rt->rt6i_gateway, addr)) |
@@ -1449,7 +1625,7 @@ struct rt6_info *rt6_get_dflt_router(struct in6_addr *addr, struct net_device *d | |||
1449 | } | 1625 | } |
1450 | if (rt) | 1626 | if (rt) |
1451 | dst_hold(&rt->u.dst); | 1627 | dst_hold(&rt->u.dst); |
1452 | write_unlock_bh(&rt6_lock); | 1628 | write_unlock_bh(&table->tb6_lock); |
1453 | return rt; | 1629 | return rt; |
1454 | } | 1630 | } |
1455 | 1631 | ||
@@ -1457,43 +1633,65 @@ struct rt6_info *rt6_add_dflt_router(struct in6_addr *gwaddr, | |||
1457 | struct net_device *dev, | 1633 | struct net_device *dev, |
1458 | unsigned int pref) | 1634 | unsigned int pref) |
1459 | { | 1635 | { |
1460 | struct in6_rtmsg rtmsg; | 1636 | struct fib6_config cfg = { |
1637 | .fc_table = RT6_TABLE_DFLT, | ||
1638 | .fc_metric = 1024, | ||
1639 | .fc_ifindex = dev->ifindex, | ||
1640 | .fc_flags = RTF_GATEWAY | RTF_ADDRCONF | RTF_DEFAULT | | ||
1641 | RTF_UP | RTF_EXPIRES | RTF_PREF(pref), | ||
1642 | }; | ||
1461 | 1643 | ||
1462 | memset(&rtmsg, 0, sizeof(struct in6_rtmsg)); | 1644 | ipv6_addr_copy(&cfg.fc_gateway, gwaddr); |
1463 | rtmsg.rtmsg_type = RTMSG_NEWROUTE; | ||
1464 | ipv6_addr_copy(&rtmsg.rtmsg_gateway, gwaddr); | ||
1465 | rtmsg.rtmsg_metric = 1024; | ||
1466 | rtmsg.rtmsg_flags = RTF_GATEWAY | RTF_ADDRCONF | RTF_DEFAULT | RTF_UP | RTF_EXPIRES | | ||
1467 | RTF_PREF(pref); | ||
1468 | 1645 | ||
1469 | rtmsg.rtmsg_ifindex = dev->ifindex; | 1646 | ip6_route_add(&cfg); |
1470 | 1647 | ||
1471 | ip6_route_add(&rtmsg, NULL, NULL, NULL); | ||
1472 | return rt6_get_dflt_router(gwaddr, dev); | 1648 | return rt6_get_dflt_router(gwaddr, dev); |
1473 | } | 1649 | } |
1474 | 1650 | ||
1475 | void rt6_purge_dflt_routers(void) | 1651 | void rt6_purge_dflt_routers(void) |
1476 | { | 1652 | { |
1477 | struct rt6_info *rt; | 1653 | struct rt6_info *rt; |
1654 | struct fib6_table *table; | ||
1655 | |||
1656 | /* NOTE: Keep consistent with rt6_get_dflt_router */ | ||
1657 | table = fib6_get_table(RT6_TABLE_DFLT); | ||
1658 | if (table == NULL) | ||
1659 | return; | ||
1478 | 1660 | ||
1479 | restart: | 1661 | restart: |
1480 | read_lock_bh(&rt6_lock); | 1662 | read_lock_bh(&table->tb6_lock); |
1481 | for (rt = ip6_routing_table.leaf; rt; rt = rt->u.next) { | 1663 | for (rt = table->tb6_root.leaf; rt; rt = rt->u.next) { |
1482 | if (rt->rt6i_flags & (RTF_DEFAULT | RTF_ADDRCONF)) { | 1664 | if (rt->rt6i_flags & (RTF_DEFAULT | RTF_ADDRCONF)) { |
1483 | dst_hold(&rt->u.dst); | 1665 | dst_hold(&rt->u.dst); |
1484 | 1666 | read_unlock_bh(&table->tb6_lock); | |
1485 | read_unlock_bh(&rt6_lock); | 1667 | ip6_del_rt(rt); |
1486 | |||
1487 | ip6_del_rt(rt, NULL, NULL, NULL); | ||
1488 | |||
1489 | goto restart; | 1668 | goto restart; |
1490 | } | 1669 | } |
1491 | } | 1670 | } |
1492 | read_unlock_bh(&rt6_lock); | 1671 | read_unlock_bh(&table->tb6_lock); |
1672 | } | ||
1673 | |||
1674 | static void rtmsg_to_fib6_config(struct in6_rtmsg *rtmsg, | ||
1675 | struct fib6_config *cfg) | ||
1676 | { | ||
1677 | memset(cfg, 0, sizeof(*cfg)); | ||
1678 | |||
1679 | cfg->fc_table = RT6_TABLE_MAIN; | ||
1680 | cfg->fc_ifindex = rtmsg->rtmsg_ifindex; | ||
1681 | cfg->fc_metric = rtmsg->rtmsg_metric; | ||
1682 | cfg->fc_expires = rtmsg->rtmsg_info; | ||
1683 | cfg->fc_dst_len = rtmsg->rtmsg_dst_len; | ||
1684 | cfg->fc_src_len = rtmsg->rtmsg_src_len; | ||
1685 | cfg->fc_flags = rtmsg->rtmsg_flags; | ||
1686 | |||
1687 | ipv6_addr_copy(&cfg->fc_dst, &rtmsg->rtmsg_dst); | ||
1688 | ipv6_addr_copy(&cfg->fc_src, &rtmsg->rtmsg_src); | ||
1689 | ipv6_addr_copy(&cfg->fc_gateway, &rtmsg->rtmsg_gateway); | ||
1493 | } | 1690 | } |
1494 | 1691 | ||
1495 | int ipv6_route_ioctl(unsigned int cmd, void __user *arg) | 1692 | int ipv6_route_ioctl(unsigned int cmd, void __user *arg) |
1496 | { | 1693 | { |
1694 | struct fib6_config cfg; | ||
1497 | struct in6_rtmsg rtmsg; | 1695 | struct in6_rtmsg rtmsg; |
1498 | int err; | 1696 | int err; |
1499 | 1697 | ||
@@ -1506,14 +1704,16 @@ int ipv6_route_ioctl(unsigned int cmd, void __user *arg) | |||
1506 | sizeof(struct in6_rtmsg)); | 1704 | sizeof(struct in6_rtmsg)); |
1507 | if (err) | 1705 | if (err) |
1508 | return -EFAULT; | 1706 | return -EFAULT; |
1509 | 1707 | ||
1708 | rtmsg_to_fib6_config(&rtmsg, &cfg); | ||
1709 | |||
1510 | rtnl_lock(); | 1710 | rtnl_lock(); |
1511 | switch (cmd) { | 1711 | switch (cmd) { |
1512 | case SIOCADDRT: | 1712 | case SIOCADDRT: |
1513 | err = ip6_route_add(&rtmsg, NULL, NULL, NULL); | 1713 | err = ip6_route_add(&cfg); |
1514 | break; | 1714 | break; |
1515 | case SIOCDELRT: | 1715 | case SIOCDELRT: |
1516 | err = ip6_route_del(&rtmsg, NULL, NULL, NULL); | 1716 | err = ip6_route_del(&cfg); |
1517 | break; | 1717 | break; |
1518 | default: | 1718 | default: |
1519 | err = -EINVAL; | 1719 | err = -EINVAL; |
@@ -1587,6 +1787,7 @@ struct rt6_info *addrconf_dst_alloc(struct inet6_dev *idev, | |||
1587 | 1787 | ||
1588 | ipv6_addr_copy(&rt->rt6i_dst.addr, addr); | 1788 | ipv6_addr_copy(&rt->rt6i_dst.addr, addr); |
1589 | rt->rt6i_dst.plen = 128; | 1789 | rt->rt6i_dst.plen = 128; |
1790 | rt->rt6i_table = fib6_get_table(RT6_TABLE_LOCAL); | ||
1590 | 1791 | ||
1591 | atomic_set(&rt->u.dst.__refcnt, 1); | 1792 | atomic_set(&rt->u.dst.__refcnt, 1); |
1592 | 1793 | ||
@@ -1605,9 +1806,7 @@ static int fib6_ifdown(struct rt6_info *rt, void *arg) | |||
1605 | 1806 | ||
1606 | void rt6_ifdown(struct net_device *dev) | 1807 | void rt6_ifdown(struct net_device *dev) |
1607 | { | 1808 | { |
1608 | write_lock_bh(&rt6_lock); | 1809 | fib6_clean_all(fib6_ifdown, 0, dev); |
1609 | fib6_clean_tree(&ip6_routing_table, fib6_ifdown, 0, dev); | ||
1610 | write_unlock_bh(&rt6_lock); | ||
1611 | } | 1810 | } |
1612 | 1811 | ||
1613 | struct rt6_mtu_change_arg | 1812 | struct rt6_mtu_change_arg |
@@ -1657,80 +1856,114 @@ static int rt6_mtu_change_route(struct rt6_info *rt, void *p_arg) | |||
1657 | 1856 | ||
1658 | void rt6_mtu_change(struct net_device *dev, unsigned mtu) | 1857 | void rt6_mtu_change(struct net_device *dev, unsigned mtu) |
1659 | { | 1858 | { |
1660 | struct rt6_mtu_change_arg arg; | 1859 | struct rt6_mtu_change_arg arg = { |
1860 | .dev = dev, | ||
1861 | .mtu = mtu, | ||
1862 | }; | ||
1661 | 1863 | ||
1662 | arg.dev = dev; | 1864 | fib6_clean_all(rt6_mtu_change_route, 0, &arg); |
1663 | arg.mtu = mtu; | ||
1664 | read_lock_bh(&rt6_lock); | ||
1665 | fib6_clean_tree(&ip6_routing_table, rt6_mtu_change_route, 0, &arg); | ||
1666 | read_unlock_bh(&rt6_lock); | ||
1667 | } | 1865 | } |
1668 | 1866 | ||
1669 | static int inet6_rtm_to_rtmsg(struct rtmsg *r, struct rtattr **rta, | 1867 | static struct nla_policy rtm_ipv6_policy[RTA_MAX+1] __read_mostly = { |
1670 | struct in6_rtmsg *rtmsg) | 1868 | [RTA_GATEWAY] = { .len = sizeof(struct in6_addr) }, |
1869 | [RTA_OIF] = { .type = NLA_U32 }, | ||
1870 | [RTA_IIF] = { .type = NLA_U32 }, | ||
1871 | [RTA_PRIORITY] = { .type = NLA_U32 }, | ||
1872 | [RTA_METRICS] = { .type = NLA_NESTED }, | ||
1873 | }; | ||
1874 | |||
1875 | static int rtm_to_fib6_config(struct sk_buff *skb, struct nlmsghdr *nlh, | ||
1876 | struct fib6_config *cfg) | ||
1671 | { | 1877 | { |
1672 | memset(rtmsg, 0, sizeof(*rtmsg)); | 1878 | struct rtmsg *rtm; |
1879 | struct nlattr *tb[RTA_MAX+1]; | ||
1880 | int err; | ||
1673 | 1881 | ||
1674 | rtmsg->rtmsg_dst_len = r->rtm_dst_len; | 1882 | err = nlmsg_parse(nlh, sizeof(*rtm), tb, RTA_MAX, rtm_ipv6_policy); |
1675 | rtmsg->rtmsg_src_len = r->rtm_src_len; | 1883 | if (err < 0) |
1676 | rtmsg->rtmsg_flags = RTF_UP; | 1884 | goto errout; |
1677 | if (r->rtm_type == RTN_UNREACHABLE) | ||
1678 | rtmsg->rtmsg_flags |= RTF_REJECT; | ||
1679 | 1885 | ||
1680 | if (rta[RTA_GATEWAY-1]) { | 1886 | err = -EINVAL; |
1681 | if (rta[RTA_GATEWAY-1]->rta_len != RTA_LENGTH(16)) | 1887 | rtm = nlmsg_data(nlh); |
1682 | return -EINVAL; | 1888 | memset(cfg, 0, sizeof(*cfg)); |
1683 | memcpy(&rtmsg->rtmsg_gateway, RTA_DATA(rta[RTA_GATEWAY-1]), 16); | 1889 | |
1684 | rtmsg->rtmsg_flags |= RTF_GATEWAY; | 1890 | cfg->fc_table = rtm->rtm_table; |
1685 | } | 1891 | cfg->fc_dst_len = rtm->rtm_dst_len; |
1686 | if (rta[RTA_DST-1]) { | 1892 | cfg->fc_src_len = rtm->rtm_src_len; |
1687 | if (RTA_PAYLOAD(rta[RTA_DST-1]) < ((r->rtm_dst_len+7)>>3)) | 1893 | cfg->fc_flags = RTF_UP; |
1688 | return -EINVAL; | 1894 | cfg->fc_protocol = rtm->rtm_protocol; |
1689 | memcpy(&rtmsg->rtmsg_dst, RTA_DATA(rta[RTA_DST-1]), ((r->rtm_dst_len+7)>>3)); | 1895 | |
1896 | if (rtm->rtm_type == RTN_UNREACHABLE) | ||
1897 | cfg->fc_flags |= RTF_REJECT; | ||
1898 | |||
1899 | cfg->fc_nlinfo.pid = NETLINK_CB(skb).pid; | ||
1900 | cfg->fc_nlinfo.nlh = nlh; | ||
1901 | |||
1902 | if (tb[RTA_GATEWAY]) { | ||
1903 | nla_memcpy(&cfg->fc_gateway, tb[RTA_GATEWAY], 16); | ||
1904 | cfg->fc_flags |= RTF_GATEWAY; | ||
1690 | } | 1905 | } |
1691 | if (rta[RTA_SRC-1]) { | 1906 | |
1692 | if (RTA_PAYLOAD(rta[RTA_SRC-1]) < ((r->rtm_src_len+7)>>3)) | 1907 | if (tb[RTA_DST]) { |
1693 | return -EINVAL; | 1908 | int plen = (rtm->rtm_dst_len + 7) >> 3; |
1694 | memcpy(&rtmsg->rtmsg_src, RTA_DATA(rta[RTA_SRC-1]), ((r->rtm_src_len+7)>>3)); | 1909 | |
1910 | if (nla_len(tb[RTA_DST]) < plen) | ||
1911 | goto errout; | ||
1912 | |||
1913 | nla_memcpy(&cfg->fc_dst, tb[RTA_DST], plen); | ||
1695 | } | 1914 | } |
1696 | if (rta[RTA_OIF-1]) { | 1915 | |
1697 | if (rta[RTA_OIF-1]->rta_len != RTA_LENGTH(sizeof(int))) | 1916 | if (tb[RTA_SRC]) { |
1698 | return -EINVAL; | 1917 | int plen = (rtm->rtm_src_len + 7) >> 3; |
1699 | memcpy(&rtmsg->rtmsg_ifindex, RTA_DATA(rta[RTA_OIF-1]), sizeof(int)); | 1918 | |
1919 | if (nla_len(tb[RTA_SRC]) < plen) | ||
1920 | goto errout; | ||
1921 | |||
1922 | nla_memcpy(&cfg->fc_src, tb[RTA_SRC], plen); | ||
1700 | } | 1923 | } |
1701 | if (rta[RTA_PRIORITY-1]) { | 1924 | |
1702 | if (rta[RTA_PRIORITY-1]->rta_len != RTA_LENGTH(4)) | 1925 | if (tb[RTA_OIF]) |
1703 | return -EINVAL; | 1926 | cfg->fc_ifindex = nla_get_u32(tb[RTA_OIF]); |
1704 | memcpy(&rtmsg->rtmsg_metric, RTA_DATA(rta[RTA_PRIORITY-1]), 4); | 1927 | |
1928 | if (tb[RTA_PRIORITY]) | ||
1929 | cfg->fc_metric = nla_get_u32(tb[RTA_PRIORITY]); | ||
1930 | |||
1931 | if (tb[RTA_METRICS]) { | ||
1932 | cfg->fc_mx = nla_data(tb[RTA_METRICS]); | ||
1933 | cfg->fc_mx_len = nla_len(tb[RTA_METRICS]); | ||
1705 | } | 1934 | } |
1706 | return 0; | 1935 | |
1936 | if (tb[RTA_TABLE]) | ||
1937 | cfg->fc_table = nla_get_u32(tb[RTA_TABLE]); | ||
1938 | |||
1939 | err = 0; | ||
1940 | errout: | ||
1941 | return err; | ||
1707 | } | 1942 | } |
1708 | 1943 | ||
1709 | int inet6_rtm_delroute(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg) | 1944 | int inet6_rtm_delroute(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg) |
1710 | { | 1945 | { |
1711 | struct rtmsg *r = NLMSG_DATA(nlh); | 1946 | struct fib6_config cfg; |
1712 | struct in6_rtmsg rtmsg; | 1947 | int err; |
1713 | 1948 | ||
1714 | if (inet6_rtm_to_rtmsg(r, arg, &rtmsg)) | 1949 | err = rtm_to_fib6_config(skb, nlh, &cfg); |
1715 | return -EINVAL; | 1950 | if (err < 0) |
1716 | return ip6_route_del(&rtmsg, nlh, arg, &NETLINK_CB(skb)); | 1951 | return err; |
1952 | |||
1953 | return ip6_route_del(&cfg); | ||
1717 | } | 1954 | } |
1718 | 1955 | ||
1719 | int inet6_rtm_newroute(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg) | 1956 | int inet6_rtm_newroute(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg) |
1720 | { | 1957 | { |
1721 | struct rtmsg *r = NLMSG_DATA(nlh); | 1958 | struct fib6_config cfg; |
1722 | struct in6_rtmsg rtmsg; | 1959 | int err; |
1723 | 1960 | ||
1724 | if (inet6_rtm_to_rtmsg(r, arg, &rtmsg)) | 1961 | err = rtm_to_fib6_config(skb, nlh, &cfg); |
1725 | return -EINVAL; | 1962 | if (err < 0) |
1726 | return ip6_route_add(&rtmsg, nlh, arg, &NETLINK_CB(skb)); | 1963 | return err; |
1727 | } | ||
1728 | 1964 | ||
1729 | struct rt6_rtnl_dump_arg | 1965 | return ip6_route_add(&cfg); |
1730 | { | 1966 | } |
1731 | struct sk_buff *skb; | ||
1732 | struct netlink_callback *cb; | ||
1733 | }; | ||
1734 | 1967 | ||
1735 | static int rt6_fill_node(struct sk_buff *skb, struct rt6_info *rt, | 1968 | static int rt6_fill_node(struct sk_buff *skb, struct rt6_info *rt, |
1736 | struct in6_addr *dst, struct in6_addr *src, | 1969 | struct in6_addr *dst, struct in6_addr *src, |
@@ -1738,9 +1971,9 @@ static int rt6_fill_node(struct sk_buff *skb, struct rt6_info *rt, | |||
1738 | int prefix, unsigned int flags) | 1971 | int prefix, unsigned int flags) |
1739 | { | 1972 | { |
1740 | struct rtmsg *rtm; | 1973 | struct rtmsg *rtm; |
1741 | struct nlmsghdr *nlh; | 1974 | struct nlmsghdr *nlh; |
1742 | unsigned char *b = skb->tail; | ||
1743 | struct rta_cacheinfo ci; | 1975 | struct rta_cacheinfo ci; |
1976 | u32 table; | ||
1744 | 1977 | ||
1745 | if (prefix) { /* user wants prefix routes only */ | 1978 | if (prefix) { /* user wants prefix routes only */ |
1746 | if (!(rt->rt6i_flags & RTF_PREFIX_RT)) { | 1979 | if (!(rt->rt6i_flags & RTF_PREFIX_RT)) { |
@@ -1749,13 +1982,21 @@ static int rt6_fill_node(struct sk_buff *skb, struct rt6_info *rt, | |||
1749 | } | 1982 | } |
1750 | } | 1983 | } |
1751 | 1984 | ||
1752 | nlh = NLMSG_NEW(skb, pid, seq, type, sizeof(*rtm), flags); | 1985 | nlh = nlmsg_put(skb, pid, seq, type, sizeof(*rtm), flags); |
1753 | rtm = NLMSG_DATA(nlh); | 1986 | if (nlh == NULL) |
1987 | return -ENOBUFS; | ||
1988 | |||
1989 | rtm = nlmsg_data(nlh); | ||
1754 | rtm->rtm_family = AF_INET6; | 1990 | rtm->rtm_family = AF_INET6; |
1755 | rtm->rtm_dst_len = rt->rt6i_dst.plen; | 1991 | rtm->rtm_dst_len = rt->rt6i_dst.plen; |
1756 | rtm->rtm_src_len = rt->rt6i_src.plen; | 1992 | rtm->rtm_src_len = rt->rt6i_src.plen; |
1757 | rtm->rtm_tos = 0; | 1993 | rtm->rtm_tos = 0; |
1758 | rtm->rtm_table = RT_TABLE_MAIN; | 1994 | if (rt->rt6i_table) |
1995 | table = rt->rt6i_table->tb6_id; | ||
1996 | else | ||
1997 | table = RT6_TABLE_UNSPEC; | ||
1998 | rtm->rtm_table = table; | ||
1999 | NLA_PUT_U32(skb, RTA_TABLE, table); | ||
1759 | if (rt->rt6i_flags&RTF_REJECT) | 2000 | if (rt->rt6i_flags&RTF_REJECT) |
1760 | rtm->rtm_type = RTN_UNREACHABLE; | 2001 | rtm->rtm_type = RTN_UNREACHABLE; |
1761 | else if (rt->rt6i_dev && (rt->rt6i_dev->flags&IFF_LOOPBACK)) | 2002 | else if (rt->rt6i_dev && (rt->rt6i_dev->flags&IFF_LOOPBACK)) |
@@ -1776,31 +2017,35 @@ static int rt6_fill_node(struct sk_buff *skb, struct rt6_info *rt, | |||
1776 | rtm->rtm_flags |= RTM_F_CLONED; | 2017 | rtm->rtm_flags |= RTM_F_CLONED; |
1777 | 2018 | ||
1778 | if (dst) { | 2019 | if (dst) { |
1779 | RTA_PUT(skb, RTA_DST, 16, dst); | 2020 | NLA_PUT(skb, RTA_DST, 16, dst); |
1780 | rtm->rtm_dst_len = 128; | 2021 | rtm->rtm_dst_len = 128; |
1781 | } else if (rtm->rtm_dst_len) | 2022 | } else if (rtm->rtm_dst_len) |
1782 | RTA_PUT(skb, RTA_DST, 16, &rt->rt6i_dst.addr); | 2023 | NLA_PUT(skb, RTA_DST, 16, &rt->rt6i_dst.addr); |
1783 | #ifdef CONFIG_IPV6_SUBTREES | 2024 | #ifdef CONFIG_IPV6_SUBTREES |
1784 | if (src) { | 2025 | if (src) { |
1785 | RTA_PUT(skb, RTA_SRC, 16, src); | 2026 | NLA_PUT(skb, RTA_SRC, 16, src); |
1786 | rtm->rtm_src_len = 128; | 2027 | rtm->rtm_src_len = 128; |
1787 | } else if (rtm->rtm_src_len) | 2028 | } else if (rtm->rtm_src_len) |
1788 | RTA_PUT(skb, RTA_SRC, 16, &rt->rt6i_src.addr); | 2029 | NLA_PUT(skb, RTA_SRC, 16, &rt->rt6i_src.addr); |
1789 | #endif | 2030 | #endif |
1790 | if (iif) | 2031 | if (iif) |
1791 | RTA_PUT(skb, RTA_IIF, 4, &iif); | 2032 | NLA_PUT_U32(skb, RTA_IIF, iif); |
1792 | else if (dst) { | 2033 | else if (dst) { |
1793 | struct in6_addr saddr_buf; | 2034 | struct in6_addr saddr_buf; |
1794 | if (ipv6_get_saddr(&rt->u.dst, dst, &saddr_buf) == 0) | 2035 | if (ipv6_get_saddr(&rt->u.dst, dst, &saddr_buf) == 0) |
1795 | RTA_PUT(skb, RTA_PREFSRC, 16, &saddr_buf); | 2036 | NLA_PUT(skb, RTA_PREFSRC, 16, &saddr_buf); |
1796 | } | 2037 | } |
2038 | |||
1797 | if (rtnetlink_put_metrics(skb, rt->u.dst.metrics) < 0) | 2039 | if (rtnetlink_put_metrics(skb, rt->u.dst.metrics) < 0) |
1798 | goto rtattr_failure; | 2040 | goto nla_put_failure; |
2041 | |||
1799 | if (rt->u.dst.neighbour) | 2042 | if (rt->u.dst.neighbour) |
1800 | RTA_PUT(skb, RTA_GATEWAY, 16, &rt->u.dst.neighbour->primary_key); | 2043 | NLA_PUT(skb, RTA_GATEWAY, 16, &rt->u.dst.neighbour->primary_key); |
2044 | |||
1801 | if (rt->u.dst.dev) | 2045 | if (rt->u.dst.dev) |
1802 | RTA_PUT(skb, RTA_OIF, sizeof(int), &rt->rt6i_dev->ifindex); | 2046 | NLA_PUT_U32(skb, RTA_OIF, rt->rt6i_dev->ifindex); |
1803 | RTA_PUT(skb, RTA_PRIORITY, 4, &rt->rt6i_metric); | 2047 | |
2048 | NLA_PUT_U32(skb, RTA_PRIORITY, rt->rt6i_metric); | ||
1804 | ci.rta_lastuse = jiffies_to_clock_t(jiffies - rt->u.dst.lastuse); | 2049 | ci.rta_lastuse = jiffies_to_clock_t(jiffies - rt->u.dst.lastuse); |
1805 | if (rt->rt6i_expires) | 2050 | if (rt->rt6i_expires) |
1806 | ci.rta_expires = jiffies_to_clock_t(rt->rt6i_expires - jiffies); | 2051 | ci.rta_expires = jiffies_to_clock_t(rt->rt6i_expires - jiffies); |
@@ -1812,23 +2057,21 @@ static int rt6_fill_node(struct sk_buff *skb, struct rt6_info *rt, | |||
1812 | ci.rta_id = 0; | 2057 | ci.rta_id = 0; |
1813 | ci.rta_ts = 0; | 2058 | ci.rta_ts = 0; |
1814 | ci.rta_tsage = 0; | 2059 | ci.rta_tsage = 0; |
1815 | RTA_PUT(skb, RTA_CACHEINFO, sizeof(ci), &ci); | 2060 | NLA_PUT(skb, RTA_CACHEINFO, sizeof(ci), &ci); |
1816 | nlh->nlmsg_len = skb->tail - b; | ||
1817 | return skb->len; | ||
1818 | 2061 | ||
1819 | nlmsg_failure: | 2062 | return nlmsg_end(skb, nlh); |
1820 | rtattr_failure: | 2063 | |
1821 | skb_trim(skb, b - skb->data); | 2064 | nla_put_failure: |
1822 | return -1; | 2065 | return nlmsg_cancel(skb, nlh); |
1823 | } | 2066 | } |
1824 | 2067 | ||
1825 | static int rt6_dump_route(struct rt6_info *rt, void *p_arg) | 2068 | int rt6_dump_route(struct rt6_info *rt, void *p_arg) |
1826 | { | 2069 | { |
1827 | struct rt6_rtnl_dump_arg *arg = (struct rt6_rtnl_dump_arg *) p_arg; | 2070 | struct rt6_rtnl_dump_arg *arg = (struct rt6_rtnl_dump_arg *) p_arg; |
1828 | int prefix; | 2071 | int prefix; |
1829 | 2072 | ||
1830 | if (arg->cb->nlh->nlmsg_len >= NLMSG_LENGTH(sizeof(struct rtmsg))) { | 2073 | if (nlmsg_len(arg->cb->nlh) >= sizeof(struct rtmsg)) { |
1831 | struct rtmsg *rtm = NLMSG_DATA(arg->cb->nlh); | 2074 | struct rtmsg *rtm = nlmsg_data(arg->cb->nlh); |
1832 | prefix = (rtm->rtm_flags & RTM_F_PREFIX) != 0; | 2075 | prefix = (rtm->rtm_flags & RTM_F_PREFIX) != 0; |
1833 | } else | 2076 | } else |
1834 | prefix = 0; | 2077 | prefix = 0; |
@@ -1838,189 +2081,108 @@ static int rt6_dump_route(struct rt6_info *rt, void *p_arg) | |||
1838 | prefix, NLM_F_MULTI); | 2081 | prefix, NLM_F_MULTI); |
1839 | } | 2082 | } |
1840 | 2083 | ||
1841 | static int fib6_dump_node(struct fib6_walker_t *w) | 2084 | int inet6_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr* nlh, void *arg) |
1842 | { | 2085 | { |
1843 | int res; | 2086 | struct nlattr *tb[RTA_MAX+1]; |
1844 | struct rt6_info *rt; | 2087 | struct rt6_info *rt; |
2088 | struct sk_buff *skb; | ||
2089 | struct rtmsg *rtm; | ||
2090 | struct flowi fl; | ||
2091 | int err, iif = 0; | ||
1845 | 2092 | ||
1846 | for (rt = w->leaf; rt; rt = rt->u.next) { | 2093 | err = nlmsg_parse(nlh, sizeof(*rtm), tb, RTA_MAX, rtm_ipv6_policy); |
1847 | res = rt6_dump_route(rt, w->args); | 2094 | if (err < 0) |
1848 | if (res < 0) { | 2095 | goto errout; |
1849 | /* Frame is full, suspend walking */ | ||
1850 | w->leaf = rt; | ||
1851 | return 1; | ||
1852 | } | ||
1853 | BUG_TRAP(res!=0); | ||
1854 | } | ||
1855 | w->leaf = NULL; | ||
1856 | return 0; | ||
1857 | } | ||
1858 | |||
1859 | static void fib6_dump_end(struct netlink_callback *cb) | ||
1860 | { | ||
1861 | struct fib6_walker_t *w = (void*)cb->args[0]; | ||
1862 | |||
1863 | if (w) { | ||
1864 | cb->args[0] = 0; | ||
1865 | fib6_walker_unlink(w); | ||
1866 | kfree(w); | ||
1867 | } | ||
1868 | cb->done = (void*)cb->args[1]; | ||
1869 | cb->args[1] = 0; | ||
1870 | } | ||
1871 | |||
1872 | static int fib6_dump_done(struct netlink_callback *cb) | ||
1873 | { | ||
1874 | fib6_dump_end(cb); | ||
1875 | return cb->done ? cb->done(cb) : 0; | ||
1876 | } | ||
1877 | |||
1878 | int inet6_dump_fib(struct sk_buff *skb, struct netlink_callback *cb) | ||
1879 | { | ||
1880 | struct rt6_rtnl_dump_arg arg; | ||
1881 | struct fib6_walker_t *w; | ||
1882 | int res; | ||
1883 | 2096 | ||
1884 | arg.skb = skb; | 2097 | err = -EINVAL; |
1885 | arg.cb = cb; | 2098 | memset(&fl, 0, sizeof(fl)); |
1886 | 2099 | ||
1887 | w = (void*)cb->args[0]; | 2100 | if (tb[RTA_SRC]) { |
1888 | if (w == NULL) { | 2101 | if (nla_len(tb[RTA_SRC]) < sizeof(struct in6_addr)) |
1889 | /* New dump: | 2102 | goto errout; |
1890 | * | ||
1891 | * 1. hook callback destructor. | ||
1892 | */ | ||
1893 | cb->args[1] = (long)cb->done; | ||
1894 | cb->done = fib6_dump_done; | ||
1895 | 2103 | ||
1896 | /* | 2104 | ipv6_addr_copy(&fl.fl6_src, nla_data(tb[RTA_SRC])); |
1897 | * 2. allocate and initialize walker. | ||
1898 | */ | ||
1899 | w = kzalloc(sizeof(*w), GFP_ATOMIC); | ||
1900 | if (w == NULL) | ||
1901 | return -ENOMEM; | ||
1902 | RT6_TRACE("dump<%p", w); | ||
1903 | w->root = &ip6_routing_table; | ||
1904 | w->func = fib6_dump_node; | ||
1905 | w->args = &arg; | ||
1906 | cb->args[0] = (long)w; | ||
1907 | read_lock_bh(&rt6_lock); | ||
1908 | res = fib6_walk(w); | ||
1909 | read_unlock_bh(&rt6_lock); | ||
1910 | } else { | ||
1911 | w->args = &arg; | ||
1912 | read_lock_bh(&rt6_lock); | ||
1913 | res = fib6_walk_continue(w); | ||
1914 | read_unlock_bh(&rt6_lock); | ||
1915 | } | 2105 | } |
1916 | #if RT6_DEBUG >= 3 | ||
1917 | if (res <= 0 && skb->len == 0) | ||
1918 | RT6_TRACE("%p>dump end\n", w); | ||
1919 | #endif | ||
1920 | res = res < 0 ? res : skb->len; | ||
1921 | /* res < 0 is an error. (really, impossible) | ||
1922 | res == 0 means that dump is complete, but skb still can contain data. | ||
1923 | res > 0 dump is not complete, but frame is full. | ||
1924 | */ | ||
1925 | /* Destroy walker, if dump of this table is complete. */ | ||
1926 | if (res <= 0) | ||
1927 | fib6_dump_end(cb); | ||
1928 | return res; | ||
1929 | } | ||
1930 | |||
1931 | int inet6_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr* nlh, void *arg) | ||
1932 | { | ||
1933 | struct rtattr **rta = arg; | ||
1934 | int iif = 0; | ||
1935 | int err = -ENOBUFS; | ||
1936 | struct sk_buff *skb; | ||
1937 | struct flowi fl; | ||
1938 | struct rt6_info *rt; | ||
1939 | 2106 | ||
1940 | skb = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL); | 2107 | if (tb[RTA_DST]) { |
1941 | if (skb == NULL) | 2108 | if (nla_len(tb[RTA_DST]) < sizeof(struct in6_addr)) |
1942 | goto out; | 2109 | goto errout; |
1943 | 2110 | ||
1944 | /* Reserve room for dummy headers, this skb can pass | 2111 | ipv6_addr_copy(&fl.fl6_dst, nla_data(tb[RTA_DST])); |
1945 | through good chunk of routing engine. | 2112 | } |
1946 | */ | ||
1947 | skb->mac.raw = skb->data; | ||
1948 | skb_reserve(skb, MAX_HEADER + sizeof(struct ipv6hdr)); | ||
1949 | 2113 | ||
1950 | memset(&fl, 0, sizeof(fl)); | 2114 | if (tb[RTA_IIF]) |
1951 | if (rta[RTA_SRC-1]) | 2115 | iif = nla_get_u32(tb[RTA_IIF]); |
1952 | ipv6_addr_copy(&fl.fl6_src, | ||
1953 | (struct in6_addr*)RTA_DATA(rta[RTA_SRC-1])); | ||
1954 | if (rta[RTA_DST-1]) | ||
1955 | ipv6_addr_copy(&fl.fl6_dst, | ||
1956 | (struct in6_addr*)RTA_DATA(rta[RTA_DST-1])); | ||
1957 | 2116 | ||
1958 | if (rta[RTA_IIF-1]) | 2117 | if (tb[RTA_OIF]) |
1959 | memcpy(&iif, RTA_DATA(rta[RTA_IIF-1]), sizeof(int)); | 2118 | fl.oif = nla_get_u32(tb[RTA_OIF]); |
1960 | 2119 | ||
1961 | if (iif) { | 2120 | if (iif) { |
1962 | struct net_device *dev; | 2121 | struct net_device *dev; |
1963 | dev = __dev_get_by_index(iif); | 2122 | dev = __dev_get_by_index(iif); |
1964 | if (!dev) { | 2123 | if (!dev) { |
1965 | err = -ENODEV; | 2124 | err = -ENODEV; |
1966 | goto out_free; | 2125 | goto errout; |
1967 | } | 2126 | } |
1968 | } | 2127 | } |
1969 | 2128 | ||
1970 | fl.oif = 0; | 2129 | skb = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL); |
1971 | if (rta[RTA_OIF-1]) | 2130 | if (skb == NULL) { |
1972 | memcpy(&fl.oif, RTA_DATA(rta[RTA_OIF-1]), sizeof(int)); | 2131 | err = -ENOBUFS; |
2132 | goto errout; | ||
2133 | } | ||
1973 | 2134 | ||
1974 | rt = (struct rt6_info*)ip6_route_output(NULL, &fl); | 2135 | /* Reserve room for dummy headers, this skb can pass |
2136 | through good chunk of routing engine. | ||
2137 | */ | ||
2138 | skb->mac.raw = skb->data; | ||
2139 | skb_reserve(skb, MAX_HEADER + sizeof(struct ipv6hdr)); | ||
1975 | 2140 | ||
2141 | rt = (struct rt6_info*) ip6_route_output(NULL, &fl); | ||
1976 | skb->dst = &rt->u.dst; | 2142 | skb->dst = &rt->u.dst; |
1977 | 2143 | ||
1978 | NETLINK_CB(skb).dst_pid = NETLINK_CB(in_skb).pid; | 2144 | err = rt6_fill_node(skb, rt, &fl.fl6_dst, &fl.fl6_src, iif, |
1979 | err = rt6_fill_node(skb, rt, | ||
1980 | &fl.fl6_dst, &fl.fl6_src, | ||
1981 | iif, | ||
1982 | RTM_NEWROUTE, NETLINK_CB(in_skb).pid, | 2145 | RTM_NEWROUTE, NETLINK_CB(in_skb).pid, |
1983 | nlh->nlmsg_seq, 0, 0); | 2146 | nlh->nlmsg_seq, 0, 0); |
1984 | if (err < 0) { | 2147 | if (err < 0) { |
1985 | err = -EMSGSIZE; | 2148 | kfree_skb(skb); |
1986 | goto out_free; | 2149 | goto errout; |
1987 | } | 2150 | } |
1988 | 2151 | ||
1989 | err = netlink_unicast(rtnl, skb, NETLINK_CB(in_skb).pid, MSG_DONTWAIT); | 2152 | err = rtnl_unicast(skb, NETLINK_CB(in_skb).pid); |
1990 | if (err > 0) | 2153 | errout: |
1991 | err = 0; | ||
1992 | out: | ||
1993 | return err; | 2154 | return err; |
1994 | out_free: | ||
1995 | kfree_skb(skb); | ||
1996 | goto out; | ||
1997 | } | 2155 | } |
1998 | 2156 | ||
1999 | void inet6_rt_notify(int event, struct rt6_info *rt, struct nlmsghdr *nlh, | 2157 | void inet6_rt_notify(int event, struct rt6_info *rt, struct nl_info *info) |
2000 | struct netlink_skb_parms *req) | ||
2001 | { | 2158 | { |
2002 | struct sk_buff *skb; | 2159 | struct sk_buff *skb; |
2003 | int size = NLMSG_SPACE(sizeof(struct rtmsg)+256); | 2160 | u32 pid = 0, seq = 0; |
2004 | u32 pid = current->pid; | 2161 | struct nlmsghdr *nlh = NULL; |
2005 | u32 seq = 0; | 2162 | int payload = sizeof(struct rtmsg) + 256; |
2006 | 2163 | int err = -ENOBUFS; | |
2007 | if (req) | 2164 | |
2008 | pid = req->pid; | 2165 | if (info) { |
2009 | if (nlh) | 2166 | pid = info->pid; |
2010 | seq = nlh->nlmsg_seq; | 2167 | nlh = info->nlh; |
2011 | 2168 | if (nlh) | |
2012 | skb = alloc_skb(size, gfp_any()); | 2169 | seq = nlh->nlmsg_seq; |
2013 | if (!skb) { | ||
2014 | netlink_set_err(rtnl, 0, RTNLGRP_IPV6_ROUTE, ENOBUFS); | ||
2015 | return; | ||
2016 | } | 2170 | } |
2017 | if (rt6_fill_node(skb, rt, NULL, NULL, 0, event, pid, seq, 0, 0) < 0) { | 2171 | |
2172 | skb = nlmsg_new(nlmsg_total_size(payload), gfp_any()); | ||
2173 | if (skb == NULL) | ||
2174 | goto errout; | ||
2175 | |||
2176 | err = rt6_fill_node(skb, rt, NULL, NULL, 0, event, pid, seq, 0, 0); | ||
2177 | if (err < 0) { | ||
2018 | kfree_skb(skb); | 2178 | kfree_skb(skb); |
2019 | netlink_set_err(rtnl, 0, RTNLGRP_IPV6_ROUTE, EINVAL); | 2179 | goto errout; |
2020 | return; | ||
2021 | } | 2180 | } |
2022 | NETLINK_CB(skb).dst_group = RTNLGRP_IPV6_ROUTE; | 2181 | |
2023 | netlink_broadcast(rtnl, skb, 0, RTNLGRP_IPV6_ROUTE, gfp_any()); | 2182 | err = rtnl_notify(skb, pid, RTNLGRP_IPV6_ROUTE, nlh, gfp_any()); |
2183 | errout: | ||
2184 | if (err < 0) | ||
2185 | rtnl_set_sk_err(RTNLGRP_IPV6_ROUTE, err); | ||
2024 | } | 2186 | } |
2025 | 2187 | ||
2026 | /* | 2188 | /* |
@@ -2096,16 +2258,13 @@ static int rt6_info_route(struct rt6_info *rt, void *p_arg) | |||
2096 | 2258 | ||
2097 | static int rt6_proc_info(char *buffer, char **start, off_t offset, int length) | 2259 | static int rt6_proc_info(char *buffer, char **start, off_t offset, int length) |
2098 | { | 2260 | { |
2099 | struct rt6_proc_arg arg; | 2261 | struct rt6_proc_arg arg = { |
2100 | arg.buffer = buffer; | 2262 | .buffer = buffer, |
2101 | arg.offset = offset; | 2263 | .offset = offset, |
2102 | arg.length = length; | 2264 | .length = length, |
2103 | arg.skip = 0; | 2265 | }; |
2104 | arg.len = 0; | ||
2105 | 2266 | ||
2106 | read_lock_bh(&rt6_lock); | 2267 | fib6_clean_all(rt6_info_route, 0, &arg); |
2107 | fib6_clean_tree(&ip6_routing_table, rt6_info_route, 0, &arg); | ||
2108 | read_unlock_bh(&rt6_lock); | ||
2109 | 2268 | ||
2110 | *start = buffer; | 2269 | *start = buffer; |
2111 | if (offset) | 2270 | if (offset) |
@@ -2260,13 +2419,9 @@ void __init ip6_route_init(void) | |||
2260 | { | 2419 | { |
2261 | struct proc_dir_entry *p; | 2420 | struct proc_dir_entry *p; |
2262 | 2421 | ||
2263 | ip6_dst_ops.kmem_cachep = kmem_cache_create("ip6_dst_cache", | 2422 | ip6_dst_ops.kmem_cachep = |
2264 | sizeof(struct rt6_info), | 2423 | kmem_cache_create("ip6_dst_cache", sizeof(struct rt6_info), 0, |
2265 | 0, SLAB_HWCACHE_ALIGN, | 2424 | SLAB_HWCACHE_ALIGN|SLAB_PANIC, NULL, NULL); |
2266 | NULL, NULL); | ||
2267 | if (!ip6_dst_ops.kmem_cachep) | ||
2268 | panic("cannot create ip6_dst_cache"); | ||
2269 | |||
2270 | fib6_init(); | 2425 | fib6_init(); |
2271 | #ifdef CONFIG_PROC_FS | 2426 | #ifdef CONFIG_PROC_FS |
2272 | p = proc_net_create("ipv6_route", 0, rt6_proc_info); | 2427 | p = proc_net_create("ipv6_route", 0, rt6_proc_info); |
@@ -2278,10 +2433,16 @@ void __init ip6_route_init(void) | |||
2278 | #ifdef CONFIG_XFRM | 2433 | #ifdef CONFIG_XFRM |
2279 | xfrm6_init(); | 2434 | xfrm6_init(); |
2280 | #endif | 2435 | #endif |
2436 | #ifdef CONFIG_IPV6_MULTIPLE_TABLES | ||
2437 | fib6_rules_init(); | ||
2438 | #endif | ||
2281 | } | 2439 | } |
2282 | 2440 | ||
2283 | void ip6_route_cleanup(void) | 2441 | void ip6_route_cleanup(void) |
2284 | { | 2442 | { |
2443 | #ifdef CONFIG_IPV6_MULTIPLE_TABLES | ||
2444 | fib6_rules_cleanup(); | ||
2445 | #endif | ||
2285 | #ifdef CONFIG_PROC_FS | 2446 | #ifdef CONFIG_PROC_FS |
2286 | proc_net_remove("ipv6_route"); | 2447 | proc_net_remove("ipv6_route"); |
2287 | proc_net_remove("rt6_stats"); | 2448 | proc_net_remove("rt6_stats"); |
diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c index 802a1a6b1037..2546fc9f0a78 100644 --- a/net/ipv6/tcp_ipv6.c +++ b/net/ipv6/tcp_ipv6.c | |||
@@ -251,6 +251,8 @@ static int tcp_v6_connect(struct sock *sk, struct sockaddr *uaddr, | |||
251 | final_p = &final; | 251 | final_p = &final; |
252 | } | 252 | } |
253 | 253 | ||
254 | security_sk_classify_flow(sk, &fl); | ||
255 | |||
254 | err = ip6_dst_lookup(sk, &dst, &fl); | 256 | err = ip6_dst_lookup(sk, &dst, &fl); |
255 | if (err) | 257 | if (err) |
256 | goto failure; | 258 | goto failure; |
@@ -270,7 +272,7 @@ static int tcp_v6_connect(struct sock *sk, struct sockaddr *uaddr, | |||
270 | inet->rcv_saddr = LOOPBACK4_IPV6; | 272 | inet->rcv_saddr = LOOPBACK4_IPV6; |
271 | 273 | ||
272 | sk->sk_gso_type = SKB_GSO_TCPV6; | 274 | sk->sk_gso_type = SKB_GSO_TCPV6; |
273 | __ip6_dst_store(sk, dst, NULL); | 275 | __ip6_dst_store(sk, dst, NULL, NULL); |
274 | 276 | ||
275 | icsk->icsk_ext_hdr_len = 0; | 277 | icsk->icsk_ext_hdr_len = 0; |
276 | if (np->opt) | 278 | if (np->opt) |
@@ -374,6 +376,7 @@ static void tcp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, | |||
374 | fl.oif = sk->sk_bound_dev_if; | 376 | fl.oif = sk->sk_bound_dev_if; |
375 | fl.fl_ip_dport = inet->dport; | 377 | fl.fl_ip_dport = inet->dport; |
376 | fl.fl_ip_sport = inet->sport; | 378 | fl.fl_ip_sport = inet->sport; |
379 | security_skb_classify_flow(skb, &fl); | ||
377 | 380 | ||
378 | if ((err = ip6_dst_lookup(sk, &dst, &fl))) { | 381 | if ((err = ip6_dst_lookup(sk, &dst, &fl))) { |
379 | sk->sk_err_soft = -err; | 382 | sk->sk_err_soft = -err; |
@@ -467,6 +470,7 @@ static int tcp_v6_send_synack(struct sock *sk, struct request_sock *req, | |||
467 | fl.oif = treq->iif; | 470 | fl.oif = treq->iif; |
468 | fl.fl_ip_dport = inet_rsk(req)->rmt_port; | 471 | fl.fl_ip_dport = inet_rsk(req)->rmt_port; |
469 | fl.fl_ip_sport = inet_sk(sk)->sport; | 472 | fl.fl_ip_sport = inet_sk(sk)->sport; |
473 | security_req_classify_flow(req, &fl); | ||
470 | 474 | ||
471 | if (dst == NULL) { | 475 | if (dst == NULL) { |
472 | opt = np->opt; | 476 | opt = np->opt; |
@@ -541,7 +545,7 @@ static void tcp_v6_send_check(struct sock *sk, int len, struct sk_buff *skb) | |||
541 | struct ipv6_pinfo *np = inet6_sk(sk); | 545 | struct ipv6_pinfo *np = inet6_sk(sk); |
542 | struct tcphdr *th = skb->h.th; | 546 | struct tcphdr *th = skb->h.th; |
543 | 547 | ||
544 | if (skb->ip_summed == CHECKSUM_HW) { | 548 | if (skb->ip_summed == CHECKSUM_PARTIAL) { |
545 | th->check = ~csum_ipv6_magic(&np->saddr, &np->daddr, len, IPPROTO_TCP, 0); | 549 | th->check = ~csum_ipv6_magic(&np->saddr, &np->daddr, len, IPPROTO_TCP, 0); |
546 | skb->csum = offsetof(struct tcphdr, check); | 550 | skb->csum = offsetof(struct tcphdr, check); |
547 | } else { | 551 | } else { |
@@ -566,7 +570,7 @@ static int tcp_v6_gso_send_check(struct sk_buff *skb) | |||
566 | th->check = ~csum_ipv6_magic(&ipv6h->saddr, &ipv6h->daddr, skb->len, | 570 | th->check = ~csum_ipv6_magic(&ipv6h->saddr, &ipv6h->daddr, skb->len, |
567 | IPPROTO_TCP, 0); | 571 | IPPROTO_TCP, 0); |
568 | skb->csum = offsetof(struct tcphdr, check); | 572 | skb->csum = offsetof(struct tcphdr, check); |
569 | skb->ip_summed = CHECKSUM_HW; | 573 | skb->ip_summed = CHECKSUM_PARTIAL; |
570 | return 0; | 574 | return 0; |
571 | } | 575 | } |
572 | 576 | ||
@@ -625,6 +629,7 @@ static void tcp_v6_send_reset(struct sk_buff *skb) | |||
625 | fl.oif = inet6_iif(skb); | 629 | fl.oif = inet6_iif(skb); |
626 | fl.fl_ip_dport = t1->dest; | 630 | fl.fl_ip_dport = t1->dest; |
627 | fl.fl_ip_sport = t1->source; | 631 | fl.fl_ip_sport = t1->source; |
632 | security_skb_classify_flow(skb, &fl); | ||
628 | 633 | ||
629 | /* sk = NULL, but it is safe for now. RST socket required. */ | 634 | /* sk = NULL, but it is safe for now. RST socket required. */ |
630 | if (!ip6_dst_lookup(NULL, &buff->dst, &fl)) { | 635 | if (!ip6_dst_lookup(NULL, &buff->dst, &fl)) { |
@@ -691,6 +696,7 @@ static void tcp_v6_send_ack(struct sk_buff *skb, u32 seq, u32 ack, u32 win, u32 | |||
691 | fl.oif = inet6_iif(skb); | 696 | fl.oif = inet6_iif(skb); |
692 | fl.fl_ip_dport = t1->dest; | 697 | fl.fl_ip_dport = t1->dest; |
693 | fl.fl_ip_sport = t1->source; | 698 | fl.fl_ip_sport = t1->source; |
699 | security_skb_classify_flow(skb, &fl); | ||
694 | 700 | ||
695 | if (!ip6_dst_lookup(NULL, &buff->dst, &fl)) { | 701 | if (!ip6_dst_lookup(NULL, &buff->dst, &fl)) { |
696 | if (xfrm_lookup(&buff->dst, &fl, NULL, 0) >= 0) { | 702 | if (xfrm_lookup(&buff->dst, &fl, NULL, 0) >= 0) { |
@@ -820,6 +826,8 @@ static int tcp_v6_conn_request(struct sock *sk, struct sk_buff *skb) | |||
820 | 826 | ||
821 | tcp_rsk(req)->snt_isn = isn; | 827 | tcp_rsk(req)->snt_isn = isn; |
822 | 828 | ||
829 | security_inet_conn_request(sk, skb, req); | ||
830 | |||
823 | if (tcp_v6_send_synack(sk, req, NULL)) | 831 | if (tcp_v6_send_synack(sk, req, NULL)) |
824 | goto drop; | 832 | goto drop; |
825 | 833 | ||
@@ -923,6 +931,7 @@ static struct sock * tcp_v6_syn_recv_sock(struct sock *sk, struct sk_buff *skb, | |||
923 | fl.oif = sk->sk_bound_dev_if; | 931 | fl.oif = sk->sk_bound_dev_if; |
924 | fl.fl_ip_dport = inet_rsk(req)->rmt_port; | 932 | fl.fl_ip_dport = inet_rsk(req)->rmt_port; |
925 | fl.fl_ip_sport = inet_sk(sk)->sport; | 933 | fl.fl_ip_sport = inet_sk(sk)->sport; |
934 | security_req_classify_flow(req, &fl); | ||
926 | 935 | ||
927 | if (ip6_dst_lookup(sk, &dst, &fl)) | 936 | if (ip6_dst_lookup(sk, &dst, &fl)) |
928 | goto out; | 937 | goto out; |
@@ -945,7 +954,7 @@ static struct sock * tcp_v6_syn_recv_sock(struct sock *sk, struct sk_buff *skb, | |||
945 | */ | 954 | */ |
946 | 955 | ||
947 | newsk->sk_gso_type = SKB_GSO_TCPV6; | 956 | newsk->sk_gso_type = SKB_GSO_TCPV6; |
948 | __ip6_dst_store(newsk, dst, NULL); | 957 | __ip6_dst_store(newsk, dst, NULL, NULL); |
949 | 958 | ||
950 | newtcp6sk = (struct tcp6_sock *)newsk; | 959 | newtcp6sk = (struct tcp6_sock *)newsk; |
951 | inet_sk(newsk)->pinet6 = &newtcp6sk->inet6; | 960 | inet_sk(newsk)->pinet6 = &newtcp6sk->inet6; |
@@ -1024,7 +1033,7 @@ out: | |||
1024 | 1033 | ||
1025 | static int tcp_v6_checksum_init(struct sk_buff *skb) | 1034 | static int tcp_v6_checksum_init(struct sk_buff *skb) |
1026 | { | 1035 | { |
1027 | if (skb->ip_summed == CHECKSUM_HW) { | 1036 | if (skb->ip_summed == CHECKSUM_COMPLETE) { |
1028 | if (!tcp_v6_check(skb->h.th,skb->len,&skb->nh.ipv6h->saddr, | 1037 | if (!tcp_v6_check(skb->h.th,skb->len,&skb->nh.ipv6h->saddr, |
1029 | &skb->nh.ipv6h->daddr,skb->csum)) { | 1038 | &skb->nh.ipv6h->daddr,skb->csum)) { |
1030 | skb->ip_summed = CHECKSUM_UNNECESSARY; | 1039 | skb->ip_summed = CHECKSUM_UNNECESSARY; |
@@ -1066,7 +1075,7 @@ static int tcp_v6_do_rcv(struct sock *sk, struct sk_buff *skb) | |||
1066 | if (skb->protocol == htons(ETH_P_IP)) | 1075 | if (skb->protocol == htons(ETH_P_IP)) |
1067 | return tcp_v4_do_rcv(sk, skb); | 1076 | return tcp_v4_do_rcv(sk, skb); |
1068 | 1077 | ||
1069 | if (sk_filter(sk, skb, 0)) | 1078 | if (sk_filter(sk, skb)) |
1070 | goto discard; | 1079 | goto discard; |
1071 | 1080 | ||
1072 | /* | 1081 | /* |
@@ -1223,7 +1232,7 @@ process: | |||
1223 | if (!xfrm6_policy_check(sk, XFRM_POLICY_IN, skb)) | 1232 | if (!xfrm6_policy_check(sk, XFRM_POLICY_IN, skb)) |
1224 | goto discard_and_relse; | 1233 | goto discard_and_relse; |
1225 | 1234 | ||
1226 | if (sk_filter(sk, skb, 0)) | 1235 | if (sk_filter(sk, skb)) |
1227 | goto discard_and_relse; | 1236 | goto discard_and_relse; |
1228 | 1237 | ||
1229 | skb->dev = NULL; | 1238 | skb->dev = NULL; |
diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c index 3d54f246411e..9662561701d1 100644 --- a/net/ipv6/udp.c +++ b/net/ipv6/udp.c | |||
@@ -61,81 +61,9 @@ | |||
61 | 61 | ||
62 | DEFINE_SNMP_STAT(struct udp_mib, udp_stats_in6) __read_mostly; | 62 | DEFINE_SNMP_STAT(struct udp_mib, udp_stats_in6) __read_mostly; |
63 | 63 | ||
64 | /* Grrr, addr_type already calculated by caller, but I don't want | 64 | static inline int udp_v6_get_port(struct sock *sk, unsigned short snum) |
65 | * to add some silly "cookie" argument to this method just for that. | ||
66 | */ | ||
67 | static int udp_v6_get_port(struct sock *sk, unsigned short snum) | ||
68 | { | 65 | { |
69 | struct sock *sk2; | 66 | return udp_get_port(sk, snum, ipv6_rcv_saddr_equal); |
70 | struct hlist_node *node; | ||
71 | |||
72 | write_lock_bh(&udp_hash_lock); | ||
73 | if (snum == 0) { | ||
74 | int best_size_so_far, best, result, i; | ||
75 | |||
76 | if (udp_port_rover > sysctl_local_port_range[1] || | ||
77 | udp_port_rover < sysctl_local_port_range[0]) | ||
78 | udp_port_rover = sysctl_local_port_range[0]; | ||
79 | best_size_so_far = 32767; | ||
80 | best = result = udp_port_rover; | ||
81 | for (i = 0; i < UDP_HTABLE_SIZE; i++, result++) { | ||
82 | int size; | ||
83 | struct hlist_head *list; | ||
84 | |||
85 | list = &udp_hash[result & (UDP_HTABLE_SIZE - 1)]; | ||
86 | if (hlist_empty(list)) { | ||
87 | if (result > sysctl_local_port_range[1]) | ||
88 | result = sysctl_local_port_range[0] + | ||
89 | ((result - sysctl_local_port_range[0]) & | ||
90 | (UDP_HTABLE_SIZE - 1)); | ||
91 | goto gotit; | ||
92 | } | ||
93 | size = 0; | ||
94 | sk_for_each(sk2, node, list) | ||
95 | if (++size >= best_size_so_far) | ||
96 | goto next; | ||
97 | best_size_so_far = size; | ||
98 | best = result; | ||
99 | next:; | ||
100 | } | ||
101 | result = best; | ||
102 | for(i = 0; i < (1 << 16) / UDP_HTABLE_SIZE; i++, result += UDP_HTABLE_SIZE) { | ||
103 | if (result > sysctl_local_port_range[1]) | ||
104 | result = sysctl_local_port_range[0] | ||
105 | + ((result - sysctl_local_port_range[0]) & | ||
106 | (UDP_HTABLE_SIZE - 1)); | ||
107 | if (!udp_lport_inuse(result)) | ||
108 | break; | ||
109 | } | ||
110 | if (i >= (1 << 16) / UDP_HTABLE_SIZE) | ||
111 | goto fail; | ||
112 | gotit: | ||
113 | udp_port_rover = snum = result; | ||
114 | } else { | ||
115 | sk_for_each(sk2, node, | ||
116 | &udp_hash[snum & (UDP_HTABLE_SIZE - 1)]) { | ||
117 | if (inet_sk(sk2)->num == snum && | ||
118 | sk2 != sk && | ||
119 | (!sk2->sk_bound_dev_if || | ||
120 | !sk->sk_bound_dev_if || | ||
121 | sk2->sk_bound_dev_if == sk->sk_bound_dev_if) && | ||
122 | (!sk2->sk_reuse || !sk->sk_reuse) && | ||
123 | ipv6_rcv_saddr_equal(sk, sk2)) | ||
124 | goto fail; | ||
125 | } | ||
126 | } | ||
127 | |||
128 | inet_sk(sk)->num = snum; | ||
129 | if (sk_unhashed(sk)) { | ||
130 | sk_add_node(sk, &udp_hash[snum & (UDP_HTABLE_SIZE - 1)]); | ||
131 | sock_prot_inc_use(sk->sk_prot); | ||
132 | } | ||
133 | write_unlock_bh(&udp_hash_lock); | ||
134 | return 0; | ||
135 | |||
136 | fail: | ||
137 | write_unlock_bh(&udp_hash_lock); | ||
138 | return 1; | ||
139 | } | 67 | } |
140 | 68 | ||
141 | static void udp_v6_hash(struct sock *sk) | 69 | static void udp_v6_hash(struct sock *sk) |
@@ -345,6 +273,8 @@ out: | |||
345 | 273 | ||
346 | static inline int udpv6_queue_rcv_skb(struct sock * sk, struct sk_buff *skb) | 274 | static inline int udpv6_queue_rcv_skb(struct sock * sk, struct sk_buff *skb) |
347 | { | 275 | { |
276 | int rc; | ||
277 | |||
348 | if (!xfrm6_policy_check(sk, XFRM_POLICY_IN, skb)) { | 278 | if (!xfrm6_policy_check(sk, XFRM_POLICY_IN, skb)) { |
349 | kfree_skb(skb); | 279 | kfree_skb(skb); |
350 | return -1; | 280 | return -1; |
@@ -356,7 +286,10 @@ static inline int udpv6_queue_rcv_skb(struct sock * sk, struct sk_buff *skb) | |||
356 | return 0; | 286 | return 0; |
357 | } | 287 | } |
358 | 288 | ||
359 | if (sock_queue_rcv_skb(sk,skb)<0) { | 289 | if ((rc = sock_queue_rcv_skb(sk,skb)) < 0) { |
290 | /* Note that an ENOMEM error is charged twice */ | ||
291 | if (rc == -ENOMEM) | ||
292 | UDP6_INC_STATS_BH(UDP_MIB_RCVBUFERRORS); | ||
360 | UDP6_INC_STATS_BH(UDP_MIB_INERRORS); | 293 | UDP6_INC_STATS_BH(UDP_MIB_INERRORS); |
361 | kfree_skb(skb); | 294 | kfree_skb(skb); |
362 | return 0; | 295 | return 0; |
@@ -475,7 +408,7 @@ static int udpv6_rcv(struct sk_buff **pskb) | |||
475 | uh = skb->h.uh; | 408 | uh = skb->h.uh; |
476 | } | 409 | } |
477 | 410 | ||
478 | if (skb->ip_summed == CHECKSUM_HW && | 411 | if (skb->ip_summed == CHECKSUM_COMPLETE && |
479 | !csum_ipv6_magic(saddr, daddr, ulen, IPPROTO_UDP, skb->csum)) | 412 | !csum_ipv6_magic(saddr, daddr, ulen, IPPROTO_UDP, skb->csum)) |
480 | skb->ip_summed = CHECKSUM_UNNECESSARY; | 413 | skb->ip_summed = CHECKSUM_UNNECESSARY; |
481 | 414 | ||
@@ -782,6 +715,8 @@ do_udp_sendmsg: | |||
782 | connected = 0; | 715 | connected = 0; |
783 | } | 716 | } |
784 | 717 | ||
718 | security_sk_classify_flow(sk, fl); | ||
719 | |||
785 | err = ip6_sk_dst_lookup(sk, &dst, fl); | 720 | err = ip6_sk_dst_lookup(sk, &dst, fl); |
786 | if (err) | 721 | if (err) |
787 | goto out; | 722 | goto out; |
@@ -840,7 +775,12 @@ do_append_data: | |||
840 | if (connected) { | 775 | if (connected) { |
841 | ip6_dst_store(sk, dst, | 776 | ip6_dst_store(sk, dst, |
842 | ipv6_addr_equal(&fl->fl6_dst, &np->daddr) ? | 777 | ipv6_addr_equal(&fl->fl6_dst, &np->daddr) ? |
843 | &np->daddr : NULL); | 778 | &np->daddr : NULL, |
779 | #ifdef CONFIG_IPV6_SUBTREES | ||
780 | ipv6_addr_equal(&fl->fl6_src, &np->saddr) ? | ||
781 | &np->saddr : | ||
782 | #endif | ||
783 | NULL); | ||
844 | } else { | 784 | } else { |
845 | dst_release(dst); | 785 | dst_release(dst); |
846 | } | 786 | } |
@@ -855,6 +795,16 @@ out: | |||
855 | UDP6_INC_STATS_USER(UDP_MIB_OUTDATAGRAMS); | 795 | UDP6_INC_STATS_USER(UDP_MIB_OUTDATAGRAMS); |
856 | return len; | 796 | return len; |
857 | } | 797 | } |
798 | /* | ||
799 | * ENOBUFS = no kernel mem, SOCK_NOSPACE = no sndbuf space. Reporting | ||
800 | * ENOBUFS might not be good (it's not tunable per se), but otherwise | ||
801 | * we don't have a good statistic (IpOutDiscards but it can be too many | ||
802 | * things). We could add another new stat but at least for now that | ||
803 | * seems like overkill. | ||
804 | */ | ||
805 | if (err == -ENOBUFS || test_bit(SOCK_NOSPACE, &sk->sk_socket->flags)) { | ||
806 | UDP6_INC_STATS_USER(UDP_MIB_SNDBUFERRORS); | ||
807 | } | ||
858 | return err; | 808 | return err; |
859 | 809 | ||
860 | do_confirm: | 810 | do_confirm: |
diff --git a/net/ipv6/xfrm6_input.c b/net/ipv6/xfrm6_input.c index 0405d74ff910..a40a05789013 100644 --- a/net/ipv6/xfrm6_input.c +++ b/net/ipv6/xfrm6_input.c | |||
@@ -72,7 +72,7 @@ int xfrm6_rcv_spi(struct sk_buff *skb, u32 spi) | |||
72 | if (x->mode->input(x, skb)) | 72 | if (x->mode->input(x, skb)) |
73 | goto drop; | 73 | goto drop; |
74 | 74 | ||
75 | if (x->props.mode) { /* XXX */ | 75 | if (x->props.mode == XFRM_MODE_TUNNEL) { /* XXX */ |
76 | decaps = 1; | 76 | decaps = 1; |
77 | break; | 77 | break; |
78 | } | 78 | } |
@@ -138,3 +138,111 @@ int xfrm6_rcv(struct sk_buff **pskb) | |||
138 | { | 138 | { |
139 | return xfrm6_rcv_spi(*pskb, 0); | 139 | return xfrm6_rcv_spi(*pskb, 0); |
140 | } | 140 | } |
141 | |||
142 | int xfrm6_input_addr(struct sk_buff *skb, xfrm_address_t *daddr, | ||
143 | xfrm_address_t *saddr, u8 proto) | ||
144 | { | ||
145 | struct xfrm_state *x = NULL; | ||
146 | int wildcard = 0; | ||
147 | struct in6_addr any; | ||
148 | xfrm_address_t *xany; | ||
149 | struct xfrm_state *xfrm_vec_one = NULL; | ||
150 | int nh = 0; | ||
151 | int i = 0; | ||
152 | |||
153 | ipv6_addr_set(&any, 0, 0, 0, 0); | ||
154 | xany = (xfrm_address_t *)&any; | ||
155 | |||
156 | for (i = 0; i < 3; i++) { | ||
157 | xfrm_address_t *dst, *src; | ||
158 | switch (i) { | ||
159 | case 0: | ||
160 | dst = daddr; | ||
161 | src = saddr; | ||
162 | break; | ||
163 | case 1: | ||
164 | /* lookup state with wild-card source address */ | ||
165 | wildcard = 1; | ||
166 | dst = daddr; | ||
167 | src = xany; | ||
168 | break; | ||
169 | case 2: | ||
170 | default: | ||
171 | /* lookup state with wild-card addresses */ | ||
172 | wildcard = 1; /* XXX */ | ||
173 | dst = xany; | ||
174 | src = xany; | ||
175 | break; | ||
176 | } | ||
177 | |||
178 | x = xfrm_state_lookup_byaddr(dst, src, proto, AF_INET6); | ||
179 | if (!x) | ||
180 | continue; | ||
181 | |||
182 | spin_lock(&x->lock); | ||
183 | |||
184 | if (wildcard) { | ||
185 | if ((x->props.flags & XFRM_STATE_WILDRECV) == 0) { | ||
186 | spin_unlock(&x->lock); | ||
187 | xfrm_state_put(x); | ||
188 | x = NULL; | ||
189 | continue; | ||
190 | } | ||
191 | } | ||
192 | |||
193 | if (unlikely(x->km.state != XFRM_STATE_VALID)) { | ||
194 | spin_unlock(&x->lock); | ||
195 | xfrm_state_put(x); | ||
196 | x = NULL; | ||
197 | continue; | ||
198 | } | ||
199 | if (xfrm_state_check_expire(x)) { | ||
200 | spin_unlock(&x->lock); | ||
201 | xfrm_state_put(x); | ||
202 | x = NULL; | ||
203 | continue; | ||
204 | } | ||
205 | |||
206 | nh = x->type->input(x, skb); | ||
207 | if (nh <= 0) { | ||
208 | spin_unlock(&x->lock); | ||
209 | xfrm_state_put(x); | ||
210 | x = NULL; | ||
211 | continue; | ||
212 | } | ||
213 | |||
214 | x->curlft.bytes += skb->len; | ||
215 | x->curlft.packets++; | ||
216 | |||
217 | spin_unlock(&x->lock); | ||
218 | |||
219 | xfrm_vec_one = x; | ||
220 | break; | ||
221 | } | ||
222 | |||
223 | if (!xfrm_vec_one) | ||
224 | goto drop; | ||
225 | |||
226 | /* Allocate new secpath or COW existing one. */ | ||
227 | if (!skb->sp || atomic_read(&skb->sp->refcnt) != 1) { | ||
228 | struct sec_path *sp; | ||
229 | sp = secpath_dup(skb->sp); | ||
230 | if (!sp) | ||
231 | goto drop; | ||
232 | if (skb->sp) | ||
233 | secpath_put(skb->sp); | ||
234 | skb->sp = sp; | ||
235 | } | ||
236 | |||
237 | if (1 + skb->sp->len > XFRM_MAX_DEPTH) | ||
238 | goto drop; | ||
239 | |||
240 | skb->sp->xvec[skb->sp->len] = xfrm_vec_one; | ||
241 | skb->sp->len ++; | ||
242 | |||
243 | return 1; | ||
244 | drop: | ||
245 | if (xfrm_vec_one) | ||
246 | xfrm_state_put(xfrm_vec_one); | ||
247 | return -1; | ||
248 | } | ||
diff --git a/net/ipv6/xfrm6_mode_ro.c b/net/ipv6/xfrm6_mode_ro.c new file mode 100644 index 000000000000..6031c16d46ca --- /dev/null +++ b/net/ipv6/xfrm6_mode_ro.c | |||
@@ -0,0 +1,93 @@ | |||
1 | /* | ||
2 | * xfrm6_mode_ro.c - Route optimization mode for IPv6. | ||
3 | * | ||
4 | * Copyright (C)2003-2006 Helsinki University of Technology | ||
5 | * Copyright (C)2003-2006 USAGI/WIDE Project | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License as published by | ||
9 | * the Free Software Foundation; either version 2 of the License, or | ||
10 | * (at your option) any later version. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, | ||
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | * GNU General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program; if not, write to the Free Software | ||
19 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
20 | */ | ||
21 | /* | ||
22 | * Authors: | ||
23 | * Noriaki TAKAMIYA @USAGI | ||
24 | * Masahide NAKAMURA @USAGI | ||
25 | */ | ||
26 | |||
27 | #include <linux/init.h> | ||
28 | #include <linux/kernel.h> | ||
29 | #include <linux/module.h> | ||
30 | #include <linux/skbuff.h> | ||
31 | #include <linux/stringify.h> | ||
32 | #include <net/ipv6.h> | ||
33 | #include <net/xfrm.h> | ||
34 | |||
35 | /* Add route optimization header space. | ||
36 | * | ||
37 | * The IP header and mutable extension headers will be moved forward to make | ||
38 | * space for the route optimization header. | ||
39 | * | ||
40 | * On exit, skb->h will be set to the start of the encapsulation header to be | ||
41 | * filled in by x->type->output and skb->nh will be set to the nextheader field | ||
42 | * of the extension header directly preceding the encapsulation header, or in | ||
43 | * its absence, that of the top IP header. The value of skb->data will always | ||
44 | * point to the top IP header. | ||
45 | */ | ||
46 | static int xfrm6_ro_output(struct xfrm_state *x, struct sk_buff *skb) | ||
47 | { | ||
48 | struct ipv6hdr *iph; | ||
49 | u8 *prevhdr; | ||
50 | int hdr_len; | ||
51 | |||
52 | skb_push(skb, x->props.header_len); | ||
53 | iph = skb->nh.ipv6h; | ||
54 | |||
55 | hdr_len = x->type->hdr_offset(x, skb, &prevhdr); | ||
56 | skb->nh.raw = prevhdr - x->props.header_len; | ||
57 | skb->h.raw = skb->data + hdr_len; | ||
58 | memmove(skb->data, iph, hdr_len); | ||
59 | return 0; | ||
60 | } | ||
61 | |||
62 | /* | ||
63 | * Do nothing about routing optimization header unlike IPsec. | ||
64 | */ | ||
65 | static int xfrm6_ro_input(struct xfrm_state *x, struct sk_buff *skb) | ||
66 | { | ||
67 | return 0; | ||
68 | } | ||
69 | |||
70 | static struct xfrm_mode xfrm6_ro_mode = { | ||
71 | .input = xfrm6_ro_input, | ||
72 | .output = xfrm6_ro_output, | ||
73 | .owner = THIS_MODULE, | ||
74 | .encap = XFRM_MODE_ROUTEOPTIMIZATION, | ||
75 | }; | ||
76 | |||
77 | static int __init xfrm6_ro_init(void) | ||
78 | { | ||
79 | return xfrm_register_mode(&xfrm6_ro_mode, AF_INET6); | ||
80 | } | ||
81 | |||
82 | static void __exit xfrm6_ro_exit(void) | ||
83 | { | ||
84 | int err; | ||
85 | |||
86 | err = xfrm_unregister_mode(&xfrm6_ro_mode, AF_INET6); | ||
87 | BUG_ON(err); | ||
88 | } | ||
89 | |||
90 | module_init(xfrm6_ro_init); | ||
91 | module_exit(xfrm6_ro_exit); | ||
92 | MODULE_LICENSE("GPL"); | ||
93 | MODULE_ALIAS_XFRM_MODE(AF_INET6, XFRM_MODE_ROUTEOPTIMIZATION); | ||
diff --git a/net/ipv6/xfrm6_mode_transport.c b/net/ipv6/xfrm6_mode_transport.c index 711d713e36d8..3a4b39b12bad 100644 --- a/net/ipv6/xfrm6_mode_transport.c +++ b/net/ipv6/xfrm6_mode_transport.c | |||
@@ -25,9 +25,8 @@ | |||
25 | * its absence, that of the top IP header. The value of skb->data will always | 25 | * its absence, that of the top IP header. The value of skb->data will always |
26 | * point to the top IP header. | 26 | * point to the top IP header. |
27 | */ | 27 | */ |
28 | static int xfrm6_transport_output(struct sk_buff *skb) | 28 | static int xfrm6_transport_output(struct xfrm_state *x, struct sk_buff *skb) |
29 | { | 29 | { |
30 | struct xfrm_state *x = skb->dst->xfrm; | ||
31 | struct ipv6hdr *iph; | 30 | struct ipv6hdr *iph; |
32 | u8 *prevhdr; | 31 | u8 *prevhdr; |
33 | int hdr_len; | 32 | int hdr_len; |
@@ -35,7 +34,7 @@ static int xfrm6_transport_output(struct sk_buff *skb) | |||
35 | skb_push(skb, x->props.header_len); | 34 | skb_push(skb, x->props.header_len); |
36 | iph = skb->nh.ipv6h; | 35 | iph = skb->nh.ipv6h; |
37 | 36 | ||
38 | hdr_len = ip6_find_1stfragopt(skb, &prevhdr); | 37 | hdr_len = x->type->hdr_offset(x, skb, &prevhdr); |
39 | skb->nh.raw = prevhdr - x->props.header_len; | 38 | skb->nh.raw = prevhdr - x->props.header_len; |
40 | skb->h.raw = skb->data + hdr_len; | 39 | skb->h.raw = skb->data + hdr_len; |
41 | memmove(skb->data, iph, hdr_len); | 40 | memmove(skb->data, iph, hdr_len); |
diff --git a/net/ipv6/xfrm6_mode_tunnel.c b/net/ipv6/xfrm6_mode_tunnel.c index 8af79be2edca..5e7d8a7d6414 100644 --- a/net/ipv6/xfrm6_mode_tunnel.c +++ b/net/ipv6/xfrm6_mode_tunnel.c | |||
@@ -37,10 +37,9 @@ static inline void ipip6_ecn_decapsulate(struct sk_buff *skb) | |||
37 | * its absence, that of the top IP header. The value of skb->data will always | 37 | * its absence, that of the top IP header. The value of skb->data will always |
38 | * point to the top IP header. | 38 | * point to the top IP header. |
39 | */ | 39 | */ |
40 | static int xfrm6_tunnel_output(struct sk_buff *skb) | 40 | static int xfrm6_tunnel_output(struct xfrm_state *x, struct sk_buff *skb) |
41 | { | 41 | { |
42 | struct dst_entry *dst = skb->dst; | 42 | struct dst_entry *dst = skb->dst; |
43 | struct xfrm_state *x = dst->xfrm; | ||
44 | struct ipv6hdr *iph, *top_iph; | 43 | struct ipv6hdr *iph, *top_iph; |
45 | int dsfield; | 44 | int dsfield; |
46 | 45 | ||
diff --git a/net/ipv6/xfrm6_output.c b/net/ipv6/xfrm6_output.c index c8c8b44a0f58..c260ea104c52 100644 --- a/net/ipv6/xfrm6_output.c +++ b/net/ipv6/xfrm6_output.c | |||
@@ -17,6 +17,12 @@ | |||
17 | #include <net/ipv6.h> | 17 | #include <net/ipv6.h> |
18 | #include <net/xfrm.h> | 18 | #include <net/xfrm.h> |
19 | 19 | ||
20 | int xfrm6_find_1stfragopt(struct xfrm_state *x, struct sk_buff *skb, | ||
21 | u8 **prevhdr) | ||
22 | { | ||
23 | return ip6_find_1stfragopt(skb, prevhdr); | ||
24 | } | ||
25 | |||
20 | static int xfrm6_tunnel_check_size(struct sk_buff *skb) | 26 | static int xfrm6_tunnel_check_size(struct sk_buff *skb) |
21 | { | 27 | { |
22 | int mtu, ret = 0; | 28 | int mtu, ret = 0; |
@@ -41,13 +47,13 @@ static int xfrm6_output_one(struct sk_buff *skb) | |||
41 | struct xfrm_state *x = dst->xfrm; | 47 | struct xfrm_state *x = dst->xfrm; |
42 | int err; | 48 | int err; |
43 | 49 | ||
44 | if (skb->ip_summed == CHECKSUM_HW) { | 50 | if (skb->ip_summed == CHECKSUM_PARTIAL) { |
45 | err = skb_checksum_help(skb, 0); | 51 | err = skb_checksum_help(skb); |
46 | if (err) | 52 | if (err) |
47 | goto error_nolock; | 53 | goto error_nolock; |
48 | } | 54 | } |
49 | 55 | ||
50 | if (x->props.mode) { | 56 | if (x->props.mode == XFRM_MODE_TUNNEL) { |
51 | err = xfrm6_tunnel_check_size(skb); | 57 | err = xfrm6_tunnel_check_size(skb); |
52 | if (err) | 58 | if (err) |
53 | goto error_nolock; | 59 | goto error_nolock; |
@@ -59,7 +65,7 @@ static int xfrm6_output_one(struct sk_buff *skb) | |||
59 | if (err) | 65 | if (err) |
60 | goto error; | 66 | goto error; |
61 | 67 | ||
62 | err = x->mode->output(skb); | 68 | err = x->mode->output(x, skb); |
63 | if (err) | 69 | if (err) |
64 | goto error; | 70 | goto error; |
65 | 71 | ||
@@ -69,6 +75,8 @@ static int xfrm6_output_one(struct sk_buff *skb) | |||
69 | 75 | ||
70 | x->curlft.bytes += skb->len; | 76 | x->curlft.bytes += skb->len; |
71 | x->curlft.packets++; | 77 | x->curlft.packets++; |
78 | if (x->props.mode == XFRM_MODE_ROUTEOPTIMIZATION) | ||
79 | x->lastused = (u64)xtime.tv_sec; | ||
72 | 80 | ||
73 | spin_unlock_bh(&x->lock); | 81 | spin_unlock_bh(&x->lock); |
74 | 82 | ||
@@ -80,7 +88,7 @@ static int xfrm6_output_one(struct sk_buff *skb) | |||
80 | } | 88 | } |
81 | dst = skb->dst; | 89 | dst = skb->dst; |
82 | x = dst->xfrm; | 90 | x = dst->xfrm; |
83 | } while (x && !x->props.mode); | 91 | } while (x && (x->props.mode != XFRM_MODE_TUNNEL)); |
84 | 92 | ||
85 | IP6CB(skb)->flags |= IP6SKB_XFRM_TRANSFORMED; | 93 | IP6CB(skb)->flags |= IP6SKB_XFRM_TRANSFORMED; |
86 | err = 0; | 94 | err = 0; |
diff --git a/net/ipv6/xfrm6_policy.c b/net/ipv6/xfrm6_policy.c index 73cd250aecbb..6a252e2134d1 100644 --- a/net/ipv6/xfrm6_policy.c +++ b/net/ipv6/xfrm6_policy.c | |||
@@ -18,6 +18,9 @@ | |||
18 | #include <net/ip.h> | 18 | #include <net/ip.h> |
19 | #include <net/ipv6.h> | 19 | #include <net/ipv6.h> |
20 | #include <net/ip6_route.h> | 20 | #include <net/ip6_route.h> |
21 | #ifdef CONFIG_IPV6_MIP6 | ||
22 | #include <net/mip6.h> | ||
23 | #endif | ||
21 | 24 | ||
22 | static struct dst_ops xfrm6_dst_ops; | 25 | static struct dst_ops xfrm6_dst_ops; |
23 | static struct xfrm_policy_afinfo xfrm6_policy_afinfo; | 26 | static struct xfrm_policy_afinfo xfrm6_policy_afinfo; |
@@ -31,6 +34,26 @@ static int xfrm6_dst_lookup(struct xfrm_dst **dst, struct flowi *fl) | |||
31 | return err; | 34 | return err; |
32 | } | 35 | } |
33 | 36 | ||
37 | static int xfrm6_get_saddr(xfrm_address_t *saddr, xfrm_address_t *daddr) | ||
38 | { | ||
39 | struct rt6_info *rt; | ||
40 | struct flowi fl_tunnel = { | ||
41 | .nl_u = { | ||
42 | .ip6_u = { | ||
43 | .daddr = *(struct in6_addr *)&daddr->a6, | ||
44 | }, | ||
45 | }, | ||
46 | }; | ||
47 | |||
48 | if (!xfrm6_dst_lookup((struct xfrm_dst **)&rt, &fl_tunnel)) { | ||
49 | ipv6_get_saddr(&rt->u.dst, (struct in6_addr *)&daddr->a6, | ||
50 | (struct in6_addr *)&saddr->a6); | ||
51 | dst_release(&rt->u.dst); | ||
52 | return 0; | ||
53 | } | ||
54 | return -EHOSTUNREACH; | ||
55 | } | ||
56 | |||
34 | static struct dst_entry * | 57 | static struct dst_entry * |
35 | __xfrm6_find_bundle(struct flowi *fl, struct xfrm_policy *policy) | 58 | __xfrm6_find_bundle(struct flowi *fl, struct xfrm_policy *policy) |
36 | { | 59 | { |
@@ -50,7 +73,9 @@ __xfrm6_find_bundle(struct flowi *fl, struct xfrm_policy *policy) | |||
50 | xdst->u.rt6.rt6i_src.plen); | 73 | xdst->u.rt6.rt6i_src.plen); |
51 | if (ipv6_addr_equal(&xdst->u.rt6.rt6i_dst.addr, &fl_dst_prefix) && | 74 | if (ipv6_addr_equal(&xdst->u.rt6.rt6i_dst.addr, &fl_dst_prefix) && |
52 | ipv6_addr_equal(&xdst->u.rt6.rt6i_src.addr, &fl_src_prefix) && | 75 | ipv6_addr_equal(&xdst->u.rt6.rt6i_src.addr, &fl_src_prefix) && |
53 | xfrm_bundle_ok(xdst, fl, AF_INET6)) { | 76 | xfrm_bundle_ok(xdst, fl, AF_INET6, |
77 | (xdst->u.rt6.rt6i_dst.plen != 128 || | ||
78 | xdst->u.rt6.rt6i_src.plen != 128))) { | ||
54 | dst_clone(dst); | 79 | dst_clone(dst); |
55 | break; | 80 | break; |
56 | } | 81 | } |
@@ -59,6 +84,40 @@ __xfrm6_find_bundle(struct flowi *fl, struct xfrm_policy *policy) | |||
59 | return dst; | 84 | return dst; |
60 | } | 85 | } |
61 | 86 | ||
87 | static inline struct in6_addr* | ||
88 | __xfrm6_bundle_addr_remote(struct xfrm_state *x, struct in6_addr *addr) | ||
89 | { | ||
90 | return (x->type->remote_addr) ? | ||
91 | (struct in6_addr*)x->type->remote_addr(x, (xfrm_address_t *)addr) : | ||
92 | (struct in6_addr*)&x->id.daddr; | ||
93 | } | ||
94 | |||
95 | static inline struct in6_addr* | ||
96 | __xfrm6_bundle_addr_local(struct xfrm_state *x, struct in6_addr *addr) | ||
97 | { | ||
98 | return (x->type->local_addr) ? | ||
99 | (struct in6_addr*)x->type->local_addr(x, (xfrm_address_t *)addr) : | ||
100 | (struct in6_addr*)&x->props.saddr; | ||
101 | } | ||
102 | |||
103 | static inline void | ||
104 | __xfrm6_bundle_len_inc(int *len, int *nflen, struct xfrm_state *x) | ||
105 | { | ||
106 | if (x->type->flags & XFRM_TYPE_NON_FRAGMENT) | ||
107 | *nflen += x->props.header_len; | ||
108 | else | ||
109 | *len += x->props.header_len; | ||
110 | } | ||
111 | |||
112 | static inline void | ||
113 | __xfrm6_bundle_len_dec(int *len, int *nflen, struct xfrm_state *x) | ||
114 | { | ||
115 | if (x->type->flags & XFRM_TYPE_NON_FRAGMENT) | ||
116 | *nflen -= x->props.header_len; | ||
117 | else | ||
118 | *len -= x->props.header_len; | ||
119 | } | ||
120 | |||
62 | /* Allocate chain of dst_entry's, attach known xfrm's, calculate | 121 | /* Allocate chain of dst_entry's, attach known xfrm's, calculate |
63 | * all the metrics... Shortly, bundle a bundle. | 122 | * all the metrics... Shortly, bundle a bundle. |
64 | */ | 123 | */ |
@@ -83,6 +142,7 @@ __xfrm6_bundle_create(struct xfrm_policy *policy, struct xfrm_state **xfrm, int | |||
83 | int i; | 142 | int i; |
84 | int err = 0; | 143 | int err = 0; |
85 | int header_len = 0; | 144 | int header_len = 0; |
145 | int nfheader_len = 0; | ||
86 | int trailer_len = 0; | 146 | int trailer_len = 0; |
87 | 147 | ||
88 | dst = dst_prev = NULL; | 148 | dst = dst_prev = NULL; |
@@ -109,17 +169,18 @@ __xfrm6_bundle_create(struct xfrm_policy *policy, struct xfrm_state **xfrm, int | |||
109 | 169 | ||
110 | xdst = (struct xfrm_dst *)dst1; | 170 | xdst = (struct xfrm_dst *)dst1; |
111 | xdst->route = &rt->u.dst; | 171 | xdst->route = &rt->u.dst; |
172 | xdst->genid = xfrm[i]->genid; | ||
112 | if (rt->rt6i_node) | 173 | if (rt->rt6i_node) |
113 | xdst->route_cookie = rt->rt6i_node->fn_sernum; | 174 | xdst->route_cookie = rt->rt6i_node->fn_sernum; |
114 | 175 | ||
115 | dst1->next = dst_prev; | 176 | dst1->next = dst_prev; |
116 | dst_prev = dst1; | 177 | dst_prev = dst1; |
117 | if (xfrm[i]->props.mode) { | 178 | if (xfrm[i]->props.mode != XFRM_MODE_TRANSPORT) { |
118 | remote = (struct in6_addr*)&xfrm[i]->id.daddr; | 179 | remote = __xfrm6_bundle_addr_remote(xfrm[i], remote); |
119 | local = (struct in6_addr*)&xfrm[i]->props.saddr; | 180 | local = __xfrm6_bundle_addr_local(xfrm[i], local); |
120 | tunnel = 1; | 181 | tunnel = 1; |
121 | } | 182 | } |
122 | header_len += xfrm[i]->props.header_len; | 183 | __xfrm6_bundle_len_inc(&header_len, &nfheader_len, xfrm[i]); |
123 | trailer_len += xfrm[i]->props.trailer_len; | 184 | trailer_len += xfrm[i]->props.trailer_len; |
124 | 185 | ||
125 | if (tunnel) { | 186 | if (tunnel) { |
@@ -154,6 +215,7 @@ __xfrm6_bundle_create(struct xfrm_policy *policy, struct xfrm_state **xfrm, int | |||
154 | dst_prev->flags |= DST_HOST; | 215 | dst_prev->flags |= DST_HOST; |
155 | dst_prev->lastuse = jiffies; | 216 | dst_prev->lastuse = jiffies; |
156 | dst_prev->header_len = header_len; | 217 | dst_prev->header_len = header_len; |
218 | dst_prev->nfheader_len = nfheader_len; | ||
157 | dst_prev->trailer_len = trailer_len; | 219 | dst_prev->trailer_len = trailer_len; |
158 | memcpy(&dst_prev->metrics, &x->route->metrics, sizeof(dst_prev->metrics)); | 220 | memcpy(&dst_prev->metrics, &x->route->metrics, sizeof(dst_prev->metrics)); |
159 | 221 | ||
@@ -172,7 +234,7 @@ __xfrm6_bundle_create(struct xfrm_policy *policy, struct xfrm_state **xfrm, int | |||
172 | x->u.rt6.rt6i_src = rt0->rt6i_src; | 234 | x->u.rt6.rt6i_src = rt0->rt6i_src; |
173 | x->u.rt6.rt6i_idev = rt0->rt6i_idev; | 235 | x->u.rt6.rt6i_idev = rt0->rt6i_idev; |
174 | in6_dev_hold(rt0->rt6i_idev); | 236 | in6_dev_hold(rt0->rt6i_idev); |
175 | header_len -= x->u.dst.xfrm->props.header_len; | 237 | __xfrm6_bundle_len_dec(&header_len, &nfheader_len, x->u.dst.xfrm); |
176 | trailer_len -= x->u.dst.xfrm->props.trailer_len; | 238 | trailer_len -= x->u.dst.xfrm->props.trailer_len; |
177 | } | 239 | } |
178 | 240 | ||
@@ -232,6 +294,18 @@ _decode_session6(struct sk_buff *skb, struct flowi *fl) | |||
232 | fl->proto = nexthdr; | 294 | fl->proto = nexthdr; |
233 | return; | 295 | return; |
234 | 296 | ||
297 | #ifdef CONFIG_IPV6_MIP6 | ||
298 | case IPPROTO_MH: | ||
299 | if (pskb_may_pull(skb, skb->nh.raw + offset + 3 - skb->data)) { | ||
300 | struct ip6_mh *mh; | ||
301 | mh = (struct ip6_mh *)exthdr; | ||
302 | |||
303 | fl->fl_mh_type = mh->ip6mh_type; | ||
304 | } | ||
305 | fl->proto = nexthdr; | ||
306 | return; | ||
307 | #endif | ||
308 | |||
235 | /* XXX Why are there these headers? */ | 309 | /* XXX Why are there these headers? */ |
236 | case IPPROTO_AH: | 310 | case IPPROTO_AH: |
237 | case IPPROTO_ESP: | 311 | case IPPROTO_ESP: |
@@ -308,6 +382,7 @@ static struct xfrm_policy_afinfo xfrm6_policy_afinfo = { | |||
308 | .family = AF_INET6, | 382 | .family = AF_INET6, |
309 | .dst_ops = &xfrm6_dst_ops, | 383 | .dst_ops = &xfrm6_dst_ops, |
310 | .dst_lookup = xfrm6_dst_lookup, | 384 | .dst_lookup = xfrm6_dst_lookup, |
385 | .get_saddr = xfrm6_get_saddr, | ||
311 | .find_bundle = __xfrm6_find_bundle, | 386 | .find_bundle = __xfrm6_find_bundle, |
312 | .bundle_create = __xfrm6_bundle_create, | 387 | .bundle_create = __xfrm6_bundle_create, |
313 | .decode_session = _decode_session6, | 388 | .decode_session = _decode_session6, |
diff --git a/net/ipv6/xfrm6_state.c b/net/ipv6/xfrm6_state.c index b33296b3f6de..711bfafb2472 100644 --- a/net/ipv6/xfrm6_state.c +++ b/net/ipv6/xfrm6_state.c | |||
@@ -42,102 +42,135 @@ __xfrm6_init_tempsel(struct xfrm_state *x, struct flowi *fl, | |||
42 | memcpy(&x->props.saddr, &tmpl->saddr, sizeof(x->props.saddr)); | 42 | memcpy(&x->props.saddr, &tmpl->saddr, sizeof(x->props.saddr)); |
43 | if (ipv6_addr_any((struct in6_addr*)&x->props.saddr)) | 43 | if (ipv6_addr_any((struct in6_addr*)&x->props.saddr)) |
44 | memcpy(&x->props.saddr, saddr, sizeof(x->props.saddr)); | 44 | memcpy(&x->props.saddr, saddr, sizeof(x->props.saddr)); |
45 | if (tmpl->mode && ipv6_addr_any((struct in6_addr*)&x->props.saddr)) { | ||
46 | struct rt6_info *rt; | ||
47 | struct flowi fl_tunnel = { | ||
48 | .nl_u = { | ||
49 | .ip6_u = { | ||
50 | .daddr = *(struct in6_addr *)daddr, | ||
51 | } | ||
52 | } | ||
53 | }; | ||
54 | if (!xfrm_dst_lookup((struct xfrm_dst **)&rt, | ||
55 | &fl_tunnel, AF_INET6)) { | ||
56 | ipv6_get_saddr(&rt->u.dst, (struct in6_addr *)daddr, | ||
57 | (struct in6_addr *)&x->props.saddr); | ||
58 | dst_release(&rt->u.dst); | ||
59 | } | ||
60 | } | ||
61 | x->props.mode = tmpl->mode; | 45 | x->props.mode = tmpl->mode; |
62 | x->props.reqid = tmpl->reqid; | 46 | x->props.reqid = tmpl->reqid; |
63 | x->props.family = AF_INET6; | 47 | x->props.family = AF_INET6; |
64 | } | 48 | } |
65 | 49 | ||
66 | static struct xfrm_state * | 50 | static int |
67 | __xfrm6_state_lookup(xfrm_address_t *daddr, u32 spi, u8 proto) | 51 | __xfrm6_state_sort(struct xfrm_state **dst, struct xfrm_state **src, int n) |
68 | { | 52 | { |
69 | unsigned h = __xfrm6_spi_hash(daddr, spi, proto); | 53 | int i; |
70 | struct xfrm_state *x; | 54 | int j = 0; |
71 | 55 | ||
72 | list_for_each_entry(x, xfrm6_state_afinfo.state_byspi+h, byspi) { | 56 | /* Rule 1: select IPsec transport except AH */ |
73 | if (x->props.family == AF_INET6 && | 57 | for (i = 0; i < n; i++) { |
74 | spi == x->id.spi && | 58 | if (src[i]->props.mode == XFRM_MODE_TRANSPORT && |
75 | ipv6_addr_equal((struct in6_addr *)daddr, (struct in6_addr *)x->id.daddr.a6) && | 59 | src[i]->id.proto != IPPROTO_AH) { |
76 | proto == x->id.proto) { | 60 | dst[j++] = src[i]; |
77 | xfrm_state_hold(x); | 61 | src[i] = NULL; |
78 | return x; | 62 | } |
63 | } | ||
64 | if (j == n) | ||
65 | goto end; | ||
66 | |||
67 | /* Rule 2: select MIPv6 RO or inbound trigger */ | ||
68 | #ifdef CONFIG_IPV6_MIP6 | ||
69 | for (i = 0; i < n; i++) { | ||
70 | if (src[i] && | ||
71 | (src[i]->props.mode == XFRM_MODE_ROUTEOPTIMIZATION || | ||
72 | src[i]->props.mode == XFRM_MODE_IN_TRIGGER)) { | ||
73 | dst[j++] = src[i]; | ||
74 | src[i] = NULL; | ||
75 | } | ||
76 | } | ||
77 | if (j == n) | ||
78 | goto end; | ||
79 | #endif | ||
80 | |||
81 | /* Rule 3: select IPsec transport AH */ | ||
82 | for (i = 0; i < n; i++) { | ||
83 | if (src[i] && | ||
84 | src[i]->props.mode == XFRM_MODE_TRANSPORT && | ||
85 | src[i]->id.proto == IPPROTO_AH) { | ||
86 | dst[j++] = src[i]; | ||
87 | src[i] = NULL; | ||
79 | } | 88 | } |
80 | } | 89 | } |
81 | return NULL; | 90 | if (j == n) |
91 | goto end; | ||
92 | |||
93 | /* Rule 4: select IPsec tunnel */ | ||
94 | for (i = 0; i < n; i++) { | ||
95 | if (src[i] && | ||
96 | src[i]->props.mode == XFRM_MODE_TUNNEL) { | ||
97 | dst[j++] = src[i]; | ||
98 | src[i] = NULL; | ||
99 | } | ||
100 | } | ||
101 | if (likely(j == n)) | ||
102 | goto end; | ||
103 | |||
104 | /* Final rule */ | ||
105 | for (i = 0; i < n; i++) { | ||
106 | if (src[i]) { | ||
107 | dst[j++] = src[i]; | ||
108 | src[i] = NULL; | ||
109 | } | ||
110 | } | ||
111 | |||
112 | end: | ||
113 | return 0; | ||
82 | } | 114 | } |
83 | 115 | ||
84 | static struct xfrm_state * | 116 | static int |
85 | __xfrm6_find_acq(u8 mode, u32 reqid, u8 proto, | 117 | __xfrm6_tmpl_sort(struct xfrm_tmpl **dst, struct xfrm_tmpl **src, int n) |
86 | xfrm_address_t *daddr, xfrm_address_t *saddr, | ||
87 | int create) | ||
88 | { | 118 | { |
89 | struct xfrm_state *x, *x0; | 119 | int i; |
90 | unsigned h = __xfrm6_dst_hash(daddr); | 120 | int j = 0; |
91 | 121 | ||
92 | x0 = NULL; | 122 | /* Rule 1: select IPsec transport */ |
93 | 123 | for (i = 0; i < n; i++) { | |
94 | list_for_each_entry(x, xfrm6_state_afinfo.state_bydst+h, bydst) { | 124 | if (src[i]->mode == XFRM_MODE_TRANSPORT) { |
95 | if (x->props.family == AF_INET6 && | 125 | dst[j++] = src[i]; |
96 | ipv6_addr_equal((struct in6_addr *)daddr, (struct in6_addr *)x->id.daddr.a6) && | 126 | src[i] = NULL; |
97 | mode == x->props.mode && | 127 | } |
98 | proto == x->id.proto && | ||
99 | ipv6_addr_equal((struct in6_addr *)saddr, (struct in6_addr *)x->props.saddr.a6) && | ||
100 | reqid == x->props.reqid && | ||
101 | x->km.state == XFRM_STATE_ACQ && | ||
102 | !x->id.spi) { | ||
103 | x0 = x; | ||
104 | break; | ||
105 | } | ||
106 | } | 128 | } |
107 | if (!x0 && create && (x0 = xfrm_state_alloc()) != NULL) { | 129 | if (j == n) |
108 | ipv6_addr_copy((struct in6_addr *)x0->sel.daddr.a6, | 130 | goto end; |
109 | (struct in6_addr *)daddr); | 131 | |
110 | ipv6_addr_copy((struct in6_addr *)x0->sel.saddr.a6, | 132 | /* Rule 2: select MIPv6 RO or inbound trigger */ |
111 | (struct in6_addr *)saddr); | 133 | #ifdef CONFIG_IPV6_MIP6 |
112 | x0->sel.prefixlen_d = 128; | 134 | for (i = 0; i < n; i++) { |
113 | x0->sel.prefixlen_s = 128; | 135 | if (src[i] && |
114 | ipv6_addr_copy((struct in6_addr *)x0->props.saddr.a6, | 136 | (src[i]->mode == XFRM_MODE_ROUTEOPTIMIZATION || |
115 | (struct in6_addr *)saddr); | 137 | src[i]->mode == XFRM_MODE_IN_TRIGGER)) { |
116 | x0->km.state = XFRM_STATE_ACQ; | 138 | dst[j++] = src[i]; |
117 | ipv6_addr_copy((struct in6_addr *)x0->id.daddr.a6, | 139 | src[i] = NULL; |
118 | (struct in6_addr *)daddr); | 140 | } |
119 | x0->id.proto = proto; | ||
120 | x0->props.family = AF_INET6; | ||
121 | x0->props.mode = mode; | ||
122 | x0->props.reqid = reqid; | ||
123 | x0->lft.hard_add_expires_seconds = XFRM_ACQ_EXPIRES; | ||
124 | xfrm_state_hold(x0); | ||
125 | x0->timer.expires = jiffies + XFRM_ACQ_EXPIRES*HZ; | ||
126 | add_timer(&x0->timer); | ||
127 | xfrm_state_hold(x0); | ||
128 | list_add_tail(&x0->bydst, xfrm6_state_afinfo.state_bydst+h); | ||
129 | wake_up(&km_waitq); | ||
130 | } | 141 | } |
131 | if (x0) | 142 | if (j == n) |
132 | xfrm_state_hold(x0); | 143 | goto end; |
133 | return x0; | 144 | #endif |
145 | |||
146 | /* Rule 3: select IPsec tunnel */ | ||
147 | for (i = 0; i < n; i++) { | ||
148 | if (src[i] && | ||
149 | src[i]->mode == XFRM_MODE_TUNNEL) { | ||
150 | dst[j++] = src[i]; | ||
151 | src[i] = NULL; | ||
152 | } | ||
153 | } | ||
154 | if (likely(j == n)) | ||
155 | goto end; | ||
156 | |||
157 | /* Final rule */ | ||
158 | for (i = 0; i < n; i++) { | ||
159 | if (src[i]) { | ||
160 | dst[j++] = src[i]; | ||
161 | src[i] = NULL; | ||
162 | } | ||
163 | } | ||
164 | |||
165 | end: | ||
166 | return 0; | ||
134 | } | 167 | } |
135 | 168 | ||
136 | static struct xfrm_state_afinfo xfrm6_state_afinfo = { | 169 | static struct xfrm_state_afinfo xfrm6_state_afinfo = { |
137 | .family = AF_INET6, | 170 | .family = AF_INET6, |
138 | .init_tempsel = __xfrm6_init_tempsel, | 171 | .init_tempsel = __xfrm6_init_tempsel, |
139 | .state_lookup = __xfrm6_state_lookup, | 172 | .tmpl_sort = __xfrm6_tmpl_sort, |
140 | .find_acq = __xfrm6_find_acq, | 173 | .state_sort = __xfrm6_state_sort, |
141 | }; | 174 | }; |
142 | 175 | ||
143 | void __init xfrm6_state_init(void) | 176 | void __init xfrm6_state_init(void) |
diff --git a/net/ipv6/xfrm6_tunnel.c b/net/ipv6/xfrm6_tunnel.c index c8f9369c2a87..59685ee8f700 100644 --- a/net/ipv6/xfrm6_tunnel.c +++ b/net/ipv6/xfrm6_tunnel.c | |||
@@ -307,7 +307,7 @@ static int xfrm6_tunnel_err(struct sk_buff *skb, struct inet6_skb_parm *opt, | |||
307 | 307 | ||
308 | static int xfrm6_tunnel_init_state(struct xfrm_state *x) | 308 | static int xfrm6_tunnel_init_state(struct xfrm_state *x) |
309 | { | 309 | { |
310 | if (!x->props.mode) | 310 | if (x->props.mode != XFRM_MODE_TUNNEL) |
311 | return -EINVAL; | 311 | return -EINVAL; |
312 | 312 | ||
313 | if (x->encap) | 313 | if (x->encap) |
diff --git a/net/key/af_key.c b/net/key/af_key.c index 3a95b2ee4690..83b443ddc72f 100644 --- a/net/key/af_key.c +++ b/net/key/af_key.c | |||
@@ -1731,7 +1731,8 @@ static u32 gen_reqid(void) | |||
1731 | ++reqid; | 1731 | ++reqid; |
1732 | if (reqid == 0) | 1732 | if (reqid == 0) |
1733 | reqid = IPSEC_MANUAL_REQID_MAX+1; | 1733 | reqid = IPSEC_MANUAL_REQID_MAX+1; |
1734 | if (xfrm_policy_walk(check_reqid, (void*)&reqid) != -EEXIST) | 1734 | if (xfrm_policy_walk(XFRM_POLICY_TYPE_MAIN, check_reqid, |
1735 | (void*)&reqid) != -EEXIST) | ||
1735 | return reqid; | 1736 | return reqid; |
1736 | } while (reqid != start); | 1737 | } while (reqid != start); |
1737 | return 0; | 1738 | return 0; |
@@ -1765,7 +1766,7 @@ parse_ipsecrequest(struct xfrm_policy *xp, struct sadb_x_ipsecrequest *rq) | |||
1765 | } | 1766 | } |
1766 | 1767 | ||
1767 | /* addresses present only in tunnel mode */ | 1768 | /* addresses present only in tunnel mode */ |
1768 | if (t->mode) { | 1769 | if (t->mode == XFRM_MODE_TUNNEL) { |
1769 | switch (xp->family) { | 1770 | switch (xp->family) { |
1770 | case AF_INET: | 1771 | case AF_INET: |
1771 | sin = (void*)(rq+1); | 1772 | sin = (void*)(rq+1); |
@@ -1997,7 +1998,7 @@ static void pfkey_xfrm_policy2msg(struct sk_buff *skb, struct xfrm_policy *xp, i | |||
1997 | int req_size; | 1998 | int req_size; |
1998 | 1999 | ||
1999 | req_size = sizeof(struct sadb_x_ipsecrequest); | 2000 | req_size = sizeof(struct sadb_x_ipsecrequest); |
2000 | if (t->mode) | 2001 | if (t->mode == XFRM_MODE_TUNNEL) |
2001 | req_size += 2*socklen; | 2002 | req_size += 2*socklen; |
2002 | else | 2003 | else |
2003 | size -= 2*socklen; | 2004 | size -= 2*socklen; |
@@ -2013,7 +2014,7 @@ static void pfkey_xfrm_policy2msg(struct sk_buff *skb, struct xfrm_policy *xp, i | |||
2013 | if (t->optional) | 2014 | if (t->optional) |
2014 | rq->sadb_x_ipsecrequest_level = IPSEC_LEVEL_USE; | 2015 | rq->sadb_x_ipsecrequest_level = IPSEC_LEVEL_USE; |
2015 | rq->sadb_x_ipsecrequest_reqid = t->reqid; | 2016 | rq->sadb_x_ipsecrequest_reqid = t->reqid; |
2016 | if (t->mode) { | 2017 | if (t->mode == XFRM_MODE_TUNNEL) { |
2017 | switch (xp->family) { | 2018 | switch (xp->family) { |
2018 | case AF_INET: | 2019 | case AF_INET: |
2019 | sin = (void*)(rq+1); | 2020 | sin = (void*)(rq+1); |
@@ -2268,7 +2269,8 @@ static int pfkey_spddelete(struct sock *sk, struct sk_buff *skb, struct sadb_msg | |||
2268 | return err; | 2269 | return err; |
2269 | } | 2270 | } |
2270 | 2271 | ||
2271 | xp = xfrm_policy_bysel_ctx(pol->sadb_x_policy_dir-1, &sel, tmp.security, 1); | 2272 | xp = xfrm_policy_bysel_ctx(XFRM_POLICY_TYPE_MAIN, pol->sadb_x_policy_dir-1, |
2273 | &sel, tmp.security, 1); | ||
2272 | security_xfrm_policy_free(&tmp); | 2274 | security_xfrm_policy_free(&tmp); |
2273 | if (xp == NULL) | 2275 | if (xp == NULL) |
2274 | return -ENOENT; | 2276 | return -ENOENT; |
@@ -2330,7 +2332,7 @@ static int pfkey_spdget(struct sock *sk, struct sk_buff *skb, struct sadb_msg *h | |||
2330 | if (dir >= XFRM_POLICY_MAX) | 2332 | if (dir >= XFRM_POLICY_MAX) |
2331 | return -EINVAL; | 2333 | return -EINVAL; |
2332 | 2334 | ||
2333 | xp = xfrm_policy_byid(dir, pol->sadb_x_policy_id, | 2335 | xp = xfrm_policy_byid(XFRM_POLICY_TYPE_MAIN, dir, pol->sadb_x_policy_id, |
2334 | hdr->sadb_msg_type == SADB_X_SPDDELETE2); | 2336 | hdr->sadb_msg_type == SADB_X_SPDDELETE2); |
2335 | if (xp == NULL) | 2337 | if (xp == NULL) |
2336 | return -ENOENT; | 2338 | return -ENOENT; |
@@ -2378,7 +2380,7 @@ static int pfkey_spddump(struct sock *sk, struct sk_buff *skb, struct sadb_msg * | |||
2378 | { | 2380 | { |
2379 | struct pfkey_dump_data data = { .skb = skb, .hdr = hdr, .sk = sk }; | 2381 | struct pfkey_dump_data data = { .skb = skb, .hdr = hdr, .sk = sk }; |
2380 | 2382 | ||
2381 | return xfrm_policy_walk(dump_sp, &data); | 2383 | return xfrm_policy_walk(XFRM_POLICY_TYPE_MAIN, dump_sp, &data); |
2382 | } | 2384 | } |
2383 | 2385 | ||
2384 | static int key_notify_policy_flush(struct km_event *c) | 2386 | static int key_notify_policy_flush(struct km_event *c) |
@@ -2405,7 +2407,8 @@ static int pfkey_spdflush(struct sock *sk, struct sk_buff *skb, struct sadb_msg | |||
2405 | { | 2407 | { |
2406 | struct km_event c; | 2408 | struct km_event c; |
2407 | 2409 | ||
2408 | xfrm_policy_flush(); | 2410 | xfrm_policy_flush(XFRM_POLICY_TYPE_MAIN); |
2411 | c.data.type = XFRM_POLICY_TYPE_MAIN; | ||
2409 | c.event = XFRM_MSG_FLUSHPOLICY; | 2412 | c.event = XFRM_MSG_FLUSHPOLICY; |
2410 | c.pid = hdr->sadb_msg_pid; | 2413 | c.pid = hdr->sadb_msg_pid; |
2411 | c.seq = hdr->sadb_msg_seq; | 2414 | c.seq = hdr->sadb_msg_seq; |
@@ -2667,6 +2670,9 @@ static int pfkey_send_notify(struct xfrm_state *x, struct km_event *c) | |||
2667 | 2670 | ||
2668 | static int pfkey_send_policy_notify(struct xfrm_policy *xp, int dir, struct km_event *c) | 2671 | static int pfkey_send_policy_notify(struct xfrm_policy *xp, int dir, struct km_event *c) |
2669 | { | 2672 | { |
2673 | if (xp && xp->type != XFRM_POLICY_TYPE_MAIN) | ||
2674 | return 0; | ||
2675 | |||
2670 | switch (c->event) { | 2676 | switch (c->event) { |
2671 | case XFRM_MSG_POLEXPIRE: | 2677 | case XFRM_MSG_POLEXPIRE: |
2672 | return key_notify_policy_expire(xp, c); | 2678 | return key_notify_policy_expire(xp, c); |
@@ -2675,6 +2681,8 @@ static int pfkey_send_policy_notify(struct xfrm_policy *xp, int dir, struct km_e | |||
2675 | case XFRM_MSG_UPDPOLICY: | 2681 | case XFRM_MSG_UPDPOLICY: |
2676 | return key_notify_policy(xp, dir, c); | 2682 | return key_notify_policy(xp, dir, c); |
2677 | case XFRM_MSG_FLUSHPOLICY: | 2683 | case XFRM_MSG_FLUSHPOLICY: |
2684 | if (c->data.type != XFRM_POLICY_TYPE_MAIN) | ||
2685 | break; | ||
2678 | return key_notify_policy_flush(c); | 2686 | return key_notify_policy_flush(c); |
2679 | default: | 2687 | default: |
2680 | printk("pfkey: Unknown policy event %d\n", c->event); | 2688 | printk("pfkey: Unknown policy event %d\n", c->event); |
@@ -2708,6 +2716,9 @@ static int pfkey_send_acquire(struct xfrm_state *x, struct xfrm_tmpl *t, struct | |||
2708 | #endif | 2716 | #endif |
2709 | int sockaddr_size; | 2717 | int sockaddr_size; |
2710 | int size; | 2718 | int size; |
2719 | struct sadb_x_sec_ctx *sec_ctx; | ||
2720 | struct xfrm_sec_ctx *xfrm_ctx; | ||
2721 | int ctx_size = 0; | ||
2711 | 2722 | ||
2712 | sockaddr_size = pfkey_sockaddr_size(x->props.family); | 2723 | sockaddr_size = pfkey_sockaddr_size(x->props.family); |
2713 | if (!sockaddr_size) | 2724 | if (!sockaddr_size) |
@@ -2723,6 +2734,11 @@ static int pfkey_send_acquire(struct xfrm_state *x, struct xfrm_tmpl *t, struct | |||
2723 | else if (x->id.proto == IPPROTO_ESP) | 2734 | else if (x->id.proto == IPPROTO_ESP) |
2724 | size += count_esp_combs(t); | 2735 | size += count_esp_combs(t); |
2725 | 2736 | ||
2737 | if ((xfrm_ctx = x->security)) { | ||
2738 | ctx_size = PFKEY_ALIGN8(xfrm_ctx->ctx_len); | ||
2739 | size += sizeof(struct sadb_x_sec_ctx) + ctx_size; | ||
2740 | } | ||
2741 | |||
2726 | skb = alloc_skb(size + 16, GFP_ATOMIC); | 2742 | skb = alloc_skb(size + 16, GFP_ATOMIC); |
2727 | if (skb == NULL) | 2743 | if (skb == NULL) |
2728 | return -ENOMEM; | 2744 | return -ENOMEM; |
@@ -2818,17 +2834,31 @@ static int pfkey_send_acquire(struct xfrm_state *x, struct xfrm_tmpl *t, struct | |||
2818 | else if (x->id.proto == IPPROTO_ESP) | 2834 | else if (x->id.proto == IPPROTO_ESP) |
2819 | dump_esp_combs(skb, t); | 2835 | dump_esp_combs(skb, t); |
2820 | 2836 | ||
2837 | /* security context */ | ||
2838 | if (xfrm_ctx) { | ||
2839 | sec_ctx = (struct sadb_x_sec_ctx *) skb_put(skb, | ||
2840 | sizeof(struct sadb_x_sec_ctx) + ctx_size); | ||
2841 | sec_ctx->sadb_x_sec_len = | ||
2842 | (sizeof(struct sadb_x_sec_ctx) + ctx_size) / sizeof(uint64_t); | ||
2843 | sec_ctx->sadb_x_sec_exttype = SADB_X_EXT_SEC_CTX; | ||
2844 | sec_ctx->sadb_x_ctx_doi = xfrm_ctx->ctx_doi; | ||
2845 | sec_ctx->sadb_x_ctx_alg = xfrm_ctx->ctx_alg; | ||
2846 | sec_ctx->sadb_x_ctx_len = xfrm_ctx->ctx_len; | ||
2847 | memcpy(sec_ctx + 1, xfrm_ctx->ctx_str, | ||
2848 | xfrm_ctx->ctx_len); | ||
2849 | } | ||
2850 | |||
2821 | return pfkey_broadcast(skb, GFP_ATOMIC, BROADCAST_REGISTERED, NULL); | 2851 | return pfkey_broadcast(skb, GFP_ATOMIC, BROADCAST_REGISTERED, NULL); |
2822 | } | 2852 | } |
2823 | 2853 | ||
2824 | static struct xfrm_policy *pfkey_compile_policy(u16 family, int opt, | 2854 | static struct xfrm_policy *pfkey_compile_policy(struct sock *sk, int opt, |
2825 | u8 *data, int len, int *dir) | 2855 | u8 *data, int len, int *dir) |
2826 | { | 2856 | { |
2827 | struct xfrm_policy *xp; | 2857 | struct xfrm_policy *xp; |
2828 | struct sadb_x_policy *pol = (struct sadb_x_policy*)data; | 2858 | struct sadb_x_policy *pol = (struct sadb_x_policy*)data; |
2829 | struct sadb_x_sec_ctx *sec_ctx; | 2859 | struct sadb_x_sec_ctx *sec_ctx; |
2830 | 2860 | ||
2831 | switch (family) { | 2861 | switch (sk->sk_family) { |
2832 | case AF_INET: | 2862 | case AF_INET: |
2833 | if (opt != IP_IPSEC_POLICY) { | 2863 | if (opt != IP_IPSEC_POLICY) { |
2834 | *dir = -EOPNOTSUPP; | 2864 | *dir = -EOPNOTSUPP; |
@@ -2869,7 +2899,7 @@ static struct xfrm_policy *pfkey_compile_policy(u16 family, int opt, | |||
2869 | xp->lft.hard_byte_limit = XFRM_INF; | 2899 | xp->lft.hard_byte_limit = XFRM_INF; |
2870 | xp->lft.soft_packet_limit = XFRM_INF; | 2900 | xp->lft.soft_packet_limit = XFRM_INF; |
2871 | xp->lft.hard_packet_limit = XFRM_INF; | 2901 | xp->lft.hard_packet_limit = XFRM_INF; |
2872 | xp->family = family; | 2902 | xp->family = sk->sk_family; |
2873 | 2903 | ||
2874 | xp->xfrm_nr = 0; | 2904 | xp->xfrm_nr = 0; |
2875 | if (pol->sadb_x_policy_type == IPSEC_POLICY_IPSEC && | 2905 | if (pol->sadb_x_policy_type == IPSEC_POLICY_IPSEC && |
@@ -2885,8 +2915,10 @@ static struct xfrm_policy *pfkey_compile_policy(u16 family, int opt, | |||
2885 | p += pol->sadb_x_policy_len*8; | 2915 | p += pol->sadb_x_policy_len*8; |
2886 | sec_ctx = (struct sadb_x_sec_ctx *)p; | 2916 | sec_ctx = (struct sadb_x_sec_ctx *)p; |
2887 | if (len < pol->sadb_x_policy_len*8 + | 2917 | if (len < pol->sadb_x_policy_len*8 + |
2888 | sec_ctx->sadb_x_sec_len) | 2918 | sec_ctx->sadb_x_sec_len) { |
2919 | *dir = -EINVAL; | ||
2889 | goto out; | 2920 | goto out; |
2921 | } | ||
2890 | if ((*dir = verify_sec_ctx_len(p))) | 2922 | if ((*dir = verify_sec_ctx_len(p))) |
2891 | goto out; | 2923 | goto out; |
2892 | uctx = pfkey_sadb2xfrm_user_sec_ctx(sec_ctx); | 2924 | uctx = pfkey_sadb2xfrm_user_sec_ctx(sec_ctx); |
@@ -2896,6 +2928,11 @@ static struct xfrm_policy *pfkey_compile_policy(u16 family, int opt, | |||
2896 | if (*dir) | 2928 | if (*dir) |
2897 | goto out; | 2929 | goto out; |
2898 | } | 2930 | } |
2931 | else { | ||
2932 | *dir = security_xfrm_sock_policy_alloc(xp, sk); | ||
2933 | if (*dir) | ||
2934 | goto out; | ||
2935 | } | ||
2899 | 2936 | ||
2900 | *dir = pol->sadb_x_policy_dir-1; | 2937 | *dir = pol->sadb_x_policy_dir-1; |
2901 | return xp; | 2938 | return xp; |
diff --git a/net/netfilter/Kconfig b/net/netfilter/Kconfig index a9894ddfd72a..0a28d2c5c44f 100644 --- a/net/netfilter/Kconfig +++ b/net/netfilter/Kconfig | |||
@@ -148,6 +148,18 @@ config NETFILTER_XT_TARGET_CONNMARK | |||
148 | <file:Documentation/modules.txt>. The module will be called | 148 | <file:Documentation/modules.txt>. The module will be called |
149 | ipt_CONNMARK.o. If unsure, say `N'. | 149 | ipt_CONNMARK.o. If unsure, say `N'. |
150 | 150 | ||
151 | config NETFILTER_XT_TARGET_DSCP | ||
152 | tristate '"DSCP" target support' | ||
153 | depends on NETFILTER_XTABLES | ||
154 | depends on IP_NF_MANGLE || IP6_NF_MANGLE | ||
155 | help | ||
156 | This option adds a `DSCP' target, which allows you to manipulate | ||
157 | the IPv4/IPv6 header DSCP field (differentiated services codepoint). | ||
158 | |||
159 | The DSCP field can have any value between 0x0 and 0x3f inclusive. | ||
160 | |||
161 | To compile it as a module, choose M here. If unsure, say N. | ||
162 | |||
151 | config NETFILTER_XT_TARGET_MARK | 163 | config NETFILTER_XT_TARGET_MARK |
152 | tristate '"MARK" target support' | 164 | tristate '"MARK" target support' |
153 | depends on NETFILTER_XTABLES | 165 | depends on NETFILTER_XTABLES |
@@ -263,6 +275,17 @@ config NETFILTER_XT_MATCH_DCCP | |||
263 | If you want to compile it as a module, say M here and read | 275 | If you want to compile it as a module, say M here and read |
264 | <file:Documentation/modules.txt>. If unsure, say `N'. | 276 | <file:Documentation/modules.txt>. If unsure, say `N'. |
265 | 277 | ||
278 | config NETFILTER_XT_MATCH_DSCP | ||
279 | tristate '"DSCP" match support' | ||
280 | depends on NETFILTER_XTABLES | ||
281 | help | ||
282 | This option adds a `DSCP' match, which allows you to match against | ||
283 | the IPv4/IPv6 header DSCP field (differentiated services codepoint). | ||
284 | |||
285 | The DSCP field can have any value between 0x0 and 0x3f inclusive. | ||
286 | |||
287 | To compile it as a module, choose M here. If unsure, say N. | ||
288 | |||
266 | config NETFILTER_XT_MATCH_ESP | 289 | config NETFILTER_XT_MATCH_ESP |
267 | tristate '"ESP" match support' | 290 | tristate '"ESP" match support' |
268 | depends on NETFILTER_XTABLES | 291 | depends on NETFILTER_XTABLES |
diff --git a/net/netfilter/Makefile b/net/netfilter/Makefile index 6fa4b7580458..a74be492fd0a 100644 --- a/net/netfilter/Makefile +++ b/net/netfilter/Makefile | |||
@@ -25,6 +25,7 @@ obj-$(CONFIG_NETFILTER_XTABLES) += x_tables.o xt_tcpudp.o | |||
25 | # targets | 25 | # targets |
26 | obj-$(CONFIG_NETFILTER_XT_TARGET_CLASSIFY) += xt_CLASSIFY.o | 26 | obj-$(CONFIG_NETFILTER_XT_TARGET_CLASSIFY) += xt_CLASSIFY.o |
27 | obj-$(CONFIG_NETFILTER_XT_TARGET_CONNMARK) += xt_CONNMARK.o | 27 | obj-$(CONFIG_NETFILTER_XT_TARGET_CONNMARK) += xt_CONNMARK.o |
28 | obj-$(CONFIG_NETFILTER_XT_TARGET_DSCP) += xt_DSCP.o | ||
28 | obj-$(CONFIG_NETFILTER_XT_TARGET_MARK) += xt_MARK.o | 29 | obj-$(CONFIG_NETFILTER_XT_TARGET_MARK) += xt_MARK.o |
29 | obj-$(CONFIG_NETFILTER_XT_TARGET_NFQUEUE) += xt_NFQUEUE.o | 30 | obj-$(CONFIG_NETFILTER_XT_TARGET_NFQUEUE) += xt_NFQUEUE.o |
30 | obj-$(CONFIG_NETFILTER_XT_TARGET_NOTRACK) += xt_NOTRACK.o | 31 | obj-$(CONFIG_NETFILTER_XT_TARGET_NOTRACK) += xt_NOTRACK.o |
@@ -37,6 +38,7 @@ obj-$(CONFIG_NETFILTER_XT_MATCH_CONNBYTES) += xt_connbytes.o | |||
37 | obj-$(CONFIG_NETFILTER_XT_MATCH_CONNMARK) += xt_connmark.o | 38 | obj-$(CONFIG_NETFILTER_XT_MATCH_CONNMARK) += xt_connmark.o |
38 | obj-$(CONFIG_NETFILTER_XT_MATCH_CONNTRACK) += xt_conntrack.o | 39 | obj-$(CONFIG_NETFILTER_XT_MATCH_CONNTRACK) += xt_conntrack.o |
39 | obj-$(CONFIG_NETFILTER_XT_MATCH_DCCP) += xt_dccp.o | 40 | obj-$(CONFIG_NETFILTER_XT_MATCH_DCCP) += xt_dccp.o |
41 | obj-$(CONFIG_NETFILTER_XT_MATCH_DSCP) += xt_dscp.o | ||
40 | obj-$(CONFIG_NETFILTER_XT_MATCH_ESP) += xt_esp.o | 42 | obj-$(CONFIG_NETFILTER_XT_MATCH_ESP) += xt_esp.o |
41 | obj-$(CONFIG_NETFILTER_XT_MATCH_HELPER) += xt_helper.o | 43 | obj-$(CONFIG_NETFILTER_XT_MATCH_HELPER) += xt_helper.o |
42 | obj-$(CONFIG_NETFILTER_XT_MATCH_LENGTH) += xt_length.o | 44 | obj-$(CONFIG_NETFILTER_XT_MATCH_LENGTH) += xt_length.o |
diff --git a/net/netfilter/core.c b/net/netfilter/core.c index 5d29d5e23624..d80b935b3a92 100644 --- a/net/netfilter/core.c +++ b/net/netfilter/core.c | |||
@@ -182,7 +182,7 @@ next_hook: | |||
182 | ret = -EPERM; | 182 | ret = -EPERM; |
183 | } else if ((verdict & NF_VERDICT_MASK) == NF_QUEUE) { | 183 | } else if ((verdict & NF_VERDICT_MASK) == NF_QUEUE) { |
184 | NFDEBUG("nf_hook: Verdict = QUEUE.\n"); | 184 | NFDEBUG("nf_hook: Verdict = QUEUE.\n"); |
185 | if (!nf_queue(pskb, elem, pf, hook, indev, outdev, okfn, | 185 | if (!nf_queue(*pskb, elem, pf, hook, indev, outdev, okfn, |
186 | verdict >> NF_VERDICT_BITS)) | 186 | verdict >> NF_VERDICT_BITS)) |
187 | goto next_hook; | 187 | goto next_hook; |
188 | } | 188 | } |
@@ -222,6 +222,28 @@ copy_skb: | |||
222 | } | 222 | } |
223 | EXPORT_SYMBOL(skb_make_writable); | 223 | EXPORT_SYMBOL(skb_make_writable); |
224 | 224 | ||
225 | u_int16_t nf_csum_update(u_int32_t oldval, u_int32_t newval, u_int32_t csum) | ||
226 | { | ||
227 | u_int32_t diff[] = { oldval, newval }; | ||
228 | |||
229 | return csum_fold(csum_partial((char *)diff, sizeof(diff), ~csum)); | ||
230 | } | ||
231 | EXPORT_SYMBOL(nf_csum_update); | ||
232 | |||
233 | u_int16_t nf_proto_csum_update(struct sk_buff *skb, | ||
234 | u_int32_t oldval, u_int32_t newval, | ||
235 | u_int16_t csum, int pseudohdr) | ||
236 | { | ||
237 | if (skb->ip_summed != CHECKSUM_PARTIAL) { | ||
238 | csum = nf_csum_update(oldval, newval, csum); | ||
239 | if (skb->ip_summed == CHECKSUM_COMPLETE && pseudohdr) | ||
240 | skb->csum = nf_csum_update(oldval, newval, skb->csum); | ||
241 | } else if (pseudohdr) | ||
242 | csum = ~nf_csum_update(oldval, newval, ~csum); | ||
243 | |||
244 | return csum; | ||
245 | } | ||
246 | EXPORT_SYMBOL(nf_proto_csum_update); | ||
225 | 247 | ||
226 | /* This does not belong here, but locally generated errors need it if connection | 248 | /* This does not belong here, but locally generated errors need it if connection |
227 | tracking in use: without this, connection may not be in hash table, and hence | 249 | tracking in use: without this, connection may not be in hash table, and hence |
diff --git a/net/netfilter/nf_conntrack_core.c b/net/netfilter/nf_conntrack_core.c index 8f2261965a68..093b3ddc513c 100644 --- a/net/netfilter/nf_conntrack_core.c +++ b/net/netfilter/nf_conntrack_core.c | |||
@@ -57,7 +57,6 @@ | |||
57 | #include <net/netfilter/nf_conntrack_protocol.h> | 57 | #include <net/netfilter/nf_conntrack_protocol.h> |
58 | #include <net/netfilter/nf_conntrack_helper.h> | 58 | #include <net/netfilter/nf_conntrack_helper.h> |
59 | #include <net/netfilter/nf_conntrack_core.h> | 59 | #include <net/netfilter/nf_conntrack_core.h> |
60 | #include <linux/netfilter_ipv4/listhelp.h> | ||
61 | 60 | ||
62 | #define NF_CONNTRACK_VERSION "0.5.0" | 61 | #define NF_CONNTRACK_VERSION "0.5.0" |
63 | 62 | ||
@@ -74,17 +73,17 @@ atomic_t nf_conntrack_count = ATOMIC_INIT(0); | |||
74 | 73 | ||
75 | void (*nf_conntrack_destroyed)(struct nf_conn *conntrack) = NULL; | 74 | void (*nf_conntrack_destroyed)(struct nf_conn *conntrack) = NULL; |
76 | LIST_HEAD(nf_conntrack_expect_list); | 75 | LIST_HEAD(nf_conntrack_expect_list); |
77 | struct nf_conntrack_protocol **nf_ct_protos[PF_MAX]; | 76 | struct nf_conntrack_protocol **nf_ct_protos[PF_MAX] __read_mostly; |
78 | struct nf_conntrack_l3proto *nf_ct_l3protos[PF_MAX]; | 77 | struct nf_conntrack_l3proto *nf_ct_l3protos[PF_MAX] __read_mostly; |
79 | static LIST_HEAD(helpers); | 78 | static LIST_HEAD(helpers); |
80 | unsigned int nf_conntrack_htable_size = 0; | 79 | unsigned int nf_conntrack_htable_size __read_mostly = 0; |
81 | int nf_conntrack_max; | 80 | int nf_conntrack_max __read_mostly; |
82 | struct list_head *nf_conntrack_hash; | 81 | struct list_head *nf_conntrack_hash __read_mostly; |
83 | static kmem_cache_t *nf_conntrack_expect_cachep; | 82 | static kmem_cache_t *nf_conntrack_expect_cachep __read_mostly; |
84 | struct nf_conn nf_conntrack_untracked; | 83 | struct nf_conn nf_conntrack_untracked; |
85 | unsigned int nf_ct_log_invalid; | 84 | unsigned int nf_ct_log_invalid __read_mostly; |
86 | static LIST_HEAD(unconfirmed); | 85 | static LIST_HEAD(unconfirmed); |
87 | static int nf_conntrack_vmalloc; | 86 | static int nf_conntrack_vmalloc __read_mostly; |
88 | 87 | ||
89 | static unsigned int nf_conntrack_next_id; | 88 | static unsigned int nf_conntrack_next_id; |
90 | static unsigned int nf_conntrack_expect_next_id; | 89 | static unsigned int nf_conntrack_expect_next_id; |
@@ -539,15 +538,10 @@ void nf_ct_remove_expectations(struct nf_conn *ct) | |||
539 | static void | 538 | static void |
540 | clean_from_lists(struct nf_conn *ct) | 539 | clean_from_lists(struct nf_conn *ct) |
541 | { | 540 | { |
542 | unsigned int ho, hr; | ||
543 | |||
544 | DEBUGP("clean_from_lists(%p)\n", ct); | 541 | DEBUGP("clean_from_lists(%p)\n", ct); |
545 | ASSERT_WRITE_LOCK(&nf_conntrack_lock); | 542 | ASSERT_WRITE_LOCK(&nf_conntrack_lock); |
546 | 543 | list_del(&ct->tuplehash[IP_CT_DIR_ORIGINAL].list); | |
547 | ho = hash_conntrack(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple); | 544 | list_del(&ct->tuplehash[IP_CT_DIR_REPLY].list); |
548 | hr = hash_conntrack(&ct->tuplehash[IP_CT_DIR_REPLY].tuple); | ||
549 | LIST_DELETE(&nf_conntrack_hash[ho], &ct->tuplehash[IP_CT_DIR_ORIGINAL]); | ||
550 | LIST_DELETE(&nf_conntrack_hash[hr], &ct->tuplehash[IP_CT_DIR_REPLY]); | ||
551 | 545 | ||
552 | /* Destroy all pending expectations */ | 546 | /* Destroy all pending expectations */ |
553 | nf_ct_remove_expectations(ct); | 547 | nf_ct_remove_expectations(ct); |
@@ -617,16 +611,6 @@ static void death_by_timeout(unsigned long ul_conntrack) | |||
617 | nf_ct_put(ct); | 611 | nf_ct_put(ct); |
618 | } | 612 | } |
619 | 613 | ||
620 | static inline int | ||
621 | conntrack_tuple_cmp(const struct nf_conntrack_tuple_hash *i, | ||
622 | const struct nf_conntrack_tuple *tuple, | ||
623 | const struct nf_conn *ignored_conntrack) | ||
624 | { | ||
625 | ASSERT_READ_LOCK(&nf_conntrack_lock); | ||
626 | return nf_ct_tuplehash_to_ctrack(i) != ignored_conntrack | ||
627 | && nf_ct_tuple_equal(tuple, &i->tuple); | ||
628 | } | ||
629 | |||
630 | struct nf_conntrack_tuple_hash * | 614 | struct nf_conntrack_tuple_hash * |
631 | __nf_conntrack_find(const struct nf_conntrack_tuple *tuple, | 615 | __nf_conntrack_find(const struct nf_conntrack_tuple *tuple, |
632 | const struct nf_conn *ignored_conntrack) | 616 | const struct nf_conn *ignored_conntrack) |
@@ -636,7 +620,8 @@ __nf_conntrack_find(const struct nf_conntrack_tuple *tuple, | |||
636 | 620 | ||
637 | ASSERT_READ_LOCK(&nf_conntrack_lock); | 621 | ASSERT_READ_LOCK(&nf_conntrack_lock); |
638 | list_for_each_entry(h, &nf_conntrack_hash[hash], list) { | 622 | list_for_each_entry(h, &nf_conntrack_hash[hash], list) { |
639 | if (conntrack_tuple_cmp(h, tuple, ignored_conntrack)) { | 623 | if (nf_ct_tuplehash_to_ctrack(h) != ignored_conntrack && |
624 | nf_ct_tuple_equal(tuple, &h->tuple)) { | ||
640 | NF_CT_STAT_INC(found); | 625 | NF_CT_STAT_INC(found); |
641 | return h; | 626 | return h; |
642 | } | 627 | } |
@@ -667,10 +652,10 @@ static void __nf_conntrack_hash_insert(struct nf_conn *ct, | |||
667 | unsigned int repl_hash) | 652 | unsigned int repl_hash) |
668 | { | 653 | { |
669 | ct->id = ++nf_conntrack_next_id; | 654 | ct->id = ++nf_conntrack_next_id; |
670 | list_prepend(&nf_conntrack_hash[hash], | 655 | list_add(&ct->tuplehash[IP_CT_DIR_ORIGINAL].list, |
671 | &ct->tuplehash[IP_CT_DIR_ORIGINAL].list); | 656 | &nf_conntrack_hash[hash]); |
672 | list_prepend(&nf_conntrack_hash[repl_hash], | 657 | list_add(&ct->tuplehash[IP_CT_DIR_REPLY].list, |
673 | &ct->tuplehash[IP_CT_DIR_REPLY].list); | 658 | &nf_conntrack_hash[repl_hash]); |
674 | } | 659 | } |
675 | 660 | ||
676 | void nf_conntrack_hash_insert(struct nf_conn *ct) | 661 | void nf_conntrack_hash_insert(struct nf_conn *ct) |
@@ -690,7 +675,9 @@ int | |||
690 | __nf_conntrack_confirm(struct sk_buff **pskb) | 675 | __nf_conntrack_confirm(struct sk_buff **pskb) |
691 | { | 676 | { |
692 | unsigned int hash, repl_hash; | 677 | unsigned int hash, repl_hash; |
678 | struct nf_conntrack_tuple_hash *h; | ||
693 | struct nf_conn *ct; | 679 | struct nf_conn *ct; |
680 | struct nf_conn_help *help; | ||
694 | enum ip_conntrack_info ctinfo; | 681 | enum ip_conntrack_info ctinfo; |
695 | 682 | ||
696 | ct = nf_ct_get(*pskb, &ctinfo); | 683 | ct = nf_ct_get(*pskb, &ctinfo); |
@@ -720,41 +707,41 @@ __nf_conntrack_confirm(struct sk_buff **pskb) | |||
720 | /* See if there's one in the list already, including reverse: | 707 | /* See if there's one in the list already, including reverse: |
721 | NAT could have grabbed it without realizing, since we're | 708 | NAT could have grabbed it without realizing, since we're |
722 | not in the hash. If there is, we lost race. */ | 709 | not in the hash. If there is, we lost race. */ |
723 | if (!LIST_FIND(&nf_conntrack_hash[hash], | 710 | list_for_each_entry(h, &nf_conntrack_hash[hash], list) |
724 | conntrack_tuple_cmp, | 711 | if (nf_ct_tuple_equal(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple, |
725 | struct nf_conntrack_tuple_hash *, | 712 | &h->tuple)) |
726 | &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple, NULL) | 713 | goto out; |
727 | && !LIST_FIND(&nf_conntrack_hash[repl_hash], | 714 | list_for_each_entry(h, &nf_conntrack_hash[repl_hash], list) |
728 | conntrack_tuple_cmp, | 715 | if (nf_ct_tuple_equal(&ct->tuplehash[IP_CT_DIR_REPLY].tuple, |
729 | struct nf_conntrack_tuple_hash *, | 716 | &h->tuple)) |
730 | &ct->tuplehash[IP_CT_DIR_REPLY].tuple, NULL)) { | 717 | goto out; |
731 | struct nf_conn_help *help; | ||
732 | /* Remove from unconfirmed list */ | ||
733 | list_del(&ct->tuplehash[IP_CT_DIR_ORIGINAL].list); | ||
734 | 718 | ||
735 | __nf_conntrack_hash_insert(ct, hash, repl_hash); | 719 | /* Remove from unconfirmed list */ |
736 | /* Timer relative to confirmation time, not original | 720 | list_del(&ct->tuplehash[IP_CT_DIR_ORIGINAL].list); |
737 | setting time, otherwise we'd get timer wrap in | 721 | |
738 | weird delay cases. */ | 722 | __nf_conntrack_hash_insert(ct, hash, repl_hash); |
739 | ct->timeout.expires += jiffies; | 723 | /* Timer relative to confirmation time, not original |
740 | add_timer(&ct->timeout); | 724 | setting time, otherwise we'd get timer wrap in |
741 | atomic_inc(&ct->ct_general.use); | 725 | weird delay cases. */ |
742 | set_bit(IPS_CONFIRMED_BIT, &ct->status); | 726 | ct->timeout.expires += jiffies; |
743 | NF_CT_STAT_INC(insert); | 727 | add_timer(&ct->timeout); |
744 | write_unlock_bh(&nf_conntrack_lock); | 728 | atomic_inc(&ct->ct_general.use); |
745 | help = nfct_help(ct); | 729 | set_bit(IPS_CONFIRMED_BIT, &ct->status); |
746 | if (help && help->helper) | 730 | NF_CT_STAT_INC(insert); |
747 | nf_conntrack_event_cache(IPCT_HELPER, *pskb); | 731 | write_unlock_bh(&nf_conntrack_lock); |
732 | help = nfct_help(ct); | ||
733 | if (help && help->helper) | ||
734 | nf_conntrack_event_cache(IPCT_HELPER, *pskb); | ||
748 | #ifdef CONFIG_NF_NAT_NEEDED | 735 | #ifdef CONFIG_NF_NAT_NEEDED |
749 | if (test_bit(IPS_SRC_NAT_DONE_BIT, &ct->status) || | 736 | if (test_bit(IPS_SRC_NAT_DONE_BIT, &ct->status) || |
750 | test_bit(IPS_DST_NAT_DONE_BIT, &ct->status)) | 737 | test_bit(IPS_DST_NAT_DONE_BIT, &ct->status)) |
751 | nf_conntrack_event_cache(IPCT_NATINFO, *pskb); | 738 | nf_conntrack_event_cache(IPCT_NATINFO, *pskb); |
752 | #endif | 739 | #endif |
753 | nf_conntrack_event_cache(master_ct(ct) ? | 740 | nf_conntrack_event_cache(master_ct(ct) ? |
754 | IPCT_RELATED : IPCT_NEW, *pskb); | 741 | IPCT_RELATED : IPCT_NEW, *pskb); |
755 | return NF_ACCEPT; | 742 | return NF_ACCEPT; |
756 | } | ||
757 | 743 | ||
744 | out: | ||
758 | NF_CT_STAT_INC(insert_failed); | 745 | NF_CT_STAT_INC(insert_failed); |
759 | write_unlock_bh(&nf_conntrack_lock); | 746 | write_unlock_bh(&nf_conntrack_lock); |
760 | return NF_DROP; | 747 | return NF_DROP; |
@@ -777,24 +764,21 @@ nf_conntrack_tuple_taken(const struct nf_conntrack_tuple *tuple, | |||
777 | 764 | ||
778 | /* There's a small race here where we may free a just-assured | 765 | /* There's a small race here where we may free a just-assured |
779 | connection. Too bad: we're in trouble anyway. */ | 766 | connection. Too bad: we're in trouble anyway. */ |
780 | static inline int unreplied(const struct nf_conntrack_tuple_hash *i) | ||
781 | { | ||
782 | return !(test_bit(IPS_ASSURED_BIT, | ||
783 | &nf_ct_tuplehash_to_ctrack(i)->status)); | ||
784 | } | ||
785 | |||
786 | static int early_drop(struct list_head *chain) | 767 | static int early_drop(struct list_head *chain) |
787 | { | 768 | { |
788 | /* Traverse backwards: gives us oldest, which is roughly LRU */ | 769 | /* Traverse backwards: gives us oldest, which is roughly LRU */ |
789 | struct nf_conntrack_tuple_hash *h; | 770 | struct nf_conntrack_tuple_hash *h; |
790 | struct nf_conn *ct = NULL; | 771 | struct nf_conn *ct = NULL, *tmp; |
791 | int dropped = 0; | 772 | int dropped = 0; |
792 | 773 | ||
793 | read_lock_bh(&nf_conntrack_lock); | 774 | read_lock_bh(&nf_conntrack_lock); |
794 | h = LIST_FIND_B(chain, unreplied, struct nf_conntrack_tuple_hash *); | 775 | list_for_each_entry_reverse(h, chain, list) { |
795 | if (h) { | 776 | tmp = nf_ct_tuplehash_to_ctrack(h); |
796 | ct = nf_ct_tuplehash_to_ctrack(h); | 777 | if (!test_bit(IPS_ASSURED_BIT, &tmp->status)) { |
797 | atomic_inc(&ct->ct_general.use); | 778 | ct = tmp; |
779 | atomic_inc(&ct->ct_general.use); | ||
780 | break; | ||
781 | } | ||
798 | } | 782 | } |
799 | read_unlock_bh(&nf_conntrack_lock); | 783 | read_unlock_bh(&nf_conntrack_lock); |
800 | 784 | ||
@@ -810,18 +794,16 @@ static int early_drop(struct list_head *chain) | |||
810 | return dropped; | 794 | return dropped; |
811 | } | 795 | } |
812 | 796 | ||
813 | static inline int helper_cmp(const struct nf_conntrack_helper *i, | ||
814 | const struct nf_conntrack_tuple *rtuple) | ||
815 | { | ||
816 | return nf_ct_tuple_mask_cmp(rtuple, &i->tuple, &i->mask); | ||
817 | } | ||
818 | |||
819 | static struct nf_conntrack_helper * | 797 | static struct nf_conntrack_helper * |
820 | __nf_ct_helper_find(const struct nf_conntrack_tuple *tuple) | 798 | __nf_ct_helper_find(const struct nf_conntrack_tuple *tuple) |
821 | { | 799 | { |
822 | return LIST_FIND(&helpers, helper_cmp, | 800 | struct nf_conntrack_helper *h; |
823 | struct nf_conntrack_helper *, | 801 | |
824 | tuple); | 802 | list_for_each_entry(h, &helpers, list) { |
803 | if (nf_ct_tuple_mask_cmp(tuple, &h->tuple, &h->mask)) | ||
804 | return h; | ||
805 | } | ||
806 | return NULL; | ||
825 | } | 807 | } |
826 | 808 | ||
827 | struct nf_conntrack_helper * | 809 | struct nf_conntrack_helper * |
@@ -866,11 +848,15 @@ __nf_conntrack_alloc(const struct nf_conntrack_tuple *orig, | |||
866 | nf_conntrack_hash_rnd_initted = 1; | 848 | nf_conntrack_hash_rnd_initted = 1; |
867 | } | 849 | } |
868 | 850 | ||
851 | /* We don't want any race condition at early drop stage */ | ||
852 | atomic_inc(&nf_conntrack_count); | ||
853 | |||
869 | if (nf_conntrack_max | 854 | if (nf_conntrack_max |
870 | && atomic_read(&nf_conntrack_count) >= nf_conntrack_max) { | 855 | && atomic_read(&nf_conntrack_count) > nf_conntrack_max) { |
871 | unsigned int hash = hash_conntrack(orig); | 856 | unsigned int hash = hash_conntrack(orig); |
872 | /* Try dropping from this hash chain. */ | 857 | /* Try dropping from this hash chain. */ |
873 | if (!early_drop(&nf_conntrack_hash[hash])) { | 858 | if (!early_drop(&nf_conntrack_hash[hash])) { |
859 | atomic_dec(&nf_conntrack_count); | ||
874 | if (net_ratelimit()) | 860 | if (net_ratelimit()) |
875 | printk(KERN_WARNING | 861 | printk(KERN_WARNING |
876 | "nf_conntrack: table full, dropping" | 862 | "nf_conntrack: table full, dropping" |
@@ -921,10 +907,12 @@ __nf_conntrack_alloc(const struct nf_conntrack_tuple *orig, | |||
921 | init_timer(&conntrack->timeout); | 907 | init_timer(&conntrack->timeout); |
922 | conntrack->timeout.data = (unsigned long)conntrack; | 908 | conntrack->timeout.data = (unsigned long)conntrack; |
923 | conntrack->timeout.function = death_by_timeout; | 909 | conntrack->timeout.function = death_by_timeout; |
910 | read_unlock_bh(&nf_ct_cache_lock); | ||
924 | 911 | ||
925 | atomic_inc(&nf_conntrack_count); | 912 | return conntrack; |
926 | out: | 913 | out: |
927 | read_unlock_bh(&nf_ct_cache_lock); | 914 | read_unlock_bh(&nf_ct_cache_lock); |
915 | atomic_dec(&nf_conntrack_count); | ||
928 | return conntrack; | 916 | return conntrack; |
929 | } | 917 | } |
930 | 918 | ||
@@ -1323,7 +1311,7 @@ int nf_conntrack_helper_register(struct nf_conntrack_helper *me) | |||
1323 | return ret; | 1311 | return ret; |
1324 | } | 1312 | } |
1325 | write_lock_bh(&nf_conntrack_lock); | 1313 | write_lock_bh(&nf_conntrack_lock); |
1326 | list_prepend(&helpers, me); | 1314 | list_add(&me->list, &helpers); |
1327 | write_unlock_bh(&nf_conntrack_lock); | 1315 | write_unlock_bh(&nf_conntrack_lock); |
1328 | 1316 | ||
1329 | return 0; | 1317 | return 0; |
@@ -1342,8 +1330,8 @@ __nf_conntrack_helper_find_byname(const char *name) | |||
1342 | return NULL; | 1330 | return NULL; |
1343 | } | 1331 | } |
1344 | 1332 | ||
1345 | static inline int unhelp(struct nf_conntrack_tuple_hash *i, | 1333 | static inline void unhelp(struct nf_conntrack_tuple_hash *i, |
1346 | const struct nf_conntrack_helper *me) | 1334 | const struct nf_conntrack_helper *me) |
1347 | { | 1335 | { |
1348 | struct nf_conn *ct = nf_ct_tuplehash_to_ctrack(i); | 1336 | struct nf_conn *ct = nf_ct_tuplehash_to_ctrack(i); |
1349 | struct nf_conn_help *help = nfct_help(ct); | 1337 | struct nf_conn_help *help = nfct_help(ct); |
@@ -1352,17 +1340,17 @@ static inline int unhelp(struct nf_conntrack_tuple_hash *i, | |||
1352 | nf_conntrack_event(IPCT_HELPER, ct); | 1340 | nf_conntrack_event(IPCT_HELPER, ct); |
1353 | help->helper = NULL; | 1341 | help->helper = NULL; |
1354 | } | 1342 | } |
1355 | return 0; | ||
1356 | } | 1343 | } |
1357 | 1344 | ||
1358 | void nf_conntrack_helper_unregister(struct nf_conntrack_helper *me) | 1345 | void nf_conntrack_helper_unregister(struct nf_conntrack_helper *me) |
1359 | { | 1346 | { |
1360 | unsigned int i; | 1347 | unsigned int i; |
1348 | struct nf_conntrack_tuple_hash *h; | ||
1361 | struct nf_conntrack_expect *exp, *tmp; | 1349 | struct nf_conntrack_expect *exp, *tmp; |
1362 | 1350 | ||
1363 | /* Need write lock here, to delete helper. */ | 1351 | /* Need write lock here, to delete helper. */ |
1364 | write_lock_bh(&nf_conntrack_lock); | 1352 | write_lock_bh(&nf_conntrack_lock); |
1365 | LIST_DELETE(&helpers, me); | 1353 | list_del(&me->list); |
1366 | 1354 | ||
1367 | /* Get rid of expectations */ | 1355 | /* Get rid of expectations */ |
1368 | list_for_each_entry_safe(exp, tmp, &nf_conntrack_expect_list, list) { | 1356 | list_for_each_entry_safe(exp, tmp, &nf_conntrack_expect_list, list) { |
@@ -1374,10 +1362,12 @@ void nf_conntrack_helper_unregister(struct nf_conntrack_helper *me) | |||
1374 | } | 1362 | } |
1375 | 1363 | ||
1376 | /* Get rid of expecteds, set helpers to NULL. */ | 1364 | /* Get rid of expecteds, set helpers to NULL. */ |
1377 | LIST_FIND_W(&unconfirmed, unhelp, struct nf_conntrack_tuple_hash*, me); | 1365 | list_for_each_entry(h, &unconfirmed, list) |
1378 | for (i = 0; i < nf_conntrack_htable_size; i++) | 1366 | unhelp(h, me); |
1379 | LIST_FIND_W(&nf_conntrack_hash[i], unhelp, | 1367 | for (i = 0; i < nf_conntrack_htable_size; i++) { |
1380 | struct nf_conntrack_tuple_hash *, me); | 1368 | list_for_each_entry(h, &nf_conntrack_hash[i], list) |
1369 | unhelp(h, me); | ||
1370 | } | ||
1381 | write_unlock_bh(&nf_conntrack_lock); | 1371 | write_unlock_bh(&nf_conntrack_lock); |
1382 | 1372 | ||
1383 | /* Someone could be still looking at the helper in a bh. */ | 1373 | /* Someone could be still looking at the helper in a bh. */ |
@@ -1510,37 +1500,40 @@ do_iter(const struct nf_conntrack_tuple_hash *i, | |||
1510 | } | 1500 | } |
1511 | 1501 | ||
1512 | /* Bring out ya dead! */ | 1502 | /* Bring out ya dead! */ |
1513 | static struct nf_conntrack_tuple_hash * | 1503 | static struct nf_conn * |
1514 | get_next_corpse(int (*iter)(struct nf_conn *i, void *data), | 1504 | get_next_corpse(int (*iter)(struct nf_conn *i, void *data), |
1515 | void *data, unsigned int *bucket) | 1505 | void *data, unsigned int *bucket) |
1516 | { | 1506 | { |
1517 | struct nf_conntrack_tuple_hash *h = NULL; | 1507 | struct nf_conntrack_tuple_hash *h; |
1508 | struct nf_conn *ct; | ||
1518 | 1509 | ||
1519 | write_lock_bh(&nf_conntrack_lock); | 1510 | write_lock_bh(&nf_conntrack_lock); |
1520 | for (; *bucket < nf_conntrack_htable_size; (*bucket)++) { | 1511 | for (; *bucket < nf_conntrack_htable_size; (*bucket)++) { |
1521 | h = LIST_FIND_W(&nf_conntrack_hash[*bucket], do_iter, | 1512 | list_for_each_entry(h, &nf_conntrack_hash[*bucket], list) { |
1522 | struct nf_conntrack_tuple_hash *, iter, data); | 1513 | ct = nf_ct_tuplehash_to_ctrack(h); |
1523 | if (h) | 1514 | if (iter(ct, data)) |
1524 | break; | 1515 | goto found; |
1516 | } | ||
1525 | } | 1517 | } |
1526 | if (!h) | 1518 | list_for_each_entry(h, &unconfirmed, list) { |
1527 | h = LIST_FIND_W(&unconfirmed, do_iter, | 1519 | ct = nf_ct_tuplehash_to_ctrack(h); |
1528 | struct nf_conntrack_tuple_hash *, iter, data); | 1520 | if (iter(ct, data)) |
1529 | if (h) | 1521 | goto found; |
1530 | atomic_inc(&nf_ct_tuplehash_to_ctrack(h)->ct_general.use); | 1522 | } |
1523 | return NULL; | ||
1524 | found: | ||
1525 | atomic_inc(&nf_ct_tuplehash_to_ctrack(h)->ct_general.use); | ||
1531 | write_unlock_bh(&nf_conntrack_lock); | 1526 | write_unlock_bh(&nf_conntrack_lock); |
1532 | 1527 | return ct; | |
1533 | return h; | ||
1534 | } | 1528 | } |
1535 | 1529 | ||
1536 | void | 1530 | void |
1537 | nf_ct_iterate_cleanup(int (*iter)(struct nf_conn *i, void *data), void *data) | 1531 | nf_ct_iterate_cleanup(int (*iter)(struct nf_conn *i, void *data), void *data) |
1538 | { | 1532 | { |
1539 | struct nf_conntrack_tuple_hash *h; | 1533 | struct nf_conn *ct; |
1540 | unsigned int bucket = 0; | 1534 | unsigned int bucket = 0; |
1541 | 1535 | ||
1542 | while ((h = get_next_corpse(iter, data, &bucket)) != NULL) { | 1536 | while ((ct = get_next_corpse(iter, data, &bucket)) != NULL) { |
1543 | struct nf_conn *ct = nf_ct_tuplehash_to_ctrack(h); | ||
1544 | /* Time to push up daises... */ | 1537 | /* Time to push up daises... */ |
1545 | if (del_timer(&ct->timeout)) | 1538 | if (del_timer(&ct->timeout)) |
1546 | death_by_timeout((unsigned long)ct); | 1539 | death_by_timeout((unsigned long)ct); |
diff --git a/net/netfilter/nf_conntrack_ftp.c b/net/netfilter/nf_conntrack_ftp.c index 960972d225f9..0c17a5bd112b 100644 --- a/net/netfilter/nf_conntrack_ftp.c +++ b/net/netfilter/nf_conntrack_ftp.c | |||
@@ -21,6 +21,7 @@ | |||
21 | #include <linux/ip.h> | 21 | #include <linux/ip.h> |
22 | #include <linux/ipv6.h> | 22 | #include <linux/ipv6.h> |
23 | #include <linux/ctype.h> | 23 | #include <linux/ctype.h> |
24 | #include <linux/inet.h> | ||
24 | #include <net/checksum.h> | 25 | #include <net/checksum.h> |
25 | #include <net/tcp.h> | 26 | #include <net/tcp.h> |
26 | 27 | ||
@@ -111,101 +112,14 @@ static struct ftp_search { | |||
111 | }, | 112 | }, |
112 | }; | 113 | }; |
113 | 114 | ||
114 | /* This code is based on inet_pton() in glibc-2.2.4 */ | ||
115 | static int | 115 | static int |
116 | get_ipv6_addr(const char *src, size_t dlen, struct in6_addr *dst, u_int8_t term) | 116 | get_ipv6_addr(const char *src, size_t dlen, struct in6_addr *dst, u_int8_t term) |
117 | { | 117 | { |
118 | static const char xdigits[] = "0123456789abcdef"; | 118 | const char *end; |
119 | u_int8_t tmp[16], *tp, *endp, *colonp; | 119 | int ret = in6_pton(src, min_t(size_t, dlen, 0xffff), (u8 *)dst, term, &end); |
120 | int ch, saw_xdigit; | 120 | if (ret > 0) |
121 | u_int32_t val; | 121 | return (int)(end - src); |
122 | size_t clen = 0; | 122 | return 0; |
123 | |||
124 | tp = memset(tmp, '\0', sizeof(tmp)); | ||
125 | endp = tp + sizeof(tmp); | ||
126 | colonp = NULL; | ||
127 | |||
128 | /* Leading :: requires some special handling. */ | ||
129 | if (*src == ':'){ | ||
130 | if (*++src != ':') { | ||
131 | DEBUGP("invalid \":\" at the head of addr\n"); | ||
132 | return 0; | ||
133 | } | ||
134 | clen++; | ||
135 | } | ||
136 | |||
137 | saw_xdigit = 0; | ||
138 | val = 0; | ||
139 | while ((clen < dlen) && (*src != term)) { | ||
140 | const char *pch; | ||
141 | |||
142 | ch = tolower(*src++); | ||
143 | clen++; | ||
144 | |||
145 | pch = strchr(xdigits, ch); | ||
146 | if (pch != NULL) { | ||
147 | val <<= 4; | ||
148 | val |= (pch - xdigits); | ||
149 | if (val > 0xffff) | ||
150 | return 0; | ||
151 | |||
152 | saw_xdigit = 1; | ||
153 | continue; | ||
154 | } | ||
155 | if (ch != ':') { | ||
156 | DEBUGP("get_ipv6_addr: invalid char. \'%c\'\n", ch); | ||
157 | return 0; | ||
158 | } | ||
159 | |||
160 | if (!saw_xdigit) { | ||
161 | if (colonp) { | ||
162 | DEBUGP("invalid location of \"::\".\n"); | ||
163 | return 0; | ||
164 | } | ||
165 | colonp = tp; | ||
166 | continue; | ||
167 | } else if (*src == term) { | ||
168 | DEBUGP("trancated IPv6 addr\n"); | ||
169 | return 0; | ||
170 | } | ||
171 | |||
172 | if (tp + 2 > endp) | ||
173 | return 0; | ||
174 | *tp++ = (u_int8_t) (val >> 8) & 0xff; | ||
175 | *tp++ = (u_int8_t) val & 0xff; | ||
176 | |||
177 | saw_xdigit = 0; | ||
178 | val = 0; | ||
179 | continue; | ||
180 | } | ||
181 | if (saw_xdigit) { | ||
182 | if (tp + 2 > endp) | ||
183 | return 0; | ||
184 | *tp++ = (u_int8_t) (val >> 8) & 0xff; | ||
185 | *tp++ = (u_int8_t) val & 0xff; | ||
186 | } | ||
187 | if (colonp != NULL) { | ||
188 | /* | ||
189 | * Since some memmove()'s erroneously fail to handle | ||
190 | * overlapping regions, we'll do the shift by hand. | ||
191 | */ | ||
192 | const int n = tp - colonp; | ||
193 | int i; | ||
194 | |||
195 | if (tp == endp) | ||
196 | return 0; | ||
197 | |||
198 | for (i = 1; i <= n; i++) { | ||
199 | endp[- i] = colonp[n - i]; | ||
200 | colonp[n - i] = 0; | ||
201 | } | ||
202 | tp = endp; | ||
203 | } | ||
204 | if (tp != endp || (*src != term)) | ||
205 | return 0; | ||
206 | |||
207 | memcpy(dst->s6_addr, tmp, sizeof(dst->s6_addr)); | ||
208 | return clen; | ||
209 | } | 123 | } |
210 | 124 | ||
211 | static int try_number(const char *data, size_t dlen, u_int32_t array[], | 125 | static int try_number(const char *data, size_t dlen, u_int32_t array[], |
diff --git a/net/netfilter/nf_conntrack_netlink.c b/net/netfilter/nf_conntrack_netlink.c index 6527d4e048d8..1721f7c78c77 100644 --- a/net/netfilter/nf_conntrack_netlink.c +++ b/net/netfilter/nf_conntrack_netlink.c | |||
@@ -339,11 +339,7 @@ static int ctnetlink_conntrack_event(struct notifier_block *this, | |||
339 | /* dump everything */ | 339 | /* dump everything */ |
340 | events = ~0UL; | 340 | events = ~0UL; |
341 | group = NFNLGRP_CONNTRACK_NEW; | 341 | group = NFNLGRP_CONNTRACK_NEW; |
342 | } else if (events & (IPCT_STATUS | | 342 | } else if (events & (IPCT_STATUS | IPCT_PROTOINFO)) { |
343 | IPCT_PROTOINFO | | ||
344 | IPCT_HELPER | | ||
345 | IPCT_HELPINFO | | ||
346 | IPCT_NATINFO)) { | ||
347 | type = IPCTNL_MSG_CT_NEW; | 343 | type = IPCTNL_MSG_CT_NEW; |
348 | group = NFNLGRP_CONNTRACK_UPDATE; | 344 | group = NFNLGRP_CONNTRACK_UPDATE; |
349 | } else | 345 | } else |
@@ -395,6 +391,10 @@ static int ctnetlink_conntrack_event(struct notifier_block *this, | |||
395 | ctnetlink_dump_counters(skb, ct, IP_CT_DIR_REPLY) < 0) | 391 | ctnetlink_dump_counters(skb, ct, IP_CT_DIR_REPLY) < 0) |
396 | goto nfattr_failure; | 392 | goto nfattr_failure; |
397 | 393 | ||
394 | if (events & IPCT_MARK | ||
395 | && ctnetlink_dump_mark(skb, ct) < 0) | ||
396 | goto nfattr_failure; | ||
397 | |||
398 | nlh->nlmsg_len = skb->tail - b; | 398 | nlh->nlmsg_len = skb->tail - b; |
399 | nfnetlink_send(skb, 0, group, 0); | 399 | nfnetlink_send(skb, 0, group, 0); |
400 | return NOTIFY_DONE; | 400 | return NOTIFY_DONE; |
@@ -455,6 +455,11 @@ restart: | |||
455 | cb->args[1] = (unsigned long)ct; | 455 | cb->args[1] = (unsigned long)ct; |
456 | goto out; | 456 | goto out; |
457 | } | 457 | } |
458 | #ifdef CONFIG_NF_CT_ACCT | ||
459 | if (NFNL_MSG_TYPE(cb->nlh->nlmsg_type) == | ||
460 | IPCTNL_MSG_CT_GET_CTRZERO) | ||
461 | memset(&ct->counters, 0, sizeof(ct->counters)); | ||
462 | #endif | ||
458 | } | 463 | } |
459 | if (cb->args[1]) { | 464 | if (cb->args[1]) { |
460 | cb->args[1] = 0; | 465 | cb->args[1] = 0; |
@@ -470,50 +475,6 @@ out: | |||
470 | return skb->len; | 475 | return skb->len; |
471 | } | 476 | } |
472 | 477 | ||
473 | #ifdef CONFIG_NF_CT_ACCT | ||
474 | static int | ||
475 | ctnetlink_dump_table_w(struct sk_buff *skb, struct netlink_callback *cb) | ||
476 | { | ||
477 | struct nf_conn *ct = NULL; | ||
478 | struct nf_conntrack_tuple_hash *h; | ||
479 | struct list_head *i; | ||
480 | u_int32_t *id = (u_int32_t *) &cb->args[1]; | ||
481 | struct nfgenmsg *nfmsg = NLMSG_DATA(cb->nlh); | ||
482 | u_int8_t l3proto = nfmsg->nfgen_family; | ||
483 | |||
484 | DEBUGP("entered %s, last bucket=%u id=%u\n", __FUNCTION__, | ||
485 | cb->args[0], *id); | ||
486 | |||
487 | write_lock_bh(&nf_conntrack_lock); | ||
488 | for (; cb->args[0] < nf_conntrack_htable_size; cb->args[0]++, *id = 0) { | ||
489 | list_for_each_prev(i, &nf_conntrack_hash[cb->args[0]]) { | ||
490 | h = (struct nf_conntrack_tuple_hash *) i; | ||
491 | if (DIRECTION(h) != IP_CT_DIR_ORIGINAL) | ||
492 | continue; | ||
493 | ct = nf_ct_tuplehash_to_ctrack(h); | ||
494 | if (l3proto && L3PROTO(ct) != l3proto) | ||
495 | continue; | ||
496 | if (ct->id <= *id) | ||
497 | continue; | ||
498 | if (ctnetlink_fill_info(skb, NETLINK_CB(cb->skb).pid, | ||
499 | cb->nlh->nlmsg_seq, | ||
500 | IPCTNL_MSG_CT_NEW, | ||
501 | 1, ct) < 0) | ||
502 | goto out; | ||
503 | *id = ct->id; | ||
504 | |||
505 | memset(&ct->counters, 0, sizeof(ct->counters)); | ||
506 | } | ||
507 | } | ||
508 | out: | ||
509 | write_unlock_bh(&nf_conntrack_lock); | ||
510 | |||
511 | DEBUGP("leaving, last bucket=%lu id=%u\n", cb->args[0], *id); | ||
512 | |||
513 | return skb->len; | ||
514 | } | ||
515 | #endif | ||
516 | |||
517 | static inline int | 478 | static inline int |
518 | ctnetlink_parse_tuple_ip(struct nfattr *attr, struct nf_conntrack_tuple *tuple) | 479 | ctnetlink_parse_tuple_ip(struct nfattr *attr, struct nf_conntrack_tuple *tuple) |
519 | { | 480 | { |
@@ -788,22 +749,14 @@ ctnetlink_get_conntrack(struct sock *ctnl, struct sk_buff *skb, | |||
788 | if (nlh->nlmsg_flags & NLM_F_DUMP) { | 749 | if (nlh->nlmsg_flags & NLM_F_DUMP) { |
789 | u32 rlen; | 750 | u32 rlen; |
790 | 751 | ||
791 | if (NFNL_MSG_TYPE(nlh->nlmsg_type) == | 752 | #ifndef CONFIG_NF_CT_ACCT |
792 | IPCTNL_MSG_CT_GET_CTRZERO) { | 753 | if (NFNL_MSG_TYPE(nlh->nlmsg_type) == IPCTNL_MSG_CT_GET_CTRZERO) |
793 | #ifdef CONFIG_NF_CT_ACCT | ||
794 | if ((*errp = netlink_dump_start(ctnl, skb, nlh, | ||
795 | ctnetlink_dump_table_w, | ||
796 | ctnetlink_done)) != 0) | ||
797 | return -EINVAL; | ||
798 | #else | ||
799 | return -ENOTSUPP; | 754 | return -ENOTSUPP; |
800 | #endif | 755 | #endif |
801 | } else { | 756 | if ((*errp = netlink_dump_start(ctnl, skb, nlh, |
802 | if ((*errp = netlink_dump_start(ctnl, skb, nlh, | 757 | ctnetlink_dump_table, |
803 | ctnetlink_dump_table, | 758 | ctnetlink_done)) != 0) |
804 | ctnetlink_done)) != 0) | ||
805 | return -EINVAL; | 759 | return -EINVAL; |
806 | } | ||
807 | 760 | ||
808 | rlen = NLMSG_ALIGN(nlh->nlmsg_len); | 761 | rlen = NLMSG_ALIGN(nlh->nlmsg_len); |
809 | if (rlen > skb->len) | 762 | if (rlen > skb->len) |
@@ -1274,6 +1227,9 @@ static int ctnetlink_expect_event(struct notifier_block *this, | |||
1274 | } else | 1227 | } else |
1275 | return NOTIFY_DONE; | 1228 | return NOTIFY_DONE; |
1276 | 1229 | ||
1230 | if (!nfnetlink_has_listeners(NFNLGRP_CONNTRACK_EXP_NEW)) | ||
1231 | return NOTIFY_DONE; | ||
1232 | |||
1277 | skb = alloc_skb(NLMSG_GOODSIZE, GFP_ATOMIC); | 1233 | skb = alloc_skb(NLMSG_GOODSIZE, GFP_ATOMIC); |
1278 | if (!skb) | 1234 | if (!skb) |
1279 | return NOTIFY_DONE; | 1235 | return NOTIFY_DONE; |
diff --git a/net/netfilter/nf_conntrack_proto_generic.c b/net/netfilter/nf_conntrack_proto_generic.c index 46bc27e2756d..26408bb0955b 100644 --- a/net/netfilter/nf_conntrack_proto_generic.c +++ b/net/netfilter/nf_conntrack_proto_generic.c | |||
@@ -17,7 +17,7 @@ | |||
17 | #include <linux/netfilter.h> | 17 | #include <linux/netfilter.h> |
18 | #include <net/netfilter/nf_conntrack_protocol.h> | 18 | #include <net/netfilter/nf_conntrack_protocol.h> |
19 | 19 | ||
20 | unsigned int nf_ct_generic_timeout = 600*HZ; | 20 | unsigned int nf_ct_generic_timeout __read_mostly = 600*HZ; |
21 | 21 | ||
22 | static int generic_pkt_to_tuple(const struct sk_buff *skb, | 22 | static int generic_pkt_to_tuple(const struct sk_buff *skb, |
23 | unsigned int dataoff, | 23 | unsigned int dataoff, |
diff --git a/net/netfilter/nf_conntrack_proto_sctp.c b/net/netfilter/nf_conntrack_proto_sctp.c index 9bd8a7877fd5..af568777372b 100644 --- a/net/netfilter/nf_conntrack_proto_sctp.c +++ b/net/netfilter/nf_conntrack_proto_sctp.c | |||
@@ -64,13 +64,13 @@ static const char *sctp_conntrack_names[] = { | |||
64 | #define HOURS * 60 MINS | 64 | #define HOURS * 60 MINS |
65 | #define DAYS * 24 HOURS | 65 | #define DAYS * 24 HOURS |
66 | 66 | ||
67 | static unsigned int nf_ct_sctp_timeout_closed = 10 SECS; | 67 | static unsigned int nf_ct_sctp_timeout_closed __read_mostly = 10 SECS; |
68 | static unsigned int nf_ct_sctp_timeout_cookie_wait = 3 SECS; | 68 | static unsigned int nf_ct_sctp_timeout_cookie_wait __read_mostly = 3 SECS; |
69 | static unsigned int nf_ct_sctp_timeout_cookie_echoed = 3 SECS; | 69 | static unsigned int nf_ct_sctp_timeout_cookie_echoed __read_mostly = 3 SECS; |
70 | static unsigned int nf_ct_sctp_timeout_established = 5 DAYS; | 70 | static unsigned int nf_ct_sctp_timeout_established __read_mostly = 5 DAYS; |
71 | static unsigned int nf_ct_sctp_timeout_shutdown_sent = 300 SECS / 1000; | 71 | static unsigned int nf_ct_sctp_timeout_shutdown_sent __read_mostly = 300 SECS / 1000; |
72 | static unsigned int nf_ct_sctp_timeout_shutdown_recd = 300 SECS / 1000; | 72 | static unsigned int nf_ct_sctp_timeout_shutdown_recd __read_mostly = 300 SECS / 1000; |
73 | static unsigned int nf_ct_sctp_timeout_shutdown_ack_sent = 3 SECS; | 73 | static unsigned int nf_ct_sctp_timeout_shutdown_ack_sent __read_mostly = 3 SECS; |
74 | 74 | ||
75 | static unsigned int * sctp_timeouts[] | 75 | static unsigned int * sctp_timeouts[] |
76 | = { NULL, /* SCTP_CONNTRACK_NONE */ | 76 | = { NULL, /* SCTP_CONNTRACK_NONE */ |
diff --git a/net/netfilter/nf_conntrack_proto_tcp.c b/net/netfilter/nf_conntrack_proto_tcp.c index af8adcba23a7..238bbb5b72ef 100644 --- a/net/netfilter/nf_conntrack_proto_tcp.c +++ b/net/netfilter/nf_conntrack_proto_tcp.c | |||
@@ -57,19 +57,19 @@ static DEFINE_RWLOCK(tcp_lock); | |||
57 | /* "Be conservative in what you do, | 57 | /* "Be conservative in what you do, |
58 | be liberal in what you accept from others." | 58 | be liberal in what you accept from others." |
59 | If it's non-zero, we mark only out of window RST segments as INVALID. */ | 59 | If it's non-zero, we mark only out of window RST segments as INVALID. */ |
60 | int nf_ct_tcp_be_liberal = 0; | 60 | int nf_ct_tcp_be_liberal __read_mostly = 0; |
61 | 61 | ||
62 | /* When connection is picked up from the middle, how many packets are required | 62 | /* When connection is picked up from the middle, how many packets are required |
63 | to pass in each direction when we assume we are in sync - if any side uses | 63 | to pass in each direction when we assume we are in sync - if any side uses |
64 | window scaling, we lost the game. | 64 | window scaling, we lost the game. |
65 | If it is set to zero, we disable picking up already established | 65 | If it is set to zero, we disable picking up already established |
66 | connections. */ | 66 | connections. */ |
67 | int nf_ct_tcp_loose = 3; | 67 | int nf_ct_tcp_loose __read_mostly = 3; |
68 | 68 | ||
69 | /* Max number of the retransmitted packets without receiving an (acceptable) | 69 | /* Max number of the retransmitted packets without receiving an (acceptable) |
70 | ACK from the destination. If this number is reached, a shorter timer | 70 | ACK from the destination. If this number is reached, a shorter timer |
71 | will be started. */ | 71 | will be started. */ |
72 | int nf_ct_tcp_max_retrans = 3; | 72 | int nf_ct_tcp_max_retrans __read_mostly = 3; |
73 | 73 | ||
74 | /* FIXME: Examine ipfilter's timeouts and conntrack transitions more | 74 | /* FIXME: Examine ipfilter's timeouts and conntrack transitions more |
75 | closely. They're more complex. --RR */ | 75 | closely. They're more complex. --RR */ |
@@ -92,19 +92,19 @@ static const char *tcp_conntrack_names[] = { | |||
92 | #define HOURS * 60 MINS | 92 | #define HOURS * 60 MINS |
93 | #define DAYS * 24 HOURS | 93 | #define DAYS * 24 HOURS |
94 | 94 | ||
95 | unsigned int nf_ct_tcp_timeout_syn_sent = 2 MINS; | 95 | unsigned int nf_ct_tcp_timeout_syn_sent __read_mostly = 2 MINS; |
96 | unsigned int nf_ct_tcp_timeout_syn_recv = 60 SECS; | 96 | unsigned int nf_ct_tcp_timeout_syn_recv __read_mostly = 60 SECS; |
97 | unsigned int nf_ct_tcp_timeout_established = 5 DAYS; | 97 | unsigned int nf_ct_tcp_timeout_established __read_mostly = 5 DAYS; |
98 | unsigned int nf_ct_tcp_timeout_fin_wait = 2 MINS; | 98 | unsigned int nf_ct_tcp_timeout_fin_wait __read_mostly = 2 MINS; |
99 | unsigned int nf_ct_tcp_timeout_close_wait = 60 SECS; | 99 | unsigned int nf_ct_tcp_timeout_close_wait __read_mostly = 60 SECS; |
100 | unsigned int nf_ct_tcp_timeout_last_ack = 30 SECS; | 100 | unsigned int nf_ct_tcp_timeout_last_ack __read_mostly = 30 SECS; |
101 | unsigned int nf_ct_tcp_timeout_time_wait = 2 MINS; | 101 | unsigned int nf_ct_tcp_timeout_time_wait __read_mostly = 2 MINS; |
102 | unsigned int nf_ct_tcp_timeout_close = 10 SECS; | 102 | unsigned int nf_ct_tcp_timeout_close __read_mostly = 10 SECS; |
103 | 103 | ||
104 | /* RFC1122 says the R2 limit should be at least 100 seconds. | 104 | /* RFC1122 says the R2 limit should be at least 100 seconds. |
105 | Linux uses 15 packets as limit, which corresponds | 105 | Linux uses 15 packets as limit, which corresponds |
106 | to ~13-30min depending on RTO. */ | 106 | to ~13-30min depending on RTO. */ |
107 | unsigned int nf_ct_tcp_timeout_max_retrans = 5 MINS; | 107 | unsigned int nf_ct_tcp_timeout_max_retrans __read_mostly = 5 MINS; |
108 | 108 | ||
109 | static unsigned int * tcp_timeouts[] | 109 | static unsigned int * tcp_timeouts[] |
110 | = { NULL, /* TCP_CONNTRACK_NONE */ | 110 | = { NULL, /* TCP_CONNTRACK_NONE */ |
@@ -688,13 +688,15 @@ static int tcp_in_window(struct ip_ct_tcp *state, | |||
688 | if (state->last_dir == dir | 688 | if (state->last_dir == dir |
689 | && state->last_seq == seq | 689 | && state->last_seq == seq |
690 | && state->last_ack == ack | 690 | && state->last_ack == ack |
691 | && state->last_end == end) | 691 | && state->last_end == end |
692 | && state->last_win == win) | ||
692 | state->retrans++; | 693 | state->retrans++; |
693 | else { | 694 | else { |
694 | state->last_dir = dir; | 695 | state->last_dir = dir; |
695 | state->last_seq = seq; | 696 | state->last_seq = seq; |
696 | state->last_ack = ack; | 697 | state->last_ack = ack; |
697 | state->last_end = end; | 698 | state->last_end = end; |
699 | state->last_win = win; | ||
698 | state->retrans = 0; | 700 | state->retrans = 0; |
699 | } | 701 | } |
700 | } | 702 | } |
@@ -823,8 +825,7 @@ static int tcp_error(struct sk_buff *skb, | |||
823 | 825 | ||
824 | /* Checksum invalid? Ignore. | 826 | /* Checksum invalid? Ignore. |
825 | * We skip checking packets on the outgoing path | 827 | * We skip checking packets on the outgoing path |
826 | * because the semantic of CHECKSUM_HW is different there | 828 | * because the checksum is assumed to be correct. |
827 | * and moreover root might send raw packets. | ||
828 | */ | 829 | */ |
829 | /* FIXME: Source route IP option packets --RR */ | 830 | /* FIXME: Source route IP option packets --RR */ |
830 | if (nf_conntrack_checksum && | 831 | if (nf_conntrack_checksum && |
diff --git a/net/netfilter/nf_conntrack_proto_udp.c b/net/netfilter/nf_conntrack_proto_udp.c index ae07ebe3ab37..d28981cf9af5 100644 --- a/net/netfilter/nf_conntrack_proto_udp.c +++ b/net/netfilter/nf_conntrack_proto_udp.c | |||
@@ -27,8 +27,8 @@ | |||
27 | #include <linux/netfilter_ipv6.h> | 27 | #include <linux/netfilter_ipv6.h> |
28 | #include <net/netfilter/nf_conntrack_protocol.h> | 28 | #include <net/netfilter/nf_conntrack_protocol.h> |
29 | 29 | ||
30 | unsigned int nf_ct_udp_timeout = 30*HZ; | 30 | unsigned int nf_ct_udp_timeout __read_mostly = 30*HZ; |
31 | unsigned int nf_ct_udp_timeout_stream = 180*HZ; | 31 | unsigned int nf_ct_udp_timeout_stream __read_mostly = 180*HZ; |
32 | 32 | ||
33 | static int udp_pkt_to_tuple(const struct sk_buff *skb, | 33 | static int udp_pkt_to_tuple(const struct sk_buff *skb, |
34 | unsigned int dataoff, | 34 | unsigned int dataoff, |
@@ -131,8 +131,7 @@ static int udp_error(struct sk_buff *skb, unsigned int dataoff, | |||
131 | 131 | ||
132 | /* Checksum invalid? Ignore. | 132 | /* Checksum invalid? Ignore. |
133 | * We skip checking packets on the outgoing path | 133 | * We skip checking packets on the outgoing path |
134 | * because the semantic of CHECKSUM_HW is different there | 134 | * because the checksum is assumed to be correct. |
135 | * and moreover root might send raw packets. | ||
136 | * FIXME: Source route IP option packets --RR */ | 135 | * FIXME: Source route IP option packets --RR */ |
137 | if (nf_conntrack_checksum && | 136 | if (nf_conntrack_checksum && |
138 | ((pf == PF_INET && hooknum == NF_IP_PRE_ROUTING) || | 137 | ((pf == PF_INET && hooknum == NF_IP_PRE_ROUTING) || |
diff --git a/net/netfilter/nf_conntrack_standalone.c b/net/netfilter/nf_conntrack_standalone.c index 4ef836699962..5954f6773810 100644 --- a/net/netfilter/nf_conntrack_standalone.c +++ b/net/netfilter/nf_conntrack_standalone.c | |||
@@ -37,7 +37,6 @@ | |||
37 | #include <net/netfilter/nf_conntrack_protocol.h> | 37 | #include <net/netfilter/nf_conntrack_protocol.h> |
38 | #include <net/netfilter/nf_conntrack_core.h> | 38 | #include <net/netfilter/nf_conntrack_core.h> |
39 | #include <net/netfilter/nf_conntrack_helper.h> | 39 | #include <net/netfilter/nf_conntrack_helper.h> |
40 | #include <linux/netfilter_ipv4/listhelp.h> | ||
41 | 40 | ||
42 | #if 0 | 41 | #if 0 |
43 | #define DEBUGP printk | 42 | #define DEBUGP printk |
@@ -428,7 +427,7 @@ static struct file_operations ct_cpu_seq_fops = { | |||
428 | 427 | ||
429 | /* Sysctl support */ | 428 | /* Sysctl support */ |
430 | 429 | ||
431 | int nf_conntrack_checksum = 1; | 430 | int nf_conntrack_checksum __read_mostly = 1; |
432 | 431 | ||
433 | #ifdef CONFIG_SYSCTL | 432 | #ifdef CONFIG_SYSCTL |
434 | 433 | ||
diff --git a/net/netfilter/nf_internals.h b/net/netfilter/nf_internals.h index 86e392bfe833..a981971ce1d5 100644 --- a/net/netfilter/nf_internals.h +++ b/net/netfilter/nf_internals.h | |||
@@ -23,7 +23,7 @@ extern unsigned int nf_iterate(struct list_head *head, | |||
23 | int hook_thresh); | 23 | int hook_thresh); |
24 | 24 | ||
25 | /* nf_queue.c */ | 25 | /* nf_queue.c */ |
26 | extern int nf_queue(struct sk_buff **skb, | 26 | extern int nf_queue(struct sk_buff *skb, |
27 | struct list_head *elem, | 27 | struct list_head *elem, |
28 | int pf, unsigned int hook, | 28 | int pf, unsigned int hook, |
29 | struct net_device *indev, | 29 | struct net_device *indev, |
diff --git a/net/netfilter/nf_queue.c b/net/netfilter/nf_queue.c index 662a869593bf..4d8936ed581d 100644 --- a/net/netfilter/nf_queue.c +++ b/net/netfilter/nf_queue.c | |||
@@ -74,13 +74,13 @@ EXPORT_SYMBOL_GPL(nf_unregister_queue_handlers); | |||
74 | * Any packet that leaves via this function must come back | 74 | * Any packet that leaves via this function must come back |
75 | * through nf_reinject(). | 75 | * through nf_reinject(). |
76 | */ | 76 | */ |
77 | int nf_queue(struct sk_buff **skb, | 77 | static int __nf_queue(struct sk_buff *skb, |
78 | struct list_head *elem, | 78 | struct list_head *elem, |
79 | int pf, unsigned int hook, | 79 | int pf, unsigned int hook, |
80 | struct net_device *indev, | 80 | struct net_device *indev, |
81 | struct net_device *outdev, | 81 | struct net_device *outdev, |
82 | int (*okfn)(struct sk_buff *), | 82 | int (*okfn)(struct sk_buff *), |
83 | unsigned int queuenum) | 83 | unsigned int queuenum) |
84 | { | 84 | { |
85 | int status; | 85 | int status; |
86 | struct nf_info *info; | 86 | struct nf_info *info; |
@@ -94,14 +94,14 @@ int nf_queue(struct sk_buff **skb, | |||
94 | read_lock(&queue_handler_lock); | 94 | read_lock(&queue_handler_lock); |
95 | if (!queue_handler[pf]) { | 95 | if (!queue_handler[pf]) { |
96 | read_unlock(&queue_handler_lock); | 96 | read_unlock(&queue_handler_lock); |
97 | kfree_skb(*skb); | 97 | kfree_skb(skb); |
98 | return 1; | 98 | return 1; |
99 | } | 99 | } |
100 | 100 | ||
101 | afinfo = nf_get_afinfo(pf); | 101 | afinfo = nf_get_afinfo(pf); |
102 | if (!afinfo) { | 102 | if (!afinfo) { |
103 | read_unlock(&queue_handler_lock); | 103 | read_unlock(&queue_handler_lock); |
104 | kfree_skb(*skb); | 104 | kfree_skb(skb); |
105 | return 1; | 105 | return 1; |
106 | } | 106 | } |
107 | 107 | ||
@@ -109,9 +109,9 @@ int nf_queue(struct sk_buff **skb, | |||
109 | if (!info) { | 109 | if (!info) { |
110 | if (net_ratelimit()) | 110 | if (net_ratelimit()) |
111 | printk(KERN_ERR "OOM queueing packet %p\n", | 111 | printk(KERN_ERR "OOM queueing packet %p\n", |
112 | *skb); | 112 | skb); |
113 | read_unlock(&queue_handler_lock); | 113 | read_unlock(&queue_handler_lock); |
114 | kfree_skb(*skb); | 114 | kfree_skb(skb); |
115 | return 1; | 115 | return 1; |
116 | } | 116 | } |
117 | 117 | ||
@@ -130,15 +130,15 @@ int nf_queue(struct sk_buff **skb, | |||
130 | if (outdev) dev_hold(outdev); | 130 | if (outdev) dev_hold(outdev); |
131 | 131 | ||
132 | #ifdef CONFIG_BRIDGE_NETFILTER | 132 | #ifdef CONFIG_BRIDGE_NETFILTER |
133 | if ((*skb)->nf_bridge) { | 133 | if (skb->nf_bridge) { |
134 | physindev = (*skb)->nf_bridge->physindev; | 134 | physindev = skb->nf_bridge->physindev; |
135 | if (physindev) dev_hold(physindev); | 135 | if (physindev) dev_hold(physindev); |
136 | physoutdev = (*skb)->nf_bridge->physoutdev; | 136 | physoutdev = skb->nf_bridge->physoutdev; |
137 | if (physoutdev) dev_hold(physoutdev); | 137 | if (physoutdev) dev_hold(physoutdev); |
138 | } | 138 | } |
139 | #endif | 139 | #endif |
140 | afinfo->saveroute(*skb, info); | 140 | afinfo->saveroute(skb, info); |
141 | status = queue_handler[pf]->outfn(*skb, info, queuenum, | 141 | status = queue_handler[pf]->outfn(skb, info, queuenum, |
142 | queue_handler[pf]->data); | 142 | queue_handler[pf]->data); |
143 | 143 | ||
144 | read_unlock(&queue_handler_lock); | 144 | read_unlock(&queue_handler_lock); |
@@ -153,7 +153,7 @@ int nf_queue(struct sk_buff **skb, | |||
153 | #endif | 153 | #endif |
154 | module_put(info->elem->owner); | 154 | module_put(info->elem->owner); |
155 | kfree(info); | 155 | kfree(info); |
156 | kfree_skb(*skb); | 156 | kfree_skb(skb); |
157 | 157 | ||
158 | return 1; | 158 | return 1; |
159 | } | 159 | } |
@@ -161,6 +161,46 @@ int nf_queue(struct sk_buff **skb, | |||
161 | return 1; | 161 | return 1; |
162 | } | 162 | } |
163 | 163 | ||
164 | int nf_queue(struct sk_buff *skb, | ||
165 | struct list_head *elem, | ||
166 | int pf, unsigned int hook, | ||
167 | struct net_device *indev, | ||
168 | struct net_device *outdev, | ||
169 | int (*okfn)(struct sk_buff *), | ||
170 | unsigned int queuenum) | ||
171 | { | ||
172 | struct sk_buff *segs; | ||
173 | |||
174 | if (!skb_is_gso(skb)) | ||
175 | return __nf_queue(skb, elem, pf, hook, indev, outdev, okfn, | ||
176 | queuenum); | ||
177 | |||
178 | switch (pf) { | ||
179 | case AF_INET: | ||
180 | skb->protocol = htons(ETH_P_IP); | ||
181 | break; | ||
182 | case AF_INET6: | ||
183 | skb->protocol = htons(ETH_P_IPV6); | ||
184 | break; | ||
185 | } | ||
186 | |||
187 | segs = skb_gso_segment(skb, 0); | ||
188 | kfree_skb(skb); | ||
189 | if (unlikely(IS_ERR(segs))) | ||
190 | return 1; | ||
191 | |||
192 | do { | ||
193 | struct sk_buff *nskb = segs->next; | ||
194 | |||
195 | segs->next = NULL; | ||
196 | if (!__nf_queue(segs, elem, pf, hook, indev, outdev, okfn, | ||
197 | queuenum)) | ||
198 | kfree_skb(segs); | ||
199 | segs = nskb; | ||
200 | } while (segs); | ||
201 | return 1; | ||
202 | } | ||
203 | |||
164 | void nf_reinject(struct sk_buff *skb, struct nf_info *info, | 204 | void nf_reinject(struct sk_buff *skb, struct nf_info *info, |
165 | unsigned int verdict) | 205 | unsigned int verdict) |
166 | { | 206 | { |
@@ -224,9 +264,9 @@ void nf_reinject(struct sk_buff *skb, struct nf_info *info, | |||
224 | case NF_STOLEN: | 264 | case NF_STOLEN: |
225 | break; | 265 | break; |
226 | case NF_QUEUE: | 266 | case NF_QUEUE: |
227 | if (!nf_queue(&skb, elem, info->pf, info->hook, | 267 | if (!__nf_queue(skb, elem, info->pf, info->hook, |
228 | info->indev, info->outdev, info->okfn, | 268 | info->indev, info->outdev, info->okfn, |
229 | verdict >> NF_VERDICT_BITS)) | 269 | verdict >> NF_VERDICT_BITS)) |
230 | goto next_hook; | 270 | goto next_hook; |
231 | break; | 271 | break; |
232 | default: | 272 | default: |
diff --git a/net/netfilter/nfnetlink_queue.c b/net/netfilter/nfnetlink_queue.c index 49ef41e34c48..8eb2473d83e1 100644 --- a/net/netfilter/nfnetlink_queue.c +++ b/net/netfilter/nfnetlink_queue.c | |||
@@ -377,9 +377,9 @@ nfqnl_build_packet_message(struct nfqnl_instance *queue, | |||
377 | break; | 377 | break; |
378 | 378 | ||
379 | case NFQNL_COPY_PACKET: | 379 | case NFQNL_COPY_PACKET: |
380 | if (entskb->ip_summed == CHECKSUM_HW && | 380 | if ((entskb->ip_summed == CHECKSUM_PARTIAL || |
381 | (*errp = skb_checksum_help(entskb, | 381 | entskb->ip_summed == CHECKSUM_COMPLETE) && |
382 | outdev == NULL))) { | 382 | (*errp = skb_checksum_help(entskb))) { |
383 | spin_unlock_bh(&queue->lock); | 383 | spin_unlock_bh(&queue->lock); |
384 | return NULL; | 384 | return NULL; |
385 | } | 385 | } |
@@ -584,7 +584,7 @@ nfqnl_enqueue_packet(struct sk_buff *skb, struct nf_info *info, | |||
584 | queue->queue_dropped++; | 584 | queue->queue_dropped++; |
585 | status = -ENOSPC; | 585 | status = -ENOSPC; |
586 | if (net_ratelimit()) | 586 | if (net_ratelimit()) |
587 | printk(KERN_WARNING "ip_queue: full at %d entries, " | 587 | printk(KERN_WARNING "nf_queue: full at %d entries, " |
588 | "dropping packets(s). Dropped: %d\n", | 588 | "dropping packets(s). Dropped: %d\n", |
589 | queue->queue_total, queue->queue_dropped); | 589 | queue->queue_total, queue->queue_dropped); |
590 | goto err_out_free_nskb; | 590 | goto err_out_free_nskb; |
@@ -635,7 +635,7 @@ nfqnl_mangle(void *data, int data_len, struct nfqnl_queue_entry *e) | |||
635 | diff, | 635 | diff, |
636 | GFP_ATOMIC); | 636 | GFP_ATOMIC); |
637 | if (newskb == NULL) { | 637 | if (newskb == NULL) { |
638 | printk(KERN_WARNING "ip_queue: OOM " | 638 | printk(KERN_WARNING "nf_queue: OOM " |
639 | "in mangle, dropping packet\n"); | 639 | "in mangle, dropping packet\n"); |
640 | return -ENOMEM; | 640 | return -ENOMEM; |
641 | } | 641 | } |
diff --git a/net/netfilter/x_tables.c b/net/netfilter/x_tables.c index 174e8f970095..58522fc65d33 100644 --- a/net/netfilter/x_tables.c +++ b/net/netfilter/x_tables.c | |||
@@ -81,12 +81,42 @@ xt_unregister_target(struct xt_target *target) | |||
81 | int af = target->family; | 81 | int af = target->family; |
82 | 82 | ||
83 | mutex_lock(&xt[af].mutex); | 83 | mutex_lock(&xt[af].mutex); |
84 | LIST_DELETE(&xt[af].target, target); | 84 | list_del(&target->list); |
85 | mutex_unlock(&xt[af].mutex); | 85 | mutex_unlock(&xt[af].mutex); |
86 | } | 86 | } |
87 | EXPORT_SYMBOL(xt_unregister_target); | 87 | EXPORT_SYMBOL(xt_unregister_target); |
88 | 88 | ||
89 | int | 89 | int |
90 | xt_register_targets(struct xt_target *target, unsigned int n) | ||
91 | { | ||
92 | unsigned int i; | ||
93 | int err = 0; | ||
94 | |||
95 | for (i = 0; i < n; i++) { | ||
96 | err = xt_register_target(&target[i]); | ||
97 | if (err) | ||
98 | goto err; | ||
99 | } | ||
100 | return err; | ||
101 | |||
102 | err: | ||
103 | if (i > 0) | ||
104 | xt_unregister_targets(target, i); | ||
105 | return err; | ||
106 | } | ||
107 | EXPORT_SYMBOL(xt_register_targets); | ||
108 | |||
109 | void | ||
110 | xt_unregister_targets(struct xt_target *target, unsigned int n) | ||
111 | { | ||
112 | unsigned int i; | ||
113 | |||
114 | for (i = 0; i < n; i++) | ||
115 | xt_unregister_target(&target[i]); | ||
116 | } | ||
117 | EXPORT_SYMBOL(xt_unregister_targets); | ||
118 | |||
119 | int | ||
90 | xt_register_match(struct xt_match *match) | 120 | xt_register_match(struct xt_match *match) |
91 | { | 121 | { |
92 | int ret, af = match->family; | 122 | int ret, af = match->family; |
@@ -108,11 +138,41 @@ xt_unregister_match(struct xt_match *match) | |||
108 | int af = match->family; | 138 | int af = match->family; |
109 | 139 | ||
110 | mutex_lock(&xt[af].mutex); | 140 | mutex_lock(&xt[af].mutex); |
111 | LIST_DELETE(&xt[af].match, match); | 141 | list_del(&match->list); |
112 | mutex_unlock(&xt[af].mutex); | 142 | mutex_unlock(&xt[af].mutex); |
113 | } | 143 | } |
114 | EXPORT_SYMBOL(xt_unregister_match); | 144 | EXPORT_SYMBOL(xt_unregister_match); |
115 | 145 | ||
146 | int | ||
147 | xt_register_matches(struct xt_match *match, unsigned int n) | ||
148 | { | ||
149 | unsigned int i; | ||
150 | int err = 0; | ||
151 | |||
152 | for (i = 0; i < n; i++) { | ||
153 | err = xt_register_match(&match[i]); | ||
154 | if (err) | ||
155 | goto err; | ||
156 | } | ||
157 | return err; | ||
158 | |||
159 | err: | ||
160 | if (i > 0) | ||
161 | xt_unregister_matches(match, i); | ||
162 | return err; | ||
163 | } | ||
164 | EXPORT_SYMBOL(xt_register_matches); | ||
165 | |||
166 | void | ||
167 | xt_unregister_matches(struct xt_match *match, unsigned int n) | ||
168 | { | ||
169 | unsigned int i; | ||
170 | |||
171 | for (i = 0; i < n; i++) | ||
172 | xt_unregister_match(&match[i]); | ||
173 | } | ||
174 | EXPORT_SYMBOL(xt_unregister_matches); | ||
175 | |||
116 | 176 | ||
117 | /* | 177 | /* |
118 | * These are weird, but module loading must not be done with mutex | 178 | * These are weird, but module loading must not be done with mutex |
@@ -273,52 +333,65 @@ int xt_check_match(const struct xt_match *match, unsigned short family, | |||
273 | EXPORT_SYMBOL_GPL(xt_check_match); | 333 | EXPORT_SYMBOL_GPL(xt_check_match); |
274 | 334 | ||
275 | #ifdef CONFIG_COMPAT | 335 | #ifdef CONFIG_COMPAT |
276 | int xt_compat_match(void *match, void **dstptr, int *size, int convert) | 336 | int xt_compat_match_offset(struct xt_match *match) |
277 | { | 337 | { |
278 | struct xt_match *m; | 338 | u_int16_t csize = match->compatsize ? : match->matchsize; |
279 | struct compat_xt_entry_match *pcompat_m; | 339 | return XT_ALIGN(match->matchsize) - COMPAT_XT_ALIGN(csize); |
280 | struct xt_entry_match *pm; | 340 | } |
281 | u_int16_t msize; | 341 | EXPORT_SYMBOL_GPL(xt_compat_match_offset); |
282 | int off, ret; | ||
283 | 342 | ||
284 | ret = 0; | 343 | void xt_compat_match_from_user(struct xt_entry_match *m, void **dstptr, |
285 | m = ((struct xt_entry_match *)match)->u.kernel.match; | 344 | int *size) |
286 | off = XT_ALIGN(m->matchsize) - COMPAT_XT_ALIGN(m->matchsize); | 345 | { |
287 | switch (convert) { | 346 | struct xt_match *match = m->u.kernel.match; |
288 | case COMPAT_TO_USER: | 347 | struct compat_xt_entry_match *cm = (struct compat_xt_entry_match *)m; |
289 | pm = (struct xt_entry_match *)match; | 348 | int pad, off = xt_compat_match_offset(match); |
290 | msize = pm->u.user.match_size; | 349 | u_int16_t msize = cm->u.user.match_size; |
291 | if (copy_to_user(*dstptr, pm, msize)) { | 350 | |
292 | ret = -EFAULT; | 351 | m = *dstptr; |
293 | break; | 352 | memcpy(m, cm, sizeof(*cm)); |
294 | } | 353 | if (match->compat_from_user) |
295 | msize -= off; | 354 | match->compat_from_user(m->data, cm->data); |
296 | if (put_user(msize, (u_int16_t *)*dstptr)) | 355 | else |
297 | ret = -EFAULT; | 356 | memcpy(m->data, cm->data, msize - sizeof(*cm)); |
298 | *size -= off; | 357 | pad = XT_ALIGN(match->matchsize) - match->matchsize; |
299 | *dstptr += msize; | 358 | if (pad > 0) |
300 | break; | 359 | memset(m->data + match->matchsize, 0, pad); |
301 | case COMPAT_FROM_USER: | 360 | |
302 | pcompat_m = (struct compat_xt_entry_match *)match; | 361 | msize += off; |
303 | pm = (struct xt_entry_match *)*dstptr; | 362 | m->u.user.match_size = msize; |
304 | msize = pcompat_m->u.user.match_size; | 363 | |
305 | memcpy(pm, pcompat_m, msize); | 364 | *size += off; |
306 | msize += off; | 365 | *dstptr += msize; |
307 | pm->u.user.match_size = msize; | 366 | } |
308 | *size += off; | 367 | EXPORT_SYMBOL_GPL(xt_compat_match_from_user); |
309 | *dstptr += msize; | 368 | |
310 | break; | 369 | int xt_compat_match_to_user(struct xt_entry_match *m, void __user **dstptr, |
311 | case COMPAT_CALC_SIZE: | 370 | int *size) |
312 | *size += off; | 371 | { |
313 | break; | 372 | struct xt_match *match = m->u.kernel.match; |
314 | default: | 373 | struct compat_xt_entry_match __user *cm = *dstptr; |
315 | ret = -ENOPROTOOPT; | 374 | int off = xt_compat_match_offset(match); |
316 | break; | 375 | u_int16_t msize = m->u.user.match_size - off; |
376 | |||
377 | if (copy_to_user(cm, m, sizeof(*cm)) || | ||
378 | put_user(msize, &cm->u.user.match_size)) | ||
379 | return -EFAULT; | ||
380 | |||
381 | if (match->compat_to_user) { | ||
382 | if (match->compat_to_user((void __user *)cm->data, m->data)) | ||
383 | return -EFAULT; | ||
384 | } else { | ||
385 | if (copy_to_user(cm->data, m->data, msize - sizeof(*cm))) | ||
386 | return -EFAULT; | ||
317 | } | 387 | } |
318 | return ret; | 388 | |
389 | *size -= off; | ||
390 | *dstptr += msize; | ||
391 | return 0; | ||
319 | } | 392 | } |
320 | EXPORT_SYMBOL_GPL(xt_compat_match); | 393 | EXPORT_SYMBOL_GPL(xt_compat_match_to_user); |
321 | #endif | 394 | #endif /* CONFIG_COMPAT */ |
322 | 395 | ||
323 | int xt_check_target(const struct xt_target *target, unsigned short family, | 396 | int xt_check_target(const struct xt_target *target, unsigned short family, |
324 | unsigned int size, const char *table, unsigned int hook_mask, | 397 | unsigned int size, const char *table, unsigned int hook_mask, |
@@ -350,51 +423,64 @@ int xt_check_target(const struct xt_target *target, unsigned short family, | |||
350 | EXPORT_SYMBOL_GPL(xt_check_target); | 423 | EXPORT_SYMBOL_GPL(xt_check_target); |
351 | 424 | ||
352 | #ifdef CONFIG_COMPAT | 425 | #ifdef CONFIG_COMPAT |
353 | int xt_compat_target(void *target, void **dstptr, int *size, int convert) | 426 | int xt_compat_target_offset(struct xt_target *target) |
354 | { | 427 | { |
355 | struct xt_target *t; | 428 | u_int16_t csize = target->compatsize ? : target->targetsize; |
356 | struct compat_xt_entry_target *pcompat; | 429 | return XT_ALIGN(target->targetsize) - COMPAT_XT_ALIGN(csize); |
357 | struct xt_entry_target *pt; | 430 | } |
358 | u_int16_t tsize; | 431 | EXPORT_SYMBOL_GPL(xt_compat_target_offset); |
359 | int off, ret; | ||
360 | 432 | ||
361 | ret = 0; | 433 | void xt_compat_target_from_user(struct xt_entry_target *t, void **dstptr, |
362 | t = ((struct xt_entry_target *)target)->u.kernel.target; | 434 | int *size) |
363 | off = XT_ALIGN(t->targetsize) - COMPAT_XT_ALIGN(t->targetsize); | 435 | { |
364 | switch (convert) { | 436 | struct xt_target *target = t->u.kernel.target; |
365 | case COMPAT_TO_USER: | 437 | struct compat_xt_entry_target *ct = (struct compat_xt_entry_target *)t; |
366 | pt = (struct xt_entry_target *)target; | 438 | int pad, off = xt_compat_target_offset(target); |
367 | tsize = pt->u.user.target_size; | 439 | u_int16_t tsize = ct->u.user.target_size; |
368 | if (copy_to_user(*dstptr, pt, tsize)) { | 440 | |
369 | ret = -EFAULT; | 441 | t = *dstptr; |
370 | break; | 442 | memcpy(t, ct, sizeof(*ct)); |
371 | } | 443 | if (target->compat_from_user) |
372 | tsize -= off; | 444 | target->compat_from_user(t->data, ct->data); |
373 | if (put_user(tsize, (u_int16_t *)*dstptr)) | 445 | else |
374 | ret = -EFAULT; | 446 | memcpy(t->data, ct->data, tsize - sizeof(*ct)); |
375 | *size -= off; | 447 | pad = XT_ALIGN(target->targetsize) - target->targetsize; |
376 | *dstptr += tsize; | 448 | if (pad > 0) |
377 | break; | 449 | memset(t->data + target->targetsize, 0, pad); |
378 | case COMPAT_FROM_USER: | 450 | |
379 | pcompat = (struct compat_xt_entry_target *)target; | 451 | tsize += off; |
380 | pt = (struct xt_entry_target *)*dstptr; | 452 | t->u.user.target_size = tsize; |
381 | tsize = pcompat->u.user.target_size; | 453 | |
382 | memcpy(pt, pcompat, tsize); | 454 | *size += off; |
383 | tsize += off; | 455 | *dstptr += tsize; |
384 | pt->u.user.target_size = tsize; | 456 | } |
385 | *size += off; | 457 | EXPORT_SYMBOL_GPL(xt_compat_target_from_user); |
386 | *dstptr += tsize; | 458 | |
387 | break; | 459 | int xt_compat_target_to_user(struct xt_entry_target *t, void __user **dstptr, |
388 | case COMPAT_CALC_SIZE: | 460 | int *size) |
389 | *size += off; | 461 | { |
390 | break; | 462 | struct xt_target *target = t->u.kernel.target; |
391 | default: | 463 | struct compat_xt_entry_target __user *ct = *dstptr; |
392 | ret = -ENOPROTOOPT; | 464 | int off = xt_compat_target_offset(target); |
393 | break; | 465 | u_int16_t tsize = t->u.user.target_size - off; |
466 | |||
467 | if (copy_to_user(ct, t, sizeof(*ct)) || | ||
468 | put_user(tsize, &ct->u.user.target_size)) | ||
469 | return -EFAULT; | ||
470 | |||
471 | if (target->compat_to_user) { | ||
472 | if (target->compat_to_user((void __user *)ct->data, t->data)) | ||
473 | return -EFAULT; | ||
474 | } else { | ||
475 | if (copy_to_user(ct->data, t->data, tsize - sizeof(*ct))) | ||
476 | return -EFAULT; | ||
394 | } | 477 | } |
395 | return ret; | 478 | |
479 | *size -= off; | ||
480 | *dstptr += tsize; | ||
481 | return 0; | ||
396 | } | 482 | } |
397 | EXPORT_SYMBOL_GPL(xt_compat_target); | 483 | EXPORT_SYMBOL_GPL(xt_compat_target_to_user); |
398 | #endif | 484 | #endif |
399 | 485 | ||
400 | struct xt_table_info *xt_alloc_table_info(unsigned int size) | 486 | struct xt_table_info *xt_alloc_table_info(unsigned int size) |
@@ -515,15 +601,18 @@ int xt_register_table(struct xt_table *table, | |||
515 | { | 601 | { |
516 | int ret; | 602 | int ret; |
517 | struct xt_table_info *private; | 603 | struct xt_table_info *private; |
604 | struct xt_table *t; | ||
518 | 605 | ||
519 | ret = mutex_lock_interruptible(&xt[table->af].mutex); | 606 | ret = mutex_lock_interruptible(&xt[table->af].mutex); |
520 | if (ret != 0) | 607 | if (ret != 0) |
521 | return ret; | 608 | return ret; |
522 | 609 | ||
523 | /* Don't autoload: we'd eat our tail... */ | 610 | /* Don't autoload: we'd eat our tail... */ |
524 | if (list_named_find(&xt[table->af].tables, table->name)) { | 611 | list_for_each_entry(t, &xt[table->af].tables, list) { |
525 | ret = -EEXIST; | 612 | if (strcmp(t->name, table->name) == 0) { |
526 | goto unlock; | 613 | ret = -EEXIST; |
614 | goto unlock; | ||
615 | } | ||
527 | } | 616 | } |
528 | 617 | ||
529 | /* Simplifies replace_table code. */ | 618 | /* Simplifies replace_table code. */ |
@@ -538,7 +627,7 @@ int xt_register_table(struct xt_table *table, | |||
538 | /* save number of initial entries */ | 627 | /* save number of initial entries */ |
539 | private->initial_entries = private->number; | 628 | private->initial_entries = private->number; |
540 | 629 | ||
541 | list_prepend(&xt[table->af].tables, table); | 630 | list_add(&table->list, &xt[table->af].tables); |
542 | 631 | ||
543 | ret = 0; | 632 | ret = 0; |
544 | unlock: | 633 | unlock: |
@@ -553,7 +642,7 @@ void *xt_unregister_table(struct xt_table *table) | |||
553 | 642 | ||
554 | mutex_lock(&xt[table->af].mutex); | 643 | mutex_lock(&xt[table->af].mutex); |
555 | private = table->private; | 644 | private = table->private; |
556 | LIST_DELETE(&xt[table->af].tables, table); | 645 | list_del(&table->list); |
557 | mutex_unlock(&xt[table->af].mutex); | 646 | mutex_unlock(&xt[table->af].mutex); |
558 | 647 | ||
559 | return private; | 648 | return private; |
diff --git a/net/netfilter/xt_CLASSIFY.c b/net/netfilter/xt_CLASSIFY.c index e54e57730012..50de965bb104 100644 --- a/net/netfilter/xt_CLASSIFY.c +++ b/net/netfilter/xt_CLASSIFY.c | |||
@@ -29,8 +29,7 @@ target(struct sk_buff **pskb, | |||
29 | const struct net_device *out, | 29 | const struct net_device *out, |
30 | unsigned int hooknum, | 30 | unsigned int hooknum, |
31 | const struct xt_target *target, | 31 | const struct xt_target *target, |
32 | const void *targinfo, | 32 | const void *targinfo) |
33 | void *userinfo) | ||
34 | { | 33 | { |
35 | const struct xt_classify_target_info *clinfo = targinfo; | 34 | const struct xt_classify_target_info *clinfo = targinfo; |
36 | 35 | ||
@@ -40,47 +39,41 @@ target(struct sk_buff **pskb, | |||
40 | return XT_CONTINUE; | 39 | return XT_CONTINUE; |
41 | } | 40 | } |
42 | 41 | ||
43 | static struct xt_target classify_reg = { | 42 | static struct xt_target xt_classify_target[] = { |
44 | .name = "CLASSIFY", | 43 | { |
45 | .target = target, | 44 | .family = AF_INET, |
46 | .targetsize = sizeof(struct xt_classify_target_info), | 45 | .name = "CLASSIFY", |
47 | .table = "mangle", | 46 | .target = target, |
48 | .hooks = (1 << NF_IP_LOCAL_OUT) | (1 << NF_IP_FORWARD) | | 47 | .targetsize = sizeof(struct xt_classify_target_info), |
49 | (1 << NF_IP_POST_ROUTING), | 48 | .table = "mangle", |
50 | .family = AF_INET, | 49 | .hooks = (1 << NF_IP_LOCAL_OUT) | |
51 | .me = THIS_MODULE, | 50 | (1 << NF_IP_FORWARD) | |
51 | (1 << NF_IP_POST_ROUTING), | ||
52 | .me = THIS_MODULE, | ||
53 | }, | ||
54 | { | ||
55 | .name = "CLASSIFY", | ||
56 | .family = AF_INET6, | ||
57 | .target = target, | ||
58 | .targetsize = sizeof(struct xt_classify_target_info), | ||
59 | .table = "mangle", | ||
60 | .hooks = (1 << NF_IP_LOCAL_OUT) | | ||
61 | (1 << NF_IP_FORWARD) | | ||
62 | (1 << NF_IP_POST_ROUTING), | ||
63 | .me = THIS_MODULE, | ||
64 | }, | ||
52 | }; | 65 | }; |
53 | static struct xt_target classify6_reg = { | ||
54 | .name = "CLASSIFY", | ||
55 | .target = target, | ||
56 | .targetsize = sizeof(struct xt_classify_target_info), | ||
57 | .table = "mangle", | ||
58 | .hooks = (1 << NF_IP_LOCAL_OUT) | (1 << NF_IP_FORWARD) | | ||
59 | (1 << NF_IP_POST_ROUTING), | ||
60 | .family = AF_INET6, | ||
61 | .me = THIS_MODULE, | ||
62 | }; | ||
63 | |||
64 | 66 | ||
65 | static int __init xt_classify_init(void) | 67 | static int __init xt_classify_init(void) |
66 | { | 68 | { |
67 | int ret; | 69 | return xt_register_targets(xt_classify_target, |
68 | 70 | ARRAY_SIZE(xt_classify_target)); | |
69 | ret = xt_register_target(&classify_reg); | ||
70 | if (ret) | ||
71 | return ret; | ||
72 | |||
73 | ret = xt_register_target(&classify6_reg); | ||
74 | if (ret) | ||
75 | xt_unregister_target(&classify_reg); | ||
76 | |||
77 | return ret; | ||
78 | } | 71 | } |
79 | 72 | ||
80 | static void __exit xt_classify_fini(void) | 73 | static void __exit xt_classify_fini(void) |
81 | { | 74 | { |
82 | xt_unregister_target(&classify_reg); | 75 | xt_unregister_targets(xt_classify_target, |
83 | xt_unregister_target(&classify6_reg); | 76 | ARRAY_SIZE(xt_classify_target)); |
84 | } | 77 | } |
85 | 78 | ||
86 | module_init(xt_classify_init); | 79 | module_init(xt_classify_init); |
diff --git a/net/netfilter/xt_CONNMARK.c b/net/netfilter/xt_CONNMARK.c index 60c375d36f01..c01524f817f0 100644 --- a/net/netfilter/xt_CONNMARK.c +++ b/net/netfilter/xt_CONNMARK.c | |||
@@ -38,8 +38,7 @@ target(struct sk_buff **pskb, | |||
38 | const struct net_device *out, | 38 | const struct net_device *out, |
39 | unsigned int hooknum, | 39 | unsigned int hooknum, |
40 | const struct xt_target *target, | 40 | const struct xt_target *target, |
41 | const void *targinfo, | 41 | const void *targinfo) |
42 | void *userinfo) | ||
43 | { | 42 | { |
44 | const struct xt_connmark_target_info *markinfo = targinfo; | 43 | const struct xt_connmark_target_info *markinfo = targinfo; |
45 | u_int32_t diff; | 44 | u_int32_t diff; |
@@ -49,24 +48,37 @@ target(struct sk_buff **pskb, | |||
49 | u_int32_t *ctmark = nf_ct_get_mark(*pskb, &ctinfo); | 48 | u_int32_t *ctmark = nf_ct_get_mark(*pskb, &ctinfo); |
50 | 49 | ||
51 | if (ctmark) { | 50 | if (ctmark) { |
52 | switch(markinfo->mode) { | 51 | switch(markinfo->mode) { |
53 | case XT_CONNMARK_SET: | 52 | case XT_CONNMARK_SET: |
54 | newmark = (*ctmark & ~markinfo->mask) | markinfo->mark; | 53 | newmark = (*ctmark & ~markinfo->mask) | markinfo->mark; |
55 | if (newmark != *ctmark) | 54 | if (newmark != *ctmark) { |
56 | *ctmark = newmark; | 55 | *ctmark = newmark; |
57 | break; | 56 | #if defined(CONFIG_IP_NF_CONNTRACK) || defined(CONFIG_IP_NF_CONNTRACK_MODULE) |
58 | case XT_CONNMARK_SAVE: | 57 | ip_conntrack_event_cache(IPCT_MARK, *pskb); |
59 | newmark = (*ctmark & ~markinfo->mask) | ((*pskb)->nfmark & markinfo->mask); | 58 | #else |
60 | if (*ctmark != newmark) | 59 | nf_conntrack_event_cache(IPCT_MARK, *pskb); |
61 | *ctmark = newmark; | 60 | #endif |
62 | break; | 61 | } |
63 | case XT_CONNMARK_RESTORE: | 62 | break; |
64 | nfmark = (*pskb)->nfmark; | 63 | case XT_CONNMARK_SAVE: |
65 | diff = (*ctmark ^ nfmark) & markinfo->mask; | 64 | newmark = (*ctmark & ~markinfo->mask) | |
66 | if (diff != 0) | 65 | ((*pskb)->nfmark & markinfo->mask); |
67 | (*pskb)->nfmark = nfmark ^ diff; | 66 | if (*ctmark != newmark) { |
68 | break; | 67 | *ctmark = newmark; |
69 | } | 68 | #if defined(CONFIG_IP_NF_CONNTRACK) || defined(CONFIG_IP_NF_CONNTRACK_MODULE) |
69 | ip_conntrack_event_cache(IPCT_MARK, *pskb); | ||
70 | #else | ||
71 | nf_conntrack_event_cache(IPCT_MARK, *pskb); | ||
72 | #endif | ||
73 | } | ||
74 | break; | ||
75 | case XT_CONNMARK_RESTORE: | ||
76 | nfmark = (*pskb)->nfmark; | ||
77 | diff = (*ctmark ^ nfmark) & markinfo->mask; | ||
78 | if (diff != 0) | ||
79 | (*pskb)->nfmark = nfmark ^ diff; | ||
80 | break; | ||
81 | } | ||
70 | } | 82 | } |
71 | 83 | ||
72 | return XT_CONTINUE; | 84 | return XT_CONTINUE; |
@@ -77,65 +89,91 @@ checkentry(const char *tablename, | |||
77 | const void *entry, | 89 | const void *entry, |
78 | const struct xt_target *target, | 90 | const struct xt_target *target, |
79 | void *targinfo, | 91 | void *targinfo, |
80 | unsigned int targinfosize, | ||
81 | unsigned int hook_mask) | 92 | unsigned int hook_mask) |
82 | { | 93 | { |
83 | struct xt_connmark_target_info *matchinfo = targinfo; | 94 | struct xt_connmark_target_info *matchinfo = targinfo; |
84 | 95 | ||
85 | if (matchinfo->mode == XT_CONNMARK_RESTORE) { | 96 | if (matchinfo->mode == XT_CONNMARK_RESTORE) { |
86 | if (strcmp(tablename, "mangle") != 0) { | 97 | if (strcmp(tablename, "mangle") != 0) { |
87 | printk(KERN_WARNING "CONNMARK: restore can only be called from \"mangle\" table, not \"%s\"\n", tablename); | 98 | printk(KERN_WARNING "CONNMARK: restore can only be " |
88 | return 0; | 99 | "called from \"mangle\" table, not \"%s\"\n", |
89 | } | 100 | tablename); |
101 | return 0; | ||
102 | } | ||
90 | } | 103 | } |
91 | |||
92 | if (matchinfo->mark > 0xffffffff || matchinfo->mask > 0xffffffff) { | 104 | if (matchinfo->mark > 0xffffffff || matchinfo->mask > 0xffffffff) { |
93 | printk(KERN_WARNING "CONNMARK: Only supports 32bit mark\n"); | 105 | printk(KERN_WARNING "CONNMARK: Only supports 32bit mark\n"); |
94 | return 0; | 106 | return 0; |
95 | } | 107 | } |
96 | |||
97 | return 1; | 108 | return 1; |
98 | } | 109 | } |
99 | 110 | ||
100 | static struct xt_target connmark_reg = { | 111 | #ifdef CONFIG_COMPAT |
101 | .name = "CONNMARK", | 112 | struct compat_xt_connmark_target_info { |
102 | .target = target, | 113 | compat_ulong_t mark, mask; |
103 | .targetsize = sizeof(struct xt_connmark_target_info), | 114 | u_int8_t mode; |
104 | .checkentry = checkentry, | 115 | u_int8_t __pad1; |
105 | .family = AF_INET, | 116 | u_int16_t __pad2; |
106 | .me = THIS_MODULE | ||
107 | }; | 117 | }; |
108 | 118 | ||
109 | static struct xt_target connmark6_reg = { | 119 | static void compat_from_user(void *dst, void *src) |
110 | .name = "CONNMARK", | 120 | { |
111 | .target = target, | 121 | struct compat_xt_connmark_target_info *cm = src; |
112 | .targetsize = sizeof(struct xt_connmark_target_info), | 122 | struct xt_connmark_target_info m = { |
113 | .checkentry = checkentry, | 123 | .mark = cm->mark, |
114 | .family = AF_INET6, | 124 | .mask = cm->mask, |
115 | .me = THIS_MODULE | 125 | .mode = cm->mode, |
126 | }; | ||
127 | memcpy(dst, &m, sizeof(m)); | ||
128 | } | ||
129 | |||
130 | static int compat_to_user(void __user *dst, void *src) | ||
131 | { | ||
132 | struct xt_connmark_target_info *m = src; | ||
133 | struct compat_xt_connmark_target_info cm = { | ||
134 | .mark = m->mark, | ||
135 | .mask = m->mask, | ||
136 | .mode = m->mode, | ||
137 | }; | ||
138 | return copy_to_user(dst, &cm, sizeof(cm)) ? -EFAULT : 0; | ||
139 | } | ||
140 | #endif /* CONFIG_COMPAT */ | ||
141 | |||
142 | static struct xt_target xt_connmark_target[] = { | ||
143 | { | ||
144 | .name = "CONNMARK", | ||
145 | .family = AF_INET, | ||
146 | .checkentry = checkentry, | ||
147 | .target = target, | ||
148 | .targetsize = sizeof(struct xt_connmark_target_info), | ||
149 | #ifdef CONFIG_COMPAT | ||
150 | .compatsize = sizeof(struct compat_xt_connmark_target_info), | ||
151 | .compat_from_user = compat_from_user, | ||
152 | .compat_to_user = compat_to_user, | ||
153 | #endif | ||
154 | .me = THIS_MODULE | ||
155 | }, | ||
156 | { | ||
157 | .name = "CONNMARK", | ||
158 | .family = AF_INET6, | ||
159 | .checkentry = checkentry, | ||
160 | .target = target, | ||
161 | .targetsize = sizeof(struct xt_connmark_target_info), | ||
162 | .me = THIS_MODULE | ||
163 | }, | ||
116 | }; | 164 | }; |
117 | 165 | ||
118 | static int __init xt_connmark_init(void) | 166 | static int __init xt_connmark_init(void) |
119 | { | 167 | { |
120 | int ret; | ||
121 | |||
122 | need_conntrack(); | 168 | need_conntrack(); |
123 | 169 | return xt_register_targets(xt_connmark_target, | |
124 | ret = xt_register_target(&connmark_reg); | 170 | ARRAY_SIZE(xt_connmark_target)); |
125 | if (ret) | ||
126 | return ret; | ||
127 | |||
128 | ret = xt_register_target(&connmark6_reg); | ||
129 | if (ret) | ||
130 | xt_unregister_target(&connmark_reg); | ||
131 | |||
132 | return ret; | ||
133 | } | 171 | } |
134 | 172 | ||
135 | static void __exit xt_connmark_fini(void) | 173 | static void __exit xt_connmark_fini(void) |
136 | { | 174 | { |
137 | xt_unregister_target(&connmark_reg); | 175 | xt_unregister_targets(xt_connmark_target, |
138 | xt_unregister_target(&connmark6_reg); | 176 | ARRAY_SIZE(xt_connmark_target)); |
139 | } | 177 | } |
140 | 178 | ||
141 | module_init(xt_connmark_init); | 179 | module_init(xt_connmark_init); |
diff --git a/net/netfilter/xt_CONNSECMARK.c b/net/netfilter/xt_CONNSECMARK.c index 8c011e020769..467386266674 100644 --- a/net/netfilter/xt_CONNSECMARK.c +++ b/net/netfilter/xt_CONNSECMARK.c | |||
@@ -66,7 +66,7 @@ static void secmark_restore(struct sk_buff *skb) | |||
66 | static unsigned int target(struct sk_buff **pskb, const struct net_device *in, | 66 | static unsigned int target(struct sk_buff **pskb, const struct net_device *in, |
67 | const struct net_device *out, unsigned int hooknum, | 67 | const struct net_device *out, unsigned int hooknum, |
68 | const struct xt_target *target, | 68 | const struct xt_target *target, |
69 | const void *targinfo, void *userinfo) | 69 | const void *targinfo) |
70 | { | 70 | { |
71 | struct sk_buff *skb = *pskb; | 71 | struct sk_buff *skb = *pskb; |
72 | const struct xt_connsecmark_target_info *info = targinfo; | 72 | const struct xt_connsecmark_target_info *info = targinfo; |
@@ -89,7 +89,7 @@ static unsigned int target(struct sk_buff **pskb, const struct net_device *in, | |||
89 | 89 | ||
90 | static int checkentry(const char *tablename, const void *entry, | 90 | static int checkentry(const char *tablename, const void *entry, |
91 | const struct xt_target *target, void *targinfo, | 91 | const struct xt_target *target, void *targinfo, |
92 | unsigned int targinfosize, unsigned int hook_mask) | 92 | unsigned int hook_mask) |
93 | { | 93 | { |
94 | struct xt_connsecmark_target_info *info = targinfo; | 94 | struct xt_connsecmark_target_info *info = targinfo; |
95 | 95 | ||
@@ -106,49 +106,38 @@ static int checkentry(const char *tablename, const void *entry, | |||
106 | return 1; | 106 | return 1; |
107 | } | 107 | } |
108 | 108 | ||
109 | static struct xt_target ipt_connsecmark_reg = { | 109 | static struct xt_target xt_connsecmark_target[] = { |
110 | .name = "CONNSECMARK", | 110 | { |
111 | .target = target, | 111 | .name = "CONNSECMARK", |
112 | .targetsize = sizeof(struct xt_connsecmark_target_info), | 112 | .family = AF_INET, |
113 | .table = "mangle", | 113 | .checkentry = checkentry, |
114 | .checkentry = checkentry, | 114 | .target = target, |
115 | .me = THIS_MODULE, | 115 | .targetsize = sizeof(struct xt_connsecmark_target_info), |
116 | .family = AF_INET, | 116 | .table = "mangle", |
117 | .revision = 0, | 117 | .me = THIS_MODULE, |
118 | }; | 118 | }, |
119 | 119 | { | |
120 | static struct xt_target ip6t_connsecmark_reg = { | 120 | .name = "CONNSECMARK", |
121 | .name = "CONNSECMARK", | 121 | .family = AF_INET6, |
122 | .target = target, | 122 | .checkentry = checkentry, |
123 | .targetsize = sizeof(struct xt_connsecmark_target_info), | 123 | .target = target, |
124 | .table = "mangle", | 124 | .targetsize = sizeof(struct xt_connsecmark_target_info), |
125 | .checkentry = checkentry, | 125 | .table = "mangle", |
126 | .me = THIS_MODULE, | 126 | .me = THIS_MODULE, |
127 | .family = AF_INET6, | 127 | }, |
128 | .revision = 0, | ||
129 | }; | 128 | }; |
130 | 129 | ||
131 | static int __init xt_connsecmark_init(void) | 130 | static int __init xt_connsecmark_init(void) |
132 | { | 131 | { |
133 | int err; | ||
134 | |||
135 | need_conntrack(); | 132 | need_conntrack(); |
136 | 133 | return xt_register_targets(xt_connsecmark_target, | |
137 | err = xt_register_target(&ipt_connsecmark_reg); | 134 | ARRAY_SIZE(xt_connsecmark_target)); |
138 | if (err) | ||
139 | return err; | ||
140 | |||
141 | err = xt_register_target(&ip6t_connsecmark_reg); | ||
142 | if (err) | ||
143 | xt_unregister_target(&ipt_connsecmark_reg); | ||
144 | |||
145 | return err; | ||
146 | } | 135 | } |
147 | 136 | ||
148 | static void __exit xt_connsecmark_fini(void) | 137 | static void __exit xt_connsecmark_fini(void) |
149 | { | 138 | { |
150 | xt_unregister_target(&ip6t_connsecmark_reg); | 139 | xt_unregister_targets(xt_connsecmark_target, |
151 | xt_unregister_target(&ipt_connsecmark_reg); | 140 | ARRAY_SIZE(xt_connsecmark_target)); |
152 | } | 141 | } |
153 | 142 | ||
154 | module_init(xt_connsecmark_init); | 143 | module_init(xt_connsecmark_init); |
diff --git a/net/netfilter/xt_DSCP.c b/net/netfilter/xt_DSCP.c new file mode 100644 index 000000000000..a7cc75aeb38d --- /dev/null +++ b/net/netfilter/xt_DSCP.c | |||
@@ -0,0 +1,118 @@ | |||
1 | /* x_tables module for setting the IPv4/IPv6 DSCP field, Version 1.8 | ||
2 | * | ||
3 | * (C) 2002 by Harald Welte <laforge@netfilter.org> | ||
4 | * based on ipt_FTOS.c (C) 2000 by Matthew G. Marsh <mgm@paktronix.com> | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License version 2 as | ||
8 | * published by the Free Software Foundation. | ||
9 | * | ||
10 | * See RFC2474 for a description of the DSCP field within the IP Header. | ||
11 | * | ||
12 | * xt_DSCP.c,v 1.8 2002/08/06 18:41:57 laforge Exp | ||
13 | */ | ||
14 | |||
15 | #include <linux/module.h> | ||
16 | #include <linux/skbuff.h> | ||
17 | #include <linux/ip.h> | ||
18 | #include <linux/ipv6.h> | ||
19 | #include <net/dsfield.h> | ||
20 | |||
21 | #include <linux/netfilter/x_tables.h> | ||
22 | #include <linux/netfilter/xt_DSCP.h> | ||
23 | |||
24 | MODULE_AUTHOR("Harald Welte <laforge@netfilter.org>"); | ||
25 | MODULE_DESCRIPTION("x_tables DSCP modification module"); | ||
26 | MODULE_LICENSE("GPL"); | ||
27 | MODULE_ALIAS("ipt_DSCP"); | ||
28 | MODULE_ALIAS("ip6t_DSCP"); | ||
29 | |||
30 | static unsigned int target(struct sk_buff **pskb, | ||
31 | const struct net_device *in, | ||
32 | const struct net_device *out, | ||
33 | unsigned int hooknum, | ||
34 | const struct xt_target *target, | ||
35 | const void *targinfo) | ||
36 | { | ||
37 | const struct xt_DSCP_info *dinfo = targinfo; | ||
38 | u_int8_t dscp = ipv4_get_dsfield((*pskb)->nh.iph) >> XT_DSCP_SHIFT; | ||
39 | |||
40 | if (dscp != dinfo->dscp) { | ||
41 | if (!skb_make_writable(pskb, sizeof(struct iphdr))) | ||
42 | return NF_DROP; | ||
43 | |||
44 | ipv4_change_dsfield((*pskb)->nh.iph, (__u8)(~XT_DSCP_MASK), | ||
45 | dinfo->dscp << XT_DSCP_SHIFT); | ||
46 | |||
47 | } | ||
48 | return XT_CONTINUE; | ||
49 | } | ||
50 | |||
51 | static unsigned int target6(struct sk_buff **pskb, | ||
52 | const struct net_device *in, | ||
53 | const struct net_device *out, | ||
54 | unsigned int hooknum, | ||
55 | const struct xt_target *target, | ||
56 | const void *targinfo) | ||
57 | { | ||
58 | const struct xt_DSCP_info *dinfo = targinfo; | ||
59 | u_int8_t dscp = ipv6_get_dsfield((*pskb)->nh.ipv6h) >> XT_DSCP_SHIFT; | ||
60 | |||
61 | if (dscp != dinfo->dscp) { | ||
62 | if (!skb_make_writable(pskb, sizeof(struct ipv6hdr))) | ||
63 | return NF_DROP; | ||
64 | |||
65 | ipv6_change_dsfield((*pskb)->nh.ipv6h, (__u8)(~XT_DSCP_MASK), | ||
66 | dinfo->dscp << XT_DSCP_SHIFT); | ||
67 | } | ||
68 | return XT_CONTINUE; | ||
69 | } | ||
70 | |||
71 | static int checkentry(const char *tablename, | ||
72 | const void *e_void, | ||
73 | const struct xt_target *target, | ||
74 | void *targinfo, | ||
75 | unsigned int hook_mask) | ||
76 | { | ||
77 | const u_int8_t dscp = ((struct xt_DSCP_info *)targinfo)->dscp; | ||
78 | |||
79 | if ((dscp > XT_DSCP_MAX)) { | ||
80 | printk(KERN_WARNING "DSCP: dscp %x out of range\n", dscp); | ||
81 | return 0; | ||
82 | } | ||
83 | return 1; | ||
84 | } | ||
85 | |||
86 | static struct xt_target xt_dscp_target[] = { | ||
87 | { | ||
88 | .name = "DSCP", | ||
89 | .family = AF_INET, | ||
90 | .checkentry = checkentry, | ||
91 | .target = target, | ||
92 | .targetsize = sizeof(struct xt_DSCP_info), | ||
93 | .table = "mangle", | ||
94 | .me = THIS_MODULE, | ||
95 | }, | ||
96 | { | ||
97 | .name = "DSCP", | ||
98 | .family = AF_INET6, | ||
99 | .checkentry = checkentry, | ||
100 | .target = target6, | ||
101 | .targetsize = sizeof(struct xt_DSCP_info), | ||
102 | .table = "mangle", | ||
103 | .me = THIS_MODULE, | ||
104 | }, | ||
105 | }; | ||
106 | |||
107 | static int __init xt_dscp_target_init(void) | ||
108 | { | ||
109 | return xt_register_targets(xt_dscp_target, ARRAY_SIZE(xt_dscp_target)); | ||
110 | } | ||
111 | |||
112 | static void __exit xt_dscp_target_fini(void) | ||
113 | { | ||
114 | xt_unregister_targets(xt_dscp_target, ARRAY_SIZE(xt_dscp_target)); | ||
115 | } | ||
116 | |||
117 | module_init(xt_dscp_target_init); | ||
118 | module_exit(xt_dscp_target_fini); | ||
diff --git a/net/netfilter/xt_MARK.c b/net/netfilter/xt_MARK.c index ee9c34edc76c..c6e860a7114f 100644 --- a/net/netfilter/xt_MARK.c +++ b/net/netfilter/xt_MARK.c | |||
@@ -27,8 +27,7 @@ target_v0(struct sk_buff **pskb, | |||
27 | const struct net_device *out, | 27 | const struct net_device *out, |
28 | unsigned int hooknum, | 28 | unsigned int hooknum, |
29 | const struct xt_target *target, | 29 | const struct xt_target *target, |
30 | const void *targinfo, | 30 | const void *targinfo) |
31 | void *userinfo) | ||
32 | { | 31 | { |
33 | const struct xt_mark_target_info *markinfo = targinfo; | 32 | const struct xt_mark_target_info *markinfo = targinfo; |
34 | 33 | ||
@@ -44,8 +43,7 @@ target_v1(struct sk_buff **pskb, | |||
44 | const struct net_device *out, | 43 | const struct net_device *out, |
45 | unsigned int hooknum, | 44 | unsigned int hooknum, |
46 | const struct xt_target *target, | 45 | const struct xt_target *target, |
47 | const void *targinfo, | 46 | const void *targinfo) |
48 | void *userinfo) | ||
49 | { | 47 | { |
50 | const struct xt_mark_target_info_v1 *markinfo = targinfo; | 48 | const struct xt_mark_target_info_v1 *markinfo = targinfo; |
51 | int mark = 0; | 49 | int mark = 0; |
@@ -76,7 +74,6 @@ checkentry_v0(const char *tablename, | |||
76 | const void *entry, | 74 | const void *entry, |
77 | const struct xt_target *target, | 75 | const struct xt_target *target, |
78 | void *targinfo, | 76 | void *targinfo, |
79 | unsigned int targinfosize, | ||
80 | unsigned int hook_mask) | 77 | unsigned int hook_mask) |
81 | { | 78 | { |
82 | struct xt_mark_target_info *markinfo = targinfo; | 79 | struct xt_mark_target_info *markinfo = targinfo; |
@@ -93,7 +90,6 @@ checkentry_v1(const char *tablename, | |||
93 | const void *entry, | 90 | const void *entry, |
94 | const struct xt_target *target, | 91 | const struct xt_target *target, |
95 | void *targinfo, | 92 | void *targinfo, |
96 | unsigned int targinfosize, | ||
97 | unsigned int hook_mask) | 93 | unsigned int hook_mask) |
98 | { | 94 | { |
99 | struct xt_mark_target_info_v1 *markinfo = targinfo; | 95 | struct xt_mark_target_info_v1 *markinfo = targinfo; |
@@ -112,65 +108,81 @@ checkentry_v1(const char *tablename, | |||
112 | return 1; | 108 | return 1; |
113 | } | 109 | } |
114 | 110 | ||
115 | static struct xt_target ipt_mark_reg_v0 = { | 111 | #ifdef CONFIG_COMPAT |
116 | .name = "MARK", | 112 | struct compat_xt_mark_target_info_v1 { |
117 | .target = target_v0, | 113 | compat_ulong_t mark; |
118 | .targetsize = sizeof(struct xt_mark_target_info), | 114 | u_int8_t mode; |
119 | .table = "mangle", | 115 | u_int8_t __pad1; |
120 | .checkentry = checkentry_v0, | 116 | u_int16_t __pad2; |
121 | .me = THIS_MODULE, | ||
122 | .family = AF_INET, | ||
123 | .revision = 0, | ||
124 | }; | 117 | }; |
125 | 118 | ||
126 | static struct xt_target ipt_mark_reg_v1 = { | 119 | static void compat_from_user_v1(void *dst, void *src) |
127 | .name = "MARK", | 120 | { |
128 | .target = target_v1, | 121 | struct compat_xt_mark_target_info_v1 *cm = src; |
129 | .targetsize = sizeof(struct xt_mark_target_info_v1), | 122 | struct xt_mark_target_info_v1 m = { |
130 | .table = "mangle", | 123 | .mark = cm->mark, |
131 | .checkentry = checkentry_v1, | 124 | .mode = cm->mode, |
132 | .me = THIS_MODULE, | 125 | }; |
133 | .family = AF_INET, | 126 | memcpy(dst, &m, sizeof(m)); |
134 | .revision = 1, | 127 | } |
135 | }; | ||
136 | 128 | ||
137 | static struct xt_target ip6t_mark_reg_v0 = { | 129 | static int compat_to_user_v1(void __user *dst, void *src) |
138 | .name = "MARK", | 130 | { |
139 | .target = target_v0, | 131 | struct xt_mark_target_info_v1 *m = src; |
140 | .targetsize = sizeof(struct xt_mark_target_info), | 132 | struct compat_xt_mark_target_info_v1 cm = { |
141 | .table = "mangle", | 133 | .mark = m->mark, |
142 | .checkentry = checkentry_v0, | 134 | .mode = m->mode, |
143 | .me = THIS_MODULE, | 135 | }; |
144 | .family = AF_INET6, | 136 | return copy_to_user(dst, &cm, sizeof(cm)) ? -EFAULT : 0; |
145 | .revision = 0, | 137 | } |
138 | #endif /* CONFIG_COMPAT */ | ||
139 | |||
140 | static struct xt_target xt_mark_target[] = { | ||
141 | { | ||
142 | .name = "MARK", | ||
143 | .family = AF_INET, | ||
144 | .revision = 0, | ||
145 | .checkentry = checkentry_v0, | ||
146 | .target = target_v0, | ||
147 | .targetsize = sizeof(struct xt_mark_target_info), | ||
148 | .table = "mangle", | ||
149 | .me = THIS_MODULE, | ||
150 | }, | ||
151 | { | ||
152 | .name = "MARK", | ||
153 | .family = AF_INET, | ||
154 | .revision = 1, | ||
155 | .checkentry = checkentry_v1, | ||
156 | .target = target_v1, | ||
157 | .targetsize = sizeof(struct xt_mark_target_info_v1), | ||
158 | #ifdef CONFIG_COMPAT | ||
159 | .compatsize = sizeof(struct compat_xt_mark_target_info_v1), | ||
160 | .compat_from_user = compat_from_user_v1, | ||
161 | .compat_to_user = compat_to_user_v1, | ||
162 | #endif | ||
163 | .table = "mangle", | ||
164 | .me = THIS_MODULE, | ||
165 | }, | ||
166 | { | ||
167 | .name = "MARK", | ||
168 | .family = AF_INET6, | ||
169 | .revision = 0, | ||
170 | .checkentry = checkentry_v0, | ||
171 | .target = target_v0, | ||
172 | .targetsize = sizeof(struct xt_mark_target_info), | ||
173 | .table = "mangle", | ||
174 | .me = THIS_MODULE, | ||
175 | }, | ||
146 | }; | 176 | }; |
147 | 177 | ||
148 | static int __init xt_mark_init(void) | 178 | static int __init xt_mark_init(void) |
149 | { | 179 | { |
150 | int err; | 180 | return xt_register_targets(xt_mark_target, ARRAY_SIZE(xt_mark_target)); |
151 | |||
152 | err = xt_register_target(&ipt_mark_reg_v0); | ||
153 | if (err) | ||
154 | return err; | ||
155 | |||
156 | err = xt_register_target(&ipt_mark_reg_v1); | ||
157 | if (err) | ||
158 | xt_unregister_target(&ipt_mark_reg_v0); | ||
159 | |||
160 | err = xt_register_target(&ip6t_mark_reg_v0); | ||
161 | if (err) { | ||
162 | xt_unregister_target(&ipt_mark_reg_v0); | ||
163 | xt_unregister_target(&ipt_mark_reg_v1); | ||
164 | } | ||
165 | |||
166 | return err; | ||
167 | } | 181 | } |
168 | 182 | ||
169 | static void __exit xt_mark_fini(void) | 183 | static void __exit xt_mark_fini(void) |
170 | { | 184 | { |
171 | xt_unregister_target(&ipt_mark_reg_v0); | 185 | xt_unregister_targets(xt_mark_target, ARRAY_SIZE(xt_mark_target)); |
172 | xt_unregister_target(&ipt_mark_reg_v1); | ||
173 | xt_unregister_target(&ip6t_mark_reg_v0); | ||
174 | } | 186 | } |
175 | 187 | ||
176 | module_init(xt_mark_init); | 188 | module_init(xt_mark_init); |
diff --git a/net/netfilter/xt_NFQUEUE.c b/net/netfilter/xt_NFQUEUE.c index 86ccceb61fdd..db9b896e57c8 100644 --- a/net/netfilter/xt_NFQUEUE.c +++ b/net/netfilter/xt_NFQUEUE.c | |||
@@ -29,65 +29,46 @@ target(struct sk_buff **pskb, | |||
29 | const struct net_device *out, | 29 | const struct net_device *out, |
30 | unsigned int hooknum, | 30 | unsigned int hooknum, |
31 | const struct xt_target *target, | 31 | const struct xt_target *target, |
32 | const void *targinfo, | 32 | const void *targinfo) |
33 | void *userinfo) | ||
34 | { | 33 | { |
35 | const struct xt_NFQ_info *tinfo = targinfo; | 34 | const struct xt_NFQ_info *tinfo = targinfo; |
36 | 35 | ||
37 | return NF_QUEUE_NR(tinfo->queuenum); | 36 | return NF_QUEUE_NR(tinfo->queuenum); |
38 | } | 37 | } |
39 | 38 | ||
40 | static struct xt_target ipt_NFQ_reg = { | 39 | static struct xt_target xt_nfqueue_target[] = { |
41 | .name = "NFQUEUE", | 40 | { |
42 | .target = target, | 41 | .name = "NFQUEUE", |
43 | .targetsize = sizeof(struct xt_NFQ_info), | 42 | .family = AF_INET, |
44 | .family = AF_INET, | 43 | .target = target, |
45 | .me = THIS_MODULE, | 44 | .targetsize = sizeof(struct xt_NFQ_info), |
46 | }; | 45 | .me = THIS_MODULE, |
47 | 46 | }, | |
48 | static struct xt_target ip6t_NFQ_reg = { | 47 | { |
49 | .name = "NFQUEUE", | 48 | .name = "NFQUEUE", |
50 | .target = target, | 49 | .family = AF_INET6, |
51 | .targetsize = sizeof(struct xt_NFQ_info), | 50 | .target = target, |
52 | .family = AF_INET6, | 51 | .targetsize = sizeof(struct xt_NFQ_info), |
53 | .me = THIS_MODULE, | 52 | .me = THIS_MODULE, |
54 | }; | 53 | }, |
55 | 54 | { | |
56 | static struct xt_target arpt_NFQ_reg = { | 55 | .name = "NFQUEUE", |
57 | .name = "NFQUEUE", | 56 | .family = NF_ARP, |
58 | .target = target, | 57 | .target = target, |
59 | .targetsize = sizeof(struct xt_NFQ_info), | 58 | .targetsize = sizeof(struct xt_NFQ_info), |
60 | .family = NF_ARP, | 59 | .me = THIS_MODULE, |
61 | .me = THIS_MODULE, | 60 | }, |
62 | }; | 61 | }; |
63 | 62 | ||
64 | static int __init xt_nfqueue_init(void) | 63 | static int __init xt_nfqueue_init(void) |
65 | { | 64 | { |
66 | int ret; | 65 | return xt_register_targets(xt_nfqueue_target, |
67 | ret = xt_register_target(&ipt_NFQ_reg); | 66 | ARRAY_SIZE(xt_nfqueue_target)); |
68 | if (ret) | ||
69 | return ret; | ||
70 | ret = xt_register_target(&ip6t_NFQ_reg); | ||
71 | if (ret) | ||
72 | goto out_ip; | ||
73 | ret = xt_register_target(&arpt_NFQ_reg); | ||
74 | if (ret) | ||
75 | goto out_ip6; | ||
76 | |||
77 | return ret; | ||
78 | out_ip6: | ||
79 | xt_unregister_target(&ip6t_NFQ_reg); | ||
80 | out_ip: | ||
81 | xt_unregister_target(&ipt_NFQ_reg); | ||
82 | |||
83 | return ret; | ||
84 | } | 67 | } |
85 | 68 | ||
86 | static void __exit xt_nfqueue_fini(void) | 69 | static void __exit xt_nfqueue_fini(void) |
87 | { | 70 | { |
88 | xt_unregister_target(&arpt_NFQ_reg); | 71 | xt_register_targets(xt_nfqueue_target, ARRAY_SIZE(xt_nfqueue_target)); |
89 | xt_unregister_target(&ip6t_NFQ_reg); | ||
90 | xt_unregister_target(&ipt_NFQ_reg); | ||
91 | } | 72 | } |
92 | 73 | ||
93 | module_init(xt_nfqueue_init); | 74 | module_init(xt_nfqueue_init); |
diff --git a/net/netfilter/xt_NOTRACK.c b/net/netfilter/xt_NOTRACK.c index 98f4b5363ce8..6d00dcaed238 100644 --- a/net/netfilter/xt_NOTRACK.c +++ b/net/netfilter/xt_NOTRACK.c | |||
@@ -16,8 +16,7 @@ target(struct sk_buff **pskb, | |||
16 | const struct net_device *out, | 16 | const struct net_device *out, |
17 | unsigned int hooknum, | 17 | unsigned int hooknum, |
18 | const struct xt_target *target, | 18 | const struct xt_target *target, |
19 | const void *targinfo, | 19 | const void *targinfo) |
20 | void *userinfo) | ||
21 | { | 20 | { |
22 | /* Previously seen (loopback)? Ignore. */ | 21 | /* Previously seen (loopback)? Ignore. */ |
23 | if ((*pskb)->nfct != NULL) | 22 | if ((*pskb)->nfct != NULL) |
@@ -34,43 +33,32 @@ target(struct sk_buff **pskb, | |||
34 | return XT_CONTINUE; | 33 | return XT_CONTINUE; |
35 | } | 34 | } |
36 | 35 | ||
37 | static struct xt_target notrack_reg = { | 36 | static struct xt_target xt_notrack_target[] = { |
38 | .name = "NOTRACK", | 37 | { |
39 | .target = target, | 38 | .name = "NOTRACK", |
40 | .targetsize = 0, | 39 | .family = AF_INET, |
41 | .table = "raw", | 40 | .target = target, |
42 | .family = AF_INET, | 41 | .table = "raw", |
43 | .me = THIS_MODULE, | 42 | .me = THIS_MODULE, |
44 | }; | 43 | }, |
45 | 44 | { | |
46 | static struct xt_target notrack6_reg = { | 45 | .name = "NOTRACK", |
47 | .name = "NOTRACK", | 46 | .family = AF_INET6, |
48 | .target = target, | 47 | .target = target, |
49 | .targetsize = 0, | 48 | .table = "raw", |
50 | .table = "raw", | 49 | .me = THIS_MODULE, |
51 | .family = AF_INET6, | 50 | }, |
52 | .me = THIS_MODULE, | ||
53 | }; | 51 | }; |
54 | 52 | ||
55 | static int __init xt_notrack_init(void) | 53 | static int __init xt_notrack_init(void) |
56 | { | 54 | { |
57 | int ret; | 55 | return xt_register_targets(xt_notrack_target, |
58 | 56 | ARRAY_SIZE(xt_notrack_target)); | |
59 | ret = xt_register_target(¬rack_reg); | ||
60 | if (ret) | ||
61 | return ret; | ||
62 | |||
63 | ret = xt_register_target(¬rack6_reg); | ||
64 | if (ret) | ||
65 | xt_unregister_target(¬rack_reg); | ||
66 | |||
67 | return ret; | ||
68 | } | 57 | } |
69 | 58 | ||
70 | static void __exit xt_notrack_fini(void) | 59 | static void __exit xt_notrack_fini(void) |
71 | { | 60 | { |
72 | xt_unregister_target(¬rack6_reg); | 61 | xt_unregister_targets(xt_notrack_target, ARRAY_SIZE(xt_notrack_target)); |
73 | xt_unregister_target(¬rack_reg); | ||
74 | } | 62 | } |
75 | 63 | ||
76 | module_init(xt_notrack_init); | 64 | module_init(xt_notrack_init); |
diff --git a/net/netfilter/xt_SECMARK.c b/net/netfilter/xt_SECMARK.c index de9537ad9a7c..add752196290 100644 --- a/net/netfilter/xt_SECMARK.c +++ b/net/netfilter/xt_SECMARK.c | |||
@@ -31,7 +31,7 @@ static u8 mode; | |||
31 | static unsigned int target(struct sk_buff **pskb, const struct net_device *in, | 31 | static unsigned int target(struct sk_buff **pskb, const struct net_device *in, |
32 | const struct net_device *out, unsigned int hooknum, | 32 | const struct net_device *out, unsigned int hooknum, |
33 | const struct xt_target *target, | 33 | const struct xt_target *target, |
34 | const void *targinfo, void *userinfo) | 34 | const void *targinfo) |
35 | { | 35 | { |
36 | u32 secmark = 0; | 36 | u32 secmark = 0; |
37 | const struct xt_secmark_target_info *info = targinfo; | 37 | const struct xt_secmark_target_info *info = targinfo; |
@@ -85,7 +85,7 @@ static int checkentry_selinux(struct xt_secmark_target_info *info) | |||
85 | 85 | ||
86 | static int checkentry(const char *tablename, const void *entry, | 86 | static int checkentry(const char *tablename, const void *entry, |
87 | const struct xt_target *target, void *targinfo, | 87 | const struct xt_target *target, void *targinfo, |
88 | unsigned int targinfosize, unsigned int hook_mask) | 88 | unsigned int hook_mask) |
89 | { | 89 | { |
90 | struct xt_secmark_target_info *info = targinfo; | 90 | struct xt_secmark_target_info *info = targinfo; |
91 | 91 | ||
@@ -111,47 +111,36 @@ static int checkentry(const char *tablename, const void *entry, | |||
111 | return 1; | 111 | return 1; |
112 | } | 112 | } |
113 | 113 | ||
114 | static struct xt_target ipt_secmark_reg = { | 114 | static struct xt_target xt_secmark_target[] = { |
115 | .name = "SECMARK", | 115 | { |
116 | .target = target, | 116 | .name = "SECMARK", |
117 | .targetsize = sizeof(struct xt_secmark_target_info), | 117 | .family = AF_INET, |
118 | .table = "mangle", | 118 | .checkentry = checkentry, |
119 | .checkentry = checkentry, | 119 | .target = target, |
120 | .me = THIS_MODULE, | 120 | .targetsize = sizeof(struct xt_secmark_target_info), |
121 | .family = AF_INET, | 121 | .table = "mangle", |
122 | .revision = 0, | 122 | .me = THIS_MODULE, |
123 | }; | 123 | }, |
124 | 124 | { | |
125 | static struct xt_target ip6t_secmark_reg = { | 125 | .name = "SECMARK", |
126 | .name = "SECMARK", | 126 | .family = AF_INET6, |
127 | .target = target, | 127 | .checkentry = checkentry, |
128 | .targetsize = sizeof(struct xt_secmark_target_info), | 128 | .target = target, |
129 | .table = "mangle", | 129 | .targetsize = sizeof(struct xt_secmark_target_info), |
130 | .checkentry = checkentry, | 130 | .table = "mangle", |
131 | .me = THIS_MODULE, | 131 | .me = THIS_MODULE, |
132 | .family = AF_INET6, | 132 | }, |
133 | .revision = 0, | ||
134 | }; | 133 | }; |
135 | 134 | ||
136 | static int __init xt_secmark_init(void) | 135 | static int __init xt_secmark_init(void) |
137 | { | 136 | { |
138 | int err; | 137 | return xt_register_targets(xt_secmark_target, |
139 | 138 | ARRAY_SIZE(xt_secmark_target)); | |
140 | err = xt_register_target(&ipt_secmark_reg); | ||
141 | if (err) | ||
142 | return err; | ||
143 | |||
144 | err = xt_register_target(&ip6t_secmark_reg); | ||
145 | if (err) | ||
146 | xt_unregister_target(&ipt_secmark_reg); | ||
147 | |||
148 | return err; | ||
149 | } | 139 | } |
150 | 140 | ||
151 | static void __exit xt_secmark_fini(void) | 141 | static void __exit xt_secmark_fini(void) |
152 | { | 142 | { |
153 | xt_unregister_target(&ip6t_secmark_reg); | 143 | xt_unregister_targets(xt_secmark_target, ARRAY_SIZE(xt_secmark_target)); |
154 | xt_unregister_target(&ipt_secmark_reg); | ||
155 | } | 144 | } |
156 | 145 | ||
157 | module_init(xt_secmark_init); | 146 | module_init(xt_secmark_init); |
diff --git a/net/netfilter/xt_comment.c b/net/netfilter/xt_comment.c index 197609cb06d7..7db492d65220 100644 --- a/net/netfilter/xt_comment.c +++ b/net/netfilter/xt_comment.c | |||
@@ -29,41 +29,32 @@ match(const struct sk_buff *skb, | |||
29 | return 1; | 29 | return 1; |
30 | } | 30 | } |
31 | 31 | ||
32 | static struct xt_match comment_match = { | 32 | static struct xt_match xt_comment_match[] = { |
33 | .name = "comment", | 33 | { |
34 | .match = match, | 34 | .name = "comment", |
35 | .matchsize = sizeof(struct xt_comment_info), | 35 | .family = AF_INET, |
36 | .family = AF_INET, | 36 | .match = match, |
37 | .me = THIS_MODULE | 37 | .matchsize = sizeof(struct xt_comment_info), |
38 | }; | 38 | .me = THIS_MODULE |
39 | 39 | }, | |
40 | static struct xt_match comment6_match = { | 40 | { |
41 | .name = "comment", | 41 | .name = "comment", |
42 | .match = match, | 42 | .family = AF_INET6, |
43 | .matchsize = sizeof(struct xt_comment_info), | 43 | .match = match, |
44 | .family = AF_INET6, | 44 | .matchsize = sizeof(struct xt_comment_info), |
45 | .me = THIS_MODULE | 45 | .me = THIS_MODULE |
46 | }, | ||
46 | }; | 47 | }; |
47 | 48 | ||
48 | static int __init xt_comment_init(void) | 49 | static int __init xt_comment_init(void) |
49 | { | 50 | { |
50 | int ret; | 51 | return xt_register_matches(xt_comment_match, |
51 | 52 | ARRAY_SIZE(xt_comment_match)); | |
52 | ret = xt_register_match(&comment_match); | ||
53 | if (ret) | ||
54 | return ret; | ||
55 | |||
56 | ret = xt_register_match(&comment6_match); | ||
57 | if (ret) | ||
58 | xt_unregister_match(&comment_match); | ||
59 | |||
60 | return ret; | ||
61 | } | 53 | } |
62 | 54 | ||
63 | static void __exit xt_comment_fini(void) | 55 | static void __exit xt_comment_fini(void) |
64 | { | 56 | { |
65 | xt_unregister_match(&comment_match); | 57 | xt_unregister_matches(xt_comment_match, ARRAY_SIZE(xt_comment_match)); |
66 | xt_unregister_match(&comment6_match); | ||
67 | } | 58 | } |
68 | 59 | ||
69 | module_init(xt_comment_init); | 60 | module_init(xt_comment_init); |
diff --git a/net/netfilter/xt_connbytes.c b/net/netfilter/xt_connbytes.c index 1396fe2d07c1..dcc497ea8183 100644 --- a/net/netfilter/xt_connbytes.c +++ b/net/netfilter/xt_connbytes.c | |||
@@ -125,7 +125,6 @@ static int check(const char *tablename, | |||
125 | const void *ip, | 125 | const void *ip, |
126 | const struct xt_match *match, | 126 | const struct xt_match *match, |
127 | void *matchinfo, | 127 | void *matchinfo, |
128 | unsigned int matchsize, | ||
129 | unsigned int hook_mask) | 128 | unsigned int hook_mask) |
130 | { | 129 | { |
131 | const struct xt_connbytes_info *sinfo = matchinfo; | 130 | const struct xt_connbytes_info *sinfo = matchinfo; |
@@ -143,40 +142,35 @@ static int check(const char *tablename, | |||
143 | return 1; | 142 | return 1; |
144 | } | 143 | } |
145 | 144 | ||
146 | static struct xt_match connbytes_match = { | 145 | static struct xt_match xt_connbytes_match[] = { |
147 | .name = "connbytes", | 146 | { |
148 | .match = match, | 147 | .name = "connbytes", |
149 | .checkentry = check, | 148 | .family = AF_INET, |
150 | .matchsize = sizeof(struct xt_connbytes_info), | 149 | .checkentry = check, |
151 | .family = AF_INET, | 150 | .match = match, |
152 | .me = THIS_MODULE | 151 | .matchsize = sizeof(struct xt_connbytes_info), |
153 | }; | 152 | .me = THIS_MODULE |
154 | static struct xt_match connbytes6_match = { | 153 | }, |
155 | .name = "connbytes", | 154 | { |
156 | .match = match, | 155 | .name = "connbytes", |
157 | .checkentry = check, | 156 | .family = AF_INET6, |
158 | .matchsize = sizeof(struct xt_connbytes_info), | 157 | .checkentry = check, |
159 | .family = AF_INET6, | 158 | .match = match, |
160 | .me = THIS_MODULE | 159 | .matchsize = sizeof(struct xt_connbytes_info), |
160 | .me = THIS_MODULE | ||
161 | }, | ||
161 | }; | 162 | }; |
162 | 163 | ||
163 | static int __init xt_connbytes_init(void) | 164 | static int __init xt_connbytes_init(void) |
164 | { | 165 | { |
165 | int ret; | 166 | return xt_register_matches(xt_connbytes_match, |
166 | ret = xt_register_match(&connbytes_match); | 167 | ARRAY_SIZE(xt_connbytes_match)); |
167 | if (ret) | ||
168 | return ret; | ||
169 | |||
170 | ret = xt_register_match(&connbytes6_match); | ||
171 | if (ret) | ||
172 | xt_unregister_match(&connbytes_match); | ||
173 | return ret; | ||
174 | } | 168 | } |
175 | 169 | ||
176 | static void __exit xt_connbytes_fini(void) | 170 | static void __exit xt_connbytes_fini(void) |
177 | { | 171 | { |
178 | xt_unregister_match(&connbytes_match); | 172 | xt_unregister_matches(xt_connbytes_match, |
179 | xt_unregister_match(&connbytes6_match); | 173 | ARRAY_SIZE(xt_connbytes_match)); |
180 | } | 174 | } |
181 | 175 | ||
182 | module_init(xt_connbytes_init); | 176 | module_init(xt_connbytes_init); |
diff --git a/net/netfilter/xt_connmark.c b/net/netfilter/xt_connmark.c index 56324c8aff0a..92a5726ef237 100644 --- a/net/netfilter/xt_connmark.c +++ b/net/netfilter/xt_connmark.c | |||
@@ -55,7 +55,6 @@ checkentry(const char *tablename, | |||
55 | const void *ip, | 55 | const void *ip, |
56 | const struct xt_match *match, | 56 | const struct xt_match *match, |
57 | void *matchinfo, | 57 | void *matchinfo, |
58 | unsigned int matchsize, | ||
59 | unsigned int hook_mask) | 58 | unsigned int hook_mask) |
60 | { | 59 | { |
61 | struct xt_connmark_info *cm = matchinfo; | 60 | struct xt_connmark_info *cm = matchinfo; |
@@ -75,53 +74,80 @@ checkentry(const char *tablename, | |||
75 | } | 74 | } |
76 | 75 | ||
77 | static void | 76 | static void |
78 | destroy(const struct xt_match *match, void *matchinfo, unsigned int matchsize) | 77 | destroy(const struct xt_match *match, void *matchinfo) |
79 | { | 78 | { |
80 | #if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE) | 79 | #if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE) |
81 | nf_ct_l3proto_module_put(match->family); | 80 | nf_ct_l3proto_module_put(match->family); |
82 | #endif | 81 | #endif |
83 | } | 82 | } |
84 | 83 | ||
85 | static struct xt_match connmark_match = { | 84 | #ifdef CONFIG_COMPAT |
86 | .name = "connmark", | 85 | struct compat_xt_connmark_info { |
87 | .match = match, | 86 | compat_ulong_t mark, mask; |
88 | .matchsize = sizeof(struct xt_connmark_info), | 87 | u_int8_t invert; |
89 | .checkentry = checkentry, | 88 | u_int8_t __pad1; |
90 | .destroy = destroy, | 89 | u_int16_t __pad2; |
91 | .family = AF_INET, | ||
92 | .me = THIS_MODULE | ||
93 | }; | 90 | }; |
94 | 91 | ||
95 | static struct xt_match connmark6_match = { | 92 | static void compat_from_user(void *dst, void *src) |
96 | .name = "connmark", | 93 | { |
97 | .match = match, | 94 | struct compat_xt_connmark_info *cm = src; |
98 | .matchsize = sizeof(struct xt_connmark_info), | 95 | struct xt_connmark_info m = { |
99 | .checkentry = checkentry, | 96 | .mark = cm->mark, |
100 | .destroy = destroy, | 97 | .mask = cm->mask, |
101 | .family = AF_INET6, | 98 | .invert = cm->invert, |
102 | .me = THIS_MODULE | 99 | }; |
100 | memcpy(dst, &m, sizeof(m)); | ||
101 | } | ||
102 | |||
103 | static int compat_to_user(void __user *dst, void *src) | ||
104 | { | ||
105 | struct xt_connmark_info *m = src; | ||
106 | struct compat_xt_connmark_info cm = { | ||
107 | .mark = m->mark, | ||
108 | .mask = m->mask, | ||
109 | .invert = m->invert, | ||
110 | }; | ||
111 | return copy_to_user(dst, &cm, sizeof(cm)) ? -EFAULT : 0; | ||
112 | } | ||
113 | #endif /* CONFIG_COMPAT */ | ||
114 | |||
115 | static struct xt_match xt_connmark_match[] = { | ||
116 | { | ||
117 | .name = "connmark", | ||
118 | .family = AF_INET, | ||
119 | .checkentry = checkentry, | ||
120 | .match = match, | ||
121 | .destroy = destroy, | ||
122 | .matchsize = sizeof(struct xt_connmark_info), | ||
123 | #ifdef CONFIG_COMPAT | ||
124 | .compatsize = sizeof(struct compat_xt_connmark_info), | ||
125 | .compat_from_user = compat_from_user, | ||
126 | .compat_to_user = compat_to_user, | ||
127 | #endif | ||
128 | .me = THIS_MODULE | ||
129 | }, | ||
130 | { | ||
131 | .name = "connmark", | ||
132 | .family = AF_INET6, | ||
133 | .checkentry = checkentry, | ||
134 | .match = match, | ||
135 | .destroy = destroy, | ||
136 | .matchsize = sizeof(struct xt_connmark_info), | ||
137 | .me = THIS_MODULE | ||
138 | }, | ||
103 | }; | 139 | }; |
104 | 140 | ||
105 | static int __init xt_connmark_init(void) | 141 | static int __init xt_connmark_init(void) |
106 | { | 142 | { |
107 | int ret; | ||
108 | |||
109 | need_conntrack(); | 143 | need_conntrack(); |
110 | 144 | return xt_register_matches(xt_connmark_match, | |
111 | ret = xt_register_match(&connmark_match); | 145 | ARRAY_SIZE(xt_connmark_match)); |
112 | if (ret) | ||
113 | return ret; | ||
114 | |||
115 | ret = xt_register_match(&connmark6_match); | ||
116 | if (ret) | ||
117 | xt_unregister_match(&connmark_match); | ||
118 | return ret; | ||
119 | } | 146 | } |
120 | 147 | ||
121 | static void __exit xt_connmark_fini(void) | 148 | static void __exit xt_connmark_fini(void) |
122 | { | 149 | { |
123 | xt_unregister_match(&connmark6_match); | 150 | xt_register_matches(xt_connmark_match, ARRAY_SIZE(xt_connmark_match)); |
124 | xt_unregister_match(&connmark_match); | ||
125 | } | 151 | } |
126 | 152 | ||
127 | module_init(xt_connmark_init); | 153 | module_init(xt_connmark_init); |
diff --git a/net/netfilter/xt_conntrack.c b/net/netfilter/xt_conntrack.c index 145489a4c3f2..0ea501a2fda5 100644 --- a/net/netfilter/xt_conntrack.c +++ b/net/netfilter/xt_conntrack.c | |||
@@ -45,7 +45,7 @@ match(const struct sk_buff *skb, | |||
45 | 45 | ||
46 | ct = ip_conntrack_get((struct sk_buff *)skb, &ctinfo); | 46 | ct = ip_conntrack_get((struct sk_buff *)skb, &ctinfo); |
47 | 47 | ||
48 | #define FWINV(bool,invflg) ((bool) ^ !!(sinfo->invflags & invflg)) | 48 | #define FWINV(bool, invflg) ((bool) ^ !!(sinfo->invflags & invflg)) |
49 | 49 | ||
50 | if (ct == &ip_conntrack_untracked) | 50 | if (ct == &ip_conntrack_untracked) |
51 | statebit = XT_CONNTRACK_STATE_UNTRACKED; | 51 | statebit = XT_CONNTRACK_STATE_UNTRACKED; |
@@ -54,63 +54,72 @@ match(const struct sk_buff *skb, | |||
54 | else | 54 | else |
55 | statebit = XT_CONNTRACK_STATE_INVALID; | 55 | statebit = XT_CONNTRACK_STATE_INVALID; |
56 | 56 | ||
57 | if(sinfo->flags & XT_CONNTRACK_STATE) { | 57 | if (sinfo->flags & XT_CONNTRACK_STATE) { |
58 | if (ct) { | 58 | if (ct) { |
59 | if(ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip != | 59 | if (test_bit(IPS_SRC_NAT_BIT, &ct->status)) |
60 | ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip) | ||
61 | statebit |= XT_CONNTRACK_STATE_SNAT; | 60 | statebit |= XT_CONNTRACK_STATE_SNAT; |
62 | 61 | if (test_bit(IPS_DST_NAT_BIT, &ct->status)) | |
63 | if(ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip != | ||
64 | ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.ip) | ||
65 | statebit |= XT_CONNTRACK_STATE_DNAT; | 62 | statebit |= XT_CONNTRACK_STATE_DNAT; |
66 | } | 63 | } |
67 | 64 | if (FWINV((statebit & sinfo->statemask) == 0, | |
68 | if (FWINV((statebit & sinfo->statemask) == 0, XT_CONNTRACK_STATE)) | 65 | XT_CONNTRACK_STATE)) |
69 | return 0; | ||
70 | } | ||
71 | |||
72 | if(sinfo->flags & XT_CONNTRACK_PROTO) { | ||
73 | if (!ct || FWINV(ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.protonum != sinfo->tuple[IP_CT_DIR_ORIGINAL].dst.protonum, XT_CONNTRACK_PROTO)) | ||
74 | return 0; | ||
75 | } | ||
76 | |||
77 | if(sinfo->flags & XT_CONNTRACK_ORIGSRC) { | ||
78 | if (!ct || FWINV((ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip&sinfo->sipmsk[IP_CT_DIR_ORIGINAL].s_addr) != sinfo->tuple[IP_CT_DIR_ORIGINAL].src.ip, XT_CONNTRACK_ORIGSRC)) | ||
79 | return 0; | 66 | return 0; |
80 | } | 67 | } |
81 | 68 | ||
82 | if(sinfo->flags & XT_CONNTRACK_ORIGDST) { | 69 | if (ct == NULL) { |
83 | if (!ct || FWINV((ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip&sinfo->dipmsk[IP_CT_DIR_ORIGINAL].s_addr) != sinfo->tuple[IP_CT_DIR_ORIGINAL].dst.ip, XT_CONNTRACK_ORIGDST)) | 70 | if (sinfo->flags & ~XT_CONNTRACK_STATE) |
84 | return 0; | 71 | return 0; |
72 | return 1; | ||
85 | } | 73 | } |
86 | 74 | ||
87 | if(sinfo->flags & XT_CONNTRACK_REPLSRC) { | 75 | if (sinfo->flags & XT_CONNTRACK_PROTO && |
88 | if (!ct || FWINV((ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.ip&sinfo->sipmsk[IP_CT_DIR_REPLY].s_addr) != sinfo->tuple[IP_CT_DIR_REPLY].src.ip, XT_CONNTRACK_REPLSRC)) | 76 | FWINV(ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.protonum != |
89 | return 0; | 77 | sinfo->tuple[IP_CT_DIR_ORIGINAL].dst.protonum, |
90 | } | 78 | XT_CONNTRACK_PROTO)) |
79 | return 0; | ||
80 | |||
81 | if (sinfo->flags & XT_CONNTRACK_ORIGSRC && | ||
82 | FWINV((ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip & | ||
83 | sinfo->sipmsk[IP_CT_DIR_ORIGINAL].s_addr) != | ||
84 | sinfo->tuple[IP_CT_DIR_ORIGINAL].src.ip, | ||
85 | XT_CONNTRACK_ORIGSRC)) | ||
86 | return 0; | ||
91 | 87 | ||
92 | if(sinfo->flags & XT_CONNTRACK_REPLDST) { | 88 | if (sinfo->flags & XT_CONNTRACK_ORIGDST && |
93 | if (!ct || FWINV((ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip&sinfo->dipmsk[IP_CT_DIR_REPLY].s_addr) != sinfo->tuple[IP_CT_DIR_REPLY].dst.ip, XT_CONNTRACK_REPLDST)) | 89 | FWINV((ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip & |
94 | return 0; | 90 | sinfo->dipmsk[IP_CT_DIR_ORIGINAL].s_addr) != |
95 | } | 91 | sinfo->tuple[IP_CT_DIR_ORIGINAL].dst.ip, |
92 | XT_CONNTRACK_ORIGDST)) | ||
93 | return 0; | ||
96 | 94 | ||
97 | if(sinfo->flags & XT_CONNTRACK_STATUS) { | 95 | if (sinfo->flags & XT_CONNTRACK_REPLSRC && |
98 | if (!ct || FWINV((ct->status & sinfo->statusmask) == 0, XT_CONNTRACK_STATUS)) | 96 | FWINV((ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.ip & |
99 | return 0; | 97 | sinfo->sipmsk[IP_CT_DIR_REPLY].s_addr) != |
100 | } | 98 | sinfo->tuple[IP_CT_DIR_REPLY].src.ip, |
99 | XT_CONNTRACK_REPLSRC)) | ||
100 | return 0; | ||
101 | 101 | ||
102 | if(sinfo->flags & XT_CONNTRACK_EXPIRES) { | 102 | if (sinfo->flags & XT_CONNTRACK_REPLDST && |
103 | unsigned long expires; | 103 | FWINV((ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip & |
104 | sinfo->dipmsk[IP_CT_DIR_REPLY].s_addr) != | ||
105 | sinfo->tuple[IP_CT_DIR_REPLY].dst.ip, | ||
106 | XT_CONNTRACK_REPLDST)) | ||
107 | return 0; | ||
104 | 108 | ||
105 | if(!ct) | 109 | if (sinfo->flags & XT_CONNTRACK_STATUS && |
106 | return 0; | 110 | FWINV((ct->status & sinfo->statusmask) == 0, |
111 | XT_CONNTRACK_STATUS)) | ||
112 | return 0; | ||
107 | 113 | ||
108 | expires = timer_pending(&ct->timeout) ? (ct->timeout.expires - jiffies)/HZ : 0; | 114 | if (sinfo->flags & XT_CONNTRACK_EXPIRES) { |
115 | unsigned long expires = timer_pending(&ct->timeout) ? | ||
116 | (ct->timeout.expires - jiffies)/HZ : 0; | ||
109 | 117 | ||
110 | if (FWINV(!(expires >= sinfo->expires_min && expires <= sinfo->expires_max), XT_CONNTRACK_EXPIRES)) | 118 | if (FWINV(!(expires >= sinfo->expires_min && |
119 | expires <= sinfo->expires_max), | ||
120 | XT_CONNTRACK_EXPIRES)) | ||
111 | return 0; | 121 | return 0; |
112 | } | 122 | } |
113 | |||
114 | return 1; | 123 | return 1; |
115 | } | 124 | } |
116 | 125 | ||
@@ -141,63 +150,72 @@ match(const struct sk_buff *skb, | |||
141 | else | 150 | else |
142 | statebit = XT_CONNTRACK_STATE_INVALID; | 151 | statebit = XT_CONNTRACK_STATE_INVALID; |
143 | 152 | ||
144 | if(sinfo->flags & XT_CONNTRACK_STATE) { | 153 | if (sinfo->flags & XT_CONNTRACK_STATE) { |
145 | if (ct) { | 154 | if (ct) { |
146 | if(ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u3.ip != | 155 | if (test_bit(IPS_SRC_NAT_BIT, &ct->status)) |
147 | ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u3.ip) | ||
148 | statebit |= XT_CONNTRACK_STATE_SNAT; | 156 | statebit |= XT_CONNTRACK_STATE_SNAT; |
149 | 157 | if (test_bit(IPS_DST_NAT_BIT, &ct->status)) | |
150 | if(ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.u3.ip != | ||
151 | ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.u3.ip) | ||
152 | statebit |= XT_CONNTRACK_STATE_DNAT; | 158 | statebit |= XT_CONNTRACK_STATE_DNAT; |
153 | } | 159 | } |
154 | 160 | if (FWINV((statebit & sinfo->statemask) == 0, | |
155 | if (FWINV((statebit & sinfo->statemask) == 0, XT_CONNTRACK_STATE)) | 161 | XT_CONNTRACK_STATE)) |
156 | return 0; | ||
157 | } | ||
158 | |||
159 | if(sinfo->flags & XT_CONNTRACK_PROTO) { | ||
160 | if (!ct || FWINV(ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.protonum != sinfo->tuple[IP_CT_DIR_ORIGINAL].dst.protonum, XT_CONNTRACK_PROTO)) | ||
161 | return 0; | ||
162 | } | ||
163 | |||
164 | if(sinfo->flags & XT_CONNTRACK_ORIGSRC) { | ||
165 | if (!ct || FWINV((ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u3.ip&sinfo->sipmsk[IP_CT_DIR_ORIGINAL].s_addr) != sinfo->tuple[IP_CT_DIR_ORIGINAL].src.ip, XT_CONNTRACK_ORIGSRC)) | ||
166 | return 0; | 162 | return 0; |
167 | } | 163 | } |
168 | 164 | ||
169 | if(sinfo->flags & XT_CONNTRACK_ORIGDST) { | 165 | if (ct == NULL) { |
170 | if (!ct || FWINV((ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.u3.ip&sinfo->dipmsk[IP_CT_DIR_ORIGINAL].s_addr) != sinfo->tuple[IP_CT_DIR_ORIGINAL].dst.ip, XT_CONNTRACK_ORIGDST)) | 166 | if (sinfo->flags & ~XT_CONNTRACK_STATE) |
171 | return 0; | 167 | return 0; |
168 | return 1; | ||
172 | } | 169 | } |
173 | 170 | ||
174 | if(sinfo->flags & XT_CONNTRACK_REPLSRC) { | 171 | if (sinfo->flags & XT_CONNTRACK_PROTO && |
175 | if (!ct || FWINV((ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.u3.ip&sinfo->sipmsk[IP_CT_DIR_REPLY].s_addr) != sinfo->tuple[IP_CT_DIR_REPLY].src.ip, XT_CONNTRACK_REPLSRC)) | 172 | FWINV(ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.protonum != |
176 | return 0; | 173 | sinfo->tuple[IP_CT_DIR_ORIGINAL].dst.protonum, |
177 | } | 174 | XT_CONNTRACK_PROTO)) |
175 | return 0; | ||
176 | |||
177 | if (sinfo->flags & XT_CONNTRACK_ORIGSRC && | ||
178 | FWINV((ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u3.ip & | ||
179 | sinfo->sipmsk[IP_CT_DIR_ORIGINAL].s_addr) != | ||
180 | sinfo->tuple[IP_CT_DIR_ORIGINAL].src.ip, | ||
181 | XT_CONNTRACK_ORIGSRC)) | ||
182 | return 0; | ||
178 | 183 | ||
179 | if(sinfo->flags & XT_CONNTRACK_REPLDST) { | 184 | if (sinfo->flags & XT_CONNTRACK_ORIGDST && |
180 | if (!ct || FWINV((ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u3.ip&sinfo->dipmsk[IP_CT_DIR_REPLY].s_addr) != sinfo->tuple[IP_CT_DIR_REPLY].dst.ip, XT_CONNTRACK_REPLDST)) | 185 | FWINV((ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.u3.ip & |
181 | return 0; | 186 | sinfo->dipmsk[IP_CT_DIR_ORIGINAL].s_addr) != |
182 | } | 187 | sinfo->tuple[IP_CT_DIR_ORIGINAL].dst.ip, |
188 | XT_CONNTRACK_ORIGDST)) | ||
189 | return 0; | ||
183 | 190 | ||
184 | if(sinfo->flags & XT_CONNTRACK_STATUS) { | 191 | if (sinfo->flags & XT_CONNTRACK_REPLSRC && |
185 | if (!ct || FWINV((ct->status & sinfo->statusmask) == 0, XT_CONNTRACK_STATUS)) | 192 | FWINV((ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.u3.ip & |
186 | return 0; | 193 | sinfo->sipmsk[IP_CT_DIR_REPLY].s_addr) != |
187 | } | 194 | sinfo->tuple[IP_CT_DIR_REPLY].src.ip, |
195 | XT_CONNTRACK_REPLSRC)) | ||
196 | return 0; | ||
188 | 197 | ||
189 | if(sinfo->flags & XT_CONNTRACK_EXPIRES) { | 198 | if (sinfo->flags & XT_CONNTRACK_REPLDST && |
190 | unsigned long expires; | 199 | FWINV((ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u3.ip & |
200 | sinfo->dipmsk[IP_CT_DIR_REPLY].s_addr) != | ||
201 | sinfo->tuple[IP_CT_DIR_REPLY].dst.ip, | ||
202 | XT_CONNTRACK_REPLDST)) | ||
203 | return 0; | ||
191 | 204 | ||
192 | if(!ct) | 205 | if (sinfo->flags & XT_CONNTRACK_STATUS && |
193 | return 0; | 206 | FWINV((ct->status & sinfo->statusmask) == 0, |
207 | XT_CONNTRACK_STATUS)) | ||
208 | return 0; | ||
194 | 209 | ||
195 | expires = timer_pending(&ct->timeout) ? (ct->timeout.expires - jiffies)/HZ : 0; | 210 | if(sinfo->flags & XT_CONNTRACK_EXPIRES) { |
211 | unsigned long expires = timer_pending(&ct->timeout) ? | ||
212 | (ct->timeout.expires - jiffies)/HZ : 0; | ||
196 | 213 | ||
197 | if (FWINV(!(expires >= sinfo->expires_min && expires <= sinfo->expires_max), XT_CONNTRACK_EXPIRES)) | 214 | if (FWINV(!(expires >= sinfo->expires_min && |
215 | expires <= sinfo->expires_max), | ||
216 | XT_CONNTRACK_EXPIRES)) | ||
198 | return 0; | 217 | return 0; |
199 | } | 218 | } |
200 | |||
201 | return 1; | 219 | return 1; |
202 | } | 220 | } |
203 | 221 | ||
@@ -208,7 +226,6 @@ checkentry(const char *tablename, | |||
208 | const void *ip, | 226 | const void *ip, |
209 | const struct xt_match *match, | 227 | const struct xt_match *match, |
210 | void *matchinfo, | 228 | void *matchinfo, |
211 | unsigned int matchsize, | ||
212 | unsigned int hook_mask) | 229 | unsigned int hook_mask) |
213 | { | 230 | { |
214 | #if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE) | 231 | #if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE) |
@@ -221,8 +238,7 @@ checkentry(const char *tablename, | |||
221 | return 1; | 238 | return 1; |
222 | } | 239 | } |
223 | 240 | ||
224 | static void | 241 | static void destroy(const struct xt_match *match, void *matchinfo) |
225 | destroy(const struct xt_match *match, void *matchinfo, unsigned int matchsize) | ||
226 | { | 242 | { |
227 | #if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE) | 243 | #if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE) |
228 | nf_ct_l3proto_module_put(match->family); | 244 | nf_ct_l3proto_module_put(match->family); |
@@ -241,11 +257,8 @@ static struct xt_match conntrack_match = { | |||
241 | 257 | ||
242 | static int __init xt_conntrack_init(void) | 258 | static int __init xt_conntrack_init(void) |
243 | { | 259 | { |
244 | int ret; | ||
245 | need_conntrack(); | 260 | need_conntrack(); |
246 | ret = xt_register_match(&conntrack_match); | 261 | return xt_register_match(&conntrack_match); |
247 | |||
248 | return ret; | ||
249 | } | 262 | } |
250 | 263 | ||
251 | static void __exit xt_conntrack_fini(void) | 264 | static void __exit xt_conntrack_fini(void) |
diff --git a/net/netfilter/xt_dccp.c b/net/netfilter/xt_dccp.c index 2e2f825dad4c..3e6cf430e518 100644 --- a/net/netfilter/xt_dccp.c +++ b/net/netfilter/xt_dccp.c | |||
@@ -131,7 +131,6 @@ checkentry(const char *tablename, | |||
131 | const void *inf, | 131 | const void *inf, |
132 | const struct xt_match *match, | 132 | const struct xt_match *match, |
133 | void *matchinfo, | 133 | void *matchinfo, |
134 | unsigned int matchsize, | ||
135 | unsigned int hook_mask) | 134 | unsigned int hook_mask) |
136 | { | 135 | { |
137 | const struct xt_dccp_info *info = matchinfo; | 136 | const struct xt_dccp_info *info = matchinfo; |
@@ -141,27 +140,26 @@ checkentry(const char *tablename, | |||
141 | && !(info->invflags & ~info->flags); | 140 | && !(info->invflags & ~info->flags); |
142 | } | 141 | } |
143 | 142 | ||
144 | static struct xt_match dccp_match = | 143 | static struct xt_match xt_dccp_match[] = { |
145 | { | 144 | { |
146 | .name = "dccp", | 145 | .name = "dccp", |
147 | .match = match, | 146 | .family = AF_INET, |
148 | .matchsize = sizeof(struct xt_dccp_info), | 147 | .checkentry = checkentry, |
149 | .proto = IPPROTO_DCCP, | 148 | .match = match, |
150 | .checkentry = checkentry, | 149 | .matchsize = sizeof(struct xt_dccp_info), |
151 | .family = AF_INET, | 150 | .proto = IPPROTO_DCCP, |
152 | .me = THIS_MODULE, | 151 | .me = THIS_MODULE, |
152 | }, | ||
153 | { | ||
154 | .name = "dccp", | ||
155 | .family = AF_INET6, | ||
156 | .checkentry = checkentry, | ||
157 | .match = match, | ||
158 | .matchsize = sizeof(struct xt_dccp_info), | ||
159 | .proto = IPPROTO_DCCP, | ||
160 | .me = THIS_MODULE, | ||
161 | }, | ||
153 | }; | 162 | }; |
154 | static struct xt_match dccp6_match = | ||
155 | { | ||
156 | .name = "dccp", | ||
157 | .match = match, | ||
158 | .matchsize = sizeof(struct xt_dccp_info), | ||
159 | .proto = IPPROTO_DCCP, | ||
160 | .checkentry = checkentry, | ||
161 | .family = AF_INET6, | ||
162 | .me = THIS_MODULE, | ||
163 | }; | ||
164 | |||
165 | 163 | ||
166 | static int __init xt_dccp_init(void) | 164 | static int __init xt_dccp_init(void) |
167 | { | 165 | { |
@@ -173,27 +171,19 @@ static int __init xt_dccp_init(void) | |||
173 | dccp_optbuf = kmalloc(256 * 4, GFP_KERNEL); | 171 | dccp_optbuf = kmalloc(256 * 4, GFP_KERNEL); |
174 | if (!dccp_optbuf) | 172 | if (!dccp_optbuf) |
175 | return -ENOMEM; | 173 | return -ENOMEM; |
176 | ret = xt_register_match(&dccp_match); | 174 | ret = xt_register_matches(xt_dccp_match, ARRAY_SIZE(xt_dccp_match)); |
177 | if (ret) | 175 | if (ret) |
178 | goto out_kfree; | 176 | goto out_kfree; |
179 | ret = xt_register_match(&dccp6_match); | ||
180 | if (ret) | ||
181 | goto out_unreg; | ||
182 | |||
183 | return ret; | 177 | return ret; |
184 | 178 | ||
185 | out_unreg: | ||
186 | xt_unregister_match(&dccp_match); | ||
187 | out_kfree: | 179 | out_kfree: |
188 | kfree(dccp_optbuf); | 180 | kfree(dccp_optbuf); |
189 | |||
190 | return ret; | 181 | return ret; |
191 | } | 182 | } |
192 | 183 | ||
193 | static void __exit xt_dccp_fini(void) | 184 | static void __exit xt_dccp_fini(void) |
194 | { | 185 | { |
195 | xt_unregister_match(&dccp6_match); | 186 | xt_unregister_matches(xt_dccp_match, ARRAY_SIZE(xt_dccp_match)); |
196 | xt_unregister_match(&dccp_match); | ||
197 | kfree(dccp_optbuf); | 187 | kfree(dccp_optbuf); |
198 | } | 188 | } |
199 | 189 | ||
diff --git a/net/netfilter/xt_dscp.c b/net/netfilter/xt_dscp.c new file mode 100644 index 000000000000..26c7f4ad102a --- /dev/null +++ b/net/netfilter/xt_dscp.c | |||
@@ -0,0 +1,103 @@ | |||
1 | /* IP tables module for matching the value of the IPv4/IPv6 DSCP field | ||
2 | * | ||
3 | * xt_dscp.c,v 1.3 2002/08/05 19:00:21 laforge Exp | ||
4 | * | ||
5 | * (C) 2002 by Harald Welte <laforge@netfilter.org> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License version 2 as | ||
9 | * published by the Free Software Foundation. | ||
10 | */ | ||
11 | |||
12 | #include <linux/module.h> | ||
13 | #include <linux/skbuff.h> | ||
14 | #include <linux/ip.h> | ||
15 | #include <linux/ipv6.h> | ||
16 | #include <net/dsfield.h> | ||
17 | |||
18 | #include <linux/netfilter/xt_dscp.h> | ||
19 | #include <linux/netfilter/x_tables.h> | ||
20 | |||
21 | MODULE_AUTHOR("Harald Welte <laforge@netfilter.org>"); | ||
22 | MODULE_DESCRIPTION("x_tables DSCP matching module"); | ||
23 | MODULE_LICENSE("GPL"); | ||
24 | MODULE_ALIAS("ipt_dscp"); | ||
25 | MODULE_ALIAS("ip6t_dscp"); | ||
26 | |||
27 | static int match(const struct sk_buff *skb, | ||
28 | const struct net_device *in, | ||
29 | const struct net_device *out, | ||
30 | const struct xt_match *match, | ||
31 | const void *matchinfo, | ||
32 | int offset, | ||
33 | unsigned int protoff, | ||
34 | int *hotdrop) | ||
35 | { | ||
36 | const struct xt_dscp_info *info = matchinfo; | ||
37 | u_int8_t dscp = ipv4_get_dsfield(skb->nh.iph) >> XT_DSCP_SHIFT; | ||
38 | |||
39 | return (dscp == info->dscp) ^ !!info->invert; | ||
40 | } | ||
41 | |||
42 | static int match6(const struct sk_buff *skb, | ||
43 | const struct net_device *in, | ||
44 | const struct net_device *out, | ||
45 | const struct xt_match *match, | ||
46 | const void *matchinfo, | ||
47 | int offset, | ||
48 | unsigned int protoff, | ||
49 | int *hotdrop) | ||
50 | { | ||
51 | const struct xt_dscp_info *info = matchinfo; | ||
52 | u_int8_t dscp = ipv6_get_dsfield(skb->nh.ipv6h) >> XT_DSCP_SHIFT; | ||
53 | |||
54 | return (dscp == info->dscp) ^ !!info->invert; | ||
55 | } | ||
56 | |||
57 | static int checkentry(const char *tablename, | ||
58 | const void *info, | ||
59 | const struct xt_match *match, | ||
60 | void *matchinfo, | ||
61 | unsigned int hook_mask) | ||
62 | { | ||
63 | const u_int8_t dscp = ((struct xt_dscp_info *)matchinfo)->dscp; | ||
64 | |||
65 | if (dscp > XT_DSCP_MAX) { | ||
66 | printk(KERN_ERR "xt_dscp: dscp %x out of range\n", dscp); | ||
67 | return 0; | ||
68 | } | ||
69 | |||
70 | return 1; | ||
71 | } | ||
72 | |||
73 | static struct xt_match xt_dscp_match[] = { | ||
74 | { | ||
75 | .name = "dscp", | ||
76 | .family = AF_INET, | ||
77 | .checkentry = checkentry, | ||
78 | .match = match, | ||
79 | .matchsize = sizeof(struct xt_dscp_info), | ||
80 | .me = THIS_MODULE, | ||
81 | }, | ||
82 | { | ||
83 | .name = "dscp", | ||
84 | .family = AF_INET6, | ||
85 | .checkentry = checkentry, | ||
86 | .match = match6, | ||
87 | .matchsize = sizeof(struct xt_dscp_info), | ||
88 | .me = THIS_MODULE, | ||
89 | }, | ||
90 | }; | ||
91 | |||
92 | static int __init xt_dscp_match_init(void) | ||
93 | { | ||
94 | return xt_register_matches(xt_dscp_match, ARRAY_SIZE(xt_dscp_match)); | ||
95 | } | ||
96 | |||
97 | static void __exit xt_dscp_match_fini(void) | ||
98 | { | ||
99 | xt_unregister_matches(xt_dscp_match, ARRAY_SIZE(xt_dscp_match)); | ||
100 | } | ||
101 | |||
102 | module_init(xt_dscp_match_init); | ||
103 | module_exit(xt_dscp_match_fini); | ||
diff --git a/net/netfilter/xt_esp.c b/net/netfilter/xt_esp.c index 9dad6281e0c1..7c95f149d942 100644 --- a/net/netfilter/xt_esp.c +++ b/net/netfilter/xt_esp.c | |||
@@ -79,7 +79,6 @@ checkentry(const char *tablename, | |||
79 | const void *ip_void, | 79 | const void *ip_void, |
80 | const struct xt_match *match, | 80 | const struct xt_match *match, |
81 | void *matchinfo, | 81 | void *matchinfo, |
82 | unsigned int matchinfosize, | ||
83 | unsigned int hook_mask) | 82 | unsigned int hook_mask) |
84 | { | 83 | { |
85 | const struct xt_esp *espinfo = matchinfo; | 84 | const struct xt_esp *espinfo = matchinfo; |
@@ -92,44 +91,35 @@ checkentry(const char *tablename, | |||
92 | return 1; | 91 | return 1; |
93 | } | 92 | } |
94 | 93 | ||
95 | static struct xt_match esp_match = { | 94 | static struct xt_match xt_esp_match[] = { |
96 | .name = "esp", | 95 | { |
97 | .family = AF_INET, | 96 | .name = "esp", |
98 | .proto = IPPROTO_ESP, | 97 | .family = AF_INET, |
99 | .match = &match, | 98 | .checkentry = checkentry, |
100 | .matchsize = sizeof(struct xt_esp), | 99 | .match = match, |
101 | .checkentry = &checkentry, | 100 | .matchsize = sizeof(struct xt_esp), |
102 | .me = THIS_MODULE, | 101 | .proto = IPPROTO_ESP, |
103 | }; | 102 | .me = THIS_MODULE, |
104 | 103 | }, | |
105 | static struct xt_match esp6_match = { | 104 | { |
106 | .name = "esp", | 105 | .name = "esp", |
107 | .family = AF_INET6, | 106 | .family = AF_INET6, |
108 | .proto = IPPROTO_ESP, | 107 | .checkentry = checkentry, |
109 | .match = &match, | 108 | .match = match, |
110 | .matchsize = sizeof(struct xt_esp), | 109 | .matchsize = sizeof(struct xt_esp), |
111 | .checkentry = &checkentry, | 110 | .proto = IPPROTO_ESP, |
112 | .me = THIS_MODULE, | 111 | .me = THIS_MODULE, |
112 | }, | ||
113 | }; | 113 | }; |
114 | 114 | ||
115 | static int __init xt_esp_init(void) | 115 | static int __init xt_esp_init(void) |
116 | { | 116 | { |
117 | int ret; | 117 | return xt_register_matches(xt_esp_match, ARRAY_SIZE(xt_esp_match)); |
118 | ret = xt_register_match(&esp_match); | ||
119 | if (ret) | ||
120 | return ret; | ||
121 | |||
122 | ret = xt_register_match(&esp6_match); | ||
123 | if (ret) | ||
124 | xt_unregister_match(&esp_match); | ||
125 | |||
126 | return ret; | ||
127 | } | 118 | } |
128 | 119 | ||
129 | static void __exit xt_esp_cleanup(void) | 120 | static void __exit xt_esp_cleanup(void) |
130 | { | 121 | { |
131 | xt_unregister_match(&esp_match); | 122 | xt_unregister_matches(xt_esp_match, ARRAY_SIZE(xt_esp_match)); |
132 | xt_unregister_match(&esp6_match); | ||
133 | } | 123 | } |
134 | 124 | ||
135 | module_init(xt_esp_init); | 125 | module_init(xt_esp_init); |
diff --git a/net/netfilter/xt_helper.c b/net/netfilter/xt_helper.c index 799c2a43e3b9..5d7818b73e3a 100644 --- a/net/netfilter/xt_helper.c +++ b/net/netfilter/xt_helper.c | |||
@@ -139,7 +139,6 @@ static int check(const char *tablename, | |||
139 | const void *inf, | 139 | const void *inf, |
140 | const struct xt_match *match, | 140 | const struct xt_match *match, |
141 | void *matchinfo, | 141 | void *matchinfo, |
142 | unsigned int matchsize, | ||
143 | unsigned int hook_mask) | 142 | unsigned int hook_mask) |
144 | { | 143 | { |
145 | struct xt_helper_info *info = matchinfo; | 144 | struct xt_helper_info *info = matchinfo; |
@@ -156,52 +155,44 @@ static int check(const char *tablename, | |||
156 | } | 155 | } |
157 | 156 | ||
158 | static void | 157 | static void |
159 | destroy(const struct xt_match *match, void *matchinfo, unsigned int matchsize) | 158 | destroy(const struct xt_match *match, void *matchinfo) |
160 | { | 159 | { |
161 | #if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE) | 160 | #if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE) |
162 | nf_ct_l3proto_module_put(match->family); | 161 | nf_ct_l3proto_module_put(match->family); |
163 | #endif | 162 | #endif |
164 | } | 163 | } |
165 | 164 | ||
166 | static struct xt_match helper_match = { | 165 | static struct xt_match xt_helper_match[] = { |
167 | .name = "helper", | 166 | { |
168 | .match = match, | 167 | .name = "helper", |
169 | .matchsize = sizeof(struct xt_helper_info), | 168 | .family = AF_INET, |
170 | .checkentry = check, | 169 | .checkentry = check, |
171 | .destroy = destroy, | 170 | .match = match, |
172 | .family = AF_INET, | 171 | .destroy = destroy, |
173 | .me = THIS_MODULE, | 172 | .matchsize = sizeof(struct xt_helper_info), |
174 | }; | 173 | .me = THIS_MODULE, |
175 | static struct xt_match helper6_match = { | 174 | }, |
176 | .name = "helper", | 175 | { |
177 | .match = match, | 176 | .name = "helper", |
178 | .matchsize = sizeof(struct xt_helper_info), | 177 | .family = AF_INET6, |
179 | .checkentry = check, | 178 | .checkentry = check, |
180 | .destroy = destroy, | 179 | .match = match, |
181 | .family = AF_INET6, | 180 | .destroy = destroy, |
182 | .me = THIS_MODULE, | 181 | .matchsize = sizeof(struct xt_helper_info), |
182 | .me = THIS_MODULE, | ||
183 | }, | ||
183 | }; | 184 | }; |
184 | 185 | ||
185 | static int __init xt_helper_init(void) | 186 | static int __init xt_helper_init(void) |
186 | { | 187 | { |
187 | int ret; | ||
188 | need_conntrack(); | 188 | need_conntrack(); |
189 | 189 | return xt_register_matches(xt_helper_match, | |
190 | ret = xt_register_match(&helper_match); | 190 | ARRAY_SIZE(xt_helper_match)); |
191 | if (ret < 0) | ||
192 | return ret; | ||
193 | |||
194 | ret = xt_register_match(&helper6_match); | ||
195 | if (ret < 0) | ||
196 | xt_unregister_match(&helper_match); | ||
197 | |||
198 | return ret; | ||
199 | } | 191 | } |
200 | 192 | ||
201 | static void __exit xt_helper_fini(void) | 193 | static void __exit xt_helper_fini(void) |
202 | { | 194 | { |
203 | xt_unregister_match(&helper_match); | 195 | xt_unregister_matches(xt_helper_match, ARRAY_SIZE(xt_helper_match)); |
204 | xt_unregister_match(&helper6_match); | ||
205 | } | 196 | } |
206 | 197 | ||
207 | module_init(xt_helper_init); | 198 | module_init(xt_helper_init); |
diff --git a/net/netfilter/xt_length.c b/net/netfilter/xt_length.c index 109132c9a146..67fd30d9f303 100644 --- a/net/netfilter/xt_length.c +++ b/net/netfilter/xt_length.c | |||
@@ -52,39 +52,32 @@ match6(const struct sk_buff *skb, | |||
52 | return (pktlen >= info->min && pktlen <= info->max) ^ info->invert; | 52 | return (pktlen >= info->min && pktlen <= info->max) ^ info->invert; |
53 | } | 53 | } |
54 | 54 | ||
55 | static struct xt_match length_match = { | 55 | static struct xt_match xt_length_match[] = { |
56 | .name = "length", | 56 | { |
57 | .match = match, | 57 | .name = "length", |
58 | .matchsize = sizeof(struct xt_length_info), | 58 | .family = AF_INET, |
59 | .family = AF_INET, | 59 | .match = match, |
60 | .me = THIS_MODULE, | 60 | .matchsize = sizeof(struct xt_length_info), |
61 | }; | 61 | .me = THIS_MODULE, |
62 | 62 | }, | |
63 | static struct xt_match length6_match = { | 63 | { |
64 | .name = "length", | 64 | .name = "length", |
65 | .match = match6, | 65 | .family = AF_INET6, |
66 | .matchsize = sizeof(struct xt_length_info), | 66 | .match = match6, |
67 | .family = AF_INET6, | 67 | .matchsize = sizeof(struct xt_length_info), |
68 | .me = THIS_MODULE, | 68 | .me = THIS_MODULE, |
69 | }, | ||
69 | }; | 70 | }; |
70 | 71 | ||
71 | static int __init xt_length_init(void) | 72 | static int __init xt_length_init(void) |
72 | { | 73 | { |
73 | int ret; | 74 | return xt_register_matches(xt_length_match, |
74 | ret = xt_register_match(&length_match); | 75 | ARRAY_SIZE(xt_length_match)); |
75 | if (ret) | ||
76 | return ret; | ||
77 | ret = xt_register_match(&length6_match); | ||
78 | if (ret) | ||
79 | xt_unregister_match(&length_match); | ||
80 | |||
81 | return ret; | ||
82 | } | 76 | } |
83 | 77 | ||
84 | static void __exit xt_length_fini(void) | 78 | static void __exit xt_length_fini(void) |
85 | { | 79 | { |
86 | xt_unregister_match(&length_match); | 80 | xt_unregister_matches(xt_length_match, ARRAY_SIZE(xt_length_match)); |
87 | xt_unregister_match(&length6_match); | ||
88 | } | 81 | } |
89 | 82 | ||
90 | module_init(xt_length_init); | 83 | module_init(xt_length_init); |
diff --git a/net/netfilter/xt_limit.c b/net/netfilter/xt_limit.c index ce7fdb7e4e07..fda7b7dec27d 100644 --- a/net/netfilter/xt_limit.c +++ b/net/netfilter/xt_limit.c | |||
@@ -110,7 +110,6 @@ ipt_limit_checkentry(const char *tablename, | |||
110 | const void *inf, | 110 | const void *inf, |
111 | const struct xt_match *match, | 111 | const struct xt_match *match, |
112 | void *matchinfo, | 112 | void *matchinfo, |
113 | unsigned int matchsize, | ||
114 | unsigned int hook_mask) | 113 | unsigned int hook_mask) |
115 | { | 114 | { |
116 | struct xt_rateinfo *r = matchinfo; | 115 | struct xt_rateinfo *r = matchinfo; |
@@ -123,55 +122,95 @@ ipt_limit_checkentry(const char *tablename, | |||
123 | return 0; | 122 | return 0; |
124 | } | 123 | } |
125 | 124 | ||
126 | /* User avg in seconds * XT_LIMIT_SCALE: convert to jiffies * | ||
127 | 128. */ | ||
128 | r->prev = jiffies; | ||
129 | r->credit = user2credits(r->avg * r->burst); /* Credits full. */ | ||
130 | r->credit_cap = user2credits(r->avg * r->burst); /* Credits full. */ | ||
131 | r->cost = user2credits(r->avg); | ||
132 | |||
133 | /* For SMP, we only want to use one set of counters. */ | 125 | /* For SMP, we only want to use one set of counters. */ |
134 | r->master = r; | 126 | r->master = r; |
135 | 127 | if (r->cost == 0) { | |
128 | /* User avg in seconds * XT_LIMIT_SCALE: convert to jiffies * | ||
129 | 128. */ | ||
130 | r->prev = jiffies; | ||
131 | r->credit = user2credits(r->avg * r->burst); /* Credits full. */ | ||
132 | r->credit_cap = user2credits(r->avg * r->burst); /* Credits full. */ | ||
133 | r->cost = user2credits(r->avg); | ||
134 | } | ||
136 | return 1; | 135 | return 1; |
137 | } | 136 | } |
138 | 137 | ||
139 | static struct xt_match ipt_limit_reg = { | 138 | #ifdef CONFIG_COMPAT |
140 | .name = "limit", | 139 | struct compat_xt_rateinfo { |
141 | .match = ipt_limit_match, | 140 | u_int32_t avg; |
142 | .matchsize = sizeof(struct xt_rateinfo), | 141 | u_int32_t burst; |
143 | .checkentry = ipt_limit_checkentry, | 142 | |
144 | .family = AF_INET, | 143 | compat_ulong_t prev; |
145 | .me = THIS_MODULE, | 144 | u_int32_t credit; |
145 | u_int32_t credit_cap, cost; | ||
146 | |||
147 | u_int32_t master; | ||
146 | }; | 148 | }; |
147 | static struct xt_match limit6_reg = { | 149 | |
148 | .name = "limit", | 150 | /* To keep the full "prev" timestamp, the upper 32 bits are stored in the |
149 | .match = ipt_limit_match, | 151 | * master pointer, which does not need to be preserved. */ |
150 | .matchsize = sizeof(struct xt_rateinfo), | 152 | static void compat_from_user(void *dst, void *src) |
151 | .checkentry = ipt_limit_checkentry, | 153 | { |
152 | .family = AF_INET6, | 154 | struct compat_xt_rateinfo *cm = src; |
153 | .me = THIS_MODULE, | 155 | struct xt_rateinfo m = { |
156 | .avg = cm->avg, | ||
157 | .burst = cm->burst, | ||
158 | .prev = cm->prev | (unsigned long)cm->master << 32, | ||
159 | .credit = cm->credit, | ||
160 | .credit_cap = cm->credit_cap, | ||
161 | .cost = cm->cost, | ||
162 | }; | ||
163 | memcpy(dst, &m, sizeof(m)); | ||
164 | } | ||
165 | |||
166 | static int compat_to_user(void __user *dst, void *src) | ||
167 | { | ||
168 | struct xt_rateinfo *m = src; | ||
169 | struct compat_xt_rateinfo cm = { | ||
170 | .avg = m->avg, | ||
171 | .burst = m->burst, | ||
172 | .prev = m->prev, | ||
173 | .credit = m->credit, | ||
174 | .credit_cap = m->credit_cap, | ||
175 | .cost = m->cost, | ||
176 | .master = m->prev >> 32, | ||
177 | }; | ||
178 | return copy_to_user(dst, &cm, sizeof(cm)) ? -EFAULT : 0; | ||
179 | } | ||
180 | #endif /* CONFIG_COMPAT */ | ||
181 | |||
182 | static struct xt_match xt_limit_match[] = { | ||
183 | { | ||
184 | .name = "limit", | ||
185 | .family = AF_INET, | ||
186 | .checkentry = ipt_limit_checkentry, | ||
187 | .match = ipt_limit_match, | ||
188 | .matchsize = sizeof(struct xt_rateinfo), | ||
189 | #ifdef CONFIG_COMPAT | ||
190 | .compatsize = sizeof(struct compat_xt_rateinfo), | ||
191 | .compat_from_user = compat_from_user, | ||
192 | .compat_to_user = compat_to_user, | ||
193 | #endif | ||
194 | .me = THIS_MODULE, | ||
195 | }, | ||
196 | { | ||
197 | .name = "limit", | ||
198 | .family = AF_INET6, | ||
199 | .checkentry = ipt_limit_checkentry, | ||
200 | .match = ipt_limit_match, | ||
201 | .matchsize = sizeof(struct xt_rateinfo), | ||
202 | .me = THIS_MODULE, | ||
203 | }, | ||
154 | }; | 204 | }; |
155 | 205 | ||
156 | static int __init xt_limit_init(void) | 206 | static int __init xt_limit_init(void) |
157 | { | 207 | { |
158 | int ret; | 208 | return xt_register_matches(xt_limit_match, ARRAY_SIZE(xt_limit_match)); |
159 | |||
160 | ret = xt_register_match(&ipt_limit_reg); | ||
161 | if (ret) | ||
162 | return ret; | ||
163 | |||
164 | ret = xt_register_match(&limit6_reg); | ||
165 | if (ret) | ||
166 | xt_unregister_match(&ipt_limit_reg); | ||
167 | |||
168 | return ret; | ||
169 | } | 209 | } |
170 | 210 | ||
171 | static void __exit xt_limit_fini(void) | 211 | static void __exit xt_limit_fini(void) |
172 | { | 212 | { |
173 | xt_unregister_match(&ipt_limit_reg); | 213 | xt_unregister_matches(xt_limit_match, ARRAY_SIZE(xt_limit_match)); |
174 | xt_unregister_match(&limit6_reg); | ||
175 | } | 214 | } |
176 | 215 | ||
177 | module_init(xt_limit_init); | 216 | module_init(xt_limit_init); |
diff --git a/net/netfilter/xt_mac.c b/net/netfilter/xt_mac.c index 356290ffe386..425fc21e31f5 100644 --- a/net/netfilter/xt_mac.c +++ b/net/netfilter/xt_mac.c | |||
@@ -43,43 +43,37 @@ match(const struct sk_buff *skb, | |||
43 | ^ info->invert)); | 43 | ^ info->invert)); |
44 | } | 44 | } |
45 | 45 | ||
46 | static struct xt_match mac_match = { | 46 | static struct xt_match xt_mac_match[] = { |
47 | .name = "mac", | 47 | { |
48 | .match = match, | 48 | .name = "mac", |
49 | .matchsize = sizeof(struct xt_mac_info), | 49 | .family = AF_INET, |
50 | .hooks = (1 << NF_IP_PRE_ROUTING) | (1 << NF_IP_LOCAL_IN) | | 50 | .match = match, |
51 | (1 << NF_IP_FORWARD), | 51 | .matchsize = sizeof(struct xt_mac_info), |
52 | .family = AF_INET, | 52 | .hooks = (1 << NF_IP_PRE_ROUTING) | |
53 | .me = THIS_MODULE, | 53 | (1 << NF_IP_LOCAL_IN) | |
54 | }; | 54 | (1 << NF_IP_FORWARD), |
55 | static struct xt_match mac6_match = { | 55 | .me = THIS_MODULE, |
56 | .name = "mac", | 56 | }, |
57 | .match = match, | 57 | { |
58 | .matchsize = sizeof(struct xt_mac_info), | 58 | .name = "mac", |
59 | .hooks = (1 << NF_IP_PRE_ROUTING) | (1 << NF_IP_LOCAL_IN) | | 59 | .family = AF_INET6, |
60 | (1 << NF_IP_FORWARD), | 60 | .match = match, |
61 | .family = AF_INET6, | 61 | .matchsize = sizeof(struct xt_mac_info), |
62 | .me = THIS_MODULE, | 62 | .hooks = (1 << NF_IP_PRE_ROUTING) | |
63 | (1 << NF_IP_LOCAL_IN) | | ||
64 | (1 << NF_IP_FORWARD), | ||
65 | .me = THIS_MODULE, | ||
66 | }, | ||
63 | }; | 67 | }; |
64 | 68 | ||
65 | static int __init xt_mac_init(void) | 69 | static int __init xt_mac_init(void) |
66 | { | 70 | { |
67 | int ret; | 71 | return xt_register_matches(xt_mac_match, ARRAY_SIZE(xt_mac_match)); |
68 | ret = xt_register_match(&mac_match); | ||
69 | if (ret) | ||
70 | return ret; | ||
71 | |||
72 | ret = xt_register_match(&mac6_match); | ||
73 | if (ret) | ||
74 | xt_unregister_match(&mac_match); | ||
75 | |||
76 | return ret; | ||
77 | } | 72 | } |
78 | 73 | ||
79 | static void __exit xt_mac_fini(void) | 74 | static void __exit xt_mac_fini(void) |
80 | { | 75 | { |
81 | xt_unregister_match(&mac_match); | 76 | xt_unregister_matches(xt_mac_match, ARRAY_SIZE(xt_mac_match)); |
82 | xt_unregister_match(&mac6_match); | ||
83 | } | 77 | } |
84 | 78 | ||
85 | module_init(xt_mac_init); | 79 | module_init(xt_mac_init); |
diff --git a/net/netfilter/xt_mark.c b/net/netfilter/xt_mark.c index 876bc5797738..934dddfbcd23 100644 --- a/net/netfilter/xt_mark.c +++ b/net/netfilter/xt_mark.c | |||
@@ -39,7 +39,6 @@ checkentry(const char *tablename, | |||
39 | const void *entry, | 39 | const void *entry, |
40 | const struct xt_match *match, | 40 | const struct xt_match *match, |
41 | void *matchinfo, | 41 | void *matchinfo, |
42 | unsigned int matchsize, | ||
43 | unsigned int hook_mask) | 42 | unsigned int hook_mask) |
44 | { | 43 | { |
45 | const struct xt_mark_info *minfo = matchinfo; | 44 | const struct xt_mark_info *minfo = matchinfo; |
@@ -51,42 +50,69 @@ checkentry(const char *tablename, | |||
51 | return 1; | 50 | return 1; |
52 | } | 51 | } |
53 | 52 | ||
54 | static struct xt_match mark_match = { | 53 | #ifdef CONFIG_COMPAT |
55 | .name = "mark", | 54 | struct compat_xt_mark_info { |
56 | .match = match, | 55 | compat_ulong_t mark, mask; |
57 | .matchsize = sizeof(struct xt_mark_info), | 56 | u_int8_t invert; |
58 | .checkentry = checkentry, | 57 | u_int8_t __pad1; |
59 | .family = AF_INET, | 58 | u_int16_t __pad2; |
60 | .me = THIS_MODULE, | ||
61 | }; | 59 | }; |
62 | 60 | ||
63 | static struct xt_match mark6_match = { | 61 | static void compat_from_user(void *dst, void *src) |
64 | .name = "mark", | 62 | { |
65 | .match = match, | 63 | struct compat_xt_mark_info *cm = src; |
66 | .matchsize = sizeof(struct xt_mark_info), | 64 | struct xt_mark_info m = { |
67 | .checkentry = checkentry, | 65 | .mark = cm->mark, |
68 | .family = AF_INET6, | 66 | .mask = cm->mask, |
69 | .me = THIS_MODULE, | 67 | .invert = cm->invert, |
70 | }; | 68 | }; |
69 | memcpy(dst, &m, sizeof(m)); | ||
70 | } | ||
71 | 71 | ||
72 | static int __init xt_mark_init(void) | 72 | static int compat_to_user(void __user *dst, void *src) |
73 | { | 73 | { |
74 | int ret; | 74 | struct xt_mark_info *m = src; |
75 | ret = xt_register_match(&mark_match); | 75 | struct compat_xt_mark_info cm = { |
76 | if (ret) | 76 | .mark = m->mark, |
77 | return ret; | 77 | .mask = m->mask, |
78 | .invert = m->invert, | ||
79 | }; | ||
80 | return copy_to_user(dst, &cm, sizeof(cm)) ? -EFAULT : 0; | ||
81 | } | ||
82 | #endif /* CONFIG_COMPAT */ | ||
78 | 83 | ||
79 | ret = xt_register_match(&mark6_match); | 84 | static struct xt_match xt_mark_match[] = { |
80 | if (ret) | 85 | { |
81 | xt_unregister_match(&mark_match); | 86 | .name = "mark", |
87 | .family = AF_INET, | ||
88 | .checkentry = checkentry, | ||
89 | .match = match, | ||
90 | .matchsize = sizeof(struct xt_mark_info), | ||
91 | #ifdef CONFIG_COMPAT | ||
92 | .compatsize = sizeof(struct compat_xt_mark_info), | ||
93 | .compat_from_user = compat_from_user, | ||
94 | .compat_to_user = compat_to_user, | ||
95 | #endif | ||
96 | .me = THIS_MODULE, | ||
97 | }, | ||
98 | { | ||
99 | .name = "mark", | ||
100 | .family = AF_INET6, | ||
101 | .checkentry = checkentry, | ||
102 | .match = match, | ||
103 | .matchsize = sizeof(struct xt_mark_info), | ||
104 | .me = THIS_MODULE, | ||
105 | }, | ||
106 | }; | ||
82 | 107 | ||
83 | return ret; | 108 | static int __init xt_mark_init(void) |
109 | { | ||
110 | return xt_register_matches(xt_mark_match, ARRAY_SIZE(xt_mark_match)); | ||
84 | } | 111 | } |
85 | 112 | ||
86 | static void __exit xt_mark_fini(void) | 113 | static void __exit xt_mark_fini(void) |
87 | { | 114 | { |
88 | xt_unregister_match(&mark_match); | 115 | xt_unregister_matches(xt_mark_match, ARRAY_SIZE(xt_mark_match)); |
89 | xt_unregister_match(&mark6_match); | ||
90 | } | 116 | } |
91 | 117 | ||
92 | module_init(xt_mark_init); | 118 | module_init(xt_mark_init); |
diff --git a/net/netfilter/xt_multiport.c b/net/netfilter/xt_multiport.c index 1ff0a25396e7..d3aefd380930 100644 --- a/net/netfilter/xt_multiport.c +++ b/net/netfilter/xt_multiport.c | |||
@@ -176,7 +176,6 @@ checkentry(const char *tablename, | |||
176 | const void *info, | 176 | const void *info, |
177 | const struct xt_match *match, | 177 | const struct xt_match *match, |
178 | void *matchinfo, | 178 | void *matchinfo, |
179 | unsigned int matchsize, | ||
180 | unsigned int hook_mask) | 179 | unsigned int hook_mask) |
181 | { | 180 | { |
182 | const struct ipt_ip *ip = info; | 181 | const struct ipt_ip *ip = info; |
@@ -191,7 +190,6 @@ checkentry_v1(const char *tablename, | |||
191 | const void *info, | 190 | const void *info, |
192 | const struct xt_match *match, | 191 | const struct xt_match *match, |
193 | void *matchinfo, | 192 | void *matchinfo, |
194 | unsigned int matchsize, | ||
195 | unsigned int hook_mask) | 193 | unsigned int hook_mask) |
196 | { | 194 | { |
197 | const struct ipt_ip *ip = info; | 195 | const struct ipt_ip *ip = info; |
@@ -206,7 +204,6 @@ checkentry6(const char *tablename, | |||
206 | const void *info, | 204 | const void *info, |
207 | const struct xt_match *match, | 205 | const struct xt_match *match, |
208 | void *matchinfo, | 206 | void *matchinfo, |
209 | unsigned int matchsize, | ||
210 | unsigned int hook_mask) | 207 | unsigned int hook_mask) |
211 | { | 208 | { |
212 | const struct ip6t_ip6 *ip = info; | 209 | const struct ip6t_ip6 *ip = info; |
@@ -221,7 +218,6 @@ checkentry6_v1(const char *tablename, | |||
221 | const void *info, | 218 | const void *info, |
222 | const struct xt_match *match, | 219 | const struct xt_match *match, |
223 | void *matchinfo, | 220 | void *matchinfo, |
224 | unsigned int matchsize, | ||
225 | unsigned int hook_mask) | 221 | unsigned int hook_mask) |
226 | { | 222 | { |
227 | const struct ip6t_ip6 *ip = info; | 223 | const struct ip6t_ip6 *ip = info; |
@@ -231,84 +227,55 @@ checkentry6_v1(const char *tablename, | |||
231 | multiinfo->count); | 227 | multiinfo->count); |
232 | } | 228 | } |
233 | 229 | ||
234 | static struct xt_match multiport_match = { | 230 | static struct xt_match xt_multiport_match[] = { |
235 | .name = "multiport", | 231 | { |
236 | .revision = 0, | 232 | .name = "multiport", |
237 | .matchsize = sizeof(struct xt_multiport), | 233 | .family = AF_INET, |
238 | .match = &match, | 234 | .revision = 0, |
239 | .checkentry = &checkentry, | 235 | .checkentry = checkentry, |
240 | .family = AF_INET, | 236 | .match = match, |
241 | .me = THIS_MODULE, | 237 | .matchsize = sizeof(struct xt_multiport), |
242 | }; | 238 | .me = THIS_MODULE, |
243 | 239 | }, | |
244 | static struct xt_match multiport_match_v1 = { | 240 | { |
245 | .name = "multiport", | 241 | .name = "multiport", |
246 | .revision = 1, | 242 | .family = AF_INET, |
247 | .matchsize = sizeof(struct xt_multiport_v1), | 243 | .revision = 1, |
248 | .match = &match_v1, | 244 | .checkentry = checkentry_v1, |
249 | .checkentry = &checkentry_v1, | 245 | .match = match_v1, |
250 | .family = AF_INET, | 246 | .matchsize = sizeof(struct xt_multiport_v1), |
251 | .me = THIS_MODULE, | 247 | .me = THIS_MODULE, |
252 | }; | 248 | }, |
253 | 249 | { | |
254 | static struct xt_match multiport6_match = { | 250 | .name = "multiport", |
255 | .name = "multiport", | 251 | .family = AF_INET6, |
256 | .revision = 0, | 252 | .revision = 0, |
257 | .matchsize = sizeof(struct xt_multiport), | 253 | .checkentry = checkentry6, |
258 | .match = &match, | 254 | .match = match, |
259 | .checkentry = &checkentry6, | 255 | .matchsize = sizeof(struct xt_multiport), |
260 | .family = AF_INET6, | 256 | .me = THIS_MODULE, |
261 | .me = THIS_MODULE, | 257 | }, |
262 | }; | 258 | { |
263 | 259 | .name = "multiport", | |
264 | static struct xt_match multiport6_match_v1 = { | 260 | .family = AF_INET6, |
265 | .name = "multiport", | 261 | .revision = 1, |
266 | .revision = 1, | 262 | .checkentry = checkentry6_v1, |
267 | .matchsize = sizeof(struct xt_multiport_v1), | 263 | .match = match_v1, |
268 | .match = &match_v1, | 264 | .matchsize = sizeof(struct xt_multiport_v1), |
269 | .checkentry = &checkentry6_v1, | 265 | .me = THIS_MODULE, |
270 | .family = AF_INET6, | 266 | }, |
271 | .me = THIS_MODULE, | ||
272 | }; | 267 | }; |
273 | 268 | ||
274 | static int __init xt_multiport_init(void) | 269 | static int __init xt_multiport_init(void) |
275 | { | 270 | { |
276 | int ret; | 271 | return xt_register_matches(xt_multiport_match, |
277 | 272 | ARRAY_SIZE(xt_multiport_match)); | |
278 | ret = xt_register_match(&multiport_match); | ||
279 | if (ret) | ||
280 | goto out; | ||
281 | |||
282 | ret = xt_register_match(&multiport_match_v1); | ||
283 | if (ret) | ||
284 | goto out_unreg_multi_v0; | ||
285 | |||
286 | ret = xt_register_match(&multiport6_match); | ||
287 | if (ret) | ||
288 | goto out_unreg_multi_v1; | ||
289 | |||
290 | ret = xt_register_match(&multiport6_match_v1); | ||
291 | if (ret) | ||
292 | goto out_unreg_multi6_v0; | ||
293 | |||
294 | return ret; | ||
295 | |||
296 | out_unreg_multi6_v0: | ||
297 | xt_unregister_match(&multiport6_match); | ||
298 | out_unreg_multi_v1: | ||
299 | xt_unregister_match(&multiport_match_v1); | ||
300 | out_unreg_multi_v0: | ||
301 | xt_unregister_match(&multiport_match); | ||
302 | out: | ||
303 | return ret; | ||
304 | } | 273 | } |
305 | 274 | ||
306 | static void __exit xt_multiport_fini(void) | 275 | static void __exit xt_multiport_fini(void) |
307 | { | 276 | { |
308 | xt_unregister_match(&multiport_match); | 277 | xt_unregister_matches(xt_multiport_match, |
309 | xt_unregister_match(&multiport_match_v1); | 278 | ARRAY_SIZE(xt_multiport_match)); |
310 | xt_unregister_match(&multiport6_match); | ||
311 | xt_unregister_match(&multiport6_match_v1); | ||
312 | } | 279 | } |
313 | 280 | ||
314 | module_init(xt_multiport_init); | 281 | module_init(xt_multiport_init); |
diff --git a/net/netfilter/xt_physdev.c b/net/netfilter/xt_physdev.c index 63a965467465..fd8f954cded5 100644 --- a/net/netfilter/xt_physdev.c +++ b/net/netfilter/xt_physdev.c | |||
@@ -106,7 +106,6 @@ checkentry(const char *tablename, | |||
106 | const void *ip, | 106 | const void *ip, |
107 | const struct xt_match *match, | 107 | const struct xt_match *match, |
108 | void *matchinfo, | 108 | void *matchinfo, |
109 | unsigned int matchsize, | ||
110 | unsigned int hook_mask) | 109 | unsigned int hook_mask) |
111 | { | 110 | { |
112 | const struct xt_physdev_info *info = matchinfo; | 111 | const struct xt_physdev_info *info = matchinfo; |
@@ -132,43 +131,34 @@ checkentry(const char *tablename, | |||
132 | return 1; | 131 | return 1; |
133 | } | 132 | } |
134 | 133 | ||
135 | static struct xt_match physdev_match = { | 134 | static struct xt_match xt_physdev_match[] = { |
136 | .name = "physdev", | 135 | { |
137 | .match = match, | 136 | .name = "physdev", |
138 | .matchsize = sizeof(struct xt_physdev_info), | 137 | .family = AF_INET, |
139 | .checkentry = checkentry, | 138 | .checkentry = checkentry, |
140 | .family = AF_INET, | 139 | .match = match, |
141 | .me = THIS_MODULE, | 140 | .matchsize = sizeof(struct xt_physdev_info), |
142 | }; | 141 | .me = THIS_MODULE, |
143 | 142 | }, | |
144 | static struct xt_match physdev6_match = { | 143 | { |
145 | .name = "physdev", | 144 | .name = "physdev", |
146 | .match = match, | 145 | .family = AF_INET6, |
147 | .matchsize = sizeof(struct xt_physdev_info), | 146 | .checkentry = checkentry, |
148 | .checkentry = checkentry, | 147 | .match = match, |
149 | .family = AF_INET6, | 148 | .matchsize = sizeof(struct xt_physdev_info), |
150 | .me = THIS_MODULE, | 149 | .me = THIS_MODULE, |
150 | }, | ||
151 | }; | 151 | }; |
152 | 152 | ||
153 | static int __init xt_physdev_init(void) | 153 | static int __init xt_physdev_init(void) |
154 | { | 154 | { |
155 | int ret; | 155 | return xt_register_matches(xt_physdev_match, |
156 | 156 | ARRAY_SIZE(xt_physdev_match)); | |
157 | ret = xt_register_match(&physdev_match); | ||
158 | if (ret < 0) | ||
159 | return ret; | ||
160 | |||
161 | ret = xt_register_match(&physdev6_match); | ||
162 | if (ret < 0) | ||
163 | xt_unregister_match(&physdev_match); | ||
164 | |||
165 | return ret; | ||
166 | } | 157 | } |
167 | 158 | ||
168 | static void __exit xt_physdev_fini(void) | 159 | static void __exit xt_physdev_fini(void) |
169 | { | 160 | { |
170 | xt_unregister_match(&physdev_match); | 161 | xt_unregister_matches(xt_physdev_match, ARRAY_SIZE(xt_physdev_match)); |
171 | xt_unregister_match(&physdev6_match); | ||
172 | } | 162 | } |
173 | 163 | ||
174 | module_init(xt_physdev_init); | 164 | module_init(xt_physdev_init); |
diff --git a/net/netfilter/xt_pkttype.c b/net/netfilter/xt_pkttype.c index d2f5320a80bf..16e7b0804287 100644 --- a/net/netfilter/xt_pkttype.c +++ b/net/netfilter/xt_pkttype.c | |||
@@ -43,40 +43,32 @@ static int match(const struct sk_buff *skb, | |||
43 | return (type == info->pkttype) ^ info->invert; | 43 | return (type == info->pkttype) ^ info->invert; |
44 | } | 44 | } |
45 | 45 | ||
46 | static struct xt_match pkttype_match = { | 46 | static struct xt_match xt_pkttype_match[] = { |
47 | .name = "pkttype", | 47 | { |
48 | .match = match, | 48 | .name = "pkttype", |
49 | .matchsize = sizeof(struct xt_pkttype_info), | 49 | .family = AF_INET, |
50 | .family = AF_INET, | 50 | .match = match, |
51 | .me = THIS_MODULE, | 51 | .matchsize = sizeof(struct xt_pkttype_info), |
52 | }; | 52 | .me = THIS_MODULE, |
53 | 53 | }, | |
54 | static struct xt_match pkttype6_match = { | 54 | { |
55 | .name = "pkttype", | 55 | .name = "pkttype", |
56 | .match = match, | 56 | .family = AF_INET6, |
57 | .matchsize = sizeof(struct xt_pkttype_info), | 57 | .match = match, |
58 | .family = AF_INET6, | 58 | .matchsize = sizeof(struct xt_pkttype_info), |
59 | .me = THIS_MODULE, | 59 | .me = THIS_MODULE, |
60 | }, | ||
60 | }; | 61 | }; |
61 | 62 | ||
62 | static int __init xt_pkttype_init(void) | 63 | static int __init xt_pkttype_init(void) |
63 | { | 64 | { |
64 | int ret; | 65 | return xt_register_matches(xt_pkttype_match, |
65 | ret = xt_register_match(&pkttype_match); | 66 | ARRAY_SIZE(xt_pkttype_match)); |
66 | if (ret) | ||
67 | return ret; | ||
68 | |||
69 | ret = xt_register_match(&pkttype6_match); | ||
70 | if (ret) | ||
71 | xt_unregister_match(&pkttype_match); | ||
72 | |||
73 | return ret; | ||
74 | } | 67 | } |
75 | 68 | ||
76 | static void __exit xt_pkttype_fini(void) | 69 | static void __exit xt_pkttype_fini(void) |
77 | { | 70 | { |
78 | xt_unregister_match(&pkttype_match); | 71 | xt_unregister_matches(xt_pkttype_match, ARRAY_SIZE(xt_pkttype_match)); |
79 | xt_unregister_match(&pkttype6_match); | ||
80 | } | 72 | } |
81 | 73 | ||
82 | module_init(xt_pkttype_init); | 74 | module_init(xt_pkttype_init); |
diff --git a/net/netfilter/xt_policy.c b/net/netfilter/xt_policy.c index ba1ca03abad3..46bde2b1e1e0 100644 --- a/net/netfilter/xt_policy.c +++ b/net/netfilter/xt_policy.c | |||
@@ -135,8 +135,7 @@ static int match(const struct sk_buff *skb, | |||
135 | 135 | ||
136 | static int checkentry(const char *tablename, const void *ip_void, | 136 | static int checkentry(const char *tablename, const void *ip_void, |
137 | const struct xt_match *match, | 137 | const struct xt_match *match, |
138 | void *matchinfo, unsigned int matchsize, | 138 | void *matchinfo, unsigned int hook_mask) |
139 | unsigned int hook_mask) | ||
140 | { | 139 | { |
141 | struct xt_policy_info *info = matchinfo; | 140 | struct xt_policy_info *info = matchinfo; |
142 | 141 | ||
@@ -165,43 +164,34 @@ static int checkentry(const char *tablename, const void *ip_void, | |||
165 | return 1; | 164 | return 1; |
166 | } | 165 | } |
167 | 166 | ||
168 | static struct xt_match policy_match = { | 167 | static struct xt_match xt_policy_match[] = { |
169 | .name = "policy", | 168 | { |
170 | .family = AF_INET, | 169 | .name = "policy", |
171 | .match = match, | 170 | .family = AF_INET, |
172 | .matchsize = sizeof(struct xt_policy_info), | 171 | .checkentry = checkentry, |
173 | .checkentry = checkentry, | 172 | .match = match, |
174 | .family = AF_INET, | 173 | .matchsize = sizeof(struct xt_policy_info), |
175 | .me = THIS_MODULE, | 174 | .me = THIS_MODULE, |
176 | }; | 175 | }, |
177 | 176 | { | |
178 | static struct xt_match policy6_match = { | 177 | .name = "policy", |
179 | .name = "policy", | 178 | .family = AF_INET6, |
180 | .family = AF_INET6, | 179 | .checkentry = checkentry, |
181 | .match = match, | 180 | .match = match, |
182 | .matchsize = sizeof(struct xt_policy_info), | 181 | .matchsize = sizeof(struct xt_policy_info), |
183 | .checkentry = checkentry, | 182 | .me = THIS_MODULE, |
184 | .family = AF_INET6, | 183 | }, |
185 | .me = THIS_MODULE, | ||
186 | }; | 184 | }; |
187 | 185 | ||
188 | static int __init init(void) | 186 | static int __init init(void) |
189 | { | 187 | { |
190 | int ret; | 188 | return xt_register_matches(xt_policy_match, |
191 | 189 | ARRAY_SIZE(xt_policy_match)); | |
192 | ret = xt_register_match(&policy_match); | ||
193 | if (ret) | ||
194 | return ret; | ||
195 | ret = xt_register_match(&policy6_match); | ||
196 | if (ret) | ||
197 | xt_unregister_match(&policy_match); | ||
198 | return ret; | ||
199 | } | 190 | } |
200 | 191 | ||
201 | static void __exit fini(void) | 192 | static void __exit fini(void) |
202 | { | 193 | { |
203 | xt_unregister_match(&policy6_match); | 194 | xt_unregister_matches(xt_policy_match, ARRAY_SIZE(xt_policy_match)); |
204 | xt_unregister_match(&policy_match); | ||
205 | } | 195 | } |
206 | 196 | ||
207 | module_init(init); | 197 | module_init(init); |
diff --git a/net/netfilter/xt_quota.c b/net/netfilter/xt_quota.c index be8d3c26b568..b75fa2c70e66 100644 --- a/net/netfilter/xt_quota.c +++ b/net/netfilter/xt_quota.c | |||
@@ -41,7 +41,7 @@ match(const struct sk_buff *skb, | |||
41 | static int | 41 | static int |
42 | checkentry(const char *tablename, const void *entry, | 42 | checkentry(const char *tablename, const void *entry, |
43 | const struct xt_match *match, void *matchinfo, | 43 | const struct xt_match *match, void *matchinfo, |
44 | unsigned int matchsize, unsigned int hook_mask) | 44 | unsigned int hook_mask) |
45 | { | 45 | { |
46 | struct xt_quota_info *q = (struct xt_quota_info *)matchinfo; | 46 | struct xt_quota_info *q = (struct xt_quota_info *)matchinfo; |
47 | 47 | ||
@@ -52,46 +52,33 @@ checkentry(const char *tablename, const void *entry, | |||
52 | return 1; | 52 | return 1; |
53 | } | 53 | } |
54 | 54 | ||
55 | static struct xt_match quota_match = { | 55 | static struct xt_match xt_quota_match[] = { |
56 | .name = "quota", | 56 | { |
57 | .family = AF_INET, | 57 | .name = "quota", |
58 | .match = match, | 58 | .family = AF_INET, |
59 | .matchsize = sizeof(struct xt_quota_info), | 59 | .checkentry = checkentry, |
60 | .checkentry = checkentry, | 60 | .match = match, |
61 | .me = THIS_MODULE | 61 | .matchsize = sizeof(struct xt_quota_info), |
62 | }; | 62 | .me = THIS_MODULE |
63 | 63 | }, | |
64 | static struct xt_match quota_match6 = { | 64 | { |
65 | .name = "quota", | 65 | .name = "quota", |
66 | .family = AF_INET6, | 66 | .family = AF_INET6, |
67 | .match = match, | 67 | .checkentry = checkentry, |
68 | .matchsize = sizeof(struct xt_quota_info), | 68 | .match = match, |
69 | .checkentry = checkentry, | 69 | .matchsize = sizeof(struct xt_quota_info), |
70 | .me = THIS_MODULE | 70 | .me = THIS_MODULE |
71 | }, | ||
71 | }; | 72 | }; |
72 | 73 | ||
73 | static int __init xt_quota_init(void) | 74 | static int __init xt_quota_init(void) |
74 | { | 75 | { |
75 | int ret; | 76 | return xt_register_matches(xt_quota_match, ARRAY_SIZE(xt_quota_match)); |
76 | |||
77 | ret = xt_register_match("a_match); | ||
78 | if (ret) | ||
79 | goto err1; | ||
80 | ret = xt_register_match("a_match6); | ||
81 | if (ret) | ||
82 | goto err2; | ||
83 | return ret; | ||
84 | |||
85 | err2: | ||
86 | xt_unregister_match("a_match); | ||
87 | err1: | ||
88 | return ret; | ||
89 | } | 77 | } |
90 | 78 | ||
91 | static void __exit xt_quota_fini(void) | 79 | static void __exit xt_quota_fini(void) |
92 | { | 80 | { |
93 | xt_unregister_match("a_match6); | 81 | xt_unregister_matches(xt_quota_match, ARRAY_SIZE(xt_quota_match)); |
94 | xt_unregister_match("a_match); | ||
95 | } | 82 | } |
96 | 83 | ||
97 | module_init(xt_quota_init); | 84 | module_init(xt_quota_init); |
diff --git a/net/netfilter/xt_sctp.c b/net/netfilter/xt_sctp.c index 843383e01d41..7956acaaa24b 100644 --- a/net/netfilter/xt_sctp.c +++ b/net/netfilter/xt_sctp.c | |||
@@ -163,7 +163,6 @@ checkentry(const char *tablename, | |||
163 | const void *inf, | 163 | const void *inf, |
164 | const struct xt_match *match, | 164 | const struct xt_match *match, |
165 | void *matchinfo, | 165 | void *matchinfo, |
166 | unsigned int matchsize, | ||
167 | unsigned int hook_mask) | 166 | unsigned int hook_mask) |
168 | { | 167 | { |
169 | const struct xt_sctp_info *info = matchinfo; | 168 | const struct xt_sctp_info *info = matchinfo; |
@@ -178,44 +177,35 @@ checkentry(const char *tablename, | |||
178 | | SCTP_CHUNK_MATCH_ONLY))); | 177 | | SCTP_CHUNK_MATCH_ONLY))); |
179 | } | 178 | } |
180 | 179 | ||
181 | static struct xt_match sctp_match = { | 180 | static struct xt_match xt_sctp_match[] = { |
182 | .name = "sctp", | 181 | { |
183 | .match = match, | 182 | .name = "sctp", |
184 | .matchsize = sizeof(struct xt_sctp_info), | 183 | .family = AF_INET, |
185 | .proto = IPPROTO_SCTP, | 184 | .checkentry = checkentry, |
186 | .checkentry = checkentry, | 185 | .match = match, |
187 | .family = AF_INET, | 186 | .matchsize = sizeof(struct xt_sctp_info), |
188 | .me = THIS_MODULE | 187 | .proto = IPPROTO_SCTP, |
189 | }; | 188 | .me = THIS_MODULE |
190 | 189 | }, | |
191 | static struct xt_match sctp6_match = { | 190 | { |
192 | .name = "sctp", | 191 | .name = "sctp", |
193 | .match = match, | 192 | .family = AF_INET6, |
194 | .matchsize = sizeof(struct xt_sctp_info), | 193 | .checkentry = checkentry, |
195 | .proto = IPPROTO_SCTP, | 194 | .match = match, |
196 | .checkentry = checkentry, | 195 | .matchsize = sizeof(struct xt_sctp_info), |
197 | .family = AF_INET6, | 196 | .proto = IPPROTO_SCTP, |
198 | .me = THIS_MODULE | 197 | .me = THIS_MODULE |
198 | }, | ||
199 | }; | 199 | }; |
200 | 200 | ||
201 | static int __init xt_sctp_init(void) | 201 | static int __init xt_sctp_init(void) |
202 | { | 202 | { |
203 | int ret; | 203 | return xt_register_matches(xt_sctp_match, ARRAY_SIZE(xt_sctp_match)); |
204 | ret = xt_register_match(&sctp_match); | ||
205 | if (ret) | ||
206 | return ret; | ||
207 | |||
208 | ret = xt_register_match(&sctp6_match); | ||
209 | if (ret) | ||
210 | xt_unregister_match(&sctp_match); | ||
211 | |||
212 | return ret; | ||
213 | } | 204 | } |
214 | 205 | ||
215 | static void __exit xt_sctp_fini(void) | 206 | static void __exit xt_sctp_fini(void) |
216 | { | 207 | { |
217 | xt_unregister_match(&sctp6_match); | 208 | xt_unregister_matches(xt_sctp_match, ARRAY_SIZE(xt_sctp_match)); |
218 | xt_unregister_match(&sctp_match); | ||
219 | } | 209 | } |
220 | 210 | ||
221 | module_init(xt_sctp_init); | 211 | module_init(xt_sctp_init); |
diff --git a/net/netfilter/xt_state.c b/net/netfilter/xt_state.c index f9e304dc4504..d9010b16a1f9 100644 --- a/net/netfilter/xt_state.c +++ b/net/netfilter/xt_state.c | |||
@@ -48,7 +48,6 @@ static int check(const char *tablename, | |||
48 | const void *inf, | 48 | const void *inf, |
49 | const struct xt_match *match, | 49 | const struct xt_match *match, |
50 | void *matchinfo, | 50 | void *matchinfo, |
51 | unsigned int matchsize, | ||
52 | unsigned int hook_mask) | 51 | unsigned int hook_mask) |
53 | { | 52 | { |
54 | #if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE) | 53 | #if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE) |
@@ -62,54 +61,43 @@ static int check(const char *tablename, | |||
62 | } | 61 | } |
63 | 62 | ||
64 | static void | 63 | static void |
65 | destroy(const struct xt_match *match, void *matchinfo, unsigned int matchsize) | 64 | destroy(const struct xt_match *match, void *matchinfo) |
66 | { | 65 | { |
67 | #if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE) | 66 | #if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE) |
68 | nf_ct_l3proto_module_put(match->family); | 67 | nf_ct_l3proto_module_put(match->family); |
69 | #endif | 68 | #endif |
70 | } | 69 | } |
71 | 70 | ||
72 | static struct xt_match state_match = { | 71 | static struct xt_match xt_state_match[] = { |
73 | .name = "state", | 72 | { |
74 | .match = match, | 73 | .name = "state", |
75 | .checkentry = check, | 74 | .family = AF_INET, |
76 | .destroy = destroy, | 75 | .checkentry = check, |
77 | .matchsize = sizeof(struct xt_state_info), | 76 | .match = match, |
78 | .family = AF_INET, | 77 | .destroy = destroy, |
79 | .me = THIS_MODULE, | 78 | .matchsize = sizeof(struct xt_state_info), |
80 | }; | 79 | .me = THIS_MODULE, |
81 | 80 | }, | |
82 | static struct xt_match state6_match = { | 81 | { |
83 | .name = "state", | 82 | .name = "state", |
84 | .match = match, | 83 | .family = AF_INET6, |
85 | .checkentry = check, | 84 | .checkentry = check, |
86 | .destroy = destroy, | 85 | .match = match, |
87 | .matchsize = sizeof(struct xt_state_info), | 86 | .destroy = destroy, |
88 | .family = AF_INET6, | 87 | .matchsize = sizeof(struct xt_state_info), |
89 | .me = THIS_MODULE, | 88 | .me = THIS_MODULE, |
89 | }, | ||
90 | }; | 90 | }; |
91 | 91 | ||
92 | static int __init xt_state_init(void) | 92 | static int __init xt_state_init(void) |
93 | { | 93 | { |
94 | int ret; | ||
95 | |||
96 | need_conntrack(); | 94 | need_conntrack(); |
97 | 95 | return xt_register_matches(xt_state_match, ARRAY_SIZE(xt_state_match)); | |
98 | ret = xt_register_match(&state_match); | ||
99 | if (ret < 0) | ||
100 | return ret; | ||
101 | |||
102 | ret = xt_register_match(&state6_match); | ||
103 | if (ret < 0) | ||
104 | xt_unregister_match(&state_match); | ||
105 | |||
106 | return ret; | ||
107 | } | 96 | } |
108 | 97 | ||
109 | static void __exit xt_state_fini(void) | 98 | static void __exit xt_state_fini(void) |
110 | { | 99 | { |
111 | xt_unregister_match(&state_match); | 100 | xt_unregister_matches(xt_state_match, ARRAY_SIZE(xt_state_match)); |
112 | xt_unregister_match(&state6_match); | ||
113 | } | 101 | } |
114 | 102 | ||
115 | module_init(xt_state_init); | 103 | module_init(xt_state_init); |
diff --git a/net/netfilter/xt_statistic.c b/net/netfilter/xt_statistic.c index de1037f58596..091a9f89f5d5 100644 --- a/net/netfilter/xt_statistic.c +++ b/net/netfilter/xt_statistic.c | |||
@@ -55,7 +55,7 @@ match(const struct sk_buff *skb, | |||
55 | static int | 55 | static int |
56 | checkentry(const char *tablename, const void *entry, | 56 | checkentry(const char *tablename, const void *entry, |
57 | const struct xt_match *match, void *matchinfo, | 57 | const struct xt_match *match, void *matchinfo, |
58 | unsigned int matchsize, unsigned int hook_mask) | 58 | unsigned int hook_mask) |
59 | { | 59 | { |
60 | struct xt_statistic_info *info = (struct xt_statistic_info *)matchinfo; | 60 | struct xt_statistic_info *info = (struct xt_statistic_info *)matchinfo; |
61 | 61 | ||
@@ -66,46 +66,35 @@ checkentry(const char *tablename, const void *entry, | |||
66 | return 1; | 66 | return 1; |
67 | } | 67 | } |
68 | 68 | ||
69 | static struct xt_match statistic_match = { | 69 | static struct xt_match xt_statistic_match[] = { |
70 | .name = "statistic", | 70 | { |
71 | .match = match, | 71 | .name = "statistic", |
72 | .matchsize = sizeof(struct xt_statistic_info), | 72 | .family = AF_INET, |
73 | .checkentry = checkentry, | 73 | .checkentry = checkentry, |
74 | .family = AF_INET, | 74 | .match = match, |
75 | .me = THIS_MODULE, | 75 | .matchsize = sizeof(struct xt_statistic_info), |
76 | }; | 76 | .me = THIS_MODULE, |
77 | 77 | }, | |
78 | static struct xt_match statistic_match6 = { | 78 | { |
79 | .name = "statistic", | 79 | .name = "statistic", |
80 | .match = match, | 80 | .family = AF_INET6, |
81 | .matchsize = sizeof(struct xt_statistic_info), | 81 | .checkentry = checkentry, |
82 | .checkentry = checkentry, | 82 | .match = match, |
83 | .family = AF_INET6, | 83 | .matchsize = sizeof(struct xt_statistic_info), |
84 | .me = THIS_MODULE, | 84 | .me = THIS_MODULE, |
85 | }, | ||
85 | }; | 86 | }; |
86 | 87 | ||
87 | static int __init xt_statistic_init(void) | 88 | static int __init xt_statistic_init(void) |
88 | { | 89 | { |
89 | int ret; | 90 | return xt_register_matches(xt_statistic_match, |
90 | 91 | ARRAY_SIZE(xt_statistic_match)); | |
91 | ret = xt_register_match(&statistic_match); | ||
92 | if (ret) | ||
93 | goto err1; | ||
94 | |||
95 | ret = xt_register_match(&statistic_match6); | ||
96 | if (ret) | ||
97 | goto err2; | ||
98 | return ret; | ||
99 | err2: | ||
100 | xt_unregister_match(&statistic_match); | ||
101 | err1: | ||
102 | return ret; | ||
103 | } | 92 | } |
104 | 93 | ||
105 | static void __exit xt_statistic_fini(void) | 94 | static void __exit xt_statistic_fini(void) |
106 | { | 95 | { |
107 | xt_unregister_match(&statistic_match6); | 96 | xt_unregister_matches(xt_statistic_match, |
108 | xt_unregister_match(&statistic_match); | 97 | ARRAY_SIZE(xt_statistic_match)); |
109 | } | 98 | } |
110 | 99 | ||
111 | module_init(xt_statistic_init); | 100 | module_init(xt_statistic_init); |
diff --git a/net/netfilter/xt_string.c b/net/netfilter/xt_string.c index 275330fcdaaa..4453252400aa 100644 --- a/net/netfilter/xt_string.c +++ b/net/netfilter/xt_string.c | |||
@@ -46,7 +46,6 @@ static int checkentry(const char *tablename, | |||
46 | const void *ip, | 46 | const void *ip, |
47 | const struct xt_match *match, | 47 | const struct xt_match *match, |
48 | void *matchinfo, | 48 | void *matchinfo, |
49 | unsigned int matchsize, | ||
50 | unsigned int hook_mask) | 49 | unsigned int hook_mask) |
51 | { | 50 | { |
52 | struct xt_string_info *conf = matchinfo; | 51 | struct xt_string_info *conf = matchinfo; |
@@ -69,49 +68,40 @@ static int checkentry(const char *tablename, | |||
69 | return 1; | 68 | return 1; |
70 | } | 69 | } |
71 | 70 | ||
72 | static void destroy(const struct xt_match *match, void *matchinfo, | 71 | static void destroy(const struct xt_match *match, void *matchinfo) |
73 | unsigned int matchsize) | ||
74 | { | 72 | { |
75 | textsearch_destroy(STRING_TEXT_PRIV(matchinfo)->config); | 73 | textsearch_destroy(STRING_TEXT_PRIV(matchinfo)->config); |
76 | } | 74 | } |
77 | 75 | ||
78 | static struct xt_match string_match = { | 76 | static struct xt_match xt_string_match[] = { |
79 | .name = "string", | 77 | { |
80 | .match = match, | 78 | .name = "string", |
81 | .matchsize = sizeof(struct xt_string_info), | 79 | .family = AF_INET, |
82 | .checkentry = checkentry, | 80 | .checkentry = checkentry, |
83 | .destroy = destroy, | 81 | .match = match, |
84 | .family = AF_INET, | 82 | .destroy = destroy, |
85 | .me = THIS_MODULE | 83 | .matchsize = sizeof(struct xt_string_info), |
86 | }; | 84 | .me = THIS_MODULE |
87 | static struct xt_match string6_match = { | 85 | }, |
88 | .name = "string", | 86 | { |
89 | .match = match, | 87 | .name = "string", |
90 | .matchsize = sizeof(struct xt_string_info), | 88 | .family = AF_INET6, |
91 | .checkentry = checkentry, | 89 | .checkentry = checkentry, |
92 | .destroy = destroy, | 90 | .match = match, |
93 | .family = AF_INET6, | 91 | .destroy = destroy, |
94 | .me = THIS_MODULE | 92 | .matchsize = sizeof(struct xt_string_info), |
93 | .me = THIS_MODULE | ||
94 | }, | ||
95 | }; | 95 | }; |
96 | 96 | ||
97 | static int __init xt_string_init(void) | 97 | static int __init xt_string_init(void) |
98 | { | 98 | { |
99 | int ret; | 99 | return xt_register_matches(xt_string_match, ARRAY_SIZE(xt_string_match)); |
100 | |||
101 | ret = xt_register_match(&string_match); | ||
102 | if (ret) | ||
103 | return ret; | ||
104 | ret = xt_register_match(&string6_match); | ||
105 | if (ret) | ||
106 | xt_unregister_match(&string_match); | ||
107 | |||
108 | return ret; | ||
109 | } | 100 | } |
110 | 101 | ||
111 | static void __exit xt_string_fini(void) | 102 | static void __exit xt_string_fini(void) |
112 | { | 103 | { |
113 | xt_unregister_match(&string_match); | 104 | xt_unregister_matches(xt_string_match, ARRAY_SIZE(xt_string_match)); |
114 | xt_unregister_match(&string6_match); | ||
115 | } | 105 | } |
116 | 106 | ||
117 | module_init(xt_string_init); | 107 | module_init(xt_string_init); |
diff --git a/net/netfilter/xt_tcpmss.c b/net/netfilter/xt_tcpmss.c index cf7d335cadcd..a3682fe2f192 100644 --- a/net/netfilter/xt_tcpmss.c +++ b/net/netfilter/xt_tcpmss.c | |||
@@ -18,21 +18,22 @@ | |||
18 | #include <linux/netfilter_ipv4/ip_tables.h> | 18 | #include <linux/netfilter_ipv4/ip_tables.h> |
19 | #include <linux/netfilter_ipv6/ip6_tables.h> | 19 | #include <linux/netfilter_ipv6/ip6_tables.h> |
20 | 20 | ||
21 | #define TH_SYN 0x02 | ||
22 | |||
23 | MODULE_LICENSE("GPL"); | 21 | MODULE_LICENSE("GPL"); |
24 | MODULE_AUTHOR("Marc Boucher <marc@mbsi.ca>"); | 22 | MODULE_AUTHOR("Marc Boucher <marc@mbsi.ca>"); |
25 | MODULE_DESCRIPTION("iptables TCP MSS match module"); | 23 | MODULE_DESCRIPTION("iptables TCP MSS match module"); |
26 | MODULE_ALIAS("ipt_tcpmss"); | 24 | MODULE_ALIAS("ipt_tcpmss"); |
27 | 25 | ||
28 | /* Returns 1 if the mss option is set and matched by the range, 0 otherwise */ | 26 | static int |
29 | static inline int | 27 | match(const struct sk_buff *skb, |
30 | mssoption_match(u_int16_t min, u_int16_t max, | 28 | const struct net_device *in, |
31 | const struct sk_buff *skb, | 29 | const struct net_device *out, |
32 | unsigned int protoff, | 30 | const struct xt_match *match, |
33 | int invert, | 31 | const void *matchinfo, |
34 | int *hotdrop) | 32 | int offset, |
33 | unsigned int protoff, | ||
34 | int *hotdrop) | ||
35 | { | 35 | { |
36 | const struct xt_tcpmss_match_info *info = matchinfo; | ||
36 | struct tcphdr _tcph, *th; | 37 | struct tcphdr _tcph, *th; |
37 | /* tcp.doff is only 4 bits, ie. max 15 * 4 bytes */ | 38 | /* tcp.doff is only 4 bits, ie. max 15 * 4 bytes */ |
38 | u8 _opt[15 * 4 - sizeof(_tcph)], *op; | 39 | u8 _opt[15 * 4 - sizeof(_tcph)], *op; |
@@ -64,72 +65,50 @@ mssoption_match(u_int16_t min, u_int16_t max, | |||
64 | 65 | ||
65 | mssval = (op[i+2] << 8) | op[i+3]; | 66 | mssval = (op[i+2] << 8) | op[i+3]; |
66 | 67 | ||
67 | return (mssval >= min && mssval <= max) ^ invert; | 68 | return (mssval >= info->mss_min && |
69 | mssval <= info->mss_max) ^ info->invert; | ||
68 | } | 70 | } |
69 | if (op[i] < 2) i++; | 71 | if (op[i] < 2) |
70 | else i += op[i+1]?:1; | 72 | i++; |
73 | else | ||
74 | i += op[i+1] ? : 1; | ||
71 | } | 75 | } |
72 | out: | 76 | out: |
73 | return invert; | 77 | return info->invert; |
74 | 78 | ||
75 | dropit: | 79 | dropit: |
76 | *hotdrop = 1; | 80 | *hotdrop = 1; |
77 | return 0; | 81 | return 0; |
78 | } | 82 | } |
79 | 83 | ||
80 | static int | 84 | static struct xt_match xt_tcpmss_match[] = { |
81 | match(const struct sk_buff *skb, | 85 | { |
82 | const struct net_device *in, | 86 | .name = "tcpmss", |
83 | const struct net_device *out, | 87 | .family = AF_INET, |
84 | const struct xt_match *match, | 88 | .match = match, |
85 | const void *matchinfo, | 89 | .matchsize = sizeof(struct xt_tcpmss_match_info), |
86 | int offset, | 90 | .proto = IPPROTO_TCP, |
87 | unsigned int protoff, | 91 | .me = THIS_MODULE, |
88 | int *hotdrop) | 92 | }, |
89 | { | 93 | { |
90 | const struct xt_tcpmss_match_info *info = matchinfo; | 94 | .name = "tcpmss", |
91 | 95 | .family = AF_INET6, | |
92 | return mssoption_match(info->mss_min, info->mss_max, skb, protoff, | 96 | .match = match, |
93 | info->invert, hotdrop); | 97 | .matchsize = sizeof(struct xt_tcpmss_match_info), |
94 | } | 98 | .proto = IPPROTO_TCP, |
95 | 99 | .me = THIS_MODULE, | |
96 | static struct xt_match tcpmss_match = { | 100 | }, |
97 | .name = "tcpmss", | ||
98 | .match = match, | ||
99 | .matchsize = sizeof(struct xt_tcpmss_match_info), | ||
100 | .proto = IPPROTO_TCP, | ||
101 | .family = AF_INET, | ||
102 | .me = THIS_MODULE, | ||
103 | }; | ||
104 | |||
105 | static struct xt_match tcpmss6_match = { | ||
106 | .name = "tcpmss", | ||
107 | .match = match, | ||
108 | .matchsize = sizeof(struct xt_tcpmss_match_info), | ||
109 | .proto = IPPROTO_TCP, | ||
110 | .family = AF_INET6, | ||
111 | .me = THIS_MODULE, | ||
112 | }; | 101 | }; |
113 | 102 | ||
114 | |||
115 | static int __init xt_tcpmss_init(void) | 103 | static int __init xt_tcpmss_init(void) |
116 | { | 104 | { |
117 | int ret; | 105 | return xt_register_matches(xt_tcpmss_match, |
118 | ret = xt_register_match(&tcpmss_match); | 106 | ARRAY_SIZE(xt_tcpmss_match)); |
119 | if (ret) | ||
120 | return ret; | ||
121 | |||
122 | ret = xt_register_match(&tcpmss6_match); | ||
123 | if (ret) | ||
124 | xt_unregister_match(&tcpmss_match); | ||
125 | |||
126 | return ret; | ||
127 | } | 107 | } |
128 | 108 | ||
129 | static void __exit xt_tcpmss_fini(void) | 109 | static void __exit xt_tcpmss_fini(void) |
130 | { | 110 | { |
131 | xt_unregister_match(&tcpmss6_match); | 111 | xt_unregister_matches(xt_tcpmss_match, ARRAY_SIZE(xt_tcpmss_match)); |
132 | xt_unregister_match(&tcpmss_match); | ||
133 | } | 112 | } |
134 | 113 | ||
135 | module_init(xt_tcpmss_init); | 114 | module_init(xt_tcpmss_init); |
diff --git a/net/netfilter/xt_tcpudp.c b/net/netfilter/xt_tcpudp.c index a9a63aa68936..e76a68e0bc66 100644 --- a/net/netfilter/xt_tcpudp.c +++ b/net/netfilter/xt_tcpudp.c | |||
@@ -141,7 +141,6 @@ tcp_checkentry(const char *tablename, | |||
141 | const void *info, | 141 | const void *info, |
142 | const struct xt_match *match, | 142 | const struct xt_match *match, |
143 | void *matchinfo, | 143 | void *matchinfo, |
144 | unsigned int matchsize, | ||
145 | unsigned int hook_mask) | 144 | unsigned int hook_mask) |
146 | { | 145 | { |
147 | const struct xt_tcp *tcpinfo = matchinfo; | 146 | const struct xt_tcp *tcpinfo = matchinfo; |
@@ -190,7 +189,6 @@ udp_checkentry(const char *tablename, | |||
190 | const void *info, | 189 | const void *info, |
191 | const struct xt_match *match, | 190 | const struct xt_match *match, |
192 | void *matchinfo, | 191 | void *matchinfo, |
193 | unsigned int matchsize, | ||
194 | unsigned int hook_mask) | 192 | unsigned int hook_mask) |
195 | { | 193 | { |
196 | const struct xt_tcp *udpinfo = matchinfo; | 194 | const struct xt_tcp *udpinfo = matchinfo; |
@@ -199,81 +197,54 @@ udp_checkentry(const char *tablename, | |||
199 | return !(udpinfo->invflags & ~XT_UDP_INV_MASK); | 197 | return !(udpinfo->invflags & ~XT_UDP_INV_MASK); |
200 | } | 198 | } |
201 | 199 | ||
202 | static struct xt_match tcp_matchstruct = { | 200 | static struct xt_match xt_tcpudp_match[] = { |
203 | .name = "tcp", | 201 | { |
204 | .match = tcp_match, | 202 | .name = "tcp", |
205 | .matchsize = sizeof(struct xt_tcp), | 203 | .family = AF_INET, |
206 | .proto = IPPROTO_TCP, | 204 | .checkentry = tcp_checkentry, |
207 | .family = AF_INET, | 205 | .match = tcp_match, |
208 | .checkentry = tcp_checkentry, | 206 | .matchsize = sizeof(struct xt_tcp), |
209 | .me = THIS_MODULE, | 207 | .proto = IPPROTO_TCP, |
210 | }; | 208 | .me = THIS_MODULE, |
211 | 209 | }, | |
212 | static struct xt_match tcp6_matchstruct = { | 210 | { |
213 | .name = "tcp", | 211 | .name = "tcp", |
214 | .match = tcp_match, | 212 | .family = AF_INET6, |
215 | .matchsize = sizeof(struct xt_tcp), | 213 | .checkentry = tcp_checkentry, |
216 | .proto = IPPROTO_TCP, | 214 | .match = tcp_match, |
217 | .family = AF_INET6, | 215 | .matchsize = sizeof(struct xt_tcp), |
218 | .checkentry = tcp_checkentry, | 216 | .proto = IPPROTO_TCP, |
219 | .me = THIS_MODULE, | 217 | .me = THIS_MODULE, |
220 | }; | 218 | }, |
221 | 219 | { | |
222 | static struct xt_match udp_matchstruct = { | 220 | .name = "udp", |
223 | .name = "udp", | 221 | .family = AF_INET, |
224 | .match = udp_match, | 222 | .checkentry = udp_checkentry, |
225 | .matchsize = sizeof(struct xt_udp), | 223 | .match = udp_match, |
226 | .proto = IPPROTO_UDP, | 224 | .matchsize = sizeof(struct xt_udp), |
227 | .family = AF_INET, | 225 | .proto = IPPROTO_UDP, |
228 | .checkentry = udp_checkentry, | 226 | .me = THIS_MODULE, |
229 | .me = THIS_MODULE, | 227 | }, |
230 | }; | 228 | { |
231 | static struct xt_match udp6_matchstruct = { | 229 | .name = "udp", |
232 | .name = "udp", | 230 | .family = AF_INET6, |
233 | .match = udp_match, | 231 | .checkentry = udp_checkentry, |
234 | .matchsize = sizeof(struct xt_udp), | 232 | .match = udp_match, |
235 | .proto = IPPROTO_UDP, | 233 | .matchsize = sizeof(struct xt_udp), |
236 | .family = AF_INET6, | 234 | .proto = IPPROTO_UDP, |
237 | .checkentry = udp_checkentry, | 235 | .me = THIS_MODULE, |
238 | .me = THIS_MODULE, | 236 | }, |
239 | }; | 237 | }; |
240 | 238 | ||
241 | static int __init xt_tcpudp_init(void) | 239 | static int __init xt_tcpudp_init(void) |
242 | { | 240 | { |
243 | int ret; | 241 | return xt_register_matches(xt_tcpudp_match, |
244 | ret = xt_register_match(&tcp_matchstruct); | 242 | ARRAY_SIZE(xt_tcpudp_match)); |
245 | if (ret) | ||
246 | return ret; | ||
247 | |||
248 | ret = xt_register_match(&tcp6_matchstruct); | ||
249 | if (ret) | ||
250 | goto out_unreg_tcp; | ||
251 | |||
252 | ret = xt_register_match(&udp_matchstruct); | ||
253 | if (ret) | ||
254 | goto out_unreg_tcp6; | ||
255 | |||
256 | ret = xt_register_match(&udp6_matchstruct); | ||
257 | if (ret) | ||
258 | goto out_unreg_udp; | ||
259 | |||
260 | return ret; | ||
261 | |||
262 | out_unreg_udp: | ||
263 | xt_unregister_match(&udp_matchstruct); | ||
264 | out_unreg_tcp6: | ||
265 | xt_unregister_match(&tcp6_matchstruct); | ||
266 | out_unreg_tcp: | ||
267 | xt_unregister_match(&tcp_matchstruct); | ||
268 | return ret; | ||
269 | } | 243 | } |
270 | 244 | ||
271 | static void __exit xt_tcpudp_fini(void) | 245 | static void __exit xt_tcpudp_fini(void) |
272 | { | 246 | { |
273 | xt_unregister_match(&udp6_matchstruct); | 247 | xt_unregister_matches(xt_tcpudp_match, ARRAY_SIZE(xt_tcpudp_match)); |
274 | xt_unregister_match(&udp_matchstruct); | ||
275 | xt_unregister_match(&tcp6_matchstruct); | ||
276 | xt_unregister_match(&tcp_matchstruct); | ||
277 | } | 248 | } |
278 | 249 | ||
279 | module_init(xt_tcpudp_init); | 250 | module_init(xt_tcpudp_init); |
diff --git a/net/netlabel/Kconfig b/net/netlabel/Kconfig new file mode 100644 index 000000000000..fe23cb7f1e87 --- /dev/null +++ b/net/netlabel/Kconfig | |||
@@ -0,0 +1,14 @@ | |||
1 | # | ||
2 | # NetLabel configuration | ||
3 | # | ||
4 | |||
5 | config NETLABEL | ||
6 | bool "NetLabel subsystem support" | ||
7 | depends on NET && SECURITY | ||
8 | default n | ||
9 | ---help--- | ||
10 | NetLabel provides support for explicit network packet labeling | ||
11 | protocols such as CIPSO and RIPSO. For more information see | ||
12 | Documentation/netlabel. | ||
13 | |||
14 | If you are unsure, say N. | ||
diff --git a/net/netlabel/Makefile b/net/netlabel/Makefile new file mode 100644 index 000000000000..8af18c0a47d9 --- /dev/null +++ b/net/netlabel/Makefile | |||
@@ -0,0 +1,16 @@ | |||
1 | # | ||
2 | # Makefile for the NetLabel subsystem. | ||
3 | # | ||
4 | # Feb 9, 2006, Paul Moore <paul.moore@hp.com> | ||
5 | # | ||
6 | |||
7 | # base objects | ||
8 | obj-y := netlabel_user.o netlabel_kapi.o netlabel_domainhash.o | ||
9 | |||
10 | # management objects | ||
11 | obj-y += netlabel_mgmt.o | ||
12 | |||
13 | # protocol modules | ||
14 | obj-y += netlabel_unlabeled.o | ||
15 | obj-y += netlabel_cipso_v4.o | ||
16 | |||
diff --git a/net/netlabel/netlabel_cipso_v4.c b/net/netlabel/netlabel_cipso_v4.c new file mode 100644 index 000000000000..a4f40adc447b --- /dev/null +++ b/net/netlabel/netlabel_cipso_v4.c | |||
@@ -0,0 +1,542 @@ | |||
1 | /* | ||
2 | * NetLabel CIPSO/IPv4 Support | ||
3 | * | ||
4 | * This file defines the CIPSO/IPv4 functions for the NetLabel system. The | ||
5 | * NetLabel system manages static and dynamic label mappings for network | ||
6 | * protocols such as CIPSO and RIPSO. | ||
7 | * | ||
8 | * Author: Paul Moore <paul.moore@hp.com> | ||
9 | * | ||
10 | */ | ||
11 | |||
12 | /* | ||
13 | * (c) Copyright Hewlett-Packard Development Company, L.P., 2006 | ||
14 | * | ||
15 | * This program is free software; you can redistribute it and/or modify | ||
16 | * it under the terms of the GNU General Public License as published by | ||
17 | * the Free Software Foundation; either version 2 of the License, or | ||
18 | * (at your option) any later version. | ||
19 | * | ||
20 | * This program is distributed in the hope that it will be useful, | ||
21 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
22 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See | ||
23 | * the GNU General Public License for more details. | ||
24 | * | ||
25 | * You should have received a copy of the GNU General Public License | ||
26 | * along with this program; if not, write to the Free Software | ||
27 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
28 | * | ||
29 | */ | ||
30 | |||
31 | #include <linux/types.h> | ||
32 | #include <linux/socket.h> | ||
33 | #include <linux/string.h> | ||
34 | #include <linux/skbuff.h> | ||
35 | #include <net/sock.h> | ||
36 | #include <net/netlink.h> | ||
37 | #include <net/genetlink.h> | ||
38 | #include <net/netlabel.h> | ||
39 | #include <net/cipso_ipv4.h> | ||
40 | |||
41 | #include "netlabel_user.h" | ||
42 | #include "netlabel_cipso_v4.h" | ||
43 | |||
44 | /* NetLabel Generic NETLINK CIPSOv4 family */ | ||
45 | static struct genl_family netlbl_cipsov4_gnl_family = { | ||
46 | .id = GENL_ID_GENERATE, | ||
47 | .hdrsize = 0, | ||
48 | .name = NETLBL_NLTYPE_CIPSOV4_NAME, | ||
49 | .version = NETLBL_PROTO_VERSION, | ||
50 | .maxattr = 0, | ||
51 | }; | ||
52 | |||
53 | |||
54 | /* | ||
55 | * Helper Functions | ||
56 | */ | ||
57 | |||
58 | /** | ||
59 | * netlbl_cipsov4_doi_free - Frees a CIPSO V4 DOI definition | ||
60 | * @entry: the entry's RCU field | ||
61 | * | ||
62 | * Description: | ||
63 | * This function is designed to be used as a callback to the call_rcu() | ||
64 | * function so that the memory allocated to the DOI definition can be released | ||
65 | * safely. | ||
66 | * | ||
67 | */ | ||
68 | static void netlbl_cipsov4_doi_free(struct rcu_head *entry) | ||
69 | { | ||
70 | struct cipso_v4_doi *ptr; | ||
71 | |||
72 | ptr = container_of(entry, struct cipso_v4_doi, rcu); | ||
73 | switch (ptr->type) { | ||
74 | case CIPSO_V4_MAP_STD: | ||
75 | kfree(ptr->map.std->lvl.cipso); | ||
76 | kfree(ptr->map.std->lvl.local); | ||
77 | kfree(ptr->map.std->cat.cipso); | ||
78 | kfree(ptr->map.std->cat.local); | ||
79 | break; | ||
80 | } | ||
81 | kfree(ptr); | ||
82 | } | ||
83 | |||
84 | |||
85 | /* | ||
86 | * NetLabel Command Handlers | ||
87 | */ | ||
88 | |||
89 | /** | ||
90 | * netlbl_cipsov4_add_std - Adds a CIPSO V4 DOI definition | ||
91 | * @doi: the DOI value | ||
92 | * @msg: the ADD message data | ||
93 | * @msg_size: the size of the ADD message buffer | ||
94 | * | ||
95 | * Description: | ||
96 | * Create a new CIPSO_V4_MAP_STD DOI definition based on the given ADD message | ||
97 | * and add it to the CIPSO V4 engine. Return zero on success and non-zero on | ||
98 | * error. | ||
99 | * | ||
100 | */ | ||
101 | static int netlbl_cipsov4_add_std(u32 doi, struct nlattr *msg, size_t msg_size) | ||
102 | { | ||
103 | int ret_val = -EINVAL; | ||
104 | int msg_len = msg_size; | ||
105 | u32 num_tags; | ||
106 | u32 num_lvls; | ||
107 | u32 num_cats; | ||
108 | struct cipso_v4_doi *doi_def = NULL; | ||
109 | u32 iter; | ||
110 | u32 tmp_val_a; | ||
111 | u32 tmp_val_b; | ||
112 | |||
113 | if (msg_len < NETLBL_LEN_U32) | ||
114 | goto add_std_failure; | ||
115 | num_tags = netlbl_getinc_u32(&msg, &msg_len); | ||
116 | if (num_tags == 0 || num_tags > CIPSO_V4_TAG_MAXCNT) | ||
117 | goto add_std_failure; | ||
118 | |||
119 | doi_def = kmalloc(sizeof(*doi_def), GFP_KERNEL); | ||
120 | if (doi_def == NULL) { | ||
121 | ret_val = -ENOMEM; | ||
122 | goto add_std_failure; | ||
123 | } | ||
124 | doi_def->map.std = kzalloc(sizeof(*doi_def->map.std), GFP_KERNEL); | ||
125 | if (doi_def->map.std == NULL) { | ||
126 | ret_val = -ENOMEM; | ||
127 | goto add_std_failure; | ||
128 | } | ||
129 | doi_def->type = CIPSO_V4_MAP_STD; | ||
130 | |||
131 | for (iter = 0; iter < num_tags; iter++) { | ||
132 | if (msg_len < NETLBL_LEN_U8) | ||
133 | goto add_std_failure; | ||
134 | doi_def->tags[iter] = netlbl_getinc_u8(&msg, &msg_len); | ||
135 | switch (doi_def->tags[iter]) { | ||
136 | case CIPSO_V4_TAG_RBITMAP: | ||
137 | break; | ||
138 | default: | ||
139 | goto add_std_failure; | ||
140 | } | ||
141 | } | ||
142 | if (iter < CIPSO_V4_TAG_MAXCNT) | ||
143 | doi_def->tags[iter] = CIPSO_V4_TAG_INVALID; | ||
144 | |||
145 | if (msg_len < 6 * NETLBL_LEN_U32) | ||
146 | goto add_std_failure; | ||
147 | |||
148 | num_lvls = netlbl_getinc_u32(&msg, &msg_len); | ||
149 | if (num_lvls == 0) | ||
150 | goto add_std_failure; | ||
151 | doi_def->map.std->lvl.local_size = netlbl_getinc_u32(&msg, &msg_len); | ||
152 | if (doi_def->map.std->lvl.local_size > CIPSO_V4_MAX_LOC_LVLS) | ||
153 | goto add_std_failure; | ||
154 | doi_def->map.std->lvl.local = kcalloc(doi_def->map.std->lvl.local_size, | ||
155 | sizeof(u32), | ||
156 | GFP_KERNEL); | ||
157 | if (doi_def->map.std->lvl.local == NULL) { | ||
158 | ret_val = -ENOMEM; | ||
159 | goto add_std_failure; | ||
160 | } | ||
161 | doi_def->map.std->lvl.cipso_size = netlbl_getinc_u8(&msg, &msg_len); | ||
162 | if (doi_def->map.std->lvl.cipso_size > CIPSO_V4_MAX_REM_LVLS) | ||
163 | goto add_std_failure; | ||
164 | doi_def->map.std->lvl.cipso = kcalloc(doi_def->map.std->lvl.cipso_size, | ||
165 | sizeof(u32), | ||
166 | GFP_KERNEL); | ||
167 | if (doi_def->map.std->lvl.cipso == NULL) { | ||
168 | ret_val = -ENOMEM; | ||
169 | goto add_std_failure; | ||
170 | } | ||
171 | |||
172 | num_cats = netlbl_getinc_u32(&msg, &msg_len); | ||
173 | doi_def->map.std->cat.local_size = netlbl_getinc_u32(&msg, &msg_len); | ||
174 | if (doi_def->map.std->cat.local_size > CIPSO_V4_MAX_LOC_CATS) | ||
175 | goto add_std_failure; | ||
176 | doi_def->map.std->cat.local = kcalloc(doi_def->map.std->cat.local_size, | ||
177 | sizeof(u32), | ||
178 | GFP_KERNEL); | ||
179 | if (doi_def->map.std->cat.local == NULL) { | ||
180 | ret_val = -ENOMEM; | ||
181 | goto add_std_failure; | ||
182 | } | ||
183 | doi_def->map.std->cat.cipso_size = netlbl_getinc_u16(&msg, &msg_len); | ||
184 | if (doi_def->map.std->cat.cipso_size > CIPSO_V4_MAX_REM_CATS) | ||
185 | goto add_std_failure; | ||
186 | doi_def->map.std->cat.cipso = kcalloc(doi_def->map.std->cat.cipso_size, | ||
187 | sizeof(u32), | ||
188 | GFP_KERNEL); | ||
189 | if (doi_def->map.std->cat.cipso == NULL) { | ||
190 | ret_val = -ENOMEM; | ||
191 | goto add_std_failure; | ||
192 | } | ||
193 | |||
194 | if (msg_len < | ||
195 | num_lvls * (NETLBL_LEN_U32 + NETLBL_LEN_U8) + | ||
196 | num_cats * (NETLBL_LEN_U32 + NETLBL_LEN_U16)) | ||
197 | goto add_std_failure; | ||
198 | |||
199 | for (iter = 0; iter < doi_def->map.std->lvl.cipso_size; iter++) | ||
200 | doi_def->map.std->lvl.cipso[iter] = CIPSO_V4_INV_LVL; | ||
201 | for (iter = 0; iter < doi_def->map.std->lvl.local_size; iter++) | ||
202 | doi_def->map.std->lvl.local[iter] = CIPSO_V4_INV_LVL; | ||
203 | for (iter = 0; iter < doi_def->map.std->cat.cipso_size; iter++) | ||
204 | doi_def->map.std->cat.cipso[iter] = CIPSO_V4_INV_CAT; | ||
205 | for (iter = 0; iter < doi_def->map.std->cat.local_size; iter++) | ||
206 | doi_def->map.std->cat.local[iter] = CIPSO_V4_INV_CAT; | ||
207 | |||
208 | for (iter = 0; iter < num_lvls; iter++) { | ||
209 | tmp_val_a = netlbl_getinc_u32(&msg, &msg_len); | ||
210 | tmp_val_b = netlbl_getinc_u8(&msg, &msg_len); | ||
211 | |||
212 | if (tmp_val_a >= doi_def->map.std->lvl.local_size || | ||
213 | tmp_val_b >= doi_def->map.std->lvl.cipso_size) | ||
214 | goto add_std_failure; | ||
215 | |||
216 | doi_def->map.std->lvl.cipso[tmp_val_b] = tmp_val_a; | ||
217 | doi_def->map.std->lvl.local[tmp_val_a] = tmp_val_b; | ||
218 | } | ||
219 | |||
220 | for (iter = 0; iter < num_cats; iter++) { | ||
221 | tmp_val_a = netlbl_getinc_u32(&msg, &msg_len); | ||
222 | tmp_val_b = netlbl_getinc_u16(&msg, &msg_len); | ||
223 | |||
224 | if (tmp_val_a >= doi_def->map.std->cat.local_size || | ||
225 | tmp_val_b >= doi_def->map.std->cat.cipso_size) | ||
226 | goto add_std_failure; | ||
227 | |||
228 | doi_def->map.std->cat.cipso[tmp_val_b] = tmp_val_a; | ||
229 | doi_def->map.std->cat.local[tmp_val_a] = tmp_val_b; | ||
230 | } | ||
231 | |||
232 | doi_def->doi = doi; | ||
233 | ret_val = cipso_v4_doi_add(doi_def); | ||
234 | if (ret_val != 0) | ||
235 | goto add_std_failure; | ||
236 | return 0; | ||
237 | |||
238 | add_std_failure: | ||
239 | if (doi_def) | ||
240 | netlbl_cipsov4_doi_free(&doi_def->rcu); | ||
241 | return ret_val; | ||
242 | } | ||
243 | |||
244 | /** | ||
245 | * netlbl_cipsov4_add_pass - Adds a CIPSO V4 DOI definition | ||
246 | * @doi: the DOI value | ||
247 | * @msg: the ADD message data | ||
248 | * @msg_size: the size of the ADD message buffer | ||
249 | * | ||
250 | * Description: | ||
251 | * Create a new CIPSO_V4_MAP_PASS DOI definition based on the given ADD message | ||
252 | * and add it to the CIPSO V4 engine. Return zero on success and non-zero on | ||
253 | * error. | ||
254 | * | ||
255 | */ | ||
256 | static int netlbl_cipsov4_add_pass(u32 doi, | ||
257 | struct nlattr *msg, | ||
258 | size_t msg_size) | ||
259 | { | ||
260 | int ret_val = -EINVAL; | ||
261 | int msg_len = msg_size; | ||
262 | u32 num_tags; | ||
263 | struct cipso_v4_doi *doi_def = NULL; | ||
264 | u32 iter; | ||
265 | |||
266 | if (msg_len < NETLBL_LEN_U32) | ||
267 | goto add_pass_failure; | ||
268 | num_tags = netlbl_getinc_u32(&msg, &msg_len); | ||
269 | if (num_tags == 0 || num_tags > CIPSO_V4_TAG_MAXCNT) | ||
270 | goto add_pass_failure; | ||
271 | |||
272 | doi_def = kmalloc(sizeof(*doi_def), GFP_KERNEL); | ||
273 | if (doi_def == NULL) { | ||
274 | ret_val = -ENOMEM; | ||
275 | goto add_pass_failure; | ||
276 | } | ||
277 | doi_def->type = CIPSO_V4_MAP_PASS; | ||
278 | |||
279 | for (iter = 0; iter < num_tags; iter++) { | ||
280 | if (msg_len < NETLBL_LEN_U8) | ||
281 | goto add_pass_failure; | ||
282 | doi_def->tags[iter] = netlbl_getinc_u8(&msg, &msg_len); | ||
283 | switch (doi_def->tags[iter]) { | ||
284 | case CIPSO_V4_TAG_RBITMAP: | ||
285 | break; | ||
286 | default: | ||
287 | goto add_pass_failure; | ||
288 | } | ||
289 | } | ||
290 | if (iter < CIPSO_V4_TAG_MAXCNT) | ||
291 | doi_def->tags[iter] = CIPSO_V4_TAG_INVALID; | ||
292 | |||
293 | doi_def->doi = doi; | ||
294 | ret_val = cipso_v4_doi_add(doi_def); | ||
295 | if (ret_val != 0) | ||
296 | goto add_pass_failure; | ||
297 | return 0; | ||
298 | |||
299 | add_pass_failure: | ||
300 | if (doi_def) | ||
301 | netlbl_cipsov4_doi_free(&doi_def->rcu); | ||
302 | return ret_val; | ||
303 | } | ||
304 | |||
305 | /** | ||
306 | * netlbl_cipsov4_add - Handle an ADD message | ||
307 | * @skb: the NETLINK buffer | ||
308 | * @info: the Generic NETLINK info block | ||
309 | * | ||
310 | * Description: | ||
311 | * Create a new DOI definition based on the given ADD message and add it to the | ||
312 | * CIPSO V4 engine. Returns zero on success, negative values on failure. | ||
313 | * | ||
314 | */ | ||
315 | static int netlbl_cipsov4_add(struct sk_buff *skb, struct genl_info *info) | ||
316 | |||
317 | { | ||
318 | int ret_val = -EINVAL; | ||
319 | u32 doi; | ||
320 | u32 map_type; | ||
321 | int msg_len = netlbl_netlink_payload_len(skb); | ||
322 | struct nlattr *msg = netlbl_netlink_payload_data(skb); | ||
323 | |||
324 | ret_val = netlbl_netlink_cap_check(skb, CAP_NET_ADMIN); | ||
325 | if (ret_val != 0) | ||
326 | goto add_return; | ||
327 | |||
328 | if (msg_len < 2 * NETLBL_LEN_U32) | ||
329 | goto add_return; | ||
330 | |||
331 | doi = netlbl_getinc_u32(&msg, &msg_len); | ||
332 | map_type = netlbl_getinc_u32(&msg, &msg_len); | ||
333 | switch (map_type) { | ||
334 | case CIPSO_V4_MAP_STD: | ||
335 | ret_val = netlbl_cipsov4_add_std(doi, msg, msg_len); | ||
336 | break; | ||
337 | case CIPSO_V4_MAP_PASS: | ||
338 | ret_val = netlbl_cipsov4_add_pass(doi, msg, msg_len); | ||
339 | break; | ||
340 | } | ||
341 | |||
342 | add_return: | ||
343 | netlbl_netlink_send_ack(info, | ||
344 | netlbl_cipsov4_gnl_family.id, | ||
345 | NLBL_CIPSOV4_C_ACK, | ||
346 | -ret_val); | ||
347 | return ret_val; | ||
348 | } | ||
349 | |||
350 | /** | ||
351 | * netlbl_cipsov4_list - Handle a LIST message | ||
352 | * @skb: the NETLINK buffer | ||
353 | * @info: the Generic NETLINK info block | ||
354 | * | ||
355 | * Description: | ||
356 | * Process a user generated LIST message and respond accordingly. Returns | ||
357 | * zero on success and negative values on error. | ||
358 | * | ||
359 | */ | ||
360 | static int netlbl_cipsov4_list(struct sk_buff *skb, struct genl_info *info) | ||
361 | { | ||
362 | int ret_val = -EINVAL; | ||
363 | u32 doi; | ||
364 | struct nlattr *msg = netlbl_netlink_payload_data(skb); | ||
365 | struct sk_buff *ans_skb; | ||
366 | |||
367 | if (netlbl_netlink_payload_len(skb) != NETLBL_LEN_U32) | ||
368 | goto list_failure; | ||
369 | |||
370 | doi = nla_get_u32(msg); | ||
371 | ans_skb = cipso_v4_doi_dump(doi, NLMSG_SPACE(GENL_HDRLEN)); | ||
372 | if (ans_skb == NULL) { | ||
373 | ret_val = -ENOMEM; | ||
374 | goto list_failure; | ||
375 | } | ||
376 | netlbl_netlink_hdr_push(ans_skb, | ||
377 | info->snd_pid, | ||
378 | 0, | ||
379 | netlbl_cipsov4_gnl_family.id, | ||
380 | NLBL_CIPSOV4_C_LIST); | ||
381 | |||
382 | ret_val = netlbl_netlink_snd(ans_skb, info->snd_pid); | ||
383 | if (ret_val != 0) | ||
384 | goto list_failure; | ||
385 | |||
386 | return 0; | ||
387 | |||
388 | list_failure: | ||
389 | netlbl_netlink_send_ack(info, | ||
390 | netlbl_cipsov4_gnl_family.id, | ||
391 | NLBL_CIPSOV4_C_ACK, | ||
392 | -ret_val); | ||
393 | return ret_val; | ||
394 | } | ||
395 | |||
396 | /** | ||
397 | * netlbl_cipsov4_listall - Handle a LISTALL message | ||
398 | * @skb: the NETLINK buffer | ||
399 | * @info: the Generic NETLINK info block | ||
400 | * | ||
401 | * Description: | ||
402 | * Process a user generated LISTALL message and respond accordingly. Returns | ||
403 | * zero on success and negative values on error. | ||
404 | * | ||
405 | */ | ||
406 | static int netlbl_cipsov4_listall(struct sk_buff *skb, struct genl_info *info) | ||
407 | { | ||
408 | int ret_val = -EINVAL; | ||
409 | struct sk_buff *ans_skb; | ||
410 | |||
411 | ans_skb = cipso_v4_doi_dump_all(NLMSG_SPACE(GENL_HDRLEN)); | ||
412 | if (ans_skb == NULL) { | ||
413 | ret_val = -ENOMEM; | ||
414 | goto listall_failure; | ||
415 | } | ||
416 | netlbl_netlink_hdr_push(ans_skb, | ||
417 | info->snd_pid, | ||
418 | 0, | ||
419 | netlbl_cipsov4_gnl_family.id, | ||
420 | NLBL_CIPSOV4_C_LISTALL); | ||
421 | |||
422 | ret_val = netlbl_netlink_snd(ans_skb, info->snd_pid); | ||
423 | if (ret_val != 0) | ||
424 | goto listall_failure; | ||
425 | |||
426 | return 0; | ||
427 | |||
428 | listall_failure: | ||
429 | netlbl_netlink_send_ack(info, | ||
430 | netlbl_cipsov4_gnl_family.id, | ||
431 | NLBL_CIPSOV4_C_ACK, | ||
432 | -ret_val); | ||
433 | return ret_val; | ||
434 | } | ||
435 | |||
436 | /** | ||
437 | * netlbl_cipsov4_remove - Handle a REMOVE message | ||
438 | * @skb: the NETLINK buffer | ||
439 | * @info: the Generic NETLINK info block | ||
440 | * | ||
441 | * Description: | ||
442 | * Process a user generated REMOVE message and respond accordingly. Returns | ||
443 | * zero on success, negative values on failure. | ||
444 | * | ||
445 | */ | ||
446 | static int netlbl_cipsov4_remove(struct sk_buff *skb, struct genl_info *info) | ||
447 | { | ||
448 | int ret_val; | ||
449 | u32 doi; | ||
450 | struct nlattr *msg = netlbl_netlink_payload_data(skb); | ||
451 | |||
452 | ret_val = netlbl_netlink_cap_check(skb, CAP_NET_ADMIN); | ||
453 | if (ret_val != 0) | ||
454 | goto remove_return; | ||
455 | |||
456 | if (netlbl_netlink_payload_len(skb) != NETLBL_LEN_U32) { | ||
457 | ret_val = -EINVAL; | ||
458 | goto remove_return; | ||
459 | } | ||
460 | |||
461 | doi = nla_get_u32(msg); | ||
462 | ret_val = cipso_v4_doi_remove(doi, netlbl_cipsov4_doi_free); | ||
463 | |||
464 | remove_return: | ||
465 | netlbl_netlink_send_ack(info, | ||
466 | netlbl_cipsov4_gnl_family.id, | ||
467 | NLBL_CIPSOV4_C_ACK, | ||
468 | -ret_val); | ||
469 | return ret_val; | ||
470 | } | ||
471 | |||
472 | /* | ||
473 | * NetLabel Generic NETLINK Command Definitions | ||
474 | */ | ||
475 | |||
476 | static struct genl_ops netlbl_cipsov4_genl_c_add = { | ||
477 | .cmd = NLBL_CIPSOV4_C_ADD, | ||
478 | .flags = 0, | ||
479 | .doit = netlbl_cipsov4_add, | ||
480 | .dumpit = NULL, | ||
481 | }; | ||
482 | |||
483 | static struct genl_ops netlbl_cipsov4_genl_c_remove = { | ||
484 | .cmd = NLBL_CIPSOV4_C_REMOVE, | ||
485 | .flags = 0, | ||
486 | .doit = netlbl_cipsov4_remove, | ||
487 | .dumpit = NULL, | ||
488 | }; | ||
489 | |||
490 | static struct genl_ops netlbl_cipsov4_genl_c_list = { | ||
491 | .cmd = NLBL_CIPSOV4_C_LIST, | ||
492 | .flags = 0, | ||
493 | .doit = netlbl_cipsov4_list, | ||
494 | .dumpit = NULL, | ||
495 | }; | ||
496 | |||
497 | static struct genl_ops netlbl_cipsov4_genl_c_listall = { | ||
498 | .cmd = NLBL_CIPSOV4_C_LISTALL, | ||
499 | .flags = 0, | ||
500 | .doit = netlbl_cipsov4_listall, | ||
501 | .dumpit = NULL, | ||
502 | }; | ||
503 | |||
504 | /* | ||
505 | * NetLabel Generic NETLINK Protocol Functions | ||
506 | */ | ||
507 | |||
508 | /** | ||
509 | * netlbl_cipsov4_genl_init - Register the CIPSOv4 NetLabel component | ||
510 | * | ||
511 | * Description: | ||
512 | * Register the CIPSOv4 packet NetLabel component with the Generic NETLINK | ||
513 | * mechanism. Returns zero on success, negative values on failure. | ||
514 | * | ||
515 | */ | ||
516 | int netlbl_cipsov4_genl_init(void) | ||
517 | { | ||
518 | int ret_val; | ||
519 | |||
520 | ret_val = genl_register_family(&netlbl_cipsov4_gnl_family); | ||
521 | if (ret_val != 0) | ||
522 | return ret_val; | ||
523 | |||
524 | ret_val = genl_register_ops(&netlbl_cipsov4_gnl_family, | ||
525 | &netlbl_cipsov4_genl_c_add); | ||
526 | if (ret_val != 0) | ||
527 | return ret_val; | ||
528 | ret_val = genl_register_ops(&netlbl_cipsov4_gnl_family, | ||
529 | &netlbl_cipsov4_genl_c_remove); | ||
530 | if (ret_val != 0) | ||
531 | return ret_val; | ||
532 | ret_val = genl_register_ops(&netlbl_cipsov4_gnl_family, | ||
533 | &netlbl_cipsov4_genl_c_list); | ||
534 | if (ret_val != 0) | ||
535 | return ret_val; | ||
536 | ret_val = genl_register_ops(&netlbl_cipsov4_gnl_family, | ||
537 | &netlbl_cipsov4_genl_c_listall); | ||
538 | if (ret_val != 0) | ||
539 | return ret_val; | ||
540 | |||
541 | return 0; | ||
542 | } | ||
diff --git a/net/netlabel/netlabel_cipso_v4.h b/net/netlabel/netlabel_cipso_v4.h new file mode 100644 index 000000000000..4c6ff4b93004 --- /dev/null +++ b/net/netlabel/netlabel_cipso_v4.h | |||
@@ -0,0 +1,217 @@ | |||
1 | /* | ||
2 | * NetLabel CIPSO/IPv4 Support | ||
3 | * | ||
4 | * This file defines the CIPSO/IPv4 functions for the NetLabel system. The | ||
5 | * NetLabel system manages static and dynamic label mappings for network | ||
6 | * protocols such as CIPSO and RIPSO. | ||
7 | * | ||
8 | * Author: Paul Moore <paul.moore@hp.com> | ||
9 | * | ||
10 | */ | ||
11 | |||
12 | /* | ||
13 | * (c) Copyright Hewlett-Packard Development Company, L.P., 2006 | ||
14 | * | ||
15 | * This program is free software; you can redistribute it and/or modify | ||
16 | * it under the terms of the GNU General Public License as published by | ||
17 | * the Free Software Foundation; either version 2 of the License, or | ||
18 | * (at your option) any later version. | ||
19 | * | ||
20 | * This program is distributed in the hope that it will be useful, | ||
21 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
22 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See | ||
23 | * the GNU General Public License for more details. | ||
24 | * | ||
25 | * You should have received a copy of the GNU General Public License | ||
26 | * along with this program; if not, write to the Free Software | ||
27 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
28 | * | ||
29 | */ | ||
30 | |||
31 | #ifndef _NETLABEL_CIPSO_V4 | ||
32 | #define _NETLABEL_CIPSO_V4 | ||
33 | |||
34 | #include <net/netlabel.h> | ||
35 | |||
36 | /* | ||
37 | * The following NetLabel payloads are supported by the CIPSO subsystem, all | ||
38 | * of which are preceeded by the nlmsghdr struct. | ||
39 | * | ||
40 | * o ACK: | ||
41 | * Sent by the kernel in response to an applications message, applications | ||
42 | * should never send this message. | ||
43 | * | ||
44 | * +----------------------+-----------------------+ | ||
45 | * | seq number (32 bits) | return code (32 bits) | | ||
46 | * +----------------------+-----------------------+ | ||
47 | * | ||
48 | * seq number: the sequence number of the original message, taken from the | ||
49 | * nlmsghdr structure | ||
50 | * return code: return value, based on errno values | ||
51 | * | ||
52 | * o ADD: | ||
53 | * Sent by an application to add a new DOI mapping table, after completion | ||
54 | * of the task the kernel should ACK this message. | ||
55 | * | ||
56 | * +---------------+--------------------+---------------------+ | ||
57 | * | DOI (32 bits) | map type (32 bits) | tag count (32 bits) | ... | ||
58 | * +---------------+--------------------+---------------------+ | ||
59 | * | ||
60 | * +-----------------+ | ||
61 | * | tag #X (8 bits) | ... repeated | ||
62 | * +-----------------+ | ||
63 | * | ||
64 | * +-------------- ---- --- -- - | ||
65 | * | mapping data | ||
66 | * +-------------- ---- --- -- - | ||
67 | * | ||
68 | * DOI: the DOI value | ||
69 | * map type: the mapping table type (defined in the cipso_ipv4.h header | ||
70 | * as CIPSO_V4_MAP_*) | ||
71 | * tag count: the number of tags, must be greater than zero | ||
72 | * tag: the CIPSO tag for the DOI, tags listed first are given | ||
73 | * higher priorirty when sending packets | ||
74 | * mapping data: specific to the map type (see below) | ||
75 | * | ||
76 | * CIPSO_V4_MAP_STD | ||
77 | * | ||
78 | * +------------------+-----------------------+----------------------+ | ||
79 | * | levels (32 bits) | max l level (32 bits) | max r level (8 bits) | ... | ||
80 | * +------------------+-----------------------+----------------------+ | ||
81 | * | ||
82 | * +----------------------+---------------------+---------------------+ | ||
83 | * | categories (32 bits) | max l cat (32 bits) | max r cat (16 bits) | ... | ||
84 | * +----------------------+---------------------+---------------------+ | ||
85 | * | ||
86 | * +--------------------------+-------------------------+ | ||
87 | * | local level #X (32 bits) | CIPSO level #X (8 bits) | ... repeated | ||
88 | * +--------------------------+-------------------------+ | ||
89 | * | ||
90 | * +-----------------------------+-----------------------------+ | ||
91 | * | local category #X (32 bits) | CIPSO category #X (16 bits) | ... repeated | ||
92 | * +-----------------------------+-----------------------------+ | ||
93 | * | ||
94 | * levels: the number of level mappings | ||
95 | * max l level: the highest local level | ||
96 | * max r level: the highest remote/CIPSO level | ||
97 | * categories: the number of category mappings | ||
98 | * max l cat: the highest local category | ||
99 | * max r cat: the highest remote/CIPSO category | ||
100 | * local level: the local part of a level mapping | ||
101 | * CIPSO level: the remote/CIPSO part of a level mapping | ||
102 | * local category: the local part of a category mapping | ||
103 | * CIPSO category: the remote/CIPSO part of a category mapping | ||
104 | * | ||
105 | * CIPSO_V4_MAP_PASS | ||
106 | * | ||
107 | * No mapping data is needed for this map type. | ||
108 | * | ||
109 | * o REMOVE: | ||
110 | * Sent by an application to remove a specific DOI mapping table from the | ||
111 | * CIPSO V4 system. The kernel should ACK this message. | ||
112 | * | ||
113 | * +---------------+ | ||
114 | * | DOI (32 bits) | | ||
115 | * +---------------+ | ||
116 | * | ||
117 | * DOI: the DOI value | ||
118 | * | ||
119 | * o LIST: | ||
120 | * Sent by an application to list the details of a DOI definition. The | ||
121 | * kernel should send an ACK on error or a response as indicated below. The | ||
122 | * application generated message format is shown below. | ||
123 | * | ||
124 | * +---------------+ | ||
125 | * | DOI (32 bits) | | ||
126 | * +---------------+ | ||
127 | * | ||
128 | * DOI: the DOI value | ||
129 | * | ||
130 | * The valid response message format depends on the type of the DOI mapping, | ||
131 | * the known formats are shown below. | ||
132 | * | ||
133 | * +--------------------+ | ||
134 | * | map type (32 bits) | ... | ||
135 | * +--------------------+ | ||
136 | * | ||
137 | * map type: the DOI mapping table type (defined in the cipso_ipv4.h | ||
138 | * header as CIPSO_V4_MAP_*) | ||
139 | * | ||
140 | * (map type == CIPSO_V4_MAP_STD) | ||
141 | * | ||
142 | * +----------------+------------------+----------------------+ | ||
143 | * | tags (32 bits) | levels (32 bits) | categories (32 bits) | ... | ||
144 | * +----------------+------------------+----------------------+ | ||
145 | * | ||
146 | * +-----------------+ | ||
147 | * | tag #X (8 bits) | ... repeated | ||
148 | * +-----------------+ | ||
149 | * | ||
150 | * +--------------------------+-------------------------+ | ||
151 | * | local level #X (32 bits) | CIPSO level #X (8 bits) | ... repeated | ||
152 | * +--------------------------+-------------------------+ | ||
153 | * | ||
154 | * +-----------------------------+-----------------------------+ | ||
155 | * | local category #X (32 bits) | CIPSO category #X (16 bits) | ... repeated | ||
156 | * +-----------------------------+-----------------------------+ | ||
157 | * | ||
158 | * tags: the number of CIPSO tag types | ||
159 | * levels: the number of level mappings | ||
160 | * categories: the number of category mappings | ||
161 | * tag: the tag number, tags listed first are given higher | ||
162 | * priority when sending packets | ||
163 | * local level: the local part of a level mapping | ||
164 | * CIPSO level: the remote/CIPSO part of a level mapping | ||
165 | * local category: the local part of a category mapping | ||
166 | * CIPSO category: the remote/CIPSO part of a category mapping | ||
167 | * | ||
168 | * (map type == CIPSO_V4_MAP_PASS) | ||
169 | * | ||
170 | * +----------------+ | ||
171 | * | tags (32 bits) | ... | ||
172 | * +----------------+ | ||
173 | * | ||
174 | * +-----------------+ | ||
175 | * | tag #X (8 bits) | ... repeated | ||
176 | * +-----------------+ | ||
177 | * | ||
178 | * tags: the number of CIPSO tag types | ||
179 | * tag: the tag number, tags listed first are given higher | ||
180 | * priority when sending packets | ||
181 | * | ||
182 | * o LISTALL: | ||
183 | * This message is sent by an application to list the valid DOIs on the | ||
184 | * system. There is no payload and the kernel should respond with an ACK | ||
185 | * or the following message. | ||
186 | * | ||
187 | * +---------------------+------------------+-----------------------+ | ||
188 | * | DOI count (32 bits) | DOI #X (32 bits) | map type #X (32 bits) | | ||
189 | * +---------------------+------------------+-----------------------+ | ||
190 | * | ||
191 | * +-----------------------+ | ||
192 | * | map type #X (32 bits) | ... | ||
193 | * +-----------------------+ | ||
194 | * | ||
195 | * DOI count: the number of DOIs | ||
196 | * DOI: the DOI value | ||
197 | * map type: the DOI mapping table type (defined in the cipso_ipv4.h | ||
198 | * header as CIPSO_V4_MAP_*) | ||
199 | * | ||
200 | */ | ||
201 | |||
202 | /* NetLabel CIPSOv4 commands */ | ||
203 | enum { | ||
204 | NLBL_CIPSOV4_C_UNSPEC, | ||
205 | NLBL_CIPSOV4_C_ACK, | ||
206 | NLBL_CIPSOV4_C_ADD, | ||
207 | NLBL_CIPSOV4_C_REMOVE, | ||
208 | NLBL_CIPSOV4_C_LIST, | ||
209 | NLBL_CIPSOV4_C_LISTALL, | ||
210 | __NLBL_CIPSOV4_C_MAX, | ||
211 | }; | ||
212 | #define NLBL_CIPSOV4_C_MAX (__NLBL_CIPSOV4_C_MAX - 1) | ||
213 | |||
214 | /* NetLabel protocol functions */ | ||
215 | int netlbl_cipsov4_genl_init(void); | ||
216 | |||
217 | #endif | ||
diff --git a/net/netlabel/netlabel_domainhash.c b/net/netlabel/netlabel_domainhash.c new file mode 100644 index 000000000000..0489a1378101 --- /dev/null +++ b/net/netlabel/netlabel_domainhash.c | |||
@@ -0,0 +1,513 @@ | |||
1 | /* | ||
2 | * NetLabel Domain Hash Table | ||
3 | * | ||
4 | * This file manages the domain hash table that NetLabel uses to determine | ||
5 | * which network labeling protocol to use for a given domain. The NetLabel | ||
6 | * system manages static and dynamic label mappings for network protocols such | ||
7 | * as CIPSO and RIPSO. | ||
8 | * | ||
9 | * Author: Paul Moore <paul.moore@hp.com> | ||
10 | * | ||
11 | */ | ||
12 | |||
13 | /* | ||
14 | * (c) Copyright Hewlett-Packard Development Company, L.P., 2006 | ||
15 | * | ||
16 | * This program is free software; you can redistribute it and/or modify | ||
17 | * it under the terms of the GNU General Public License as published by | ||
18 | * the Free Software Foundation; either version 2 of the License, or | ||
19 | * (at your option) any later version. | ||
20 | * | ||
21 | * This program is distributed in the hope that it will be useful, | ||
22 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
23 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See | ||
24 | * the GNU General Public License for more details. | ||
25 | * | ||
26 | * You should have received a copy of the GNU General Public License | ||
27 | * along with this program; if not, write to the Free Software | ||
28 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
29 | * | ||
30 | */ | ||
31 | |||
32 | #include <linux/types.h> | ||
33 | #include <linux/rcupdate.h> | ||
34 | #include <linux/list.h> | ||
35 | #include <linux/skbuff.h> | ||
36 | #include <linux/spinlock.h> | ||
37 | #include <linux/string.h> | ||
38 | #include <net/netlabel.h> | ||
39 | #include <net/cipso_ipv4.h> | ||
40 | #include <asm/bug.h> | ||
41 | |||
42 | #include "netlabel_mgmt.h" | ||
43 | #include "netlabel_domainhash.h" | ||
44 | |||
45 | struct netlbl_domhsh_tbl { | ||
46 | struct list_head *tbl; | ||
47 | u32 size; | ||
48 | }; | ||
49 | |||
50 | /* Domain hash table */ | ||
51 | /* XXX - updates should be so rare that having one spinlock for the entire | ||
52 | * hash table should be okay */ | ||
53 | static DEFINE_SPINLOCK(netlbl_domhsh_lock); | ||
54 | static struct netlbl_domhsh_tbl *netlbl_domhsh = NULL; | ||
55 | |||
56 | /* Default domain mapping */ | ||
57 | static DEFINE_SPINLOCK(netlbl_domhsh_def_lock); | ||
58 | static struct netlbl_dom_map *netlbl_domhsh_def = NULL; | ||
59 | |||
60 | /* | ||
61 | * Domain Hash Table Helper Functions | ||
62 | */ | ||
63 | |||
64 | /** | ||
65 | * netlbl_domhsh_free_entry - Frees a domain hash table entry | ||
66 | * @entry: the entry's RCU field | ||
67 | * | ||
68 | * Description: | ||
69 | * This function is designed to be used as a callback to the call_rcu() | ||
70 | * function so that the memory allocated to a hash table entry can be released | ||
71 | * safely. | ||
72 | * | ||
73 | */ | ||
74 | static void netlbl_domhsh_free_entry(struct rcu_head *entry) | ||
75 | { | ||
76 | struct netlbl_dom_map *ptr; | ||
77 | |||
78 | ptr = container_of(entry, struct netlbl_dom_map, rcu); | ||
79 | kfree(ptr->domain); | ||
80 | kfree(ptr); | ||
81 | } | ||
82 | |||
83 | /** | ||
84 | * netlbl_domhsh_hash - Hashing function for the domain hash table | ||
85 | * @domain: the domain name to hash | ||
86 | * | ||
87 | * Description: | ||
88 | * This is the hashing function for the domain hash table, it returns the | ||
89 | * correct bucket number for the domain. The caller is responsibile for | ||
90 | * calling the rcu_read_[un]lock() functions. | ||
91 | * | ||
92 | */ | ||
93 | static u32 netlbl_domhsh_hash(const char *key) | ||
94 | { | ||
95 | u32 iter; | ||
96 | u32 val; | ||
97 | u32 len; | ||
98 | |||
99 | /* This is taken (with slight modification) from | ||
100 | * security/selinux/ss/symtab.c:symhash() */ | ||
101 | |||
102 | for (iter = 0, val = 0, len = strlen(key); iter < len; iter++) | ||
103 | val = (val << 4 | (val >> (8 * sizeof(u32) - 4))) ^ key[iter]; | ||
104 | return val & (rcu_dereference(netlbl_domhsh)->size - 1); | ||
105 | } | ||
106 | |||
107 | /** | ||
108 | * netlbl_domhsh_search - Search for a domain entry | ||
109 | * @domain: the domain | ||
110 | * @def: return default if no match is found | ||
111 | * | ||
112 | * Description: | ||
113 | * Searches the domain hash table and returns a pointer to the hash table | ||
114 | * entry if found, otherwise NULL is returned. If @def is non-zero and a | ||
115 | * match is not found in the domain hash table the default mapping is returned | ||
116 | * if it exists. The caller is responsibile for the rcu hash table locks | ||
117 | * (i.e. the caller much call rcu_read_[un]lock()). | ||
118 | * | ||
119 | */ | ||
120 | static struct netlbl_dom_map *netlbl_domhsh_search(const char *domain, u32 def) | ||
121 | { | ||
122 | u32 bkt; | ||
123 | struct netlbl_dom_map *iter; | ||
124 | |||
125 | if (domain != NULL) { | ||
126 | bkt = netlbl_domhsh_hash(domain); | ||
127 | list_for_each_entry_rcu(iter, &netlbl_domhsh->tbl[bkt], list) | ||
128 | if (iter->valid && strcmp(iter->domain, domain) == 0) | ||
129 | return iter; | ||
130 | } | ||
131 | |||
132 | if (def != 0) { | ||
133 | iter = rcu_dereference(netlbl_domhsh_def); | ||
134 | if (iter != NULL && iter->valid) | ||
135 | return iter; | ||
136 | } | ||
137 | |||
138 | return NULL; | ||
139 | } | ||
140 | |||
141 | /* | ||
142 | * Domain Hash Table Functions | ||
143 | */ | ||
144 | |||
145 | /** | ||
146 | * netlbl_domhsh_init - Init for the domain hash | ||
147 | * @size: the number of bits to use for the hash buckets | ||
148 | * | ||
149 | * Description: | ||
150 | * Initializes the domain hash table, should be called only by | ||
151 | * netlbl_user_init() during initialization. Returns zero on success, non-zero | ||
152 | * values on error. | ||
153 | * | ||
154 | */ | ||
155 | int netlbl_domhsh_init(u32 size) | ||
156 | { | ||
157 | u32 iter; | ||
158 | struct netlbl_domhsh_tbl *hsh_tbl; | ||
159 | |||
160 | if (size == 0) | ||
161 | return -EINVAL; | ||
162 | |||
163 | hsh_tbl = kmalloc(sizeof(*hsh_tbl), GFP_KERNEL); | ||
164 | if (hsh_tbl == NULL) | ||
165 | return -ENOMEM; | ||
166 | hsh_tbl->size = 1 << size; | ||
167 | hsh_tbl->tbl = kcalloc(hsh_tbl->size, | ||
168 | sizeof(struct list_head), | ||
169 | GFP_KERNEL); | ||
170 | if (hsh_tbl->tbl == NULL) { | ||
171 | kfree(hsh_tbl); | ||
172 | return -ENOMEM; | ||
173 | } | ||
174 | for (iter = 0; iter < hsh_tbl->size; iter++) | ||
175 | INIT_LIST_HEAD(&hsh_tbl->tbl[iter]); | ||
176 | |||
177 | rcu_read_lock(); | ||
178 | spin_lock(&netlbl_domhsh_lock); | ||
179 | rcu_assign_pointer(netlbl_domhsh, hsh_tbl); | ||
180 | spin_unlock(&netlbl_domhsh_lock); | ||
181 | rcu_read_unlock(); | ||
182 | |||
183 | return 0; | ||
184 | } | ||
185 | |||
186 | /** | ||
187 | * netlbl_domhsh_add - Adds a entry to the domain hash table | ||
188 | * @entry: the entry to add | ||
189 | * | ||
190 | * Description: | ||
191 | * Adds a new entry to the domain hash table and handles any updates to the | ||
192 | * lower level protocol handler (i.e. CIPSO). Returns zero on success, | ||
193 | * negative on failure. | ||
194 | * | ||
195 | */ | ||
196 | int netlbl_domhsh_add(struct netlbl_dom_map *entry) | ||
197 | { | ||
198 | int ret_val; | ||
199 | u32 bkt; | ||
200 | |||
201 | switch (entry->type) { | ||
202 | case NETLBL_NLTYPE_UNLABELED: | ||
203 | ret_val = 0; | ||
204 | break; | ||
205 | case NETLBL_NLTYPE_CIPSOV4: | ||
206 | ret_val = cipso_v4_doi_domhsh_add(entry->type_def.cipsov4, | ||
207 | entry->domain); | ||
208 | break; | ||
209 | default: | ||
210 | return -EINVAL; | ||
211 | } | ||
212 | if (ret_val != 0) | ||
213 | return ret_val; | ||
214 | |||
215 | entry->valid = 1; | ||
216 | INIT_RCU_HEAD(&entry->rcu); | ||
217 | |||
218 | ret_val = 0; | ||
219 | rcu_read_lock(); | ||
220 | if (entry->domain != NULL) { | ||
221 | bkt = netlbl_domhsh_hash(entry->domain); | ||
222 | spin_lock(&netlbl_domhsh_lock); | ||
223 | if (netlbl_domhsh_search(entry->domain, 0) == NULL) | ||
224 | list_add_tail_rcu(&entry->list, | ||
225 | &netlbl_domhsh->tbl[bkt]); | ||
226 | else | ||
227 | ret_val = -EEXIST; | ||
228 | spin_unlock(&netlbl_domhsh_lock); | ||
229 | } else if (entry->domain == NULL) { | ||
230 | INIT_LIST_HEAD(&entry->list); | ||
231 | spin_lock(&netlbl_domhsh_def_lock); | ||
232 | if (rcu_dereference(netlbl_domhsh_def) == NULL) | ||
233 | rcu_assign_pointer(netlbl_domhsh_def, entry); | ||
234 | else | ||
235 | ret_val = -EEXIST; | ||
236 | spin_unlock(&netlbl_domhsh_def_lock); | ||
237 | } else | ||
238 | ret_val = -EINVAL; | ||
239 | rcu_read_unlock(); | ||
240 | |||
241 | if (ret_val != 0) { | ||
242 | switch (entry->type) { | ||
243 | case NETLBL_NLTYPE_CIPSOV4: | ||
244 | if (cipso_v4_doi_domhsh_remove(entry->type_def.cipsov4, | ||
245 | entry->domain) != 0) | ||
246 | BUG(); | ||
247 | break; | ||
248 | } | ||
249 | } | ||
250 | |||
251 | return ret_val; | ||
252 | } | ||
253 | |||
254 | /** | ||
255 | * netlbl_domhsh_add_default - Adds the default entry to the domain hash table | ||
256 | * @entry: the entry to add | ||
257 | * | ||
258 | * Description: | ||
259 | * Adds a new default entry to the domain hash table and handles any updates | ||
260 | * to the lower level protocol handler (i.e. CIPSO). Returns zero on success, | ||
261 | * negative on failure. | ||
262 | * | ||
263 | */ | ||
264 | int netlbl_domhsh_add_default(struct netlbl_dom_map *entry) | ||
265 | { | ||
266 | return netlbl_domhsh_add(entry); | ||
267 | } | ||
268 | |||
269 | /** | ||
270 | * netlbl_domhsh_remove - Removes an entry from the domain hash table | ||
271 | * @domain: the domain to remove | ||
272 | * | ||
273 | * Description: | ||
274 | * Removes an entry from the domain hash table and handles any updates to the | ||
275 | * lower level protocol handler (i.e. CIPSO). Returns zero on success, | ||
276 | * negative on failure. | ||
277 | * | ||
278 | */ | ||
279 | int netlbl_domhsh_remove(const char *domain) | ||
280 | { | ||
281 | int ret_val = -ENOENT; | ||
282 | struct netlbl_dom_map *entry; | ||
283 | |||
284 | rcu_read_lock(); | ||
285 | if (domain != NULL) | ||
286 | entry = netlbl_domhsh_search(domain, 0); | ||
287 | else | ||
288 | entry = netlbl_domhsh_search(domain, 1); | ||
289 | if (entry == NULL) | ||
290 | goto remove_return; | ||
291 | switch (entry->type) { | ||
292 | case NETLBL_NLTYPE_UNLABELED: | ||
293 | break; | ||
294 | case NETLBL_NLTYPE_CIPSOV4: | ||
295 | ret_val = cipso_v4_doi_domhsh_remove(entry->type_def.cipsov4, | ||
296 | entry->domain); | ||
297 | if (ret_val != 0) | ||
298 | goto remove_return; | ||
299 | break; | ||
300 | } | ||
301 | ret_val = 0; | ||
302 | if (entry != rcu_dereference(netlbl_domhsh_def)) { | ||
303 | spin_lock(&netlbl_domhsh_lock); | ||
304 | if (entry->valid) { | ||
305 | entry->valid = 0; | ||
306 | list_del_rcu(&entry->list); | ||
307 | } else | ||
308 | ret_val = -ENOENT; | ||
309 | spin_unlock(&netlbl_domhsh_lock); | ||
310 | } else { | ||
311 | spin_lock(&netlbl_domhsh_def_lock); | ||
312 | if (entry->valid) { | ||
313 | entry->valid = 0; | ||
314 | rcu_assign_pointer(netlbl_domhsh_def, NULL); | ||
315 | } else | ||
316 | ret_val = -ENOENT; | ||
317 | spin_unlock(&netlbl_domhsh_def_lock); | ||
318 | } | ||
319 | if (ret_val == 0) | ||
320 | call_rcu(&entry->rcu, netlbl_domhsh_free_entry); | ||
321 | |||
322 | remove_return: | ||
323 | rcu_read_unlock(); | ||
324 | return ret_val; | ||
325 | } | ||
326 | |||
327 | /** | ||
328 | * netlbl_domhsh_remove_default - Removes the default entry from the table | ||
329 | * | ||
330 | * Description: | ||
331 | * Removes/resets the default entry for the domain hash table and handles any | ||
332 | * updates to the lower level protocol handler (i.e. CIPSO). Returns zero on | ||
333 | * success, non-zero on failure. | ||
334 | * | ||
335 | */ | ||
336 | int netlbl_domhsh_remove_default(void) | ||
337 | { | ||
338 | return netlbl_domhsh_remove(NULL); | ||
339 | } | ||
340 | |||
341 | /** | ||
342 | * netlbl_domhsh_getentry - Get an entry from the domain hash table | ||
343 | * @domain: the domain name to search for | ||
344 | * | ||
345 | * Description: | ||
346 | * Look through the domain hash table searching for an entry to match @domain, | ||
347 | * return a pointer to a copy of the entry or NULL. The caller is responsibile | ||
348 | * for ensuring that rcu_read_[un]lock() is called. | ||
349 | * | ||
350 | */ | ||
351 | struct netlbl_dom_map *netlbl_domhsh_getentry(const char *domain) | ||
352 | { | ||
353 | return netlbl_domhsh_search(domain, 1); | ||
354 | } | ||
355 | |||
356 | /** | ||
357 | * netlbl_domhsh_dump - Dump the domain hash table into a sk_buff | ||
358 | * | ||
359 | * Description: | ||
360 | * Dump the domain hash table into a buffer suitable for returning to an | ||
361 | * application in response to a NetLabel management DOMAIN message. This | ||
362 | * function may fail if another process is growing the hash table at the same | ||
363 | * time. The returned sk_buff has room at the front of the sk_buff for | ||
364 | * @headroom bytes. See netlabel.h for the DOMAIN message format. Returns a | ||
365 | * pointer to a sk_buff on success, NULL on error. | ||
366 | * | ||
367 | */ | ||
368 | struct sk_buff *netlbl_domhsh_dump(size_t headroom) | ||
369 | { | ||
370 | struct sk_buff *skb = NULL; | ||
371 | ssize_t buf_len; | ||
372 | u32 bkt_iter; | ||
373 | u32 dom_cnt = 0; | ||
374 | struct netlbl_domhsh_tbl *hsh_tbl; | ||
375 | struct netlbl_dom_map *list_iter; | ||
376 | ssize_t tmp_len; | ||
377 | |||
378 | buf_len = NETLBL_LEN_U32; | ||
379 | rcu_read_lock(); | ||
380 | hsh_tbl = rcu_dereference(netlbl_domhsh); | ||
381 | for (bkt_iter = 0; bkt_iter < hsh_tbl->size; bkt_iter++) | ||
382 | list_for_each_entry_rcu(list_iter, | ||
383 | &hsh_tbl->tbl[bkt_iter], list) { | ||
384 | buf_len += NETLBL_LEN_U32 + | ||
385 | nla_total_size(strlen(list_iter->domain) + 1); | ||
386 | switch (list_iter->type) { | ||
387 | case NETLBL_NLTYPE_UNLABELED: | ||
388 | break; | ||
389 | case NETLBL_NLTYPE_CIPSOV4: | ||
390 | buf_len += 2 * NETLBL_LEN_U32; | ||
391 | break; | ||
392 | } | ||
393 | dom_cnt++; | ||
394 | } | ||
395 | |||
396 | skb = netlbl_netlink_alloc_skb(headroom, buf_len, GFP_ATOMIC); | ||
397 | if (skb == NULL) | ||
398 | goto dump_failure; | ||
399 | |||
400 | if (nla_put_u32(skb, NLA_U32, dom_cnt) != 0) | ||
401 | goto dump_failure; | ||
402 | buf_len -= NETLBL_LEN_U32; | ||
403 | hsh_tbl = rcu_dereference(netlbl_domhsh); | ||
404 | for (bkt_iter = 0; bkt_iter < hsh_tbl->size; bkt_iter++) | ||
405 | list_for_each_entry_rcu(list_iter, | ||
406 | &hsh_tbl->tbl[bkt_iter], list) { | ||
407 | tmp_len = nla_total_size(strlen(list_iter->domain) + | ||
408 | 1); | ||
409 | if (buf_len < NETLBL_LEN_U32 + tmp_len) | ||
410 | goto dump_failure; | ||
411 | if (nla_put_string(skb, | ||
412 | NLA_STRING, | ||
413 | list_iter->domain) != 0) | ||
414 | goto dump_failure; | ||
415 | if (nla_put_u32(skb, NLA_U32, list_iter->type) != 0) | ||
416 | goto dump_failure; | ||
417 | buf_len -= NETLBL_LEN_U32 + tmp_len; | ||
418 | switch (list_iter->type) { | ||
419 | case NETLBL_NLTYPE_UNLABELED: | ||
420 | break; | ||
421 | case NETLBL_NLTYPE_CIPSOV4: | ||
422 | if (buf_len < 2 * NETLBL_LEN_U32) | ||
423 | goto dump_failure; | ||
424 | if (nla_put_u32(skb, | ||
425 | NLA_U32, | ||
426 | list_iter->type_def.cipsov4->type) != 0) | ||
427 | goto dump_failure; | ||
428 | if (nla_put_u32(skb, | ||
429 | NLA_U32, | ||
430 | list_iter->type_def.cipsov4->doi) != 0) | ||
431 | goto dump_failure; | ||
432 | buf_len -= 2 * NETLBL_LEN_U32; | ||
433 | break; | ||
434 | } | ||
435 | } | ||
436 | rcu_read_unlock(); | ||
437 | |||
438 | return skb; | ||
439 | |||
440 | dump_failure: | ||
441 | rcu_read_unlock(); | ||
442 | kfree_skb(skb); | ||
443 | return NULL; | ||
444 | } | ||
445 | |||
446 | /** | ||
447 | * netlbl_domhsh_dump_default - Dump the default domain mapping into a sk_buff | ||
448 | * | ||
449 | * Description: | ||
450 | * Dump the default domain mapping into a buffer suitable for returning to an | ||
451 | * application in response to a NetLabel management DEFDOMAIN message. This | ||
452 | * function may fail if another process is changing the default domain mapping | ||
453 | * at the same time. The returned sk_buff has room at the front of the | ||
454 | * skb_buff for @headroom bytes. See netlabel.h for the DEFDOMAIN message | ||
455 | * format. Returns a pointer to a sk_buff on success, NULL on error. | ||
456 | * | ||
457 | */ | ||
458 | struct sk_buff *netlbl_domhsh_dump_default(size_t headroom) | ||
459 | { | ||
460 | struct sk_buff *skb; | ||
461 | ssize_t buf_len; | ||
462 | struct netlbl_dom_map *entry; | ||
463 | |||
464 | buf_len = NETLBL_LEN_U32; | ||
465 | rcu_read_lock(); | ||
466 | entry = rcu_dereference(netlbl_domhsh_def); | ||
467 | if (entry != NULL) | ||
468 | switch (entry->type) { | ||
469 | case NETLBL_NLTYPE_UNLABELED: | ||
470 | break; | ||
471 | case NETLBL_NLTYPE_CIPSOV4: | ||
472 | buf_len += 2 * NETLBL_LEN_U32; | ||
473 | break; | ||
474 | } | ||
475 | |||
476 | skb = netlbl_netlink_alloc_skb(headroom, buf_len, GFP_ATOMIC); | ||
477 | if (skb == NULL) | ||
478 | goto dump_default_failure; | ||
479 | |||
480 | if (entry != rcu_dereference(netlbl_domhsh_def)) | ||
481 | goto dump_default_failure; | ||
482 | if (entry != NULL) { | ||
483 | if (nla_put_u32(skb, NLA_U32, entry->type) != 0) | ||
484 | goto dump_default_failure; | ||
485 | buf_len -= NETLBL_LEN_U32; | ||
486 | switch (entry->type) { | ||
487 | case NETLBL_NLTYPE_UNLABELED: | ||
488 | break; | ||
489 | case NETLBL_NLTYPE_CIPSOV4: | ||
490 | if (buf_len < 2 * NETLBL_LEN_U32) | ||
491 | goto dump_default_failure; | ||
492 | if (nla_put_u32(skb, | ||
493 | NLA_U32, | ||
494 | entry->type_def.cipsov4->type) != 0) | ||
495 | goto dump_default_failure; | ||
496 | if (nla_put_u32(skb, | ||
497 | NLA_U32, | ||
498 | entry->type_def.cipsov4->doi) != 0) | ||
499 | goto dump_default_failure; | ||
500 | buf_len -= 2 * NETLBL_LEN_U32; | ||
501 | break; | ||
502 | } | ||
503 | } else | ||
504 | nla_put_u32(skb, NLA_U32, NETLBL_NLTYPE_NONE); | ||
505 | rcu_read_unlock(); | ||
506 | |||
507 | return skb; | ||
508 | |||
509 | dump_default_failure: | ||
510 | rcu_read_unlock(); | ||
511 | kfree_skb(skb); | ||
512 | return NULL; | ||
513 | } | ||
diff --git a/net/netlabel/netlabel_domainhash.h b/net/netlabel/netlabel_domainhash.h new file mode 100644 index 000000000000..99a2287de246 --- /dev/null +++ b/net/netlabel/netlabel_domainhash.h | |||
@@ -0,0 +1,67 @@ | |||
1 | /* | ||
2 | * NetLabel Domain Hash Table | ||
3 | * | ||
4 | * This file manages the domain hash table that NetLabel uses to determine | ||
5 | * which network labeling protocol to use for a given domain. The NetLabel | ||
6 | * system manages static and dynamic label mappings for network protocols such | ||
7 | * as CIPSO and RIPSO. | ||
8 | * | ||
9 | * Author: Paul Moore <paul.moore@hp.com> | ||
10 | * | ||
11 | */ | ||
12 | |||
13 | /* | ||
14 | * (c) Copyright Hewlett-Packard Development Company, L.P., 2006 | ||
15 | * | ||
16 | * This program is free software; you can redistribute it and/or modify | ||
17 | * it under the terms of the GNU General Public License as published by | ||
18 | * the Free Software Foundation; either version 2 of the License, or | ||
19 | * (at your option) any later version. | ||
20 | * | ||
21 | * This program is distributed in the hope that it will be useful, | ||
22 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
23 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See | ||
24 | * the GNU General Public License for more details. | ||
25 | * | ||
26 | * You should have received a copy of the GNU General Public License | ||
27 | * along with this program; if not, write to the Free Software | ||
28 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
29 | * | ||
30 | */ | ||
31 | |||
32 | #ifndef _NETLABEL_DOMAINHASH_H | ||
33 | #define _NETLABEL_DOMAINHASH_H | ||
34 | |||
35 | #include <linux/types.h> | ||
36 | #include <linux/rcupdate.h> | ||
37 | #include <linux/list.h> | ||
38 | |||
39 | /* Domain hash table size */ | ||
40 | /* XXX - currently this number is an uneducated guess */ | ||
41 | #define NETLBL_DOMHSH_BITSIZE 7 | ||
42 | |||
43 | /* Domain mapping definition struct */ | ||
44 | struct netlbl_dom_map { | ||
45 | char *domain; | ||
46 | u32 type; | ||
47 | union { | ||
48 | struct cipso_v4_doi *cipsov4; | ||
49 | } type_def; | ||
50 | |||
51 | u32 valid; | ||
52 | struct list_head list; | ||
53 | struct rcu_head rcu; | ||
54 | }; | ||
55 | |||
56 | /* init function */ | ||
57 | int netlbl_domhsh_init(u32 size); | ||
58 | |||
59 | /* Manipulate the domain hash table */ | ||
60 | int netlbl_domhsh_add(struct netlbl_dom_map *entry); | ||
61 | int netlbl_domhsh_add_default(struct netlbl_dom_map *entry); | ||
62 | int netlbl_domhsh_remove_default(void); | ||
63 | struct netlbl_dom_map *netlbl_domhsh_getentry(const char *domain); | ||
64 | struct sk_buff *netlbl_domhsh_dump(size_t headroom); | ||
65 | struct sk_buff *netlbl_domhsh_dump_default(size_t headroom); | ||
66 | |||
67 | #endif | ||
diff --git a/net/netlabel/netlabel_kapi.c b/net/netlabel/netlabel_kapi.c new file mode 100644 index 000000000000..0fd8aaafe23f --- /dev/null +++ b/net/netlabel/netlabel_kapi.c | |||
@@ -0,0 +1,231 @@ | |||
1 | /* | ||
2 | * NetLabel Kernel API | ||
3 | * | ||
4 | * This file defines the kernel API for the NetLabel system. The NetLabel | ||
5 | * system manages static and dynamic label mappings for network protocols such | ||
6 | * as CIPSO and RIPSO. | ||
7 | * | ||
8 | * Author: Paul Moore <paul.moore@hp.com> | ||
9 | * | ||
10 | */ | ||
11 | |||
12 | /* | ||
13 | * (c) Copyright Hewlett-Packard Development Company, L.P., 2006 | ||
14 | * | ||
15 | * This program is free software; you can redistribute it and/or modify | ||
16 | * it under the terms of the GNU General Public License as published by | ||
17 | * the Free Software Foundation; either version 2 of the License, or | ||
18 | * (at your option) any later version. | ||
19 | * | ||
20 | * This program is distributed in the hope that it will be useful, | ||
21 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
22 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See | ||
23 | * the GNU General Public License for more details. | ||
24 | * | ||
25 | * You should have received a copy of the GNU General Public License | ||
26 | * along with this program; if not, write to the Free Software | ||
27 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
28 | * | ||
29 | */ | ||
30 | |||
31 | #include <linux/init.h> | ||
32 | #include <linux/types.h> | ||
33 | #include <net/ip.h> | ||
34 | #include <net/netlabel.h> | ||
35 | #include <net/cipso_ipv4.h> | ||
36 | #include <asm/bug.h> | ||
37 | |||
38 | #include "netlabel_domainhash.h" | ||
39 | #include "netlabel_unlabeled.h" | ||
40 | #include "netlabel_user.h" | ||
41 | |||
42 | /* | ||
43 | * LSM Functions | ||
44 | */ | ||
45 | |||
46 | /** | ||
47 | * netlbl_socket_setattr - Label a socket using the correct protocol | ||
48 | * @sock: the socket to label | ||
49 | * @secattr: the security attributes | ||
50 | * | ||
51 | * Description: | ||
52 | * Attach the correct label to the given socket using the security attributes | ||
53 | * specified in @secattr. This function requires exclusive access to | ||
54 | * @sock->sk, which means it either needs to be in the process of being | ||
55 | * created or locked via lock_sock(sock->sk). Returns zero on success, | ||
56 | * negative values on failure. | ||
57 | * | ||
58 | */ | ||
59 | int netlbl_socket_setattr(const struct socket *sock, | ||
60 | const struct netlbl_lsm_secattr *secattr) | ||
61 | { | ||
62 | int ret_val = -ENOENT; | ||
63 | struct netlbl_dom_map *dom_entry; | ||
64 | |||
65 | rcu_read_lock(); | ||
66 | dom_entry = netlbl_domhsh_getentry(secattr->domain); | ||
67 | if (dom_entry == NULL) | ||
68 | goto socket_setattr_return; | ||
69 | switch (dom_entry->type) { | ||
70 | case NETLBL_NLTYPE_CIPSOV4: | ||
71 | ret_val = cipso_v4_socket_setattr(sock, | ||
72 | dom_entry->type_def.cipsov4, | ||
73 | secattr); | ||
74 | break; | ||
75 | case NETLBL_NLTYPE_UNLABELED: | ||
76 | ret_val = 0; | ||
77 | break; | ||
78 | default: | ||
79 | ret_val = -ENOENT; | ||
80 | } | ||
81 | |||
82 | socket_setattr_return: | ||
83 | rcu_read_unlock(); | ||
84 | return ret_val; | ||
85 | } | ||
86 | |||
87 | /** | ||
88 | * netlbl_socket_getattr - Determine the security attributes of a socket | ||
89 | * @sock: the socket | ||
90 | * @secattr: the security attributes | ||
91 | * | ||
92 | * Description: | ||
93 | * Examines the given socket to see any NetLabel style labeling has been | ||
94 | * applied to the socket, if so it parses the socket label and returns the | ||
95 | * security attributes in @secattr. Returns zero on success, negative values | ||
96 | * on failure. | ||
97 | * | ||
98 | */ | ||
99 | int netlbl_socket_getattr(const struct socket *sock, | ||
100 | struct netlbl_lsm_secattr *secattr) | ||
101 | { | ||
102 | int ret_val; | ||
103 | |||
104 | ret_val = cipso_v4_socket_getattr(sock, secattr); | ||
105 | if (ret_val == 0) | ||
106 | return 0; | ||
107 | |||
108 | return netlbl_unlabel_getattr(secattr); | ||
109 | } | ||
110 | |||
111 | /** | ||
112 | * netlbl_skbuff_getattr - Determine the security attributes of a packet | ||
113 | * @skb: the packet | ||
114 | * @secattr: the security attributes | ||
115 | * | ||
116 | * Description: | ||
117 | * Examines the given packet to see if a recognized form of packet labeling | ||
118 | * is present, if so it parses the packet label and returns the security | ||
119 | * attributes in @secattr. Returns zero on success, negative values on | ||
120 | * failure. | ||
121 | * | ||
122 | */ | ||
123 | int netlbl_skbuff_getattr(const struct sk_buff *skb, | ||
124 | struct netlbl_lsm_secattr *secattr) | ||
125 | { | ||
126 | int ret_val; | ||
127 | |||
128 | ret_val = cipso_v4_skbuff_getattr(skb, secattr); | ||
129 | if (ret_val == 0) | ||
130 | return 0; | ||
131 | |||
132 | return netlbl_unlabel_getattr(secattr); | ||
133 | } | ||
134 | |||
135 | /** | ||
136 | * netlbl_skbuff_err - Handle a LSM error on a sk_buff | ||
137 | * @skb: the packet | ||
138 | * @error: the error code | ||
139 | * | ||
140 | * Description: | ||
141 | * Deal with a LSM problem when handling the packet in @skb, typically this is | ||
142 | * a permission denied problem (-EACCES). The correct action is determined | ||
143 | * according to the packet's labeling protocol. | ||
144 | * | ||
145 | */ | ||
146 | void netlbl_skbuff_err(struct sk_buff *skb, int error) | ||
147 | { | ||
148 | if (CIPSO_V4_OPTEXIST(skb)) | ||
149 | cipso_v4_error(skb, error, 0); | ||
150 | } | ||
151 | |||
152 | /** | ||
153 | * netlbl_cache_invalidate - Invalidate all of the NetLabel protocol caches | ||
154 | * | ||
155 | * Description: | ||
156 | * For all of the NetLabel protocols that support some form of label mapping | ||
157 | * cache, invalidate the cache. Returns zero on success, negative values on | ||
158 | * error. | ||
159 | * | ||
160 | */ | ||
161 | void netlbl_cache_invalidate(void) | ||
162 | { | ||
163 | cipso_v4_cache_invalidate(); | ||
164 | } | ||
165 | |||
166 | /** | ||
167 | * netlbl_cache_add - Add an entry to a NetLabel protocol cache | ||
168 | * @skb: the packet | ||
169 | * @secattr: the packet's security attributes | ||
170 | * | ||
171 | * Description: | ||
172 | * Add the LSM security attributes for the given packet to the underlying | ||
173 | * NetLabel protocol's label mapping cache. Returns zero on success, negative | ||
174 | * values on error. | ||
175 | * | ||
176 | */ | ||
177 | int netlbl_cache_add(const struct sk_buff *skb, | ||
178 | const struct netlbl_lsm_secattr *secattr) | ||
179 | { | ||
180 | if (secattr->cache.data == NULL) | ||
181 | return -ENOMSG; | ||
182 | |||
183 | if (CIPSO_V4_OPTEXIST(skb)) | ||
184 | return cipso_v4_cache_add(skb, secattr); | ||
185 | |||
186 | return -ENOMSG; | ||
187 | } | ||
188 | |||
189 | /* | ||
190 | * Setup Functions | ||
191 | */ | ||
192 | |||
193 | /** | ||
194 | * netlbl_init - Initialize NetLabel | ||
195 | * | ||
196 | * Description: | ||
197 | * Perform the required NetLabel initialization before first use. | ||
198 | * | ||
199 | */ | ||
200 | static int __init netlbl_init(void) | ||
201 | { | ||
202 | int ret_val; | ||
203 | |||
204 | printk(KERN_INFO "NetLabel: Initializing\n"); | ||
205 | printk(KERN_INFO "NetLabel: domain hash size = %u\n", | ||
206 | (1 << NETLBL_DOMHSH_BITSIZE)); | ||
207 | printk(KERN_INFO "NetLabel: protocols =" | ||
208 | " UNLABELED" | ||
209 | " CIPSOv4" | ||
210 | "\n"); | ||
211 | |||
212 | ret_val = netlbl_domhsh_init(NETLBL_DOMHSH_BITSIZE); | ||
213 | if (ret_val != 0) | ||
214 | goto init_failure; | ||
215 | |||
216 | ret_val = netlbl_netlink_init(); | ||
217 | if (ret_val != 0) | ||
218 | goto init_failure; | ||
219 | |||
220 | ret_val = netlbl_unlabel_defconf(); | ||
221 | if (ret_val != 0) | ||
222 | goto init_failure; | ||
223 | printk(KERN_INFO "NetLabel: unlabeled traffic allowed by default\n"); | ||
224 | |||
225 | return 0; | ||
226 | |||
227 | init_failure: | ||
228 | panic("NetLabel: failed to initialize properly (%d)\n", ret_val); | ||
229 | } | ||
230 | |||
231 | subsys_initcall(netlbl_init); | ||
diff --git a/net/netlabel/netlabel_mgmt.c b/net/netlabel/netlabel_mgmt.c new file mode 100644 index 000000000000..85bc11a1fc46 --- /dev/null +++ b/net/netlabel/netlabel_mgmt.c | |||
@@ -0,0 +1,624 @@ | |||
1 | /* | ||
2 | * NetLabel Management Support | ||
3 | * | ||
4 | * This file defines the management functions for the NetLabel system. The | ||
5 | * NetLabel system manages static and dynamic label mappings for network | ||
6 | * protocols such as CIPSO and RIPSO. | ||
7 | * | ||
8 | * Author: Paul Moore <paul.moore@hp.com> | ||
9 | * | ||
10 | */ | ||
11 | |||
12 | /* | ||
13 | * (c) Copyright Hewlett-Packard Development Company, L.P., 2006 | ||
14 | * | ||
15 | * This program is free software; you can redistribute it and/or modify | ||
16 | * it under the terms of the GNU General Public License as published by | ||
17 | * the Free Software Foundation; either version 2 of the License, or | ||
18 | * (at your option) any later version. | ||
19 | * | ||
20 | * This program is distributed in the hope that it will be useful, | ||
21 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
22 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See | ||
23 | * the GNU General Public License for more details. | ||
24 | * | ||
25 | * You should have received a copy of the GNU General Public License | ||
26 | * along with this program; if not, write to the Free Software | ||
27 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
28 | * | ||
29 | */ | ||
30 | |||
31 | #include <linux/types.h> | ||
32 | #include <linux/socket.h> | ||
33 | #include <linux/string.h> | ||
34 | #include <linux/skbuff.h> | ||
35 | #include <net/sock.h> | ||
36 | #include <net/netlink.h> | ||
37 | #include <net/genetlink.h> | ||
38 | #include <net/netlabel.h> | ||
39 | #include <net/cipso_ipv4.h> | ||
40 | |||
41 | #include "netlabel_domainhash.h" | ||
42 | #include "netlabel_user.h" | ||
43 | #include "netlabel_mgmt.h" | ||
44 | |||
45 | /* NetLabel Generic NETLINK CIPSOv4 family */ | ||
46 | static struct genl_family netlbl_mgmt_gnl_family = { | ||
47 | .id = GENL_ID_GENERATE, | ||
48 | .hdrsize = 0, | ||
49 | .name = NETLBL_NLTYPE_MGMT_NAME, | ||
50 | .version = NETLBL_PROTO_VERSION, | ||
51 | .maxattr = 0, | ||
52 | }; | ||
53 | |||
54 | |||
55 | /* | ||
56 | * NetLabel Command Handlers | ||
57 | */ | ||
58 | |||
59 | /** | ||
60 | * netlbl_mgmt_add - Handle an ADD message | ||
61 | * @skb: the NETLINK buffer | ||
62 | * @info: the Generic NETLINK info block | ||
63 | * | ||
64 | * Description: | ||
65 | * Process a user generated ADD message and add the domains from the message | ||
66 | * to the hash table. See netlabel.h for a description of the message format. | ||
67 | * Returns zero on success, negative values on failure. | ||
68 | * | ||
69 | */ | ||
70 | static int netlbl_mgmt_add(struct sk_buff *skb, struct genl_info *info) | ||
71 | { | ||
72 | int ret_val = -EINVAL; | ||
73 | struct nlattr *msg_ptr = netlbl_netlink_payload_data(skb); | ||
74 | int msg_len = netlbl_netlink_payload_len(skb); | ||
75 | u32 count; | ||
76 | struct netlbl_dom_map *entry = NULL; | ||
77 | u32 iter; | ||
78 | u32 tmp_val; | ||
79 | int tmp_size; | ||
80 | |||
81 | ret_val = netlbl_netlink_cap_check(skb, CAP_NET_ADMIN); | ||
82 | if (ret_val != 0) | ||
83 | goto add_failure; | ||
84 | |||
85 | if (msg_len < NETLBL_LEN_U32) | ||
86 | goto add_failure; | ||
87 | count = netlbl_getinc_u32(&msg_ptr, &msg_len); | ||
88 | |||
89 | for (iter = 0; iter < count && msg_len > 0; iter++, entry = NULL) { | ||
90 | if (msg_len <= 0) { | ||
91 | ret_val = -EINVAL; | ||
92 | goto add_failure; | ||
93 | } | ||
94 | entry = kzalloc(sizeof(*entry), GFP_KERNEL); | ||
95 | if (entry == NULL) { | ||
96 | ret_val = -ENOMEM; | ||
97 | goto add_failure; | ||
98 | } | ||
99 | tmp_size = nla_len(msg_ptr); | ||
100 | if (tmp_size <= 0 || tmp_size > msg_len) { | ||
101 | ret_val = -EINVAL; | ||
102 | goto add_failure; | ||
103 | } | ||
104 | entry->domain = kmalloc(tmp_size, GFP_KERNEL); | ||
105 | if (entry->domain == NULL) { | ||
106 | ret_val = -ENOMEM; | ||
107 | goto add_failure; | ||
108 | } | ||
109 | nla_strlcpy(entry->domain, msg_ptr, tmp_size); | ||
110 | entry->domain[tmp_size - 1] = '\0'; | ||
111 | msg_ptr = nla_next(msg_ptr, &msg_len); | ||
112 | |||
113 | if (msg_len < NETLBL_LEN_U32) { | ||
114 | ret_val = -EINVAL; | ||
115 | goto add_failure; | ||
116 | } | ||
117 | tmp_val = netlbl_getinc_u32(&msg_ptr, &msg_len); | ||
118 | entry->type = tmp_val; | ||
119 | switch (tmp_val) { | ||
120 | case NETLBL_NLTYPE_UNLABELED: | ||
121 | ret_val = netlbl_domhsh_add(entry); | ||
122 | break; | ||
123 | case NETLBL_NLTYPE_CIPSOV4: | ||
124 | if (msg_len < NETLBL_LEN_U32) { | ||
125 | ret_val = -EINVAL; | ||
126 | goto add_failure; | ||
127 | } | ||
128 | tmp_val = netlbl_getinc_u32(&msg_ptr, &msg_len); | ||
129 | /* We should be holding a rcu_read_lock() here | ||
130 | * while we hold the result but since the entry | ||
131 | * will always be deleted when the CIPSO DOI | ||
132 | * is deleted we aren't going to keep the lock. */ | ||
133 | rcu_read_lock(); | ||
134 | entry->type_def.cipsov4 = cipso_v4_doi_getdef(tmp_val); | ||
135 | if (entry->type_def.cipsov4 == NULL) { | ||
136 | rcu_read_unlock(); | ||
137 | ret_val = -EINVAL; | ||
138 | goto add_failure; | ||
139 | } | ||
140 | ret_val = netlbl_domhsh_add(entry); | ||
141 | rcu_read_unlock(); | ||
142 | break; | ||
143 | default: | ||
144 | ret_val = -EINVAL; | ||
145 | } | ||
146 | if (ret_val != 0) | ||
147 | goto add_failure; | ||
148 | } | ||
149 | |||
150 | netlbl_netlink_send_ack(info, | ||
151 | netlbl_mgmt_gnl_family.id, | ||
152 | NLBL_MGMT_C_ACK, | ||
153 | NETLBL_E_OK); | ||
154 | return 0; | ||
155 | |||
156 | add_failure: | ||
157 | if (entry) | ||
158 | kfree(entry->domain); | ||
159 | kfree(entry); | ||
160 | netlbl_netlink_send_ack(info, | ||
161 | netlbl_mgmt_gnl_family.id, | ||
162 | NLBL_MGMT_C_ACK, | ||
163 | -ret_val); | ||
164 | return ret_val; | ||
165 | } | ||
166 | |||
167 | /** | ||
168 | * netlbl_mgmt_remove - Handle a REMOVE message | ||
169 | * @skb: the NETLINK buffer | ||
170 | * @info: the Generic NETLINK info block | ||
171 | * | ||
172 | * Description: | ||
173 | * Process a user generated REMOVE message and remove the specified domain | ||
174 | * mappings. Returns zero on success, negative values on failure. | ||
175 | * | ||
176 | */ | ||
177 | static int netlbl_mgmt_remove(struct sk_buff *skb, struct genl_info *info) | ||
178 | { | ||
179 | int ret_val = -EINVAL; | ||
180 | struct nlattr *msg_ptr = netlbl_netlink_payload_data(skb); | ||
181 | int msg_len = netlbl_netlink_payload_len(skb); | ||
182 | u32 count; | ||
183 | u32 iter; | ||
184 | int tmp_size; | ||
185 | unsigned char *domain; | ||
186 | |||
187 | ret_val = netlbl_netlink_cap_check(skb, CAP_NET_ADMIN); | ||
188 | if (ret_val != 0) | ||
189 | goto remove_return; | ||
190 | |||
191 | if (msg_len < NETLBL_LEN_U32) | ||
192 | goto remove_return; | ||
193 | count = netlbl_getinc_u32(&msg_ptr, &msg_len); | ||
194 | |||
195 | for (iter = 0; iter < count && msg_len > 0; iter++) { | ||
196 | if (msg_len <= 0) { | ||
197 | ret_val = -EINVAL; | ||
198 | goto remove_return; | ||
199 | } | ||
200 | tmp_size = nla_len(msg_ptr); | ||
201 | domain = nla_data(msg_ptr); | ||
202 | if (tmp_size <= 0 || tmp_size > msg_len || | ||
203 | domain[tmp_size - 1] != '\0') { | ||
204 | ret_val = -EINVAL; | ||
205 | goto remove_return; | ||
206 | } | ||
207 | ret_val = netlbl_domhsh_remove(domain); | ||
208 | if (ret_val != 0) | ||
209 | goto remove_return; | ||
210 | msg_ptr = nla_next(msg_ptr, &msg_len); | ||
211 | } | ||
212 | |||
213 | ret_val = 0; | ||
214 | |||
215 | remove_return: | ||
216 | netlbl_netlink_send_ack(info, | ||
217 | netlbl_mgmt_gnl_family.id, | ||
218 | NLBL_MGMT_C_ACK, | ||
219 | -ret_val); | ||
220 | return ret_val; | ||
221 | } | ||
222 | |||
223 | /** | ||
224 | * netlbl_mgmt_list - Handle a LIST message | ||
225 | * @skb: the NETLINK buffer | ||
226 | * @info: the Generic NETLINK info block | ||
227 | * | ||
228 | * Description: | ||
229 | * Process a user generated LIST message and dumps the domain hash table in a | ||
230 | * form suitable for use in a kernel generated LIST message. Returns zero on | ||
231 | * success, negative values on failure. | ||
232 | * | ||
233 | */ | ||
234 | static int netlbl_mgmt_list(struct sk_buff *skb, struct genl_info *info) | ||
235 | { | ||
236 | int ret_val = -ENOMEM; | ||
237 | struct sk_buff *ans_skb; | ||
238 | |||
239 | ans_skb = netlbl_domhsh_dump(NLMSG_SPACE(GENL_HDRLEN)); | ||
240 | if (ans_skb == NULL) | ||
241 | goto list_failure; | ||
242 | netlbl_netlink_hdr_push(ans_skb, | ||
243 | info->snd_pid, | ||
244 | 0, | ||
245 | netlbl_mgmt_gnl_family.id, | ||
246 | NLBL_MGMT_C_LIST); | ||
247 | |||
248 | ret_val = netlbl_netlink_snd(ans_skb, info->snd_pid); | ||
249 | if (ret_val != 0) | ||
250 | goto list_failure; | ||
251 | |||
252 | return 0; | ||
253 | |||
254 | list_failure: | ||
255 | netlbl_netlink_send_ack(info, | ||
256 | netlbl_mgmt_gnl_family.id, | ||
257 | NLBL_MGMT_C_ACK, | ||
258 | -ret_val); | ||
259 | return ret_val; | ||
260 | } | ||
261 | |||
262 | /** | ||
263 | * netlbl_mgmt_adddef - Handle an ADDDEF message | ||
264 | * @skb: the NETLINK buffer | ||
265 | * @info: the Generic NETLINK info block | ||
266 | * | ||
267 | * Description: | ||
268 | * Process a user generated ADDDEF message and respond accordingly. Returns | ||
269 | * zero on success, negative values on failure. | ||
270 | * | ||
271 | */ | ||
272 | static int netlbl_mgmt_adddef(struct sk_buff *skb, struct genl_info *info) | ||
273 | { | ||
274 | int ret_val = -EINVAL; | ||
275 | struct nlattr *msg_ptr = netlbl_netlink_payload_data(skb); | ||
276 | int msg_len = netlbl_netlink_payload_len(skb); | ||
277 | struct netlbl_dom_map *entry = NULL; | ||
278 | u32 tmp_val; | ||
279 | |||
280 | ret_val = netlbl_netlink_cap_check(skb, CAP_NET_ADMIN); | ||
281 | if (ret_val != 0) | ||
282 | goto adddef_failure; | ||
283 | |||
284 | if (msg_len < NETLBL_LEN_U32) | ||
285 | goto adddef_failure; | ||
286 | tmp_val = netlbl_getinc_u32(&msg_ptr, &msg_len); | ||
287 | |||
288 | entry = kzalloc(sizeof(*entry), GFP_KERNEL); | ||
289 | if (entry == NULL) { | ||
290 | ret_val = -ENOMEM; | ||
291 | goto adddef_failure; | ||
292 | } | ||
293 | |||
294 | entry->type = tmp_val; | ||
295 | switch (entry->type) { | ||
296 | case NETLBL_NLTYPE_UNLABELED: | ||
297 | ret_val = netlbl_domhsh_add_default(entry); | ||
298 | break; | ||
299 | case NETLBL_NLTYPE_CIPSOV4: | ||
300 | if (msg_len < NETLBL_LEN_U32) { | ||
301 | ret_val = -EINVAL; | ||
302 | goto adddef_failure; | ||
303 | } | ||
304 | tmp_val = netlbl_getinc_u32(&msg_ptr, &msg_len); | ||
305 | /* We should be holding a rcu_read_lock here while we | ||
306 | * hold the result but since the entry will always be | ||
307 | * deleted when the CIPSO DOI is deleted we are going | ||
308 | * to skip the lock. */ | ||
309 | rcu_read_lock(); | ||
310 | entry->type_def.cipsov4 = cipso_v4_doi_getdef(tmp_val); | ||
311 | if (entry->type_def.cipsov4 == NULL) { | ||
312 | rcu_read_unlock(); | ||
313 | ret_val = -EINVAL; | ||
314 | goto adddef_failure; | ||
315 | } | ||
316 | ret_val = netlbl_domhsh_add_default(entry); | ||
317 | rcu_read_unlock(); | ||
318 | break; | ||
319 | default: | ||
320 | ret_val = -EINVAL; | ||
321 | } | ||
322 | if (ret_val != 0) | ||
323 | goto adddef_failure; | ||
324 | |||
325 | netlbl_netlink_send_ack(info, | ||
326 | netlbl_mgmt_gnl_family.id, | ||
327 | NLBL_MGMT_C_ACK, | ||
328 | NETLBL_E_OK); | ||
329 | return 0; | ||
330 | |||
331 | adddef_failure: | ||
332 | kfree(entry); | ||
333 | netlbl_netlink_send_ack(info, | ||
334 | netlbl_mgmt_gnl_family.id, | ||
335 | NLBL_MGMT_C_ACK, | ||
336 | -ret_val); | ||
337 | return ret_val; | ||
338 | } | ||
339 | |||
340 | /** | ||
341 | * netlbl_mgmt_removedef - Handle a REMOVEDEF message | ||
342 | * @skb: the NETLINK buffer | ||
343 | * @info: the Generic NETLINK info block | ||
344 | * | ||
345 | * Description: | ||
346 | * Process a user generated REMOVEDEF message and remove the default domain | ||
347 | * mapping. Returns zero on success, negative values on failure. | ||
348 | * | ||
349 | */ | ||
350 | static int netlbl_mgmt_removedef(struct sk_buff *skb, struct genl_info *info) | ||
351 | { | ||
352 | int ret_val; | ||
353 | |||
354 | ret_val = netlbl_netlink_cap_check(skb, CAP_NET_ADMIN); | ||
355 | if (ret_val != 0) | ||
356 | goto removedef_return; | ||
357 | |||
358 | ret_val = netlbl_domhsh_remove_default(); | ||
359 | |||
360 | removedef_return: | ||
361 | netlbl_netlink_send_ack(info, | ||
362 | netlbl_mgmt_gnl_family.id, | ||
363 | NLBL_MGMT_C_ACK, | ||
364 | -ret_val); | ||
365 | return ret_val; | ||
366 | } | ||
367 | |||
368 | /** | ||
369 | * netlbl_mgmt_listdef - Handle a LISTDEF message | ||
370 | * @skb: the NETLINK buffer | ||
371 | * @info: the Generic NETLINK info block | ||
372 | * | ||
373 | * Description: | ||
374 | * Process a user generated LISTDEF message and dumps the default domain | ||
375 | * mapping in a form suitable for use in a kernel generated LISTDEF message. | ||
376 | * Returns zero on success, negative values on failure. | ||
377 | * | ||
378 | */ | ||
379 | static int netlbl_mgmt_listdef(struct sk_buff *skb, struct genl_info *info) | ||
380 | { | ||
381 | int ret_val = -ENOMEM; | ||
382 | struct sk_buff *ans_skb; | ||
383 | |||
384 | ans_skb = netlbl_domhsh_dump_default(NLMSG_SPACE(GENL_HDRLEN)); | ||
385 | if (ans_skb == NULL) | ||
386 | goto listdef_failure; | ||
387 | netlbl_netlink_hdr_push(ans_skb, | ||
388 | info->snd_pid, | ||
389 | 0, | ||
390 | netlbl_mgmt_gnl_family.id, | ||
391 | NLBL_MGMT_C_LISTDEF); | ||
392 | |||
393 | ret_val = netlbl_netlink_snd(ans_skb, info->snd_pid); | ||
394 | if (ret_val != 0) | ||
395 | goto listdef_failure; | ||
396 | |||
397 | return 0; | ||
398 | |||
399 | listdef_failure: | ||
400 | netlbl_netlink_send_ack(info, | ||
401 | netlbl_mgmt_gnl_family.id, | ||
402 | NLBL_MGMT_C_ACK, | ||
403 | -ret_val); | ||
404 | return ret_val; | ||
405 | } | ||
406 | |||
407 | /** | ||
408 | * netlbl_mgmt_modules - Handle a MODULES message | ||
409 | * @skb: the NETLINK buffer | ||
410 | * @info: the Generic NETLINK info block | ||
411 | * | ||
412 | * Description: | ||
413 | * Process a user generated MODULES message and respond accordingly. | ||
414 | * | ||
415 | */ | ||
416 | static int netlbl_mgmt_modules(struct sk_buff *skb, struct genl_info *info) | ||
417 | { | ||
418 | int ret_val = -ENOMEM; | ||
419 | size_t data_size; | ||
420 | u32 mod_count; | ||
421 | struct sk_buff *ans_skb = NULL; | ||
422 | |||
423 | /* unlabeled + cipsov4 */ | ||
424 | mod_count = 2; | ||
425 | |||
426 | data_size = GENL_HDRLEN + NETLBL_LEN_U32 + mod_count * NETLBL_LEN_U32; | ||
427 | ans_skb = netlbl_netlink_alloc_skb(0, data_size, GFP_KERNEL); | ||
428 | if (ans_skb == NULL) | ||
429 | goto modules_failure; | ||
430 | |||
431 | if (netlbl_netlink_hdr_put(ans_skb, | ||
432 | info->snd_pid, | ||
433 | 0, | ||
434 | netlbl_mgmt_gnl_family.id, | ||
435 | NLBL_MGMT_C_MODULES) == NULL) | ||
436 | goto modules_failure; | ||
437 | |||
438 | ret_val = nla_put_u32(ans_skb, NLA_U32, mod_count); | ||
439 | if (ret_val != 0) | ||
440 | goto modules_failure; | ||
441 | ret_val = nla_put_u32(ans_skb, NLA_U32, NETLBL_NLTYPE_UNLABELED); | ||
442 | if (ret_val != 0) | ||
443 | goto modules_failure; | ||
444 | ret_val = nla_put_u32(ans_skb, NLA_U32, NETLBL_NLTYPE_CIPSOV4); | ||
445 | if (ret_val != 0) | ||
446 | goto modules_failure; | ||
447 | |||
448 | ret_val = netlbl_netlink_snd(ans_skb, info->snd_pid); | ||
449 | if (ret_val != 0) | ||
450 | goto modules_failure; | ||
451 | |||
452 | return 0; | ||
453 | |||
454 | modules_failure: | ||
455 | kfree_skb(ans_skb); | ||
456 | netlbl_netlink_send_ack(info, | ||
457 | netlbl_mgmt_gnl_family.id, | ||
458 | NLBL_MGMT_C_ACK, | ||
459 | -ret_val); | ||
460 | return ret_val; | ||
461 | } | ||
462 | |||
463 | /** | ||
464 | * netlbl_mgmt_version - Handle a VERSION message | ||
465 | * @skb: the NETLINK buffer | ||
466 | * @info: the Generic NETLINK info block | ||
467 | * | ||
468 | * Description: | ||
469 | * Process a user generated VERSION message and respond accordingly. Returns | ||
470 | * zero on success, negative values on failure. | ||
471 | * | ||
472 | */ | ||
473 | static int netlbl_mgmt_version(struct sk_buff *skb, struct genl_info *info) | ||
474 | { | ||
475 | int ret_val = -ENOMEM; | ||
476 | struct sk_buff *ans_skb = NULL; | ||
477 | |||
478 | ans_skb = netlbl_netlink_alloc_skb(0, | ||
479 | GENL_HDRLEN + NETLBL_LEN_U32, | ||
480 | GFP_KERNEL); | ||
481 | if (ans_skb == NULL) | ||
482 | goto version_failure; | ||
483 | if (netlbl_netlink_hdr_put(ans_skb, | ||
484 | info->snd_pid, | ||
485 | 0, | ||
486 | netlbl_mgmt_gnl_family.id, | ||
487 | NLBL_MGMT_C_VERSION) == NULL) | ||
488 | goto version_failure; | ||
489 | |||
490 | ret_val = nla_put_u32(ans_skb, NLA_U32, NETLBL_PROTO_VERSION); | ||
491 | if (ret_val != 0) | ||
492 | goto version_failure; | ||
493 | |||
494 | ret_val = netlbl_netlink_snd(ans_skb, info->snd_pid); | ||
495 | if (ret_val != 0) | ||
496 | goto version_failure; | ||
497 | |||
498 | return 0; | ||
499 | |||
500 | version_failure: | ||
501 | kfree_skb(ans_skb); | ||
502 | netlbl_netlink_send_ack(info, | ||
503 | netlbl_mgmt_gnl_family.id, | ||
504 | NLBL_MGMT_C_ACK, | ||
505 | -ret_val); | ||
506 | return ret_val; | ||
507 | } | ||
508 | |||
509 | |||
510 | /* | ||
511 | * NetLabel Generic NETLINK Command Definitions | ||
512 | */ | ||
513 | |||
514 | static struct genl_ops netlbl_mgmt_genl_c_add = { | ||
515 | .cmd = NLBL_MGMT_C_ADD, | ||
516 | .flags = 0, | ||
517 | .doit = netlbl_mgmt_add, | ||
518 | .dumpit = NULL, | ||
519 | }; | ||
520 | |||
521 | static struct genl_ops netlbl_mgmt_genl_c_remove = { | ||
522 | .cmd = NLBL_MGMT_C_REMOVE, | ||
523 | .flags = 0, | ||
524 | .doit = netlbl_mgmt_remove, | ||
525 | .dumpit = NULL, | ||
526 | }; | ||
527 | |||
528 | static struct genl_ops netlbl_mgmt_genl_c_list = { | ||
529 | .cmd = NLBL_MGMT_C_LIST, | ||
530 | .flags = 0, | ||
531 | .doit = netlbl_mgmt_list, | ||
532 | .dumpit = NULL, | ||
533 | }; | ||
534 | |||
535 | static struct genl_ops netlbl_mgmt_genl_c_adddef = { | ||
536 | .cmd = NLBL_MGMT_C_ADDDEF, | ||
537 | .flags = 0, | ||
538 | .doit = netlbl_mgmt_adddef, | ||
539 | .dumpit = NULL, | ||
540 | }; | ||
541 | |||
542 | static struct genl_ops netlbl_mgmt_genl_c_removedef = { | ||
543 | .cmd = NLBL_MGMT_C_REMOVEDEF, | ||
544 | .flags = 0, | ||
545 | .doit = netlbl_mgmt_removedef, | ||
546 | .dumpit = NULL, | ||
547 | }; | ||
548 | |||
549 | static struct genl_ops netlbl_mgmt_genl_c_listdef = { | ||
550 | .cmd = NLBL_MGMT_C_LISTDEF, | ||
551 | .flags = 0, | ||
552 | .doit = netlbl_mgmt_listdef, | ||
553 | .dumpit = NULL, | ||
554 | }; | ||
555 | |||
556 | static struct genl_ops netlbl_mgmt_genl_c_modules = { | ||
557 | .cmd = NLBL_MGMT_C_MODULES, | ||
558 | .flags = 0, | ||
559 | .doit = netlbl_mgmt_modules, | ||
560 | .dumpit = NULL, | ||
561 | }; | ||
562 | |||
563 | static struct genl_ops netlbl_mgmt_genl_c_version = { | ||
564 | .cmd = NLBL_MGMT_C_VERSION, | ||
565 | .flags = 0, | ||
566 | .doit = netlbl_mgmt_version, | ||
567 | .dumpit = NULL, | ||
568 | }; | ||
569 | |||
570 | /* | ||
571 | * NetLabel Generic NETLINK Protocol Functions | ||
572 | */ | ||
573 | |||
574 | /** | ||
575 | * netlbl_mgmt_genl_init - Register the NetLabel management component | ||
576 | * | ||
577 | * Description: | ||
578 | * Register the NetLabel management component with the Generic NETLINK | ||
579 | * mechanism. Returns zero on success, negative values on failure. | ||
580 | * | ||
581 | */ | ||
582 | int netlbl_mgmt_genl_init(void) | ||
583 | { | ||
584 | int ret_val; | ||
585 | |||
586 | ret_val = genl_register_family(&netlbl_mgmt_gnl_family); | ||
587 | if (ret_val != 0) | ||
588 | return ret_val; | ||
589 | |||
590 | ret_val = genl_register_ops(&netlbl_mgmt_gnl_family, | ||
591 | &netlbl_mgmt_genl_c_add); | ||
592 | if (ret_val != 0) | ||
593 | return ret_val; | ||
594 | ret_val = genl_register_ops(&netlbl_mgmt_gnl_family, | ||
595 | &netlbl_mgmt_genl_c_remove); | ||
596 | if (ret_val != 0) | ||
597 | return ret_val; | ||
598 | ret_val = genl_register_ops(&netlbl_mgmt_gnl_family, | ||
599 | &netlbl_mgmt_genl_c_list); | ||
600 | if (ret_val != 0) | ||
601 | return ret_val; | ||
602 | ret_val = genl_register_ops(&netlbl_mgmt_gnl_family, | ||
603 | &netlbl_mgmt_genl_c_adddef); | ||
604 | if (ret_val != 0) | ||
605 | return ret_val; | ||
606 | ret_val = genl_register_ops(&netlbl_mgmt_gnl_family, | ||
607 | &netlbl_mgmt_genl_c_removedef); | ||
608 | if (ret_val != 0) | ||
609 | return ret_val; | ||
610 | ret_val = genl_register_ops(&netlbl_mgmt_gnl_family, | ||
611 | &netlbl_mgmt_genl_c_listdef); | ||
612 | if (ret_val != 0) | ||
613 | return ret_val; | ||
614 | ret_val = genl_register_ops(&netlbl_mgmt_gnl_family, | ||
615 | &netlbl_mgmt_genl_c_modules); | ||
616 | if (ret_val != 0) | ||
617 | return ret_val; | ||
618 | ret_val = genl_register_ops(&netlbl_mgmt_gnl_family, | ||
619 | &netlbl_mgmt_genl_c_version); | ||
620 | if (ret_val != 0) | ||
621 | return ret_val; | ||
622 | |||
623 | return 0; | ||
624 | } | ||
diff --git a/net/netlabel/netlabel_mgmt.h b/net/netlabel/netlabel_mgmt.h new file mode 100644 index 000000000000..fd6c6acbfa08 --- /dev/null +++ b/net/netlabel/netlabel_mgmt.h | |||
@@ -0,0 +1,246 @@ | |||
1 | /* | ||
2 | * NetLabel Management Support | ||
3 | * | ||
4 | * This file defines the management functions for the NetLabel system. The | ||
5 | * NetLabel system manages static and dynamic label mappings for network | ||
6 | * protocols such as CIPSO and RIPSO. | ||
7 | * | ||
8 | * Author: Paul Moore <paul.moore@hp.com> | ||
9 | * | ||
10 | */ | ||
11 | |||
12 | /* | ||
13 | * (c) Copyright Hewlett-Packard Development Company, L.P., 2006 | ||
14 | * | ||
15 | * This program is free software; you can redistribute it and/or modify | ||
16 | * it under the terms of the GNU General Public License as published by | ||
17 | * the Free Software Foundation; either version 2 of the License, or | ||
18 | * (at your option) any later version. | ||
19 | * | ||
20 | * This program is distributed in the hope that it will be useful, | ||
21 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
22 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See | ||
23 | * the GNU General Public License for more details. | ||
24 | * | ||
25 | * You should have received a copy of the GNU General Public License | ||
26 | * along with this program; if not, write to the Free Software | ||
27 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
28 | * | ||
29 | */ | ||
30 | |||
31 | #ifndef _NETLABEL_MGMT_H | ||
32 | #define _NETLABEL_MGMT_H | ||
33 | |||
34 | #include <net/netlabel.h> | ||
35 | |||
36 | /* | ||
37 | * The following NetLabel payloads are supported by the management interface, | ||
38 | * all of which are preceeded by the nlmsghdr struct. | ||
39 | * | ||
40 | * o ACK: | ||
41 | * Sent by the kernel in response to an applications message, applications | ||
42 | * should never send this message. | ||
43 | * | ||
44 | * +----------------------+-----------------------+ | ||
45 | * | seq number (32 bits) | return code (32 bits) | | ||
46 | * +----------------------+-----------------------+ | ||
47 | * | ||
48 | * seq number: the sequence number of the original message, taken from the | ||
49 | * nlmsghdr structure | ||
50 | * return code: return value, based on errno values | ||
51 | * | ||
52 | * o ADD: | ||
53 | * Sent by an application to add a domain mapping to the NetLabel system. | ||
54 | * The kernel should respond with an ACK. | ||
55 | * | ||
56 | * +-------------------+ | ||
57 | * | domains (32 bits) | ... | ||
58 | * +-------------------+ | ||
59 | * | ||
60 | * domains: the number of domains in the message | ||
61 | * | ||
62 | * +--------------------------+-------------------------+ | ||
63 | * | domain string (variable) | protocol type (32 bits) | ... | ||
64 | * +--------------------------+-------------------------+ | ||
65 | * | ||
66 | * +-------------- ---- --- -- - | ||
67 | * | mapping data ... repeated | ||
68 | * +-------------- ---- --- -- - | ||
69 | * | ||
70 | * domain string: the domain string, NULL terminated | ||
71 | * protocol type: the protocol type (defined by NETLBL_NLTYPE_*) | ||
72 | * mapping data: specific to the map type (see below) | ||
73 | * | ||
74 | * NETLBL_NLTYPE_UNLABELED | ||
75 | * | ||
76 | * No mapping data for this protocol type. | ||
77 | * | ||
78 | * NETLBL_NLTYPE_CIPSOV4 | ||
79 | * | ||
80 | * +---------------+ | ||
81 | * | doi (32 bits) | | ||
82 | * +---------------+ | ||
83 | * | ||
84 | * doi: the CIPSO DOI value | ||
85 | * | ||
86 | * o REMOVE: | ||
87 | * Sent by an application to remove a domain mapping from the NetLabel | ||
88 | * system. The kernel should ACK this message. | ||
89 | * | ||
90 | * +-------------------+ | ||
91 | * | domains (32 bits) | ... | ||
92 | * +-------------------+ | ||
93 | * | ||
94 | * domains: the number of domains in the message | ||
95 | * | ||
96 | * +--------------------------+ | ||
97 | * | domain string (variable) | ... | ||
98 | * +--------------------------+ | ||
99 | * | ||
100 | * domain string: the domain string, NULL terminated | ||
101 | * | ||
102 | * o LIST: | ||
103 | * This message can be sent either from an application or by the kernel in | ||
104 | * response to an application generated LIST message. When sent by an | ||
105 | * application there is no payload. The kernel should respond to a LIST | ||
106 | * message either with a LIST message on success or an ACK message on | ||
107 | * failure. | ||
108 | * | ||
109 | * +-------------------+ | ||
110 | * | domains (32 bits) | ... | ||
111 | * +-------------------+ | ||
112 | * | ||
113 | * domains: the number of domains in the message | ||
114 | * | ||
115 | * +--------------------------+ | ||
116 | * | domain string (variable) | ... | ||
117 | * +--------------------------+ | ||
118 | * | ||
119 | * +-------------------------+-------------- ---- --- -- - | ||
120 | * | protocol type (32 bits) | mapping data ... repeated | ||
121 | * +-------------------------+-------------- ---- --- -- - | ||
122 | * | ||
123 | * domain string: the domain string, NULL terminated | ||
124 | * protocol type: the protocol type (defined by NETLBL_NLTYPE_*) | ||
125 | * mapping data: specific to the map type (see below) | ||
126 | * | ||
127 | * NETLBL_NLTYPE_UNLABELED | ||
128 | * | ||
129 | * No mapping data for this protocol type. | ||
130 | * | ||
131 | * NETLBL_NLTYPE_CIPSOV4 | ||
132 | * | ||
133 | * +----------------+---------------+ | ||
134 | * | type (32 bits) | doi (32 bits) | | ||
135 | * +----------------+---------------+ | ||
136 | * | ||
137 | * type: the CIPSO mapping table type (defined in the cipso_ipv4.h header | ||
138 | * as CIPSO_V4_MAP_*) | ||
139 | * doi: the CIPSO DOI value | ||
140 | * | ||
141 | * o ADDDEF: | ||
142 | * Sent by an application to set the default domain mapping for the NetLabel | ||
143 | * system. The kernel should respond with an ACK. | ||
144 | * | ||
145 | * +-------------------------+-------------- ---- --- -- - | ||
146 | * | protocol type (32 bits) | mapping data ... repeated | ||
147 | * +-------------------------+-------------- ---- --- -- - | ||
148 | * | ||
149 | * protocol type: the protocol type (defined by NETLBL_NLTYPE_*) | ||
150 | * mapping data: specific to the map type (see below) | ||
151 | * | ||
152 | * NETLBL_NLTYPE_UNLABELED | ||
153 | * | ||
154 | * No mapping data for this protocol type. | ||
155 | * | ||
156 | * NETLBL_NLTYPE_CIPSOV4 | ||
157 | * | ||
158 | * +---------------+ | ||
159 | * | doi (32 bits) | | ||
160 | * +---------------+ | ||
161 | * | ||
162 | * doi: the CIPSO DOI value | ||
163 | * | ||
164 | * o REMOVEDEF: | ||
165 | * Sent by an application to remove the default domain mapping from the | ||
166 | * NetLabel system, there is no payload. The kernel should ACK this message. | ||
167 | * | ||
168 | * o LISTDEF: | ||
169 | * This message can be sent either from an application or by the kernel in | ||
170 | * response to an application generated LISTDEF message. When sent by an | ||
171 | * application there is no payload. The kernel should respond to a | ||
172 | * LISTDEF message either with a LISTDEF message on success or an ACK message | ||
173 | * on failure. | ||
174 | * | ||
175 | * +-------------------------+-------------- ---- --- -- - | ||
176 | * | protocol type (32 bits) | mapping data ... repeated | ||
177 | * +-------------------------+-------------- ---- --- -- - | ||
178 | * | ||
179 | * protocol type: the protocol type (defined by NETLBL_NLTYPE_*) | ||
180 | * mapping data: specific to the map type (see below) | ||
181 | * | ||
182 | * NETLBL_NLTYPE_UNLABELED | ||
183 | * | ||
184 | * No mapping data for this protocol type. | ||
185 | * | ||
186 | * NETLBL_NLTYPE_CIPSOV4 | ||
187 | * | ||
188 | * +----------------+---------------+ | ||
189 | * | type (32 bits) | doi (32 bits) | | ||
190 | * +----------------+---------------+ | ||
191 | * | ||
192 | * type: the CIPSO mapping table type (defined in the cipso_ipv4.h header | ||
193 | * as CIPSO_V4_MAP_*) | ||
194 | * doi: the CIPSO DOI value | ||
195 | * | ||
196 | * o MODULES: | ||
197 | * Sent by an application to request a list of configured NetLabel modules | ||
198 | * in the kernel. When sent by an application there is no payload. | ||
199 | * | ||
200 | * +-------------------+ | ||
201 | * | modules (32 bits) | ... | ||
202 | * +-------------------+ | ||
203 | * | ||
204 | * modules: the number of modules in the message, if this is an application | ||
205 | * generated message and the value is zero then return a list of | ||
206 | * the configured modules | ||
207 | * | ||
208 | * +------------------+ | ||
209 | * | module (32 bits) | ... repeated | ||
210 | * +------------------+ | ||
211 | * | ||
212 | * module: the module number as defined by NETLBL_NLTYPE_* | ||
213 | * | ||
214 | * o VERSION: | ||
215 | * Sent by an application to request the NetLabel version string. When sent | ||
216 | * by an application there is no payload. This message type is also used by | ||
217 | * the kernel to respond to an VERSION request. | ||
218 | * | ||
219 | * +-------------------+ | ||
220 | * | version (32 bits) | | ||
221 | * +-------------------+ | ||
222 | * | ||
223 | * version: the protocol version number | ||
224 | * | ||
225 | */ | ||
226 | |||
227 | /* NetLabel Management commands */ | ||
228 | enum { | ||
229 | NLBL_MGMT_C_UNSPEC, | ||
230 | NLBL_MGMT_C_ACK, | ||
231 | NLBL_MGMT_C_ADD, | ||
232 | NLBL_MGMT_C_REMOVE, | ||
233 | NLBL_MGMT_C_LIST, | ||
234 | NLBL_MGMT_C_ADDDEF, | ||
235 | NLBL_MGMT_C_REMOVEDEF, | ||
236 | NLBL_MGMT_C_LISTDEF, | ||
237 | NLBL_MGMT_C_MODULES, | ||
238 | NLBL_MGMT_C_VERSION, | ||
239 | __NLBL_MGMT_C_MAX, | ||
240 | }; | ||
241 | #define NLBL_MGMT_C_MAX (__NLBL_MGMT_C_MAX - 1) | ||
242 | |||
243 | /* NetLabel protocol functions */ | ||
244 | int netlbl_mgmt_genl_init(void); | ||
245 | |||
246 | #endif | ||
diff --git a/net/netlabel/netlabel_unlabeled.c b/net/netlabel/netlabel_unlabeled.c new file mode 100644 index 000000000000..785f4960e0d3 --- /dev/null +++ b/net/netlabel/netlabel_unlabeled.c | |||
@@ -0,0 +1,253 @@ | |||
1 | /* | ||
2 | * NetLabel Unlabeled Support | ||
3 | * | ||
4 | * This file defines functions for dealing with unlabeled packets for the | ||
5 | * NetLabel system. The NetLabel system manages static and dynamic label | ||
6 | * mappings for network protocols such as CIPSO and RIPSO. | ||
7 | * | ||
8 | * Author: Paul Moore <paul.moore@hp.com> | ||
9 | * | ||
10 | */ | ||
11 | |||
12 | /* | ||
13 | * (c) Copyright Hewlett-Packard Development Company, L.P., 2006 | ||
14 | * | ||
15 | * This program is free software; you can redistribute it and/or modify | ||
16 | * it under the terms of the GNU General Public License as published by | ||
17 | * the Free Software Foundation; either version 2 of the License, or | ||
18 | * (at your option) any later version. | ||
19 | * | ||
20 | * This program is distributed in the hope that it will be useful, | ||
21 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
22 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See | ||
23 | * the GNU General Public License for more details. | ||
24 | * | ||
25 | * You should have received a copy of the GNU General Public License | ||
26 | * along with this program; if not, write to the Free Software | ||
27 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
28 | * | ||
29 | */ | ||
30 | |||
31 | #include <linux/types.h> | ||
32 | #include <linux/rcupdate.h> | ||
33 | #include <linux/list.h> | ||
34 | #include <linux/spinlock.h> | ||
35 | #include <linux/socket.h> | ||
36 | #include <linux/string.h> | ||
37 | #include <linux/skbuff.h> | ||
38 | #include <net/sock.h> | ||
39 | #include <net/netlink.h> | ||
40 | #include <net/genetlink.h> | ||
41 | |||
42 | #include <net/netlabel.h> | ||
43 | #include <asm/bug.h> | ||
44 | |||
45 | #include "netlabel_user.h" | ||
46 | #include "netlabel_domainhash.h" | ||
47 | #include "netlabel_unlabeled.h" | ||
48 | |||
49 | /* Accept unlabeled packets flag */ | ||
50 | static atomic_t netlabel_unlabel_accept_flg = ATOMIC_INIT(0); | ||
51 | |||
52 | /* NetLabel Generic NETLINK CIPSOv4 family */ | ||
53 | static struct genl_family netlbl_unlabel_gnl_family = { | ||
54 | .id = GENL_ID_GENERATE, | ||
55 | .hdrsize = 0, | ||
56 | .name = NETLBL_NLTYPE_UNLABELED_NAME, | ||
57 | .version = NETLBL_PROTO_VERSION, | ||
58 | .maxattr = 0, | ||
59 | }; | ||
60 | |||
61 | |||
62 | /* | ||
63 | * NetLabel Command Handlers | ||
64 | */ | ||
65 | |||
66 | /** | ||
67 | * netlbl_unlabel_accept - Handle an ACCEPT message | ||
68 | * @skb: the NETLINK buffer | ||
69 | * @info: the Generic NETLINK info block | ||
70 | * | ||
71 | * Description: | ||
72 | * Process a user generated ACCEPT message and set the accept flag accordingly. | ||
73 | * Returns zero on success, negative values on failure. | ||
74 | * | ||
75 | */ | ||
76 | static int netlbl_unlabel_accept(struct sk_buff *skb, struct genl_info *info) | ||
77 | { | ||
78 | int ret_val; | ||
79 | struct nlattr *data = netlbl_netlink_payload_data(skb); | ||
80 | u32 value; | ||
81 | |||
82 | ret_val = netlbl_netlink_cap_check(skb, CAP_NET_ADMIN); | ||
83 | if (ret_val != 0) | ||
84 | return ret_val; | ||
85 | |||
86 | if (netlbl_netlink_payload_len(skb) == NETLBL_LEN_U32) { | ||
87 | value = nla_get_u32(data); | ||
88 | if (value == 1 || value == 0) { | ||
89 | atomic_set(&netlabel_unlabel_accept_flg, value); | ||
90 | netlbl_netlink_send_ack(info, | ||
91 | netlbl_unlabel_gnl_family.id, | ||
92 | NLBL_UNLABEL_C_ACK, | ||
93 | NETLBL_E_OK); | ||
94 | return 0; | ||
95 | } | ||
96 | } | ||
97 | |||
98 | netlbl_netlink_send_ack(info, | ||
99 | netlbl_unlabel_gnl_family.id, | ||
100 | NLBL_UNLABEL_C_ACK, | ||
101 | EINVAL); | ||
102 | return -EINVAL; | ||
103 | } | ||
104 | |||
105 | /** | ||
106 | * netlbl_unlabel_list - Handle a LIST message | ||
107 | * @skb: the NETLINK buffer | ||
108 | * @info: the Generic NETLINK info block | ||
109 | * | ||
110 | * Description: | ||
111 | * Process a user generated LIST message and respond with the current status. | ||
112 | * Returns zero on success, negative values on failure. | ||
113 | * | ||
114 | */ | ||
115 | static int netlbl_unlabel_list(struct sk_buff *skb, struct genl_info *info) | ||
116 | { | ||
117 | int ret_val = -ENOMEM; | ||
118 | struct sk_buff *ans_skb; | ||
119 | |||
120 | ans_skb = netlbl_netlink_alloc_skb(0, | ||
121 | GENL_HDRLEN + NETLBL_LEN_U32, | ||
122 | GFP_KERNEL); | ||
123 | if (ans_skb == NULL) | ||
124 | goto list_failure; | ||
125 | |||
126 | if (netlbl_netlink_hdr_put(ans_skb, | ||
127 | info->snd_pid, | ||
128 | 0, | ||
129 | netlbl_unlabel_gnl_family.id, | ||
130 | NLBL_UNLABEL_C_LIST) == NULL) | ||
131 | goto list_failure; | ||
132 | |||
133 | ret_val = nla_put_u32(ans_skb, | ||
134 | NLA_U32, | ||
135 | atomic_read(&netlabel_unlabel_accept_flg)); | ||
136 | if (ret_val != 0) | ||
137 | goto list_failure; | ||
138 | |||
139 | ret_val = netlbl_netlink_snd(ans_skb, info->snd_pid); | ||
140 | if (ret_val != 0) | ||
141 | goto list_failure; | ||
142 | |||
143 | return 0; | ||
144 | |||
145 | list_failure: | ||
146 | netlbl_netlink_send_ack(info, | ||
147 | netlbl_unlabel_gnl_family.id, | ||
148 | NLBL_UNLABEL_C_ACK, | ||
149 | -ret_val); | ||
150 | return ret_val; | ||
151 | } | ||
152 | |||
153 | |||
154 | /* | ||
155 | * NetLabel Generic NETLINK Command Definitions | ||
156 | */ | ||
157 | |||
158 | static struct genl_ops netlbl_unlabel_genl_c_accept = { | ||
159 | .cmd = NLBL_UNLABEL_C_ACCEPT, | ||
160 | .flags = 0, | ||
161 | .doit = netlbl_unlabel_accept, | ||
162 | .dumpit = NULL, | ||
163 | }; | ||
164 | |||
165 | static struct genl_ops netlbl_unlabel_genl_c_list = { | ||
166 | .cmd = NLBL_UNLABEL_C_LIST, | ||
167 | .flags = 0, | ||
168 | .doit = netlbl_unlabel_list, | ||
169 | .dumpit = NULL, | ||
170 | }; | ||
171 | |||
172 | |||
173 | /* | ||
174 | * NetLabel Generic NETLINK Protocol Functions | ||
175 | */ | ||
176 | |||
177 | /** | ||
178 | * netlbl_unlabel_genl_init - Register the Unlabeled NetLabel component | ||
179 | * | ||
180 | * Description: | ||
181 | * Register the unlabeled packet NetLabel component with the Generic NETLINK | ||
182 | * mechanism. Returns zero on success, negative values on failure. | ||
183 | * | ||
184 | */ | ||
185 | int netlbl_unlabel_genl_init(void) | ||
186 | { | ||
187 | int ret_val; | ||
188 | |||
189 | ret_val = genl_register_family(&netlbl_unlabel_gnl_family); | ||
190 | if (ret_val != 0) | ||
191 | return ret_val; | ||
192 | |||
193 | ret_val = genl_register_ops(&netlbl_unlabel_gnl_family, | ||
194 | &netlbl_unlabel_genl_c_accept); | ||
195 | if (ret_val != 0) | ||
196 | return ret_val; | ||
197 | |||
198 | ret_val = genl_register_ops(&netlbl_unlabel_gnl_family, | ||
199 | &netlbl_unlabel_genl_c_list); | ||
200 | if (ret_val != 0) | ||
201 | return ret_val; | ||
202 | |||
203 | return 0; | ||
204 | } | ||
205 | |||
206 | /* | ||
207 | * NetLabel KAPI Hooks | ||
208 | */ | ||
209 | |||
210 | /** | ||
211 | * netlbl_unlabel_getattr - Get the security attributes for an unlabled packet | ||
212 | * @secattr: the security attributes | ||
213 | * | ||
214 | * Description: | ||
215 | * Determine the security attributes, if any, for an unlabled packet and return | ||
216 | * them in @secattr. Returns zero on success and negative values on failure. | ||
217 | * | ||
218 | */ | ||
219 | int netlbl_unlabel_getattr(struct netlbl_lsm_secattr *secattr) | ||
220 | { | ||
221 | if (atomic_read(&netlabel_unlabel_accept_flg) == 1) { | ||
222 | memset(secattr, 0, sizeof(*secattr)); | ||
223 | return 0; | ||
224 | } | ||
225 | |||
226 | return -ENOMSG; | ||
227 | } | ||
228 | |||
229 | /** | ||
230 | * netlbl_unlabel_defconf - Set the default config to allow unlabeled packets | ||
231 | * | ||
232 | * Description: | ||
233 | * Set the default NetLabel configuration to allow incoming unlabeled packets | ||
234 | * and to send unlabeled network traffic by default. | ||
235 | * | ||
236 | */ | ||
237 | int netlbl_unlabel_defconf(void) | ||
238 | { | ||
239 | int ret_val; | ||
240 | struct netlbl_dom_map *entry; | ||
241 | |||
242 | entry = kzalloc(sizeof(*entry), GFP_KERNEL); | ||
243 | if (entry == NULL) | ||
244 | return -ENOMEM; | ||
245 | entry->type = NETLBL_NLTYPE_UNLABELED; | ||
246 | ret_val = netlbl_domhsh_add_default(entry); | ||
247 | if (ret_val != 0) | ||
248 | return ret_val; | ||
249 | |||
250 | atomic_set(&netlabel_unlabel_accept_flg, 1); | ||
251 | |||
252 | return 0; | ||
253 | } | ||
diff --git a/net/netlabel/netlabel_unlabeled.h b/net/netlabel/netlabel_unlabeled.h new file mode 100644 index 000000000000..f300e54e14b6 --- /dev/null +++ b/net/netlabel/netlabel_unlabeled.h | |||
@@ -0,0 +1,98 @@ | |||
1 | /* | ||
2 | * NetLabel Unlabeled Support | ||
3 | * | ||
4 | * This file defines functions for dealing with unlabeled packets for the | ||
5 | * NetLabel system. The NetLabel system manages static and dynamic label | ||
6 | * mappings for network protocols such as CIPSO and RIPSO. | ||
7 | * | ||
8 | * Author: Paul Moore <paul.moore@hp.com> | ||
9 | * | ||
10 | */ | ||
11 | |||
12 | /* | ||
13 | * (c) Copyright Hewlett-Packard Development Company, L.P., 2006 | ||
14 | * | ||
15 | * This program is free software; you can redistribute it and/or modify | ||
16 | * it under the terms of the GNU General Public License as published by | ||
17 | * the Free Software Foundation; either version 2 of the License, or | ||
18 | * (at your option) any later version. | ||
19 | * | ||
20 | * This program is distributed in the hope that it will be useful, | ||
21 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
22 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See | ||
23 | * the GNU General Public License for more details. | ||
24 | * | ||
25 | * You should have received a copy of the GNU General Public License | ||
26 | * along with this program; if not, write to the Free Software | ||
27 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
28 | * | ||
29 | */ | ||
30 | |||
31 | #ifndef _NETLABEL_UNLABELED_H | ||
32 | #define _NETLABEL_UNLABELED_H | ||
33 | |||
34 | #include <net/netlabel.h> | ||
35 | |||
36 | /* | ||
37 | * The following NetLabel payloads are supported by the Unlabeled subsystem. | ||
38 | * | ||
39 | * o ACK: | ||
40 | * Sent by the kernel in response to an applications message, applications | ||
41 | * should never send this message. | ||
42 | * | ||
43 | * +----------------------+-----------------------+ | ||
44 | * | seq number (32 bits) | return code (32 bits) | | ||
45 | * +----------------------+-----------------------+ | ||
46 | * | ||
47 | * seq number: the sequence number of the original message, taken from the | ||
48 | * nlmsghdr structure | ||
49 | * return code: return value, based on errno values | ||
50 | * | ||
51 | * o ACCEPT | ||
52 | * This message is sent from an application to specify if the kernel should | ||
53 | * allow unlabled packets to pass if they do not match any of the static | ||
54 | * mappings defined in the unlabeled module. | ||
55 | * | ||
56 | * +-----------------+ | ||
57 | * | allow (32 bits) | | ||
58 | * +-----------------+ | ||
59 | * | ||
60 | * allow: if true (1) then allow the packets to pass, if false (0) then | ||
61 | * reject the packets | ||
62 | * | ||
63 | * o LIST | ||
64 | * This message can be sent either from an application or by the kernel in | ||
65 | * response to an application generated LIST message. When sent by an | ||
66 | * application there is no payload. The kernel should respond to a LIST | ||
67 | * message either with a LIST message on success or an ACK message on | ||
68 | * failure. | ||
69 | * | ||
70 | * +-----------------------+ | ||
71 | * | accept flag (32 bits) | | ||
72 | * +-----------------------+ | ||
73 | * | ||
74 | * accept flag: if true (1) then unlabeled packets are allowed to pass, | ||
75 | * if false (0) then unlabeled packets are rejected | ||
76 | * | ||
77 | */ | ||
78 | |||
79 | /* NetLabel Unlabeled commands */ | ||
80 | enum { | ||
81 | NLBL_UNLABEL_C_UNSPEC, | ||
82 | NLBL_UNLABEL_C_ACK, | ||
83 | NLBL_UNLABEL_C_ACCEPT, | ||
84 | NLBL_UNLABEL_C_LIST, | ||
85 | __NLBL_UNLABEL_C_MAX, | ||
86 | }; | ||
87 | #define NLBL_UNLABEL_C_MAX (__NLBL_UNLABEL_C_MAX - 1) | ||
88 | |||
89 | /* NetLabel protocol functions */ | ||
90 | int netlbl_unlabel_genl_init(void); | ||
91 | |||
92 | /* Process Unlabeled incoming network packets */ | ||
93 | int netlbl_unlabel_getattr(struct netlbl_lsm_secattr *secattr); | ||
94 | |||
95 | /* Set the default configuration to allow Unlabeled packets */ | ||
96 | int netlbl_unlabel_defconf(void); | ||
97 | |||
98 | #endif | ||
diff --git a/net/netlabel/netlabel_user.c b/net/netlabel/netlabel_user.c new file mode 100644 index 000000000000..73cbe66e42ff --- /dev/null +++ b/net/netlabel/netlabel_user.c | |||
@@ -0,0 +1,158 @@ | |||
1 | /* | ||
2 | * NetLabel NETLINK Interface | ||
3 | * | ||
4 | * This file defines the NETLINK interface for the NetLabel system. The | ||
5 | * NetLabel system manages static and dynamic label mappings for network | ||
6 | * protocols such as CIPSO and RIPSO. | ||
7 | * | ||
8 | * Author: Paul Moore <paul.moore@hp.com> | ||
9 | * | ||
10 | */ | ||
11 | |||
12 | /* | ||
13 | * (c) Copyright Hewlett-Packard Development Company, L.P., 2006 | ||
14 | * | ||
15 | * This program is free software; you can redistribute it and/or modify | ||
16 | * it under the terms of the GNU General Public License as published by | ||
17 | * the Free Software Foundation; either version 2 of the License, or | ||
18 | * (at your option) any later version. | ||
19 | * | ||
20 | * This program is distributed in the hope that it will be useful, | ||
21 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
22 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See | ||
23 | * the GNU General Public License for more details. | ||
24 | * | ||
25 | * You should have received a copy of the GNU General Public License | ||
26 | * along with this program; if not, write to the Free Software | ||
27 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
28 | * | ||
29 | */ | ||
30 | |||
31 | #include <linux/init.h> | ||
32 | #include <linux/types.h> | ||
33 | #include <linux/list.h> | ||
34 | #include <linux/socket.h> | ||
35 | #include <net/sock.h> | ||
36 | #include <net/netlink.h> | ||
37 | #include <net/genetlink.h> | ||
38 | #include <net/netlabel.h> | ||
39 | #include <asm/bug.h> | ||
40 | |||
41 | #include "netlabel_mgmt.h" | ||
42 | #include "netlabel_unlabeled.h" | ||
43 | #include "netlabel_cipso_v4.h" | ||
44 | #include "netlabel_user.h" | ||
45 | |||
46 | /* | ||
47 | * NetLabel NETLINK Setup Functions | ||
48 | */ | ||
49 | |||
50 | /** | ||
51 | * netlbl_netlink_init - Initialize the NETLINK communication channel | ||
52 | * | ||
53 | * Description: | ||
54 | * Call out to the NetLabel components so they can register their families and | ||
55 | * commands with the Generic NETLINK mechanism. Returns zero on success and | ||
56 | * non-zero on failure. | ||
57 | * | ||
58 | */ | ||
59 | int netlbl_netlink_init(void) | ||
60 | { | ||
61 | int ret_val; | ||
62 | |||
63 | ret_val = netlbl_mgmt_genl_init(); | ||
64 | if (ret_val != 0) | ||
65 | return ret_val; | ||
66 | |||
67 | ret_val = netlbl_cipsov4_genl_init(); | ||
68 | if (ret_val != 0) | ||
69 | return ret_val; | ||
70 | |||
71 | ret_val = netlbl_unlabel_genl_init(); | ||
72 | if (ret_val != 0) | ||
73 | return ret_val; | ||
74 | |||
75 | return 0; | ||
76 | } | ||
77 | |||
78 | /* | ||
79 | * NetLabel Common Protocol Functions | ||
80 | */ | ||
81 | |||
82 | /** | ||
83 | * netlbl_netlink_send_ack - Send an ACK message | ||
84 | * @info: the generic NETLINK information | ||
85 | * @genl_family: the generic NETLINK family ID value | ||
86 | * @ack_cmd: the generic NETLINK family ACK command value | ||
87 | * @ret_code: return code to use | ||
88 | * | ||
89 | * Description: | ||
90 | * This function sends an ACK message to the sender of the NETLINK message | ||
91 | * specified by @info. | ||
92 | * | ||
93 | */ | ||
94 | void netlbl_netlink_send_ack(const struct genl_info *info, | ||
95 | u32 genl_family, | ||
96 | u8 ack_cmd, | ||
97 | u32 ret_code) | ||
98 | { | ||
99 | size_t data_size; | ||
100 | struct sk_buff *skb; | ||
101 | |||
102 | data_size = GENL_HDRLEN + 2 * NETLBL_LEN_U32; | ||
103 | skb = netlbl_netlink_alloc_skb(0, data_size, GFP_KERNEL); | ||
104 | if (skb == NULL) | ||
105 | return; | ||
106 | |||
107 | if (netlbl_netlink_hdr_put(skb, | ||
108 | info->snd_pid, | ||
109 | 0, | ||
110 | genl_family, | ||
111 | ack_cmd) == NULL) | ||
112 | goto send_ack_failure; | ||
113 | |||
114 | if (nla_put_u32(skb, NLA_U32, info->snd_seq) != 0) | ||
115 | goto send_ack_failure; | ||
116 | if (nla_put_u32(skb, NLA_U32, ret_code) != 0) | ||
117 | goto send_ack_failure; | ||
118 | |||
119 | netlbl_netlink_snd(skb, info->snd_pid); | ||
120 | return; | ||
121 | |||
122 | send_ack_failure: | ||
123 | kfree_skb(skb); | ||
124 | } | ||
125 | |||
126 | /* | ||
127 | * NETLINK I/O Functions | ||
128 | */ | ||
129 | |||
130 | /** | ||
131 | * netlbl_netlink_snd - Send a NetLabel message | ||
132 | * @skb: NetLabel message | ||
133 | * @pid: destination PID | ||
134 | * | ||
135 | * Description: | ||
136 | * Sends a unicast NetLabel message over the NETLINK socket. | ||
137 | * | ||
138 | */ | ||
139 | int netlbl_netlink_snd(struct sk_buff *skb, u32 pid) | ||
140 | { | ||
141 | return genlmsg_unicast(skb, pid); | ||
142 | } | ||
143 | |||
144 | /** | ||
145 | * netlbl_netlink_snd - Send a NetLabel message | ||
146 | * @skb: NetLabel message | ||
147 | * @pid: sending PID | ||
148 | * @group: multicast group id | ||
149 | * | ||
150 | * Description: | ||
151 | * Sends a multicast NetLabel message over the NETLINK socket to all members | ||
152 | * of @group except @pid. | ||
153 | * | ||
154 | */ | ||
155 | int netlbl_netlink_snd_multicast(struct sk_buff *skb, u32 pid, u32 group) | ||
156 | { | ||
157 | return genlmsg_multicast(skb, pid, group, GFP_KERNEL); | ||
158 | } | ||
diff --git a/net/netlabel/netlabel_user.h b/net/netlabel/netlabel_user.h new file mode 100644 index 000000000000..385a6c7488c6 --- /dev/null +++ b/net/netlabel/netlabel_user.h | |||
@@ -0,0 +1,215 @@ | |||
1 | /* | ||
2 | * NetLabel NETLINK Interface | ||
3 | * | ||
4 | * This file defines the NETLINK interface for the NetLabel system. The | ||
5 | * NetLabel system manages static and dynamic label mappings for network | ||
6 | * protocols such as CIPSO and RIPSO. | ||
7 | * | ||
8 | * Author: Paul Moore <paul.moore@hp.com> | ||
9 | * | ||
10 | */ | ||
11 | |||
12 | /* | ||
13 | * (c) Copyright Hewlett-Packard Development Company, L.P., 2006 | ||
14 | * | ||
15 | * This program is free software; you can redistribute it and/or modify | ||
16 | * it under the terms of the GNU General Public License as published by | ||
17 | * the Free Software Foundation; either version 2 of the License, or | ||
18 | * (at your option) any later version. | ||
19 | * | ||
20 | * This program is distributed in the hope that it will be useful, | ||
21 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
22 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See | ||
23 | * the GNU General Public License for more details. | ||
24 | * | ||
25 | * You should have received a copy of the GNU General Public License | ||
26 | * along with this program; if not, write to the Free Software | ||
27 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
28 | * | ||
29 | */ | ||
30 | |||
31 | #ifndef _NETLABEL_USER_H | ||
32 | #define _NETLABEL_USER_H | ||
33 | |||
34 | #include <linux/types.h> | ||
35 | #include <linux/skbuff.h> | ||
36 | #include <linux/capability.h> | ||
37 | #include <net/netlink.h> | ||
38 | #include <net/genetlink.h> | ||
39 | #include <net/netlabel.h> | ||
40 | |||
41 | /* NetLabel NETLINK helper functions */ | ||
42 | |||
43 | /** | ||
44 | * netlbl_netlink_cap_check - Check the NETLINK msg capabilities | ||
45 | * @skb: the NETLINK buffer | ||
46 | * @req_cap: the required capability | ||
47 | * | ||
48 | * Description: | ||
49 | * Check the NETLINK buffer's capabilities against the required capabilities. | ||
50 | * Returns zero on success, negative values on failure. | ||
51 | * | ||
52 | */ | ||
53 | static inline int netlbl_netlink_cap_check(const struct sk_buff *skb, | ||
54 | kernel_cap_t req_cap) | ||
55 | { | ||
56 | if (cap_raised(NETLINK_CB(skb).eff_cap, req_cap)) | ||
57 | return 0; | ||
58 | return -EPERM; | ||
59 | } | ||
60 | |||
61 | /** | ||
62 | * netlbl_getinc_u8 - Read a u8 value from a nlattr stream and move on | ||
63 | * @nla: the attribute | ||
64 | * @rem_len: remaining length | ||
65 | * | ||
66 | * Description: | ||
67 | * Return a u8 value pointed to by @nla and advance it to the next attribute. | ||
68 | * | ||
69 | */ | ||
70 | static inline u8 netlbl_getinc_u8(struct nlattr **nla, int *rem_len) | ||
71 | { | ||
72 | u8 val = nla_get_u8(*nla); | ||
73 | *nla = nla_next(*nla, rem_len); | ||
74 | return val; | ||
75 | } | ||
76 | |||
77 | /** | ||
78 | * netlbl_getinc_u16 - Read a u16 value from a nlattr stream and move on | ||
79 | * @nla: the attribute | ||
80 | * @rem_len: remaining length | ||
81 | * | ||
82 | * Description: | ||
83 | * Return a u16 value pointed to by @nla and advance it to the next attribute. | ||
84 | * | ||
85 | */ | ||
86 | static inline u16 netlbl_getinc_u16(struct nlattr **nla, int *rem_len) | ||
87 | { | ||
88 | u16 val = nla_get_u16(*nla); | ||
89 | *nla = nla_next(*nla, rem_len); | ||
90 | return val; | ||
91 | } | ||
92 | |||
93 | /** | ||
94 | * netlbl_getinc_u32 - Read a u32 value from a nlattr stream and move on | ||
95 | * @nla: the attribute | ||
96 | * @rem_len: remaining length | ||
97 | * | ||
98 | * Description: | ||
99 | * Return a u32 value pointed to by @nla and advance it to the next attribute. | ||
100 | * | ||
101 | */ | ||
102 | static inline u32 netlbl_getinc_u32(struct nlattr **nla, int *rem_len) | ||
103 | { | ||
104 | u32 val = nla_get_u32(*nla); | ||
105 | *nla = nla_next(*nla, rem_len); | ||
106 | return val; | ||
107 | } | ||
108 | |||
109 | /** | ||
110 | * netlbl_netlink_hdr_put - Write the NETLINK buffers into a sk_buff | ||
111 | * @skb: the packet | ||
112 | * @pid: the PID of the receipient | ||
113 | * @seq: the sequence number | ||
114 | * @type: the generic NETLINK message family type | ||
115 | * @cmd: command | ||
116 | * | ||
117 | * Description: | ||
118 | * Write both a NETLINK nlmsghdr structure and a Generic NETLINK genlmsghdr | ||
119 | * struct to the packet. Returns a pointer to the start of the payload buffer | ||
120 | * on success or NULL on failure. | ||
121 | * | ||
122 | */ | ||
123 | static inline void *netlbl_netlink_hdr_put(struct sk_buff *skb, | ||
124 | u32 pid, | ||
125 | u32 seq, | ||
126 | int type, | ||
127 | u8 cmd) | ||
128 | { | ||
129 | return genlmsg_put(skb, | ||
130 | pid, | ||
131 | seq, | ||
132 | type, | ||
133 | 0, | ||
134 | 0, | ||
135 | cmd, | ||
136 | NETLBL_PROTO_VERSION); | ||
137 | } | ||
138 | |||
139 | /** | ||
140 | * netlbl_netlink_hdr_push - Write the NETLINK buffers into a sk_buff | ||
141 | * @skb: the packet | ||
142 | * @pid: the PID of the receipient | ||
143 | * @seq: the sequence number | ||
144 | * @type: the generic NETLINK message family type | ||
145 | * @cmd: command | ||
146 | * | ||
147 | * Description: | ||
148 | * Write both a NETLINK nlmsghdr structure and a Generic NETLINK genlmsghdr | ||
149 | * struct to the packet. | ||
150 | * | ||
151 | */ | ||
152 | static inline void netlbl_netlink_hdr_push(struct sk_buff *skb, | ||
153 | u32 pid, | ||
154 | u32 seq, | ||
155 | int type, | ||
156 | u8 cmd) | ||
157 | |||
158 | { | ||
159 | struct nlmsghdr *nlh; | ||
160 | struct genlmsghdr *hdr; | ||
161 | |||
162 | nlh = (struct nlmsghdr *)skb_push(skb, NLMSG_SPACE(GENL_HDRLEN)); | ||
163 | nlh->nlmsg_type = type; | ||
164 | nlh->nlmsg_len = skb->len; | ||
165 | nlh->nlmsg_flags = 0; | ||
166 | nlh->nlmsg_pid = pid; | ||
167 | nlh->nlmsg_seq = seq; | ||
168 | |||
169 | hdr = nlmsg_data(nlh); | ||
170 | hdr->cmd = cmd; | ||
171 | hdr->version = NETLBL_PROTO_VERSION; | ||
172 | hdr->reserved = 0; | ||
173 | } | ||
174 | |||
175 | /** | ||
176 | * netlbl_netlink_payload_len - Return the length of the payload | ||
177 | * @skb: the NETLINK buffer | ||
178 | * | ||
179 | * Description: | ||
180 | * This function returns the length of the NetLabel payload. | ||
181 | * | ||
182 | */ | ||
183 | static inline u32 netlbl_netlink_payload_len(const struct sk_buff *skb) | ||
184 | { | ||
185 | return nlmsg_len((struct nlmsghdr *)skb->data) - GENL_HDRLEN; | ||
186 | } | ||
187 | |||
188 | /** | ||
189 | * netlbl_netlink_payload_data - Returns a pointer to the start of the payload | ||
190 | * @skb: the NETLINK buffer | ||
191 | * | ||
192 | * Description: | ||
193 | * This function returns a pointer to the start of the NetLabel payload. | ||
194 | * | ||
195 | */ | ||
196 | static inline void *netlbl_netlink_payload_data(const struct sk_buff *skb) | ||
197 | { | ||
198 | return (unsigned char *)nlmsg_data((struct nlmsghdr *)skb->data) + | ||
199 | GENL_HDRLEN; | ||
200 | } | ||
201 | |||
202 | /* NetLabel common protocol functions */ | ||
203 | |||
204 | void netlbl_netlink_send_ack(const struct genl_info *info, | ||
205 | u32 genl_family, | ||
206 | u8 ack_cmd, | ||
207 | u32 ret_code); | ||
208 | |||
209 | /* NetLabel NETLINK I/O functions */ | ||
210 | |||
211 | int netlbl_netlink_init(void); | ||
212 | int netlbl_netlink_snd(struct sk_buff *skb, u32 pid); | ||
213 | int netlbl_netlink_snd_multicast(struct sk_buff *skb, u32 pid, u32 group); | ||
214 | |||
215 | #endif | ||
diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c index 8b85036ba8e3..d56e0d21f919 100644 --- a/net/netlink/af_netlink.c +++ b/net/netlink/af_netlink.c | |||
@@ -1147,7 +1147,7 @@ static int netlink_sendmsg(struct kiocb *kiocb, struct socket *sock, | |||
1147 | if (len > sk->sk_sndbuf - 32) | 1147 | if (len > sk->sk_sndbuf - 32) |
1148 | goto out; | 1148 | goto out; |
1149 | err = -ENOBUFS; | 1149 | err = -ENOBUFS; |
1150 | skb = alloc_skb(len, GFP_KERNEL); | 1150 | skb = nlmsg_new(len, GFP_KERNEL); |
1151 | if (skb==NULL) | 1151 | if (skb==NULL) |
1152 | goto out; | 1152 | goto out; |
1153 | 1153 | ||
@@ -1341,19 +1341,18 @@ static int netlink_dump(struct sock *sk) | |||
1341 | struct netlink_callback *cb; | 1341 | struct netlink_callback *cb; |
1342 | struct sk_buff *skb; | 1342 | struct sk_buff *skb; |
1343 | struct nlmsghdr *nlh; | 1343 | struct nlmsghdr *nlh; |
1344 | int len; | 1344 | int len, err = -ENOBUFS; |
1345 | 1345 | ||
1346 | skb = sock_rmalloc(sk, NLMSG_GOODSIZE, 0, GFP_KERNEL); | 1346 | skb = sock_rmalloc(sk, NLMSG_GOODSIZE, 0, GFP_KERNEL); |
1347 | if (!skb) | 1347 | if (!skb) |
1348 | return -ENOBUFS; | 1348 | goto errout; |
1349 | 1349 | ||
1350 | spin_lock(&nlk->cb_lock); | 1350 | spin_lock(&nlk->cb_lock); |
1351 | 1351 | ||
1352 | cb = nlk->cb; | 1352 | cb = nlk->cb; |
1353 | if (cb == NULL) { | 1353 | if (cb == NULL) { |
1354 | spin_unlock(&nlk->cb_lock); | 1354 | err = -EINVAL; |
1355 | kfree_skb(skb); | 1355 | goto errout_skb; |
1356 | return -EINVAL; | ||
1357 | } | 1356 | } |
1358 | 1357 | ||
1359 | len = cb->dump(skb, cb); | 1358 | len = cb->dump(skb, cb); |
@@ -1365,8 +1364,12 @@ static int netlink_dump(struct sock *sk) | |||
1365 | return 0; | 1364 | return 0; |
1366 | } | 1365 | } |
1367 | 1366 | ||
1368 | nlh = NLMSG_NEW_ANSWER(skb, cb, NLMSG_DONE, sizeof(len), NLM_F_MULTI); | 1367 | nlh = nlmsg_put_answer(skb, cb, NLMSG_DONE, sizeof(len), NLM_F_MULTI); |
1369 | memcpy(NLMSG_DATA(nlh), &len, sizeof(len)); | 1368 | if (!nlh) |
1369 | goto errout_skb; | ||
1370 | |||
1371 | memcpy(nlmsg_data(nlh), &len, sizeof(len)); | ||
1372 | |||
1370 | skb_queue_tail(&sk->sk_receive_queue, skb); | 1373 | skb_queue_tail(&sk->sk_receive_queue, skb); |
1371 | sk->sk_data_ready(sk, skb->len); | 1374 | sk->sk_data_ready(sk, skb->len); |
1372 | 1375 | ||
@@ -1378,8 +1381,11 @@ static int netlink_dump(struct sock *sk) | |||
1378 | netlink_destroy_callback(cb); | 1381 | netlink_destroy_callback(cb); |
1379 | return 0; | 1382 | return 0; |
1380 | 1383 | ||
1381 | nlmsg_failure: | 1384 | errout_skb: |
1382 | return -ENOBUFS; | 1385 | spin_unlock(&nlk->cb_lock); |
1386 | kfree_skb(skb); | ||
1387 | errout: | ||
1388 | return err; | ||
1383 | } | 1389 | } |
1384 | 1390 | ||
1385 | int netlink_dump_start(struct sock *ssk, struct sk_buff *skb, | 1391 | int netlink_dump_start(struct sock *ssk, struct sk_buff *skb, |
@@ -1431,11 +1437,11 @@ void netlink_ack(struct sk_buff *in_skb, struct nlmsghdr *nlh, int err) | |||
1431 | int size; | 1437 | int size; |
1432 | 1438 | ||
1433 | if (err == 0) | 1439 | if (err == 0) |
1434 | size = NLMSG_SPACE(sizeof(struct nlmsgerr)); | 1440 | size = nlmsg_total_size(sizeof(*errmsg)); |
1435 | else | 1441 | else |
1436 | size = NLMSG_SPACE(4 + NLMSG_ALIGN(nlh->nlmsg_len)); | 1442 | size = nlmsg_total_size(sizeof(*errmsg) + nlmsg_len(nlh)); |
1437 | 1443 | ||
1438 | skb = alloc_skb(size, GFP_KERNEL); | 1444 | skb = nlmsg_new(size, GFP_KERNEL); |
1439 | if (!skb) { | 1445 | if (!skb) { |
1440 | struct sock *sk; | 1446 | struct sock *sk; |
1441 | 1447 | ||
@@ -1451,16 +1457,15 @@ void netlink_ack(struct sk_buff *in_skb, struct nlmsghdr *nlh, int err) | |||
1451 | 1457 | ||
1452 | rep = __nlmsg_put(skb, NETLINK_CB(in_skb).pid, nlh->nlmsg_seq, | 1458 | rep = __nlmsg_put(skb, NETLINK_CB(in_skb).pid, nlh->nlmsg_seq, |
1453 | NLMSG_ERROR, sizeof(struct nlmsgerr), 0); | 1459 | NLMSG_ERROR, sizeof(struct nlmsgerr), 0); |
1454 | errmsg = NLMSG_DATA(rep); | 1460 | errmsg = nlmsg_data(rep); |
1455 | errmsg->error = err; | 1461 | errmsg->error = err; |
1456 | memcpy(&errmsg->msg, nlh, err ? nlh->nlmsg_len : sizeof(struct nlmsghdr)); | 1462 | memcpy(&errmsg->msg, nlh, err ? nlh->nlmsg_len : sizeof(*nlh)); |
1457 | netlink_unicast(in_skb->sk, skb, NETLINK_CB(in_skb).pid, MSG_DONTWAIT); | 1463 | netlink_unicast(in_skb->sk, skb, NETLINK_CB(in_skb).pid, MSG_DONTWAIT); |
1458 | } | 1464 | } |
1459 | 1465 | ||
1460 | static int netlink_rcv_skb(struct sk_buff *skb, int (*cb)(struct sk_buff *, | 1466 | static int netlink_rcv_skb(struct sk_buff *skb, int (*cb)(struct sk_buff *, |
1461 | struct nlmsghdr *, int *)) | 1467 | struct nlmsghdr *, int *)) |
1462 | { | 1468 | { |
1463 | unsigned int total_len; | ||
1464 | struct nlmsghdr *nlh; | 1469 | struct nlmsghdr *nlh; |
1465 | int err; | 1470 | int err; |
1466 | 1471 | ||
@@ -1470,8 +1475,6 @@ static int netlink_rcv_skb(struct sk_buff *skb, int (*cb)(struct sk_buff *, | |||
1470 | if (nlh->nlmsg_len < NLMSG_HDRLEN || skb->len < nlh->nlmsg_len) | 1475 | if (nlh->nlmsg_len < NLMSG_HDRLEN || skb->len < nlh->nlmsg_len) |
1471 | return 0; | 1476 | return 0; |
1472 | 1477 | ||
1473 | total_len = min(NLMSG_ALIGN(nlh->nlmsg_len), skb->len); | ||
1474 | |||
1475 | if (cb(skb, nlh, &err) < 0) { | 1478 | if (cb(skb, nlh, &err) < 0) { |
1476 | /* Not an error, but we have to interrupt processing | 1479 | /* Not an error, but we have to interrupt processing |
1477 | * here. Note: that in this case we do not pull | 1480 | * here. Note: that in this case we do not pull |
@@ -1483,7 +1486,7 @@ static int netlink_rcv_skb(struct sk_buff *skb, int (*cb)(struct sk_buff *, | |||
1483 | } else if (nlh->nlmsg_flags & NLM_F_ACK) | 1486 | } else if (nlh->nlmsg_flags & NLM_F_ACK) |
1484 | netlink_ack(skb, nlh, 0); | 1487 | netlink_ack(skb, nlh, 0); |
1485 | 1488 | ||
1486 | skb_pull(skb, total_len); | 1489 | netlink_queue_skip(nlh, skb); |
1487 | } | 1490 | } |
1488 | 1491 | ||
1489 | return 0; | 1492 | return 0; |
@@ -1546,6 +1549,38 @@ void netlink_queue_skip(struct nlmsghdr *nlh, struct sk_buff *skb) | |||
1546 | skb_pull(skb, msglen); | 1549 | skb_pull(skb, msglen); |
1547 | } | 1550 | } |
1548 | 1551 | ||
1552 | /** | ||
1553 | * nlmsg_notify - send a notification netlink message | ||
1554 | * @sk: netlink socket to use | ||
1555 | * @skb: notification message | ||
1556 | * @pid: destination netlink pid for reports or 0 | ||
1557 | * @group: destination multicast group or 0 | ||
1558 | * @report: 1 to report back, 0 to disable | ||
1559 | * @flags: allocation flags | ||
1560 | */ | ||
1561 | int nlmsg_notify(struct sock *sk, struct sk_buff *skb, u32 pid, | ||
1562 | unsigned int group, int report, gfp_t flags) | ||
1563 | { | ||
1564 | int err = 0; | ||
1565 | |||
1566 | if (group) { | ||
1567 | int exclude_pid = 0; | ||
1568 | |||
1569 | if (report) { | ||
1570 | atomic_inc(&skb->users); | ||
1571 | exclude_pid = pid; | ||
1572 | } | ||
1573 | |||
1574 | /* errors reported via destination sk->sk_err */ | ||
1575 | nlmsg_multicast(sk, skb, exclude_pid, group, flags); | ||
1576 | } | ||
1577 | |||
1578 | if (report) | ||
1579 | err = nlmsg_unicast(sk, skb, pid); | ||
1580 | |||
1581 | return err; | ||
1582 | } | ||
1583 | |||
1549 | #ifdef CONFIG_PROC_FS | 1584 | #ifdef CONFIG_PROC_FS |
1550 | struct nl_seq_iter { | 1585 | struct nl_seq_iter { |
1551 | int link; | 1586 | int link; |
@@ -1727,8 +1762,6 @@ static struct net_proto_family netlink_family_ops = { | |||
1727 | .owner = THIS_MODULE, /* for consistency 8) */ | 1762 | .owner = THIS_MODULE, /* for consistency 8) */ |
1728 | }; | 1763 | }; |
1729 | 1764 | ||
1730 | extern void netlink_skb_parms_too_large(void); | ||
1731 | |||
1732 | static int __init netlink_proto_init(void) | 1765 | static int __init netlink_proto_init(void) |
1733 | { | 1766 | { |
1734 | struct sk_buff *dummy_skb; | 1767 | struct sk_buff *dummy_skb; |
@@ -1740,8 +1773,7 @@ static int __init netlink_proto_init(void) | |||
1740 | if (err != 0) | 1773 | if (err != 0) |
1741 | goto out; | 1774 | goto out; |
1742 | 1775 | ||
1743 | if (sizeof(struct netlink_skb_parms) > sizeof(dummy_skb->cb)) | 1776 | BUILD_BUG_ON(sizeof(struct netlink_skb_parms) > sizeof(dummy_skb->cb)); |
1744 | netlink_skb_parms_too_large(); | ||
1745 | 1777 | ||
1746 | nl_table = kcalloc(MAX_LINKS, sizeof(*nl_table), GFP_KERNEL); | 1778 | nl_table = kcalloc(MAX_LINKS, sizeof(*nl_table), GFP_KERNEL); |
1747 | if (!nl_table) | 1779 | if (!nl_table) |
@@ -1799,4 +1831,4 @@ EXPORT_SYMBOL(netlink_set_err); | |||
1799 | EXPORT_SYMBOL(netlink_set_nonroot); | 1831 | EXPORT_SYMBOL(netlink_set_nonroot); |
1800 | EXPORT_SYMBOL(netlink_unicast); | 1832 | EXPORT_SYMBOL(netlink_unicast); |
1801 | EXPORT_SYMBOL(netlink_unregister_notifier); | 1833 | EXPORT_SYMBOL(netlink_unregister_notifier); |
1802 | 1834 | EXPORT_SYMBOL(nlmsg_notify); | |
diff --git a/net/netlink/attr.c b/net/netlink/attr.c index dddbd15135a8..004139557e09 100644 --- a/net/netlink/attr.c +++ b/net/netlink/attr.c | |||
@@ -20,7 +20,6 @@ static u16 nla_attr_minlen[NLA_TYPE_MAX+1] __read_mostly = { | |||
20 | [NLA_U16] = sizeof(u16), | 20 | [NLA_U16] = sizeof(u16), |
21 | [NLA_U32] = sizeof(u32), | 21 | [NLA_U32] = sizeof(u32), |
22 | [NLA_U64] = sizeof(u64), | 22 | [NLA_U64] = sizeof(u64), |
23 | [NLA_STRING] = 1, | ||
24 | [NLA_NESTED] = NLA_HDRLEN, | 23 | [NLA_NESTED] = NLA_HDRLEN, |
25 | }; | 24 | }; |
26 | 25 | ||
@@ -28,7 +27,7 @@ static int validate_nla(struct nlattr *nla, int maxtype, | |||
28 | struct nla_policy *policy) | 27 | struct nla_policy *policy) |
29 | { | 28 | { |
30 | struct nla_policy *pt; | 29 | struct nla_policy *pt; |
31 | int minlen = 0; | 30 | int minlen = 0, attrlen = nla_len(nla); |
32 | 31 | ||
33 | if (nla->nla_type <= 0 || nla->nla_type > maxtype) | 32 | if (nla->nla_type <= 0 || nla->nla_type > maxtype) |
34 | return 0; | 33 | return 0; |
@@ -37,16 +36,46 @@ static int validate_nla(struct nlattr *nla, int maxtype, | |||
37 | 36 | ||
38 | BUG_ON(pt->type > NLA_TYPE_MAX); | 37 | BUG_ON(pt->type > NLA_TYPE_MAX); |
39 | 38 | ||
40 | if (pt->minlen) | 39 | switch (pt->type) { |
41 | minlen = pt->minlen; | 40 | case NLA_FLAG: |
42 | else if (pt->type != NLA_UNSPEC) | 41 | if (attrlen > 0) |
43 | minlen = nla_attr_minlen[pt->type]; | 42 | return -ERANGE; |
43 | break; | ||
44 | 44 | ||
45 | if (pt->type == NLA_FLAG && nla_len(nla) > 0) | 45 | case NLA_NUL_STRING: |
46 | return -ERANGE; | 46 | if (pt->len) |
47 | minlen = min_t(int, attrlen, pt->len + 1); | ||
48 | else | ||
49 | minlen = attrlen; | ||
47 | 50 | ||
48 | if (nla_len(nla) < minlen) | 51 | if (!minlen || memchr(nla_data(nla), '\0', minlen) == NULL) |
49 | return -ERANGE; | 52 | return -EINVAL; |
53 | /* fall through */ | ||
54 | |||
55 | case NLA_STRING: | ||
56 | if (attrlen < 1) | ||
57 | return -ERANGE; | ||
58 | |||
59 | if (pt->len) { | ||
60 | char *buf = nla_data(nla); | ||
61 | |||
62 | if (buf[attrlen - 1] == '\0') | ||
63 | attrlen--; | ||
64 | |||
65 | if (attrlen > pt->len) | ||
66 | return -ERANGE; | ||
67 | } | ||
68 | break; | ||
69 | |||
70 | default: | ||
71 | if (pt->len) | ||
72 | minlen = pt->len; | ||
73 | else if (pt->type != NLA_UNSPEC) | ||
74 | minlen = nla_attr_minlen[pt->type]; | ||
75 | |||
76 | if (attrlen < minlen) | ||
77 | return -ERANGE; | ||
78 | } | ||
50 | 79 | ||
51 | return 0; | 80 | return 0; |
52 | } | 81 | } |
@@ -255,6 +284,26 @@ struct nlattr *__nla_reserve(struct sk_buff *skb, int attrtype, int attrlen) | |||
255 | } | 284 | } |
256 | 285 | ||
257 | /** | 286 | /** |
287 | * __nla_reserve_nohdr - reserve room for attribute without header | ||
288 | * @skb: socket buffer to reserve room on | ||
289 | * @attrlen: length of attribute payload | ||
290 | * | ||
291 | * Reserves room for attribute payload without a header. | ||
292 | * | ||
293 | * The caller is responsible to ensure that the skb provides enough | ||
294 | * tailroom for the payload. | ||
295 | */ | ||
296 | void *__nla_reserve_nohdr(struct sk_buff *skb, int attrlen) | ||
297 | { | ||
298 | void *start; | ||
299 | |||
300 | start = skb_put(skb, NLA_ALIGN(attrlen)); | ||
301 | memset(start, 0, NLA_ALIGN(attrlen)); | ||
302 | |||
303 | return start; | ||
304 | } | ||
305 | |||
306 | /** | ||
258 | * nla_reserve - reserve room for attribute on the skb | 307 | * nla_reserve - reserve room for attribute on the skb |
259 | * @skb: socket buffer to reserve room on | 308 | * @skb: socket buffer to reserve room on |
260 | * @attrtype: attribute type | 309 | * @attrtype: attribute type |
@@ -275,6 +324,24 @@ struct nlattr *nla_reserve(struct sk_buff *skb, int attrtype, int attrlen) | |||
275 | } | 324 | } |
276 | 325 | ||
277 | /** | 326 | /** |
327 | * nla_reserve - reserve room for attribute without header | ||
328 | * @skb: socket buffer to reserve room on | ||
329 | * @len: length of attribute payload | ||
330 | * | ||
331 | * Reserves room for attribute payload without a header. | ||
332 | * | ||
333 | * Returns NULL if the tailroom of the skb is insufficient to store | ||
334 | * the attribute payload. | ||
335 | */ | ||
336 | void *nla_reserve_nohdr(struct sk_buff *skb, int attrlen) | ||
337 | { | ||
338 | if (unlikely(skb_tailroom(skb) < NLA_ALIGN(attrlen))) | ||
339 | return NULL; | ||
340 | |||
341 | return __nla_reserve_nohdr(skb, attrlen); | ||
342 | } | ||
343 | |||
344 | /** | ||
278 | * __nla_put - Add a netlink attribute to a socket buffer | 345 | * __nla_put - Add a netlink attribute to a socket buffer |
279 | * @skb: socket buffer to add attribute to | 346 | * @skb: socket buffer to add attribute to |
280 | * @attrtype: attribute type | 347 | * @attrtype: attribute type |
@@ -293,6 +360,22 @@ void __nla_put(struct sk_buff *skb, int attrtype, int attrlen, | |||
293 | memcpy(nla_data(nla), data, attrlen); | 360 | memcpy(nla_data(nla), data, attrlen); |
294 | } | 361 | } |
295 | 362 | ||
363 | /** | ||
364 | * __nla_put_nohdr - Add a netlink attribute without header | ||
365 | * @skb: socket buffer to add attribute to | ||
366 | * @attrlen: length of attribute payload | ||
367 | * @data: head of attribute payload | ||
368 | * | ||
369 | * The caller is responsible to ensure that the skb provides enough | ||
370 | * tailroom for the attribute payload. | ||
371 | */ | ||
372 | void __nla_put_nohdr(struct sk_buff *skb, int attrlen, const void *data) | ||
373 | { | ||
374 | void *start; | ||
375 | |||
376 | start = __nla_reserve_nohdr(skb, attrlen); | ||
377 | memcpy(start, data, attrlen); | ||
378 | } | ||
296 | 379 | ||
297 | /** | 380 | /** |
298 | * nla_put - Add a netlink attribute to a socket buffer | 381 | * nla_put - Add a netlink attribute to a socket buffer |
@@ -313,15 +396,36 @@ int nla_put(struct sk_buff *skb, int attrtype, int attrlen, const void *data) | |||
313 | return 0; | 396 | return 0; |
314 | } | 397 | } |
315 | 398 | ||
399 | /** | ||
400 | * nla_put_nohdr - Add a netlink attribute without header | ||
401 | * @skb: socket buffer to add attribute to | ||
402 | * @attrlen: length of attribute payload | ||
403 | * @data: head of attribute payload | ||
404 | * | ||
405 | * Returns -1 if the tailroom of the skb is insufficient to store | ||
406 | * the attribute payload. | ||
407 | */ | ||
408 | int nla_put_nohdr(struct sk_buff *skb, int attrlen, const void *data) | ||
409 | { | ||
410 | if (unlikely(skb_tailroom(skb) < NLA_ALIGN(attrlen))) | ||
411 | return -1; | ||
412 | |||
413 | __nla_put_nohdr(skb, attrlen, data); | ||
414 | return 0; | ||
415 | } | ||
316 | 416 | ||
317 | EXPORT_SYMBOL(nla_validate); | 417 | EXPORT_SYMBOL(nla_validate); |
318 | EXPORT_SYMBOL(nla_parse); | 418 | EXPORT_SYMBOL(nla_parse); |
319 | EXPORT_SYMBOL(nla_find); | 419 | EXPORT_SYMBOL(nla_find); |
320 | EXPORT_SYMBOL(nla_strlcpy); | 420 | EXPORT_SYMBOL(nla_strlcpy); |
321 | EXPORT_SYMBOL(__nla_reserve); | 421 | EXPORT_SYMBOL(__nla_reserve); |
422 | EXPORT_SYMBOL(__nla_reserve_nohdr); | ||
322 | EXPORT_SYMBOL(nla_reserve); | 423 | EXPORT_SYMBOL(nla_reserve); |
424 | EXPORT_SYMBOL(nla_reserve_nohdr); | ||
323 | EXPORT_SYMBOL(__nla_put); | 425 | EXPORT_SYMBOL(__nla_put); |
426 | EXPORT_SYMBOL(__nla_put_nohdr); | ||
324 | EXPORT_SYMBOL(nla_put); | 427 | EXPORT_SYMBOL(nla_put); |
428 | EXPORT_SYMBOL(nla_put_nohdr); | ||
325 | EXPORT_SYMBOL(nla_memcpy); | 429 | EXPORT_SYMBOL(nla_memcpy); |
326 | EXPORT_SYMBOL(nla_memcmp); | 430 | EXPORT_SYMBOL(nla_memcmp); |
327 | EXPORT_SYMBOL(nla_strcmp); | 431 | EXPORT_SYMBOL(nla_strcmp); |
diff --git a/net/netlink/genetlink.c b/net/netlink/genetlink.c index a298f77cc3e3..49bc2db7982b 100644 --- a/net/netlink/genetlink.c +++ b/net/netlink/genetlink.c | |||
@@ -387,7 +387,10 @@ static void genl_rcv(struct sock *sk, int len) | |||
387 | static int ctrl_fill_info(struct genl_family *family, u32 pid, u32 seq, | 387 | static int ctrl_fill_info(struct genl_family *family, u32 pid, u32 seq, |
388 | u32 flags, struct sk_buff *skb, u8 cmd) | 388 | u32 flags, struct sk_buff *skb, u8 cmd) |
389 | { | 389 | { |
390 | struct nlattr *nla_ops; | ||
391 | struct genl_ops *ops; | ||
390 | void *hdr; | 392 | void *hdr; |
393 | int idx = 1; | ||
391 | 394 | ||
392 | hdr = genlmsg_put(skb, pid, seq, GENL_ID_CTRL, 0, flags, cmd, | 395 | hdr = genlmsg_put(skb, pid, seq, GENL_ID_CTRL, 0, flags, cmd, |
393 | family->version); | 396 | family->version); |
@@ -396,6 +399,37 @@ static int ctrl_fill_info(struct genl_family *family, u32 pid, u32 seq, | |||
396 | 399 | ||
397 | NLA_PUT_STRING(skb, CTRL_ATTR_FAMILY_NAME, family->name); | 400 | NLA_PUT_STRING(skb, CTRL_ATTR_FAMILY_NAME, family->name); |
398 | NLA_PUT_U16(skb, CTRL_ATTR_FAMILY_ID, family->id); | 401 | NLA_PUT_U16(skb, CTRL_ATTR_FAMILY_ID, family->id); |
402 | NLA_PUT_U32(skb, CTRL_ATTR_VERSION, family->version); | ||
403 | NLA_PUT_U32(skb, CTRL_ATTR_HDRSIZE, family->hdrsize); | ||
404 | NLA_PUT_U32(skb, CTRL_ATTR_MAXATTR, family->maxattr); | ||
405 | |||
406 | nla_ops = nla_nest_start(skb, CTRL_ATTR_OPS); | ||
407 | if (nla_ops == NULL) | ||
408 | goto nla_put_failure; | ||
409 | |||
410 | list_for_each_entry(ops, &family->ops_list, ops_list) { | ||
411 | struct nlattr *nest; | ||
412 | |||
413 | nest = nla_nest_start(skb, idx++); | ||
414 | if (nest == NULL) | ||
415 | goto nla_put_failure; | ||
416 | |||
417 | NLA_PUT_U32(skb, CTRL_ATTR_OP_ID, ops->cmd); | ||
418 | NLA_PUT_U32(skb, CTRL_ATTR_OP_FLAGS, ops->flags); | ||
419 | |||
420 | if (ops->policy) | ||
421 | NLA_PUT_FLAG(skb, CTRL_ATTR_OP_POLICY); | ||
422 | |||
423 | if (ops->doit) | ||
424 | NLA_PUT_FLAG(skb, CTRL_ATTR_OP_DOIT); | ||
425 | |||
426 | if (ops->dumpit) | ||
427 | NLA_PUT_FLAG(skb, CTRL_ATTR_OP_DUMPIT); | ||
428 | |||
429 | nla_nest_end(skb, nest); | ||
430 | } | ||
431 | |||
432 | nla_nest_end(skb, nla_ops); | ||
399 | 433 | ||
400 | return genlmsg_end(skb, hdr); | 434 | return genlmsg_end(skb, hdr); |
401 | 435 | ||
@@ -411,6 +445,9 @@ static int ctrl_dumpfamily(struct sk_buff *skb, struct netlink_callback *cb) | |||
411 | int chains_to_skip = cb->args[0]; | 445 | int chains_to_skip = cb->args[0]; |
412 | int fams_to_skip = cb->args[1]; | 446 | int fams_to_skip = cb->args[1]; |
413 | 447 | ||
448 | if (chains_to_skip != 0) | ||
449 | genl_lock(); | ||
450 | |||
414 | for (i = 0; i < GENL_FAM_TAB_SIZE; i++) { | 451 | for (i = 0; i < GENL_FAM_TAB_SIZE; i++) { |
415 | if (i < chains_to_skip) | 452 | if (i < chains_to_skip) |
416 | continue; | 453 | continue; |
@@ -428,6 +465,9 @@ static int ctrl_dumpfamily(struct sk_buff *skb, struct netlink_callback *cb) | |||
428 | } | 465 | } |
429 | 466 | ||
430 | errout: | 467 | errout: |
468 | if (chains_to_skip != 0) | ||
469 | genl_unlock(); | ||
470 | |||
431 | cb->args[0] = i; | 471 | cb->args[0] = i; |
432 | cb->args[1] = n; | 472 | cb->args[1] = n; |
433 | 473 | ||
@@ -440,7 +480,7 @@ static struct sk_buff *ctrl_build_msg(struct genl_family *family, u32 pid, | |||
440 | struct sk_buff *skb; | 480 | struct sk_buff *skb; |
441 | int err; | 481 | int err; |
442 | 482 | ||
443 | skb = nlmsg_new(NLMSG_GOODSIZE); | 483 | skb = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); |
444 | if (skb == NULL) | 484 | if (skb == NULL) |
445 | return ERR_PTR(-ENOBUFS); | 485 | return ERR_PTR(-ENOBUFS); |
446 | 486 | ||
@@ -455,7 +495,8 @@ static struct sk_buff *ctrl_build_msg(struct genl_family *family, u32 pid, | |||
455 | 495 | ||
456 | static struct nla_policy ctrl_policy[CTRL_ATTR_MAX+1] __read_mostly = { | 496 | static struct nla_policy ctrl_policy[CTRL_ATTR_MAX+1] __read_mostly = { |
457 | [CTRL_ATTR_FAMILY_ID] = { .type = NLA_U16 }, | 497 | [CTRL_ATTR_FAMILY_ID] = { .type = NLA_U16 }, |
458 | [CTRL_ATTR_FAMILY_NAME] = { .type = NLA_STRING }, | 498 | [CTRL_ATTR_FAMILY_NAME] = { .type = NLA_NUL_STRING, |
499 | .len = GENL_NAMSIZ - 1 }, | ||
459 | }; | 500 | }; |
460 | 501 | ||
461 | static int ctrl_getfamily(struct sk_buff *skb, struct genl_info *info) | 502 | static int ctrl_getfamily(struct sk_buff *skb, struct genl_info *info) |
@@ -470,12 +511,9 @@ static int ctrl_getfamily(struct sk_buff *skb, struct genl_info *info) | |||
470 | } | 511 | } |
471 | 512 | ||
472 | if (info->attrs[CTRL_ATTR_FAMILY_NAME]) { | 513 | if (info->attrs[CTRL_ATTR_FAMILY_NAME]) { |
473 | char name[GENL_NAMSIZ]; | 514 | char *name; |
474 | |||
475 | if (nla_strlcpy(name, info->attrs[CTRL_ATTR_FAMILY_NAME], | ||
476 | GENL_NAMSIZ) >= GENL_NAMSIZ) | ||
477 | goto errout; | ||
478 | 515 | ||
516 | name = nla_data(info->attrs[CTRL_ATTR_FAMILY_NAME]); | ||
479 | res = genl_family_find_byname(name); | 517 | res = genl_family_find_byname(name); |
480 | } | 518 | } |
481 | 519 | ||
@@ -510,7 +548,7 @@ static int genl_ctrl_event(int event, void *data) | |||
510 | if (IS_ERR(msg)) | 548 | if (IS_ERR(msg)) |
511 | return PTR_ERR(msg); | 549 | return PTR_ERR(msg); |
512 | 550 | ||
513 | genlmsg_multicast(msg, 0, GENL_ID_CTRL); | 551 | genlmsg_multicast(msg, 0, GENL_ID_CTRL, GFP_KERNEL); |
514 | break; | 552 | break; |
515 | } | 553 | } |
516 | 554 | ||
diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c index 4172a5235916..f4ccb90e6739 100644 --- a/net/packet/af_packet.c +++ b/net/packet/af_packet.c | |||
@@ -427,21 +427,24 @@ out_unlock: | |||
427 | } | 427 | } |
428 | #endif | 428 | #endif |
429 | 429 | ||
430 | static inline unsigned run_filter(struct sk_buff *skb, struct sock *sk, unsigned res) | 430 | static inline int run_filter(struct sk_buff *skb, struct sock *sk, |
431 | unsigned *snaplen) | ||
431 | { | 432 | { |
432 | struct sk_filter *filter; | 433 | struct sk_filter *filter; |
434 | int err = 0; | ||
433 | 435 | ||
434 | bh_lock_sock(sk); | 436 | rcu_read_lock_bh(); |
435 | filter = sk->sk_filter; | 437 | filter = rcu_dereference(sk->sk_filter); |
436 | /* | 438 | if (filter != NULL) { |
437 | * Our caller already checked that filter != NULL but we need to | 439 | err = sk_run_filter(skb, filter->insns, filter->len); |
438 | * verify that under bh_lock_sock() to be safe | 440 | if (!err) |
439 | */ | 441 | err = -EPERM; |
440 | if (likely(filter != NULL)) | 442 | else if (*snaplen > err) |
441 | res = sk_run_filter(skb, filter->insns, filter->len); | 443 | *snaplen = err; |
442 | bh_unlock_sock(sk); | 444 | } |
445 | rcu_read_unlock_bh(); | ||
443 | 446 | ||
444 | return res; | 447 | return err; |
445 | } | 448 | } |
446 | 449 | ||
447 | /* | 450 | /* |
@@ -491,13 +494,8 @@ static int packet_rcv(struct sk_buff *skb, struct net_device *dev, struct packet | |||
491 | 494 | ||
492 | snaplen = skb->len; | 495 | snaplen = skb->len; |
493 | 496 | ||
494 | if (sk->sk_filter) { | 497 | if (run_filter(skb, sk, &snaplen) < 0) |
495 | unsigned res = run_filter(skb, sk, snaplen); | 498 | goto drop_n_restore; |
496 | if (res == 0) | ||
497 | goto drop_n_restore; | ||
498 | if (snaplen > res) | ||
499 | snaplen = res; | ||
500 | } | ||
501 | 499 | ||
502 | if (atomic_read(&sk->sk_rmem_alloc) + skb->truesize >= | 500 | if (atomic_read(&sk->sk_rmem_alloc) + skb->truesize >= |
503 | (unsigned)sk->sk_rcvbuf) | 501 | (unsigned)sk->sk_rcvbuf) |
@@ -586,20 +584,15 @@ static int tpacket_rcv(struct sk_buff *skb, struct net_device *dev, struct packe | |||
586 | else if (skb->pkt_type == PACKET_OUTGOING) { | 584 | else if (skb->pkt_type == PACKET_OUTGOING) { |
587 | /* Special case: outgoing packets have ll header at head */ | 585 | /* Special case: outgoing packets have ll header at head */ |
588 | skb_pull(skb, skb->nh.raw - skb->data); | 586 | skb_pull(skb, skb->nh.raw - skb->data); |
589 | if (skb->ip_summed == CHECKSUM_HW) | 587 | if (skb->ip_summed == CHECKSUM_PARTIAL) |
590 | status |= TP_STATUS_CSUMNOTREADY; | 588 | status |= TP_STATUS_CSUMNOTREADY; |
591 | } | 589 | } |
592 | } | 590 | } |
593 | 591 | ||
594 | snaplen = skb->len; | 592 | snaplen = skb->len; |
595 | 593 | ||
596 | if (sk->sk_filter) { | 594 | if (run_filter(skb, sk, &snaplen) < 0) |
597 | unsigned res = run_filter(skb, sk, snaplen); | 595 | goto drop_n_restore; |
598 | if (res == 0) | ||
599 | goto drop_n_restore; | ||
600 | if (snaplen > res) | ||
601 | snaplen = res; | ||
602 | } | ||
603 | 596 | ||
604 | if (sk->sk_type == SOCK_DGRAM) { | 597 | if (sk->sk_type == SOCK_DGRAM) { |
605 | macoff = netoff = TPACKET_ALIGN(TPACKET_HDRLEN) + 16; | 598 | macoff = netoff = TPACKET_ALIGN(TPACKET_HDRLEN) + 16; |
diff --git a/net/sched/act_api.c b/net/sched/act_api.c index a2587b52e531..835070e9169c 100644 --- a/net/sched/act_api.c +++ b/net/sched/act_api.c | |||
@@ -33,16 +33,230 @@ | |||
33 | #include <net/sch_generic.h> | 33 | #include <net/sch_generic.h> |
34 | #include <net/act_api.h> | 34 | #include <net/act_api.h> |
35 | 35 | ||
36 | #if 0 /* control */ | 36 | void tcf_hash_destroy(struct tcf_common *p, struct tcf_hashinfo *hinfo) |
37 | #define DPRINTK(format, args...) printk(KERN_DEBUG format, ##args) | 37 | { |
38 | #else | 38 | unsigned int h = tcf_hash(p->tcfc_index, hinfo->hmask); |
39 | #define DPRINTK(format, args...) | 39 | struct tcf_common **p1p; |
40 | |||
41 | for (p1p = &hinfo->htab[h]; *p1p; p1p = &(*p1p)->tcfc_next) { | ||
42 | if (*p1p == p) { | ||
43 | write_lock_bh(hinfo->lock); | ||
44 | *p1p = p->tcfc_next; | ||
45 | write_unlock_bh(hinfo->lock); | ||
46 | #ifdef CONFIG_NET_ESTIMATOR | ||
47 | gen_kill_estimator(&p->tcfc_bstats, | ||
48 | &p->tcfc_rate_est); | ||
40 | #endif | 49 | #endif |
41 | #if 0 /* data */ | 50 | kfree(p); |
42 | #define D2PRINTK(format, args...) printk(KERN_DEBUG format, ##args) | 51 | return; |
43 | #else | 52 | } |
44 | #define D2PRINTK(format, args...) | 53 | } |
54 | BUG_TRAP(0); | ||
55 | } | ||
56 | EXPORT_SYMBOL(tcf_hash_destroy); | ||
57 | |||
58 | int tcf_hash_release(struct tcf_common *p, int bind, | ||
59 | struct tcf_hashinfo *hinfo) | ||
60 | { | ||
61 | int ret = 0; | ||
62 | |||
63 | if (p) { | ||
64 | if (bind) | ||
65 | p->tcfc_bindcnt--; | ||
66 | |||
67 | p->tcfc_refcnt--; | ||
68 | if (p->tcfc_bindcnt <= 0 && p->tcfc_refcnt <= 0) { | ||
69 | tcf_hash_destroy(p, hinfo); | ||
70 | ret = 1; | ||
71 | } | ||
72 | } | ||
73 | return ret; | ||
74 | } | ||
75 | EXPORT_SYMBOL(tcf_hash_release); | ||
76 | |||
77 | static int tcf_dump_walker(struct sk_buff *skb, struct netlink_callback *cb, | ||
78 | struct tc_action *a, struct tcf_hashinfo *hinfo) | ||
79 | { | ||
80 | struct tcf_common *p; | ||
81 | int err = 0, index = -1,i = 0, s_i = 0, n_i = 0; | ||
82 | struct rtattr *r ; | ||
83 | |||
84 | read_lock(hinfo->lock); | ||
85 | |||
86 | s_i = cb->args[0]; | ||
87 | |||
88 | for (i = 0; i < (hinfo->hmask + 1); i++) { | ||
89 | p = hinfo->htab[tcf_hash(i, hinfo->hmask)]; | ||
90 | |||
91 | for (; p; p = p->tcfc_next) { | ||
92 | index++; | ||
93 | if (index < s_i) | ||
94 | continue; | ||
95 | a->priv = p; | ||
96 | a->order = n_i; | ||
97 | r = (struct rtattr*) skb->tail; | ||
98 | RTA_PUT(skb, a->order, 0, NULL); | ||
99 | err = tcf_action_dump_1(skb, a, 0, 0); | ||
100 | if (err < 0) { | ||
101 | index--; | ||
102 | skb_trim(skb, (u8*)r - skb->data); | ||
103 | goto done; | ||
104 | } | ||
105 | r->rta_len = skb->tail - (u8*)r; | ||
106 | n_i++; | ||
107 | if (n_i >= TCA_ACT_MAX_PRIO) | ||
108 | goto done; | ||
109 | } | ||
110 | } | ||
111 | done: | ||
112 | read_unlock(hinfo->lock); | ||
113 | if (n_i) | ||
114 | cb->args[0] += n_i; | ||
115 | return n_i; | ||
116 | |||
117 | rtattr_failure: | ||
118 | skb_trim(skb, (u8*)r - skb->data); | ||
119 | goto done; | ||
120 | } | ||
121 | |||
122 | static int tcf_del_walker(struct sk_buff *skb, struct tc_action *a, | ||
123 | struct tcf_hashinfo *hinfo) | ||
124 | { | ||
125 | struct tcf_common *p, *s_p; | ||
126 | struct rtattr *r ; | ||
127 | int i= 0, n_i = 0; | ||
128 | |||
129 | r = (struct rtattr*) skb->tail; | ||
130 | RTA_PUT(skb, a->order, 0, NULL); | ||
131 | RTA_PUT(skb, TCA_KIND, IFNAMSIZ, a->ops->kind); | ||
132 | for (i = 0; i < (hinfo->hmask + 1); i++) { | ||
133 | p = hinfo->htab[tcf_hash(i, hinfo->hmask)]; | ||
134 | |||
135 | while (p != NULL) { | ||
136 | s_p = p->tcfc_next; | ||
137 | if (ACT_P_DELETED == tcf_hash_release(p, 0, hinfo)) | ||
138 | module_put(a->ops->owner); | ||
139 | n_i++; | ||
140 | p = s_p; | ||
141 | } | ||
142 | } | ||
143 | RTA_PUT(skb, TCA_FCNT, 4, &n_i); | ||
144 | r->rta_len = skb->tail - (u8*)r; | ||
145 | |||
146 | return n_i; | ||
147 | rtattr_failure: | ||
148 | skb_trim(skb, (u8*)r - skb->data); | ||
149 | return -EINVAL; | ||
150 | } | ||
151 | |||
152 | int tcf_generic_walker(struct sk_buff *skb, struct netlink_callback *cb, | ||
153 | int type, struct tc_action *a) | ||
154 | { | ||
155 | struct tcf_hashinfo *hinfo = a->ops->hinfo; | ||
156 | |||
157 | if (type == RTM_DELACTION) { | ||
158 | return tcf_del_walker(skb, a, hinfo); | ||
159 | } else if (type == RTM_GETACTION) { | ||
160 | return tcf_dump_walker(skb, cb, a, hinfo); | ||
161 | } else { | ||
162 | printk("tcf_generic_walker: unknown action %d\n", type); | ||
163 | return -EINVAL; | ||
164 | } | ||
165 | } | ||
166 | EXPORT_SYMBOL(tcf_generic_walker); | ||
167 | |||
168 | struct tcf_common *tcf_hash_lookup(u32 index, struct tcf_hashinfo *hinfo) | ||
169 | { | ||
170 | struct tcf_common *p; | ||
171 | |||
172 | read_lock(hinfo->lock); | ||
173 | for (p = hinfo->htab[tcf_hash(index, hinfo->hmask)]; p; | ||
174 | p = p->tcfc_next) { | ||
175 | if (p->tcfc_index == index) | ||
176 | break; | ||
177 | } | ||
178 | read_unlock(hinfo->lock); | ||
179 | |||
180 | return p; | ||
181 | } | ||
182 | EXPORT_SYMBOL(tcf_hash_lookup); | ||
183 | |||
184 | u32 tcf_hash_new_index(u32 *idx_gen, struct tcf_hashinfo *hinfo) | ||
185 | { | ||
186 | u32 val = *idx_gen; | ||
187 | |||
188 | do { | ||
189 | if (++val == 0) | ||
190 | val = 1; | ||
191 | } while (tcf_hash_lookup(val, hinfo)); | ||
192 | |||
193 | return (*idx_gen = val); | ||
194 | } | ||
195 | EXPORT_SYMBOL(tcf_hash_new_index); | ||
196 | |||
197 | int tcf_hash_search(struct tc_action *a, u32 index) | ||
198 | { | ||
199 | struct tcf_hashinfo *hinfo = a->ops->hinfo; | ||
200 | struct tcf_common *p = tcf_hash_lookup(index, hinfo); | ||
201 | |||
202 | if (p) { | ||
203 | a->priv = p; | ||
204 | return 1; | ||
205 | } | ||
206 | return 0; | ||
207 | } | ||
208 | EXPORT_SYMBOL(tcf_hash_search); | ||
209 | |||
210 | struct tcf_common *tcf_hash_check(u32 index, struct tc_action *a, int bind, | ||
211 | struct tcf_hashinfo *hinfo) | ||
212 | { | ||
213 | struct tcf_common *p = NULL; | ||
214 | if (index && (p = tcf_hash_lookup(index, hinfo)) != NULL) { | ||
215 | if (bind) { | ||
216 | p->tcfc_bindcnt++; | ||
217 | p->tcfc_refcnt++; | ||
218 | } | ||
219 | a->priv = p; | ||
220 | } | ||
221 | return p; | ||
222 | } | ||
223 | EXPORT_SYMBOL(tcf_hash_check); | ||
224 | |||
225 | struct tcf_common *tcf_hash_create(u32 index, struct rtattr *est, struct tc_action *a, int size, int bind, u32 *idx_gen, struct tcf_hashinfo *hinfo) | ||
226 | { | ||
227 | struct tcf_common *p = kzalloc(size, GFP_KERNEL); | ||
228 | |||
229 | if (unlikely(!p)) | ||
230 | return p; | ||
231 | p->tcfc_refcnt = 1; | ||
232 | if (bind) | ||
233 | p->tcfc_bindcnt = 1; | ||
234 | |||
235 | spin_lock_init(&p->tcfc_lock); | ||
236 | p->tcfc_stats_lock = &p->tcfc_lock; | ||
237 | p->tcfc_index = index ? index : tcf_hash_new_index(idx_gen, hinfo); | ||
238 | p->tcfc_tm.install = jiffies; | ||
239 | p->tcfc_tm.lastuse = jiffies; | ||
240 | #ifdef CONFIG_NET_ESTIMATOR | ||
241 | if (est) | ||
242 | gen_new_estimator(&p->tcfc_bstats, &p->tcfc_rate_est, | ||
243 | p->tcfc_stats_lock, est); | ||
45 | #endif | 244 | #endif |
245 | a->priv = (void *) p; | ||
246 | return p; | ||
247 | } | ||
248 | EXPORT_SYMBOL(tcf_hash_create); | ||
249 | |||
250 | void tcf_hash_insert(struct tcf_common *p, struct tcf_hashinfo *hinfo) | ||
251 | { | ||
252 | unsigned int h = tcf_hash(p->tcfc_index, hinfo->hmask); | ||
253 | |||
254 | write_lock_bh(hinfo->lock); | ||
255 | p->tcfc_next = hinfo->htab[h]; | ||
256 | hinfo->htab[h] = p; | ||
257 | write_unlock_bh(hinfo->lock); | ||
258 | } | ||
259 | EXPORT_SYMBOL(tcf_hash_insert); | ||
46 | 260 | ||
47 | static struct tc_action_ops *act_base = NULL; | 261 | static struct tc_action_ops *act_base = NULL; |
48 | static DEFINE_RWLOCK(act_mod_lock); | 262 | static DEFINE_RWLOCK(act_mod_lock); |
@@ -155,9 +369,6 @@ int tcf_action_exec(struct sk_buff *skb, struct tc_action *act, | |||
155 | 369 | ||
156 | if (skb->tc_verd & TC_NCLS) { | 370 | if (skb->tc_verd & TC_NCLS) { |
157 | skb->tc_verd = CLR_TC_NCLS(skb->tc_verd); | 371 | skb->tc_verd = CLR_TC_NCLS(skb->tc_verd); |
158 | D2PRINTK("(%p)tcf_action_exec: cleared TC_NCLS in %s out %s\n", | ||
159 | skb, skb->input_dev ? skb->input_dev->name : "xxx", | ||
160 | skb->dev->name); | ||
161 | ret = TC_ACT_OK; | 372 | ret = TC_ACT_OK; |
162 | goto exec_done; | 373 | goto exec_done; |
163 | } | 374 | } |
@@ -187,8 +398,6 @@ void tcf_action_destroy(struct tc_action *act, int bind) | |||
187 | 398 | ||
188 | for (a = act; a; a = act) { | 399 | for (a = act; a; a = act) { |
189 | if (a->ops && a->ops->cleanup) { | 400 | if (a->ops && a->ops->cleanup) { |
190 | DPRINTK("tcf_action_destroy destroying %p next %p\n", | ||
191 | a, a->next); | ||
192 | if (a->ops->cleanup(a, bind) == ACT_P_DELETED) | 401 | if (a->ops->cleanup(a, bind) == ACT_P_DELETED) |
193 | module_put(a->ops->owner); | 402 | module_put(a->ops->owner); |
194 | act = act->next; | 403 | act = act->next; |
@@ -331,7 +540,6 @@ struct tc_action *tcf_action_init_1(struct rtattr *rta, struct rtattr *est, | |||
331 | if (*err != ACT_P_CREATED) | 540 | if (*err != ACT_P_CREATED) |
332 | module_put(a_o->owner); | 541 | module_put(a_o->owner); |
333 | a->ops = a_o; | 542 | a->ops = a_o; |
334 | DPRINTK("tcf_action_init_1: successfull %s\n", act_name); | ||
335 | 543 | ||
336 | *err = 0; | 544 | *err = 0; |
337 | return a; | 545 | return a; |
@@ -392,12 +600,12 @@ int tcf_action_copy_stats(struct sk_buff *skb, struct tc_action *a, | |||
392 | if (compat_mode) { | 600 | if (compat_mode) { |
393 | if (a->type == TCA_OLD_COMPAT) | 601 | if (a->type == TCA_OLD_COMPAT) |
394 | err = gnet_stats_start_copy_compat(skb, 0, | 602 | err = gnet_stats_start_copy_compat(skb, 0, |
395 | TCA_STATS, TCA_XSTATS, h->stats_lock, &d); | 603 | TCA_STATS, TCA_XSTATS, h->tcf_stats_lock, &d); |
396 | else | 604 | else |
397 | return 0; | 605 | return 0; |
398 | } else | 606 | } else |
399 | err = gnet_stats_start_copy(skb, TCA_ACT_STATS, | 607 | err = gnet_stats_start_copy(skb, TCA_ACT_STATS, |
400 | h->stats_lock, &d); | 608 | h->tcf_stats_lock, &d); |
401 | 609 | ||
402 | if (err < 0) | 610 | if (err < 0) |
403 | goto errout; | 611 | goto errout; |
@@ -406,11 +614,11 @@ int tcf_action_copy_stats(struct sk_buff *skb, struct tc_action *a, | |||
406 | if (a->ops->get_stats(skb, a) < 0) | 614 | if (a->ops->get_stats(skb, a) < 0) |
407 | goto errout; | 615 | goto errout; |
408 | 616 | ||
409 | if (gnet_stats_copy_basic(&d, &h->bstats) < 0 || | 617 | if (gnet_stats_copy_basic(&d, &h->tcf_bstats) < 0 || |
410 | #ifdef CONFIG_NET_ESTIMATOR | 618 | #ifdef CONFIG_NET_ESTIMATOR |
411 | gnet_stats_copy_rate_est(&d, &h->rate_est) < 0 || | 619 | gnet_stats_copy_rate_est(&d, &h->tcf_rate_est) < 0 || |
412 | #endif | 620 | #endif |
413 | gnet_stats_copy_queue(&d, &h->qstats) < 0) | 621 | gnet_stats_copy_queue(&d, &h->tcf_qstats) < 0) |
414 | goto errout; | 622 | goto errout; |
415 | 623 | ||
416 | if (gnet_stats_finish_copy(&d) < 0) | 624 | if (gnet_stats_finish_copy(&d) < 0) |
@@ -459,7 +667,6 @@ static int | |||
459 | act_get_notify(u32 pid, struct nlmsghdr *n, struct tc_action *a, int event) | 667 | act_get_notify(u32 pid, struct nlmsghdr *n, struct tc_action *a, int event) |
460 | { | 668 | { |
461 | struct sk_buff *skb; | 669 | struct sk_buff *skb; |
462 | int err = 0; | ||
463 | 670 | ||
464 | skb = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL); | 671 | skb = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL); |
465 | if (!skb) | 672 | if (!skb) |
@@ -468,10 +675,8 @@ act_get_notify(u32 pid, struct nlmsghdr *n, struct tc_action *a, int event) | |||
468 | kfree_skb(skb); | 675 | kfree_skb(skb); |
469 | return -EINVAL; | 676 | return -EINVAL; |
470 | } | 677 | } |
471 | err = netlink_unicast(rtnl, skb, pid, MSG_DONTWAIT); | 678 | |
472 | if (err > 0) | 679 | return rtnl_unicast(skb, pid); |
473 | err = 0; | ||
474 | return err; | ||
475 | } | 680 | } |
476 | 681 | ||
477 | static struct tc_action * | 682 | static struct tc_action * |
diff --git a/net/sched/act_gact.c b/net/sched/act_gact.c index e75a147ad60f..6cff56696a81 100644 --- a/net/sched/act_gact.c +++ b/net/sched/act_gact.c | |||
@@ -34,48 +34,43 @@ | |||
34 | #include <linux/tc_act/tc_gact.h> | 34 | #include <linux/tc_act/tc_gact.h> |
35 | #include <net/tc_act/tc_gact.h> | 35 | #include <net/tc_act/tc_gact.h> |
36 | 36 | ||
37 | /* use generic hash table */ | 37 | #define GACT_TAB_MASK 15 |
38 | #define MY_TAB_SIZE 16 | 38 | static struct tcf_common *tcf_gact_ht[GACT_TAB_MASK + 1]; |
39 | #define MY_TAB_MASK 15 | 39 | static u32 gact_idx_gen; |
40 | |||
41 | static u32 idx_gen; | ||
42 | static struct tcf_gact *tcf_gact_ht[MY_TAB_SIZE]; | ||
43 | static DEFINE_RWLOCK(gact_lock); | 40 | static DEFINE_RWLOCK(gact_lock); |
44 | 41 | ||
45 | /* ovewrride the defaults */ | 42 | static struct tcf_hashinfo gact_hash_info = { |
46 | #define tcf_st tcf_gact | 43 | .htab = tcf_gact_ht, |
47 | #define tc_st tc_gact | 44 | .hmask = GACT_TAB_MASK, |
48 | #define tcf_t_lock gact_lock | 45 | .lock = &gact_lock, |
49 | #define tcf_ht tcf_gact_ht | 46 | }; |
50 | |||
51 | #define CONFIG_NET_ACT_INIT 1 | ||
52 | #include <net/pkt_act.h> | ||
53 | 47 | ||
54 | #ifdef CONFIG_GACT_PROB | 48 | #ifdef CONFIG_GACT_PROB |
55 | static int gact_net_rand(struct tcf_gact *p) | 49 | static int gact_net_rand(struct tcf_gact *gact) |
56 | { | 50 | { |
57 | if (net_random()%p->pval) | 51 | if (net_random() % gact->tcfg_pval) |
58 | return p->action; | 52 | return gact->tcf_action; |
59 | return p->paction; | 53 | return gact->tcfg_paction; |
60 | } | 54 | } |
61 | 55 | ||
62 | static int gact_determ(struct tcf_gact *p) | 56 | static int gact_determ(struct tcf_gact *gact) |
63 | { | 57 | { |
64 | if (p->bstats.packets%p->pval) | 58 | if (gact->tcf_bstats.packets % gact->tcfg_pval) |
65 | return p->action; | 59 | return gact->tcf_action; |
66 | return p->paction; | 60 | return gact->tcfg_paction; |
67 | } | 61 | } |
68 | 62 | ||
69 | typedef int (*g_rand)(struct tcf_gact *p); | 63 | typedef int (*g_rand)(struct tcf_gact *gact); |
70 | static g_rand gact_rand[MAX_RAND]= { NULL, gact_net_rand, gact_determ }; | 64 | static g_rand gact_rand[MAX_RAND]= { NULL, gact_net_rand, gact_determ }; |
71 | #endif | 65 | #endif /* CONFIG_GACT_PROB */ |
72 | 66 | ||
73 | static int tcf_gact_init(struct rtattr *rta, struct rtattr *est, | 67 | static int tcf_gact_init(struct rtattr *rta, struct rtattr *est, |
74 | struct tc_action *a, int ovr, int bind) | 68 | struct tc_action *a, int ovr, int bind) |
75 | { | 69 | { |
76 | struct rtattr *tb[TCA_GACT_MAX]; | 70 | struct rtattr *tb[TCA_GACT_MAX]; |
77 | struct tc_gact *parm; | 71 | struct tc_gact *parm; |
78 | struct tcf_gact *p; | 72 | struct tcf_gact *gact; |
73 | struct tcf_common *pc; | ||
79 | int ret = 0; | 74 | int ret = 0; |
80 | 75 | ||
81 | if (rta == NULL || rtattr_parse_nested(tb, TCA_GACT_MAX, rta) < 0) | 76 | if (rta == NULL || rtattr_parse_nested(tb, TCA_GACT_MAX, rta) < 0) |
@@ -94,105 +89,106 @@ static int tcf_gact_init(struct rtattr *rta, struct rtattr *est, | |||
94 | return -EOPNOTSUPP; | 89 | return -EOPNOTSUPP; |
95 | #endif | 90 | #endif |
96 | 91 | ||
97 | p = tcf_hash_check(parm->index, a, ovr, bind); | 92 | pc = tcf_hash_check(parm->index, a, bind, &gact_hash_info); |
98 | if (p == NULL) { | 93 | if (!pc) { |
99 | p = tcf_hash_create(parm->index, est, a, sizeof(*p), ovr, bind); | 94 | pc = tcf_hash_create(parm->index, est, a, sizeof(*gact), |
100 | if (p == NULL) | 95 | bind, &gact_idx_gen, &gact_hash_info); |
96 | if (unlikely(!pc)) | ||
101 | return -ENOMEM; | 97 | return -ENOMEM; |
102 | ret = ACT_P_CREATED; | 98 | ret = ACT_P_CREATED; |
103 | } else { | 99 | } else { |
104 | if (!ovr) { | 100 | if (!ovr) { |
105 | tcf_hash_release(p, bind); | 101 | tcf_hash_release(pc, bind, &gact_hash_info); |
106 | return -EEXIST; | 102 | return -EEXIST; |
107 | } | 103 | } |
108 | } | 104 | } |
109 | 105 | ||
110 | spin_lock_bh(&p->lock); | 106 | gact = to_gact(pc); |
111 | p->action = parm->action; | 107 | |
108 | spin_lock_bh(&gact->tcf_lock); | ||
109 | gact->tcf_action = parm->action; | ||
112 | #ifdef CONFIG_GACT_PROB | 110 | #ifdef CONFIG_GACT_PROB |
113 | if (tb[TCA_GACT_PROB-1] != NULL) { | 111 | if (tb[TCA_GACT_PROB-1] != NULL) { |
114 | struct tc_gact_p *p_parm = RTA_DATA(tb[TCA_GACT_PROB-1]); | 112 | struct tc_gact_p *p_parm = RTA_DATA(tb[TCA_GACT_PROB-1]); |
115 | p->paction = p_parm->paction; | 113 | gact->tcfg_paction = p_parm->paction; |
116 | p->pval = p_parm->pval; | 114 | gact->tcfg_pval = p_parm->pval; |
117 | p->ptype = p_parm->ptype; | 115 | gact->tcfg_ptype = p_parm->ptype; |
118 | } | 116 | } |
119 | #endif | 117 | #endif |
120 | spin_unlock_bh(&p->lock); | 118 | spin_unlock_bh(&gact->tcf_lock); |
121 | if (ret == ACT_P_CREATED) | 119 | if (ret == ACT_P_CREATED) |
122 | tcf_hash_insert(p); | 120 | tcf_hash_insert(pc, &gact_hash_info); |
123 | return ret; | 121 | return ret; |
124 | } | 122 | } |
125 | 123 | ||
126 | static int | 124 | static int tcf_gact_cleanup(struct tc_action *a, int bind) |
127 | tcf_gact_cleanup(struct tc_action *a, int bind) | ||
128 | { | 125 | { |
129 | struct tcf_gact *p = PRIV(a, gact); | 126 | struct tcf_gact *gact = a->priv; |
130 | 127 | ||
131 | if (p != NULL) | 128 | if (gact) |
132 | return tcf_hash_release(p, bind); | 129 | return tcf_hash_release(&gact->common, bind, &gact_hash_info); |
133 | return 0; | 130 | return 0; |
134 | } | 131 | } |
135 | 132 | ||
136 | static int | 133 | static int tcf_gact(struct sk_buff *skb, struct tc_action *a, struct tcf_result *res) |
137 | tcf_gact(struct sk_buff *skb, struct tc_action *a, struct tcf_result *res) | ||
138 | { | 134 | { |
139 | struct tcf_gact *p = PRIV(a, gact); | 135 | struct tcf_gact *gact = a->priv; |
140 | int action = TC_ACT_SHOT; | 136 | int action = TC_ACT_SHOT; |
141 | 137 | ||
142 | spin_lock(&p->lock); | 138 | spin_lock(&gact->tcf_lock); |
143 | #ifdef CONFIG_GACT_PROB | 139 | #ifdef CONFIG_GACT_PROB |
144 | if (p->ptype && gact_rand[p->ptype] != NULL) | 140 | if (gact->tcfg_ptype && gact_rand[gact->tcfg_ptype] != NULL) |
145 | action = gact_rand[p->ptype](p); | 141 | action = gact_rand[gact->tcfg_ptype](gact); |
146 | else | 142 | else |
147 | action = p->action; | 143 | action = gact->tcf_action; |
148 | #else | 144 | #else |
149 | action = p->action; | 145 | action = gact->tcf_action; |
150 | #endif | 146 | #endif |
151 | p->bstats.bytes += skb->len; | 147 | gact->tcf_bstats.bytes += skb->len; |
152 | p->bstats.packets++; | 148 | gact->tcf_bstats.packets++; |
153 | if (action == TC_ACT_SHOT) | 149 | if (action == TC_ACT_SHOT) |
154 | p->qstats.drops++; | 150 | gact->tcf_qstats.drops++; |
155 | p->tm.lastuse = jiffies; | 151 | gact->tcf_tm.lastuse = jiffies; |
156 | spin_unlock(&p->lock); | 152 | spin_unlock(&gact->tcf_lock); |
157 | 153 | ||
158 | return action; | 154 | return action; |
159 | } | 155 | } |
160 | 156 | ||
161 | static int | 157 | static int tcf_gact_dump(struct sk_buff *skb, struct tc_action *a, int bind, int ref) |
162 | tcf_gact_dump(struct sk_buff *skb, struct tc_action *a, int bind, int ref) | ||
163 | { | 158 | { |
164 | unsigned char *b = skb->tail; | 159 | unsigned char *b = skb->tail; |
165 | struct tc_gact opt; | 160 | struct tc_gact opt; |
166 | struct tcf_gact *p = PRIV(a, gact); | 161 | struct tcf_gact *gact = a->priv; |
167 | struct tcf_t t; | 162 | struct tcf_t t; |
168 | 163 | ||
169 | opt.index = p->index; | 164 | opt.index = gact->tcf_index; |
170 | opt.refcnt = p->refcnt - ref; | 165 | opt.refcnt = gact->tcf_refcnt - ref; |
171 | opt.bindcnt = p->bindcnt - bind; | 166 | opt.bindcnt = gact->tcf_bindcnt - bind; |
172 | opt.action = p->action; | 167 | opt.action = gact->tcf_action; |
173 | RTA_PUT(skb, TCA_GACT_PARMS, sizeof(opt), &opt); | 168 | RTA_PUT(skb, TCA_GACT_PARMS, sizeof(opt), &opt); |
174 | #ifdef CONFIG_GACT_PROB | 169 | #ifdef CONFIG_GACT_PROB |
175 | if (p->ptype) { | 170 | if (gact->tcfg_ptype) { |
176 | struct tc_gact_p p_opt; | 171 | struct tc_gact_p p_opt; |
177 | p_opt.paction = p->paction; | 172 | p_opt.paction = gact->tcfg_paction; |
178 | p_opt.pval = p->pval; | 173 | p_opt.pval = gact->tcfg_pval; |
179 | p_opt.ptype = p->ptype; | 174 | p_opt.ptype = gact->tcfg_ptype; |
180 | RTA_PUT(skb, TCA_GACT_PROB, sizeof(p_opt), &p_opt); | 175 | RTA_PUT(skb, TCA_GACT_PROB, sizeof(p_opt), &p_opt); |
181 | } | 176 | } |
182 | #endif | 177 | #endif |
183 | t.install = jiffies_to_clock_t(jiffies - p->tm.install); | 178 | t.install = jiffies_to_clock_t(jiffies - gact->tcf_tm.install); |
184 | t.lastuse = jiffies_to_clock_t(jiffies - p->tm.lastuse); | 179 | t.lastuse = jiffies_to_clock_t(jiffies - gact->tcf_tm.lastuse); |
185 | t.expires = jiffies_to_clock_t(p->tm.expires); | 180 | t.expires = jiffies_to_clock_t(gact->tcf_tm.expires); |
186 | RTA_PUT(skb, TCA_GACT_TM, sizeof(t), &t); | 181 | RTA_PUT(skb, TCA_GACT_TM, sizeof(t), &t); |
187 | return skb->len; | 182 | return skb->len; |
188 | 183 | ||
189 | rtattr_failure: | 184 | rtattr_failure: |
190 | skb_trim(skb, b - skb->data); | 185 | skb_trim(skb, b - skb->data); |
191 | return -1; | 186 | return -1; |
192 | } | 187 | } |
193 | 188 | ||
194 | static struct tc_action_ops act_gact_ops = { | 189 | static struct tc_action_ops act_gact_ops = { |
195 | .kind = "gact", | 190 | .kind = "gact", |
191 | .hinfo = &gact_hash_info, | ||
196 | .type = TCA_ACT_GACT, | 192 | .type = TCA_ACT_GACT, |
197 | .capab = TCA_CAP_NONE, | 193 | .capab = TCA_CAP_NONE, |
198 | .owner = THIS_MODULE, | 194 | .owner = THIS_MODULE, |
@@ -208,8 +204,7 @@ MODULE_AUTHOR("Jamal Hadi Salim(2002-4)"); | |||
208 | MODULE_DESCRIPTION("Generic Classifier actions"); | 204 | MODULE_DESCRIPTION("Generic Classifier actions"); |
209 | MODULE_LICENSE("GPL"); | 205 | MODULE_LICENSE("GPL"); |
210 | 206 | ||
211 | static int __init | 207 | static int __init gact_init_module(void) |
212 | gact_init_module(void) | ||
213 | { | 208 | { |
214 | #ifdef CONFIG_GACT_PROB | 209 | #ifdef CONFIG_GACT_PROB |
215 | printk("GACT probability on\n"); | 210 | printk("GACT probability on\n"); |
@@ -219,8 +214,7 @@ gact_init_module(void) | |||
219 | return tcf_register_action(&act_gact_ops); | 214 | return tcf_register_action(&act_gact_ops); |
220 | } | 215 | } |
221 | 216 | ||
222 | static void __exit | 217 | static void __exit gact_cleanup_module(void) |
223 | gact_cleanup_module(void) | ||
224 | { | 218 | { |
225 | tcf_unregister_action(&act_gact_ops); | 219 | tcf_unregister_action(&act_gact_ops); |
226 | } | 220 | } |
diff --git a/net/sched/act_ipt.c b/net/sched/act_ipt.c index d799e01248c4..d8c9310da6e5 100644 --- a/net/sched/act_ipt.c +++ b/net/sched/act_ipt.c | |||
@@ -38,25 +38,19 @@ | |||
38 | 38 | ||
39 | #include <linux/netfilter_ipv4/ip_tables.h> | 39 | #include <linux/netfilter_ipv4/ip_tables.h> |
40 | 40 | ||
41 | /* use generic hash table */ | ||
42 | #define MY_TAB_SIZE 16 | ||
43 | #define MY_TAB_MASK 15 | ||
44 | 41 | ||
45 | static u32 idx_gen; | 42 | #define IPT_TAB_MASK 15 |
46 | static struct tcf_ipt *tcf_ipt_ht[MY_TAB_SIZE]; | 43 | static struct tcf_common *tcf_ipt_ht[IPT_TAB_MASK + 1]; |
47 | /* ipt hash table lock */ | 44 | static u32 ipt_idx_gen; |
48 | static DEFINE_RWLOCK(ipt_lock); | 45 | static DEFINE_RWLOCK(ipt_lock); |
49 | 46 | ||
50 | /* ovewrride the defaults */ | 47 | static struct tcf_hashinfo ipt_hash_info = { |
51 | #define tcf_st tcf_ipt | 48 | .htab = tcf_ipt_ht, |
52 | #define tcf_t_lock ipt_lock | 49 | .hmask = IPT_TAB_MASK, |
53 | #define tcf_ht tcf_ipt_ht | 50 | .lock = &ipt_lock, |
54 | 51 | }; | |
55 | #define CONFIG_NET_ACT_INIT | ||
56 | #include <net/pkt_act.h> | ||
57 | 52 | ||
58 | static int | 53 | static int ipt_init_target(struct ipt_entry_target *t, char *table, unsigned int hook) |
59 | ipt_init_target(struct ipt_entry_target *t, char *table, unsigned int hook) | ||
60 | { | 54 | { |
61 | struct ipt_target *target; | 55 | struct ipt_target *target; |
62 | int ret = 0; | 56 | int ret = 0; |
@@ -65,7 +59,6 @@ ipt_init_target(struct ipt_entry_target *t, char *table, unsigned int hook) | |||
65 | if (!target) | 59 | if (!target) |
66 | return -ENOENT; | 60 | return -ENOENT; |
67 | 61 | ||
68 | DPRINTK("ipt_init_target: found %s\n", target->name); | ||
69 | t->u.kernel.target = target; | 62 | t->u.kernel.target = target; |
70 | 63 | ||
71 | ret = xt_check_target(target, AF_INET, t->u.target_size - sizeof(*t), | 64 | ret = xt_check_target(target, AF_INET, t->u.target_size - sizeof(*t), |
@@ -76,10 +69,7 @@ ipt_init_target(struct ipt_entry_target *t, char *table, unsigned int hook) | |||
76 | if (t->u.kernel.target->checkentry | 69 | if (t->u.kernel.target->checkentry |
77 | && !t->u.kernel.target->checkentry(table, NULL, | 70 | && !t->u.kernel.target->checkentry(table, NULL, |
78 | t->u.kernel.target, t->data, | 71 | t->u.kernel.target, t->data, |
79 | t->u.target_size - sizeof(*t), | ||
80 | hook)) { | 72 | hook)) { |
81 | DPRINTK("ipt_init_target: check failed for `%s'.\n", | ||
82 | t->u.kernel.target->name); | ||
83 | module_put(t->u.kernel.target->me); | 73 | module_put(t->u.kernel.target->me); |
84 | ret = -EINVAL; | 74 | ret = -EINVAL; |
85 | } | 75 | } |
@@ -87,40 +77,37 @@ ipt_init_target(struct ipt_entry_target *t, char *table, unsigned int hook) | |||
87 | return ret; | 77 | return ret; |
88 | } | 78 | } |
89 | 79 | ||
90 | static void | 80 | static void ipt_destroy_target(struct ipt_entry_target *t) |
91 | ipt_destroy_target(struct ipt_entry_target *t) | ||
92 | { | 81 | { |
93 | if (t->u.kernel.target->destroy) | 82 | if (t->u.kernel.target->destroy) |
94 | t->u.kernel.target->destroy(t->u.kernel.target, t->data, | 83 | t->u.kernel.target->destroy(t->u.kernel.target, t->data); |
95 | t->u.target_size - sizeof(*t)); | ||
96 | module_put(t->u.kernel.target->me); | 84 | module_put(t->u.kernel.target->me); |
97 | } | 85 | } |
98 | 86 | ||
99 | static int | 87 | static int tcf_ipt_release(struct tcf_ipt *ipt, int bind) |
100 | tcf_ipt_release(struct tcf_ipt *p, int bind) | ||
101 | { | 88 | { |
102 | int ret = 0; | 89 | int ret = 0; |
103 | if (p) { | 90 | if (ipt) { |
104 | if (bind) | 91 | if (bind) |
105 | p->bindcnt--; | 92 | ipt->tcf_bindcnt--; |
106 | p->refcnt--; | 93 | ipt->tcf_refcnt--; |
107 | if (p->bindcnt <= 0 && p->refcnt <= 0) { | 94 | if (ipt->tcf_bindcnt <= 0 && ipt->tcf_refcnt <= 0) { |
108 | ipt_destroy_target(p->t); | 95 | ipt_destroy_target(ipt->tcfi_t); |
109 | kfree(p->tname); | 96 | kfree(ipt->tcfi_tname); |
110 | kfree(p->t); | 97 | kfree(ipt->tcfi_t); |
111 | tcf_hash_destroy(p); | 98 | tcf_hash_destroy(&ipt->common, &ipt_hash_info); |
112 | ret = ACT_P_DELETED; | 99 | ret = ACT_P_DELETED; |
113 | } | 100 | } |
114 | } | 101 | } |
115 | return ret; | 102 | return ret; |
116 | } | 103 | } |
117 | 104 | ||
118 | static int | 105 | static int tcf_ipt_init(struct rtattr *rta, struct rtattr *est, |
119 | tcf_ipt_init(struct rtattr *rta, struct rtattr *est, struct tc_action *a, | 106 | struct tc_action *a, int ovr, int bind) |
120 | int ovr, int bind) | ||
121 | { | 107 | { |
122 | struct rtattr *tb[TCA_IPT_MAX]; | 108 | struct rtattr *tb[TCA_IPT_MAX]; |
123 | struct tcf_ipt *p; | 109 | struct tcf_ipt *ipt; |
110 | struct tcf_common *pc; | ||
124 | struct ipt_entry_target *td, *t; | 111 | struct ipt_entry_target *td, *t; |
125 | char *tname; | 112 | char *tname; |
126 | int ret = 0, err; | 113 | int ret = 0, err; |
@@ -144,49 +131,51 @@ tcf_ipt_init(struct rtattr *rta, struct rtattr *est, struct tc_action *a, | |||
144 | RTA_PAYLOAD(tb[TCA_IPT_INDEX-1]) >= sizeof(u32)) | 131 | RTA_PAYLOAD(tb[TCA_IPT_INDEX-1]) >= sizeof(u32)) |
145 | index = *(u32 *)RTA_DATA(tb[TCA_IPT_INDEX-1]); | 132 | index = *(u32 *)RTA_DATA(tb[TCA_IPT_INDEX-1]); |
146 | 133 | ||
147 | p = tcf_hash_check(index, a, ovr, bind); | 134 | pc = tcf_hash_check(index, a, bind, &ipt_hash_info); |
148 | if (p == NULL) { | 135 | if (!pc) { |
149 | p = tcf_hash_create(index, est, a, sizeof(*p), ovr, bind); | 136 | pc = tcf_hash_create(index, est, a, sizeof(*ipt), bind, |
150 | if (p == NULL) | 137 | &ipt_idx_gen, &ipt_hash_info); |
138 | if (unlikely(!pc)) | ||
151 | return -ENOMEM; | 139 | return -ENOMEM; |
152 | ret = ACT_P_CREATED; | 140 | ret = ACT_P_CREATED; |
153 | } else { | 141 | } else { |
154 | if (!ovr) { | 142 | if (!ovr) { |
155 | tcf_ipt_release(p, bind); | 143 | tcf_ipt_release(to_ipt(pc), bind); |
156 | return -EEXIST; | 144 | return -EEXIST; |
157 | } | 145 | } |
158 | } | 146 | } |
147 | ipt = to_ipt(pc); | ||
159 | 148 | ||
160 | hook = *(u32 *)RTA_DATA(tb[TCA_IPT_HOOK-1]); | 149 | hook = *(u32 *)RTA_DATA(tb[TCA_IPT_HOOK-1]); |
161 | 150 | ||
162 | err = -ENOMEM; | 151 | err = -ENOMEM; |
163 | tname = kmalloc(IFNAMSIZ, GFP_KERNEL); | 152 | tname = kmalloc(IFNAMSIZ, GFP_KERNEL); |
164 | if (tname == NULL) | 153 | if (unlikely(!tname)) |
165 | goto err1; | 154 | goto err1; |
166 | if (tb[TCA_IPT_TABLE - 1] == NULL || | 155 | if (tb[TCA_IPT_TABLE - 1] == NULL || |
167 | rtattr_strlcpy(tname, tb[TCA_IPT_TABLE-1], IFNAMSIZ) >= IFNAMSIZ) | 156 | rtattr_strlcpy(tname, tb[TCA_IPT_TABLE-1], IFNAMSIZ) >= IFNAMSIZ) |
168 | strcpy(tname, "mangle"); | 157 | strcpy(tname, "mangle"); |
169 | 158 | ||
170 | t = kmalloc(td->u.target_size, GFP_KERNEL); | 159 | t = kmalloc(td->u.target_size, GFP_KERNEL); |
171 | if (t == NULL) | 160 | if (unlikely(!t)) |
172 | goto err2; | 161 | goto err2; |
173 | memcpy(t, td, td->u.target_size); | 162 | memcpy(t, td, td->u.target_size); |
174 | 163 | ||
175 | if ((err = ipt_init_target(t, tname, hook)) < 0) | 164 | if ((err = ipt_init_target(t, tname, hook)) < 0) |
176 | goto err3; | 165 | goto err3; |
177 | 166 | ||
178 | spin_lock_bh(&p->lock); | 167 | spin_lock_bh(&ipt->tcf_lock); |
179 | if (ret != ACT_P_CREATED) { | 168 | if (ret != ACT_P_CREATED) { |
180 | ipt_destroy_target(p->t); | 169 | ipt_destroy_target(ipt->tcfi_t); |
181 | kfree(p->tname); | 170 | kfree(ipt->tcfi_tname); |
182 | kfree(p->t); | 171 | kfree(ipt->tcfi_t); |
183 | } | 172 | } |
184 | p->tname = tname; | 173 | ipt->tcfi_tname = tname; |
185 | p->t = t; | 174 | ipt->tcfi_t = t; |
186 | p->hook = hook; | 175 | ipt->tcfi_hook = hook; |
187 | spin_unlock_bh(&p->lock); | 176 | spin_unlock_bh(&ipt->tcf_lock); |
188 | if (ret == ACT_P_CREATED) | 177 | if (ret == ACT_P_CREATED) |
189 | tcf_hash_insert(p); | 178 | tcf_hash_insert(pc, &ipt_hash_info); |
190 | return ret; | 179 | return ret; |
191 | 180 | ||
192 | err3: | 181 | err3: |
@@ -194,33 +183,32 @@ err3: | |||
194 | err2: | 183 | err2: |
195 | kfree(tname); | 184 | kfree(tname); |
196 | err1: | 185 | err1: |
197 | kfree(p); | 186 | kfree(pc); |
198 | return err; | 187 | return err; |
199 | } | 188 | } |
200 | 189 | ||
201 | static int | 190 | static int tcf_ipt_cleanup(struct tc_action *a, int bind) |
202 | tcf_ipt_cleanup(struct tc_action *a, int bind) | ||
203 | { | 191 | { |
204 | struct tcf_ipt *p = PRIV(a, ipt); | 192 | struct tcf_ipt *ipt = a->priv; |
205 | return tcf_ipt_release(p, bind); | 193 | return tcf_ipt_release(ipt, bind); |
206 | } | 194 | } |
207 | 195 | ||
208 | static int | 196 | static int tcf_ipt(struct sk_buff *skb, struct tc_action *a, |
209 | tcf_ipt(struct sk_buff *skb, struct tc_action *a, struct tcf_result *res) | 197 | struct tcf_result *res) |
210 | { | 198 | { |
211 | int ret = 0, result = 0; | 199 | int ret = 0, result = 0; |
212 | struct tcf_ipt *p = PRIV(a, ipt); | 200 | struct tcf_ipt *ipt = a->priv; |
213 | 201 | ||
214 | if (skb_cloned(skb)) { | 202 | if (skb_cloned(skb)) { |
215 | if (pskb_expand_head(skb, 0, 0, GFP_ATOMIC)) | 203 | if (pskb_expand_head(skb, 0, 0, GFP_ATOMIC)) |
216 | return TC_ACT_UNSPEC; | 204 | return TC_ACT_UNSPEC; |
217 | } | 205 | } |
218 | 206 | ||
219 | spin_lock(&p->lock); | 207 | spin_lock(&ipt->tcf_lock); |
220 | 208 | ||
221 | p->tm.lastuse = jiffies; | 209 | ipt->tcf_tm.lastuse = jiffies; |
222 | p->bstats.bytes += skb->len; | 210 | ipt->tcf_bstats.bytes += skb->len; |
223 | p->bstats.packets++; | 211 | ipt->tcf_bstats.packets++; |
224 | 212 | ||
225 | /* yes, we have to worry about both in and out dev | 213 | /* yes, we have to worry about both in and out dev |
226 | worry later - danger - this API seems to have changed | 214 | worry later - danger - this API seems to have changed |
@@ -229,16 +217,17 @@ tcf_ipt(struct sk_buff *skb, struct tc_action *a, struct tcf_result *res) | |||
229 | /* iptables targets take a double skb pointer in case the skb | 217 | /* iptables targets take a double skb pointer in case the skb |
230 | * needs to be replaced. We don't own the skb, so this must not | 218 | * needs to be replaced. We don't own the skb, so this must not |
231 | * happen. The pskb_expand_head above should make sure of this */ | 219 | * happen. The pskb_expand_head above should make sure of this */ |
232 | ret = p->t->u.kernel.target->target(&skb, skb->dev, NULL, p->hook, | 220 | ret = ipt->tcfi_t->u.kernel.target->target(&skb, skb->dev, NULL, |
233 | p->t->u.kernel.target, p->t->data, | 221 | ipt->tcfi_hook, |
234 | NULL); | 222 | ipt->tcfi_t->u.kernel.target, |
223 | ipt->tcfi_t->data); | ||
235 | switch (ret) { | 224 | switch (ret) { |
236 | case NF_ACCEPT: | 225 | case NF_ACCEPT: |
237 | result = TC_ACT_OK; | 226 | result = TC_ACT_OK; |
238 | break; | 227 | break; |
239 | case NF_DROP: | 228 | case NF_DROP: |
240 | result = TC_ACT_SHOT; | 229 | result = TC_ACT_SHOT; |
241 | p->qstats.drops++; | 230 | ipt->tcf_qstats.drops++; |
242 | break; | 231 | break; |
243 | case IPT_CONTINUE: | 232 | case IPT_CONTINUE: |
244 | result = TC_ACT_PIPE; | 233 | result = TC_ACT_PIPE; |
@@ -249,53 +238,46 @@ tcf_ipt(struct sk_buff *skb, struct tc_action *a, struct tcf_result *res) | |||
249 | result = TC_POLICE_OK; | 238 | result = TC_POLICE_OK; |
250 | break; | 239 | break; |
251 | } | 240 | } |
252 | spin_unlock(&p->lock); | 241 | spin_unlock(&ipt->tcf_lock); |
253 | return result; | 242 | return result; |
254 | 243 | ||
255 | } | 244 | } |
256 | 245 | ||
257 | static int | 246 | static int tcf_ipt_dump(struct sk_buff *skb, struct tc_action *a, int bind, int ref) |
258 | tcf_ipt_dump(struct sk_buff *skb, struct tc_action *a, int bind, int ref) | ||
259 | { | 247 | { |
248 | unsigned char *b = skb->tail; | ||
249 | struct tcf_ipt *ipt = a->priv; | ||
260 | struct ipt_entry_target *t; | 250 | struct ipt_entry_target *t; |
261 | struct tcf_t tm; | 251 | struct tcf_t tm; |
262 | struct tc_cnt c; | 252 | struct tc_cnt c; |
263 | unsigned char *b = skb->tail; | ||
264 | struct tcf_ipt *p = PRIV(a, ipt); | ||
265 | 253 | ||
266 | /* for simple targets kernel size == user size | 254 | /* for simple targets kernel size == user size |
267 | ** user name = target name | 255 | ** user name = target name |
268 | ** for foolproof you need to not assume this | 256 | ** for foolproof you need to not assume this |
269 | */ | 257 | */ |
270 | 258 | ||
271 | t = kmalloc(p->t->u.user.target_size, GFP_ATOMIC); | 259 | t = kmalloc(ipt->tcfi_t->u.user.target_size, GFP_ATOMIC); |
272 | if (t == NULL) | 260 | if (unlikely(!t)) |
273 | goto rtattr_failure; | 261 | goto rtattr_failure; |
274 | 262 | ||
275 | c.bindcnt = p->bindcnt - bind; | 263 | c.bindcnt = ipt->tcf_bindcnt - bind; |
276 | c.refcnt = p->refcnt - ref; | 264 | c.refcnt = ipt->tcf_refcnt - ref; |
277 | memcpy(t, p->t, p->t->u.user.target_size); | 265 | memcpy(t, ipt->tcfi_t, ipt->tcfi_t->u.user.target_size); |
278 | strcpy(t->u.user.name, p->t->u.kernel.target->name); | 266 | strcpy(t->u.user.name, ipt->tcfi_t->u.kernel.target->name); |
279 | 267 | ||
280 | DPRINTK("\ttcf_ipt_dump tablename %s length %d\n", p->tname, | 268 | RTA_PUT(skb, TCA_IPT_TARG, ipt->tcfi_t->u.user.target_size, t); |
281 | strlen(p->tname)); | 269 | RTA_PUT(skb, TCA_IPT_INDEX, 4, &ipt->tcf_index); |
282 | DPRINTK("\tdump target name %s size %d size user %d " | 270 | RTA_PUT(skb, TCA_IPT_HOOK, 4, &ipt->tcfi_hook); |
283 | "data[0] %x data[1] %x\n", p->t->u.kernel.target->name, | ||
284 | p->t->u.target_size, p->t->u.user.target_size, | ||
285 | p->t->data[0], p->t->data[1]); | ||
286 | RTA_PUT(skb, TCA_IPT_TARG, p->t->u.user.target_size, t); | ||
287 | RTA_PUT(skb, TCA_IPT_INDEX, 4, &p->index); | ||
288 | RTA_PUT(skb, TCA_IPT_HOOK, 4, &p->hook); | ||
289 | RTA_PUT(skb, TCA_IPT_CNT, sizeof(struct tc_cnt), &c); | 271 | RTA_PUT(skb, TCA_IPT_CNT, sizeof(struct tc_cnt), &c); |
290 | RTA_PUT(skb, TCA_IPT_TABLE, IFNAMSIZ, p->tname); | 272 | RTA_PUT(skb, TCA_IPT_TABLE, IFNAMSIZ, ipt->tcfi_tname); |
291 | tm.install = jiffies_to_clock_t(jiffies - p->tm.install); | 273 | tm.install = jiffies_to_clock_t(jiffies - ipt->tcf_tm.install); |
292 | tm.lastuse = jiffies_to_clock_t(jiffies - p->tm.lastuse); | 274 | tm.lastuse = jiffies_to_clock_t(jiffies - ipt->tcf_tm.lastuse); |
293 | tm.expires = jiffies_to_clock_t(p->tm.expires); | 275 | tm.expires = jiffies_to_clock_t(ipt->tcf_tm.expires); |
294 | RTA_PUT(skb, TCA_IPT_TM, sizeof (tm), &tm); | 276 | RTA_PUT(skb, TCA_IPT_TM, sizeof (tm), &tm); |
295 | kfree(t); | 277 | kfree(t); |
296 | return skb->len; | 278 | return skb->len; |
297 | 279 | ||
298 | rtattr_failure: | 280 | rtattr_failure: |
299 | skb_trim(skb, b - skb->data); | 281 | skb_trim(skb, b - skb->data); |
300 | kfree(t); | 282 | kfree(t); |
301 | return -1; | 283 | return -1; |
@@ -303,6 +285,7 @@ tcf_ipt_dump(struct sk_buff *skb, struct tc_action *a, int bind, int ref) | |||
303 | 285 | ||
304 | static struct tc_action_ops act_ipt_ops = { | 286 | static struct tc_action_ops act_ipt_ops = { |
305 | .kind = "ipt", | 287 | .kind = "ipt", |
288 | .hinfo = &ipt_hash_info, | ||
306 | .type = TCA_ACT_IPT, | 289 | .type = TCA_ACT_IPT, |
307 | .capab = TCA_CAP_NONE, | 290 | .capab = TCA_CAP_NONE, |
308 | .owner = THIS_MODULE, | 291 | .owner = THIS_MODULE, |
@@ -318,14 +301,12 @@ MODULE_AUTHOR("Jamal Hadi Salim(2002-4)"); | |||
318 | MODULE_DESCRIPTION("Iptables target actions"); | 301 | MODULE_DESCRIPTION("Iptables target actions"); |
319 | MODULE_LICENSE("GPL"); | 302 | MODULE_LICENSE("GPL"); |
320 | 303 | ||
321 | static int __init | 304 | static int __init ipt_init_module(void) |
322 | ipt_init_module(void) | ||
323 | { | 305 | { |
324 | return tcf_register_action(&act_ipt_ops); | 306 | return tcf_register_action(&act_ipt_ops); |
325 | } | 307 | } |
326 | 308 | ||
327 | static void __exit | 309 | static void __exit ipt_cleanup_module(void) |
328 | ipt_cleanup_module(void) | ||
329 | { | 310 | { |
330 | tcf_unregister_action(&act_ipt_ops); | 311 | tcf_unregister_action(&act_ipt_ops); |
331 | } | 312 | } |
diff --git a/net/sched/act_mirred.c b/net/sched/act_mirred.c index fc562047ecc5..483897271f15 100644 --- a/net/sched/act_mirred.c +++ b/net/sched/act_mirred.c | |||
@@ -39,46 +39,39 @@ | |||
39 | #include <linux/etherdevice.h> | 39 | #include <linux/etherdevice.h> |
40 | #include <linux/if_arp.h> | 40 | #include <linux/if_arp.h> |
41 | 41 | ||
42 | 42 | #define MIRRED_TAB_MASK 7 | |
43 | /* use generic hash table */ | 43 | static struct tcf_common *tcf_mirred_ht[MIRRED_TAB_MASK + 1]; |
44 | #define MY_TAB_SIZE 8 | 44 | static u32 mirred_idx_gen; |
45 | #define MY_TAB_MASK (MY_TAB_SIZE - 1) | ||
46 | static u32 idx_gen; | ||
47 | static struct tcf_mirred *tcf_mirred_ht[MY_TAB_SIZE]; | ||
48 | static DEFINE_RWLOCK(mirred_lock); | 45 | static DEFINE_RWLOCK(mirred_lock); |
49 | 46 | ||
50 | /* ovewrride the defaults */ | 47 | static struct tcf_hashinfo mirred_hash_info = { |
51 | #define tcf_st tcf_mirred | 48 | .htab = tcf_mirred_ht, |
52 | #define tc_st tc_mirred | 49 | .hmask = MIRRED_TAB_MASK, |
53 | #define tcf_t_lock mirred_lock | 50 | .lock = &mirred_lock, |
54 | #define tcf_ht tcf_mirred_ht | 51 | }; |
55 | |||
56 | #define CONFIG_NET_ACT_INIT 1 | ||
57 | #include <net/pkt_act.h> | ||
58 | 52 | ||
59 | static inline int | 53 | static inline int tcf_mirred_release(struct tcf_mirred *m, int bind) |
60 | tcf_mirred_release(struct tcf_mirred *p, int bind) | ||
61 | { | 54 | { |
62 | if (p) { | 55 | if (m) { |
63 | if (bind) | 56 | if (bind) |
64 | p->bindcnt--; | 57 | m->tcf_bindcnt--; |
65 | p->refcnt--; | 58 | m->tcf_refcnt--; |
66 | if(!p->bindcnt && p->refcnt <= 0) { | 59 | if(!m->tcf_bindcnt && m->tcf_refcnt <= 0) { |
67 | dev_put(p->dev); | 60 | dev_put(m->tcfm_dev); |
68 | tcf_hash_destroy(p); | 61 | tcf_hash_destroy(&m->common, &mirred_hash_info); |
69 | return 1; | 62 | return 1; |
70 | } | 63 | } |
71 | } | 64 | } |
72 | return 0; | 65 | return 0; |
73 | } | 66 | } |
74 | 67 | ||
75 | static int | 68 | static int tcf_mirred_init(struct rtattr *rta, struct rtattr *est, |
76 | tcf_mirred_init(struct rtattr *rta, struct rtattr *est, struct tc_action *a, | 69 | struct tc_action *a, int ovr, int bind) |
77 | int ovr, int bind) | ||
78 | { | 70 | { |
79 | struct rtattr *tb[TCA_MIRRED_MAX]; | 71 | struct rtattr *tb[TCA_MIRRED_MAX]; |
80 | struct tc_mirred *parm; | 72 | struct tc_mirred *parm; |
81 | struct tcf_mirred *p; | 73 | struct tcf_mirred *m; |
74 | struct tcf_common *pc; | ||
82 | struct net_device *dev = NULL; | 75 | struct net_device *dev = NULL; |
83 | int ret = 0; | 76 | int ret = 0; |
84 | int ok_push = 0; | 77 | int ok_push = 0; |
@@ -110,64 +103,62 @@ tcf_mirred_init(struct rtattr *rta, struct rtattr *est, struct tc_action *a, | |||
110 | } | 103 | } |
111 | } | 104 | } |
112 | 105 | ||
113 | p = tcf_hash_check(parm->index, a, ovr, bind); | 106 | pc = tcf_hash_check(parm->index, a, bind, &mirred_hash_info); |
114 | if (p == NULL) { | 107 | if (!pc) { |
115 | if (!parm->ifindex) | 108 | if (!parm->ifindex) |
116 | return -EINVAL; | 109 | return -EINVAL; |
117 | p = tcf_hash_create(parm->index, est, a, sizeof(*p), ovr, bind); | 110 | pc = tcf_hash_create(parm->index, est, a, sizeof(*m), bind, |
118 | if (p == NULL) | 111 | &mirred_idx_gen, &mirred_hash_info); |
112 | if (unlikely(!pc)) | ||
119 | return -ENOMEM; | 113 | return -ENOMEM; |
120 | ret = ACT_P_CREATED; | 114 | ret = ACT_P_CREATED; |
121 | } else { | 115 | } else { |
122 | if (!ovr) { | 116 | if (!ovr) { |
123 | tcf_mirred_release(p, bind); | 117 | tcf_mirred_release(to_mirred(pc), bind); |
124 | return -EEXIST; | 118 | return -EEXIST; |
125 | } | 119 | } |
126 | } | 120 | } |
121 | m = to_mirred(pc); | ||
127 | 122 | ||
128 | spin_lock_bh(&p->lock); | 123 | spin_lock_bh(&m->tcf_lock); |
129 | p->action = parm->action; | 124 | m->tcf_action = parm->action; |
130 | p->eaction = parm->eaction; | 125 | m->tcfm_eaction = parm->eaction; |
131 | if (parm->ifindex) { | 126 | if (parm->ifindex) { |
132 | p->ifindex = parm->ifindex; | 127 | m->tcfm_ifindex = parm->ifindex; |
133 | if (ret != ACT_P_CREATED) | 128 | if (ret != ACT_P_CREATED) |
134 | dev_put(p->dev); | 129 | dev_put(m->tcfm_dev); |
135 | p->dev = dev; | 130 | m->tcfm_dev = dev; |
136 | dev_hold(dev); | 131 | dev_hold(dev); |
137 | p->ok_push = ok_push; | 132 | m->tcfm_ok_push = ok_push; |
138 | } | 133 | } |
139 | spin_unlock_bh(&p->lock); | 134 | spin_unlock_bh(&m->tcf_lock); |
140 | if (ret == ACT_P_CREATED) | 135 | if (ret == ACT_P_CREATED) |
141 | tcf_hash_insert(p); | 136 | tcf_hash_insert(pc, &mirred_hash_info); |
142 | 137 | ||
143 | DPRINTK("tcf_mirred_init index %d action %d eaction %d device %s " | ||
144 | "ifindex %d\n", parm->index, parm->action, parm->eaction, | ||
145 | dev->name, parm->ifindex); | ||
146 | return ret; | 138 | return ret; |
147 | } | 139 | } |
148 | 140 | ||
149 | static int | 141 | static int tcf_mirred_cleanup(struct tc_action *a, int bind) |
150 | tcf_mirred_cleanup(struct tc_action *a, int bind) | ||
151 | { | 142 | { |
152 | struct tcf_mirred *p = PRIV(a, mirred); | 143 | struct tcf_mirred *m = a->priv; |
153 | 144 | ||
154 | if (p != NULL) | 145 | if (m) |
155 | return tcf_mirred_release(p, bind); | 146 | return tcf_mirred_release(m, bind); |
156 | return 0; | 147 | return 0; |
157 | } | 148 | } |
158 | 149 | ||
159 | static int | 150 | static int tcf_mirred(struct sk_buff *skb, struct tc_action *a, |
160 | tcf_mirred(struct sk_buff *skb, struct tc_action *a, struct tcf_result *res) | 151 | struct tcf_result *res) |
161 | { | 152 | { |
162 | struct tcf_mirred *p = PRIV(a, mirred); | 153 | struct tcf_mirred *m = a->priv; |
163 | struct net_device *dev; | 154 | struct net_device *dev; |
164 | struct sk_buff *skb2 = NULL; | 155 | struct sk_buff *skb2 = NULL; |
165 | u32 at = G_TC_AT(skb->tc_verd); | 156 | u32 at = G_TC_AT(skb->tc_verd); |
166 | 157 | ||
167 | spin_lock(&p->lock); | 158 | spin_lock(&m->tcf_lock); |
168 | 159 | ||
169 | dev = p->dev; | 160 | dev = m->tcfm_dev; |
170 | p->tm.lastuse = jiffies; | 161 | m->tcf_tm.lastuse = jiffies; |
171 | 162 | ||
172 | if (!(dev->flags&IFF_UP) ) { | 163 | if (!(dev->flags&IFF_UP) ) { |
173 | if (net_ratelimit()) | 164 | if (net_ratelimit()) |
@@ -176,10 +167,10 @@ tcf_mirred(struct sk_buff *skb, struct tc_action *a, struct tcf_result *res) | |||
176 | bad_mirred: | 167 | bad_mirred: |
177 | if (skb2 != NULL) | 168 | if (skb2 != NULL) |
178 | kfree_skb(skb2); | 169 | kfree_skb(skb2); |
179 | p->qstats.overlimits++; | 170 | m->tcf_qstats.overlimits++; |
180 | p->bstats.bytes += skb->len; | 171 | m->tcf_bstats.bytes += skb->len; |
181 | p->bstats.packets++; | 172 | m->tcf_bstats.packets++; |
182 | spin_unlock(&p->lock); | 173 | spin_unlock(&m->tcf_lock); |
183 | /* should we be asking for packet to be dropped? | 174 | /* should we be asking for packet to be dropped? |
184 | * may make sense for redirect case only | 175 | * may make sense for redirect case only |
185 | */ | 176 | */ |
@@ -189,59 +180,59 @@ bad_mirred: | |||
189 | skb2 = skb_clone(skb, GFP_ATOMIC); | 180 | skb2 = skb_clone(skb, GFP_ATOMIC); |
190 | if (skb2 == NULL) | 181 | if (skb2 == NULL) |
191 | goto bad_mirred; | 182 | goto bad_mirred; |
192 | if (p->eaction != TCA_EGRESS_MIRROR && p->eaction != TCA_EGRESS_REDIR) { | 183 | if (m->tcfm_eaction != TCA_EGRESS_MIRROR && |
184 | m->tcfm_eaction != TCA_EGRESS_REDIR) { | ||
193 | if (net_ratelimit()) | 185 | if (net_ratelimit()) |
194 | printk("tcf_mirred unknown action %d\n", p->eaction); | 186 | printk("tcf_mirred unknown action %d\n", |
187 | m->tcfm_eaction); | ||
195 | goto bad_mirred; | 188 | goto bad_mirred; |
196 | } | 189 | } |
197 | 190 | ||
198 | p->bstats.bytes += skb2->len; | 191 | m->tcf_bstats.bytes += skb2->len; |
199 | p->bstats.packets++; | 192 | m->tcf_bstats.packets++; |
200 | if (!(at & AT_EGRESS)) | 193 | if (!(at & AT_EGRESS)) |
201 | if (p->ok_push) | 194 | if (m->tcfm_ok_push) |
202 | skb_push(skb2, skb2->dev->hard_header_len); | 195 | skb_push(skb2, skb2->dev->hard_header_len); |
203 | 196 | ||
204 | /* mirror is always swallowed */ | 197 | /* mirror is always swallowed */ |
205 | if (p->eaction != TCA_EGRESS_MIRROR) | 198 | if (m->tcfm_eaction != TCA_EGRESS_MIRROR) |
206 | skb2->tc_verd = SET_TC_FROM(skb2->tc_verd, at); | 199 | skb2->tc_verd = SET_TC_FROM(skb2->tc_verd, at); |
207 | 200 | ||
208 | skb2->dev = dev; | 201 | skb2->dev = dev; |
209 | skb2->input_dev = skb->dev; | 202 | skb2->input_dev = skb->dev; |
210 | dev_queue_xmit(skb2); | 203 | dev_queue_xmit(skb2); |
211 | spin_unlock(&p->lock); | 204 | spin_unlock(&m->tcf_lock); |
212 | return p->action; | 205 | return m->tcf_action; |
213 | } | 206 | } |
214 | 207 | ||
215 | static int | 208 | static int tcf_mirred_dump(struct sk_buff *skb, struct tc_action *a, int bind, int ref) |
216 | tcf_mirred_dump(struct sk_buff *skb, struct tc_action *a, int bind, int ref) | ||
217 | { | 209 | { |
218 | unsigned char *b = skb->tail; | 210 | unsigned char *b = skb->tail; |
211 | struct tcf_mirred *m = a->priv; | ||
219 | struct tc_mirred opt; | 212 | struct tc_mirred opt; |
220 | struct tcf_mirred *p = PRIV(a, mirred); | ||
221 | struct tcf_t t; | 213 | struct tcf_t t; |
222 | 214 | ||
223 | opt.index = p->index; | 215 | opt.index = m->tcf_index; |
224 | opt.action = p->action; | 216 | opt.action = m->tcf_action; |
225 | opt.refcnt = p->refcnt - ref; | 217 | opt.refcnt = m->tcf_refcnt - ref; |
226 | opt.bindcnt = p->bindcnt - bind; | 218 | opt.bindcnt = m->tcf_bindcnt - bind; |
227 | opt.eaction = p->eaction; | 219 | opt.eaction = m->tcfm_eaction; |
228 | opt.ifindex = p->ifindex; | 220 | opt.ifindex = m->tcfm_ifindex; |
229 | DPRINTK("tcf_mirred_dump index %d action %d eaction %d ifindex %d\n", | ||
230 | p->index, p->action, p->eaction, p->ifindex); | ||
231 | RTA_PUT(skb, TCA_MIRRED_PARMS, sizeof(opt), &opt); | 221 | RTA_PUT(skb, TCA_MIRRED_PARMS, sizeof(opt), &opt); |
232 | t.install = jiffies_to_clock_t(jiffies - p->tm.install); | 222 | t.install = jiffies_to_clock_t(jiffies - m->tcf_tm.install); |
233 | t.lastuse = jiffies_to_clock_t(jiffies - p->tm.lastuse); | 223 | t.lastuse = jiffies_to_clock_t(jiffies - m->tcf_tm.lastuse); |
234 | t.expires = jiffies_to_clock_t(p->tm.expires); | 224 | t.expires = jiffies_to_clock_t(m->tcf_tm.expires); |
235 | RTA_PUT(skb, TCA_MIRRED_TM, sizeof(t), &t); | 225 | RTA_PUT(skb, TCA_MIRRED_TM, sizeof(t), &t); |
236 | return skb->len; | 226 | return skb->len; |
237 | 227 | ||
238 | rtattr_failure: | 228 | rtattr_failure: |
239 | skb_trim(skb, b - skb->data); | 229 | skb_trim(skb, b - skb->data); |
240 | return -1; | 230 | return -1; |
241 | } | 231 | } |
242 | 232 | ||
243 | static struct tc_action_ops act_mirred_ops = { | 233 | static struct tc_action_ops act_mirred_ops = { |
244 | .kind = "mirred", | 234 | .kind = "mirred", |
235 | .hinfo = &mirred_hash_info, | ||
245 | .type = TCA_ACT_MIRRED, | 236 | .type = TCA_ACT_MIRRED, |
246 | .capab = TCA_CAP_NONE, | 237 | .capab = TCA_CAP_NONE, |
247 | .owner = THIS_MODULE, | 238 | .owner = THIS_MODULE, |
@@ -257,15 +248,13 @@ MODULE_AUTHOR("Jamal Hadi Salim(2002)"); | |||
257 | MODULE_DESCRIPTION("Device Mirror/redirect actions"); | 248 | MODULE_DESCRIPTION("Device Mirror/redirect actions"); |
258 | MODULE_LICENSE("GPL"); | 249 | MODULE_LICENSE("GPL"); |
259 | 250 | ||
260 | static int __init | 251 | static int __init mirred_init_module(void) |
261 | mirred_init_module(void) | ||
262 | { | 252 | { |
263 | printk("Mirror/redirect action on\n"); | 253 | printk("Mirror/redirect action on\n"); |
264 | return tcf_register_action(&act_mirred_ops); | 254 | return tcf_register_action(&act_mirred_ops); |
265 | } | 255 | } |
266 | 256 | ||
267 | static void __exit | 257 | static void __exit mirred_cleanup_module(void) |
268 | mirred_cleanup_module(void) | ||
269 | { | 258 | { |
270 | tcf_unregister_action(&act_mirred_ops); | 259 | tcf_unregister_action(&act_mirred_ops); |
271 | } | 260 | } |
diff --git a/net/sched/act_pedit.c b/net/sched/act_pedit.c index f257475e0e0c..8ac65c219b98 100644 --- a/net/sched/act_pedit.c +++ b/net/sched/act_pedit.c | |||
@@ -33,32 +33,25 @@ | |||
33 | #include <linux/tc_act/tc_pedit.h> | 33 | #include <linux/tc_act/tc_pedit.h> |
34 | #include <net/tc_act/tc_pedit.h> | 34 | #include <net/tc_act/tc_pedit.h> |
35 | 35 | ||
36 | 36 | #define PEDIT_TAB_MASK 15 | |
37 | #define PEDIT_DEB 1 | 37 | static struct tcf_common *tcf_pedit_ht[PEDIT_TAB_MASK + 1]; |
38 | 38 | static u32 pedit_idx_gen; | |
39 | /* use generic hash table */ | ||
40 | #define MY_TAB_SIZE 16 | ||
41 | #define MY_TAB_MASK 15 | ||
42 | static u32 idx_gen; | ||
43 | static struct tcf_pedit *tcf_pedit_ht[MY_TAB_SIZE]; | ||
44 | static DEFINE_RWLOCK(pedit_lock); | 39 | static DEFINE_RWLOCK(pedit_lock); |
45 | 40 | ||
46 | #define tcf_st tcf_pedit | 41 | static struct tcf_hashinfo pedit_hash_info = { |
47 | #define tc_st tc_pedit | 42 | .htab = tcf_pedit_ht, |
48 | #define tcf_t_lock pedit_lock | 43 | .hmask = PEDIT_TAB_MASK, |
49 | #define tcf_ht tcf_pedit_ht | 44 | .lock = &pedit_lock, |
50 | 45 | }; | |
51 | #define CONFIG_NET_ACT_INIT 1 | ||
52 | #include <net/pkt_act.h> | ||
53 | 46 | ||
54 | static int | 47 | static int tcf_pedit_init(struct rtattr *rta, struct rtattr *est, |
55 | tcf_pedit_init(struct rtattr *rta, struct rtattr *est, struct tc_action *a, | 48 | struct tc_action *a, int ovr, int bind) |
56 | int ovr, int bind) | ||
57 | { | 49 | { |
58 | struct rtattr *tb[TCA_PEDIT_MAX]; | 50 | struct rtattr *tb[TCA_PEDIT_MAX]; |
59 | struct tc_pedit *parm; | 51 | struct tc_pedit *parm; |
60 | int ret = 0; | 52 | int ret = 0; |
61 | struct tcf_pedit *p; | 53 | struct tcf_pedit *p; |
54 | struct tcf_common *pc; | ||
62 | struct tc_pedit_key *keys = NULL; | 55 | struct tc_pedit_key *keys = NULL; |
63 | int ksize; | 56 | int ksize; |
64 | 57 | ||
@@ -73,54 +66,56 @@ tcf_pedit_init(struct rtattr *rta, struct rtattr *est, struct tc_action *a, | |||
73 | if (RTA_PAYLOAD(tb[TCA_PEDIT_PARMS-1]) < sizeof(*parm) + ksize) | 66 | if (RTA_PAYLOAD(tb[TCA_PEDIT_PARMS-1]) < sizeof(*parm) + ksize) |
74 | return -EINVAL; | 67 | return -EINVAL; |
75 | 68 | ||
76 | p = tcf_hash_check(parm->index, a, ovr, bind); | 69 | pc = tcf_hash_check(parm->index, a, bind, &pedit_hash_info); |
77 | if (p == NULL) { | 70 | if (!pc) { |
78 | if (!parm->nkeys) | 71 | if (!parm->nkeys) |
79 | return -EINVAL; | 72 | return -EINVAL; |
80 | p = tcf_hash_create(parm->index, est, a, sizeof(*p), ovr, bind); | 73 | pc = tcf_hash_create(parm->index, est, a, sizeof(*p), bind, |
81 | if (p == NULL) | 74 | &pedit_idx_gen, &pedit_hash_info); |
75 | if (unlikely(!pc)) | ||
82 | return -ENOMEM; | 76 | return -ENOMEM; |
77 | p = to_pedit(pc); | ||
83 | keys = kmalloc(ksize, GFP_KERNEL); | 78 | keys = kmalloc(ksize, GFP_KERNEL); |
84 | if (keys == NULL) { | 79 | if (keys == NULL) { |
85 | kfree(p); | 80 | kfree(pc); |
86 | return -ENOMEM; | 81 | return -ENOMEM; |
87 | } | 82 | } |
88 | ret = ACT_P_CREATED; | 83 | ret = ACT_P_CREATED; |
89 | } else { | 84 | } else { |
85 | p = to_pedit(pc); | ||
90 | if (!ovr) { | 86 | if (!ovr) { |
91 | tcf_hash_release(p, bind); | 87 | tcf_hash_release(pc, bind, &pedit_hash_info); |
92 | return -EEXIST; | 88 | return -EEXIST; |
93 | } | 89 | } |
94 | if (p->nkeys && p->nkeys != parm->nkeys) { | 90 | if (p->tcfp_nkeys && p->tcfp_nkeys != parm->nkeys) { |
95 | keys = kmalloc(ksize, GFP_KERNEL); | 91 | keys = kmalloc(ksize, GFP_KERNEL); |
96 | if (keys == NULL) | 92 | if (keys == NULL) |
97 | return -ENOMEM; | 93 | return -ENOMEM; |
98 | } | 94 | } |
99 | } | 95 | } |
100 | 96 | ||
101 | spin_lock_bh(&p->lock); | 97 | spin_lock_bh(&p->tcf_lock); |
102 | p->flags = parm->flags; | 98 | p->tcfp_flags = parm->flags; |
103 | p->action = parm->action; | 99 | p->tcf_action = parm->action; |
104 | if (keys) { | 100 | if (keys) { |
105 | kfree(p->keys); | 101 | kfree(p->tcfp_keys); |
106 | p->keys = keys; | 102 | p->tcfp_keys = keys; |
107 | p->nkeys = parm->nkeys; | 103 | p->tcfp_nkeys = parm->nkeys; |
108 | } | 104 | } |
109 | memcpy(p->keys, parm->keys, ksize); | 105 | memcpy(p->tcfp_keys, parm->keys, ksize); |
110 | spin_unlock_bh(&p->lock); | 106 | spin_unlock_bh(&p->tcf_lock); |
111 | if (ret == ACT_P_CREATED) | 107 | if (ret == ACT_P_CREATED) |
112 | tcf_hash_insert(p); | 108 | tcf_hash_insert(pc, &pedit_hash_info); |
113 | return ret; | 109 | return ret; |
114 | } | 110 | } |
115 | 111 | ||
116 | static int | 112 | static int tcf_pedit_cleanup(struct tc_action *a, int bind) |
117 | tcf_pedit_cleanup(struct tc_action *a, int bind) | ||
118 | { | 113 | { |
119 | struct tcf_pedit *p = PRIV(a, pedit); | 114 | struct tcf_pedit *p = a->priv; |
120 | 115 | ||
121 | if (p != NULL) { | 116 | if (p) { |
122 | struct tc_pedit_key *keys = p->keys; | 117 | struct tc_pedit_key *keys = p->tcfp_keys; |
123 | if (tcf_hash_release(p, bind)) { | 118 | if (tcf_hash_release(&p->common, bind, &pedit_hash_info)) { |
124 | kfree(keys); | 119 | kfree(keys); |
125 | return 1; | 120 | return 1; |
126 | } | 121 | } |
@@ -128,30 +123,30 @@ tcf_pedit_cleanup(struct tc_action *a, int bind) | |||
128 | return 0; | 123 | return 0; |
129 | } | 124 | } |
130 | 125 | ||
131 | static int | 126 | static int tcf_pedit(struct sk_buff *skb, struct tc_action *a, |
132 | tcf_pedit(struct sk_buff *skb, struct tc_action *a, struct tcf_result *res) | 127 | struct tcf_result *res) |
133 | { | 128 | { |
134 | struct tcf_pedit *p = PRIV(a, pedit); | 129 | struct tcf_pedit *p = a->priv; |
135 | int i, munged = 0; | 130 | int i, munged = 0; |
136 | u8 *pptr; | 131 | u8 *pptr; |
137 | 132 | ||
138 | if (!(skb->tc_verd & TC_OK2MUNGE)) { | 133 | if (!(skb->tc_verd & TC_OK2MUNGE)) { |
139 | /* should we set skb->cloned? */ | 134 | /* should we set skb->cloned? */ |
140 | if (pskb_expand_head(skb, 0, 0, GFP_ATOMIC)) { | 135 | if (pskb_expand_head(skb, 0, 0, GFP_ATOMIC)) { |
141 | return p->action; | 136 | return p->tcf_action; |
142 | } | 137 | } |
143 | } | 138 | } |
144 | 139 | ||
145 | pptr = skb->nh.raw; | 140 | pptr = skb->nh.raw; |
146 | 141 | ||
147 | spin_lock(&p->lock); | 142 | spin_lock(&p->tcf_lock); |
148 | 143 | ||
149 | p->tm.lastuse = jiffies; | 144 | p->tcf_tm.lastuse = jiffies; |
150 | 145 | ||
151 | if (p->nkeys > 0) { | 146 | if (p->tcfp_nkeys > 0) { |
152 | struct tc_pedit_key *tkey = p->keys; | 147 | struct tc_pedit_key *tkey = p->tcfp_keys; |
153 | 148 | ||
154 | for (i = p->nkeys; i > 0; i--, tkey++) { | 149 | for (i = p->tcfp_nkeys; i > 0; i--, tkey++) { |
155 | u32 *ptr; | 150 | u32 *ptr; |
156 | int offset = tkey->off; | 151 | int offset = tkey->off; |
157 | 152 | ||
@@ -169,7 +164,8 @@ tcf_pedit(struct sk_buff *skb, struct tc_action *a, struct tcf_result *res) | |||
169 | printk("offset must be on 32 bit boundaries\n"); | 164 | printk("offset must be on 32 bit boundaries\n"); |
170 | goto bad; | 165 | goto bad; |
171 | } | 166 | } |
172 | if (skb->len < 0 || (offset > 0 && offset > skb->len)) { | 167 | if (skb->len < 0 || |
168 | (offset > 0 && offset > skb->len)) { | ||
173 | printk("offset %d cant exceed pkt length %d\n", | 169 | printk("offset %d cant exceed pkt length %d\n", |
174 | offset, skb->len); | 170 | offset, skb->len); |
175 | goto bad; | 171 | goto bad; |
@@ -185,63 +181,47 @@ tcf_pedit(struct sk_buff *skb, struct tc_action *a, struct tcf_result *res) | |||
185 | skb->tc_verd = SET_TC_MUNGED(skb->tc_verd); | 181 | skb->tc_verd = SET_TC_MUNGED(skb->tc_verd); |
186 | goto done; | 182 | goto done; |
187 | } else { | 183 | } else { |
188 | printk("pedit BUG: index %d\n",p->index); | 184 | printk("pedit BUG: index %d\n", p->tcf_index); |
189 | } | 185 | } |
190 | 186 | ||
191 | bad: | 187 | bad: |
192 | p->qstats.overlimits++; | 188 | p->tcf_qstats.overlimits++; |
193 | done: | 189 | done: |
194 | p->bstats.bytes += skb->len; | 190 | p->tcf_bstats.bytes += skb->len; |
195 | p->bstats.packets++; | 191 | p->tcf_bstats.packets++; |
196 | spin_unlock(&p->lock); | 192 | spin_unlock(&p->tcf_lock); |
197 | return p->action; | 193 | return p->tcf_action; |
198 | } | 194 | } |
199 | 195 | ||
200 | static int | 196 | static int tcf_pedit_dump(struct sk_buff *skb, struct tc_action *a, |
201 | tcf_pedit_dump(struct sk_buff *skb, struct tc_action *a,int bind, int ref) | 197 | int bind, int ref) |
202 | { | 198 | { |
203 | unsigned char *b = skb->tail; | 199 | unsigned char *b = skb->tail; |
200 | struct tcf_pedit *p = a->priv; | ||
204 | struct tc_pedit *opt; | 201 | struct tc_pedit *opt; |
205 | struct tcf_pedit *p = PRIV(a, pedit); | ||
206 | struct tcf_t t; | 202 | struct tcf_t t; |
207 | int s; | 203 | int s; |
208 | 204 | ||
209 | s = sizeof(*opt) + p->nkeys * sizeof(struct tc_pedit_key); | 205 | s = sizeof(*opt) + p->tcfp_nkeys * sizeof(struct tc_pedit_key); |
210 | 206 | ||
211 | /* netlink spinlocks held above us - must use ATOMIC */ | 207 | /* netlink spinlocks held above us - must use ATOMIC */ |
212 | opt = kzalloc(s, GFP_ATOMIC); | 208 | opt = kzalloc(s, GFP_ATOMIC); |
213 | if (opt == NULL) | 209 | if (unlikely(!opt)) |
214 | return -ENOBUFS; | 210 | return -ENOBUFS; |
215 | 211 | ||
216 | memcpy(opt->keys, p->keys, p->nkeys * sizeof(struct tc_pedit_key)); | 212 | memcpy(opt->keys, p->tcfp_keys, |
217 | opt->index = p->index; | 213 | p->tcfp_nkeys * sizeof(struct tc_pedit_key)); |
218 | opt->nkeys = p->nkeys; | 214 | opt->index = p->tcf_index; |
219 | opt->flags = p->flags; | 215 | opt->nkeys = p->tcfp_nkeys; |
220 | opt->action = p->action; | 216 | opt->flags = p->tcfp_flags; |
221 | opt->refcnt = p->refcnt - ref; | 217 | opt->action = p->tcf_action; |
222 | opt->bindcnt = p->bindcnt - bind; | 218 | opt->refcnt = p->tcf_refcnt - ref; |
223 | 219 | opt->bindcnt = p->tcf_bindcnt - bind; | |
224 | |||
225 | #ifdef PEDIT_DEB | ||
226 | { | ||
227 | /* Debug - get rid of later */ | ||
228 | int i; | ||
229 | struct tc_pedit_key *key = opt->keys; | ||
230 | |||
231 | for (i=0; i<opt->nkeys; i++, key++) { | ||
232 | printk( "\n key #%d",i); | ||
233 | printk( " at %d: val %08x mask %08x", | ||
234 | (unsigned int)key->off, | ||
235 | (unsigned int)key->val, | ||
236 | (unsigned int)key->mask); | ||
237 | } | ||
238 | } | ||
239 | #endif | ||
240 | 220 | ||
241 | RTA_PUT(skb, TCA_PEDIT_PARMS, s, opt); | 221 | RTA_PUT(skb, TCA_PEDIT_PARMS, s, opt); |
242 | t.install = jiffies_to_clock_t(jiffies - p->tm.install); | 222 | t.install = jiffies_to_clock_t(jiffies - p->tcf_tm.install); |
243 | t.lastuse = jiffies_to_clock_t(jiffies - p->tm.lastuse); | 223 | t.lastuse = jiffies_to_clock_t(jiffies - p->tcf_tm.lastuse); |
244 | t.expires = jiffies_to_clock_t(p->tm.expires); | 224 | t.expires = jiffies_to_clock_t(p->tcf_tm.expires); |
245 | RTA_PUT(skb, TCA_PEDIT_TM, sizeof(t), &t); | 225 | RTA_PUT(skb, TCA_PEDIT_TM, sizeof(t), &t); |
246 | kfree(opt); | 226 | kfree(opt); |
247 | return skb->len; | 227 | return skb->len; |
@@ -252,9 +232,9 @@ rtattr_failure: | |||
252 | return -1; | 232 | return -1; |
253 | } | 233 | } |
254 | 234 | ||
255 | static | 235 | static struct tc_action_ops act_pedit_ops = { |
256 | struct tc_action_ops act_pedit_ops = { | ||
257 | .kind = "pedit", | 236 | .kind = "pedit", |
237 | .hinfo = &pedit_hash_info, | ||
258 | .type = TCA_ACT_PEDIT, | 238 | .type = TCA_ACT_PEDIT, |
259 | .capab = TCA_CAP_NONE, | 239 | .capab = TCA_CAP_NONE, |
260 | .owner = THIS_MODULE, | 240 | .owner = THIS_MODULE, |
@@ -270,14 +250,12 @@ MODULE_AUTHOR("Jamal Hadi Salim(2002-4)"); | |||
270 | MODULE_DESCRIPTION("Generic Packet Editor actions"); | 250 | MODULE_DESCRIPTION("Generic Packet Editor actions"); |
271 | MODULE_LICENSE("GPL"); | 251 | MODULE_LICENSE("GPL"); |
272 | 252 | ||
273 | static int __init | 253 | static int __init pedit_init_module(void) |
274 | pedit_init_module(void) | ||
275 | { | 254 | { |
276 | return tcf_register_action(&act_pedit_ops); | 255 | return tcf_register_action(&act_pedit_ops); |
277 | } | 256 | } |
278 | 257 | ||
279 | static void __exit | 258 | static void __exit pedit_cleanup_module(void) |
280 | pedit_cleanup_module(void) | ||
281 | { | 259 | { |
282 | tcf_unregister_action(&act_pedit_ops); | 260 | tcf_unregister_action(&act_pedit_ops); |
283 | } | 261 | } |
diff --git a/net/sched/act_police.c b/net/sched/act_police.c index da905d7b4b40..fed47b658837 100644 --- a/net/sched/act_police.c +++ b/net/sched/act_police.c | |||
@@ -32,43 +32,27 @@ | |||
32 | #include <net/sock.h> | 32 | #include <net/sock.h> |
33 | #include <net/act_api.h> | 33 | #include <net/act_api.h> |
34 | 34 | ||
35 | #define L2T(p,L) ((p)->R_tab->data[(L)>>(p)->R_tab->rate.cell_log]) | 35 | #define L2T(p,L) ((p)->tcfp_R_tab->data[(L)>>(p)->tcfp_R_tab->rate.cell_log]) |
36 | #define L2T_P(p,L) ((p)->P_tab->data[(L)>>(p)->P_tab->rate.cell_log]) | 36 | #define L2T_P(p,L) ((p)->tcfp_P_tab->data[(L)>>(p)->tcfp_P_tab->rate.cell_log]) |
37 | #define PRIV(a) ((struct tcf_police *) (a)->priv) | ||
38 | |||
39 | /* use generic hash table */ | ||
40 | #define MY_TAB_SIZE 16 | ||
41 | #define MY_TAB_MASK 15 | ||
42 | static u32 idx_gen; | ||
43 | static struct tcf_police *tcf_police_ht[MY_TAB_SIZE]; | ||
44 | /* Policer hash table lock */ | ||
45 | static DEFINE_RWLOCK(police_lock); | ||
46 | |||
47 | /* Each policer is serialized by its individual spinlock */ | ||
48 | 37 | ||
49 | static __inline__ unsigned tcf_police_hash(u32 index) | 38 | #define POL_TAB_MASK 15 |
50 | { | 39 | static struct tcf_common *tcf_police_ht[POL_TAB_MASK + 1]; |
51 | return index&0xF; | 40 | static u32 police_idx_gen; |
52 | } | 41 | static DEFINE_RWLOCK(police_lock); |
53 | 42 | ||
54 | static __inline__ struct tcf_police * tcf_police_lookup(u32 index) | 43 | static struct tcf_hashinfo police_hash_info = { |
55 | { | 44 | .htab = tcf_police_ht, |
56 | struct tcf_police *p; | 45 | .hmask = POL_TAB_MASK, |
46 | .lock = &police_lock, | ||
47 | }; | ||
57 | 48 | ||
58 | read_lock(&police_lock); | 49 | /* Each policer is serialized by its individual spinlock */ |
59 | for (p = tcf_police_ht[tcf_police_hash(index)]; p; p = p->next) { | ||
60 | if (p->index == index) | ||
61 | break; | ||
62 | } | ||
63 | read_unlock(&police_lock); | ||
64 | return p; | ||
65 | } | ||
66 | 50 | ||
67 | #ifdef CONFIG_NET_CLS_ACT | 51 | #ifdef CONFIG_NET_CLS_ACT |
68 | static int tcf_act_police_walker(struct sk_buff *skb, struct netlink_callback *cb, | 52 | static int tcf_act_police_walker(struct sk_buff *skb, struct netlink_callback *cb, |
69 | int type, struct tc_action *a) | 53 | int type, struct tc_action *a) |
70 | { | 54 | { |
71 | struct tcf_police *p; | 55 | struct tcf_common *p; |
72 | int err = 0, index = -1, i = 0, s_i = 0, n_i = 0; | 56 | int err = 0, index = -1, i = 0, s_i = 0, n_i = 0; |
73 | struct rtattr *r; | 57 | struct rtattr *r; |
74 | 58 | ||
@@ -76,10 +60,10 @@ static int tcf_act_police_walker(struct sk_buff *skb, struct netlink_callback *c | |||
76 | 60 | ||
77 | s_i = cb->args[0]; | 61 | s_i = cb->args[0]; |
78 | 62 | ||
79 | for (i = 0; i < MY_TAB_SIZE; i++) { | 63 | for (i = 0; i < (POL_TAB_MASK + 1); i++) { |
80 | p = tcf_police_ht[tcf_police_hash(i)]; | 64 | p = tcf_police_ht[tcf_hash(i, POL_TAB_MASK)]; |
81 | 65 | ||
82 | for (; p; p = p->next) { | 66 | for (; p; p = p->tcfc_next) { |
83 | index++; | 67 | index++; |
84 | if (index < s_i) | 68 | if (index < s_i) |
85 | continue; | 69 | continue; |
@@ -110,48 +94,26 @@ rtattr_failure: | |||
110 | skb_trim(skb, (u8*)r - skb->data); | 94 | skb_trim(skb, (u8*)r - skb->data); |
111 | goto done; | 95 | goto done; |
112 | } | 96 | } |
113 | |||
114 | static inline int | ||
115 | tcf_act_police_hash_search(struct tc_action *a, u32 index) | ||
116 | { | ||
117 | struct tcf_police *p = tcf_police_lookup(index); | ||
118 | |||
119 | if (p != NULL) { | ||
120 | a->priv = p; | ||
121 | return 1; | ||
122 | } else { | ||
123 | return 0; | ||
124 | } | ||
125 | } | ||
126 | #endif | 97 | #endif |
127 | 98 | ||
128 | static inline u32 tcf_police_new_index(void) | ||
129 | { | ||
130 | do { | ||
131 | if (++idx_gen == 0) | ||
132 | idx_gen = 1; | ||
133 | } while (tcf_police_lookup(idx_gen)); | ||
134 | |||
135 | return idx_gen; | ||
136 | } | ||
137 | |||
138 | void tcf_police_destroy(struct tcf_police *p) | 99 | void tcf_police_destroy(struct tcf_police *p) |
139 | { | 100 | { |
140 | unsigned h = tcf_police_hash(p->index); | 101 | unsigned int h = tcf_hash(p->tcf_index, POL_TAB_MASK); |
141 | struct tcf_police **p1p; | 102 | struct tcf_common **p1p; |
142 | 103 | ||
143 | for (p1p = &tcf_police_ht[h]; *p1p; p1p = &(*p1p)->next) { | 104 | for (p1p = &tcf_police_ht[h]; *p1p; p1p = &(*p1p)->tcfc_next) { |
144 | if (*p1p == p) { | 105 | if (*p1p == &p->common) { |
145 | write_lock_bh(&police_lock); | 106 | write_lock_bh(&police_lock); |
146 | *p1p = p->next; | 107 | *p1p = p->tcf_next; |
147 | write_unlock_bh(&police_lock); | 108 | write_unlock_bh(&police_lock); |
148 | #ifdef CONFIG_NET_ESTIMATOR | 109 | #ifdef CONFIG_NET_ESTIMATOR |
149 | gen_kill_estimator(&p->bstats, &p->rate_est); | 110 | gen_kill_estimator(&p->tcf_bstats, |
111 | &p->tcf_rate_est); | ||
150 | #endif | 112 | #endif |
151 | if (p->R_tab) | 113 | if (p->tcfp_R_tab) |
152 | qdisc_put_rtab(p->R_tab); | 114 | qdisc_put_rtab(p->tcfp_R_tab); |
153 | if (p->P_tab) | 115 | if (p->tcfp_P_tab) |
154 | qdisc_put_rtab(p->P_tab); | 116 | qdisc_put_rtab(p->tcfp_P_tab); |
155 | kfree(p); | 117 | kfree(p); |
156 | return; | 118 | return; |
157 | } | 119 | } |
@@ -167,7 +129,7 @@ static int tcf_act_police_locate(struct rtattr *rta, struct rtattr *est, | |||
167 | int ret = 0, err; | 129 | int ret = 0, err; |
168 | struct rtattr *tb[TCA_POLICE_MAX]; | 130 | struct rtattr *tb[TCA_POLICE_MAX]; |
169 | struct tc_police *parm; | 131 | struct tc_police *parm; |
170 | struct tcf_police *p; | 132 | struct tcf_police *police; |
171 | struct qdisc_rate_table *R_tab = NULL, *P_tab = NULL; | 133 | struct qdisc_rate_table *R_tab = NULL, *P_tab = NULL; |
172 | 134 | ||
173 | if (rta == NULL || rtattr_parse_nested(tb, TCA_POLICE_MAX, rta) < 0) | 135 | if (rta == NULL || rtattr_parse_nested(tb, TCA_POLICE_MAX, rta) < 0) |
@@ -185,27 +147,32 @@ static int tcf_act_police_locate(struct rtattr *rta, struct rtattr *est, | |||
185 | RTA_PAYLOAD(tb[TCA_POLICE_RESULT-1]) != sizeof(u32)) | 147 | RTA_PAYLOAD(tb[TCA_POLICE_RESULT-1]) != sizeof(u32)) |
186 | return -EINVAL; | 148 | return -EINVAL; |
187 | 149 | ||
188 | if (parm->index && (p = tcf_police_lookup(parm->index)) != NULL) { | 150 | if (parm->index) { |
189 | a->priv = p; | 151 | struct tcf_common *pc; |
190 | if (bind) { | 152 | |
191 | p->bindcnt += 1; | 153 | pc = tcf_hash_lookup(parm->index, &police_hash_info); |
192 | p->refcnt += 1; | 154 | if (pc != NULL) { |
155 | a->priv = pc; | ||
156 | police = to_police(pc); | ||
157 | if (bind) { | ||
158 | police->tcf_bindcnt += 1; | ||
159 | police->tcf_refcnt += 1; | ||
160 | } | ||
161 | if (ovr) | ||
162 | goto override; | ||
163 | return ret; | ||
193 | } | 164 | } |
194 | if (ovr) | ||
195 | goto override; | ||
196 | return ret; | ||
197 | } | 165 | } |
198 | 166 | ||
199 | p = kzalloc(sizeof(*p), GFP_KERNEL); | 167 | police = kzalloc(sizeof(*police), GFP_KERNEL); |
200 | if (p == NULL) | 168 | if (police == NULL) |
201 | return -ENOMEM; | 169 | return -ENOMEM; |
202 | |||
203 | ret = ACT_P_CREATED; | 170 | ret = ACT_P_CREATED; |
204 | p->refcnt = 1; | 171 | police->tcf_refcnt = 1; |
205 | spin_lock_init(&p->lock); | 172 | spin_lock_init(&police->tcf_lock); |
206 | p->stats_lock = &p->lock; | 173 | police->tcf_stats_lock = &police->tcf_lock; |
207 | if (bind) | 174 | if (bind) |
208 | p->bindcnt = 1; | 175 | police->tcf_bindcnt = 1; |
209 | override: | 176 | override: |
210 | if (parm->rate.rate) { | 177 | if (parm->rate.rate) { |
211 | err = -ENOMEM; | 178 | err = -ENOMEM; |
@@ -215,67 +182,71 @@ override: | |||
215 | if (parm->peakrate.rate) { | 182 | if (parm->peakrate.rate) { |
216 | P_tab = qdisc_get_rtab(&parm->peakrate, | 183 | P_tab = qdisc_get_rtab(&parm->peakrate, |
217 | tb[TCA_POLICE_PEAKRATE-1]); | 184 | tb[TCA_POLICE_PEAKRATE-1]); |
218 | if (p->P_tab == NULL) { | 185 | if (P_tab == NULL) { |
219 | qdisc_put_rtab(R_tab); | 186 | qdisc_put_rtab(R_tab); |
220 | goto failure; | 187 | goto failure; |
221 | } | 188 | } |
222 | } | 189 | } |
223 | } | 190 | } |
224 | /* No failure allowed after this point */ | 191 | /* No failure allowed after this point */ |
225 | spin_lock_bh(&p->lock); | 192 | spin_lock_bh(&police->tcf_lock); |
226 | if (R_tab != NULL) { | 193 | if (R_tab != NULL) { |
227 | qdisc_put_rtab(p->R_tab); | 194 | qdisc_put_rtab(police->tcfp_R_tab); |
228 | p->R_tab = R_tab; | 195 | police->tcfp_R_tab = R_tab; |
229 | } | 196 | } |
230 | if (P_tab != NULL) { | 197 | if (P_tab != NULL) { |
231 | qdisc_put_rtab(p->P_tab); | 198 | qdisc_put_rtab(police->tcfp_P_tab); |
232 | p->P_tab = P_tab; | 199 | police->tcfp_P_tab = P_tab; |
233 | } | 200 | } |
234 | 201 | ||
235 | if (tb[TCA_POLICE_RESULT-1]) | 202 | if (tb[TCA_POLICE_RESULT-1]) |
236 | p->result = *(u32*)RTA_DATA(tb[TCA_POLICE_RESULT-1]); | 203 | police->tcfp_result = *(u32*)RTA_DATA(tb[TCA_POLICE_RESULT-1]); |
237 | p->toks = p->burst = parm->burst; | 204 | police->tcfp_toks = police->tcfp_burst = parm->burst; |
238 | p->mtu = parm->mtu; | 205 | police->tcfp_mtu = parm->mtu; |
239 | if (p->mtu == 0) { | 206 | if (police->tcfp_mtu == 0) { |
240 | p->mtu = ~0; | 207 | police->tcfp_mtu = ~0; |
241 | if (p->R_tab) | 208 | if (police->tcfp_R_tab) |
242 | p->mtu = 255<<p->R_tab->rate.cell_log; | 209 | police->tcfp_mtu = 255<<police->tcfp_R_tab->rate.cell_log; |
243 | } | 210 | } |
244 | if (p->P_tab) | 211 | if (police->tcfp_P_tab) |
245 | p->ptoks = L2T_P(p, p->mtu); | 212 | police->tcfp_ptoks = L2T_P(police, police->tcfp_mtu); |
246 | p->action = parm->action; | 213 | police->tcf_action = parm->action; |
247 | 214 | ||
248 | #ifdef CONFIG_NET_ESTIMATOR | 215 | #ifdef CONFIG_NET_ESTIMATOR |
249 | if (tb[TCA_POLICE_AVRATE-1]) | 216 | if (tb[TCA_POLICE_AVRATE-1]) |
250 | p->ewma_rate = *(u32*)RTA_DATA(tb[TCA_POLICE_AVRATE-1]); | 217 | police->tcfp_ewma_rate = |
218 | *(u32*)RTA_DATA(tb[TCA_POLICE_AVRATE-1]); | ||
251 | if (est) | 219 | if (est) |
252 | gen_replace_estimator(&p->bstats, &p->rate_est, p->stats_lock, est); | 220 | gen_replace_estimator(&police->tcf_bstats, |
221 | &police->tcf_rate_est, | ||
222 | police->tcf_stats_lock, est); | ||
253 | #endif | 223 | #endif |
254 | 224 | ||
255 | spin_unlock_bh(&p->lock); | 225 | spin_unlock_bh(&police->tcf_lock); |
256 | if (ret != ACT_P_CREATED) | 226 | if (ret != ACT_P_CREATED) |
257 | return ret; | 227 | return ret; |
258 | 228 | ||
259 | PSCHED_GET_TIME(p->t_c); | 229 | PSCHED_GET_TIME(police->tcfp_t_c); |
260 | p->index = parm->index ? : tcf_police_new_index(); | 230 | police->tcf_index = parm->index ? parm->index : |
261 | h = tcf_police_hash(p->index); | 231 | tcf_hash_new_index(&police_idx_gen, &police_hash_info); |
232 | h = tcf_hash(police->tcf_index, POL_TAB_MASK); | ||
262 | write_lock_bh(&police_lock); | 233 | write_lock_bh(&police_lock); |
263 | p->next = tcf_police_ht[h]; | 234 | police->tcf_next = tcf_police_ht[h]; |
264 | tcf_police_ht[h] = p; | 235 | tcf_police_ht[h] = &police->common; |
265 | write_unlock_bh(&police_lock); | 236 | write_unlock_bh(&police_lock); |
266 | 237 | ||
267 | a->priv = p; | 238 | a->priv = police; |
268 | return ret; | 239 | return ret; |
269 | 240 | ||
270 | failure: | 241 | failure: |
271 | if (ret == ACT_P_CREATED) | 242 | if (ret == ACT_P_CREATED) |
272 | kfree(p); | 243 | kfree(police); |
273 | return err; | 244 | return err; |
274 | } | 245 | } |
275 | 246 | ||
276 | static int tcf_act_police_cleanup(struct tc_action *a, int bind) | 247 | static int tcf_act_police_cleanup(struct tc_action *a, int bind) |
277 | { | 248 | { |
278 | struct tcf_police *p = PRIV(a); | 249 | struct tcf_police *p = a->priv; |
279 | 250 | ||
280 | if (p != NULL) | 251 | if (p != NULL) |
281 | return tcf_police_release(p, bind); | 252 | return tcf_police_release(p, bind); |
@@ -285,86 +256,87 @@ static int tcf_act_police_cleanup(struct tc_action *a, int bind) | |||
285 | static int tcf_act_police(struct sk_buff *skb, struct tc_action *a, | 256 | static int tcf_act_police(struct sk_buff *skb, struct tc_action *a, |
286 | struct tcf_result *res) | 257 | struct tcf_result *res) |
287 | { | 258 | { |
259 | struct tcf_police *police = a->priv; | ||
288 | psched_time_t now; | 260 | psched_time_t now; |
289 | struct tcf_police *p = PRIV(a); | ||
290 | long toks; | 261 | long toks; |
291 | long ptoks = 0; | 262 | long ptoks = 0; |
292 | 263 | ||
293 | spin_lock(&p->lock); | 264 | spin_lock(&police->tcf_lock); |
294 | 265 | ||
295 | p->bstats.bytes += skb->len; | 266 | police->tcf_bstats.bytes += skb->len; |
296 | p->bstats.packets++; | 267 | police->tcf_bstats.packets++; |
297 | 268 | ||
298 | #ifdef CONFIG_NET_ESTIMATOR | 269 | #ifdef CONFIG_NET_ESTIMATOR |
299 | if (p->ewma_rate && p->rate_est.bps >= p->ewma_rate) { | 270 | if (police->tcfp_ewma_rate && |
300 | p->qstats.overlimits++; | 271 | police->tcf_rate_est.bps >= police->tcfp_ewma_rate) { |
301 | spin_unlock(&p->lock); | 272 | police->tcf_qstats.overlimits++; |
302 | return p->action; | 273 | spin_unlock(&police->tcf_lock); |
274 | return police->tcf_action; | ||
303 | } | 275 | } |
304 | #endif | 276 | #endif |
305 | 277 | ||
306 | if (skb->len <= p->mtu) { | 278 | if (skb->len <= police->tcfp_mtu) { |
307 | if (p->R_tab == NULL) { | 279 | if (police->tcfp_R_tab == NULL) { |
308 | spin_unlock(&p->lock); | 280 | spin_unlock(&police->tcf_lock); |
309 | return p->result; | 281 | return police->tcfp_result; |
310 | } | 282 | } |
311 | 283 | ||
312 | PSCHED_GET_TIME(now); | 284 | PSCHED_GET_TIME(now); |
313 | 285 | ||
314 | toks = PSCHED_TDIFF_SAFE(now, p->t_c, p->burst); | 286 | toks = PSCHED_TDIFF_SAFE(now, police->tcfp_t_c, |
315 | 287 | police->tcfp_burst); | |
316 | if (p->P_tab) { | 288 | if (police->tcfp_P_tab) { |
317 | ptoks = toks + p->ptoks; | 289 | ptoks = toks + police->tcfp_ptoks; |
318 | if (ptoks > (long)L2T_P(p, p->mtu)) | 290 | if (ptoks > (long)L2T_P(police, police->tcfp_mtu)) |
319 | ptoks = (long)L2T_P(p, p->mtu); | 291 | ptoks = (long)L2T_P(police, police->tcfp_mtu); |
320 | ptoks -= L2T_P(p, skb->len); | 292 | ptoks -= L2T_P(police, skb->len); |
321 | } | 293 | } |
322 | toks += p->toks; | 294 | toks += police->tcfp_toks; |
323 | if (toks > (long)p->burst) | 295 | if (toks > (long)police->tcfp_burst) |
324 | toks = p->burst; | 296 | toks = police->tcfp_burst; |
325 | toks -= L2T(p, skb->len); | 297 | toks -= L2T(police, skb->len); |
326 | |||
327 | if ((toks|ptoks) >= 0) { | 298 | if ((toks|ptoks) >= 0) { |
328 | p->t_c = now; | 299 | police->tcfp_t_c = now; |
329 | p->toks = toks; | 300 | police->tcfp_toks = toks; |
330 | p->ptoks = ptoks; | 301 | police->tcfp_ptoks = ptoks; |
331 | spin_unlock(&p->lock); | 302 | spin_unlock(&police->tcf_lock); |
332 | return p->result; | 303 | return police->tcfp_result; |
333 | } | 304 | } |
334 | } | 305 | } |
335 | 306 | ||
336 | p->qstats.overlimits++; | 307 | police->tcf_qstats.overlimits++; |
337 | spin_unlock(&p->lock); | 308 | spin_unlock(&police->tcf_lock); |
338 | return p->action; | 309 | return police->tcf_action; |
339 | } | 310 | } |
340 | 311 | ||
341 | static int | 312 | static int |
342 | tcf_act_police_dump(struct sk_buff *skb, struct tc_action *a, int bind, int ref) | 313 | tcf_act_police_dump(struct sk_buff *skb, struct tc_action *a, int bind, int ref) |
343 | { | 314 | { |
344 | unsigned char *b = skb->tail; | 315 | unsigned char *b = skb->tail; |
316 | struct tcf_police *police = a->priv; | ||
345 | struct tc_police opt; | 317 | struct tc_police opt; |
346 | struct tcf_police *p = PRIV(a); | 318 | |
347 | 319 | opt.index = police->tcf_index; | |
348 | opt.index = p->index; | 320 | opt.action = police->tcf_action; |
349 | opt.action = p->action; | 321 | opt.mtu = police->tcfp_mtu; |
350 | opt.mtu = p->mtu; | 322 | opt.burst = police->tcfp_burst; |
351 | opt.burst = p->burst; | 323 | opt.refcnt = police->tcf_refcnt - ref; |
352 | opt.refcnt = p->refcnt - ref; | 324 | opt.bindcnt = police->tcf_bindcnt - bind; |
353 | opt.bindcnt = p->bindcnt - bind; | 325 | if (police->tcfp_R_tab) |
354 | if (p->R_tab) | 326 | opt.rate = police->tcfp_R_tab->rate; |
355 | opt.rate = p->R_tab->rate; | ||
356 | else | 327 | else |
357 | memset(&opt.rate, 0, sizeof(opt.rate)); | 328 | memset(&opt.rate, 0, sizeof(opt.rate)); |
358 | if (p->P_tab) | 329 | if (police->tcfp_P_tab) |
359 | opt.peakrate = p->P_tab->rate; | 330 | opt.peakrate = police->tcfp_P_tab->rate; |
360 | else | 331 | else |
361 | memset(&opt.peakrate, 0, sizeof(opt.peakrate)); | 332 | memset(&opt.peakrate, 0, sizeof(opt.peakrate)); |
362 | RTA_PUT(skb, TCA_POLICE_TBF, sizeof(opt), &opt); | 333 | RTA_PUT(skb, TCA_POLICE_TBF, sizeof(opt), &opt); |
363 | if (p->result) | 334 | if (police->tcfp_result) |
364 | RTA_PUT(skb, TCA_POLICE_RESULT, sizeof(int), &p->result); | 335 | RTA_PUT(skb, TCA_POLICE_RESULT, sizeof(int), |
336 | &police->tcfp_result); | ||
365 | #ifdef CONFIG_NET_ESTIMATOR | 337 | #ifdef CONFIG_NET_ESTIMATOR |
366 | if (p->ewma_rate) | 338 | if (police->tcfp_ewma_rate) |
367 | RTA_PUT(skb, TCA_POLICE_AVRATE, 4, &p->ewma_rate); | 339 | RTA_PUT(skb, TCA_POLICE_AVRATE, 4, &police->tcfp_ewma_rate); |
368 | #endif | 340 | #endif |
369 | return skb->len; | 341 | return skb->len; |
370 | 342 | ||
@@ -379,13 +351,14 @@ MODULE_LICENSE("GPL"); | |||
379 | 351 | ||
380 | static struct tc_action_ops act_police_ops = { | 352 | static struct tc_action_ops act_police_ops = { |
381 | .kind = "police", | 353 | .kind = "police", |
354 | .hinfo = &police_hash_info, | ||
382 | .type = TCA_ID_POLICE, | 355 | .type = TCA_ID_POLICE, |
383 | .capab = TCA_CAP_NONE, | 356 | .capab = TCA_CAP_NONE, |
384 | .owner = THIS_MODULE, | 357 | .owner = THIS_MODULE, |
385 | .act = tcf_act_police, | 358 | .act = tcf_act_police, |
386 | .dump = tcf_act_police_dump, | 359 | .dump = tcf_act_police_dump, |
387 | .cleanup = tcf_act_police_cleanup, | 360 | .cleanup = tcf_act_police_cleanup, |
388 | .lookup = tcf_act_police_hash_search, | 361 | .lookup = tcf_hash_search, |
389 | .init = tcf_act_police_locate, | 362 | .init = tcf_act_police_locate, |
390 | .walk = tcf_act_police_walker | 363 | .walk = tcf_act_police_walker |
391 | }; | 364 | }; |
@@ -407,10 +380,39 @@ module_exit(police_cleanup_module); | |||
407 | 380 | ||
408 | #else /* CONFIG_NET_CLS_ACT */ | 381 | #else /* CONFIG_NET_CLS_ACT */ |
409 | 382 | ||
410 | struct tcf_police * tcf_police_locate(struct rtattr *rta, struct rtattr *est) | 383 | static struct tcf_common *tcf_police_lookup(u32 index) |
411 | { | 384 | { |
412 | unsigned h; | 385 | struct tcf_hashinfo *hinfo = &police_hash_info; |
413 | struct tcf_police *p; | 386 | struct tcf_common *p; |
387 | |||
388 | read_lock(hinfo->lock); | ||
389 | for (p = hinfo->htab[tcf_hash(index, hinfo->hmask)]; p; | ||
390 | p = p->tcfc_next) { | ||
391 | if (p->tcfc_index == index) | ||
392 | break; | ||
393 | } | ||
394 | read_unlock(hinfo->lock); | ||
395 | |||
396 | return p; | ||
397 | } | ||
398 | |||
399 | static u32 tcf_police_new_index(void) | ||
400 | { | ||
401 | u32 *idx_gen = &police_idx_gen; | ||
402 | u32 val = *idx_gen; | ||
403 | |||
404 | do { | ||
405 | if (++val == 0) | ||
406 | val = 1; | ||
407 | } while (tcf_police_lookup(val)); | ||
408 | |||
409 | return (*idx_gen = val); | ||
410 | } | ||
411 | |||
412 | struct tcf_police *tcf_police_locate(struct rtattr *rta, struct rtattr *est) | ||
413 | { | ||
414 | unsigned int h; | ||
415 | struct tcf_police *police; | ||
414 | struct rtattr *tb[TCA_POLICE_MAX]; | 416 | struct rtattr *tb[TCA_POLICE_MAX]; |
415 | struct tc_police *parm; | 417 | struct tc_police *parm; |
416 | 418 | ||
@@ -423,149 +425,158 @@ struct tcf_police * tcf_police_locate(struct rtattr *rta, struct rtattr *est) | |||
423 | 425 | ||
424 | parm = RTA_DATA(tb[TCA_POLICE_TBF-1]); | 426 | parm = RTA_DATA(tb[TCA_POLICE_TBF-1]); |
425 | 427 | ||
426 | if (parm->index && (p = tcf_police_lookup(parm->index)) != NULL) { | 428 | if (parm->index) { |
427 | p->refcnt++; | 429 | struct tcf_common *pc; |
428 | return p; | ||
429 | } | ||
430 | 430 | ||
431 | p = kzalloc(sizeof(*p), GFP_KERNEL); | 431 | pc = tcf_police_lookup(parm->index); |
432 | if (p == NULL) | 432 | if (pc) { |
433 | police = to_police(pc); | ||
434 | police->tcf_refcnt++; | ||
435 | return police; | ||
436 | } | ||
437 | } | ||
438 | police = kzalloc(sizeof(*police), GFP_KERNEL); | ||
439 | if (unlikely(!police)) | ||
433 | return NULL; | 440 | return NULL; |
434 | 441 | ||
435 | p->refcnt = 1; | 442 | police->tcf_refcnt = 1; |
436 | spin_lock_init(&p->lock); | 443 | spin_lock_init(&police->tcf_lock); |
437 | p->stats_lock = &p->lock; | 444 | police->tcf_stats_lock = &police->tcf_lock; |
438 | if (parm->rate.rate) { | 445 | if (parm->rate.rate) { |
439 | p->R_tab = qdisc_get_rtab(&parm->rate, tb[TCA_POLICE_RATE-1]); | 446 | police->tcfp_R_tab = |
440 | if (p->R_tab == NULL) | 447 | qdisc_get_rtab(&parm->rate, tb[TCA_POLICE_RATE-1]); |
448 | if (police->tcfp_R_tab == NULL) | ||
441 | goto failure; | 449 | goto failure; |
442 | if (parm->peakrate.rate) { | 450 | if (parm->peakrate.rate) { |
443 | p->P_tab = qdisc_get_rtab(&parm->peakrate, | 451 | police->tcfp_P_tab = |
444 | tb[TCA_POLICE_PEAKRATE-1]); | 452 | qdisc_get_rtab(&parm->peakrate, |
445 | if (p->P_tab == NULL) | 453 | tb[TCA_POLICE_PEAKRATE-1]); |
454 | if (police->tcfp_P_tab == NULL) | ||
446 | goto failure; | 455 | goto failure; |
447 | } | 456 | } |
448 | } | 457 | } |
449 | if (tb[TCA_POLICE_RESULT-1]) { | 458 | if (tb[TCA_POLICE_RESULT-1]) { |
450 | if (RTA_PAYLOAD(tb[TCA_POLICE_RESULT-1]) != sizeof(u32)) | 459 | if (RTA_PAYLOAD(tb[TCA_POLICE_RESULT-1]) != sizeof(u32)) |
451 | goto failure; | 460 | goto failure; |
452 | p->result = *(u32*)RTA_DATA(tb[TCA_POLICE_RESULT-1]); | 461 | police->tcfp_result = *(u32*)RTA_DATA(tb[TCA_POLICE_RESULT-1]); |
453 | } | 462 | } |
454 | #ifdef CONFIG_NET_ESTIMATOR | 463 | #ifdef CONFIG_NET_ESTIMATOR |
455 | if (tb[TCA_POLICE_AVRATE-1]) { | 464 | if (tb[TCA_POLICE_AVRATE-1]) { |
456 | if (RTA_PAYLOAD(tb[TCA_POLICE_AVRATE-1]) != sizeof(u32)) | 465 | if (RTA_PAYLOAD(tb[TCA_POLICE_AVRATE-1]) != sizeof(u32)) |
457 | goto failure; | 466 | goto failure; |
458 | p->ewma_rate = *(u32*)RTA_DATA(tb[TCA_POLICE_AVRATE-1]); | 467 | police->tcfp_ewma_rate = |
468 | *(u32*)RTA_DATA(tb[TCA_POLICE_AVRATE-1]); | ||
459 | } | 469 | } |
460 | #endif | 470 | #endif |
461 | p->toks = p->burst = parm->burst; | 471 | police->tcfp_toks = police->tcfp_burst = parm->burst; |
462 | p->mtu = parm->mtu; | 472 | police->tcfp_mtu = parm->mtu; |
463 | if (p->mtu == 0) { | 473 | if (police->tcfp_mtu == 0) { |
464 | p->mtu = ~0; | 474 | police->tcfp_mtu = ~0; |
465 | if (p->R_tab) | 475 | if (police->tcfp_R_tab) |
466 | p->mtu = 255<<p->R_tab->rate.cell_log; | 476 | police->tcfp_mtu = 255<<police->tcfp_R_tab->rate.cell_log; |
467 | } | 477 | } |
468 | if (p->P_tab) | 478 | if (police->tcfp_P_tab) |
469 | p->ptoks = L2T_P(p, p->mtu); | 479 | police->tcfp_ptoks = L2T_P(police, police->tcfp_mtu); |
470 | PSCHED_GET_TIME(p->t_c); | 480 | PSCHED_GET_TIME(police->tcfp_t_c); |
471 | p->index = parm->index ? : tcf_police_new_index(); | 481 | police->tcf_index = parm->index ? parm->index : |
472 | p->action = parm->action; | 482 | tcf_police_new_index(); |
483 | police->tcf_action = parm->action; | ||
473 | #ifdef CONFIG_NET_ESTIMATOR | 484 | #ifdef CONFIG_NET_ESTIMATOR |
474 | if (est) | 485 | if (est) |
475 | gen_new_estimator(&p->bstats, &p->rate_est, p->stats_lock, est); | 486 | gen_new_estimator(&police->tcf_bstats, &police->tcf_rate_est, |
487 | police->tcf_stats_lock, est); | ||
476 | #endif | 488 | #endif |
477 | h = tcf_police_hash(p->index); | 489 | h = tcf_hash(police->tcf_index, POL_TAB_MASK); |
478 | write_lock_bh(&police_lock); | 490 | write_lock_bh(&police_lock); |
479 | p->next = tcf_police_ht[h]; | 491 | police->tcf_next = tcf_police_ht[h]; |
480 | tcf_police_ht[h] = p; | 492 | tcf_police_ht[h] = &police->common; |
481 | write_unlock_bh(&police_lock); | 493 | write_unlock_bh(&police_lock); |
482 | return p; | 494 | return police; |
483 | 495 | ||
484 | failure: | 496 | failure: |
485 | if (p->R_tab) | 497 | if (police->tcfp_R_tab) |
486 | qdisc_put_rtab(p->R_tab); | 498 | qdisc_put_rtab(police->tcfp_R_tab); |
487 | kfree(p); | 499 | kfree(police); |
488 | return NULL; | 500 | return NULL; |
489 | } | 501 | } |
490 | 502 | ||
491 | int tcf_police(struct sk_buff *skb, struct tcf_police *p) | 503 | int tcf_police(struct sk_buff *skb, struct tcf_police *police) |
492 | { | 504 | { |
493 | psched_time_t now; | 505 | psched_time_t now; |
494 | long toks; | 506 | long toks; |
495 | long ptoks = 0; | 507 | long ptoks = 0; |
496 | 508 | ||
497 | spin_lock(&p->lock); | 509 | spin_lock(&police->tcf_lock); |
498 | 510 | ||
499 | p->bstats.bytes += skb->len; | 511 | police->tcf_bstats.bytes += skb->len; |
500 | p->bstats.packets++; | 512 | police->tcf_bstats.packets++; |
501 | 513 | ||
502 | #ifdef CONFIG_NET_ESTIMATOR | 514 | #ifdef CONFIG_NET_ESTIMATOR |
503 | if (p->ewma_rate && p->rate_est.bps >= p->ewma_rate) { | 515 | if (police->tcfp_ewma_rate && |
504 | p->qstats.overlimits++; | 516 | police->tcf_rate_est.bps >= police->tcfp_ewma_rate) { |
505 | spin_unlock(&p->lock); | 517 | police->tcf_qstats.overlimits++; |
506 | return p->action; | 518 | spin_unlock(&police->tcf_lock); |
519 | return police->tcf_action; | ||
507 | } | 520 | } |
508 | #endif | 521 | #endif |
509 | 522 | if (skb->len <= police->tcfp_mtu) { | |
510 | if (skb->len <= p->mtu) { | 523 | if (police->tcfp_R_tab == NULL) { |
511 | if (p->R_tab == NULL) { | 524 | spin_unlock(&police->tcf_lock); |
512 | spin_unlock(&p->lock); | 525 | return police->tcfp_result; |
513 | return p->result; | ||
514 | } | 526 | } |
515 | 527 | ||
516 | PSCHED_GET_TIME(now); | 528 | PSCHED_GET_TIME(now); |
517 | 529 | toks = PSCHED_TDIFF_SAFE(now, police->tcfp_t_c, | |
518 | toks = PSCHED_TDIFF_SAFE(now, p->t_c, p->burst); | 530 | police->tcfp_burst); |
519 | 531 | if (police->tcfp_P_tab) { | |
520 | if (p->P_tab) { | 532 | ptoks = toks + police->tcfp_ptoks; |
521 | ptoks = toks + p->ptoks; | 533 | if (ptoks > (long)L2T_P(police, police->tcfp_mtu)) |
522 | if (ptoks > (long)L2T_P(p, p->mtu)) | 534 | ptoks = (long)L2T_P(police, police->tcfp_mtu); |
523 | ptoks = (long)L2T_P(p, p->mtu); | 535 | ptoks -= L2T_P(police, skb->len); |
524 | ptoks -= L2T_P(p, skb->len); | ||
525 | } | 536 | } |
526 | toks += p->toks; | 537 | toks += police->tcfp_toks; |
527 | if (toks > (long)p->burst) | 538 | if (toks > (long)police->tcfp_burst) |
528 | toks = p->burst; | 539 | toks = police->tcfp_burst; |
529 | toks -= L2T(p, skb->len); | 540 | toks -= L2T(police, skb->len); |
530 | |||
531 | if ((toks|ptoks) >= 0) { | 541 | if ((toks|ptoks) >= 0) { |
532 | p->t_c = now; | 542 | police->tcfp_t_c = now; |
533 | p->toks = toks; | 543 | police->tcfp_toks = toks; |
534 | p->ptoks = ptoks; | 544 | police->tcfp_ptoks = ptoks; |
535 | spin_unlock(&p->lock); | 545 | spin_unlock(&police->tcf_lock); |
536 | return p->result; | 546 | return police->tcfp_result; |
537 | } | 547 | } |
538 | } | 548 | } |
539 | 549 | ||
540 | p->qstats.overlimits++; | 550 | police->tcf_qstats.overlimits++; |
541 | spin_unlock(&p->lock); | 551 | spin_unlock(&police->tcf_lock); |
542 | return p->action; | 552 | return police->tcf_action; |
543 | } | 553 | } |
544 | EXPORT_SYMBOL(tcf_police); | 554 | EXPORT_SYMBOL(tcf_police); |
545 | 555 | ||
546 | int tcf_police_dump(struct sk_buff *skb, struct tcf_police *p) | 556 | int tcf_police_dump(struct sk_buff *skb, struct tcf_police *police) |
547 | { | 557 | { |
548 | unsigned char *b = skb->tail; | 558 | unsigned char *b = skb->tail; |
549 | struct tc_police opt; | 559 | struct tc_police opt; |
550 | 560 | ||
551 | opt.index = p->index; | 561 | opt.index = police->tcf_index; |
552 | opt.action = p->action; | 562 | opt.action = police->tcf_action; |
553 | opt.mtu = p->mtu; | 563 | opt.mtu = police->tcfp_mtu; |
554 | opt.burst = p->burst; | 564 | opt.burst = police->tcfp_burst; |
555 | if (p->R_tab) | 565 | if (police->tcfp_R_tab) |
556 | opt.rate = p->R_tab->rate; | 566 | opt.rate = police->tcfp_R_tab->rate; |
557 | else | 567 | else |
558 | memset(&opt.rate, 0, sizeof(opt.rate)); | 568 | memset(&opt.rate, 0, sizeof(opt.rate)); |
559 | if (p->P_tab) | 569 | if (police->tcfp_P_tab) |
560 | opt.peakrate = p->P_tab->rate; | 570 | opt.peakrate = police->tcfp_P_tab->rate; |
561 | else | 571 | else |
562 | memset(&opt.peakrate, 0, sizeof(opt.peakrate)); | 572 | memset(&opt.peakrate, 0, sizeof(opt.peakrate)); |
563 | RTA_PUT(skb, TCA_POLICE_TBF, sizeof(opt), &opt); | 573 | RTA_PUT(skb, TCA_POLICE_TBF, sizeof(opt), &opt); |
564 | if (p->result) | 574 | if (police->tcfp_result) |
565 | RTA_PUT(skb, TCA_POLICE_RESULT, sizeof(int), &p->result); | 575 | RTA_PUT(skb, TCA_POLICE_RESULT, sizeof(int), |
576 | &police->tcfp_result); | ||
566 | #ifdef CONFIG_NET_ESTIMATOR | 577 | #ifdef CONFIG_NET_ESTIMATOR |
567 | if (p->ewma_rate) | 578 | if (police->tcfp_ewma_rate) |
568 | RTA_PUT(skb, TCA_POLICE_AVRATE, 4, &p->ewma_rate); | 579 | RTA_PUT(skb, TCA_POLICE_AVRATE, 4, &police->tcfp_ewma_rate); |
569 | #endif | 580 | #endif |
570 | return skb->len; | 581 | return skb->len; |
571 | 582 | ||
@@ -574,19 +585,20 @@ rtattr_failure: | |||
574 | return -1; | 585 | return -1; |
575 | } | 586 | } |
576 | 587 | ||
577 | int tcf_police_dump_stats(struct sk_buff *skb, struct tcf_police *p) | 588 | int tcf_police_dump_stats(struct sk_buff *skb, struct tcf_police *police) |
578 | { | 589 | { |
579 | struct gnet_dump d; | 590 | struct gnet_dump d; |
580 | 591 | ||
581 | if (gnet_stats_start_copy_compat(skb, TCA_STATS2, TCA_STATS, | 592 | if (gnet_stats_start_copy_compat(skb, TCA_STATS2, TCA_STATS, |
582 | TCA_XSTATS, p->stats_lock, &d) < 0) | 593 | TCA_XSTATS, police->tcf_stats_lock, |
594 | &d) < 0) | ||
583 | goto errout; | 595 | goto errout; |
584 | 596 | ||
585 | if (gnet_stats_copy_basic(&d, &p->bstats) < 0 || | 597 | if (gnet_stats_copy_basic(&d, &police->tcf_bstats) < 0 || |
586 | #ifdef CONFIG_NET_ESTIMATOR | 598 | #ifdef CONFIG_NET_ESTIMATOR |
587 | gnet_stats_copy_rate_est(&d, &p->rate_est) < 0 || | 599 | gnet_stats_copy_rate_est(&d, &police->tcf_rate_est) < 0 || |
588 | #endif | 600 | #endif |
589 | gnet_stats_copy_queue(&d, &p->qstats) < 0) | 601 | gnet_stats_copy_queue(&d, &police->tcf_qstats) < 0) |
590 | goto errout; | 602 | goto errout; |
591 | 603 | ||
592 | if (gnet_stats_finish_copy(&d) < 0) | 604 | if (gnet_stats_finish_copy(&d) < 0) |
diff --git a/net/sched/act_simple.c b/net/sched/act_simple.c index 17105c82537f..901571a67707 100644 --- a/net/sched/act_simple.c +++ b/net/sched/act_simple.c | |||
@@ -20,54 +20,175 @@ | |||
20 | 20 | ||
21 | #define TCA_ACT_SIMP 22 | 21 | #define TCA_ACT_SIMP 22 |
22 | 22 | ||
23 | /* XXX: Hide all these common elements under some macro | ||
24 | * probably | ||
25 | */ | ||
26 | #include <linux/tc_act/tc_defact.h> | 23 | #include <linux/tc_act/tc_defact.h> |
27 | #include <net/tc_act/tc_defact.h> | 24 | #include <net/tc_act/tc_defact.h> |
28 | 25 | ||
29 | /* use generic hash table with 8 buckets */ | 26 | #define SIMP_TAB_MASK 7 |
30 | #define MY_TAB_SIZE 8 | 27 | static struct tcf_common *tcf_simp_ht[SIMP_TAB_MASK + 1]; |
31 | #define MY_TAB_MASK (MY_TAB_SIZE - 1) | 28 | static u32 simp_idx_gen; |
32 | static u32 idx_gen; | ||
33 | static struct tcf_defact *tcf_simp_ht[MY_TAB_SIZE]; | ||
34 | static DEFINE_RWLOCK(simp_lock); | 29 | static DEFINE_RWLOCK(simp_lock); |
35 | 30 | ||
36 | /* override the defaults */ | 31 | static struct tcf_hashinfo simp_hash_info = { |
37 | #define tcf_st tcf_defact | 32 | .htab = tcf_simp_ht, |
38 | #define tc_st tc_defact | 33 | .hmask = SIMP_TAB_MASK, |
39 | #define tcf_t_lock simp_lock | 34 | .lock = &simp_lock, |
40 | #define tcf_ht tcf_simp_ht | 35 | }; |
41 | |||
42 | #define CONFIG_NET_ACT_INIT 1 | ||
43 | #include <net/pkt_act.h> | ||
44 | #include <net/act_generic.h> | ||
45 | 36 | ||
46 | static int tcf_simp(struct sk_buff *skb, struct tc_action *a, struct tcf_result *res) | 37 | static int tcf_simp(struct sk_buff *skb, struct tc_action *a, struct tcf_result *res) |
47 | { | 38 | { |
48 | struct tcf_defact *p = PRIV(a, defact); | 39 | struct tcf_defact *d = a->priv; |
49 | 40 | ||
50 | spin_lock(&p->lock); | 41 | spin_lock(&d->tcf_lock); |
51 | p->tm.lastuse = jiffies; | 42 | d->tcf_tm.lastuse = jiffies; |
52 | p->bstats.bytes += skb->len; | 43 | d->tcf_bstats.bytes += skb->len; |
53 | p->bstats.packets++; | 44 | d->tcf_bstats.packets++; |
54 | 45 | ||
55 | /* print policy string followed by _ then packet count | 46 | /* print policy string followed by _ then packet count |
56 | * Example if this was the 3rd packet and the string was "hello" | 47 | * Example if this was the 3rd packet and the string was "hello" |
57 | * then it would look like "hello_3" (without quotes) | 48 | * then it would look like "hello_3" (without quotes) |
58 | **/ | 49 | **/ |
59 | printk("simple: %s_%d\n", (char *)p->defdata, p->bstats.packets); | 50 | printk("simple: %s_%d\n", |
60 | spin_unlock(&p->lock); | 51 | (char *)d->tcfd_defdata, d->tcf_bstats.packets); |
61 | return p->action; | 52 | spin_unlock(&d->tcf_lock); |
53 | return d->tcf_action; | ||
54 | } | ||
55 | |||
56 | static int tcf_simp_release(struct tcf_defact *d, int bind) | ||
57 | { | ||
58 | int ret = 0; | ||
59 | if (d) { | ||
60 | if (bind) | ||
61 | d->tcf_bindcnt--; | ||
62 | d->tcf_refcnt--; | ||
63 | if (d->tcf_bindcnt <= 0 && d->tcf_refcnt <= 0) { | ||
64 | kfree(d->tcfd_defdata); | ||
65 | tcf_hash_destroy(&d->common, &simp_hash_info); | ||
66 | ret = 1; | ||
67 | } | ||
68 | } | ||
69 | return ret; | ||
70 | } | ||
71 | |||
72 | static int alloc_defdata(struct tcf_defact *d, u32 datalen, void *defdata) | ||
73 | { | ||
74 | d->tcfd_defdata = kmalloc(datalen, GFP_KERNEL); | ||
75 | if (unlikely(!d->tcfd_defdata)) | ||
76 | return -ENOMEM; | ||
77 | d->tcfd_datalen = datalen; | ||
78 | memcpy(d->tcfd_defdata, defdata, datalen); | ||
79 | return 0; | ||
80 | } | ||
81 | |||
82 | static int realloc_defdata(struct tcf_defact *d, u32 datalen, void *defdata) | ||
83 | { | ||
84 | kfree(d->tcfd_defdata); | ||
85 | return alloc_defdata(d, datalen, defdata); | ||
86 | } | ||
87 | |||
88 | static int tcf_simp_init(struct rtattr *rta, struct rtattr *est, | ||
89 | struct tc_action *a, int ovr, int bind) | ||
90 | { | ||
91 | struct rtattr *tb[TCA_DEF_MAX]; | ||
92 | struct tc_defact *parm; | ||
93 | struct tcf_defact *d; | ||
94 | struct tcf_common *pc; | ||
95 | void *defdata; | ||
96 | u32 datalen = 0; | ||
97 | int ret = 0; | ||
98 | |||
99 | if (rta == NULL || rtattr_parse_nested(tb, TCA_DEF_MAX, rta) < 0) | ||
100 | return -EINVAL; | ||
101 | |||
102 | if (tb[TCA_DEF_PARMS - 1] == NULL || | ||
103 | RTA_PAYLOAD(tb[TCA_DEF_PARMS - 1]) < sizeof(*parm)) | ||
104 | return -EINVAL; | ||
105 | |||
106 | parm = RTA_DATA(tb[TCA_DEF_PARMS - 1]); | ||
107 | defdata = RTA_DATA(tb[TCA_DEF_DATA - 1]); | ||
108 | if (defdata == NULL) | ||
109 | return -EINVAL; | ||
110 | |||
111 | datalen = RTA_PAYLOAD(tb[TCA_DEF_DATA - 1]); | ||
112 | if (datalen <= 0) | ||
113 | return -EINVAL; | ||
114 | |||
115 | pc = tcf_hash_check(parm->index, a, bind, &simp_hash_info); | ||
116 | if (!pc) { | ||
117 | pc = tcf_hash_create(parm->index, est, a, sizeof(*d), bind, | ||
118 | &simp_idx_gen, &simp_hash_info); | ||
119 | if (unlikely(!pc)) | ||
120 | return -ENOMEM; | ||
121 | |||
122 | d = to_defact(pc); | ||
123 | ret = alloc_defdata(d, datalen, defdata); | ||
124 | if (ret < 0) { | ||
125 | kfree(pc); | ||
126 | return ret; | ||
127 | } | ||
128 | ret = ACT_P_CREATED; | ||
129 | } else { | ||
130 | d = to_defact(pc); | ||
131 | if (!ovr) { | ||
132 | tcf_simp_release(d, bind); | ||
133 | return -EEXIST; | ||
134 | } | ||
135 | realloc_defdata(d, datalen, defdata); | ||
136 | } | ||
137 | |||
138 | spin_lock_bh(&d->tcf_lock); | ||
139 | d->tcf_action = parm->action; | ||
140 | spin_unlock_bh(&d->tcf_lock); | ||
141 | |||
142 | if (ret == ACT_P_CREATED) | ||
143 | tcf_hash_insert(pc, &simp_hash_info); | ||
144 | return ret; | ||
145 | } | ||
146 | |||
147 | static inline int tcf_simp_cleanup(struct tc_action *a, int bind) | ||
148 | { | ||
149 | struct tcf_defact *d = a->priv; | ||
150 | |||
151 | if (d) | ||
152 | return tcf_simp_release(d, bind); | ||
153 | return 0; | ||
154 | } | ||
155 | |||
156 | static inline int tcf_simp_dump(struct sk_buff *skb, struct tc_action *a, | ||
157 | int bind, int ref) | ||
158 | { | ||
159 | unsigned char *b = skb->tail; | ||
160 | struct tcf_defact *d = a->priv; | ||
161 | struct tc_defact opt; | ||
162 | struct tcf_t t; | ||
163 | |||
164 | opt.index = d->tcf_index; | ||
165 | opt.refcnt = d->tcf_refcnt - ref; | ||
166 | opt.bindcnt = d->tcf_bindcnt - bind; | ||
167 | opt.action = d->tcf_action; | ||
168 | RTA_PUT(skb, TCA_DEF_PARMS, sizeof(opt), &opt); | ||
169 | RTA_PUT(skb, TCA_DEF_DATA, d->tcfd_datalen, d->tcfd_defdata); | ||
170 | t.install = jiffies_to_clock_t(jiffies - d->tcf_tm.install); | ||
171 | t.lastuse = jiffies_to_clock_t(jiffies - d->tcf_tm.lastuse); | ||
172 | t.expires = jiffies_to_clock_t(d->tcf_tm.expires); | ||
173 | RTA_PUT(skb, TCA_DEF_TM, sizeof(t), &t); | ||
174 | return skb->len; | ||
175 | |||
176 | rtattr_failure: | ||
177 | skb_trim(skb, b - skb->data); | ||
178 | return -1; | ||
62 | } | 179 | } |
63 | 180 | ||
64 | static struct tc_action_ops act_simp_ops = { | 181 | static struct tc_action_ops act_simp_ops = { |
65 | .kind = "simple", | 182 | .kind = "simple", |
66 | .type = TCA_ACT_SIMP, | 183 | .hinfo = &simp_hash_info, |
67 | .capab = TCA_CAP_NONE, | 184 | .type = TCA_ACT_SIMP, |
68 | .owner = THIS_MODULE, | 185 | .capab = TCA_CAP_NONE, |
69 | .act = tcf_simp, | 186 | .owner = THIS_MODULE, |
70 | tca_use_default_ops | 187 | .act = tcf_simp, |
188 | .dump = tcf_simp_dump, | ||
189 | .cleanup = tcf_simp_cleanup, | ||
190 | .init = tcf_simp_init, | ||
191 | .walk = tcf_generic_walker, | ||
71 | }; | 192 | }; |
72 | 193 | ||
73 | MODULE_AUTHOR("Jamal Hadi Salim(2005)"); | 194 | MODULE_AUTHOR("Jamal Hadi Salim(2005)"); |
diff --git a/net/sched/cls_fw.c b/net/sched/cls_fw.c index e6973d9b686d..e54acc6bcccd 100644 --- a/net/sched/cls_fw.c +++ b/net/sched/cls_fw.c | |||
@@ -50,6 +50,7 @@ | |||
50 | struct fw_head | 50 | struct fw_head |
51 | { | 51 | { |
52 | struct fw_filter *ht[HTSIZE]; | 52 | struct fw_filter *ht[HTSIZE]; |
53 | u32 mask; | ||
53 | }; | 54 | }; |
54 | 55 | ||
55 | struct fw_filter | 56 | struct fw_filter |
@@ -101,7 +102,7 @@ static int fw_classify(struct sk_buff *skb, struct tcf_proto *tp, | |||
101 | struct fw_filter *f; | 102 | struct fw_filter *f; |
102 | int r; | 103 | int r; |
103 | #ifdef CONFIG_NETFILTER | 104 | #ifdef CONFIG_NETFILTER |
104 | u32 id = skb->nfmark; | 105 | u32 id = skb->nfmark & head->mask; |
105 | #else | 106 | #else |
106 | u32 id = 0; | 107 | u32 id = 0; |
107 | #endif | 108 | #endif |
@@ -209,7 +210,9 @@ static int | |||
209 | fw_change_attrs(struct tcf_proto *tp, struct fw_filter *f, | 210 | fw_change_attrs(struct tcf_proto *tp, struct fw_filter *f, |
210 | struct rtattr **tb, struct rtattr **tca, unsigned long base) | 211 | struct rtattr **tb, struct rtattr **tca, unsigned long base) |
211 | { | 212 | { |
213 | struct fw_head *head = (struct fw_head *)tp->root; | ||
212 | struct tcf_exts e; | 214 | struct tcf_exts e; |
215 | u32 mask; | ||
213 | int err; | 216 | int err; |
214 | 217 | ||
215 | err = tcf_exts_validate(tp, tb, tca[TCA_RATE-1], &e, &fw_ext_map); | 218 | err = tcf_exts_validate(tp, tb, tca[TCA_RATE-1], &e, &fw_ext_map); |
@@ -232,6 +235,15 @@ fw_change_attrs(struct tcf_proto *tp, struct fw_filter *f, | |||
232 | } | 235 | } |
233 | #endif /* CONFIG_NET_CLS_IND */ | 236 | #endif /* CONFIG_NET_CLS_IND */ |
234 | 237 | ||
238 | if (tb[TCA_FW_MASK-1]) { | ||
239 | if (RTA_PAYLOAD(tb[TCA_FW_MASK-1]) != sizeof(u32)) | ||
240 | goto errout; | ||
241 | mask = *(u32*)RTA_DATA(tb[TCA_FW_MASK-1]); | ||
242 | if (mask != head->mask) | ||
243 | goto errout; | ||
244 | } else if (head->mask != 0xFFFFFFFF) | ||
245 | goto errout; | ||
246 | |||
235 | tcf_exts_change(tp, &f->exts, &e); | 247 | tcf_exts_change(tp, &f->exts, &e); |
236 | 248 | ||
237 | return 0; | 249 | return 0; |
@@ -267,9 +279,17 @@ static int fw_change(struct tcf_proto *tp, unsigned long base, | |||
267 | return -EINVAL; | 279 | return -EINVAL; |
268 | 280 | ||
269 | if (head == NULL) { | 281 | if (head == NULL) { |
282 | u32 mask = 0xFFFFFFFF; | ||
283 | if (tb[TCA_FW_MASK-1]) { | ||
284 | if (RTA_PAYLOAD(tb[TCA_FW_MASK-1]) != sizeof(u32)) | ||
285 | return -EINVAL; | ||
286 | mask = *(u32*)RTA_DATA(tb[TCA_FW_MASK-1]); | ||
287 | } | ||
288 | |||
270 | head = kzalloc(sizeof(struct fw_head), GFP_KERNEL); | 289 | head = kzalloc(sizeof(struct fw_head), GFP_KERNEL); |
271 | if (head == NULL) | 290 | if (head == NULL) |
272 | return -ENOBUFS; | 291 | return -ENOBUFS; |
292 | head->mask = mask; | ||
273 | 293 | ||
274 | tcf_tree_lock(tp); | 294 | tcf_tree_lock(tp); |
275 | tp->root = head; | 295 | tp->root = head; |
@@ -330,6 +350,7 @@ static void fw_walk(struct tcf_proto *tp, struct tcf_walker *arg) | |||
330 | static int fw_dump(struct tcf_proto *tp, unsigned long fh, | 350 | static int fw_dump(struct tcf_proto *tp, unsigned long fh, |
331 | struct sk_buff *skb, struct tcmsg *t) | 351 | struct sk_buff *skb, struct tcmsg *t) |
332 | { | 352 | { |
353 | struct fw_head *head = (struct fw_head *)tp->root; | ||
333 | struct fw_filter *f = (struct fw_filter*)fh; | 354 | struct fw_filter *f = (struct fw_filter*)fh; |
334 | unsigned char *b = skb->tail; | 355 | unsigned char *b = skb->tail; |
335 | struct rtattr *rta; | 356 | struct rtattr *rta; |
@@ -351,6 +372,8 @@ static int fw_dump(struct tcf_proto *tp, unsigned long fh, | |||
351 | if (strlen(f->indev)) | 372 | if (strlen(f->indev)) |
352 | RTA_PUT(skb, TCA_FW_INDEV, IFNAMSIZ, f->indev); | 373 | RTA_PUT(skb, TCA_FW_INDEV, IFNAMSIZ, f->indev); |
353 | #endif /* CONFIG_NET_CLS_IND */ | 374 | #endif /* CONFIG_NET_CLS_IND */ |
375 | if (head->mask != 0xFFFFFFFF) | ||
376 | RTA_PUT(skb, TCA_FW_MASK, 4, &head->mask); | ||
354 | 377 | ||
355 | if (tcf_exts_dump(skb, &f->exts, &fw_ext_map) < 0) | 378 | if (tcf_exts_dump(skb, &f->exts, &fw_ext_map) < 0) |
356 | goto rtattr_failure; | 379 | goto rtattr_failure; |
diff --git a/net/sched/sch_htb.c b/net/sched/sch_htb.c index 880a3394a51f..bb3ddd4784b1 100644 --- a/net/sched/sch_htb.c +++ b/net/sched/sch_htb.c | |||
@@ -1,4 +1,4 @@ | |||
1 | /* vim: ts=8 sw=8 | 1 | /* |
2 | * net/sched/sch_htb.c Hierarchical token bucket, feed tree version | 2 | * net/sched/sch_htb.c Hierarchical token bucket, feed tree version |
3 | * | 3 | * |
4 | * This program is free software; you can redistribute it and/or | 4 | * This program is free software; you can redistribute it and/or |
@@ -68,218 +68,165 @@ | |||
68 | one less than their parent. | 68 | one less than their parent. |
69 | */ | 69 | */ |
70 | 70 | ||
71 | #define HTB_HSIZE 16 /* classid hash size */ | 71 | #define HTB_HSIZE 16 /* classid hash size */ |
72 | #define HTB_EWMAC 2 /* rate average over HTB_EWMAC*HTB_HSIZE sec */ | 72 | #define HTB_EWMAC 2 /* rate average over HTB_EWMAC*HTB_HSIZE sec */ |
73 | #undef HTB_DEBUG /* compile debugging support (activated by tc tool) */ | 73 | #define HTB_RATECM 1 /* whether to use rate computer */ |
74 | #define HTB_RATECM 1 /* whether to use rate computer */ | 74 | #define HTB_HYSTERESIS 1 /* whether to use mode hysteresis for speedup */ |
75 | #define HTB_HYSTERESIS 1/* whether to use mode hysteresis for speedup */ | 75 | #define HTB_VER 0x30011 /* major must be matched with number suplied by TC as version */ |
76 | #define HTB_QLOCK(S) spin_lock_bh(&(S)->dev->queue_lock) | ||
77 | #define HTB_QUNLOCK(S) spin_unlock_bh(&(S)->dev->queue_lock) | ||
78 | #define HTB_VER 0x30011 /* major must be matched with number suplied by TC as version */ | ||
79 | 76 | ||
80 | #if HTB_VER >> 16 != TC_HTB_PROTOVER | 77 | #if HTB_VER >> 16 != TC_HTB_PROTOVER |
81 | #error "Mismatched sch_htb.c and pkt_sch.h" | 78 | #error "Mismatched sch_htb.c and pkt_sch.h" |
82 | #endif | 79 | #endif |
83 | 80 | ||
84 | /* debugging support; S is subsystem, these are defined: | ||
85 | 0 - netlink messages | ||
86 | 1 - enqueue | ||
87 | 2 - drop & requeue | ||
88 | 3 - dequeue main | ||
89 | 4 - dequeue one prio DRR part | ||
90 | 5 - dequeue class accounting | ||
91 | 6 - class overlimit status computation | ||
92 | 7 - hint tree | ||
93 | 8 - event queue | ||
94 | 10 - rate estimator | ||
95 | 11 - classifier | ||
96 | 12 - fast dequeue cache | ||
97 | |||
98 | L is level; 0 = none, 1 = basic info, 2 = detailed, 3 = full | ||
99 | q->debug uint32 contains 16 2-bit fields one for subsystem starting | ||
100 | from LSB | ||
101 | */ | ||
102 | #ifdef HTB_DEBUG | ||
103 | #define HTB_DBG_COND(S,L) (((q->debug>>(2*S))&3) >= L) | ||
104 | #define HTB_DBG(S,L,FMT,ARG...) if (HTB_DBG_COND(S,L)) \ | ||
105 | printk(KERN_DEBUG FMT,##ARG) | ||
106 | #define HTB_CHCL(cl) BUG_TRAP((cl)->magic == HTB_CMAGIC) | ||
107 | #define HTB_PASSQ q, | ||
108 | #define HTB_ARGQ struct htb_sched *q, | ||
109 | #define static | ||
110 | #undef __inline__ | ||
111 | #define __inline__ | ||
112 | #undef inline | ||
113 | #define inline | ||
114 | #define HTB_CMAGIC 0xFEFAFEF1 | ||
115 | #define htb_safe_rb_erase(N,R) do { BUG_TRAP((N)->rb_color != -1); \ | ||
116 | if ((N)->rb_color == -1) break; \ | ||
117 | rb_erase(N,R); \ | ||
118 | (N)->rb_color = -1; } while (0) | ||
119 | #else | ||
120 | #define HTB_DBG_COND(S,L) (0) | ||
121 | #define HTB_DBG(S,L,FMT,ARG...) | ||
122 | #define HTB_PASSQ | ||
123 | #define HTB_ARGQ | ||
124 | #define HTB_CHCL(cl) | ||
125 | #define htb_safe_rb_erase(N,R) rb_erase(N,R) | ||
126 | #endif | ||
127 | |||
128 | |||
129 | /* used internaly to keep status of single class */ | 81 | /* used internaly to keep status of single class */ |
130 | enum htb_cmode { | 82 | enum htb_cmode { |
131 | HTB_CANT_SEND, /* class can't send and can't borrow */ | 83 | HTB_CANT_SEND, /* class can't send and can't borrow */ |
132 | HTB_MAY_BORROW, /* class can't send but may borrow */ | 84 | HTB_MAY_BORROW, /* class can't send but may borrow */ |
133 | HTB_CAN_SEND /* class can send */ | 85 | HTB_CAN_SEND /* class can send */ |
134 | }; | 86 | }; |
135 | 87 | ||
136 | /* interior & leaf nodes; props specific to leaves are marked L: */ | 88 | /* interior & leaf nodes; props specific to leaves are marked L: */ |
137 | struct htb_class | 89 | struct htb_class { |
138 | { | 90 | /* general class parameters */ |
139 | #ifdef HTB_DEBUG | 91 | u32 classid; |
140 | unsigned magic; | 92 | struct gnet_stats_basic bstats; |
141 | #endif | 93 | struct gnet_stats_queue qstats; |
142 | /* general class parameters */ | 94 | struct gnet_stats_rate_est rate_est; |
143 | u32 classid; | 95 | struct tc_htb_xstats xstats; /* our special stats */ |
144 | struct gnet_stats_basic bstats; | 96 | int refcnt; /* usage count of this class */ |
145 | struct gnet_stats_queue qstats; | ||
146 | struct gnet_stats_rate_est rate_est; | ||
147 | struct tc_htb_xstats xstats;/* our special stats */ | ||
148 | int refcnt; /* usage count of this class */ | ||
149 | 97 | ||
150 | #ifdef HTB_RATECM | 98 | #ifdef HTB_RATECM |
151 | /* rate measurement counters */ | 99 | /* rate measurement counters */ |
152 | unsigned long rate_bytes,sum_bytes; | 100 | unsigned long rate_bytes, sum_bytes; |
153 | unsigned long rate_packets,sum_packets; | 101 | unsigned long rate_packets, sum_packets; |
154 | #endif | 102 | #endif |
155 | 103 | ||
156 | /* topology */ | 104 | /* topology */ |
157 | int level; /* our level (see above) */ | 105 | int level; /* our level (see above) */ |
158 | struct htb_class *parent; /* parent class */ | 106 | struct htb_class *parent; /* parent class */ |
159 | struct list_head hlist; /* classid hash list item */ | 107 | struct hlist_node hlist; /* classid hash list item */ |
160 | struct list_head sibling; /* sibling list item */ | 108 | struct list_head sibling; /* sibling list item */ |
161 | struct list_head children; /* children list */ | 109 | struct list_head children; /* children list */ |
162 | 110 | ||
163 | union { | 111 | union { |
164 | struct htb_class_leaf { | 112 | struct htb_class_leaf { |
165 | struct Qdisc *q; | 113 | struct Qdisc *q; |
166 | int prio; | 114 | int prio; |
167 | int aprio; | 115 | int aprio; |
168 | int quantum; | 116 | int quantum; |
169 | int deficit[TC_HTB_MAXDEPTH]; | 117 | int deficit[TC_HTB_MAXDEPTH]; |
170 | struct list_head drop_list; | 118 | struct list_head drop_list; |
171 | } leaf; | 119 | } leaf; |
172 | struct htb_class_inner { | 120 | struct htb_class_inner { |
173 | struct rb_root feed[TC_HTB_NUMPRIO]; /* feed trees */ | 121 | struct rb_root feed[TC_HTB_NUMPRIO]; /* feed trees */ |
174 | struct rb_node *ptr[TC_HTB_NUMPRIO]; /* current class ptr */ | 122 | struct rb_node *ptr[TC_HTB_NUMPRIO]; /* current class ptr */ |
175 | /* When class changes from state 1->2 and disconnects from | 123 | /* When class changes from state 1->2 and disconnects from |
176 | parent's feed then we lost ptr value and start from the | 124 | parent's feed then we lost ptr value and start from the |
177 | first child again. Here we store classid of the | 125 | first child again. Here we store classid of the |
178 | last valid ptr (used when ptr is NULL). */ | 126 | last valid ptr (used when ptr is NULL). */ |
179 | u32 last_ptr_id[TC_HTB_NUMPRIO]; | 127 | u32 last_ptr_id[TC_HTB_NUMPRIO]; |
180 | } inner; | 128 | } inner; |
181 | } un; | 129 | } un; |
182 | struct rb_node node[TC_HTB_NUMPRIO]; /* node for self or feed tree */ | 130 | struct rb_node node[TC_HTB_NUMPRIO]; /* node for self or feed tree */ |
183 | struct rb_node pq_node; /* node for event queue */ | 131 | struct rb_node pq_node; /* node for event queue */ |
184 | unsigned long pq_key; /* the same type as jiffies global */ | 132 | unsigned long pq_key; /* the same type as jiffies global */ |
185 | 133 | ||
186 | int prio_activity; /* for which prios are we active */ | 134 | int prio_activity; /* for which prios are we active */ |
187 | enum htb_cmode cmode; /* current mode of the class */ | 135 | enum htb_cmode cmode; /* current mode of the class */ |
188 | 136 | ||
189 | /* class attached filters */ | 137 | /* class attached filters */ |
190 | struct tcf_proto *filter_list; | 138 | struct tcf_proto *filter_list; |
191 | int filter_cnt; | 139 | int filter_cnt; |
192 | 140 | ||
193 | int warned; /* only one warning about non work conserving .. */ | 141 | int warned; /* only one warning about non work conserving .. */ |
194 | 142 | ||
195 | /* token bucket parameters */ | 143 | /* token bucket parameters */ |
196 | struct qdisc_rate_table *rate; /* rate table of the class itself */ | 144 | struct qdisc_rate_table *rate; /* rate table of the class itself */ |
197 | struct qdisc_rate_table *ceil; /* ceiling rate (limits borrows too) */ | 145 | struct qdisc_rate_table *ceil; /* ceiling rate (limits borrows too) */ |
198 | long buffer,cbuffer; /* token bucket depth/rate */ | 146 | long buffer, cbuffer; /* token bucket depth/rate */ |
199 | psched_tdiff_t mbuffer; /* max wait time */ | 147 | psched_tdiff_t mbuffer; /* max wait time */ |
200 | long tokens,ctokens; /* current number of tokens */ | 148 | long tokens, ctokens; /* current number of tokens */ |
201 | psched_time_t t_c; /* checkpoint time */ | 149 | psched_time_t t_c; /* checkpoint time */ |
202 | }; | 150 | }; |
203 | 151 | ||
204 | /* TODO: maybe compute rate when size is too large .. or drop ? */ | 152 | /* TODO: maybe compute rate when size is too large .. or drop ? */ |
205 | static __inline__ long L2T(struct htb_class *cl,struct qdisc_rate_table *rate, | 153 | static inline long L2T(struct htb_class *cl, struct qdisc_rate_table *rate, |
206 | int size) | 154 | int size) |
207 | { | 155 | { |
208 | int slot = size >> rate->rate.cell_log; | 156 | int slot = size >> rate->rate.cell_log; |
209 | if (slot > 255) { | 157 | if (slot > 255) { |
210 | cl->xstats.giants++; | 158 | cl->xstats.giants++; |
211 | slot = 255; | 159 | slot = 255; |
212 | } | 160 | } |
213 | return rate->data[slot]; | 161 | return rate->data[slot]; |
214 | } | 162 | } |
215 | 163 | ||
216 | struct htb_sched | 164 | struct htb_sched { |
217 | { | 165 | struct list_head root; /* root classes list */ |
218 | struct list_head root; /* root classes list */ | 166 | struct hlist_head hash[HTB_HSIZE]; /* hashed by classid */ |
219 | struct list_head hash[HTB_HSIZE]; /* hashed by classid */ | 167 | struct list_head drops[TC_HTB_NUMPRIO];/* active leaves (for drops) */ |
220 | struct list_head drops[TC_HTB_NUMPRIO]; /* active leaves (for drops) */ | 168 | |
221 | 169 | /* self list - roots of self generating tree */ | |
222 | /* self list - roots of self generating tree */ | 170 | struct rb_root row[TC_HTB_MAXDEPTH][TC_HTB_NUMPRIO]; |
223 | struct rb_root row[TC_HTB_MAXDEPTH][TC_HTB_NUMPRIO]; | 171 | int row_mask[TC_HTB_MAXDEPTH]; |
224 | int row_mask[TC_HTB_MAXDEPTH]; | 172 | struct rb_node *ptr[TC_HTB_MAXDEPTH][TC_HTB_NUMPRIO]; |
225 | struct rb_node *ptr[TC_HTB_MAXDEPTH][TC_HTB_NUMPRIO]; | 173 | u32 last_ptr_id[TC_HTB_MAXDEPTH][TC_HTB_NUMPRIO]; |
226 | u32 last_ptr_id[TC_HTB_MAXDEPTH][TC_HTB_NUMPRIO]; | 174 | |
227 | 175 | /* self wait list - roots of wait PQs per row */ | |
228 | /* self wait list - roots of wait PQs per row */ | 176 | struct rb_root wait_pq[TC_HTB_MAXDEPTH]; |
229 | struct rb_root wait_pq[TC_HTB_MAXDEPTH]; | 177 | |
230 | 178 | /* time of nearest event per level (row) */ | |
231 | /* time of nearest event per level (row) */ | 179 | unsigned long near_ev_cache[TC_HTB_MAXDEPTH]; |
232 | unsigned long near_ev_cache[TC_HTB_MAXDEPTH]; | 180 | |
233 | 181 | /* cached value of jiffies in dequeue */ | |
234 | /* cached value of jiffies in dequeue */ | 182 | unsigned long jiffies; |
235 | unsigned long jiffies; | 183 | |
236 | 184 | /* whether we hit non-work conserving class during this dequeue; we use */ | |
237 | /* whether we hit non-work conserving class during this dequeue; we use */ | 185 | int nwc_hit; /* this to disable mindelay complaint in dequeue */ |
238 | int nwc_hit; /* this to disable mindelay complaint in dequeue */ | 186 | |
239 | 187 | int defcls; /* class where unclassified flows go to */ | |
240 | int defcls; /* class where unclassified flows go to */ | 188 | |
241 | u32 debug; /* subsystem debug levels */ | 189 | /* filters for qdisc itself */ |
242 | 190 | struct tcf_proto *filter_list; | |
243 | /* filters for qdisc itself */ | 191 | int filter_cnt; |
244 | struct tcf_proto *filter_list; | 192 | |
245 | int filter_cnt; | 193 | int rate2quantum; /* quant = rate / rate2quantum */ |
246 | 194 | psched_time_t now; /* cached dequeue time */ | |
247 | int rate2quantum; /* quant = rate / rate2quantum */ | 195 | struct timer_list timer; /* send delay timer */ |
248 | psched_time_t now; /* cached dequeue time */ | ||
249 | struct timer_list timer; /* send delay timer */ | ||
250 | #ifdef HTB_RATECM | 196 | #ifdef HTB_RATECM |
251 | struct timer_list rttim; /* rate computer timer */ | 197 | struct timer_list rttim; /* rate computer timer */ |
252 | int recmp_bucket; /* which hash bucket to recompute next */ | 198 | int recmp_bucket; /* which hash bucket to recompute next */ |
253 | #endif | 199 | #endif |
254 | |||
255 | /* non shaped skbs; let them go directly thru */ | ||
256 | struct sk_buff_head direct_queue; | ||
257 | int direct_qlen; /* max qlen of above */ | ||
258 | 200 | ||
259 | long direct_pkts; | 201 | /* non shaped skbs; let them go directly thru */ |
202 | struct sk_buff_head direct_queue; | ||
203 | int direct_qlen; /* max qlen of above */ | ||
204 | |||
205 | long direct_pkts; | ||
260 | }; | 206 | }; |
261 | 207 | ||
262 | /* compute hash of size HTB_HSIZE for given handle */ | 208 | /* compute hash of size HTB_HSIZE for given handle */ |
263 | static __inline__ int htb_hash(u32 h) | 209 | static inline int htb_hash(u32 h) |
264 | { | 210 | { |
265 | #if HTB_HSIZE != 16 | 211 | #if HTB_HSIZE != 16 |
266 | #error "Declare new hash for your HTB_HSIZE" | 212 | #error "Declare new hash for your HTB_HSIZE" |
267 | #endif | 213 | #endif |
268 | h ^= h>>8; /* stolen from cbq_hash */ | 214 | h ^= h >> 8; /* stolen from cbq_hash */ |
269 | h ^= h>>4; | 215 | h ^= h >> 4; |
270 | return h & 0xf; | 216 | return h & 0xf; |
271 | } | 217 | } |
272 | 218 | ||
273 | /* find class in global hash table using given handle */ | 219 | /* find class in global hash table using given handle */ |
274 | static __inline__ struct htb_class *htb_find(u32 handle, struct Qdisc *sch) | 220 | static inline struct htb_class *htb_find(u32 handle, struct Qdisc *sch) |
275 | { | 221 | { |
276 | struct htb_sched *q = qdisc_priv(sch); | 222 | struct htb_sched *q = qdisc_priv(sch); |
277 | struct list_head *p; | 223 | struct hlist_node *p; |
278 | if (TC_H_MAJ(handle) != sch->handle) | 224 | struct htb_class *cl; |
225 | |||
226 | if (TC_H_MAJ(handle) != sch->handle) | ||
279 | return NULL; | 227 | return NULL; |
280 | 228 | ||
281 | list_for_each (p,q->hash+htb_hash(handle)) { | 229 | hlist_for_each_entry(cl, p, q->hash + htb_hash(handle), hlist) { |
282 | struct htb_class *cl = list_entry(p,struct htb_class,hlist); | ||
283 | if (cl->classid == handle) | 230 | if (cl->classid == handle) |
284 | return cl; | 231 | return cl; |
285 | } | 232 | } |
@@ -304,7 +251,8 @@ static inline u32 htb_classid(struct htb_class *cl) | |||
304 | return (cl && cl != HTB_DIRECT) ? cl->classid : TC_H_UNSPEC; | 251 | return (cl && cl != HTB_DIRECT) ? cl->classid : TC_H_UNSPEC; |
305 | } | 252 | } |
306 | 253 | ||
307 | static struct htb_class *htb_classify(struct sk_buff *skb, struct Qdisc *sch, int *qerr) | 254 | static struct htb_class *htb_classify(struct sk_buff *skb, struct Qdisc *sch, |
255 | int *qerr) | ||
308 | { | 256 | { |
309 | struct htb_sched *q = qdisc_priv(sch); | 257 | struct htb_sched *q = qdisc_priv(sch); |
310 | struct htb_class *cl; | 258 | struct htb_class *cl; |
@@ -316,8 +264,8 @@ static struct htb_class *htb_classify(struct sk_buff *skb, struct Qdisc *sch, in | |||
316 | note that nfmark can be used too by attaching filter fw with no | 264 | note that nfmark can be used too by attaching filter fw with no |
317 | rules in it */ | 265 | rules in it */ |
318 | if (skb->priority == sch->handle) | 266 | if (skb->priority == sch->handle) |
319 | return HTB_DIRECT; /* X:0 (direct flow) selected */ | 267 | return HTB_DIRECT; /* X:0 (direct flow) selected */ |
320 | if ((cl = htb_find(skb->priority,sch)) != NULL && cl->level == 0) | 268 | if ((cl = htb_find(skb->priority, sch)) != NULL && cl->level == 0) |
321 | return cl; | 269 | return cl; |
322 | 270 | ||
323 | *qerr = NET_XMIT_BYPASS; | 271 | *qerr = NET_XMIT_BYPASS; |
@@ -326,7 +274,7 @@ static struct htb_class *htb_classify(struct sk_buff *skb, struct Qdisc *sch, in | |||
326 | #ifdef CONFIG_NET_CLS_ACT | 274 | #ifdef CONFIG_NET_CLS_ACT |
327 | switch (result) { | 275 | switch (result) { |
328 | case TC_ACT_QUEUED: | 276 | case TC_ACT_QUEUED: |
329 | case TC_ACT_STOLEN: | 277 | case TC_ACT_STOLEN: |
330 | *qerr = NET_XMIT_SUCCESS; | 278 | *qerr = NET_XMIT_SUCCESS; |
331 | case TC_ACT_SHOT: | 279 | case TC_ACT_SHOT: |
332 | return NULL; | 280 | return NULL; |
@@ -335,97 +283,44 @@ static struct htb_class *htb_classify(struct sk_buff *skb, struct Qdisc *sch, in | |||
335 | if (result == TC_POLICE_SHOT) | 283 | if (result == TC_POLICE_SHOT) |
336 | return HTB_DIRECT; | 284 | return HTB_DIRECT; |
337 | #endif | 285 | #endif |
338 | if ((cl = (void*)res.class) == NULL) { | 286 | if ((cl = (void *)res.class) == NULL) { |
339 | if (res.classid == sch->handle) | 287 | if (res.classid == sch->handle) |
340 | return HTB_DIRECT; /* X:0 (direct flow) */ | 288 | return HTB_DIRECT; /* X:0 (direct flow) */ |
341 | if ((cl = htb_find(res.classid,sch)) == NULL) | 289 | if ((cl = htb_find(res.classid, sch)) == NULL) |
342 | break; /* filter selected invalid classid */ | 290 | break; /* filter selected invalid classid */ |
343 | } | 291 | } |
344 | if (!cl->level) | 292 | if (!cl->level) |
345 | return cl; /* we hit leaf; return it */ | 293 | return cl; /* we hit leaf; return it */ |
346 | 294 | ||
347 | /* we have got inner class; apply inner filter chain */ | 295 | /* we have got inner class; apply inner filter chain */ |
348 | tcf = cl->filter_list; | 296 | tcf = cl->filter_list; |
349 | } | 297 | } |
350 | /* classification failed; try to use default class */ | 298 | /* classification failed; try to use default class */ |
351 | cl = htb_find(TC_H_MAKE(TC_H_MAJ(sch->handle),q->defcls),sch); | 299 | cl = htb_find(TC_H_MAKE(TC_H_MAJ(sch->handle), q->defcls), sch); |
352 | if (!cl || cl->level) | 300 | if (!cl || cl->level) |
353 | return HTB_DIRECT; /* bad default .. this is safe bet */ | 301 | return HTB_DIRECT; /* bad default .. this is safe bet */ |
354 | return cl; | 302 | return cl; |
355 | } | 303 | } |
356 | 304 | ||
357 | #ifdef HTB_DEBUG | ||
358 | static void htb_next_rb_node(struct rb_node **n); | ||
359 | #define HTB_DUMTREE(root,memb) if(root) { \ | ||
360 | struct rb_node *n = (root)->rb_node; \ | ||
361 | while (n->rb_left) n = n->rb_left; \ | ||
362 | while (n) { \ | ||
363 | struct htb_class *cl = rb_entry(n, struct htb_class, memb); \ | ||
364 | printk(" %x",cl->classid); htb_next_rb_node (&n); \ | ||
365 | } } | ||
366 | |||
367 | static void htb_debug_dump (struct htb_sched *q) | ||
368 | { | ||
369 | int i,p; | ||
370 | printk(KERN_DEBUG "htb*g j=%lu lj=%lu\n",jiffies,q->jiffies); | ||
371 | /* rows */ | ||
372 | for (i=TC_HTB_MAXDEPTH-1;i>=0;i--) { | ||
373 | printk(KERN_DEBUG "htb*r%d m=%x",i,q->row_mask[i]); | ||
374 | for (p=0;p<TC_HTB_NUMPRIO;p++) { | ||
375 | if (!q->row[i][p].rb_node) continue; | ||
376 | printk(" p%d:",p); | ||
377 | HTB_DUMTREE(q->row[i]+p,node[p]); | ||
378 | } | ||
379 | printk("\n"); | ||
380 | } | ||
381 | /* classes */ | ||
382 | for (i = 0; i < HTB_HSIZE; i++) { | ||
383 | struct list_head *l; | ||
384 | list_for_each (l,q->hash+i) { | ||
385 | struct htb_class *cl = list_entry(l,struct htb_class,hlist); | ||
386 | long diff = PSCHED_TDIFF_SAFE(q->now, cl->t_c, (u32)cl->mbuffer); | ||
387 | printk(KERN_DEBUG "htb*c%x m=%d t=%ld c=%ld pq=%lu df=%ld ql=%d " | ||
388 | "pa=%x f:", | ||
389 | cl->classid,cl->cmode,cl->tokens,cl->ctokens, | ||
390 | cl->pq_node.rb_color==-1?0:cl->pq_key,diff, | ||
391 | cl->level?0:cl->un.leaf.q->q.qlen,cl->prio_activity); | ||
392 | if (cl->level) | ||
393 | for (p=0;p<TC_HTB_NUMPRIO;p++) { | ||
394 | if (!cl->un.inner.feed[p].rb_node) continue; | ||
395 | printk(" p%d a=%x:",p,cl->un.inner.ptr[p]?rb_entry(cl->un.inner.ptr[p], struct htb_class,node[p])->classid:0); | ||
396 | HTB_DUMTREE(cl->un.inner.feed+p,node[p]); | ||
397 | } | ||
398 | printk("\n"); | ||
399 | } | ||
400 | } | ||
401 | } | ||
402 | #endif | ||
403 | /** | 305 | /** |
404 | * htb_add_to_id_tree - adds class to the round robin list | 306 | * htb_add_to_id_tree - adds class to the round robin list |
405 | * | 307 | * |
406 | * Routine adds class to the list (actually tree) sorted by classid. | 308 | * Routine adds class to the list (actually tree) sorted by classid. |
407 | * Make sure that class is not already on such list for given prio. | 309 | * Make sure that class is not already on such list for given prio. |
408 | */ | 310 | */ |
409 | static void htb_add_to_id_tree (HTB_ARGQ struct rb_root *root, | 311 | static void htb_add_to_id_tree(struct rb_root *root, |
410 | struct htb_class *cl,int prio) | 312 | struct htb_class *cl, int prio) |
411 | { | 313 | { |
412 | struct rb_node **p = &root->rb_node, *parent = NULL; | 314 | struct rb_node **p = &root->rb_node, *parent = NULL; |
413 | HTB_DBG(7,3,"htb_add_id_tree cl=%X prio=%d\n",cl->classid,prio); | 315 | |
414 | #ifdef HTB_DEBUG | ||
415 | if (cl->node[prio].rb_color != -1) { BUG_TRAP(0); return; } | ||
416 | HTB_CHCL(cl); | ||
417 | if (*p) { | ||
418 | struct htb_class *x = rb_entry(*p,struct htb_class,node[prio]); | ||
419 | HTB_CHCL(x); | ||
420 | } | ||
421 | #endif | ||
422 | while (*p) { | 316 | while (*p) { |
423 | struct htb_class *c; parent = *p; | 317 | struct htb_class *c; |
318 | parent = *p; | ||
424 | c = rb_entry(parent, struct htb_class, node[prio]); | 319 | c = rb_entry(parent, struct htb_class, node[prio]); |
425 | HTB_CHCL(c); | 320 | |
426 | if (cl->classid > c->classid) | 321 | if (cl->classid > c->classid) |
427 | p = &parent->rb_right; | 322 | p = &parent->rb_right; |
428 | else | 323 | else |
429 | p = &parent->rb_left; | 324 | p = &parent->rb_left; |
430 | } | 325 | } |
431 | rb_link_node(&cl->node[prio], parent, p); | 326 | rb_link_node(&cl->node[prio], parent, p); |
@@ -439,17 +334,11 @@ static void htb_add_to_id_tree (HTB_ARGQ struct rb_root *root, | |||
439 | * change its mode in cl->pq_key microseconds. Make sure that class is not | 334 | * change its mode in cl->pq_key microseconds. Make sure that class is not |
440 | * already in the queue. | 335 | * already in the queue. |
441 | */ | 336 | */ |
442 | static void htb_add_to_wait_tree (struct htb_sched *q, | 337 | static void htb_add_to_wait_tree(struct htb_sched *q, |
443 | struct htb_class *cl,long delay,int debug_hint) | 338 | struct htb_class *cl, long delay) |
444 | { | 339 | { |
445 | struct rb_node **p = &q->wait_pq[cl->level].rb_node, *parent = NULL; | 340 | struct rb_node **p = &q->wait_pq[cl->level].rb_node, *parent = NULL; |
446 | HTB_DBG(7,3,"htb_add_wt cl=%X key=%lu\n",cl->classid,cl->pq_key); | 341 | |
447 | #ifdef HTB_DEBUG | ||
448 | if (cl->pq_node.rb_color != -1) { BUG_TRAP(0); return; } | ||
449 | HTB_CHCL(cl); | ||
450 | if ((delay <= 0 || delay > cl->mbuffer) && net_ratelimit()) | ||
451 | printk(KERN_ERR "HTB: suspicious delay in wait_tree d=%ld cl=%X h=%d\n",delay,cl->classid,debug_hint); | ||
452 | #endif | ||
453 | cl->pq_key = q->jiffies + PSCHED_US2JIFFIE(delay); | 342 | cl->pq_key = q->jiffies + PSCHED_US2JIFFIE(delay); |
454 | if (cl->pq_key == q->jiffies) | 343 | if (cl->pq_key == q->jiffies) |
455 | cl->pq_key++; | 344 | cl->pq_key++; |
@@ -457,13 +346,14 @@ static void htb_add_to_wait_tree (struct htb_sched *q, | |||
457 | /* update the nearest event cache */ | 346 | /* update the nearest event cache */ |
458 | if (time_after(q->near_ev_cache[cl->level], cl->pq_key)) | 347 | if (time_after(q->near_ev_cache[cl->level], cl->pq_key)) |
459 | q->near_ev_cache[cl->level] = cl->pq_key; | 348 | q->near_ev_cache[cl->level] = cl->pq_key; |
460 | 349 | ||
461 | while (*p) { | 350 | while (*p) { |
462 | struct htb_class *c; parent = *p; | 351 | struct htb_class *c; |
352 | parent = *p; | ||
463 | c = rb_entry(parent, struct htb_class, pq_node); | 353 | c = rb_entry(parent, struct htb_class, pq_node); |
464 | if (time_after_eq(cl->pq_key, c->pq_key)) | 354 | if (time_after_eq(cl->pq_key, c->pq_key)) |
465 | p = &parent->rb_right; | 355 | p = &parent->rb_right; |
466 | else | 356 | else |
467 | p = &parent->rb_left; | 357 | p = &parent->rb_left; |
468 | } | 358 | } |
469 | rb_link_node(&cl->pq_node, parent, p); | 359 | rb_link_node(&cl->pq_node, parent, p); |
@@ -476,7 +366,7 @@ static void htb_add_to_wait_tree (struct htb_sched *q, | |||
476 | * When we are past last key we return NULL. | 366 | * When we are past last key we return NULL. |
477 | * Average complexity is 2 steps per call. | 367 | * Average complexity is 2 steps per call. |
478 | */ | 368 | */ |
479 | static void htb_next_rb_node(struct rb_node **n) | 369 | static inline void htb_next_rb_node(struct rb_node **n) |
480 | { | 370 | { |
481 | *n = rb_next(*n); | 371 | *n = rb_next(*n); |
482 | } | 372 | } |
@@ -487,42 +377,51 @@ static void htb_next_rb_node(struct rb_node **n) | |||
487 | * The class is added to row at priorities marked in mask. | 377 | * The class is added to row at priorities marked in mask. |
488 | * It does nothing if mask == 0. | 378 | * It does nothing if mask == 0. |
489 | */ | 379 | */ |
490 | static inline void htb_add_class_to_row(struct htb_sched *q, | 380 | static inline void htb_add_class_to_row(struct htb_sched *q, |
491 | struct htb_class *cl,int mask) | 381 | struct htb_class *cl, int mask) |
492 | { | 382 | { |
493 | HTB_DBG(7,2,"htb_addrow cl=%X mask=%X rmask=%X\n", | ||
494 | cl->classid,mask,q->row_mask[cl->level]); | ||
495 | HTB_CHCL(cl); | ||
496 | q->row_mask[cl->level] |= mask; | 383 | q->row_mask[cl->level] |= mask; |
497 | while (mask) { | 384 | while (mask) { |
498 | int prio = ffz(~mask); | 385 | int prio = ffz(~mask); |
499 | mask &= ~(1 << prio); | 386 | mask &= ~(1 << prio); |
500 | htb_add_to_id_tree(HTB_PASSQ q->row[cl->level]+prio,cl,prio); | 387 | htb_add_to_id_tree(q->row[cl->level] + prio, cl, prio); |
388 | } | ||
389 | } | ||
390 | |||
391 | /* If this triggers, it is a bug in this code, but it need not be fatal */ | ||
392 | static void htb_safe_rb_erase(struct rb_node *rb, struct rb_root *root) | ||
393 | { | ||
394 | if (RB_EMPTY_NODE(rb)) { | ||
395 | WARN_ON(1); | ||
396 | } else { | ||
397 | rb_erase(rb, root); | ||
398 | RB_CLEAR_NODE(rb); | ||
501 | } | 399 | } |
502 | } | 400 | } |
503 | 401 | ||
402 | |||
504 | /** | 403 | /** |
505 | * htb_remove_class_from_row - removes class from its row | 404 | * htb_remove_class_from_row - removes class from its row |
506 | * | 405 | * |
507 | * The class is removed from row at priorities marked in mask. | 406 | * The class is removed from row at priorities marked in mask. |
508 | * It does nothing if mask == 0. | 407 | * It does nothing if mask == 0. |
509 | */ | 408 | */ |
510 | static __inline__ void htb_remove_class_from_row(struct htb_sched *q, | 409 | static inline void htb_remove_class_from_row(struct htb_sched *q, |
511 | struct htb_class *cl,int mask) | 410 | struct htb_class *cl, int mask) |
512 | { | 411 | { |
513 | int m = 0; | 412 | int m = 0; |
514 | HTB_CHCL(cl); | 413 | |
515 | while (mask) { | 414 | while (mask) { |
516 | int prio = ffz(~mask); | 415 | int prio = ffz(~mask); |
416 | |||
517 | mask &= ~(1 << prio); | 417 | mask &= ~(1 << prio); |
518 | if (q->ptr[cl->level][prio] == cl->node+prio) | 418 | if (q->ptr[cl->level][prio] == cl->node + prio) |
519 | htb_next_rb_node(q->ptr[cl->level]+prio); | 419 | htb_next_rb_node(q->ptr[cl->level] + prio); |
520 | htb_safe_rb_erase(cl->node + prio,q->row[cl->level]+prio); | 420 | |
521 | if (!q->row[cl->level][prio].rb_node) | 421 | htb_safe_rb_erase(cl->node + prio, q->row[cl->level] + prio); |
422 | if (!q->row[cl->level][prio].rb_node) | ||
522 | m |= 1 << prio; | 423 | m |= 1 << prio; |
523 | } | 424 | } |
524 | HTB_DBG(7,2,"htb_delrow cl=%X mask=%X rmask=%X maskdel=%X\n", | ||
525 | cl->classid,mask,q->row_mask[cl->level],m); | ||
526 | q->row_mask[cl->level] &= ~m; | 425 | q->row_mask[cl->level] &= ~m; |
527 | } | 426 | } |
528 | 427 | ||
@@ -533,34 +432,31 @@ static __inline__ void htb_remove_class_from_row(struct htb_sched *q, | |||
533 | * for priorities it is participating on. cl->cmode must be new | 432 | * for priorities it is participating on. cl->cmode must be new |
534 | * (activated) mode. It does nothing if cl->prio_activity == 0. | 433 | * (activated) mode. It does nothing if cl->prio_activity == 0. |
535 | */ | 434 | */ |
536 | static void htb_activate_prios(struct htb_sched *q,struct htb_class *cl) | 435 | static void htb_activate_prios(struct htb_sched *q, struct htb_class *cl) |
537 | { | 436 | { |
538 | struct htb_class *p = cl->parent; | 437 | struct htb_class *p = cl->parent; |
539 | long m,mask = cl->prio_activity; | 438 | long m, mask = cl->prio_activity; |
540 | HTB_DBG(7,2,"htb_act_prios cl=%X mask=%lX cmode=%d\n",cl->classid,mask,cl->cmode); | ||
541 | HTB_CHCL(cl); | ||
542 | 439 | ||
543 | while (cl->cmode == HTB_MAY_BORROW && p && mask) { | 440 | while (cl->cmode == HTB_MAY_BORROW && p && mask) { |
544 | HTB_CHCL(p); | 441 | m = mask; |
545 | m = mask; while (m) { | 442 | while (m) { |
546 | int prio = ffz(~m); | 443 | int prio = ffz(~m); |
547 | m &= ~(1 << prio); | 444 | m &= ~(1 << prio); |
548 | 445 | ||
549 | if (p->un.inner.feed[prio].rb_node) | 446 | if (p->un.inner.feed[prio].rb_node) |
550 | /* parent already has its feed in use so that | 447 | /* parent already has its feed in use so that |
551 | reset bit in mask as parent is already ok */ | 448 | reset bit in mask as parent is already ok */ |
552 | mask &= ~(1 << prio); | 449 | mask &= ~(1 << prio); |
553 | 450 | ||
554 | htb_add_to_id_tree(HTB_PASSQ p->un.inner.feed+prio,cl,prio); | 451 | htb_add_to_id_tree(p->un.inner.feed + prio, cl, prio); |
555 | } | 452 | } |
556 | HTB_DBG(7,3,"htb_act_pr_aft p=%X pact=%X mask=%lX pmode=%d\n", | ||
557 | p->classid,p->prio_activity,mask,p->cmode); | ||
558 | p->prio_activity |= mask; | 453 | p->prio_activity |= mask; |
559 | cl = p; p = cl->parent; | 454 | cl = p; |
560 | HTB_CHCL(cl); | 455 | p = cl->parent; |
456 | |||
561 | } | 457 | } |
562 | if (cl->cmode == HTB_CAN_SEND && mask) | 458 | if (cl->cmode == HTB_CAN_SEND && mask) |
563 | htb_add_class_to_row(q,cl,mask); | 459 | htb_add_class_to_row(q, cl, mask); |
564 | } | 460 | } |
565 | 461 | ||
566 | /** | 462 | /** |
@@ -573,39 +469,52 @@ static void htb_activate_prios(struct htb_sched *q,struct htb_class *cl) | |||
573 | static void htb_deactivate_prios(struct htb_sched *q, struct htb_class *cl) | 469 | static void htb_deactivate_prios(struct htb_sched *q, struct htb_class *cl) |
574 | { | 470 | { |
575 | struct htb_class *p = cl->parent; | 471 | struct htb_class *p = cl->parent; |
576 | long m,mask = cl->prio_activity; | 472 | long m, mask = cl->prio_activity; |
577 | HTB_DBG(7,2,"htb_deact_prios cl=%X mask=%lX cmode=%d\n",cl->classid,mask,cl->cmode); | ||
578 | HTB_CHCL(cl); | ||
579 | 473 | ||
580 | while (cl->cmode == HTB_MAY_BORROW && p && mask) { | 474 | while (cl->cmode == HTB_MAY_BORROW && p && mask) { |
581 | m = mask; mask = 0; | 475 | m = mask; |
476 | mask = 0; | ||
582 | while (m) { | 477 | while (m) { |
583 | int prio = ffz(~m); | 478 | int prio = ffz(~m); |
584 | m &= ~(1 << prio); | 479 | m &= ~(1 << prio); |
585 | 480 | ||
586 | if (p->un.inner.ptr[prio] == cl->node+prio) { | 481 | if (p->un.inner.ptr[prio] == cl->node + prio) { |
587 | /* we are removing child which is pointed to from | 482 | /* we are removing child which is pointed to from |
588 | parent feed - forget the pointer but remember | 483 | parent feed - forget the pointer but remember |
589 | classid */ | 484 | classid */ |
590 | p->un.inner.last_ptr_id[prio] = cl->classid; | 485 | p->un.inner.last_ptr_id[prio] = cl->classid; |
591 | p->un.inner.ptr[prio] = NULL; | 486 | p->un.inner.ptr[prio] = NULL; |
592 | } | 487 | } |
593 | 488 | ||
594 | htb_safe_rb_erase(cl->node + prio,p->un.inner.feed + prio); | 489 | htb_safe_rb_erase(cl->node + prio, p->un.inner.feed + prio); |
595 | 490 | ||
596 | if (!p->un.inner.feed[prio].rb_node) | 491 | if (!p->un.inner.feed[prio].rb_node) |
597 | mask |= 1 << prio; | 492 | mask |= 1 << prio; |
598 | } | 493 | } |
599 | HTB_DBG(7,3,"htb_deact_pr_aft p=%X pact=%X mask=%lX pmode=%d\n", | 494 | |
600 | p->classid,p->prio_activity,mask,p->cmode); | ||
601 | p->prio_activity &= ~mask; | 495 | p->prio_activity &= ~mask; |
602 | cl = p; p = cl->parent; | 496 | cl = p; |
603 | HTB_CHCL(cl); | 497 | p = cl->parent; |
498 | |||
604 | } | 499 | } |
605 | if (cl->cmode == HTB_CAN_SEND && mask) | 500 | if (cl->cmode == HTB_CAN_SEND && mask) |
606 | htb_remove_class_from_row(q,cl,mask); | 501 | htb_remove_class_from_row(q, cl, mask); |
607 | } | 502 | } |
608 | 503 | ||
504 | #if HTB_HYSTERESIS | ||
505 | static inline long htb_lowater(const struct htb_class *cl) | ||
506 | { | ||
507 | return cl->cmode != HTB_CANT_SEND ? -cl->cbuffer : 0; | ||
508 | } | ||
509 | static inline long htb_hiwater(const struct htb_class *cl) | ||
510 | { | ||
511 | return cl->cmode == HTB_CAN_SEND ? -cl->buffer : 0; | ||
512 | } | ||
513 | #else | ||
514 | #define htb_lowater(cl) (0) | ||
515 | #define htb_hiwater(cl) (0) | ||
516 | #endif | ||
517 | |||
609 | /** | 518 | /** |
610 | * htb_class_mode - computes and returns current class mode | 519 | * htb_class_mode - computes and returns current class mode |
611 | * | 520 | * |
@@ -617,28 +526,21 @@ static void htb_deactivate_prios(struct htb_sched *q, struct htb_class *cl) | |||
617 | * 0 .. -cl->{c,}buffer range. It is meant to limit number of | 526 | * 0 .. -cl->{c,}buffer range. It is meant to limit number of |
618 | * mode transitions per time unit. The speed gain is about 1/6. | 527 | * mode transitions per time unit. The speed gain is about 1/6. |
619 | */ | 528 | */ |
620 | static __inline__ enum htb_cmode | 529 | static inline enum htb_cmode |
621 | htb_class_mode(struct htb_class *cl,long *diff) | 530 | htb_class_mode(struct htb_class *cl, long *diff) |
622 | { | 531 | { |
623 | long toks; | 532 | long toks; |
624 | 533 | ||
625 | if ((toks = (cl->ctokens + *diff)) < ( | 534 | if ((toks = (cl->ctokens + *diff)) < htb_lowater(cl)) { |
626 | #if HTB_HYSTERESIS | 535 | *diff = -toks; |
627 | cl->cmode != HTB_CANT_SEND ? -cl->cbuffer : | 536 | return HTB_CANT_SEND; |
628 | #endif | 537 | } |
629 | 0)) { | 538 | |
630 | *diff = -toks; | 539 | if ((toks = (cl->tokens + *diff)) >= htb_hiwater(cl)) |
631 | return HTB_CANT_SEND; | 540 | return HTB_CAN_SEND; |
632 | } | ||
633 | if ((toks = (cl->tokens + *diff)) >= ( | ||
634 | #if HTB_HYSTERESIS | ||
635 | cl->cmode == HTB_CAN_SEND ? -cl->buffer : | ||
636 | #endif | ||
637 | 0)) | ||
638 | return HTB_CAN_SEND; | ||
639 | 541 | ||
640 | *diff = -toks; | 542 | *diff = -toks; |
641 | return HTB_MAY_BORROW; | 543 | return HTB_MAY_BORROW; |
642 | } | 544 | } |
643 | 545 | ||
644 | /** | 546 | /** |
@@ -650,24 +552,21 @@ htb_class_mode(struct htb_class *cl,long *diff) | |||
650 | * be different from old one and cl->pq_key has to be valid if changing | 552 | * be different from old one and cl->pq_key has to be valid if changing |
651 | * to mode other than HTB_CAN_SEND (see htb_add_to_wait_tree). | 553 | * to mode other than HTB_CAN_SEND (see htb_add_to_wait_tree). |
652 | */ | 554 | */ |
653 | static void | 555 | static void |
654 | htb_change_class_mode(struct htb_sched *q, struct htb_class *cl, long *diff) | 556 | htb_change_class_mode(struct htb_sched *q, struct htb_class *cl, long *diff) |
655 | { | 557 | { |
656 | enum htb_cmode new_mode = htb_class_mode(cl,diff); | 558 | enum htb_cmode new_mode = htb_class_mode(cl, diff); |
657 | |||
658 | HTB_CHCL(cl); | ||
659 | HTB_DBG(7,1,"htb_chging_clmode %d->%d cl=%X\n",cl->cmode,new_mode,cl->classid); | ||
660 | 559 | ||
661 | if (new_mode == cl->cmode) | 560 | if (new_mode == cl->cmode) |
662 | return; | 561 | return; |
663 | 562 | ||
664 | if (cl->prio_activity) { /* not necessary: speed optimization */ | 563 | if (cl->prio_activity) { /* not necessary: speed optimization */ |
665 | if (cl->cmode != HTB_CANT_SEND) | 564 | if (cl->cmode != HTB_CANT_SEND) |
666 | htb_deactivate_prios(q,cl); | 565 | htb_deactivate_prios(q, cl); |
667 | cl->cmode = new_mode; | 566 | cl->cmode = new_mode; |
668 | if (new_mode != HTB_CANT_SEND) | 567 | if (new_mode != HTB_CANT_SEND) |
669 | htb_activate_prios(q,cl); | 568 | htb_activate_prios(q, cl); |
670 | } else | 569 | } else |
671 | cl->cmode = new_mode; | 570 | cl->cmode = new_mode; |
672 | } | 571 | } |
673 | 572 | ||
@@ -678,14 +577,15 @@ htb_change_class_mode(struct htb_sched *q, struct htb_class *cl, long *diff) | |||
678 | * for the prio. It can be called on already active leaf safely. | 577 | * for the prio. It can be called on already active leaf safely. |
679 | * It also adds leaf into droplist. | 578 | * It also adds leaf into droplist. |
680 | */ | 579 | */ |
681 | static __inline__ void htb_activate(struct htb_sched *q,struct htb_class *cl) | 580 | static inline void htb_activate(struct htb_sched *q, struct htb_class *cl) |
682 | { | 581 | { |
683 | BUG_TRAP(!cl->level && cl->un.leaf.q && cl->un.leaf.q->q.qlen); | 582 | BUG_TRAP(!cl->level && cl->un.leaf.q && cl->un.leaf.q->q.qlen); |
684 | HTB_CHCL(cl); | 583 | |
685 | if (!cl->prio_activity) { | 584 | if (!cl->prio_activity) { |
686 | cl->prio_activity = 1 << (cl->un.leaf.aprio = cl->un.leaf.prio); | 585 | cl->prio_activity = 1 << (cl->un.leaf.aprio = cl->un.leaf.prio); |
687 | htb_activate_prios(q,cl); | 586 | htb_activate_prios(q, cl); |
688 | list_add_tail(&cl->un.leaf.drop_list,q->drops+cl->un.leaf.aprio); | 587 | list_add_tail(&cl->un.leaf.drop_list, |
588 | q->drops + cl->un.leaf.aprio); | ||
689 | } | 589 | } |
690 | } | 590 | } |
691 | 591 | ||
@@ -695,120 +595,120 @@ static __inline__ void htb_activate(struct htb_sched *q,struct htb_class *cl) | |||
695 | * Make sure that leaf is active. In the other words it can't be called | 595 | * Make sure that leaf is active. In the other words it can't be called |
696 | * with non-active leaf. It also removes class from the drop list. | 596 | * with non-active leaf. It also removes class from the drop list. |
697 | */ | 597 | */ |
698 | static __inline__ void | 598 | static inline void htb_deactivate(struct htb_sched *q, struct htb_class *cl) |
699 | htb_deactivate(struct htb_sched *q,struct htb_class *cl) | ||
700 | { | 599 | { |
701 | BUG_TRAP(cl->prio_activity); | 600 | BUG_TRAP(cl->prio_activity); |
702 | HTB_CHCL(cl); | 601 | |
703 | htb_deactivate_prios(q,cl); | 602 | htb_deactivate_prios(q, cl); |
704 | cl->prio_activity = 0; | 603 | cl->prio_activity = 0; |
705 | list_del_init(&cl->un.leaf.drop_list); | 604 | list_del_init(&cl->un.leaf.drop_list); |
706 | } | 605 | } |
707 | 606 | ||
708 | static int htb_enqueue(struct sk_buff *skb, struct Qdisc *sch) | 607 | static int htb_enqueue(struct sk_buff *skb, struct Qdisc *sch) |
709 | { | 608 | { |
710 | int ret; | 609 | int ret; |
711 | struct htb_sched *q = qdisc_priv(sch); | 610 | struct htb_sched *q = qdisc_priv(sch); |
712 | struct htb_class *cl = htb_classify(skb,sch,&ret); | 611 | struct htb_class *cl = htb_classify(skb, sch, &ret); |
713 | 612 | ||
714 | if (cl == HTB_DIRECT) { | 613 | if (cl == HTB_DIRECT) { |
715 | /* enqueue to helper queue */ | 614 | /* enqueue to helper queue */ |
716 | if (q->direct_queue.qlen < q->direct_qlen) { | 615 | if (q->direct_queue.qlen < q->direct_qlen) { |
717 | __skb_queue_tail(&q->direct_queue, skb); | 616 | __skb_queue_tail(&q->direct_queue, skb); |
718 | q->direct_pkts++; | 617 | q->direct_pkts++; |
719 | } else { | 618 | } else { |
720 | kfree_skb(skb); | 619 | kfree_skb(skb); |
721 | sch->qstats.drops++; | 620 | sch->qstats.drops++; |
722 | return NET_XMIT_DROP; | 621 | return NET_XMIT_DROP; |
723 | } | 622 | } |
724 | #ifdef CONFIG_NET_CLS_ACT | 623 | #ifdef CONFIG_NET_CLS_ACT |
725 | } else if (!cl) { | 624 | } else if (!cl) { |
726 | if (ret == NET_XMIT_BYPASS) | 625 | if (ret == NET_XMIT_BYPASS) |
727 | sch->qstats.drops++; | 626 | sch->qstats.drops++; |
728 | kfree_skb (skb); | 627 | kfree_skb(skb); |
729 | return ret; | 628 | return ret; |
730 | #endif | 629 | #endif |
731 | } else if (cl->un.leaf.q->enqueue(skb, cl->un.leaf.q) != NET_XMIT_SUCCESS) { | 630 | } else if (cl->un.leaf.q->enqueue(skb, cl->un.leaf.q) != |
732 | sch->qstats.drops++; | 631 | NET_XMIT_SUCCESS) { |
733 | cl->qstats.drops++; | 632 | sch->qstats.drops++; |
734 | return NET_XMIT_DROP; | 633 | cl->qstats.drops++; |
735 | } else { | 634 | return NET_XMIT_DROP; |
736 | cl->bstats.packets++; cl->bstats.bytes += skb->len; | 635 | } else { |
737 | htb_activate (q,cl); | 636 | cl->bstats.packets++; |
738 | } | 637 | cl->bstats.bytes += skb->len; |
739 | 638 | htb_activate(q, cl); | |
740 | sch->q.qlen++; | 639 | } |
741 | sch->bstats.packets++; sch->bstats.bytes += skb->len; | 640 | |
742 | HTB_DBG(1,1,"htb_enq_ok cl=%X skb=%p\n",(cl && cl != HTB_DIRECT)?cl->classid:0,skb); | 641 | sch->q.qlen++; |
743 | return NET_XMIT_SUCCESS; | 642 | sch->bstats.packets++; |
643 | sch->bstats.bytes += skb->len; | ||
644 | return NET_XMIT_SUCCESS; | ||
744 | } | 645 | } |
745 | 646 | ||
746 | /* TODO: requeuing packet charges it to policers again !! */ | 647 | /* TODO: requeuing packet charges it to policers again !! */ |
747 | static int htb_requeue(struct sk_buff *skb, struct Qdisc *sch) | 648 | static int htb_requeue(struct sk_buff *skb, struct Qdisc *sch) |
748 | { | 649 | { |
749 | struct htb_sched *q = qdisc_priv(sch); | 650 | struct htb_sched *q = qdisc_priv(sch); |
750 | int ret = NET_XMIT_SUCCESS; | 651 | int ret = NET_XMIT_SUCCESS; |
751 | struct htb_class *cl = htb_classify(skb,sch, &ret); | 652 | struct htb_class *cl = htb_classify(skb, sch, &ret); |
752 | struct sk_buff *tskb; | 653 | struct sk_buff *tskb; |
753 | 654 | ||
754 | if (cl == HTB_DIRECT || !cl) { | 655 | if (cl == HTB_DIRECT || !cl) { |
755 | /* enqueue to helper queue */ | 656 | /* enqueue to helper queue */ |
756 | if (q->direct_queue.qlen < q->direct_qlen && cl) { | 657 | if (q->direct_queue.qlen < q->direct_qlen && cl) { |
757 | __skb_queue_head(&q->direct_queue, skb); | 658 | __skb_queue_head(&q->direct_queue, skb); |
758 | } else { | 659 | } else { |
759 | __skb_queue_head(&q->direct_queue, skb); | 660 | __skb_queue_head(&q->direct_queue, skb); |
760 | tskb = __skb_dequeue_tail(&q->direct_queue); | 661 | tskb = __skb_dequeue_tail(&q->direct_queue); |
761 | kfree_skb (tskb); | 662 | kfree_skb(tskb); |
762 | sch->qstats.drops++; | 663 | sch->qstats.drops++; |
763 | return NET_XMIT_CN; | 664 | return NET_XMIT_CN; |
764 | } | 665 | } |
765 | } else if (cl->un.leaf.q->ops->requeue(skb, cl->un.leaf.q) != NET_XMIT_SUCCESS) { | 666 | } else if (cl->un.leaf.q->ops->requeue(skb, cl->un.leaf.q) != |
766 | sch->qstats.drops++; | 667 | NET_XMIT_SUCCESS) { |
767 | cl->qstats.drops++; | 668 | sch->qstats.drops++; |
768 | return NET_XMIT_DROP; | 669 | cl->qstats.drops++; |
769 | } else | 670 | return NET_XMIT_DROP; |
770 | htb_activate (q,cl); | 671 | } else |
771 | 672 | htb_activate(q, cl); | |
772 | sch->q.qlen++; | 673 | |
773 | sch->qstats.requeues++; | 674 | sch->q.qlen++; |
774 | HTB_DBG(1,1,"htb_req_ok cl=%X skb=%p\n",(cl && cl != HTB_DIRECT)?cl->classid:0,skb); | 675 | sch->qstats.requeues++; |
775 | return NET_XMIT_SUCCESS; | 676 | return NET_XMIT_SUCCESS; |
776 | } | 677 | } |
777 | 678 | ||
778 | static void htb_timer(unsigned long arg) | 679 | static void htb_timer(unsigned long arg) |
779 | { | 680 | { |
780 | struct Qdisc *sch = (struct Qdisc*)arg; | 681 | struct Qdisc *sch = (struct Qdisc *)arg; |
781 | sch->flags &= ~TCQ_F_THROTTLED; | 682 | sch->flags &= ~TCQ_F_THROTTLED; |
782 | wmb(); | 683 | wmb(); |
783 | netif_schedule(sch->dev); | 684 | netif_schedule(sch->dev); |
784 | } | 685 | } |
785 | 686 | ||
786 | #ifdef HTB_RATECM | 687 | #ifdef HTB_RATECM |
787 | #define RT_GEN(D,R) R+=D-(R/HTB_EWMAC);D=0 | 688 | #define RT_GEN(D,R) R+=D-(R/HTB_EWMAC);D=0 |
788 | static void htb_rate_timer(unsigned long arg) | 689 | static void htb_rate_timer(unsigned long arg) |
789 | { | 690 | { |
790 | struct Qdisc *sch = (struct Qdisc*)arg; | 691 | struct Qdisc *sch = (struct Qdisc *)arg; |
791 | struct htb_sched *q = qdisc_priv(sch); | 692 | struct htb_sched *q = qdisc_priv(sch); |
792 | struct list_head *p; | 693 | struct hlist_node *p; |
694 | struct htb_class *cl; | ||
695 | |||
793 | 696 | ||
794 | /* lock queue so that we can muck with it */ | 697 | /* lock queue so that we can muck with it */ |
795 | HTB_QLOCK(sch); | 698 | spin_lock_bh(&sch->dev->queue_lock); |
796 | HTB_DBG(10,1,"htb_rttmr j=%ld\n",jiffies); | ||
797 | 699 | ||
798 | q->rttim.expires = jiffies + HZ; | 700 | q->rttim.expires = jiffies + HZ; |
799 | add_timer(&q->rttim); | 701 | add_timer(&q->rttim); |
800 | 702 | ||
801 | /* scan and recompute one bucket at time */ | 703 | /* scan and recompute one bucket at time */ |
802 | if (++q->recmp_bucket >= HTB_HSIZE) | 704 | if (++q->recmp_bucket >= HTB_HSIZE) |
803 | q->recmp_bucket = 0; | 705 | q->recmp_bucket = 0; |
804 | list_for_each (p,q->hash+q->recmp_bucket) { | 706 | |
805 | struct htb_class *cl = list_entry(p,struct htb_class,hlist); | 707 | hlist_for_each_entry(cl,p, q->hash + q->recmp_bucket, hlist) { |
806 | HTB_DBG(10,2,"htb_rttmr_cl cl=%X sbyte=%lu spkt=%lu\n", | 708 | RT_GEN(cl->sum_bytes, cl->rate_bytes); |
807 | cl->classid,cl->sum_bytes,cl->sum_packets); | 709 | RT_GEN(cl->sum_packets, cl->rate_packets); |
808 | RT_GEN (cl->sum_bytes,cl->rate_bytes); | ||
809 | RT_GEN (cl->sum_packets,cl->rate_packets); | ||
810 | } | 710 | } |
811 | HTB_QUNLOCK(sch); | 711 | spin_unlock_bh(&sch->dev->queue_lock); |
812 | } | 712 | } |
813 | #endif | 713 | #endif |
814 | 714 | ||
@@ -823,12 +723,11 @@ static void htb_rate_timer(unsigned long arg) | |||
823 | * CAN_SEND) because we can use more precise clock that event queue here. | 723 | * CAN_SEND) because we can use more precise clock that event queue here. |
824 | * In such case we remove class from event queue first. | 724 | * In such case we remove class from event queue first. |
825 | */ | 725 | */ |
826 | static void htb_charge_class(struct htb_sched *q,struct htb_class *cl, | 726 | static void htb_charge_class(struct htb_sched *q, struct htb_class *cl, |
827 | int level,int bytes) | 727 | int level, int bytes) |
828 | { | 728 | { |
829 | long toks,diff; | 729 | long toks, diff; |
830 | enum htb_cmode old_mode; | 730 | enum htb_cmode old_mode; |
831 | HTB_DBG(5,1,"htb_chrg_cl cl=%X lev=%d len=%d\n",cl->classid,level,bytes); | ||
832 | 731 | ||
833 | #define HTB_ACCNT(T,B,R) toks = diff + cl->T; \ | 732 | #define HTB_ACCNT(T,B,R) toks = diff + cl->T; \ |
834 | if (toks > cl->B) toks = cl->B; \ | 733 | if (toks > cl->B) toks = cl->B; \ |
@@ -837,47 +736,31 @@ static void htb_charge_class(struct htb_sched *q,struct htb_class *cl, | |||
837 | cl->T = toks | 736 | cl->T = toks |
838 | 737 | ||
839 | while (cl) { | 738 | while (cl) { |
840 | HTB_CHCL(cl); | 739 | diff = PSCHED_TDIFF_SAFE(q->now, cl->t_c, (u32) cl->mbuffer); |
841 | diff = PSCHED_TDIFF_SAFE(q->now, cl->t_c, (u32)cl->mbuffer); | ||
842 | #ifdef HTB_DEBUG | ||
843 | if (diff > cl->mbuffer || diff < 0 || PSCHED_TLESS(q->now, cl->t_c)) { | ||
844 | if (net_ratelimit()) | ||
845 | printk(KERN_ERR "HTB: bad diff in charge, cl=%X diff=%lX now=%Lu then=%Lu j=%lu\n", | ||
846 | cl->classid, diff, | ||
847 | #ifdef CONFIG_NET_SCH_CLK_GETTIMEOFDAY | ||
848 | q->now.tv_sec * 1000000ULL + q->now.tv_usec, | ||
849 | cl->t_c.tv_sec * 1000000ULL + cl->t_c.tv_usec, | ||
850 | #else | ||
851 | (unsigned long long) q->now, | ||
852 | (unsigned long long) cl->t_c, | ||
853 | #endif | ||
854 | q->jiffies); | ||
855 | diff = 1000; | ||
856 | } | ||
857 | #endif | ||
858 | if (cl->level >= level) { | 740 | if (cl->level >= level) { |
859 | if (cl->level == level) cl->xstats.lends++; | 741 | if (cl->level == level) |
860 | HTB_ACCNT (tokens,buffer,rate); | 742 | cl->xstats.lends++; |
743 | HTB_ACCNT(tokens, buffer, rate); | ||
861 | } else { | 744 | } else { |
862 | cl->xstats.borrows++; | 745 | cl->xstats.borrows++; |
863 | cl->tokens += diff; /* we moved t_c; update tokens */ | 746 | cl->tokens += diff; /* we moved t_c; update tokens */ |
864 | } | 747 | } |
865 | HTB_ACCNT (ctokens,cbuffer,ceil); | 748 | HTB_ACCNT(ctokens, cbuffer, ceil); |
866 | cl->t_c = q->now; | 749 | cl->t_c = q->now; |
867 | HTB_DBG(5,2,"htb_chrg_clp cl=%X diff=%ld tok=%ld ctok=%ld\n",cl->classid,diff,cl->tokens,cl->ctokens); | ||
868 | 750 | ||
869 | old_mode = cl->cmode; diff = 0; | 751 | old_mode = cl->cmode; |
870 | htb_change_class_mode(q,cl,&diff); | 752 | diff = 0; |
753 | htb_change_class_mode(q, cl, &diff); | ||
871 | if (old_mode != cl->cmode) { | 754 | if (old_mode != cl->cmode) { |
872 | if (old_mode != HTB_CAN_SEND) | 755 | if (old_mode != HTB_CAN_SEND) |
873 | htb_safe_rb_erase(&cl->pq_node,q->wait_pq+cl->level); | 756 | htb_safe_rb_erase(&cl->pq_node, q->wait_pq + cl->level); |
874 | if (cl->cmode != HTB_CAN_SEND) | 757 | if (cl->cmode != HTB_CAN_SEND) |
875 | htb_add_to_wait_tree (q,cl,diff,1); | 758 | htb_add_to_wait_tree(q, cl, diff); |
876 | } | 759 | } |
877 | |||
878 | #ifdef HTB_RATECM | 760 | #ifdef HTB_RATECM |
879 | /* update rate counters */ | 761 | /* update rate counters */ |
880 | cl->sum_bytes += bytes; cl->sum_packets++; | 762 | cl->sum_bytes += bytes; |
763 | cl->sum_packets++; | ||
881 | #endif | 764 | #endif |
882 | 765 | ||
883 | /* update byte stats except for leaves which are already updated */ | 766 | /* update byte stats except for leaves which are already updated */ |
@@ -896,60 +779,46 @@ static void htb_charge_class(struct htb_sched *q,struct htb_class *cl, | |||
896 | * next pending event (0 for no event in pq). | 779 | * next pending event (0 for no event in pq). |
897 | * Note: Aplied are events whose have cl->pq_key <= jiffies. | 780 | * Note: Aplied are events whose have cl->pq_key <= jiffies. |
898 | */ | 781 | */ |
899 | static long htb_do_events(struct htb_sched *q,int level) | 782 | static long htb_do_events(struct htb_sched *q, int level) |
900 | { | 783 | { |
901 | int i; | 784 | int i; |
902 | HTB_DBG(8,1,"htb_do_events l=%d root=%p rmask=%X\n", | 785 | |
903 | level,q->wait_pq[level].rb_node,q->row_mask[level]); | ||
904 | for (i = 0; i < 500; i++) { | 786 | for (i = 0; i < 500; i++) { |
905 | struct htb_class *cl; | 787 | struct htb_class *cl; |
906 | long diff; | 788 | long diff; |
907 | struct rb_node *p = q->wait_pq[level].rb_node; | 789 | struct rb_node *p = q->wait_pq[level].rb_node; |
908 | if (!p) return 0; | 790 | if (!p) |
909 | while (p->rb_left) p = p->rb_left; | 791 | return 0; |
792 | while (p->rb_left) | ||
793 | p = p->rb_left; | ||
910 | 794 | ||
911 | cl = rb_entry(p, struct htb_class, pq_node); | 795 | cl = rb_entry(p, struct htb_class, pq_node); |
912 | if (time_after(cl->pq_key, q->jiffies)) { | 796 | if (time_after(cl->pq_key, q->jiffies)) { |
913 | HTB_DBG(8,3,"htb_do_ev_ret delay=%ld\n",cl->pq_key - q->jiffies); | ||
914 | return cl->pq_key - q->jiffies; | 797 | return cl->pq_key - q->jiffies; |
915 | } | 798 | } |
916 | htb_safe_rb_erase(p,q->wait_pq+level); | 799 | htb_safe_rb_erase(p, q->wait_pq + level); |
917 | diff = PSCHED_TDIFF_SAFE(q->now, cl->t_c, (u32)cl->mbuffer); | 800 | diff = PSCHED_TDIFF_SAFE(q->now, cl->t_c, (u32) cl->mbuffer); |
918 | #ifdef HTB_DEBUG | 801 | htb_change_class_mode(q, cl, &diff); |
919 | if (diff > cl->mbuffer || diff < 0 || PSCHED_TLESS(q->now, cl->t_c)) { | ||
920 | if (net_ratelimit()) | ||
921 | printk(KERN_ERR "HTB: bad diff in events, cl=%X diff=%lX now=%Lu then=%Lu j=%lu\n", | ||
922 | cl->classid, diff, | ||
923 | #ifdef CONFIG_NET_SCH_CLK_GETTIMEOFDAY | ||
924 | q->now.tv_sec * 1000000ULL + q->now.tv_usec, | ||
925 | cl->t_c.tv_sec * 1000000ULL + cl->t_c.tv_usec, | ||
926 | #else | ||
927 | (unsigned long long) q->now, | ||
928 | (unsigned long long) cl->t_c, | ||
929 | #endif | ||
930 | q->jiffies); | ||
931 | diff = 1000; | ||
932 | } | ||
933 | #endif | ||
934 | htb_change_class_mode(q,cl,&diff); | ||
935 | if (cl->cmode != HTB_CAN_SEND) | 802 | if (cl->cmode != HTB_CAN_SEND) |
936 | htb_add_to_wait_tree (q,cl,diff,2); | 803 | htb_add_to_wait_tree(q, cl, diff); |
937 | } | 804 | } |
938 | if (net_ratelimit()) | 805 | if (net_ratelimit()) |
939 | printk(KERN_WARNING "htb: too many events !\n"); | 806 | printk(KERN_WARNING "htb: too many events !\n"); |
940 | return HZ/10; | 807 | return HZ / 10; |
941 | } | 808 | } |
942 | 809 | ||
943 | /* Returns class->node+prio from id-tree where classe's id is >= id. NULL | 810 | /* Returns class->node+prio from id-tree where classe's id is >= id. NULL |
944 | is no such one exists. */ | 811 | is no such one exists. */ |
945 | static struct rb_node * | 812 | static struct rb_node *htb_id_find_next_upper(int prio, struct rb_node *n, |
946 | htb_id_find_next_upper(int prio,struct rb_node *n,u32 id) | 813 | u32 id) |
947 | { | 814 | { |
948 | struct rb_node *r = NULL; | 815 | struct rb_node *r = NULL; |
949 | while (n) { | 816 | while (n) { |
950 | struct htb_class *cl = rb_entry(n,struct htb_class,node[prio]); | 817 | struct htb_class *cl = |
951 | if (id == cl->classid) return n; | 818 | rb_entry(n, struct htb_class, node[prio]); |
952 | 819 | if (id == cl->classid) | |
820 | return n; | ||
821 | |||
953 | if (id > cl->classid) { | 822 | if (id > cl->classid) { |
954 | n = n->rb_right; | 823 | n = n->rb_right; |
955 | } else { | 824 | } else { |
@@ -965,49 +834,49 @@ htb_id_find_next_upper(int prio,struct rb_node *n,u32 id) | |||
965 | * | 834 | * |
966 | * Find leaf where current feed pointers points to. | 835 | * Find leaf where current feed pointers points to. |
967 | */ | 836 | */ |
968 | static struct htb_class * | 837 | static struct htb_class *htb_lookup_leaf(struct rb_root *tree, int prio, |
969 | htb_lookup_leaf(HTB_ARGQ struct rb_root *tree,int prio,struct rb_node **pptr,u32 *pid) | 838 | struct rb_node **pptr, u32 * pid) |
970 | { | 839 | { |
971 | int i; | 840 | int i; |
972 | struct { | 841 | struct { |
973 | struct rb_node *root; | 842 | struct rb_node *root; |
974 | struct rb_node **pptr; | 843 | struct rb_node **pptr; |
975 | u32 *pid; | 844 | u32 *pid; |
976 | } stk[TC_HTB_MAXDEPTH],*sp = stk; | 845 | } stk[TC_HTB_MAXDEPTH], *sp = stk; |
977 | 846 | ||
978 | BUG_TRAP(tree->rb_node); | 847 | BUG_TRAP(tree->rb_node); |
979 | sp->root = tree->rb_node; | 848 | sp->root = tree->rb_node; |
980 | sp->pptr = pptr; | 849 | sp->pptr = pptr; |
981 | sp->pid = pid; | 850 | sp->pid = pid; |
982 | 851 | ||
983 | for (i = 0; i < 65535; i++) { | 852 | for (i = 0; i < 65535; i++) { |
984 | HTB_DBG(4,2,"htb_lleaf ptr=%p pid=%X\n",*sp->pptr,*sp->pid); | 853 | if (!*sp->pptr && *sp->pid) { |
985 | |||
986 | if (!*sp->pptr && *sp->pid) { | ||
987 | /* ptr was invalidated but id is valid - try to recover | 854 | /* ptr was invalidated but id is valid - try to recover |
988 | the original or next ptr */ | 855 | the original or next ptr */ |
989 | *sp->pptr = htb_id_find_next_upper(prio,sp->root,*sp->pid); | 856 | *sp->pptr = |
857 | htb_id_find_next_upper(prio, sp->root, *sp->pid); | ||
990 | } | 858 | } |
991 | *sp->pid = 0; /* ptr is valid now so that remove this hint as it | 859 | *sp->pid = 0; /* ptr is valid now so that remove this hint as it |
992 | can become out of date quickly */ | 860 | can become out of date quickly */ |
993 | if (!*sp->pptr) { /* we are at right end; rewind & go up */ | 861 | if (!*sp->pptr) { /* we are at right end; rewind & go up */ |
994 | *sp->pptr = sp->root; | 862 | *sp->pptr = sp->root; |
995 | while ((*sp->pptr)->rb_left) | 863 | while ((*sp->pptr)->rb_left) |
996 | *sp->pptr = (*sp->pptr)->rb_left; | 864 | *sp->pptr = (*sp->pptr)->rb_left; |
997 | if (sp > stk) { | 865 | if (sp > stk) { |
998 | sp--; | 866 | sp--; |
999 | BUG_TRAP(*sp->pptr); if(!*sp->pptr) return NULL; | 867 | BUG_TRAP(*sp->pptr); |
1000 | htb_next_rb_node (sp->pptr); | 868 | if (!*sp->pptr) |
869 | return NULL; | ||
870 | htb_next_rb_node(sp->pptr); | ||
1001 | } | 871 | } |
1002 | } else { | 872 | } else { |
1003 | struct htb_class *cl; | 873 | struct htb_class *cl; |
1004 | cl = rb_entry(*sp->pptr,struct htb_class,node[prio]); | 874 | cl = rb_entry(*sp->pptr, struct htb_class, node[prio]); |
1005 | HTB_CHCL(cl); | 875 | if (!cl->level) |
1006 | if (!cl->level) | ||
1007 | return cl; | 876 | return cl; |
1008 | (++sp)->root = cl->un.inner.feed[prio].rb_node; | 877 | (++sp)->root = cl->un.inner.feed[prio].rb_node; |
1009 | sp->pptr = cl->un.inner.ptr+prio; | 878 | sp->pptr = cl->un.inner.ptr + prio; |
1010 | sp->pid = cl->un.inner.last_ptr_id+prio; | 879 | sp->pid = cl->un.inner.last_ptr_id + prio; |
1011 | } | 880 | } |
1012 | } | 881 | } |
1013 | BUG_TRAP(0); | 882 | BUG_TRAP(0); |
@@ -1016,21 +885,21 @@ htb_lookup_leaf(HTB_ARGQ struct rb_root *tree,int prio,struct rb_node **pptr,u32 | |||
1016 | 885 | ||
1017 | /* dequeues packet at given priority and level; call only if | 886 | /* dequeues packet at given priority and level; call only if |
1018 | you are sure that there is active class at prio/level */ | 887 | you are sure that there is active class at prio/level */ |
1019 | static struct sk_buff * | 888 | static struct sk_buff *htb_dequeue_tree(struct htb_sched *q, int prio, |
1020 | htb_dequeue_tree(struct htb_sched *q,int prio,int level) | 889 | int level) |
1021 | { | 890 | { |
1022 | struct sk_buff *skb = NULL; | 891 | struct sk_buff *skb = NULL; |
1023 | struct htb_class *cl,*start; | 892 | struct htb_class *cl, *start; |
1024 | /* look initial class up in the row */ | 893 | /* look initial class up in the row */ |
1025 | start = cl = htb_lookup_leaf (HTB_PASSQ q->row[level]+prio,prio, | 894 | start = cl = htb_lookup_leaf(q->row[level] + prio, prio, |
1026 | q->ptr[level]+prio,q->last_ptr_id[level]+prio); | 895 | q->ptr[level] + prio, |
1027 | 896 | q->last_ptr_id[level] + prio); | |
897 | |||
1028 | do { | 898 | do { |
1029 | next: | 899 | next: |
1030 | BUG_TRAP(cl); | 900 | BUG_TRAP(cl); |
1031 | if (!cl) return NULL; | 901 | if (!cl) |
1032 | HTB_DBG(4,1,"htb_deq_tr prio=%d lev=%d cl=%X defic=%d\n", | 902 | return NULL; |
1033 | prio,level,cl->classid,cl->un.leaf.deficit[level]); | ||
1034 | 903 | ||
1035 | /* class can be empty - it is unlikely but can be true if leaf | 904 | /* class can be empty - it is unlikely but can be true if leaf |
1036 | qdisc drops packets in enqueue routine or if someone used | 905 | qdisc drops packets in enqueue routine or if someone used |
@@ -1038,64 +907,69 @@ next: | |||
1038 | simply deactivate and skip such class */ | 907 | simply deactivate and skip such class */ |
1039 | if (unlikely(cl->un.leaf.q->q.qlen == 0)) { | 908 | if (unlikely(cl->un.leaf.q->q.qlen == 0)) { |
1040 | struct htb_class *next; | 909 | struct htb_class *next; |
1041 | htb_deactivate(q,cl); | 910 | htb_deactivate(q, cl); |
1042 | 911 | ||
1043 | /* row/level might become empty */ | 912 | /* row/level might become empty */ |
1044 | if ((q->row_mask[level] & (1 << prio)) == 0) | 913 | if ((q->row_mask[level] & (1 << prio)) == 0) |
1045 | return NULL; | 914 | return NULL; |
1046 | 915 | ||
1047 | next = htb_lookup_leaf (HTB_PASSQ q->row[level]+prio, | 916 | next = htb_lookup_leaf(q->row[level] + prio, |
1048 | prio,q->ptr[level]+prio,q->last_ptr_id[level]+prio); | 917 | prio, q->ptr[level] + prio, |
918 | q->last_ptr_id[level] + prio); | ||
1049 | 919 | ||
1050 | if (cl == start) /* fix start if we just deleted it */ | 920 | if (cl == start) /* fix start if we just deleted it */ |
1051 | start = next; | 921 | start = next; |
1052 | cl = next; | 922 | cl = next; |
1053 | goto next; | 923 | goto next; |
1054 | } | 924 | } |
1055 | 925 | ||
1056 | if (likely((skb = cl->un.leaf.q->dequeue(cl->un.leaf.q)) != NULL)) | 926 | skb = cl->un.leaf.q->dequeue(cl->un.leaf.q); |
927 | if (likely(skb != NULL)) | ||
1057 | break; | 928 | break; |
1058 | if (!cl->warned) { | 929 | if (!cl->warned) { |
1059 | printk(KERN_WARNING "htb: class %X isn't work conserving ?!\n",cl->classid); | 930 | printk(KERN_WARNING |
931 | "htb: class %X isn't work conserving ?!\n", | ||
932 | cl->classid); | ||
1060 | cl->warned = 1; | 933 | cl->warned = 1; |
1061 | } | 934 | } |
1062 | q->nwc_hit++; | 935 | q->nwc_hit++; |
1063 | htb_next_rb_node((level?cl->parent->un.inner.ptr:q->ptr[0])+prio); | 936 | htb_next_rb_node((level ? cl->parent->un.inner.ptr : q-> |
1064 | cl = htb_lookup_leaf (HTB_PASSQ q->row[level]+prio,prio,q->ptr[level]+prio, | 937 | ptr[0]) + prio); |
1065 | q->last_ptr_id[level]+prio); | 938 | cl = htb_lookup_leaf(q->row[level] + prio, prio, |
939 | q->ptr[level] + prio, | ||
940 | q->last_ptr_id[level] + prio); | ||
1066 | 941 | ||
1067 | } while (cl != start); | 942 | } while (cl != start); |
1068 | 943 | ||
1069 | if (likely(skb != NULL)) { | 944 | if (likely(skb != NULL)) { |
1070 | if ((cl->un.leaf.deficit[level] -= skb->len) < 0) { | 945 | if ((cl->un.leaf.deficit[level] -= skb->len) < 0) { |
1071 | HTB_DBG(4,2,"htb_next_cl oldptr=%p quant_add=%d\n", | ||
1072 | level?cl->parent->un.inner.ptr[prio]:q->ptr[0][prio],cl->un.leaf.quantum); | ||
1073 | cl->un.leaf.deficit[level] += cl->un.leaf.quantum; | 946 | cl->un.leaf.deficit[level] += cl->un.leaf.quantum; |
1074 | htb_next_rb_node((level?cl->parent->un.inner.ptr:q->ptr[0])+prio); | 947 | htb_next_rb_node((level ? cl->parent->un.inner.ptr : q-> |
948 | ptr[0]) + prio); | ||
1075 | } | 949 | } |
1076 | /* this used to be after charge_class but this constelation | 950 | /* this used to be after charge_class but this constelation |
1077 | gives us slightly better performance */ | 951 | gives us slightly better performance */ |
1078 | if (!cl->un.leaf.q->q.qlen) | 952 | if (!cl->un.leaf.q->q.qlen) |
1079 | htb_deactivate (q,cl); | 953 | htb_deactivate(q, cl); |
1080 | htb_charge_class (q,cl,level,skb->len); | 954 | htb_charge_class(q, cl, level, skb->len); |
1081 | } | 955 | } |
1082 | return skb; | 956 | return skb; |
1083 | } | 957 | } |
1084 | 958 | ||
1085 | static void htb_delay_by(struct Qdisc *sch,long delay) | 959 | static void htb_delay_by(struct Qdisc *sch, long delay) |
1086 | { | 960 | { |
1087 | struct htb_sched *q = qdisc_priv(sch); | 961 | struct htb_sched *q = qdisc_priv(sch); |
1088 | if (delay <= 0) delay = 1; | 962 | if (delay <= 0) |
1089 | if (unlikely(delay > 5*HZ)) { | 963 | delay = 1; |
964 | if (unlikely(delay > 5 * HZ)) { | ||
1090 | if (net_ratelimit()) | 965 | if (net_ratelimit()) |
1091 | printk(KERN_INFO "HTB delay %ld > 5sec\n", delay); | 966 | printk(KERN_INFO "HTB delay %ld > 5sec\n", delay); |
1092 | delay = 5*HZ; | 967 | delay = 5 * HZ; |
1093 | } | 968 | } |
1094 | /* why don't use jiffies here ? because expires can be in past */ | 969 | /* why don't use jiffies here ? because expires can be in past */ |
1095 | mod_timer(&q->timer, q->jiffies + delay); | 970 | mod_timer(&q->timer, q->jiffies + delay); |
1096 | sch->flags |= TCQ_F_THROTTLED; | 971 | sch->flags |= TCQ_F_THROTTLED; |
1097 | sch->qstats.overlimits++; | 972 | sch->qstats.overlimits++; |
1098 | HTB_DBG(3,1,"htb_deq t_delay=%ld\n",delay); | ||
1099 | } | 973 | } |
1100 | 974 | ||
1101 | static struct sk_buff *htb_dequeue(struct Qdisc *sch) | 975 | static struct sk_buff *htb_dequeue(struct Qdisc *sch) |
@@ -1104,22 +978,19 @@ static struct sk_buff *htb_dequeue(struct Qdisc *sch) | |||
1104 | struct htb_sched *q = qdisc_priv(sch); | 978 | struct htb_sched *q = qdisc_priv(sch); |
1105 | int level; | 979 | int level; |
1106 | long min_delay; | 980 | long min_delay; |
1107 | #ifdef HTB_DEBUG | ||
1108 | int evs_used = 0; | ||
1109 | #endif | ||
1110 | 981 | ||
1111 | q->jiffies = jiffies; | 982 | q->jiffies = jiffies; |
1112 | HTB_DBG(3,1,"htb_deq dircnt=%d qlen=%d\n",skb_queue_len(&q->direct_queue), | ||
1113 | sch->q.qlen); | ||
1114 | 983 | ||
1115 | /* try to dequeue direct packets as high prio (!) to minimize cpu work */ | 984 | /* try to dequeue direct packets as high prio (!) to minimize cpu work */ |
1116 | if ((skb = __skb_dequeue(&q->direct_queue)) != NULL) { | 985 | skb = __skb_dequeue(&q->direct_queue); |
986 | if (skb != NULL) { | ||
1117 | sch->flags &= ~TCQ_F_THROTTLED; | 987 | sch->flags &= ~TCQ_F_THROTTLED; |
1118 | sch->q.qlen--; | 988 | sch->q.qlen--; |
1119 | return skb; | 989 | return skb; |
1120 | } | 990 | } |
1121 | 991 | ||
1122 | if (!sch->q.qlen) goto fin; | 992 | if (!sch->q.qlen) |
993 | goto fin; | ||
1123 | PSCHED_GET_TIME(q->now); | 994 | PSCHED_GET_TIME(q->now); |
1124 | 995 | ||
1125 | min_delay = LONG_MAX; | 996 | min_delay = LONG_MAX; |
@@ -1129,21 +1000,19 @@ static struct sk_buff *htb_dequeue(struct Qdisc *sch) | |||
1129 | int m; | 1000 | int m; |
1130 | long delay; | 1001 | long delay; |
1131 | if (time_after_eq(q->jiffies, q->near_ev_cache[level])) { | 1002 | if (time_after_eq(q->jiffies, q->near_ev_cache[level])) { |
1132 | delay = htb_do_events(q,level); | 1003 | delay = htb_do_events(q, level); |
1133 | q->near_ev_cache[level] = q->jiffies + (delay ? delay : HZ); | 1004 | q->near_ev_cache[level] = |
1134 | #ifdef HTB_DEBUG | 1005 | q->jiffies + (delay ? delay : HZ); |
1135 | evs_used++; | ||
1136 | #endif | ||
1137 | } else | 1006 | } else |
1138 | delay = q->near_ev_cache[level] - q->jiffies; | 1007 | delay = q->near_ev_cache[level] - q->jiffies; |
1139 | 1008 | ||
1140 | if (delay && min_delay > delay) | 1009 | if (delay && min_delay > delay) |
1141 | min_delay = delay; | 1010 | min_delay = delay; |
1142 | m = ~q->row_mask[level]; | 1011 | m = ~q->row_mask[level]; |
1143 | while (m != (int)(-1)) { | 1012 | while (m != (int)(-1)) { |
1144 | int prio = ffz (m); | 1013 | int prio = ffz(m); |
1145 | m |= 1 << prio; | 1014 | m |= 1 << prio; |
1146 | skb = htb_dequeue_tree(q,prio,level); | 1015 | skb = htb_dequeue_tree(q, prio, level); |
1147 | if (likely(skb != NULL)) { | 1016 | if (likely(skb != NULL)) { |
1148 | sch->q.qlen--; | 1017 | sch->q.qlen--; |
1149 | sch->flags &= ~TCQ_F_THROTTLED; | 1018 | sch->flags &= ~TCQ_F_THROTTLED; |
@@ -1151,40 +1020,28 @@ static struct sk_buff *htb_dequeue(struct Qdisc *sch) | |||
1151 | } | 1020 | } |
1152 | } | 1021 | } |
1153 | } | 1022 | } |
1154 | #ifdef HTB_DEBUG | 1023 | htb_delay_by(sch, min_delay > 5 * HZ ? 5 * HZ : min_delay); |
1155 | if (!q->nwc_hit && min_delay >= 10*HZ && net_ratelimit()) { | ||
1156 | if (min_delay == LONG_MAX) { | ||
1157 | printk(KERN_ERR "HTB: dequeue bug (%d,%lu,%lu), report it please !\n", | ||
1158 | evs_used,q->jiffies,jiffies); | ||
1159 | htb_debug_dump(q); | ||
1160 | } else | ||
1161 | printk(KERN_WARNING "HTB: mindelay=%ld, some class has " | ||
1162 | "too small rate\n",min_delay); | ||
1163 | } | ||
1164 | #endif | ||
1165 | htb_delay_by (sch,min_delay > 5*HZ ? 5*HZ : min_delay); | ||
1166 | fin: | 1024 | fin: |
1167 | HTB_DBG(3,1,"htb_deq_end %s j=%lu skb=%p\n",sch->dev->name,q->jiffies,skb); | ||
1168 | return skb; | 1025 | return skb; |
1169 | } | 1026 | } |
1170 | 1027 | ||
1171 | /* try to drop from each class (by prio) until one succeed */ | 1028 | /* try to drop from each class (by prio) until one succeed */ |
1172 | static unsigned int htb_drop(struct Qdisc* sch) | 1029 | static unsigned int htb_drop(struct Qdisc *sch) |
1173 | { | 1030 | { |
1174 | struct htb_sched *q = qdisc_priv(sch); | 1031 | struct htb_sched *q = qdisc_priv(sch); |
1175 | int prio; | 1032 | int prio; |
1176 | 1033 | ||
1177 | for (prio = TC_HTB_NUMPRIO - 1; prio >= 0; prio--) { | 1034 | for (prio = TC_HTB_NUMPRIO - 1; prio >= 0; prio--) { |
1178 | struct list_head *p; | 1035 | struct list_head *p; |
1179 | list_for_each (p,q->drops+prio) { | 1036 | list_for_each(p, q->drops + prio) { |
1180 | struct htb_class *cl = list_entry(p, struct htb_class, | 1037 | struct htb_class *cl = list_entry(p, struct htb_class, |
1181 | un.leaf.drop_list); | 1038 | un.leaf.drop_list); |
1182 | unsigned int len; | 1039 | unsigned int len; |
1183 | if (cl->un.leaf.q->ops->drop && | 1040 | if (cl->un.leaf.q->ops->drop && |
1184 | (len = cl->un.leaf.q->ops->drop(cl->un.leaf.q))) { | 1041 | (len = cl->un.leaf.q->ops->drop(cl->un.leaf.q))) { |
1185 | sch->q.qlen--; | 1042 | sch->q.qlen--; |
1186 | if (!cl->un.leaf.q->q.qlen) | 1043 | if (!cl->un.leaf.q->q.qlen) |
1187 | htb_deactivate (q,cl); | 1044 | htb_deactivate(q, cl); |
1188 | return len; | 1045 | return len; |
1189 | } | 1046 | } |
1190 | } | 1047 | } |
@@ -1194,29 +1051,25 @@ static unsigned int htb_drop(struct Qdisc* sch) | |||
1194 | 1051 | ||
1195 | /* reset all classes */ | 1052 | /* reset all classes */ |
1196 | /* always caled under BH & queue lock */ | 1053 | /* always caled under BH & queue lock */ |
1197 | static void htb_reset(struct Qdisc* sch) | 1054 | static void htb_reset(struct Qdisc *sch) |
1198 | { | 1055 | { |
1199 | struct htb_sched *q = qdisc_priv(sch); | 1056 | struct htb_sched *q = qdisc_priv(sch); |
1200 | int i; | 1057 | int i; |
1201 | HTB_DBG(0,1,"htb_reset sch=%p, handle=%X\n",sch,sch->handle); | ||
1202 | 1058 | ||
1203 | for (i = 0; i < HTB_HSIZE; i++) { | 1059 | for (i = 0; i < HTB_HSIZE; i++) { |
1204 | struct list_head *p; | 1060 | struct hlist_node *p; |
1205 | list_for_each (p,q->hash+i) { | 1061 | struct htb_class *cl; |
1206 | struct htb_class *cl = list_entry(p,struct htb_class,hlist); | 1062 | |
1063 | hlist_for_each_entry(cl, p, q->hash + i, hlist) { | ||
1207 | if (cl->level) | 1064 | if (cl->level) |
1208 | memset(&cl->un.inner,0,sizeof(cl->un.inner)); | 1065 | memset(&cl->un.inner, 0, sizeof(cl->un.inner)); |
1209 | else { | 1066 | else { |
1210 | if (cl->un.leaf.q) | 1067 | if (cl->un.leaf.q) |
1211 | qdisc_reset(cl->un.leaf.q); | 1068 | qdisc_reset(cl->un.leaf.q); |
1212 | INIT_LIST_HEAD(&cl->un.leaf.drop_list); | 1069 | INIT_LIST_HEAD(&cl->un.leaf.drop_list); |
1213 | } | 1070 | } |
1214 | cl->prio_activity = 0; | 1071 | cl->prio_activity = 0; |
1215 | cl->cmode = HTB_CAN_SEND; | 1072 | cl->cmode = HTB_CAN_SEND; |
1216 | #ifdef HTB_DEBUG | ||
1217 | cl->pq_node.rb_color = -1; | ||
1218 | memset(cl->node,255,sizeof(cl->node)); | ||
1219 | #endif | ||
1220 | 1073 | ||
1221 | } | 1074 | } |
1222 | } | 1075 | } |
@@ -1224,12 +1077,12 @@ static void htb_reset(struct Qdisc* sch) | |||
1224 | del_timer(&q->timer); | 1077 | del_timer(&q->timer); |
1225 | __skb_queue_purge(&q->direct_queue); | 1078 | __skb_queue_purge(&q->direct_queue); |
1226 | sch->q.qlen = 0; | 1079 | sch->q.qlen = 0; |
1227 | memset(q->row,0,sizeof(q->row)); | 1080 | memset(q->row, 0, sizeof(q->row)); |
1228 | memset(q->row_mask,0,sizeof(q->row_mask)); | 1081 | memset(q->row_mask, 0, sizeof(q->row_mask)); |
1229 | memset(q->wait_pq,0,sizeof(q->wait_pq)); | 1082 | memset(q->wait_pq, 0, sizeof(q->wait_pq)); |
1230 | memset(q->ptr,0,sizeof(q->ptr)); | 1083 | memset(q->ptr, 0, sizeof(q->ptr)); |
1231 | for (i = 0; i < TC_HTB_NUMPRIO; i++) | 1084 | for (i = 0; i < TC_HTB_NUMPRIO; i++) |
1232 | INIT_LIST_HEAD(q->drops+i); | 1085 | INIT_LIST_HEAD(q->drops + i); |
1233 | } | 1086 | } |
1234 | 1087 | ||
1235 | static int htb_init(struct Qdisc *sch, struct rtattr *opt) | 1088 | static int htb_init(struct Qdisc *sch, struct rtattr *opt) |
@@ -1238,36 +1091,31 @@ static int htb_init(struct Qdisc *sch, struct rtattr *opt) | |||
1238 | struct rtattr *tb[TCA_HTB_INIT]; | 1091 | struct rtattr *tb[TCA_HTB_INIT]; |
1239 | struct tc_htb_glob *gopt; | 1092 | struct tc_htb_glob *gopt; |
1240 | int i; | 1093 | int i; |
1241 | #ifdef HTB_DEBUG | ||
1242 | printk(KERN_INFO "HTB init, kernel part version %d.%d\n", | ||
1243 | HTB_VER >> 16,HTB_VER & 0xffff); | ||
1244 | #endif | ||
1245 | if (!opt || rtattr_parse_nested(tb, TCA_HTB_INIT, opt) || | 1094 | if (!opt || rtattr_parse_nested(tb, TCA_HTB_INIT, opt) || |
1246 | tb[TCA_HTB_INIT-1] == NULL || | 1095 | tb[TCA_HTB_INIT - 1] == NULL || |
1247 | RTA_PAYLOAD(tb[TCA_HTB_INIT-1]) < sizeof(*gopt)) { | 1096 | RTA_PAYLOAD(tb[TCA_HTB_INIT - 1]) < sizeof(*gopt)) { |
1248 | printk(KERN_ERR "HTB: hey probably you have bad tc tool ?\n"); | 1097 | printk(KERN_ERR "HTB: hey probably you have bad tc tool ?\n"); |
1249 | return -EINVAL; | 1098 | return -EINVAL; |
1250 | } | 1099 | } |
1251 | gopt = RTA_DATA(tb[TCA_HTB_INIT-1]); | 1100 | gopt = RTA_DATA(tb[TCA_HTB_INIT - 1]); |
1252 | if (gopt->version != HTB_VER >> 16) { | 1101 | if (gopt->version != HTB_VER >> 16) { |
1253 | printk(KERN_ERR "HTB: need tc/htb version %d (minor is %d), you have %d\n", | 1102 | printk(KERN_ERR |
1254 | HTB_VER >> 16,HTB_VER & 0xffff,gopt->version); | 1103 | "HTB: need tc/htb version %d (minor is %d), you have %d\n", |
1104 | HTB_VER >> 16, HTB_VER & 0xffff, gopt->version); | ||
1255 | return -EINVAL; | 1105 | return -EINVAL; |
1256 | } | 1106 | } |
1257 | q->debug = gopt->debug; | ||
1258 | HTB_DBG(0,1,"htb_init sch=%p handle=%X r2q=%d\n",sch,sch->handle,gopt->rate2quantum); | ||
1259 | 1107 | ||
1260 | INIT_LIST_HEAD(&q->root); | 1108 | INIT_LIST_HEAD(&q->root); |
1261 | for (i = 0; i < HTB_HSIZE; i++) | 1109 | for (i = 0; i < HTB_HSIZE; i++) |
1262 | INIT_LIST_HEAD(q->hash+i); | 1110 | INIT_HLIST_HEAD(q->hash + i); |
1263 | for (i = 0; i < TC_HTB_NUMPRIO; i++) | 1111 | for (i = 0; i < TC_HTB_NUMPRIO; i++) |
1264 | INIT_LIST_HEAD(q->drops+i); | 1112 | INIT_LIST_HEAD(q->drops + i); |
1265 | 1113 | ||
1266 | init_timer(&q->timer); | 1114 | init_timer(&q->timer); |
1267 | skb_queue_head_init(&q->direct_queue); | 1115 | skb_queue_head_init(&q->direct_queue); |
1268 | 1116 | ||
1269 | q->direct_qlen = sch->dev->tx_queue_len; | 1117 | q->direct_qlen = sch->dev->tx_queue_len; |
1270 | if (q->direct_qlen < 2) /* some devices have zero tx_queue_len */ | 1118 | if (q->direct_qlen < 2) /* some devices have zero tx_queue_len */ |
1271 | q->direct_qlen = 2; | 1119 | q->direct_qlen = 2; |
1272 | q->timer.function = htb_timer; | 1120 | q->timer.function = htb_timer; |
1273 | q->timer.data = (unsigned long)sch; | 1121 | q->timer.data = (unsigned long)sch; |
@@ -1289,80 +1137,72 @@ static int htb_init(struct Qdisc *sch, struct rtattr *opt) | |||
1289 | static int htb_dump(struct Qdisc *sch, struct sk_buff *skb) | 1137 | static int htb_dump(struct Qdisc *sch, struct sk_buff *skb) |
1290 | { | 1138 | { |
1291 | struct htb_sched *q = qdisc_priv(sch); | 1139 | struct htb_sched *q = qdisc_priv(sch); |
1292 | unsigned char *b = skb->tail; | 1140 | unsigned char *b = skb->tail; |
1293 | struct rtattr *rta; | 1141 | struct rtattr *rta; |
1294 | struct tc_htb_glob gopt; | 1142 | struct tc_htb_glob gopt; |
1295 | HTB_DBG(0,1,"htb_dump sch=%p, handle=%X\n",sch,sch->handle); | 1143 | spin_lock_bh(&sch->dev->queue_lock); |
1296 | HTB_QLOCK(sch); | ||
1297 | gopt.direct_pkts = q->direct_pkts; | 1144 | gopt.direct_pkts = q->direct_pkts; |
1298 | 1145 | ||
1299 | #ifdef HTB_DEBUG | ||
1300 | if (HTB_DBG_COND(0,2)) | ||
1301 | htb_debug_dump(q); | ||
1302 | #endif | ||
1303 | gopt.version = HTB_VER; | 1146 | gopt.version = HTB_VER; |
1304 | gopt.rate2quantum = q->rate2quantum; | 1147 | gopt.rate2quantum = q->rate2quantum; |
1305 | gopt.defcls = q->defcls; | 1148 | gopt.defcls = q->defcls; |
1306 | gopt.debug = q->debug; | 1149 | gopt.debug = 0; |
1307 | rta = (struct rtattr*)b; | 1150 | rta = (struct rtattr *)b; |
1308 | RTA_PUT(skb, TCA_OPTIONS, 0, NULL); | 1151 | RTA_PUT(skb, TCA_OPTIONS, 0, NULL); |
1309 | RTA_PUT(skb, TCA_HTB_INIT, sizeof(gopt), &gopt); | 1152 | RTA_PUT(skb, TCA_HTB_INIT, sizeof(gopt), &gopt); |
1310 | rta->rta_len = skb->tail - b; | 1153 | rta->rta_len = skb->tail - b; |
1311 | HTB_QUNLOCK(sch); | 1154 | spin_unlock_bh(&sch->dev->queue_lock); |
1312 | return skb->len; | 1155 | return skb->len; |
1313 | rtattr_failure: | 1156 | rtattr_failure: |
1314 | HTB_QUNLOCK(sch); | 1157 | spin_unlock_bh(&sch->dev->queue_lock); |
1315 | skb_trim(skb, skb->tail - skb->data); | 1158 | skb_trim(skb, skb->tail - skb->data); |
1316 | return -1; | 1159 | return -1; |
1317 | } | 1160 | } |
1318 | 1161 | ||
1319 | static int htb_dump_class(struct Qdisc *sch, unsigned long arg, | 1162 | static int htb_dump_class(struct Qdisc *sch, unsigned long arg, |
1320 | struct sk_buff *skb, struct tcmsg *tcm) | 1163 | struct sk_buff *skb, struct tcmsg *tcm) |
1321 | { | 1164 | { |
1322 | #ifdef HTB_DEBUG | 1165 | struct htb_class *cl = (struct htb_class *)arg; |
1323 | struct htb_sched *q = qdisc_priv(sch); | 1166 | unsigned char *b = skb->tail; |
1324 | #endif | ||
1325 | struct htb_class *cl = (struct htb_class*)arg; | ||
1326 | unsigned char *b = skb->tail; | ||
1327 | struct rtattr *rta; | 1167 | struct rtattr *rta; |
1328 | struct tc_htb_opt opt; | 1168 | struct tc_htb_opt opt; |
1329 | 1169 | ||
1330 | HTB_DBG(0,1,"htb_dump_class handle=%X clid=%X\n",sch->handle,cl->classid); | 1170 | spin_lock_bh(&sch->dev->queue_lock); |
1331 | |||
1332 | HTB_QLOCK(sch); | ||
1333 | tcm->tcm_parent = cl->parent ? cl->parent->classid : TC_H_ROOT; | 1171 | tcm->tcm_parent = cl->parent ? cl->parent->classid : TC_H_ROOT; |
1334 | tcm->tcm_handle = cl->classid; | 1172 | tcm->tcm_handle = cl->classid; |
1335 | if (!cl->level && cl->un.leaf.q) | 1173 | if (!cl->level && cl->un.leaf.q) |
1336 | tcm->tcm_info = cl->un.leaf.q->handle; | 1174 | tcm->tcm_info = cl->un.leaf.q->handle; |
1337 | 1175 | ||
1338 | rta = (struct rtattr*)b; | 1176 | rta = (struct rtattr *)b; |
1339 | RTA_PUT(skb, TCA_OPTIONS, 0, NULL); | 1177 | RTA_PUT(skb, TCA_OPTIONS, 0, NULL); |
1340 | 1178 | ||
1341 | memset (&opt,0,sizeof(opt)); | 1179 | memset(&opt, 0, sizeof(opt)); |
1342 | 1180 | ||
1343 | opt.rate = cl->rate->rate; opt.buffer = cl->buffer; | 1181 | opt.rate = cl->rate->rate; |
1344 | opt.ceil = cl->ceil->rate; opt.cbuffer = cl->cbuffer; | 1182 | opt.buffer = cl->buffer; |
1345 | opt.quantum = cl->un.leaf.quantum; opt.prio = cl->un.leaf.prio; | 1183 | opt.ceil = cl->ceil->rate; |
1346 | opt.level = cl->level; | 1184 | opt.cbuffer = cl->cbuffer; |
1185 | opt.quantum = cl->un.leaf.quantum; | ||
1186 | opt.prio = cl->un.leaf.prio; | ||
1187 | opt.level = cl->level; | ||
1347 | RTA_PUT(skb, TCA_HTB_PARMS, sizeof(opt), &opt); | 1188 | RTA_PUT(skb, TCA_HTB_PARMS, sizeof(opt), &opt); |
1348 | rta->rta_len = skb->tail - b; | 1189 | rta->rta_len = skb->tail - b; |
1349 | HTB_QUNLOCK(sch); | 1190 | spin_unlock_bh(&sch->dev->queue_lock); |
1350 | return skb->len; | 1191 | return skb->len; |
1351 | rtattr_failure: | 1192 | rtattr_failure: |
1352 | HTB_QUNLOCK(sch); | 1193 | spin_unlock_bh(&sch->dev->queue_lock); |
1353 | skb_trim(skb, b - skb->data); | 1194 | skb_trim(skb, b - skb->data); |
1354 | return -1; | 1195 | return -1; |
1355 | } | 1196 | } |
1356 | 1197 | ||
1357 | static int | 1198 | static int |
1358 | htb_dump_class_stats(struct Qdisc *sch, unsigned long arg, | 1199 | htb_dump_class_stats(struct Qdisc *sch, unsigned long arg, struct gnet_dump *d) |
1359 | struct gnet_dump *d) | ||
1360 | { | 1200 | { |
1361 | struct htb_class *cl = (struct htb_class*)arg; | 1201 | struct htb_class *cl = (struct htb_class *)arg; |
1362 | 1202 | ||
1363 | #ifdef HTB_RATECM | 1203 | #ifdef HTB_RATECM |
1364 | cl->rate_est.bps = cl->rate_bytes/(HTB_EWMAC*HTB_HSIZE); | 1204 | cl->rate_est.bps = cl->rate_bytes / (HTB_EWMAC * HTB_HSIZE); |
1365 | cl->rate_est.pps = cl->rate_packets/(HTB_EWMAC*HTB_HSIZE); | 1205 | cl->rate_est.pps = cl->rate_packets / (HTB_EWMAC * HTB_HSIZE); |
1366 | #endif | 1206 | #endif |
1367 | 1207 | ||
1368 | if (!cl->level && cl->un.leaf.q) | 1208 | if (!cl->level && cl->un.leaf.q) |
@@ -1379,21 +1219,22 @@ htb_dump_class_stats(struct Qdisc *sch, unsigned long arg, | |||
1379 | } | 1219 | } |
1380 | 1220 | ||
1381 | static int htb_graft(struct Qdisc *sch, unsigned long arg, struct Qdisc *new, | 1221 | static int htb_graft(struct Qdisc *sch, unsigned long arg, struct Qdisc *new, |
1382 | struct Qdisc **old) | 1222 | struct Qdisc **old) |
1383 | { | 1223 | { |
1384 | struct htb_class *cl = (struct htb_class*)arg; | 1224 | struct htb_class *cl = (struct htb_class *)arg; |
1385 | 1225 | ||
1386 | if (cl && !cl->level) { | 1226 | if (cl && !cl->level) { |
1387 | if (new == NULL && (new = qdisc_create_dflt(sch->dev, | 1227 | if (new == NULL && (new = qdisc_create_dflt(sch->dev, |
1388 | &pfifo_qdisc_ops)) == NULL) | 1228 | &pfifo_qdisc_ops)) |
1389 | return -ENOBUFS; | 1229 | == NULL) |
1230 | return -ENOBUFS; | ||
1390 | sch_tree_lock(sch); | 1231 | sch_tree_lock(sch); |
1391 | if ((*old = xchg(&cl->un.leaf.q, new)) != NULL) { | 1232 | if ((*old = xchg(&cl->un.leaf.q, new)) != NULL) { |
1392 | if (cl->prio_activity) | 1233 | if (cl->prio_activity) |
1393 | htb_deactivate (qdisc_priv(sch),cl); | 1234 | htb_deactivate(qdisc_priv(sch), cl); |
1394 | 1235 | ||
1395 | /* TODO: is it correct ? Why CBQ doesn't do it ? */ | 1236 | /* TODO: is it correct ? Why CBQ doesn't do it ? */ |
1396 | sch->q.qlen -= (*old)->q.qlen; | 1237 | sch->q.qlen -= (*old)->q.qlen; |
1397 | qdisc_reset(*old); | 1238 | qdisc_reset(*old); |
1398 | } | 1239 | } |
1399 | sch_tree_unlock(sch); | 1240 | sch_tree_unlock(sch); |
@@ -1402,20 +1243,16 @@ static int htb_graft(struct Qdisc *sch, unsigned long arg, struct Qdisc *new, | |||
1402 | return -ENOENT; | 1243 | return -ENOENT; |
1403 | } | 1244 | } |
1404 | 1245 | ||
1405 | static struct Qdisc * htb_leaf(struct Qdisc *sch, unsigned long arg) | 1246 | static struct Qdisc *htb_leaf(struct Qdisc *sch, unsigned long arg) |
1406 | { | 1247 | { |
1407 | struct htb_class *cl = (struct htb_class*)arg; | 1248 | struct htb_class *cl = (struct htb_class *)arg; |
1408 | return (cl && !cl->level) ? cl->un.leaf.q : NULL; | 1249 | return (cl && !cl->level) ? cl->un.leaf.q : NULL; |
1409 | } | 1250 | } |
1410 | 1251 | ||
1411 | static unsigned long htb_get(struct Qdisc *sch, u32 classid) | 1252 | static unsigned long htb_get(struct Qdisc *sch, u32 classid) |
1412 | { | 1253 | { |
1413 | #ifdef HTB_DEBUG | 1254 | struct htb_class *cl = htb_find(classid, sch); |
1414 | struct htb_sched *q = qdisc_priv(sch); | 1255 | if (cl) |
1415 | #endif | ||
1416 | struct htb_class *cl = htb_find(classid,sch); | ||
1417 | HTB_DBG(0,1,"htb_get clid=%X q=%p cl=%p ref=%d\n",classid,q,cl,cl?cl->refcnt:0); | ||
1418 | if (cl) | ||
1419 | cl->refcnt++; | 1256 | cl->refcnt++; |
1420 | return (unsigned long)cl; | 1257 | return (unsigned long)cl; |
1421 | } | 1258 | } |
@@ -1430,10 +1267,9 @@ static void htb_destroy_filters(struct tcf_proto **fl) | |||
1430 | } | 1267 | } |
1431 | } | 1268 | } |
1432 | 1269 | ||
1433 | static void htb_destroy_class(struct Qdisc* sch,struct htb_class *cl) | 1270 | static void htb_destroy_class(struct Qdisc *sch, struct htb_class *cl) |
1434 | { | 1271 | { |
1435 | struct htb_sched *q = qdisc_priv(sch); | 1272 | struct htb_sched *q = qdisc_priv(sch); |
1436 | HTB_DBG(0,1,"htb_destrycls clid=%X ref=%d\n", cl?cl->classid:0,cl?cl->refcnt:0); | ||
1437 | if (!cl->level) { | 1273 | if (!cl->level) { |
1438 | BUG_TRAP(cl->un.leaf.q); | 1274 | BUG_TRAP(cl->un.leaf.q); |
1439 | sch->q.qlen -= cl->un.leaf.q->q.qlen; | 1275 | sch->q.qlen -= cl->un.leaf.q->q.qlen; |
@@ -1441,45 +1277,45 @@ static void htb_destroy_class(struct Qdisc* sch,struct htb_class *cl) | |||
1441 | } | 1277 | } |
1442 | qdisc_put_rtab(cl->rate); | 1278 | qdisc_put_rtab(cl->rate); |
1443 | qdisc_put_rtab(cl->ceil); | 1279 | qdisc_put_rtab(cl->ceil); |
1444 | 1280 | ||
1445 | htb_destroy_filters (&cl->filter_list); | 1281 | htb_destroy_filters(&cl->filter_list); |
1446 | 1282 | ||
1447 | while (!list_empty(&cl->children)) | 1283 | while (!list_empty(&cl->children)) |
1448 | htb_destroy_class (sch,list_entry(cl->children.next, | 1284 | htb_destroy_class(sch, list_entry(cl->children.next, |
1449 | struct htb_class,sibling)); | 1285 | struct htb_class, sibling)); |
1450 | 1286 | ||
1451 | /* note: this delete may happen twice (see htb_delete) */ | 1287 | /* note: this delete may happen twice (see htb_delete) */ |
1452 | list_del(&cl->hlist); | 1288 | if (!hlist_unhashed(&cl->hlist)) |
1289 | hlist_del(&cl->hlist); | ||
1453 | list_del(&cl->sibling); | 1290 | list_del(&cl->sibling); |
1454 | 1291 | ||
1455 | if (cl->prio_activity) | 1292 | if (cl->prio_activity) |
1456 | htb_deactivate (q,cl); | 1293 | htb_deactivate(q, cl); |
1457 | 1294 | ||
1458 | if (cl->cmode != HTB_CAN_SEND) | 1295 | if (cl->cmode != HTB_CAN_SEND) |
1459 | htb_safe_rb_erase(&cl->pq_node,q->wait_pq+cl->level); | 1296 | htb_safe_rb_erase(&cl->pq_node, q->wait_pq + cl->level); |
1460 | 1297 | ||
1461 | kfree(cl); | 1298 | kfree(cl); |
1462 | } | 1299 | } |
1463 | 1300 | ||
1464 | /* always caled under BH & queue lock */ | 1301 | /* always caled under BH & queue lock */ |
1465 | static void htb_destroy(struct Qdisc* sch) | 1302 | static void htb_destroy(struct Qdisc *sch) |
1466 | { | 1303 | { |
1467 | struct htb_sched *q = qdisc_priv(sch); | 1304 | struct htb_sched *q = qdisc_priv(sch); |
1468 | HTB_DBG(0,1,"htb_destroy q=%p\n",q); | ||
1469 | 1305 | ||
1470 | del_timer_sync (&q->timer); | 1306 | del_timer_sync(&q->timer); |
1471 | #ifdef HTB_RATECM | 1307 | #ifdef HTB_RATECM |
1472 | del_timer_sync (&q->rttim); | 1308 | del_timer_sync(&q->rttim); |
1473 | #endif | 1309 | #endif |
1474 | /* This line used to be after htb_destroy_class call below | 1310 | /* This line used to be after htb_destroy_class call below |
1475 | and surprisingly it worked in 2.4. But it must precede it | 1311 | and surprisingly it worked in 2.4. But it must precede it |
1476 | because filter need its target class alive to be able to call | 1312 | because filter need its target class alive to be able to call |
1477 | unbind_filter on it (without Oops). */ | 1313 | unbind_filter on it (without Oops). */ |
1478 | htb_destroy_filters(&q->filter_list); | 1314 | htb_destroy_filters(&q->filter_list); |
1479 | 1315 | ||
1480 | while (!list_empty(&q->root)) | 1316 | while (!list_empty(&q->root)) |
1481 | htb_destroy_class (sch,list_entry(q->root.next, | 1317 | htb_destroy_class(sch, list_entry(q->root.next, |
1482 | struct htb_class,sibling)); | 1318 | struct htb_class, sibling)); |
1483 | 1319 | ||
1484 | __skb_queue_purge(&q->direct_queue); | 1320 | __skb_queue_purge(&q->direct_queue); |
1485 | } | 1321 | } |
@@ -1487,24 +1323,25 @@ static void htb_destroy(struct Qdisc* sch) | |||
1487 | static int htb_delete(struct Qdisc *sch, unsigned long arg) | 1323 | static int htb_delete(struct Qdisc *sch, unsigned long arg) |
1488 | { | 1324 | { |
1489 | struct htb_sched *q = qdisc_priv(sch); | 1325 | struct htb_sched *q = qdisc_priv(sch); |
1490 | struct htb_class *cl = (struct htb_class*)arg; | 1326 | struct htb_class *cl = (struct htb_class *)arg; |
1491 | HTB_DBG(0,1,"htb_delete q=%p cl=%X ref=%d\n",q,cl?cl->classid:0,cl?cl->refcnt:0); | ||
1492 | 1327 | ||
1493 | // TODO: why don't allow to delete subtree ? references ? does | 1328 | // TODO: why don't allow to delete subtree ? references ? does |
1494 | // tc subsys quarantee us that in htb_destroy it holds no class | 1329 | // tc subsys quarantee us that in htb_destroy it holds no class |
1495 | // refs so that we can remove children safely there ? | 1330 | // refs so that we can remove children safely there ? |
1496 | if (!list_empty(&cl->children) || cl->filter_cnt) | 1331 | if (!list_empty(&cl->children) || cl->filter_cnt) |
1497 | return -EBUSY; | 1332 | return -EBUSY; |
1498 | 1333 | ||
1499 | sch_tree_lock(sch); | 1334 | sch_tree_lock(sch); |
1500 | 1335 | ||
1501 | /* delete from hash and active; remainder in destroy_class */ | 1336 | /* delete from hash and active; remainder in destroy_class */ |
1502 | list_del_init(&cl->hlist); | 1337 | if (!hlist_unhashed(&cl->hlist)) |
1338 | hlist_del(&cl->hlist); | ||
1339 | |||
1503 | if (cl->prio_activity) | 1340 | if (cl->prio_activity) |
1504 | htb_deactivate (q,cl); | 1341 | htb_deactivate(q, cl); |
1505 | 1342 | ||
1506 | if (--cl->refcnt == 0) | 1343 | if (--cl->refcnt == 0) |
1507 | htb_destroy_class(sch,cl); | 1344 | htb_destroy_class(sch, cl); |
1508 | 1345 | ||
1509 | sch_tree_unlock(sch); | 1346 | sch_tree_unlock(sch); |
1510 | return 0; | 1347 | return 0; |
@@ -1512,45 +1349,46 @@ static int htb_delete(struct Qdisc *sch, unsigned long arg) | |||
1512 | 1349 | ||
1513 | static void htb_put(struct Qdisc *sch, unsigned long arg) | 1350 | static void htb_put(struct Qdisc *sch, unsigned long arg) |
1514 | { | 1351 | { |
1515 | #ifdef HTB_DEBUG | 1352 | struct htb_class *cl = (struct htb_class *)arg; |
1516 | struct htb_sched *q = qdisc_priv(sch); | ||
1517 | #endif | ||
1518 | struct htb_class *cl = (struct htb_class*)arg; | ||
1519 | HTB_DBG(0,1,"htb_put q=%p cl=%X ref=%d\n",q,cl?cl->classid:0,cl?cl->refcnt:0); | ||
1520 | 1353 | ||
1521 | if (--cl->refcnt == 0) | 1354 | if (--cl->refcnt == 0) |
1522 | htb_destroy_class(sch,cl); | 1355 | htb_destroy_class(sch, cl); |
1523 | } | 1356 | } |
1524 | 1357 | ||
1525 | static int htb_change_class(struct Qdisc *sch, u32 classid, | 1358 | static int htb_change_class(struct Qdisc *sch, u32 classid, |
1526 | u32 parentid, struct rtattr **tca, unsigned long *arg) | 1359 | u32 parentid, struct rtattr **tca, |
1360 | unsigned long *arg) | ||
1527 | { | 1361 | { |
1528 | int err = -EINVAL; | 1362 | int err = -EINVAL; |
1529 | struct htb_sched *q = qdisc_priv(sch); | 1363 | struct htb_sched *q = qdisc_priv(sch); |
1530 | struct htb_class *cl = (struct htb_class*)*arg,*parent; | 1364 | struct htb_class *cl = (struct htb_class *)*arg, *parent; |
1531 | struct rtattr *opt = tca[TCA_OPTIONS-1]; | 1365 | struct rtattr *opt = tca[TCA_OPTIONS - 1]; |
1532 | struct qdisc_rate_table *rtab = NULL, *ctab = NULL; | 1366 | struct qdisc_rate_table *rtab = NULL, *ctab = NULL; |
1533 | struct rtattr *tb[TCA_HTB_RTAB]; | 1367 | struct rtattr *tb[TCA_HTB_RTAB]; |
1534 | struct tc_htb_opt *hopt; | 1368 | struct tc_htb_opt *hopt; |
1535 | 1369 | ||
1536 | /* extract all subattrs from opt attr */ | 1370 | /* extract all subattrs from opt attr */ |
1537 | if (!opt || rtattr_parse_nested(tb, TCA_HTB_RTAB, opt) || | 1371 | if (!opt || rtattr_parse_nested(tb, TCA_HTB_RTAB, opt) || |
1538 | tb[TCA_HTB_PARMS-1] == NULL || | 1372 | tb[TCA_HTB_PARMS - 1] == NULL || |
1539 | RTA_PAYLOAD(tb[TCA_HTB_PARMS-1]) < sizeof(*hopt)) | 1373 | RTA_PAYLOAD(tb[TCA_HTB_PARMS - 1]) < sizeof(*hopt)) |
1540 | goto failure; | 1374 | goto failure; |
1541 | |||
1542 | parent = parentid == TC_H_ROOT ? NULL : htb_find (parentid,sch); | ||
1543 | 1375 | ||
1544 | hopt = RTA_DATA(tb[TCA_HTB_PARMS-1]); | 1376 | parent = parentid == TC_H_ROOT ? NULL : htb_find(parentid, sch); |
1545 | HTB_DBG(0,1,"htb_chg cl=%p(%X), clid=%X, parid=%X, opt/prio=%d, rate=%u, buff=%d, quant=%d\n", cl,cl?cl->classid:0,classid,parentid,(int)hopt->prio,hopt->rate.rate,hopt->buffer,hopt->quantum); | 1377 | |
1546 | rtab = qdisc_get_rtab(&hopt->rate, tb[TCA_HTB_RTAB-1]); | 1378 | hopt = RTA_DATA(tb[TCA_HTB_PARMS - 1]); |
1547 | ctab = qdisc_get_rtab(&hopt->ceil, tb[TCA_HTB_CTAB-1]); | 1379 | |
1548 | if (!rtab || !ctab) goto failure; | 1380 | rtab = qdisc_get_rtab(&hopt->rate, tb[TCA_HTB_RTAB - 1]); |
1381 | ctab = qdisc_get_rtab(&hopt->ceil, tb[TCA_HTB_CTAB - 1]); | ||
1382 | if (!rtab || !ctab) | ||
1383 | goto failure; | ||
1549 | 1384 | ||
1550 | if (!cl) { /* new class */ | 1385 | if (!cl) { /* new class */ |
1551 | struct Qdisc *new_q; | 1386 | struct Qdisc *new_q; |
1387 | int prio; | ||
1388 | |||
1552 | /* check for valid classid */ | 1389 | /* check for valid classid */ |
1553 | if (!classid || TC_H_MAJ(classid^sch->handle) || htb_find(classid,sch)) | 1390 | if (!classid || TC_H_MAJ(classid ^ sch->handle) |
1391 | || htb_find(classid, sch)) | ||
1554 | goto failure; | 1392 | goto failure; |
1555 | 1393 | ||
1556 | /* check maximal depth */ | 1394 | /* check maximal depth */ |
@@ -1561,15 +1399,16 @@ static int htb_change_class(struct Qdisc *sch, u32 classid, | |||
1561 | err = -ENOBUFS; | 1399 | err = -ENOBUFS; |
1562 | if ((cl = kzalloc(sizeof(*cl), GFP_KERNEL)) == NULL) | 1400 | if ((cl = kzalloc(sizeof(*cl), GFP_KERNEL)) == NULL) |
1563 | goto failure; | 1401 | goto failure; |
1564 | 1402 | ||
1565 | cl->refcnt = 1; | 1403 | cl->refcnt = 1; |
1566 | INIT_LIST_HEAD(&cl->sibling); | 1404 | INIT_LIST_HEAD(&cl->sibling); |
1567 | INIT_LIST_HEAD(&cl->hlist); | 1405 | INIT_HLIST_NODE(&cl->hlist); |
1568 | INIT_LIST_HEAD(&cl->children); | 1406 | INIT_LIST_HEAD(&cl->children); |
1569 | INIT_LIST_HEAD(&cl->un.leaf.drop_list); | 1407 | INIT_LIST_HEAD(&cl->un.leaf.drop_list); |
1570 | #ifdef HTB_DEBUG | 1408 | RB_CLEAR_NODE(&cl->pq_node); |
1571 | cl->magic = HTB_CMAGIC; | 1409 | |
1572 | #endif | 1410 | for (prio = 0; prio < TC_HTB_NUMPRIO; prio++) |
1411 | RB_CLEAR_NODE(&cl->node[prio]); | ||
1573 | 1412 | ||
1574 | /* create leaf qdisc early because it uses kmalloc(GFP_KERNEL) | 1413 | /* create leaf qdisc early because it uses kmalloc(GFP_KERNEL) |
1575 | so that can't be used inside of sch_tree_lock | 1414 | so that can't be used inside of sch_tree_lock |
@@ -1579,53 +1418,53 @@ static int htb_change_class(struct Qdisc *sch, u32 classid, | |||
1579 | if (parent && !parent->level) { | 1418 | if (parent && !parent->level) { |
1580 | /* turn parent into inner node */ | 1419 | /* turn parent into inner node */ |
1581 | sch->q.qlen -= parent->un.leaf.q->q.qlen; | 1420 | sch->q.qlen -= parent->un.leaf.q->q.qlen; |
1582 | qdisc_destroy (parent->un.leaf.q); | 1421 | qdisc_destroy(parent->un.leaf.q); |
1583 | if (parent->prio_activity) | 1422 | if (parent->prio_activity) |
1584 | htb_deactivate (q,parent); | 1423 | htb_deactivate(q, parent); |
1585 | 1424 | ||
1586 | /* remove from evt list because of level change */ | 1425 | /* remove from evt list because of level change */ |
1587 | if (parent->cmode != HTB_CAN_SEND) { | 1426 | if (parent->cmode != HTB_CAN_SEND) { |
1588 | htb_safe_rb_erase(&parent->pq_node,q->wait_pq /*+0*/); | 1427 | htb_safe_rb_erase(&parent->pq_node, q->wait_pq); |
1589 | parent->cmode = HTB_CAN_SEND; | 1428 | parent->cmode = HTB_CAN_SEND; |
1590 | } | 1429 | } |
1591 | parent->level = (parent->parent ? parent->parent->level | 1430 | parent->level = (parent->parent ? parent->parent->level |
1592 | : TC_HTB_MAXDEPTH) - 1; | 1431 | : TC_HTB_MAXDEPTH) - 1; |
1593 | memset (&parent->un.inner,0,sizeof(parent->un.inner)); | 1432 | memset(&parent->un.inner, 0, sizeof(parent->un.inner)); |
1594 | } | 1433 | } |
1595 | /* leaf (we) needs elementary qdisc */ | 1434 | /* leaf (we) needs elementary qdisc */ |
1596 | cl->un.leaf.q = new_q ? new_q : &noop_qdisc; | 1435 | cl->un.leaf.q = new_q ? new_q : &noop_qdisc; |
1597 | 1436 | ||
1598 | cl->classid = classid; cl->parent = parent; | 1437 | cl->classid = classid; |
1438 | cl->parent = parent; | ||
1599 | 1439 | ||
1600 | /* set class to be in HTB_CAN_SEND state */ | 1440 | /* set class to be in HTB_CAN_SEND state */ |
1601 | cl->tokens = hopt->buffer; | 1441 | cl->tokens = hopt->buffer; |
1602 | cl->ctokens = hopt->cbuffer; | 1442 | cl->ctokens = hopt->cbuffer; |
1603 | cl->mbuffer = PSCHED_JIFFIE2US(HZ*60); /* 1min */ | 1443 | cl->mbuffer = PSCHED_JIFFIE2US(HZ * 60); /* 1min */ |
1604 | PSCHED_GET_TIME(cl->t_c); | 1444 | PSCHED_GET_TIME(cl->t_c); |
1605 | cl->cmode = HTB_CAN_SEND; | 1445 | cl->cmode = HTB_CAN_SEND; |
1606 | 1446 | ||
1607 | /* attach to the hash list and parent's family */ | 1447 | /* attach to the hash list and parent's family */ |
1608 | list_add_tail(&cl->hlist, q->hash+htb_hash(classid)); | 1448 | hlist_add_head(&cl->hlist, q->hash + htb_hash(classid)); |
1609 | list_add_tail(&cl->sibling, parent ? &parent->children : &q->root); | 1449 | list_add_tail(&cl->sibling, |
1610 | #ifdef HTB_DEBUG | 1450 | parent ? &parent->children : &q->root); |
1611 | { | 1451 | } else |
1612 | int i; | 1452 | sch_tree_lock(sch); |
1613 | for (i = 0; i < TC_HTB_NUMPRIO; i++) cl->node[i].rb_color = -1; | ||
1614 | cl->pq_node.rb_color = -1; | ||
1615 | } | ||
1616 | #endif | ||
1617 | } else sch_tree_lock(sch); | ||
1618 | 1453 | ||
1619 | /* it used to be a nasty bug here, we have to check that node | 1454 | /* it used to be a nasty bug here, we have to check that node |
1620 | is really leaf before changing cl->un.leaf ! */ | 1455 | is really leaf before changing cl->un.leaf ! */ |
1621 | if (!cl->level) { | 1456 | if (!cl->level) { |
1622 | cl->un.leaf.quantum = rtab->rate.rate / q->rate2quantum; | 1457 | cl->un.leaf.quantum = rtab->rate.rate / q->rate2quantum; |
1623 | if (!hopt->quantum && cl->un.leaf.quantum < 1000) { | 1458 | if (!hopt->quantum && cl->un.leaf.quantum < 1000) { |
1624 | printk(KERN_WARNING "HTB: quantum of class %X is small. Consider r2q change.\n", cl->classid); | 1459 | printk(KERN_WARNING |
1460 | "HTB: quantum of class %X is small. Consider r2q change.\n", | ||
1461 | cl->classid); | ||
1625 | cl->un.leaf.quantum = 1000; | 1462 | cl->un.leaf.quantum = 1000; |
1626 | } | 1463 | } |
1627 | if (!hopt->quantum && cl->un.leaf.quantum > 200000) { | 1464 | if (!hopt->quantum && cl->un.leaf.quantum > 200000) { |
1628 | printk(KERN_WARNING "HTB: quantum of class %X is big. Consider r2q change.\n", cl->classid); | 1465 | printk(KERN_WARNING |
1466 | "HTB: quantum of class %X is big. Consider r2q change.\n", | ||
1467 | cl->classid); | ||
1629 | cl->un.leaf.quantum = 200000; | 1468 | cl->un.leaf.quantum = 200000; |
1630 | } | 1469 | } |
1631 | if (hopt->quantum) | 1470 | if (hopt->quantum) |
@@ -1636,16 +1475,22 @@ static int htb_change_class(struct Qdisc *sch, u32 classid, | |||
1636 | 1475 | ||
1637 | cl->buffer = hopt->buffer; | 1476 | cl->buffer = hopt->buffer; |
1638 | cl->cbuffer = hopt->cbuffer; | 1477 | cl->cbuffer = hopt->cbuffer; |
1639 | if (cl->rate) qdisc_put_rtab(cl->rate); cl->rate = rtab; | 1478 | if (cl->rate) |
1640 | if (cl->ceil) qdisc_put_rtab(cl->ceil); cl->ceil = ctab; | 1479 | qdisc_put_rtab(cl->rate); |
1480 | cl->rate = rtab; | ||
1481 | if (cl->ceil) | ||
1482 | qdisc_put_rtab(cl->ceil); | ||
1483 | cl->ceil = ctab; | ||
1641 | sch_tree_unlock(sch); | 1484 | sch_tree_unlock(sch); |
1642 | 1485 | ||
1643 | *arg = (unsigned long)cl; | 1486 | *arg = (unsigned long)cl; |
1644 | return 0; | 1487 | return 0; |
1645 | 1488 | ||
1646 | failure: | 1489 | failure: |
1647 | if (rtab) qdisc_put_rtab(rtab); | 1490 | if (rtab) |
1648 | if (ctab) qdisc_put_rtab(ctab); | 1491 | qdisc_put_rtab(rtab); |
1492 | if (ctab) | ||
1493 | qdisc_put_rtab(ctab); | ||
1649 | return err; | 1494 | return err; |
1650 | } | 1495 | } |
1651 | 1496 | ||
@@ -1654,28 +1499,28 @@ static struct tcf_proto **htb_find_tcf(struct Qdisc *sch, unsigned long arg) | |||
1654 | struct htb_sched *q = qdisc_priv(sch); | 1499 | struct htb_sched *q = qdisc_priv(sch); |
1655 | struct htb_class *cl = (struct htb_class *)arg; | 1500 | struct htb_class *cl = (struct htb_class *)arg; |
1656 | struct tcf_proto **fl = cl ? &cl->filter_list : &q->filter_list; | 1501 | struct tcf_proto **fl = cl ? &cl->filter_list : &q->filter_list; |
1657 | HTB_DBG(0,2,"htb_tcf q=%p clid=%X fref=%d fl=%p\n",q,cl?cl->classid:0,cl?cl->filter_cnt:q->filter_cnt,*fl); | 1502 | |
1658 | return fl; | 1503 | return fl; |
1659 | } | 1504 | } |
1660 | 1505 | ||
1661 | static unsigned long htb_bind_filter(struct Qdisc *sch, unsigned long parent, | 1506 | static unsigned long htb_bind_filter(struct Qdisc *sch, unsigned long parent, |
1662 | u32 classid) | 1507 | u32 classid) |
1663 | { | 1508 | { |
1664 | struct htb_sched *q = qdisc_priv(sch); | 1509 | struct htb_sched *q = qdisc_priv(sch); |
1665 | struct htb_class *cl = htb_find (classid,sch); | 1510 | struct htb_class *cl = htb_find(classid, sch); |
1666 | HTB_DBG(0,2,"htb_bind q=%p clid=%X cl=%p fref=%d\n",q,classid,cl,cl?cl->filter_cnt:q->filter_cnt); | 1511 | |
1667 | /*if (cl && !cl->level) return 0; | 1512 | /*if (cl && !cl->level) return 0; |
1668 | The line above used to be there to prevent attaching filters to | 1513 | The line above used to be there to prevent attaching filters to |
1669 | leaves. But at least tc_index filter uses this just to get class | 1514 | leaves. But at least tc_index filter uses this just to get class |
1670 | for other reasons so that we have to allow for it. | 1515 | for other reasons so that we have to allow for it. |
1671 | ---- | 1516 | ---- |
1672 | 19.6.2002 As Werner explained it is ok - bind filter is just | 1517 | 19.6.2002 As Werner explained it is ok - bind filter is just |
1673 | another way to "lock" the class - unlike "get" this lock can | 1518 | another way to "lock" the class - unlike "get" this lock can |
1674 | be broken by class during destroy IIUC. | 1519 | be broken by class during destroy IIUC. |
1675 | */ | 1520 | */ |
1676 | if (cl) | 1521 | if (cl) |
1677 | cl->filter_cnt++; | 1522 | cl->filter_cnt++; |
1678 | else | 1523 | else |
1679 | q->filter_cnt++; | 1524 | q->filter_cnt++; |
1680 | return (unsigned long)cl; | 1525 | return (unsigned long)cl; |
1681 | } | 1526 | } |
@@ -1684,10 +1529,10 @@ static void htb_unbind_filter(struct Qdisc *sch, unsigned long arg) | |||
1684 | { | 1529 | { |
1685 | struct htb_sched *q = qdisc_priv(sch); | 1530 | struct htb_sched *q = qdisc_priv(sch); |
1686 | struct htb_class *cl = (struct htb_class *)arg; | 1531 | struct htb_class *cl = (struct htb_class *)arg; |
1687 | HTB_DBG(0,2,"htb_unbind q=%p cl=%p fref=%d\n",q,cl,cl?cl->filter_cnt:q->filter_cnt); | 1532 | |
1688 | if (cl) | 1533 | if (cl) |
1689 | cl->filter_cnt--; | 1534 | cl->filter_cnt--; |
1690 | else | 1535 | else |
1691 | q->filter_cnt--; | 1536 | q->filter_cnt--; |
1692 | } | 1537 | } |
1693 | 1538 | ||
@@ -1700,9 +1545,10 @@ static void htb_walk(struct Qdisc *sch, struct qdisc_walker *arg) | |||
1700 | return; | 1545 | return; |
1701 | 1546 | ||
1702 | for (i = 0; i < HTB_HSIZE; i++) { | 1547 | for (i = 0; i < HTB_HSIZE; i++) { |
1703 | struct list_head *p; | 1548 | struct hlist_node *p; |
1704 | list_for_each (p,q->hash+i) { | 1549 | struct htb_class *cl; |
1705 | struct htb_class *cl = list_entry(p,struct htb_class,hlist); | 1550 | |
1551 | hlist_for_each_entry(cl, p, q->hash + i, hlist) { | ||
1706 | if (arg->count < arg->skip) { | 1552 | if (arg->count < arg->skip) { |
1707 | arg->count++; | 1553 | arg->count++; |
1708 | continue; | 1554 | continue; |
@@ -1750,12 +1596,13 @@ static struct Qdisc_ops htb_qdisc_ops = { | |||
1750 | 1596 | ||
1751 | static int __init htb_module_init(void) | 1597 | static int __init htb_module_init(void) |
1752 | { | 1598 | { |
1753 | return register_qdisc(&htb_qdisc_ops); | 1599 | return register_qdisc(&htb_qdisc_ops); |
1754 | } | 1600 | } |
1755 | static void __exit htb_module_exit(void) | 1601 | static void __exit htb_module_exit(void) |
1756 | { | 1602 | { |
1757 | unregister_qdisc(&htb_qdisc_ops); | 1603 | unregister_qdisc(&htb_qdisc_ops); |
1758 | } | 1604 | } |
1605 | |||
1759 | module_init(htb_module_init) | 1606 | module_init(htb_module_init) |
1760 | module_exit(htb_module_exit) | 1607 | module_exit(htb_module_exit) |
1761 | MODULE_LICENSE("GPL"); | 1608 | MODULE_LICENSE("GPL"); |
diff --git a/net/sched/sch_netem.c b/net/sched/sch_netem.c index a08ec4c7c55d..45939bafbdf8 100644 --- a/net/sched/sch_netem.c +++ b/net/sched/sch_netem.c | |||
@@ -192,8 +192,8 @@ static int netem_enqueue(struct sk_buff *skb, struct Qdisc *sch) | |||
192 | */ | 192 | */ |
193 | if (q->corrupt && q->corrupt >= get_crandom(&q->corrupt_cor)) { | 193 | if (q->corrupt && q->corrupt >= get_crandom(&q->corrupt_cor)) { |
194 | if (!(skb = skb_unshare(skb, GFP_ATOMIC)) | 194 | if (!(skb = skb_unshare(skb, GFP_ATOMIC)) |
195 | || (skb->ip_summed == CHECKSUM_HW | 195 | || (skb->ip_summed == CHECKSUM_PARTIAL |
196 | && skb_checksum_help(skb, 0))) { | 196 | && skb_checksum_help(skb))) { |
197 | sch->qstats.drops++; | 197 | sch->qstats.drops++; |
198 | return NET_XMIT_DROP; | 198 | return NET_XMIT_DROP; |
199 | } | 199 | } |
diff --git a/net/sctp/input.c b/net/sctp/input.c index 42b66e74bbb5..03f65de75d88 100644 --- a/net/sctp/input.c +++ b/net/sctp/input.c | |||
@@ -228,7 +228,7 @@ int sctp_rcv(struct sk_buff *skb) | |||
228 | goto discard_release; | 228 | goto discard_release; |
229 | nf_reset(skb); | 229 | nf_reset(skb); |
230 | 230 | ||
231 | if (sk_filter(sk, skb, 1)) | 231 | if (sk_filter(sk, skb)) |
232 | goto discard_release; | 232 | goto discard_release; |
233 | 233 | ||
234 | /* Create an SCTP packet structure. */ | 234 | /* Create an SCTP packet structure. */ |
@@ -255,10 +255,13 @@ int sctp_rcv(struct sk_buff *skb) | |||
255 | */ | 255 | */ |
256 | sctp_bh_lock_sock(sk); | 256 | sctp_bh_lock_sock(sk); |
257 | 257 | ||
258 | if (sock_owned_by_user(sk)) | 258 | if (sock_owned_by_user(sk)) { |
259 | SCTP_INC_STATS_BH(SCTP_MIB_IN_PKT_BACKLOG); | ||
259 | sctp_add_backlog(sk, skb); | 260 | sctp_add_backlog(sk, skb); |
260 | else | 261 | } else { |
262 | SCTP_INC_STATS_BH(SCTP_MIB_IN_PKT_SOFTIRQ); | ||
261 | sctp_inq_push(&chunk->rcvr->inqueue, chunk); | 263 | sctp_inq_push(&chunk->rcvr->inqueue, chunk); |
264 | } | ||
262 | 265 | ||
263 | sctp_bh_unlock_sock(sk); | 266 | sctp_bh_unlock_sock(sk); |
264 | 267 | ||
@@ -271,6 +274,7 @@ int sctp_rcv(struct sk_buff *skb) | |||
271 | return 0; | 274 | return 0; |
272 | 275 | ||
273 | discard_it: | 276 | discard_it: |
277 | SCTP_INC_STATS_BH(SCTP_MIB_IN_PKT_DISCARDS); | ||
274 | kfree_skb(skb); | 278 | kfree_skb(skb); |
275 | return 0; | 279 | return 0; |
276 | 280 | ||
diff --git a/net/sctp/inqueue.c b/net/sctp/inqueue.c index cf0c767d43ae..cf6deed7e849 100644 --- a/net/sctp/inqueue.c +++ b/net/sctp/inqueue.c | |||
@@ -87,7 +87,7 @@ void sctp_inq_free(struct sctp_inq *queue) | |||
87 | /* Put a new packet in an SCTP inqueue. | 87 | /* Put a new packet in an SCTP inqueue. |
88 | * We assume that packet->sctp_hdr is set and in host byte order. | 88 | * We assume that packet->sctp_hdr is set and in host byte order. |
89 | */ | 89 | */ |
90 | void sctp_inq_push(struct sctp_inq *q, struct sctp_chunk *packet) | 90 | void sctp_inq_push(struct sctp_inq *q, struct sctp_chunk *chunk) |
91 | { | 91 | { |
92 | /* Directly call the packet handling routine. */ | 92 | /* Directly call the packet handling routine. */ |
93 | 93 | ||
@@ -96,7 +96,7 @@ void sctp_inq_push(struct sctp_inq *q, struct sctp_chunk *packet) | |||
96 | * Eventually, we should clean up inqueue to not rely | 96 | * Eventually, we should clean up inqueue to not rely |
97 | * on the BH related data structures. | 97 | * on the BH related data structures. |
98 | */ | 98 | */ |
99 | list_add_tail(&packet->list, &q->in_chunk_list); | 99 | list_add_tail(&chunk->list, &q->in_chunk_list); |
100 | q->immediate.func(q->immediate.data); | 100 | q->immediate.func(q->immediate.data); |
101 | } | 101 | } |
102 | 102 | ||
diff --git a/net/sctp/ipv6.c b/net/sctp/ipv6.c index 99c0cefc04e0..249e5033c1a8 100644 --- a/net/sctp/ipv6.c +++ b/net/sctp/ipv6.c | |||
@@ -78,7 +78,6 @@ | |||
78 | 78 | ||
79 | #include <asm/uaccess.h> | 79 | #include <asm/uaccess.h> |
80 | 80 | ||
81 | extern int sctp_inetaddr_event(struct notifier_block *, unsigned long, void *); | ||
82 | static struct notifier_block sctp_inet6addr_notifier = { | 81 | static struct notifier_block sctp_inet6addr_notifier = { |
83 | .notifier_call = sctp_inetaddr_event, | 82 | .notifier_call = sctp_inetaddr_event, |
84 | }; | 83 | }; |
@@ -322,9 +321,9 @@ static void sctp_v6_copy_addrlist(struct list_head *addrlist, | |||
322 | struct inet6_ifaddr *ifp; | 321 | struct inet6_ifaddr *ifp; |
323 | struct sctp_sockaddr_entry *addr; | 322 | struct sctp_sockaddr_entry *addr; |
324 | 323 | ||
325 | read_lock(&addrconf_lock); | 324 | rcu_read_lock(); |
326 | if ((in6_dev = __in6_dev_get(dev)) == NULL) { | 325 | if ((in6_dev = __in6_dev_get(dev)) == NULL) { |
327 | read_unlock(&addrconf_lock); | 326 | rcu_read_unlock(); |
328 | return; | 327 | return; |
329 | } | 328 | } |
330 | 329 | ||
@@ -343,7 +342,7 @@ static void sctp_v6_copy_addrlist(struct list_head *addrlist, | |||
343 | } | 342 | } |
344 | 343 | ||
345 | read_unlock(&in6_dev->lock); | 344 | read_unlock(&in6_dev->lock); |
346 | read_unlock(&addrconf_lock); | 345 | rcu_read_unlock(); |
347 | } | 346 | } |
348 | 347 | ||
349 | /* Initialize a sockaddr_storage from in incoming skb. */ | 348 | /* Initialize a sockaddr_storage from in incoming skb. */ |
diff --git a/net/sctp/outqueue.c b/net/sctp/outqueue.c index 30b710c54e64..37074a39ecbb 100644 --- a/net/sctp/outqueue.c +++ b/net/sctp/outqueue.c | |||
@@ -467,6 +467,7 @@ void sctp_retransmit(struct sctp_outq *q, struct sctp_transport *transport, | |||
467 | 467 | ||
468 | switch(reason) { | 468 | switch(reason) { |
469 | case SCTP_RTXR_T3_RTX: | 469 | case SCTP_RTXR_T3_RTX: |
470 | SCTP_INC_STATS(SCTP_MIB_T3_RETRANSMITS); | ||
470 | sctp_transport_lower_cwnd(transport, SCTP_LOWER_CWND_T3_RTX); | 471 | sctp_transport_lower_cwnd(transport, SCTP_LOWER_CWND_T3_RTX); |
471 | /* Update the retran path if the T3-rtx timer has expired for | 472 | /* Update the retran path if the T3-rtx timer has expired for |
472 | * the current retran path. | 473 | * the current retran path. |
@@ -475,12 +476,15 @@ void sctp_retransmit(struct sctp_outq *q, struct sctp_transport *transport, | |||
475 | sctp_assoc_update_retran_path(transport->asoc); | 476 | sctp_assoc_update_retran_path(transport->asoc); |
476 | break; | 477 | break; |
477 | case SCTP_RTXR_FAST_RTX: | 478 | case SCTP_RTXR_FAST_RTX: |
479 | SCTP_INC_STATS(SCTP_MIB_FAST_RETRANSMITS); | ||
478 | sctp_transport_lower_cwnd(transport, SCTP_LOWER_CWND_FAST_RTX); | 480 | sctp_transport_lower_cwnd(transport, SCTP_LOWER_CWND_FAST_RTX); |
479 | fast_retransmit = 1; | 481 | fast_retransmit = 1; |
480 | break; | 482 | break; |
481 | case SCTP_RTXR_PMTUD: | 483 | case SCTP_RTXR_PMTUD: |
482 | default: | 484 | SCTP_INC_STATS(SCTP_MIB_PMTUD_RETRANSMITS); |
483 | break; | 485 | break; |
486 | default: | ||
487 | BUG(); | ||
484 | } | 488 | } |
485 | 489 | ||
486 | sctp_retransmit_mark(q, transport, fast_retransmit); | 490 | sctp_retransmit_mark(q, transport, fast_retransmit); |
diff --git a/net/sctp/proc.c b/net/sctp/proc.c index 5b3b0e0ae7e5..a356d8d310a9 100644 --- a/net/sctp/proc.c +++ b/net/sctp/proc.c | |||
@@ -57,6 +57,21 @@ static struct snmp_mib sctp_snmp_list[] = { | |||
57 | SNMP_MIB_ITEM("SctpReasmUsrMsgs", SCTP_MIB_REASMUSRMSGS), | 57 | SNMP_MIB_ITEM("SctpReasmUsrMsgs", SCTP_MIB_REASMUSRMSGS), |
58 | SNMP_MIB_ITEM("SctpOutSCTPPacks", SCTP_MIB_OUTSCTPPACKS), | 58 | SNMP_MIB_ITEM("SctpOutSCTPPacks", SCTP_MIB_OUTSCTPPACKS), |
59 | SNMP_MIB_ITEM("SctpInSCTPPacks", SCTP_MIB_INSCTPPACKS), | 59 | SNMP_MIB_ITEM("SctpInSCTPPacks", SCTP_MIB_INSCTPPACKS), |
60 | SNMP_MIB_ITEM("SctpT1InitExpireds", SCTP_MIB_T1_INIT_EXPIREDS), | ||
61 | SNMP_MIB_ITEM("SctpT1CookieExpireds", SCTP_MIB_T1_COOKIE_EXPIREDS), | ||
62 | SNMP_MIB_ITEM("SctpT2ShutdownExpireds", SCTP_MIB_T2_SHUTDOWN_EXPIREDS), | ||
63 | SNMP_MIB_ITEM("SctpT3RtxExpireds", SCTP_MIB_T3_RTX_EXPIREDS), | ||
64 | SNMP_MIB_ITEM("SctpT4RtoExpireds", SCTP_MIB_T4_RTO_EXPIREDS), | ||
65 | SNMP_MIB_ITEM("SctpT5ShutdownGuardExpireds", SCTP_MIB_T5_SHUTDOWN_GUARD_EXPIREDS), | ||
66 | SNMP_MIB_ITEM("SctpDelaySackExpireds", SCTP_MIB_DELAY_SACK_EXPIREDS), | ||
67 | SNMP_MIB_ITEM("SctpAutocloseExpireds", SCTP_MIB_AUTOCLOSE_EXPIREDS), | ||
68 | SNMP_MIB_ITEM("SctpT3Retransmits", SCTP_MIB_T3_RETRANSMITS), | ||
69 | SNMP_MIB_ITEM("SctpPmtudRetransmits", SCTP_MIB_PMTUD_RETRANSMITS), | ||
70 | SNMP_MIB_ITEM("SctpFastRetransmits", SCTP_MIB_FAST_RETRANSMITS), | ||
71 | SNMP_MIB_ITEM("SctpInPktSoftirq", SCTP_MIB_IN_PKT_SOFTIRQ), | ||
72 | SNMP_MIB_ITEM("SctpInPktBacklog", SCTP_MIB_IN_PKT_BACKLOG), | ||
73 | SNMP_MIB_ITEM("SctpInPktDiscards", SCTP_MIB_IN_PKT_DISCARDS), | ||
74 | SNMP_MIB_ITEM("SctpInDataChunkDiscards", SCTP_MIB_IN_DATA_CHUNK_DISCARDS), | ||
60 | SNMP_MIB_SENTINEL | 75 | SNMP_MIB_SENTINEL |
61 | }; | 76 | }; |
62 | 77 | ||
@@ -328,8 +343,8 @@ static int sctp_assocs_seq_show(struct seq_file *seq, void *v) | |||
328 | "%8p %8p %-3d %-3d %-2d %-4d %4d %8d %8d %7d %5lu %-5d %5d ", | 343 | "%8p %8p %-3d %-3d %-2d %-4d %4d %8d %8d %7d %5lu %-5d %5d ", |
329 | assoc, sk, sctp_sk(sk)->type, sk->sk_state, | 344 | assoc, sk, sctp_sk(sk)->type, sk->sk_state, |
330 | assoc->state, hash, assoc->assoc_id, | 345 | assoc->state, hash, assoc->assoc_id, |
331 | (sk->sk_rcvbuf - assoc->rwnd), | ||
332 | assoc->sndbuf_used, | 346 | assoc->sndbuf_used, |
347 | (sk->sk_rcvbuf - assoc->rwnd), | ||
333 | sock_i_uid(sk), sock_i_ino(sk), | 348 | sock_i_uid(sk), sock_i_ino(sk), |
334 | epb->bind_addr.port, | 349 | epb->bind_addr.port, |
335 | assoc->peer.port); | 350 | assoc->peer.port); |
diff --git a/net/sctp/protocol.c b/net/sctp/protocol.c index 1ab03a27a76e..fac7674438a4 100644 --- a/net/sctp/protocol.c +++ b/net/sctp/protocol.c | |||
@@ -61,7 +61,7 @@ | |||
61 | #include <net/inet_ecn.h> | 61 | #include <net/inet_ecn.h> |
62 | 62 | ||
63 | /* Global data structures. */ | 63 | /* Global data structures. */ |
64 | struct sctp_globals sctp_globals; | 64 | struct sctp_globals sctp_globals __read_mostly; |
65 | struct proc_dir_entry *proc_net_sctp; | 65 | struct proc_dir_entry *proc_net_sctp; |
66 | DEFINE_SNMP_STAT(struct sctp_mib, sctp_statistics) __read_mostly; | 66 | DEFINE_SNMP_STAT(struct sctp_mib, sctp_statistics) __read_mostly; |
67 | 67 | ||
@@ -82,13 +82,6 @@ static struct sctp_af *sctp_af_v6_specific; | |||
82 | kmem_cache_t *sctp_chunk_cachep __read_mostly; | 82 | kmem_cache_t *sctp_chunk_cachep __read_mostly; |
83 | kmem_cache_t *sctp_bucket_cachep __read_mostly; | 83 | kmem_cache_t *sctp_bucket_cachep __read_mostly; |
84 | 84 | ||
85 | extern int sctp_snmp_proc_init(void); | ||
86 | extern int sctp_snmp_proc_exit(void); | ||
87 | extern int sctp_eps_proc_init(void); | ||
88 | extern int sctp_eps_proc_exit(void); | ||
89 | extern int sctp_assocs_proc_init(void); | ||
90 | extern int sctp_assocs_proc_exit(void); | ||
91 | |||
92 | /* Return the address of the control sock. */ | 85 | /* Return the address of the control sock. */ |
93 | struct sock *sctp_get_ctl_sock(void) | 86 | struct sock *sctp_get_ctl_sock(void) |
94 | { | 87 | { |
@@ -1049,7 +1042,7 @@ SCTP_STATIC __init int sctp_init(void) | |||
1049 | sctp_rto_beta = SCTP_RTO_BETA; | 1042 | sctp_rto_beta = SCTP_RTO_BETA; |
1050 | 1043 | ||
1051 | /* Valid.Cookie.Life - 60 seconds */ | 1044 | /* Valid.Cookie.Life - 60 seconds */ |
1052 | sctp_valid_cookie_life = 60 * HZ; | 1045 | sctp_valid_cookie_life = SCTP_DEFAULT_COOKIE_LIFE; |
1053 | 1046 | ||
1054 | /* Whether Cookie Preservative is enabled(1) or not(0) */ | 1047 | /* Whether Cookie Preservative is enabled(1) or not(0) */ |
1055 | sctp_cookie_preserve_enable = 1; | 1048 | sctp_cookie_preserve_enable = 1; |
diff --git a/net/sctp/sm_statefuns.c b/net/sctp/sm_statefuns.c index 5b5ae7958322..1c42fe983a5b 100644 --- a/net/sctp/sm_statefuns.c +++ b/net/sctp/sm_statefuns.c | |||
@@ -187,10 +187,9 @@ sctp_disposition_t sctp_sf_do_4_C(const struct sctp_endpoint *ep, | |||
187 | */ | 187 | */ |
188 | ev = sctp_ulpevent_make_assoc_change(asoc, 0, SCTP_SHUTDOWN_COMP, | 188 | ev = sctp_ulpevent_make_assoc_change(asoc, 0, SCTP_SHUTDOWN_COMP, |
189 | 0, 0, 0, GFP_ATOMIC); | 189 | 0, 0, 0, GFP_ATOMIC); |
190 | if (!ev) | 190 | if (ev) |
191 | goto nomem; | 191 | sctp_add_cmd_sf(commands, SCTP_CMD_EVENT_ULP, |
192 | 192 | SCTP_ULPEVENT(ev)); | |
193 | sctp_add_cmd_sf(commands, SCTP_CMD_EVENT_ULP, SCTP_ULPEVENT(ev)); | ||
194 | 193 | ||
195 | /* Upon reception of the SHUTDOWN COMPLETE chunk the endpoint | 194 | /* Upon reception of the SHUTDOWN COMPLETE chunk the endpoint |
196 | * will verify that it is in SHUTDOWN-ACK-SENT state, if it is | 195 | * will verify that it is in SHUTDOWN-ACK-SENT state, if it is |
@@ -215,9 +214,6 @@ sctp_disposition_t sctp_sf_do_4_C(const struct sctp_endpoint *ep, | |||
215 | sctp_add_cmd_sf(commands, SCTP_CMD_DELETE_TCB, SCTP_NULL()); | 214 | sctp_add_cmd_sf(commands, SCTP_CMD_DELETE_TCB, SCTP_NULL()); |
216 | 215 | ||
217 | return SCTP_DISPOSITION_DELETE_TCB; | 216 | return SCTP_DISPOSITION_DELETE_TCB; |
218 | |||
219 | nomem: | ||
220 | return SCTP_DISPOSITION_NOMEM; | ||
221 | } | 217 | } |
222 | 218 | ||
223 | /* | 219 | /* |
@@ -347,8 +343,6 @@ sctp_disposition_t sctp_sf_do_5_1B_init(const struct sctp_endpoint *ep, | |||
347 | GFP_ATOMIC)) | 343 | GFP_ATOMIC)) |
348 | goto nomem_init; | 344 | goto nomem_init; |
349 | 345 | ||
350 | sctp_add_cmd_sf(commands, SCTP_CMD_NEW_ASOC, SCTP_ASOC(new_asoc)); | ||
351 | |||
352 | /* B) "Z" shall respond immediately with an INIT ACK chunk. */ | 346 | /* B) "Z" shall respond immediately with an INIT ACK chunk. */ |
353 | 347 | ||
354 | /* If there are errors need to be reported for unknown parameters, | 348 | /* If there are errors need to be reported for unknown parameters, |
@@ -360,11 +354,11 @@ sctp_disposition_t sctp_sf_do_5_1B_init(const struct sctp_endpoint *ep, | |||
360 | sizeof(sctp_chunkhdr_t); | 354 | sizeof(sctp_chunkhdr_t); |
361 | 355 | ||
362 | if (sctp_assoc_set_bind_addr_from_ep(new_asoc, GFP_ATOMIC) < 0) | 356 | if (sctp_assoc_set_bind_addr_from_ep(new_asoc, GFP_ATOMIC) < 0) |
363 | goto nomem_ack; | 357 | goto nomem_init; |
364 | 358 | ||
365 | repl = sctp_make_init_ack(new_asoc, chunk, GFP_ATOMIC, len); | 359 | repl = sctp_make_init_ack(new_asoc, chunk, GFP_ATOMIC, len); |
366 | if (!repl) | 360 | if (!repl) |
367 | goto nomem_ack; | 361 | goto nomem_init; |
368 | 362 | ||
369 | /* If there are errors need to be reported for unknown parameters, | 363 | /* If there are errors need to be reported for unknown parameters, |
370 | * include them in the outgoing INIT ACK as "Unrecognized parameter" | 364 | * include them in the outgoing INIT ACK as "Unrecognized parameter" |
@@ -388,6 +382,8 @@ sctp_disposition_t sctp_sf_do_5_1B_init(const struct sctp_endpoint *ep, | |||
388 | sctp_chunk_free(err_chunk); | 382 | sctp_chunk_free(err_chunk); |
389 | } | 383 | } |
390 | 384 | ||
385 | sctp_add_cmd_sf(commands, SCTP_CMD_NEW_ASOC, SCTP_ASOC(new_asoc)); | ||
386 | |||
391 | sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(repl)); | 387 | sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(repl)); |
392 | 388 | ||
393 | /* | 389 | /* |
@@ -400,12 +396,11 @@ sctp_disposition_t sctp_sf_do_5_1B_init(const struct sctp_endpoint *ep, | |||
400 | 396 | ||
401 | return SCTP_DISPOSITION_DELETE_TCB; | 397 | return SCTP_DISPOSITION_DELETE_TCB; |
402 | 398 | ||
403 | nomem_ack: | ||
404 | if (err_chunk) | ||
405 | sctp_chunk_free(err_chunk); | ||
406 | nomem_init: | 399 | nomem_init: |
407 | sctp_association_free(new_asoc); | 400 | sctp_association_free(new_asoc); |
408 | nomem: | 401 | nomem: |
402 | if (err_chunk) | ||
403 | sctp_chunk_free(err_chunk); | ||
409 | return SCTP_DISPOSITION_NOMEM; | 404 | return SCTP_DISPOSITION_NOMEM; |
410 | } | 405 | } |
411 | 406 | ||
@@ -600,7 +595,7 @@ sctp_disposition_t sctp_sf_do_5_1D_ce(const struct sctp_endpoint *ep, | |||
600 | struct sctp_association *new_asoc; | 595 | struct sctp_association *new_asoc; |
601 | sctp_init_chunk_t *peer_init; | 596 | sctp_init_chunk_t *peer_init; |
602 | struct sctp_chunk *repl; | 597 | struct sctp_chunk *repl; |
603 | struct sctp_ulpevent *ev; | 598 | struct sctp_ulpevent *ev, *ai_ev = NULL; |
604 | int error = 0; | 599 | int error = 0; |
605 | struct sctp_chunk *err_chk_p; | 600 | struct sctp_chunk *err_chk_p; |
606 | 601 | ||
@@ -659,20 +654,10 @@ sctp_disposition_t sctp_sf_do_5_1D_ce(const struct sctp_endpoint *ep, | |||
659 | }; | 654 | }; |
660 | } | 655 | } |
661 | 656 | ||
662 | sctp_add_cmd_sf(commands, SCTP_CMD_NEW_ASOC, SCTP_ASOC(new_asoc)); | ||
663 | sctp_add_cmd_sf(commands, SCTP_CMD_NEW_STATE, | ||
664 | SCTP_STATE(SCTP_STATE_ESTABLISHED)); | ||
665 | SCTP_INC_STATS(SCTP_MIB_CURRESTAB); | ||
666 | SCTP_INC_STATS(SCTP_MIB_PASSIVEESTABS); | ||
667 | sctp_add_cmd_sf(commands, SCTP_CMD_HB_TIMERS_START, SCTP_NULL()); | ||
668 | 657 | ||
669 | if (new_asoc->autoclose) | 658 | /* Delay state machine commands until later. |
670 | sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_START, | 659 | * |
671 | SCTP_TO(SCTP_EVENT_TIMEOUT_AUTOCLOSE)); | 660 | * Re-build the bind address for the association is done in |
672 | |||
673 | sctp_add_cmd_sf(commands, SCTP_CMD_TRANSMIT, SCTP_NULL()); | ||
674 | |||
675 | /* Re-build the bind address for the association is done in | ||
676 | * the sctp_unpack_cookie() already. | 661 | * the sctp_unpack_cookie() already. |
677 | */ | 662 | */ |
678 | /* This is a brand-new association, so these are not yet side | 663 | /* This is a brand-new association, so these are not yet side |
@@ -687,9 +672,7 @@ sctp_disposition_t sctp_sf_do_5_1D_ce(const struct sctp_endpoint *ep, | |||
687 | 672 | ||
688 | repl = sctp_make_cookie_ack(new_asoc, chunk); | 673 | repl = sctp_make_cookie_ack(new_asoc, chunk); |
689 | if (!repl) | 674 | if (!repl) |
690 | goto nomem_repl; | 675 | goto nomem_init; |
691 | |||
692 | sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(repl)); | ||
693 | 676 | ||
694 | /* RFC 2960 5.1 Normal Establishment of an Association | 677 | /* RFC 2960 5.1 Normal Establishment of an Association |
695 | * | 678 | * |
@@ -704,28 +687,53 @@ sctp_disposition_t sctp_sf_do_5_1D_ce(const struct sctp_endpoint *ep, | |||
704 | if (!ev) | 687 | if (!ev) |
705 | goto nomem_ev; | 688 | goto nomem_ev; |
706 | 689 | ||
707 | sctp_add_cmd_sf(commands, SCTP_CMD_EVENT_ULP, SCTP_ULPEVENT(ev)); | ||
708 | |||
709 | /* Sockets API Draft Section 5.3.1.6 | 690 | /* Sockets API Draft Section 5.3.1.6 |
710 | * When a peer sends a Adaption Layer Indication parameter , SCTP | 691 | * When a peer sends a Adaption Layer Indication parameter , SCTP |
711 | * delivers this notification to inform the application that of the | 692 | * delivers this notification to inform the application that of the |
712 | * peers requested adaption layer. | 693 | * peers requested adaption layer. |
713 | */ | 694 | */ |
714 | if (new_asoc->peer.adaption_ind) { | 695 | if (new_asoc->peer.adaption_ind) { |
715 | ev = sctp_ulpevent_make_adaption_indication(new_asoc, | 696 | ai_ev = sctp_ulpevent_make_adaption_indication(new_asoc, |
716 | GFP_ATOMIC); | 697 | GFP_ATOMIC); |
717 | if (!ev) | 698 | if (!ai_ev) |
718 | goto nomem_ev; | 699 | goto nomem_aiev; |
700 | } | ||
701 | |||
702 | /* Add all the state machine commands now since we've created | ||
703 | * everything. This way we don't introduce memory corruptions | ||
704 | * during side-effect processing and correclty count established | ||
705 | * associations. | ||
706 | */ | ||
707 | sctp_add_cmd_sf(commands, SCTP_CMD_NEW_ASOC, SCTP_ASOC(new_asoc)); | ||
708 | sctp_add_cmd_sf(commands, SCTP_CMD_NEW_STATE, | ||
709 | SCTP_STATE(SCTP_STATE_ESTABLISHED)); | ||
710 | SCTP_INC_STATS(SCTP_MIB_CURRESTAB); | ||
711 | SCTP_INC_STATS(SCTP_MIB_PASSIVEESTABS); | ||
712 | sctp_add_cmd_sf(commands, SCTP_CMD_HB_TIMERS_START, SCTP_NULL()); | ||
713 | |||
714 | if (new_asoc->autoclose) | ||
715 | sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_START, | ||
716 | SCTP_TO(SCTP_EVENT_TIMEOUT_AUTOCLOSE)); | ||
719 | 717 | ||
718 | sctp_add_cmd_sf(commands, SCTP_CMD_TRANSMIT, SCTP_NULL()); | ||
719 | |||
720 | /* This will send the COOKIE ACK */ | ||
721 | sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(repl)); | ||
722 | |||
723 | /* Queue the ASSOC_CHANGE event */ | ||
724 | sctp_add_cmd_sf(commands, SCTP_CMD_EVENT_ULP, SCTP_ULPEVENT(ev)); | ||
725 | |||
726 | /* Send up the Adaptation Layer Indication event */ | ||
727 | if (ai_ev) | ||
720 | sctp_add_cmd_sf(commands, SCTP_CMD_EVENT_ULP, | 728 | sctp_add_cmd_sf(commands, SCTP_CMD_EVENT_ULP, |
721 | SCTP_ULPEVENT(ev)); | 729 | SCTP_ULPEVENT(ai_ev)); |
722 | } | ||
723 | 730 | ||
724 | return SCTP_DISPOSITION_CONSUME; | 731 | return SCTP_DISPOSITION_CONSUME; |
725 | 732 | ||
733 | nomem_aiev: | ||
734 | sctp_ulpevent_free(ev); | ||
726 | nomem_ev: | 735 | nomem_ev: |
727 | sctp_chunk_free(repl); | 736 | sctp_chunk_free(repl); |
728 | nomem_repl: | ||
729 | nomem_init: | 737 | nomem_init: |
730 | sctp_association_free(new_asoc); | 738 | sctp_association_free(new_asoc); |
731 | nomem: | 739 | nomem: |
@@ -1360,10 +1368,8 @@ static sctp_disposition_t sctp_sf_do_unexpected_init( | |||
1360 | if (!sctp_process_init(new_asoc, chunk->chunk_hdr->type, | 1368 | if (!sctp_process_init(new_asoc, chunk->chunk_hdr->type, |
1361 | sctp_source(chunk), | 1369 | sctp_source(chunk), |
1362 | (sctp_init_chunk_t *)chunk->chunk_hdr, | 1370 | (sctp_init_chunk_t *)chunk->chunk_hdr, |
1363 | GFP_ATOMIC)) { | 1371 | GFP_ATOMIC)) |
1364 | retval = SCTP_DISPOSITION_NOMEM; | 1372 | goto nomem; |
1365 | goto nomem_init; | ||
1366 | } | ||
1367 | 1373 | ||
1368 | /* Make sure no new addresses are being added during the | 1374 | /* Make sure no new addresses are being added during the |
1369 | * restart. Do not do this check for COOKIE-WAIT state, | 1375 | * restart. Do not do this check for COOKIE-WAIT state, |
@@ -1374,7 +1380,7 @@ static sctp_disposition_t sctp_sf_do_unexpected_init( | |||
1374 | if (!sctp_sf_check_restart_addrs(new_asoc, asoc, chunk, | 1380 | if (!sctp_sf_check_restart_addrs(new_asoc, asoc, chunk, |
1375 | commands)) { | 1381 | commands)) { |
1376 | retval = SCTP_DISPOSITION_CONSUME; | 1382 | retval = SCTP_DISPOSITION_CONSUME; |
1377 | goto cleanup_asoc; | 1383 | goto nomem_retval; |
1378 | } | 1384 | } |
1379 | } | 1385 | } |
1380 | 1386 | ||
@@ -1430,17 +1436,17 @@ static sctp_disposition_t sctp_sf_do_unexpected_init( | |||
1430 | sctp_add_cmd_sf(commands, SCTP_CMD_DELETE_TCB, SCTP_NULL()); | 1436 | sctp_add_cmd_sf(commands, SCTP_CMD_DELETE_TCB, SCTP_NULL()); |
1431 | retval = SCTP_DISPOSITION_CONSUME; | 1437 | retval = SCTP_DISPOSITION_CONSUME; |
1432 | 1438 | ||
1439 | return retval; | ||
1440 | |||
1441 | nomem: | ||
1442 | retval = SCTP_DISPOSITION_NOMEM; | ||
1443 | nomem_retval: | ||
1444 | if (new_asoc) | ||
1445 | sctp_association_free(new_asoc); | ||
1433 | cleanup: | 1446 | cleanup: |
1434 | if (err_chunk) | 1447 | if (err_chunk) |
1435 | sctp_chunk_free(err_chunk); | 1448 | sctp_chunk_free(err_chunk); |
1436 | return retval; | 1449 | return retval; |
1437 | nomem: | ||
1438 | retval = SCTP_DISPOSITION_NOMEM; | ||
1439 | goto cleanup; | ||
1440 | nomem_init: | ||
1441 | cleanup_asoc: | ||
1442 | sctp_association_free(new_asoc); | ||
1443 | goto cleanup; | ||
1444 | } | 1450 | } |
1445 | 1451 | ||
1446 | /* | 1452 | /* |
@@ -1611,15 +1617,10 @@ static sctp_disposition_t sctp_sf_do_dupcook_a(const struct sctp_endpoint *ep, | |||
1611 | */ | 1617 | */ |
1612 | sctp_add_cmd_sf(commands, SCTP_CMD_PURGE_OUTQUEUE, SCTP_NULL()); | 1618 | sctp_add_cmd_sf(commands, SCTP_CMD_PURGE_OUTQUEUE, SCTP_NULL()); |
1613 | 1619 | ||
1614 | /* Update the content of current association. */ | ||
1615 | sctp_add_cmd_sf(commands, SCTP_CMD_UPDATE_ASSOC, SCTP_ASOC(new_asoc)); | ||
1616 | |||
1617 | repl = sctp_make_cookie_ack(new_asoc, chunk); | 1620 | repl = sctp_make_cookie_ack(new_asoc, chunk); |
1618 | if (!repl) | 1621 | if (!repl) |
1619 | goto nomem; | 1622 | goto nomem; |
1620 | 1623 | ||
1621 | sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(repl)); | ||
1622 | |||
1623 | /* Report association restart to upper layer. */ | 1624 | /* Report association restart to upper layer. */ |
1624 | ev = sctp_ulpevent_make_assoc_change(asoc, 0, SCTP_RESTART, 0, | 1625 | ev = sctp_ulpevent_make_assoc_change(asoc, 0, SCTP_RESTART, 0, |
1625 | new_asoc->c.sinit_num_ostreams, | 1626 | new_asoc->c.sinit_num_ostreams, |
@@ -1628,6 +1629,9 @@ static sctp_disposition_t sctp_sf_do_dupcook_a(const struct sctp_endpoint *ep, | |||
1628 | if (!ev) | 1629 | if (!ev) |
1629 | goto nomem_ev; | 1630 | goto nomem_ev; |
1630 | 1631 | ||
1632 | /* Update the content of current association. */ | ||
1633 | sctp_add_cmd_sf(commands, SCTP_CMD_UPDATE_ASSOC, SCTP_ASOC(new_asoc)); | ||
1634 | sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(repl)); | ||
1631 | sctp_add_cmd_sf(commands, SCTP_CMD_EVENT_ULP, SCTP_ULPEVENT(ev)); | 1635 | sctp_add_cmd_sf(commands, SCTP_CMD_EVENT_ULP, SCTP_ULPEVENT(ev)); |
1632 | return SCTP_DISPOSITION_CONSUME; | 1636 | return SCTP_DISPOSITION_CONSUME; |
1633 | 1637 | ||
@@ -1751,7 +1755,7 @@ static sctp_disposition_t sctp_sf_do_dupcook_d(const struct sctp_endpoint *ep, | |||
1751 | sctp_cmd_seq_t *commands, | 1755 | sctp_cmd_seq_t *commands, |
1752 | struct sctp_association *new_asoc) | 1756 | struct sctp_association *new_asoc) |
1753 | { | 1757 | { |
1754 | struct sctp_ulpevent *ev = NULL; | 1758 | struct sctp_ulpevent *ev = NULL, *ai_ev = NULL; |
1755 | struct sctp_chunk *repl; | 1759 | struct sctp_chunk *repl; |
1756 | 1760 | ||
1757 | /* Clarification from Implementor's Guide: | 1761 | /* Clarification from Implementor's Guide: |
@@ -1778,29 +1782,25 @@ static sctp_disposition_t sctp_sf_do_dupcook_d(const struct sctp_endpoint *ep, | |||
1778 | * SCTP user upon reception of a valid COOKIE | 1782 | * SCTP user upon reception of a valid COOKIE |
1779 | * ECHO chunk. | 1783 | * ECHO chunk. |
1780 | */ | 1784 | */ |
1781 | ev = sctp_ulpevent_make_assoc_change(new_asoc, 0, | 1785 | ev = sctp_ulpevent_make_assoc_change(asoc, 0, |
1782 | SCTP_COMM_UP, 0, | 1786 | SCTP_COMM_UP, 0, |
1783 | new_asoc->c.sinit_num_ostreams, | 1787 | asoc->c.sinit_num_ostreams, |
1784 | new_asoc->c.sinit_max_instreams, | 1788 | asoc->c.sinit_max_instreams, |
1785 | GFP_ATOMIC); | 1789 | GFP_ATOMIC); |
1786 | if (!ev) | 1790 | if (!ev) |
1787 | goto nomem; | 1791 | goto nomem; |
1788 | sctp_add_cmd_sf(commands, SCTP_CMD_EVENT_ULP, | ||
1789 | SCTP_ULPEVENT(ev)); | ||
1790 | 1792 | ||
1791 | /* Sockets API Draft Section 5.3.1.6 | 1793 | /* Sockets API Draft Section 5.3.1.6 |
1792 | * When a peer sends a Adaption Layer Indication parameter, | 1794 | * When a peer sends a Adaption Layer Indication parameter, |
1793 | * SCTP delivers this notification to inform the application | 1795 | * SCTP delivers this notification to inform the application |
1794 | * that of the peers requested adaption layer. | 1796 | * that of the peers requested adaption layer. |
1795 | */ | 1797 | */ |
1796 | if (new_asoc->peer.adaption_ind) { | 1798 | if (asoc->peer.adaption_ind) { |
1797 | ev = sctp_ulpevent_make_adaption_indication(new_asoc, | 1799 | ai_ev = sctp_ulpevent_make_adaption_indication(asoc, |
1798 | GFP_ATOMIC); | 1800 | GFP_ATOMIC); |
1799 | if (!ev) | 1801 | if (!ai_ev) |
1800 | goto nomem; | 1802 | goto nomem; |
1801 | 1803 | ||
1802 | sctp_add_cmd_sf(commands, SCTP_CMD_EVENT_ULP, | ||
1803 | SCTP_ULPEVENT(ev)); | ||
1804 | } | 1804 | } |
1805 | } | 1805 | } |
1806 | sctp_add_cmd_sf(commands, SCTP_CMD_TRANSMIT, SCTP_NULL()); | 1806 | sctp_add_cmd_sf(commands, SCTP_CMD_TRANSMIT, SCTP_NULL()); |
@@ -1809,12 +1809,21 @@ static sctp_disposition_t sctp_sf_do_dupcook_d(const struct sctp_endpoint *ep, | |||
1809 | if (!repl) | 1809 | if (!repl) |
1810 | goto nomem; | 1810 | goto nomem; |
1811 | 1811 | ||
1812 | if (ev) | ||
1813 | sctp_add_cmd_sf(commands, SCTP_CMD_EVENT_ULP, | ||
1814 | SCTP_ULPEVENT(ev)); | ||
1815 | if (ai_ev) | ||
1816 | sctp_add_cmd_sf(commands, SCTP_CMD_EVENT_ULP, | ||
1817 | SCTP_ULPEVENT(ai_ev)); | ||
1818 | |||
1812 | sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(repl)); | 1819 | sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(repl)); |
1813 | sctp_add_cmd_sf(commands, SCTP_CMD_TRANSMIT, SCTP_NULL()); | 1820 | sctp_add_cmd_sf(commands, SCTP_CMD_TRANSMIT, SCTP_NULL()); |
1814 | 1821 | ||
1815 | return SCTP_DISPOSITION_CONSUME; | 1822 | return SCTP_DISPOSITION_CONSUME; |
1816 | 1823 | ||
1817 | nomem: | 1824 | nomem: |
1825 | if (ai_ev) | ||
1826 | sctp_ulpevent_free(ai_ev); | ||
1818 | if (ev) | 1827 | if (ev) |
1819 | sctp_ulpevent_free(ev); | 1828 | sctp_ulpevent_free(ev); |
1820 | return SCTP_DISPOSITION_NOMEM; | 1829 | return SCTP_DISPOSITION_NOMEM; |
@@ -2663,9 +2672,11 @@ sctp_disposition_t sctp_sf_eat_data_6_2(const struct sctp_endpoint *ep, | |||
2663 | break; | 2672 | break; |
2664 | case SCTP_IERROR_HIGH_TSN: | 2673 | case SCTP_IERROR_HIGH_TSN: |
2665 | case SCTP_IERROR_BAD_STREAM: | 2674 | case SCTP_IERROR_BAD_STREAM: |
2675 | SCTP_INC_STATS(SCTP_MIB_IN_DATA_CHUNK_DISCARDS); | ||
2666 | goto discard_noforce; | 2676 | goto discard_noforce; |
2667 | case SCTP_IERROR_DUP_TSN: | 2677 | case SCTP_IERROR_DUP_TSN: |
2668 | case SCTP_IERROR_IGNORE_TSN: | 2678 | case SCTP_IERROR_IGNORE_TSN: |
2679 | SCTP_INC_STATS(SCTP_MIB_IN_DATA_CHUNK_DISCARDS); | ||
2669 | goto discard_force; | 2680 | goto discard_force; |
2670 | case SCTP_IERROR_NO_DATA: | 2681 | case SCTP_IERROR_NO_DATA: |
2671 | goto consume; | 2682 | goto consume; |
@@ -3017,7 +3028,6 @@ sctp_disposition_t sctp_sf_do_9_2_final(const struct sctp_endpoint *ep, | |||
3017 | if (!sctp_chunk_length_valid(chunk, sizeof(sctp_chunkhdr_t))) | 3028 | if (!sctp_chunk_length_valid(chunk, sizeof(sctp_chunkhdr_t))) |
3018 | return sctp_sf_violation_chunklen(ep, asoc, type, arg, | 3029 | return sctp_sf_violation_chunklen(ep, asoc, type, arg, |
3019 | commands); | 3030 | commands); |
3020 | |||
3021 | /* 10.2 H) SHUTDOWN COMPLETE notification | 3031 | /* 10.2 H) SHUTDOWN COMPLETE notification |
3022 | * | 3032 | * |
3023 | * When SCTP completes the shutdown procedures (section 9.2) this | 3033 | * When SCTP completes the shutdown procedures (section 9.2) this |
@@ -3028,6 +3038,14 @@ sctp_disposition_t sctp_sf_do_9_2_final(const struct sctp_endpoint *ep, | |||
3028 | if (!ev) | 3038 | if (!ev) |
3029 | goto nomem; | 3039 | goto nomem; |
3030 | 3040 | ||
3041 | /* ...send a SHUTDOWN COMPLETE chunk to its peer, */ | ||
3042 | reply = sctp_make_shutdown_complete(asoc, chunk); | ||
3043 | if (!reply) | ||
3044 | goto nomem_chunk; | ||
3045 | |||
3046 | /* Do all the commands now (after allocation), so that we | ||
3047 | * have consistent state if memory allocation failes | ||
3048 | */ | ||
3031 | sctp_add_cmd_sf(commands, SCTP_CMD_EVENT_ULP, SCTP_ULPEVENT(ev)); | 3049 | sctp_add_cmd_sf(commands, SCTP_CMD_EVENT_ULP, SCTP_ULPEVENT(ev)); |
3032 | 3050 | ||
3033 | /* Upon the receipt of the SHUTDOWN ACK, the SHUTDOWN sender shall | 3051 | /* Upon the receipt of the SHUTDOWN ACK, the SHUTDOWN sender shall |
@@ -3039,11 +3057,6 @@ sctp_disposition_t sctp_sf_do_9_2_final(const struct sctp_endpoint *ep, | |||
3039 | sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_STOP, | 3057 | sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_STOP, |
3040 | SCTP_TO(SCTP_EVENT_TIMEOUT_T5_SHUTDOWN_GUARD)); | 3058 | SCTP_TO(SCTP_EVENT_TIMEOUT_T5_SHUTDOWN_GUARD)); |
3041 | 3059 | ||
3042 | /* ...send a SHUTDOWN COMPLETE chunk to its peer, */ | ||
3043 | reply = sctp_make_shutdown_complete(asoc, chunk); | ||
3044 | if (!reply) | ||
3045 | goto nomem; | ||
3046 | |||
3047 | sctp_add_cmd_sf(commands, SCTP_CMD_NEW_STATE, | 3060 | sctp_add_cmd_sf(commands, SCTP_CMD_NEW_STATE, |
3048 | SCTP_STATE(SCTP_STATE_CLOSED)); | 3061 | SCTP_STATE(SCTP_STATE_CLOSED)); |
3049 | SCTP_INC_STATS(SCTP_MIB_SHUTDOWNS); | 3062 | SCTP_INC_STATS(SCTP_MIB_SHUTDOWNS); |
@@ -3054,6 +3067,8 @@ sctp_disposition_t sctp_sf_do_9_2_final(const struct sctp_endpoint *ep, | |||
3054 | sctp_add_cmd_sf(commands, SCTP_CMD_DELETE_TCB, SCTP_NULL()); | 3067 | sctp_add_cmd_sf(commands, SCTP_CMD_DELETE_TCB, SCTP_NULL()); |
3055 | return SCTP_DISPOSITION_DELETE_TCB; | 3068 | return SCTP_DISPOSITION_DELETE_TCB; |
3056 | 3069 | ||
3070 | nomem_chunk: | ||
3071 | sctp_ulpevent_free(ev); | ||
3057 | nomem: | 3072 | nomem: |
3058 | return SCTP_DISPOSITION_NOMEM; | 3073 | return SCTP_DISPOSITION_NOMEM; |
3059 | } | 3074 | } |
@@ -3652,6 +3667,7 @@ sctp_disposition_t sctp_sf_pdiscard(const struct sctp_endpoint *ep, | |||
3652 | void *arg, | 3667 | void *arg, |
3653 | sctp_cmd_seq_t *commands) | 3668 | sctp_cmd_seq_t *commands) |
3654 | { | 3669 | { |
3670 | SCTP_INC_STATS(SCTP_MIB_IN_PKT_DISCARDS); | ||
3655 | sctp_add_cmd_sf(commands, SCTP_CMD_DISCARD_PACKET, SCTP_NULL()); | 3671 | sctp_add_cmd_sf(commands, SCTP_CMD_DISCARD_PACKET, SCTP_NULL()); |
3656 | 3672 | ||
3657 | return SCTP_DISPOSITION_CONSUME; | 3673 | return SCTP_DISPOSITION_CONSUME; |
@@ -4548,6 +4564,8 @@ sctp_disposition_t sctp_sf_do_6_3_3_rtx(const struct sctp_endpoint *ep, | |||
4548 | { | 4564 | { |
4549 | struct sctp_transport *transport = arg; | 4565 | struct sctp_transport *transport = arg; |
4550 | 4566 | ||
4567 | SCTP_INC_STATS(SCTP_MIB_T3_RTX_EXPIREDS); | ||
4568 | |||
4551 | if (asoc->overall_error_count >= asoc->max_retrans) { | 4569 | if (asoc->overall_error_count >= asoc->max_retrans) { |
4552 | sctp_add_cmd_sf(commands, SCTP_CMD_SET_SK_ERR, | 4570 | sctp_add_cmd_sf(commands, SCTP_CMD_SET_SK_ERR, |
4553 | SCTP_ERROR(ETIMEDOUT)); | 4571 | SCTP_ERROR(ETIMEDOUT)); |
@@ -4616,6 +4634,7 @@ sctp_disposition_t sctp_sf_do_6_2_sack(const struct sctp_endpoint *ep, | |||
4616 | void *arg, | 4634 | void *arg, |
4617 | sctp_cmd_seq_t *commands) | 4635 | sctp_cmd_seq_t *commands) |
4618 | { | 4636 | { |
4637 | SCTP_INC_STATS(SCTP_MIB_DELAY_SACK_EXPIREDS); | ||
4619 | sctp_add_cmd_sf(commands, SCTP_CMD_GEN_SACK, SCTP_FORCE()); | 4638 | sctp_add_cmd_sf(commands, SCTP_CMD_GEN_SACK, SCTP_FORCE()); |
4620 | return SCTP_DISPOSITION_CONSUME; | 4639 | return SCTP_DISPOSITION_CONSUME; |
4621 | } | 4640 | } |
@@ -4650,6 +4669,7 @@ sctp_disposition_t sctp_sf_t1_init_timer_expire(const struct sctp_endpoint *ep, | |||
4650 | int attempts = asoc->init_err_counter + 1; | 4669 | int attempts = asoc->init_err_counter + 1; |
4651 | 4670 | ||
4652 | SCTP_DEBUG_PRINTK("Timer T1 expired (INIT).\n"); | 4671 | SCTP_DEBUG_PRINTK("Timer T1 expired (INIT).\n"); |
4672 | SCTP_INC_STATS(SCTP_MIB_T1_INIT_EXPIREDS); | ||
4653 | 4673 | ||
4654 | if (attempts <= asoc->max_init_attempts) { | 4674 | if (attempts <= asoc->max_init_attempts) { |
4655 | bp = (struct sctp_bind_addr *) &asoc->base.bind_addr; | 4675 | bp = (struct sctp_bind_addr *) &asoc->base.bind_addr; |
@@ -4709,6 +4729,7 @@ sctp_disposition_t sctp_sf_t1_cookie_timer_expire(const struct sctp_endpoint *ep | |||
4709 | int attempts = asoc->init_err_counter + 1; | 4729 | int attempts = asoc->init_err_counter + 1; |
4710 | 4730 | ||
4711 | SCTP_DEBUG_PRINTK("Timer T1 expired (COOKIE-ECHO).\n"); | 4731 | SCTP_DEBUG_PRINTK("Timer T1 expired (COOKIE-ECHO).\n"); |
4732 | SCTP_INC_STATS(SCTP_MIB_T1_COOKIE_EXPIREDS); | ||
4712 | 4733 | ||
4713 | if (attempts <= asoc->max_init_attempts) { | 4734 | if (attempts <= asoc->max_init_attempts) { |
4714 | repl = sctp_make_cookie_echo(asoc, NULL); | 4735 | repl = sctp_make_cookie_echo(asoc, NULL); |
@@ -4753,6 +4774,8 @@ sctp_disposition_t sctp_sf_t2_timer_expire(const struct sctp_endpoint *ep, | |||
4753 | struct sctp_chunk *reply = NULL; | 4774 | struct sctp_chunk *reply = NULL; |
4754 | 4775 | ||
4755 | SCTP_DEBUG_PRINTK("Timer T2 expired.\n"); | 4776 | SCTP_DEBUG_PRINTK("Timer T2 expired.\n"); |
4777 | SCTP_INC_STATS(SCTP_MIB_T2_SHUTDOWN_EXPIREDS); | ||
4778 | |||
4756 | if (asoc->overall_error_count >= asoc->max_retrans) { | 4779 | if (asoc->overall_error_count >= asoc->max_retrans) { |
4757 | sctp_add_cmd_sf(commands, SCTP_CMD_SET_SK_ERR, | 4780 | sctp_add_cmd_sf(commands, SCTP_CMD_SET_SK_ERR, |
4758 | SCTP_ERROR(ETIMEDOUT)); | 4781 | SCTP_ERROR(ETIMEDOUT)); |
@@ -4814,6 +4837,8 @@ sctp_disposition_t sctp_sf_t4_timer_expire( | |||
4814 | struct sctp_chunk *chunk = asoc->addip_last_asconf; | 4837 | struct sctp_chunk *chunk = asoc->addip_last_asconf; |
4815 | struct sctp_transport *transport = chunk->transport; | 4838 | struct sctp_transport *transport = chunk->transport; |
4816 | 4839 | ||
4840 | SCTP_INC_STATS(SCTP_MIB_T4_RTO_EXPIREDS); | ||
4841 | |||
4817 | /* ADDIP 4.1 B1) Increment the error counters and perform path failure | 4842 | /* ADDIP 4.1 B1) Increment the error counters and perform path failure |
4818 | * detection on the appropriate destination address as defined in | 4843 | * detection on the appropriate destination address as defined in |
4819 | * RFC2960 [5] section 8.1 and 8.2. | 4844 | * RFC2960 [5] section 8.1 and 8.2. |
@@ -4880,6 +4905,7 @@ sctp_disposition_t sctp_sf_t5_timer_expire(const struct sctp_endpoint *ep, | |||
4880 | struct sctp_chunk *reply = NULL; | 4905 | struct sctp_chunk *reply = NULL; |
4881 | 4906 | ||
4882 | SCTP_DEBUG_PRINTK("Timer T5 expired.\n"); | 4907 | SCTP_DEBUG_PRINTK("Timer T5 expired.\n"); |
4908 | SCTP_INC_STATS(SCTP_MIB_T5_SHUTDOWN_GUARD_EXPIREDS); | ||
4883 | 4909 | ||
4884 | reply = sctp_make_abort(asoc, NULL, 0); | 4910 | reply = sctp_make_abort(asoc, NULL, 0); |
4885 | if (!reply) | 4911 | if (!reply) |
@@ -4910,6 +4936,8 @@ sctp_disposition_t sctp_sf_autoclose_timer_expire( | |||
4910 | { | 4936 | { |
4911 | int disposition; | 4937 | int disposition; |
4912 | 4938 | ||
4939 | SCTP_INC_STATS(SCTP_MIB_AUTOCLOSE_EXPIREDS); | ||
4940 | |||
4913 | /* From 9.2 Shutdown of an Association | 4941 | /* From 9.2 Shutdown of an Association |
4914 | * Upon receipt of the SHUTDOWN primitive from its upper | 4942 | * Upon receipt of the SHUTDOWN primitive from its upper |
4915 | * layer, the endpoint enters SHUTDOWN-PENDING state and | 4943 | * layer, the endpoint enters SHUTDOWN-PENDING state and |
diff --git a/net/sctp/socket.c b/net/sctp/socket.c index 85caf7963886..79c3e072cf28 100644 --- a/net/sctp/socket.c +++ b/net/sctp/socket.c | |||
@@ -2081,13 +2081,13 @@ static int sctp_setsockopt_autoclose(struct sock *sk, char __user *optval, | |||
2081 | * SPP_SACKDELAY_ENABLE, setting both will have undefined | 2081 | * SPP_SACKDELAY_ENABLE, setting both will have undefined |
2082 | * results. | 2082 | * results. |
2083 | */ | 2083 | */ |
2084 | int sctp_apply_peer_addr_params(struct sctp_paddrparams *params, | 2084 | static int sctp_apply_peer_addr_params(struct sctp_paddrparams *params, |
2085 | struct sctp_transport *trans, | 2085 | struct sctp_transport *trans, |
2086 | struct sctp_association *asoc, | 2086 | struct sctp_association *asoc, |
2087 | struct sctp_sock *sp, | 2087 | struct sctp_sock *sp, |
2088 | int hb_change, | 2088 | int hb_change, |
2089 | int pmtud_change, | 2089 | int pmtud_change, |
2090 | int sackdelay_change) | 2090 | int sackdelay_change) |
2091 | { | 2091 | { |
2092 | int error; | 2092 | int error; |
2093 | 2093 | ||
@@ -2970,7 +2970,7 @@ SCTP_STATIC struct sock *sctp_accept(struct sock *sk, int flags, int *err) | |||
2970 | goto out; | 2970 | goto out; |
2971 | } | 2971 | } |
2972 | 2972 | ||
2973 | timeo = sock_rcvtimeo(sk, sk->sk_socket->file->f_flags & O_NONBLOCK); | 2973 | timeo = sock_rcvtimeo(sk, flags & O_NONBLOCK); |
2974 | 2974 | ||
2975 | error = sctp_wait_for_accept(sk, timeo); | 2975 | error = sctp_wait_for_accept(sk, timeo); |
2976 | if (error) | 2976 | if (error) |
@@ -3045,14 +3045,14 @@ SCTP_STATIC int sctp_init_sock(struct sock *sk) | |||
3045 | sp->initmsg.sinit_num_ostreams = sctp_max_outstreams; | 3045 | sp->initmsg.sinit_num_ostreams = sctp_max_outstreams; |
3046 | sp->initmsg.sinit_max_instreams = sctp_max_instreams; | 3046 | sp->initmsg.sinit_max_instreams = sctp_max_instreams; |
3047 | sp->initmsg.sinit_max_attempts = sctp_max_retrans_init; | 3047 | sp->initmsg.sinit_max_attempts = sctp_max_retrans_init; |
3048 | sp->initmsg.sinit_max_init_timeo = jiffies_to_msecs(sctp_rto_max); | 3048 | sp->initmsg.sinit_max_init_timeo = sctp_rto_max; |
3049 | 3049 | ||
3050 | /* Initialize default RTO related parameters. These parameters can | 3050 | /* Initialize default RTO related parameters. These parameters can |
3051 | * be modified for with the SCTP_RTOINFO socket option. | 3051 | * be modified for with the SCTP_RTOINFO socket option. |
3052 | */ | 3052 | */ |
3053 | sp->rtoinfo.srto_initial = jiffies_to_msecs(sctp_rto_initial); | 3053 | sp->rtoinfo.srto_initial = sctp_rto_initial; |
3054 | sp->rtoinfo.srto_max = jiffies_to_msecs(sctp_rto_max); | 3054 | sp->rtoinfo.srto_max = sctp_rto_max; |
3055 | sp->rtoinfo.srto_min = jiffies_to_msecs(sctp_rto_min); | 3055 | sp->rtoinfo.srto_min = sctp_rto_min; |
3056 | 3056 | ||
3057 | /* Initialize default association related parameters. These parameters | 3057 | /* Initialize default association related parameters. These parameters |
3058 | * can be modified with the SCTP_ASSOCINFO socket option. | 3058 | * can be modified with the SCTP_ASSOCINFO socket option. |
@@ -3061,8 +3061,7 @@ SCTP_STATIC int sctp_init_sock(struct sock *sk) | |||
3061 | sp->assocparams.sasoc_number_peer_destinations = 0; | 3061 | sp->assocparams.sasoc_number_peer_destinations = 0; |
3062 | sp->assocparams.sasoc_peer_rwnd = 0; | 3062 | sp->assocparams.sasoc_peer_rwnd = 0; |
3063 | sp->assocparams.sasoc_local_rwnd = 0; | 3063 | sp->assocparams.sasoc_local_rwnd = 0; |
3064 | sp->assocparams.sasoc_cookie_life = | 3064 | sp->assocparams.sasoc_cookie_life = sctp_valid_cookie_life; |
3065 | jiffies_to_msecs(sctp_valid_cookie_life); | ||
3066 | 3065 | ||
3067 | /* Initialize default event subscriptions. By default, all the | 3066 | /* Initialize default event subscriptions. By default, all the |
3068 | * options are off. | 3067 | * options are off. |
@@ -3072,10 +3071,10 @@ SCTP_STATIC int sctp_init_sock(struct sock *sk) | |||
3072 | /* Default Peer Address Parameters. These defaults can | 3071 | /* Default Peer Address Parameters. These defaults can |
3073 | * be modified via SCTP_PEER_ADDR_PARAMS | 3072 | * be modified via SCTP_PEER_ADDR_PARAMS |
3074 | */ | 3073 | */ |
3075 | sp->hbinterval = jiffies_to_msecs(sctp_hb_interval); | 3074 | sp->hbinterval = sctp_hb_interval; |
3076 | sp->pathmaxrxt = sctp_max_retrans_path; | 3075 | sp->pathmaxrxt = sctp_max_retrans_path; |
3077 | sp->pathmtu = 0; // allow default discovery | 3076 | sp->pathmtu = 0; // allow default discovery |
3078 | sp->sackdelay = jiffies_to_msecs(sctp_sack_timeout); | 3077 | sp->sackdelay = sctp_sack_timeout; |
3079 | sp->param_flags = SPP_HB_ENABLE | | 3078 | sp->param_flags = SPP_HB_ENABLE | |
3080 | SPP_PMTUD_ENABLE | | 3079 | SPP_PMTUD_ENABLE | |
3081 | SPP_SACKDELAY_ENABLE; | 3080 | SPP_SACKDELAY_ENABLE; |
@@ -5619,6 +5618,8 @@ static void sctp_sock_migrate(struct sock *oldsk, struct sock *newsk, | |||
5619 | /* Copy the bind_addr list from the original endpoint to the new | 5618 | /* Copy the bind_addr list from the original endpoint to the new |
5620 | * endpoint so that we can handle restarts properly | 5619 | * endpoint so that we can handle restarts properly |
5621 | */ | 5620 | */ |
5621 | if (PF_INET6 == assoc->base.sk->sk_family) | ||
5622 | flags = SCTP_ADDR6_ALLOWED; | ||
5622 | if (assoc->peer.ipv4_address) | 5623 | if (assoc->peer.ipv4_address) |
5623 | flags |= SCTP_ADDR4_PEERSUPP; | 5624 | flags |= SCTP_ADDR4_PEERSUPP; |
5624 | if (assoc->peer.ipv6_address) | 5625 | if (assoc->peer.ipv6_address) |
diff --git a/net/sctp/sysctl.c b/net/sctp/sysctl.c index dc6f3ff32358..633cd178654b 100644 --- a/net/sctp/sysctl.c +++ b/net/sctp/sysctl.c | |||
@@ -45,9 +45,10 @@ | |||
45 | #include <net/sctp/sctp.h> | 45 | #include <net/sctp/sctp.h> |
46 | #include <linux/sysctl.h> | 46 | #include <linux/sysctl.h> |
47 | 47 | ||
48 | static ctl_handler sctp_sysctl_jiffies_ms; | 48 | static int zero = 0; |
49 | static long rto_timer_min = 1; | 49 | static int one = 1; |
50 | static long rto_timer_max = 86400000; /* One day */ | 50 | static int timer_max = 86400000; /* ms in one day */ |
51 | static int int_max = INT_MAX; | ||
51 | static long sack_timer_min = 1; | 52 | static long sack_timer_min = 1; |
52 | static long sack_timer_max = 500; | 53 | static long sack_timer_max = 500; |
53 | 54 | ||
@@ -56,45 +57,45 @@ static ctl_table sctp_table[] = { | |||
56 | .ctl_name = NET_SCTP_RTO_INITIAL, | 57 | .ctl_name = NET_SCTP_RTO_INITIAL, |
57 | .procname = "rto_initial", | 58 | .procname = "rto_initial", |
58 | .data = &sctp_rto_initial, | 59 | .data = &sctp_rto_initial, |
59 | .maxlen = sizeof(long), | 60 | .maxlen = sizeof(unsigned int), |
60 | .mode = 0644, | 61 | .mode = 0644, |
61 | .proc_handler = &proc_doulongvec_ms_jiffies_minmax, | 62 | .proc_handler = &proc_dointvec_minmax, |
62 | .strategy = &sctp_sysctl_jiffies_ms, | 63 | .strategy = &sysctl_intvec, |
63 | .extra1 = &rto_timer_min, | 64 | .extra1 = &one, |
64 | .extra2 = &rto_timer_max | 65 | .extra2 = &timer_max |
65 | }, | 66 | }, |
66 | { | 67 | { |
67 | .ctl_name = NET_SCTP_RTO_MIN, | 68 | .ctl_name = NET_SCTP_RTO_MIN, |
68 | .procname = "rto_min", | 69 | .procname = "rto_min", |
69 | .data = &sctp_rto_min, | 70 | .data = &sctp_rto_min, |
70 | .maxlen = sizeof(long), | 71 | .maxlen = sizeof(unsigned int), |
71 | .mode = 0644, | 72 | .mode = 0644, |
72 | .proc_handler = &proc_doulongvec_ms_jiffies_minmax, | 73 | .proc_handler = &proc_dointvec_minmax, |
73 | .strategy = &sctp_sysctl_jiffies_ms, | 74 | .strategy = &sysctl_intvec, |
74 | .extra1 = &rto_timer_min, | 75 | .extra1 = &one, |
75 | .extra2 = &rto_timer_max | 76 | .extra2 = &timer_max |
76 | }, | 77 | }, |
77 | { | 78 | { |
78 | .ctl_name = NET_SCTP_RTO_MAX, | 79 | .ctl_name = NET_SCTP_RTO_MAX, |
79 | .procname = "rto_max", | 80 | .procname = "rto_max", |
80 | .data = &sctp_rto_max, | 81 | .data = &sctp_rto_max, |
81 | .maxlen = sizeof(long), | 82 | .maxlen = sizeof(unsigned int), |
82 | .mode = 0644, | 83 | .mode = 0644, |
83 | .proc_handler = &proc_doulongvec_ms_jiffies_minmax, | 84 | .proc_handler = &proc_dointvec_minmax, |
84 | .strategy = &sctp_sysctl_jiffies_ms, | 85 | .strategy = &sysctl_intvec, |
85 | .extra1 = &rto_timer_min, | 86 | .extra1 = &one, |
86 | .extra2 = &rto_timer_max | 87 | .extra2 = &timer_max |
87 | }, | 88 | }, |
88 | { | 89 | { |
89 | .ctl_name = NET_SCTP_VALID_COOKIE_LIFE, | 90 | .ctl_name = NET_SCTP_VALID_COOKIE_LIFE, |
90 | .procname = "valid_cookie_life", | 91 | .procname = "valid_cookie_life", |
91 | .data = &sctp_valid_cookie_life, | 92 | .data = &sctp_valid_cookie_life, |
92 | .maxlen = sizeof(long), | 93 | .maxlen = sizeof(unsigned int), |
93 | .mode = 0644, | 94 | .mode = 0644, |
94 | .proc_handler = &proc_doulongvec_ms_jiffies_minmax, | 95 | .proc_handler = &proc_dointvec_minmax, |
95 | .strategy = &sctp_sysctl_jiffies_ms, | 96 | .strategy = &sysctl_intvec, |
96 | .extra1 = &rto_timer_min, | 97 | .extra1 = &one, |
97 | .extra2 = &rto_timer_max | 98 | .extra2 = &timer_max |
98 | }, | 99 | }, |
99 | { | 100 | { |
100 | .ctl_name = NET_SCTP_MAX_BURST, | 101 | .ctl_name = NET_SCTP_MAX_BURST, |
@@ -102,7 +103,10 @@ static ctl_table sctp_table[] = { | |||
102 | .data = &sctp_max_burst, | 103 | .data = &sctp_max_burst, |
103 | .maxlen = sizeof(int), | 104 | .maxlen = sizeof(int), |
104 | .mode = 0644, | 105 | .mode = 0644, |
105 | .proc_handler = &proc_dointvec | 106 | .proc_handler = &proc_dointvec_minmax, |
107 | .strategy = &sysctl_intvec, | ||
108 | .extra1 = &zero, | ||
109 | .extra2 = &int_max | ||
106 | }, | 110 | }, |
107 | { | 111 | { |
108 | .ctl_name = NET_SCTP_ASSOCIATION_MAX_RETRANS, | 112 | .ctl_name = NET_SCTP_ASSOCIATION_MAX_RETRANS, |
@@ -110,7 +114,10 @@ static ctl_table sctp_table[] = { | |||
110 | .data = &sctp_max_retrans_association, | 114 | .data = &sctp_max_retrans_association, |
111 | .maxlen = sizeof(int), | 115 | .maxlen = sizeof(int), |
112 | .mode = 0644, | 116 | .mode = 0644, |
113 | .proc_handler = &proc_dointvec | 117 | .proc_handler = &proc_dointvec_minmax, |
118 | .strategy = &sysctl_intvec, | ||
119 | .extra1 = &one, | ||
120 | .extra2 = &int_max | ||
114 | }, | 121 | }, |
115 | { | 122 | { |
116 | .ctl_name = NET_SCTP_SNDBUF_POLICY, | 123 | .ctl_name = NET_SCTP_SNDBUF_POLICY, |
@@ -118,7 +125,8 @@ static ctl_table sctp_table[] = { | |||
118 | .data = &sctp_sndbuf_policy, | 125 | .data = &sctp_sndbuf_policy, |
119 | .maxlen = sizeof(int), | 126 | .maxlen = sizeof(int), |
120 | .mode = 0644, | 127 | .mode = 0644, |
121 | .proc_handler = &proc_dointvec | 128 | .proc_handler = &proc_dointvec, |
129 | .strategy = &sysctl_intvec | ||
122 | }, | 130 | }, |
123 | { | 131 | { |
124 | .ctl_name = NET_SCTP_RCVBUF_POLICY, | 132 | .ctl_name = NET_SCTP_RCVBUF_POLICY, |
@@ -126,7 +134,8 @@ static ctl_table sctp_table[] = { | |||
126 | .data = &sctp_rcvbuf_policy, | 134 | .data = &sctp_rcvbuf_policy, |
127 | .maxlen = sizeof(int), | 135 | .maxlen = sizeof(int), |
128 | .mode = 0644, | 136 | .mode = 0644, |
129 | .proc_handler = &proc_dointvec | 137 | .proc_handler = &proc_dointvec, |
138 | .strategy = &sysctl_intvec | ||
130 | }, | 139 | }, |
131 | { | 140 | { |
132 | .ctl_name = NET_SCTP_PATH_MAX_RETRANS, | 141 | .ctl_name = NET_SCTP_PATH_MAX_RETRANS, |
@@ -134,7 +143,10 @@ static ctl_table sctp_table[] = { | |||
134 | .data = &sctp_max_retrans_path, | 143 | .data = &sctp_max_retrans_path, |
135 | .maxlen = sizeof(int), | 144 | .maxlen = sizeof(int), |
136 | .mode = 0644, | 145 | .mode = 0644, |
137 | .proc_handler = &proc_dointvec | 146 | .proc_handler = &proc_dointvec_minmax, |
147 | .strategy = &sysctl_intvec, | ||
148 | .extra1 = &one, | ||
149 | .extra2 = &int_max | ||
138 | }, | 150 | }, |
139 | { | 151 | { |
140 | .ctl_name = NET_SCTP_MAX_INIT_RETRANSMITS, | 152 | .ctl_name = NET_SCTP_MAX_INIT_RETRANSMITS, |
@@ -142,18 +154,21 @@ static ctl_table sctp_table[] = { | |||
142 | .data = &sctp_max_retrans_init, | 154 | .data = &sctp_max_retrans_init, |
143 | .maxlen = sizeof(int), | 155 | .maxlen = sizeof(int), |
144 | .mode = 0644, | 156 | .mode = 0644, |
145 | .proc_handler = &proc_dointvec | 157 | .proc_handler = &proc_dointvec_minmax, |
158 | .strategy = &sysctl_intvec, | ||
159 | .extra1 = &one, | ||
160 | .extra2 = &int_max | ||
146 | }, | 161 | }, |
147 | { | 162 | { |
148 | .ctl_name = NET_SCTP_HB_INTERVAL, | 163 | .ctl_name = NET_SCTP_HB_INTERVAL, |
149 | .procname = "hb_interval", | 164 | .procname = "hb_interval", |
150 | .data = &sctp_hb_interval, | 165 | .data = &sctp_hb_interval, |
151 | .maxlen = sizeof(long), | 166 | .maxlen = sizeof(unsigned int), |
152 | .mode = 0644, | 167 | .mode = 0644, |
153 | .proc_handler = &proc_doulongvec_ms_jiffies_minmax, | 168 | .proc_handler = &proc_dointvec_minmax, |
154 | .strategy = &sctp_sysctl_jiffies_ms, | 169 | .strategy = &sysctl_intvec, |
155 | .extra1 = &rto_timer_min, | 170 | .extra1 = &one, |
156 | .extra2 = &rto_timer_max | 171 | .extra2 = &timer_max |
157 | }, | 172 | }, |
158 | { | 173 | { |
159 | .ctl_name = NET_SCTP_PRESERVE_ENABLE, | 174 | .ctl_name = NET_SCTP_PRESERVE_ENABLE, |
@@ -161,23 +176,26 @@ static ctl_table sctp_table[] = { | |||
161 | .data = &sctp_cookie_preserve_enable, | 176 | .data = &sctp_cookie_preserve_enable, |
162 | .maxlen = sizeof(int), | 177 | .maxlen = sizeof(int), |
163 | .mode = 0644, | 178 | .mode = 0644, |
164 | .proc_handler = &proc_dointvec | 179 | .proc_handler = &proc_dointvec, |
180 | .strategy = &sysctl_intvec | ||
165 | }, | 181 | }, |
166 | { | 182 | { |
167 | .ctl_name = NET_SCTP_RTO_ALPHA, | 183 | .ctl_name = NET_SCTP_RTO_ALPHA, |
168 | .procname = "rto_alpha_exp_divisor", | 184 | .procname = "rto_alpha_exp_divisor", |
169 | .data = &sctp_rto_alpha, | 185 | .data = &sctp_rto_alpha, |
170 | .maxlen = sizeof(int), | 186 | .maxlen = sizeof(int), |
171 | .mode = 0644, | 187 | .mode = 0444, |
172 | .proc_handler = &proc_dointvec | 188 | .proc_handler = &proc_dointvec, |
189 | .strategy = &sysctl_intvec | ||
173 | }, | 190 | }, |
174 | { | 191 | { |
175 | .ctl_name = NET_SCTP_RTO_BETA, | 192 | .ctl_name = NET_SCTP_RTO_BETA, |
176 | .procname = "rto_beta_exp_divisor", | 193 | .procname = "rto_beta_exp_divisor", |
177 | .data = &sctp_rto_beta, | 194 | .data = &sctp_rto_beta, |
178 | .maxlen = sizeof(int), | 195 | .maxlen = sizeof(int), |
179 | .mode = 0644, | 196 | .mode = 0444, |
180 | .proc_handler = &proc_dointvec | 197 | .proc_handler = &proc_dointvec, |
198 | .strategy = &sysctl_intvec | ||
181 | }, | 199 | }, |
182 | { | 200 | { |
183 | .ctl_name = NET_SCTP_ADDIP_ENABLE, | 201 | .ctl_name = NET_SCTP_ADDIP_ENABLE, |
@@ -185,7 +203,8 @@ static ctl_table sctp_table[] = { | |||
185 | .data = &sctp_addip_enable, | 203 | .data = &sctp_addip_enable, |
186 | .maxlen = sizeof(int), | 204 | .maxlen = sizeof(int), |
187 | .mode = 0644, | 205 | .mode = 0644, |
188 | .proc_handler = &proc_dointvec | 206 | .proc_handler = &proc_dointvec, |
207 | .strategy = &sysctl_intvec | ||
189 | }, | 208 | }, |
190 | { | 209 | { |
191 | .ctl_name = NET_SCTP_PRSCTP_ENABLE, | 210 | .ctl_name = NET_SCTP_PRSCTP_ENABLE, |
@@ -193,7 +212,8 @@ static ctl_table sctp_table[] = { | |||
193 | .data = &sctp_prsctp_enable, | 212 | .data = &sctp_prsctp_enable, |
194 | .maxlen = sizeof(int), | 213 | .maxlen = sizeof(int), |
195 | .mode = 0644, | 214 | .mode = 0644, |
196 | .proc_handler = &proc_dointvec | 215 | .proc_handler = &proc_dointvec, |
216 | .strategy = &sysctl_intvec | ||
197 | }, | 217 | }, |
198 | { | 218 | { |
199 | .ctl_name = NET_SCTP_SACK_TIMEOUT, | 219 | .ctl_name = NET_SCTP_SACK_TIMEOUT, |
@@ -201,8 +221,8 @@ static ctl_table sctp_table[] = { | |||
201 | .data = &sctp_sack_timeout, | 221 | .data = &sctp_sack_timeout, |
202 | .maxlen = sizeof(long), | 222 | .maxlen = sizeof(long), |
203 | .mode = 0644, | 223 | .mode = 0644, |
204 | .proc_handler = &proc_doulongvec_ms_jiffies_minmax, | 224 | .proc_handler = &proc_dointvec_minmax, |
205 | .strategy = &sctp_sysctl_jiffies_ms, | 225 | .strategy = &sysctl_intvec, |
206 | .extra1 = &sack_timer_min, | 226 | .extra1 = &sack_timer_min, |
207 | .extra2 = &sack_timer_max, | 227 | .extra2 = &sack_timer_max, |
208 | }, | 228 | }, |
@@ -242,37 +262,3 @@ void sctp_sysctl_unregister(void) | |||
242 | { | 262 | { |
243 | unregister_sysctl_table(sctp_sysctl_header); | 263 | unregister_sysctl_table(sctp_sysctl_header); |
244 | } | 264 | } |
245 | |||
246 | /* Strategy function to convert jiffies to milliseconds. */ | ||
247 | static int sctp_sysctl_jiffies_ms(ctl_table *table, int __user *name, int nlen, | ||
248 | void __user *oldval, size_t __user *oldlenp, | ||
249 | void __user *newval, size_t newlen, void **context) { | ||
250 | |||
251 | if (oldval) { | ||
252 | size_t olen; | ||
253 | |||
254 | if (oldlenp) { | ||
255 | if (get_user(olen, oldlenp)) | ||
256 | return -EFAULT; | ||
257 | |||
258 | if (olen != sizeof (int)) | ||
259 | return -EINVAL; | ||
260 | } | ||
261 | if (put_user((*(int *)(table->data) * 1000) / HZ, | ||
262 | (int __user *)oldval) || | ||
263 | (oldlenp && put_user(sizeof (int), oldlenp))) | ||
264 | return -EFAULT; | ||
265 | } | ||
266 | if (newval && newlen) { | ||
267 | int new; | ||
268 | |||
269 | if (newlen != sizeof (int)) | ||
270 | return -EINVAL; | ||
271 | |||
272 | if (get_user(new, (int __user *)newval)) | ||
273 | return -EFAULT; | ||
274 | |||
275 | *(int *)(table->data) = (new * HZ) / 1000; | ||
276 | } | ||
277 | return 1; | ||
278 | } | ||
diff --git a/net/sctp/transport.c b/net/sctp/transport.c index 2763aa93de1a..3e5936a5f671 100644 --- a/net/sctp/transport.c +++ b/net/sctp/transport.c | |||
@@ -75,7 +75,7 @@ static struct sctp_transport *sctp_transport_init(struct sctp_transport *peer, | |||
75 | * parameter 'RTO.Initial'. | 75 | * parameter 'RTO.Initial'. |
76 | */ | 76 | */ |
77 | peer->rtt = 0; | 77 | peer->rtt = 0; |
78 | peer->rto = sctp_rto_initial; | 78 | peer->rto = msecs_to_jiffies(sctp_rto_initial); |
79 | peer->rttvar = 0; | 79 | peer->rttvar = 0; |
80 | peer->srtt = 0; | 80 | peer->srtt = 0; |
81 | peer->rto_pending = 0; | 81 | peer->rto_pending = 0; |
diff --git a/net/socket.c b/net/socket.c index 6d261bf206fc..1bc4167e0da8 100644 --- a/net/socket.c +++ b/net/socket.c | |||
@@ -42,7 +42,7 @@ | |||
42 | * Andi Kleen : Some small cleanups, optimizations, | 42 | * Andi Kleen : Some small cleanups, optimizations, |
43 | * and fixed a copy_from_user() bug. | 43 | * and fixed a copy_from_user() bug. |
44 | * Tigran Aivazian : sys_send(args) calls sys_sendto(args, NULL, 0) | 44 | * Tigran Aivazian : sys_send(args) calls sys_sendto(args, NULL, 0) |
45 | * Tigran Aivazian : Made listen(2) backlog sanity checks | 45 | * Tigran Aivazian : Made listen(2) backlog sanity checks |
46 | * protocol-independent | 46 | * protocol-independent |
47 | * | 47 | * |
48 | * | 48 | * |
@@ -53,17 +53,17 @@ | |||
53 | * | 53 | * |
54 | * | 54 | * |
55 | * This module is effectively the top level interface to the BSD socket | 55 | * This module is effectively the top level interface to the BSD socket |
56 | * paradigm. | 56 | * paradigm. |
57 | * | 57 | * |
58 | * Based upon Swansea University Computer Society NET3.039 | 58 | * Based upon Swansea University Computer Society NET3.039 |
59 | */ | 59 | */ |
60 | 60 | ||
61 | #include <linux/mm.h> | 61 | #include <linux/mm.h> |
62 | #include <linux/smp_lock.h> | ||
63 | #include <linux/socket.h> | 62 | #include <linux/socket.h> |
64 | #include <linux/file.h> | 63 | #include <linux/file.h> |
65 | #include <linux/net.h> | 64 | #include <linux/net.h> |
66 | #include <linux/interrupt.h> | 65 | #include <linux/interrupt.h> |
66 | #include <linux/rcupdate.h> | ||
67 | #include <linux/netdevice.h> | 67 | #include <linux/netdevice.h> |
68 | #include <linux/proc_fs.h> | 68 | #include <linux/proc_fs.h> |
69 | #include <linux/seq_file.h> | 69 | #include <linux/seq_file.h> |
@@ -96,25 +96,24 @@ | |||
96 | 96 | ||
97 | static int sock_no_open(struct inode *irrelevant, struct file *dontcare); | 97 | static int sock_no_open(struct inode *irrelevant, struct file *dontcare); |
98 | static ssize_t sock_aio_read(struct kiocb *iocb, char __user *buf, | 98 | static ssize_t sock_aio_read(struct kiocb *iocb, char __user *buf, |
99 | size_t size, loff_t pos); | 99 | size_t size, loff_t pos); |
100 | static ssize_t sock_aio_write(struct kiocb *iocb, const char __user *buf, | 100 | static ssize_t sock_aio_write(struct kiocb *iocb, const char __user *buf, |
101 | size_t size, loff_t pos); | 101 | size_t size, loff_t pos); |
102 | static int sock_mmap(struct file *file, struct vm_area_struct * vma); | 102 | static int sock_mmap(struct file *file, struct vm_area_struct *vma); |
103 | 103 | ||
104 | static int sock_close(struct inode *inode, struct file *file); | 104 | static int sock_close(struct inode *inode, struct file *file); |
105 | static unsigned int sock_poll(struct file *file, | 105 | static unsigned int sock_poll(struct file *file, |
106 | struct poll_table_struct *wait); | 106 | struct poll_table_struct *wait); |
107 | static long sock_ioctl(struct file *file, | 107 | static long sock_ioctl(struct file *file, unsigned int cmd, unsigned long arg); |
108 | unsigned int cmd, unsigned long arg); | ||
109 | #ifdef CONFIG_COMPAT | 108 | #ifdef CONFIG_COMPAT |
110 | static long compat_sock_ioctl(struct file *file, | 109 | static long compat_sock_ioctl(struct file *file, |
111 | unsigned int cmd, unsigned long arg); | 110 | unsigned int cmd, unsigned long arg); |
112 | #endif | 111 | #endif |
113 | static int sock_fasync(int fd, struct file *filp, int on); | 112 | static int sock_fasync(int fd, struct file *filp, int on); |
114 | static ssize_t sock_readv(struct file *file, const struct iovec *vector, | 113 | static ssize_t sock_readv(struct file *file, const struct iovec *vector, |
115 | unsigned long count, loff_t *ppos); | 114 | unsigned long count, loff_t *ppos); |
116 | static ssize_t sock_writev(struct file *file, const struct iovec *vector, | 115 | static ssize_t sock_writev(struct file *file, const struct iovec *vector, |
117 | unsigned long count, loff_t *ppos); | 116 | unsigned long count, loff_t *ppos); |
118 | static ssize_t sock_sendpage(struct file *file, struct page *page, | 117 | static ssize_t sock_sendpage(struct file *file, struct page *page, |
119 | int offset, size_t size, loff_t *ppos, int more); | 118 | int offset, size_t size, loff_t *ppos, int more); |
120 | 119 | ||
@@ -147,52 +146,8 @@ static struct file_operations socket_file_ops = { | |||
147 | * The protocol list. Each protocol is registered in here. | 146 | * The protocol list. Each protocol is registered in here. |
148 | */ | 147 | */ |
149 | 148 | ||
150 | static struct net_proto_family *net_families[NPROTO]; | ||
151 | |||
152 | #if defined(CONFIG_SMP) || defined(CONFIG_PREEMPT) | ||
153 | static atomic_t net_family_lockct = ATOMIC_INIT(0); | ||
154 | static DEFINE_SPINLOCK(net_family_lock); | 149 | static DEFINE_SPINLOCK(net_family_lock); |
155 | 150 | static const struct net_proto_family *net_families[NPROTO] __read_mostly; | |
156 | /* The strategy is: modifications net_family vector are short, do not | ||
157 | sleep and veeery rare, but read access should be free of any exclusive | ||
158 | locks. | ||
159 | */ | ||
160 | |||
161 | static void net_family_write_lock(void) | ||
162 | { | ||
163 | spin_lock(&net_family_lock); | ||
164 | while (atomic_read(&net_family_lockct) != 0) { | ||
165 | spin_unlock(&net_family_lock); | ||
166 | |||
167 | yield(); | ||
168 | |||
169 | spin_lock(&net_family_lock); | ||
170 | } | ||
171 | } | ||
172 | |||
173 | static __inline__ void net_family_write_unlock(void) | ||
174 | { | ||
175 | spin_unlock(&net_family_lock); | ||
176 | } | ||
177 | |||
178 | static __inline__ void net_family_read_lock(void) | ||
179 | { | ||
180 | atomic_inc(&net_family_lockct); | ||
181 | spin_unlock_wait(&net_family_lock); | ||
182 | } | ||
183 | |||
184 | static __inline__ void net_family_read_unlock(void) | ||
185 | { | ||
186 | atomic_dec(&net_family_lockct); | ||
187 | } | ||
188 | |||
189 | #else | ||
190 | #define net_family_write_lock() do { } while(0) | ||
191 | #define net_family_write_unlock() do { } while(0) | ||
192 | #define net_family_read_lock() do { } while(0) | ||
193 | #define net_family_read_unlock() do { } while(0) | ||
194 | #endif | ||
195 | |||
196 | 151 | ||
197 | /* | 152 | /* |
198 | * Statistics counters of the socket lists | 153 | * Statistics counters of the socket lists |
@@ -201,19 +156,20 @@ static __inline__ void net_family_read_unlock(void) | |||
201 | static DEFINE_PER_CPU(int, sockets_in_use) = 0; | 156 | static DEFINE_PER_CPU(int, sockets_in_use) = 0; |
202 | 157 | ||
203 | /* | 158 | /* |
204 | * Support routines. Move socket addresses back and forth across the kernel/user | 159 | * Support routines. |
205 | * divide and look after the messy bits. | 160 | * Move socket addresses back and forth across the kernel/user |
161 | * divide and look after the messy bits. | ||
206 | */ | 162 | */ |
207 | 163 | ||
208 | #define MAX_SOCK_ADDR 128 /* 108 for Unix domain - | 164 | #define MAX_SOCK_ADDR 128 /* 108 for Unix domain - |
209 | 16 for IP, 16 for IPX, | 165 | 16 for IP, 16 for IPX, |
210 | 24 for IPv6, | 166 | 24 for IPv6, |
211 | about 80 for AX.25 | 167 | about 80 for AX.25 |
212 | must be at least one bigger than | 168 | must be at least one bigger than |
213 | the AF_UNIX size (see net/unix/af_unix.c | 169 | the AF_UNIX size (see net/unix/af_unix.c |
214 | :unix_mkname()). | 170 | :unix_mkname()). |
215 | */ | 171 | */ |
216 | 172 | ||
217 | /** | 173 | /** |
218 | * move_addr_to_kernel - copy a socket address into kernel space | 174 | * move_addr_to_kernel - copy a socket address into kernel space |
219 | * @uaddr: Address in user space | 175 | * @uaddr: Address in user space |
@@ -227,11 +183,11 @@ static DEFINE_PER_CPU(int, sockets_in_use) = 0; | |||
227 | 183 | ||
228 | int move_addr_to_kernel(void __user *uaddr, int ulen, void *kaddr) | 184 | int move_addr_to_kernel(void __user *uaddr, int ulen, void *kaddr) |
229 | { | 185 | { |
230 | if(ulen<0||ulen>MAX_SOCK_ADDR) | 186 | if (ulen < 0 || ulen > MAX_SOCK_ADDR) |
231 | return -EINVAL; | 187 | return -EINVAL; |
232 | if(ulen==0) | 188 | if (ulen == 0) |
233 | return 0; | 189 | return 0; |
234 | if(copy_from_user(kaddr,uaddr,ulen)) | 190 | if (copy_from_user(kaddr, uaddr, ulen)) |
235 | return -EFAULT; | 191 | return -EFAULT; |
236 | return audit_sockaddr(ulen, kaddr); | 192 | return audit_sockaddr(ulen, kaddr); |
237 | } | 193 | } |
@@ -252,51 +208,52 @@ int move_addr_to_kernel(void __user *uaddr, int ulen, void *kaddr) | |||
252 | * length of the data is written over the length limit the user | 208 | * length of the data is written over the length limit the user |
253 | * specified. Zero is returned for a success. | 209 | * specified. Zero is returned for a success. |
254 | */ | 210 | */ |
255 | 211 | ||
256 | int move_addr_to_user(void *kaddr, int klen, void __user *uaddr, int __user *ulen) | 212 | int move_addr_to_user(void *kaddr, int klen, void __user *uaddr, |
213 | int __user *ulen) | ||
257 | { | 214 | { |
258 | int err; | 215 | int err; |
259 | int len; | 216 | int len; |
260 | 217 | ||
261 | if((err=get_user(len, ulen))) | 218 | err = get_user(len, ulen); |
219 | if (err) | ||
262 | return err; | 220 | return err; |
263 | if(len>klen) | 221 | if (len > klen) |
264 | len=klen; | 222 | len = klen; |
265 | if(len<0 || len> MAX_SOCK_ADDR) | 223 | if (len < 0 || len > MAX_SOCK_ADDR) |
266 | return -EINVAL; | 224 | return -EINVAL; |
267 | if(len) | 225 | if (len) { |
268 | { | ||
269 | if (audit_sockaddr(klen, kaddr)) | 226 | if (audit_sockaddr(klen, kaddr)) |
270 | return -ENOMEM; | 227 | return -ENOMEM; |
271 | if(copy_to_user(uaddr,kaddr,len)) | 228 | if (copy_to_user(uaddr, kaddr, len)) |
272 | return -EFAULT; | 229 | return -EFAULT; |
273 | } | 230 | } |
274 | /* | 231 | /* |
275 | * "fromlen shall refer to the value before truncation.." | 232 | * "fromlen shall refer to the value before truncation.." |
276 | * 1003.1g | 233 | * 1003.1g |
277 | */ | 234 | */ |
278 | return __put_user(klen, ulen); | 235 | return __put_user(klen, ulen); |
279 | } | 236 | } |
280 | 237 | ||
281 | #define SOCKFS_MAGIC 0x534F434B | 238 | #define SOCKFS_MAGIC 0x534F434B |
282 | 239 | ||
283 | static kmem_cache_t * sock_inode_cachep __read_mostly; | 240 | static kmem_cache_t *sock_inode_cachep __read_mostly; |
284 | 241 | ||
285 | static struct inode *sock_alloc_inode(struct super_block *sb) | 242 | static struct inode *sock_alloc_inode(struct super_block *sb) |
286 | { | 243 | { |
287 | struct socket_alloc *ei; | 244 | struct socket_alloc *ei; |
288 | ei = (struct socket_alloc *)kmem_cache_alloc(sock_inode_cachep, SLAB_KERNEL); | 245 | |
246 | ei = kmem_cache_alloc(sock_inode_cachep, SLAB_KERNEL); | ||
289 | if (!ei) | 247 | if (!ei) |
290 | return NULL; | 248 | return NULL; |
291 | init_waitqueue_head(&ei->socket.wait); | 249 | init_waitqueue_head(&ei->socket.wait); |
292 | 250 | ||
293 | ei->socket.fasync_list = NULL; | 251 | ei->socket.fasync_list = NULL; |
294 | ei->socket.state = SS_UNCONNECTED; | 252 | ei->socket.state = SS_UNCONNECTED; |
295 | ei->socket.flags = 0; | 253 | ei->socket.flags = 0; |
296 | ei->socket.ops = NULL; | 254 | ei->socket.ops = NULL; |
297 | ei->socket.sk = NULL; | 255 | ei->socket.sk = NULL; |
298 | ei->socket.file = NULL; | 256 | ei->socket.file = NULL; |
299 | ei->socket.flags = 0; | ||
300 | 257 | ||
301 | return &ei->vfs_inode; | 258 | return &ei->vfs_inode; |
302 | } | 259 | } |
@@ -307,22 +264,25 @@ static void sock_destroy_inode(struct inode *inode) | |||
307 | container_of(inode, struct socket_alloc, vfs_inode)); | 264 | container_of(inode, struct socket_alloc, vfs_inode)); |
308 | } | 265 | } |
309 | 266 | ||
310 | static void init_once(void * foo, kmem_cache_t * cachep, unsigned long flags) | 267 | static void init_once(void *foo, kmem_cache_t *cachep, unsigned long flags) |
311 | { | 268 | { |
312 | struct socket_alloc *ei = (struct socket_alloc *) foo; | 269 | struct socket_alloc *ei = (struct socket_alloc *)foo; |
313 | 270 | ||
314 | if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) == | 271 | if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) |
315 | SLAB_CTOR_CONSTRUCTOR) | 272 | == SLAB_CTOR_CONSTRUCTOR) |
316 | inode_init_once(&ei->vfs_inode); | 273 | inode_init_once(&ei->vfs_inode); |
317 | } | 274 | } |
318 | 275 | ||
319 | static int init_inodecache(void) | 276 | static int init_inodecache(void) |
320 | { | 277 | { |
321 | sock_inode_cachep = kmem_cache_create("sock_inode_cache", | 278 | sock_inode_cachep = kmem_cache_create("sock_inode_cache", |
322 | sizeof(struct socket_alloc), | 279 | sizeof(struct socket_alloc), |
323 | 0, (SLAB_HWCACHE_ALIGN|SLAB_RECLAIM_ACCOUNT| | 280 | 0, |
324 | SLAB_MEM_SPREAD), | 281 | (SLAB_HWCACHE_ALIGN | |
325 | init_once, NULL); | 282 | SLAB_RECLAIM_ACCOUNT | |
283 | SLAB_MEM_SPREAD), | ||
284 | init_once, | ||
285 | NULL); | ||
326 | if (sock_inode_cachep == NULL) | 286 | if (sock_inode_cachep == NULL) |
327 | return -ENOMEM; | 287 | return -ENOMEM; |
328 | return 0; | 288 | return 0; |
@@ -335,7 +295,8 @@ static struct super_operations sockfs_ops = { | |||
335 | }; | 295 | }; |
336 | 296 | ||
337 | static int sockfs_get_sb(struct file_system_type *fs_type, | 297 | static int sockfs_get_sb(struct file_system_type *fs_type, |
338 | int flags, const char *dev_name, void *data, struct vfsmount *mnt) | 298 | int flags, const char *dev_name, void *data, |
299 | struct vfsmount *mnt) | ||
339 | { | 300 | { |
340 | return get_sb_pseudo(fs_type, "socket:", &sockfs_ops, SOCKFS_MAGIC, | 301 | return get_sb_pseudo(fs_type, "socket:", &sockfs_ops, SOCKFS_MAGIC, |
341 | mnt); | 302 | mnt); |
@@ -348,12 +309,13 @@ static struct file_system_type sock_fs_type = { | |||
348 | .get_sb = sockfs_get_sb, | 309 | .get_sb = sockfs_get_sb, |
349 | .kill_sb = kill_anon_super, | 310 | .kill_sb = kill_anon_super, |
350 | }; | 311 | }; |
312 | |||
351 | static int sockfs_delete_dentry(struct dentry *dentry) | 313 | static int sockfs_delete_dentry(struct dentry *dentry) |
352 | { | 314 | { |
353 | return 1; | 315 | return 1; |
354 | } | 316 | } |
355 | static struct dentry_operations sockfs_dentry_operations = { | 317 | static struct dentry_operations sockfs_dentry_operations = { |
356 | .d_delete = sockfs_delete_dentry, | 318 | .d_delete = sockfs_delete_dentry, |
357 | }; | 319 | }; |
358 | 320 | ||
359 | /* | 321 | /* |
@@ -477,10 +439,12 @@ struct socket *sockfd_lookup(int fd, int *err) | |||
477 | struct file *file; | 439 | struct file *file; |
478 | struct socket *sock; | 440 | struct socket *sock; |
479 | 441 | ||
480 | if (!(file = fget(fd))) { | 442 | file = fget(fd); |
443 | if (!file) { | ||
481 | *err = -EBADF; | 444 | *err = -EBADF; |
482 | return NULL; | 445 | return NULL; |
483 | } | 446 | } |
447 | |||
484 | sock = sock_from_file(file, err); | 448 | sock = sock_from_file(file, err); |
485 | if (!sock) | 449 | if (!sock) |
486 | fput(file); | 450 | fput(file); |
@@ -505,7 +469,7 @@ static struct socket *sockfd_lookup_light(int fd, int *err, int *fput_needed) | |||
505 | 469 | ||
506 | /** | 470 | /** |
507 | * sock_alloc - allocate a socket | 471 | * sock_alloc - allocate a socket |
508 | * | 472 | * |
509 | * Allocate a new inode and socket object. The two are bound together | 473 | * Allocate a new inode and socket object. The two are bound together |
510 | * and initialised. The socket is then returned. If we are out of inodes | 474 | * and initialised. The socket is then returned. If we are out of inodes |
511 | * NULL is returned. | 475 | * NULL is returned. |
@@ -513,8 +477,8 @@ static struct socket *sockfd_lookup_light(int fd, int *err, int *fput_needed) | |||
513 | 477 | ||
514 | static struct socket *sock_alloc(void) | 478 | static struct socket *sock_alloc(void) |
515 | { | 479 | { |
516 | struct inode * inode; | 480 | struct inode *inode; |
517 | struct socket * sock; | 481 | struct socket *sock; |
518 | 482 | ||
519 | inode = new_inode(sock_mnt->mnt_sb); | 483 | inode = new_inode(sock_mnt->mnt_sb); |
520 | if (!inode) | 484 | if (!inode) |
@@ -522,7 +486,7 @@ static struct socket *sock_alloc(void) | |||
522 | 486 | ||
523 | sock = SOCKET_I(inode); | 487 | sock = SOCKET_I(inode); |
524 | 488 | ||
525 | inode->i_mode = S_IFSOCK|S_IRWXUGO; | 489 | inode->i_mode = S_IFSOCK | S_IRWXUGO; |
526 | inode->i_uid = current->fsuid; | 490 | inode->i_uid = current->fsuid; |
527 | inode->i_gid = current->fsgid; | 491 | inode->i_gid = current->fsgid; |
528 | 492 | ||
@@ -536,7 +500,7 @@ static struct socket *sock_alloc(void) | |||
536 | * a back door. Remember to keep it shut otherwise you'll let the | 500 | * a back door. Remember to keep it shut otherwise you'll let the |
537 | * creepy crawlies in. | 501 | * creepy crawlies in. |
538 | */ | 502 | */ |
539 | 503 | ||
540 | static int sock_no_open(struct inode *irrelevant, struct file *dontcare) | 504 | static int sock_no_open(struct inode *irrelevant, struct file *dontcare) |
541 | { | 505 | { |
542 | return -ENXIO; | 506 | return -ENXIO; |
@@ -553,9 +517,9 @@ const struct file_operations bad_sock_fops = { | |||
553 | * | 517 | * |
554 | * The socket is released from the protocol stack if it has a release | 518 | * The socket is released from the protocol stack if it has a release |
555 | * callback, and the inode is then released if the socket is bound to | 519 | * callback, and the inode is then released if the socket is bound to |
556 | * an inode not a file. | 520 | * an inode not a file. |
557 | */ | 521 | */ |
558 | 522 | ||
559 | void sock_release(struct socket *sock) | 523 | void sock_release(struct socket *sock) |
560 | { | 524 | { |
561 | if (sock->ops) { | 525 | if (sock->ops) { |
@@ -575,10 +539,10 @@ void sock_release(struct socket *sock) | |||
575 | iput(SOCK_INODE(sock)); | 539 | iput(SOCK_INODE(sock)); |
576 | return; | 540 | return; |
577 | } | 541 | } |
578 | sock->file=NULL; | 542 | sock->file = NULL; |
579 | } | 543 | } |
580 | 544 | ||
581 | static inline int __sock_sendmsg(struct kiocb *iocb, struct socket *sock, | 545 | static inline int __sock_sendmsg(struct kiocb *iocb, struct socket *sock, |
582 | struct msghdr *msg, size_t size) | 546 | struct msghdr *msg, size_t size) |
583 | { | 547 | { |
584 | struct sock_iocb *si = kiocb_to_siocb(iocb); | 548 | struct sock_iocb *si = kiocb_to_siocb(iocb); |
@@ -621,14 +585,14 @@ int kernel_sendmsg(struct socket *sock, struct msghdr *msg, | |||
621 | * the following is safe, since for compiler definitions of kvec and | 585 | * the following is safe, since for compiler definitions of kvec and |
622 | * iovec are identical, yielding the same in-core layout and alignment | 586 | * iovec are identical, yielding the same in-core layout and alignment |
623 | */ | 587 | */ |
624 | msg->msg_iov = (struct iovec *)vec, | 588 | msg->msg_iov = (struct iovec *)vec; |
625 | msg->msg_iovlen = num; | 589 | msg->msg_iovlen = num; |
626 | result = sock_sendmsg(sock, msg, size); | 590 | result = sock_sendmsg(sock, msg, size); |
627 | set_fs(oldfs); | 591 | set_fs(oldfs); |
628 | return result; | 592 | return result; |
629 | } | 593 | } |
630 | 594 | ||
631 | static inline int __sock_recvmsg(struct kiocb *iocb, struct socket *sock, | 595 | static inline int __sock_recvmsg(struct kiocb *iocb, struct socket *sock, |
632 | struct msghdr *msg, size_t size, int flags) | 596 | struct msghdr *msg, size_t size, int flags) |
633 | { | 597 | { |
634 | int err; | 598 | int err; |
@@ -647,14 +611,14 @@ static inline int __sock_recvmsg(struct kiocb *iocb, struct socket *sock, | |||
647 | return sock->ops->recvmsg(iocb, sock, msg, size, flags); | 611 | return sock->ops->recvmsg(iocb, sock, msg, size, flags); |
648 | } | 612 | } |
649 | 613 | ||
650 | int sock_recvmsg(struct socket *sock, struct msghdr *msg, | 614 | int sock_recvmsg(struct socket *sock, struct msghdr *msg, |
651 | size_t size, int flags) | 615 | size_t size, int flags) |
652 | { | 616 | { |
653 | struct kiocb iocb; | 617 | struct kiocb iocb; |
654 | struct sock_iocb siocb; | 618 | struct sock_iocb siocb; |
655 | int ret; | 619 | int ret; |
656 | 620 | ||
657 | init_sync_kiocb(&iocb, NULL); | 621 | init_sync_kiocb(&iocb, NULL); |
658 | iocb.private = &siocb; | 622 | iocb.private = &siocb; |
659 | ret = __sock_recvmsg(&iocb, sock, msg, size, flags); | 623 | ret = __sock_recvmsg(&iocb, sock, msg, size, flags); |
660 | if (-EIOCBQUEUED == ret) | 624 | if (-EIOCBQUEUED == ret) |
@@ -662,9 +626,8 @@ int sock_recvmsg(struct socket *sock, struct msghdr *msg, | |||
662 | return ret; | 626 | return ret; |
663 | } | 627 | } |
664 | 628 | ||
665 | int kernel_recvmsg(struct socket *sock, struct msghdr *msg, | 629 | int kernel_recvmsg(struct socket *sock, struct msghdr *msg, |
666 | struct kvec *vec, size_t num, | 630 | struct kvec *vec, size_t num, size_t size, int flags) |
667 | size_t size, int flags) | ||
668 | { | 631 | { |
669 | mm_segment_t oldfs = get_fs(); | 632 | mm_segment_t oldfs = get_fs(); |
670 | int result; | 633 | int result; |
@@ -674,8 +637,7 @@ int kernel_recvmsg(struct socket *sock, struct msghdr *msg, | |||
674 | * the following is safe, since for compiler definitions of kvec and | 637 | * the following is safe, since for compiler definitions of kvec and |
675 | * iovec are identical, yielding the same in-core layout and alignment | 638 | * iovec are identical, yielding the same in-core layout and alignment |
676 | */ | 639 | */ |
677 | msg->msg_iov = (struct iovec *)vec, | 640 | msg->msg_iov = (struct iovec *)vec, msg->msg_iovlen = num; |
678 | msg->msg_iovlen = num; | ||
679 | result = sock_recvmsg(sock, msg, size, flags); | 641 | result = sock_recvmsg(sock, msg, size, flags); |
680 | set_fs(oldfs); | 642 | set_fs(oldfs); |
681 | return result; | 643 | return result; |
@@ -702,7 +664,8 @@ static ssize_t sock_sendpage(struct file *file, struct page *page, | |||
702 | } | 664 | } |
703 | 665 | ||
704 | static struct sock_iocb *alloc_sock_iocb(struct kiocb *iocb, | 666 | static struct sock_iocb *alloc_sock_iocb(struct kiocb *iocb, |
705 | char __user *ubuf, size_t size, struct sock_iocb *siocb) | 667 | char __user *ubuf, size_t size, |
668 | struct sock_iocb *siocb) | ||
706 | { | 669 | { |
707 | if (!is_sync_kiocb(iocb)) { | 670 | if (!is_sync_kiocb(iocb)) { |
708 | siocb = kmalloc(sizeof(*siocb), GFP_KERNEL); | 671 | siocb = kmalloc(sizeof(*siocb), GFP_KERNEL); |
@@ -720,20 +683,21 @@ static struct sock_iocb *alloc_sock_iocb(struct kiocb *iocb, | |||
720 | } | 683 | } |
721 | 684 | ||
722 | static ssize_t do_sock_read(struct msghdr *msg, struct kiocb *iocb, | 685 | static ssize_t do_sock_read(struct msghdr *msg, struct kiocb *iocb, |
723 | struct file *file, struct iovec *iov, unsigned long nr_segs) | 686 | struct file *file, struct iovec *iov, |
687 | unsigned long nr_segs) | ||
724 | { | 688 | { |
725 | struct socket *sock = file->private_data; | 689 | struct socket *sock = file->private_data; |
726 | size_t size = 0; | 690 | size_t size = 0; |
727 | int i; | 691 | int i; |
728 | 692 | ||
729 | for (i = 0 ; i < nr_segs ; i++) | 693 | for (i = 0; i < nr_segs; i++) |
730 | size += iov[i].iov_len; | 694 | size += iov[i].iov_len; |
731 | 695 | ||
732 | msg->msg_name = NULL; | 696 | msg->msg_name = NULL; |
733 | msg->msg_namelen = 0; | 697 | msg->msg_namelen = 0; |
734 | msg->msg_control = NULL; | 698 | msg->msg_control = NULL; |
735 | msg->msg_controllen = 0; | 699 | msg->msg_controllen = 0; |
736 | msg->msg_iov = (struct iovec *) iov; | 700 | msg->msg_iov = (struct iovec *)iov; |
737 | msg->msg_iovlen = nr_segs; | 701 | msg->msg_iovlen = nr_segs; |
738 | msg->msg_flags = (file->f_flags & O_NONBLOCK) ? MSG_DONTWAIT : 0; | 702 | msg->msg_flags = (file->f_flags & O_NONBLOCK) ? MSG_DONTWAIT : 0; |
739 | 703 | ||
@@ -748,7 +712,7 @@ static ssize_t sock_readv(struct file *file, const struct iovec *iov, | |||
748 | struct msghdr msg; | 712 | struct msghdr msg; |
749 | int ret; | 713 | int ret; |
750 | 714 | ||
751 | init_sync_kiocb(&iocb, NULL); | 715 | init_sync_kiocb(&iocb, NULL); |
752 | iocb.private = &siocb; | 716 | iocb.private = &siocb; |
753 | 717 | ||
754 | ret = do_sock_read(&msg, &iocb, file, (struct iovec *)iov, nr_segs); | 718 | ret = do_sock_read(&msg, &iocb, file, (struct iovec *)iov, nr_segs); |
@@ -758,7 +722,7 @@ static ssize_t sock_readv(struct file *file, const struct iovec *iov, | |||
758 | } | 722 | } |
759 | 723 | ||
760 | static ssize_t sock_aio_read(struct kiocb *iocb, char __user *ubuf, | 724 | static ssize_t sock_aio_read(struct kiocb *iocb, char __user *ubuf, |
761 | size_t count, loff_t pos) | 725 | size_t count, loff_t pos) |
762 | { | 726 | { |
763 | struct sock_iocb siocb, *x; | 727 | struct sock_iocb siocb, *x; |
764 | 728 | ||
@@ -771,24 +735,25 @@ static ssize_t sock_aio_read(struct kiocb *iocb, char __user *ubuf, | |||
771 | if (!x) | 735 | if (!x) |
772 | return -ENOMEM; | 736 | return -ENOMEM; |
773 | return do_sock_read(&x->async_msg, iocb, iocb->ki_filp, | 737 | return do_sock_read(&x->async_msg, iocb, iocb->ki_filp, |
774 | &x->async_iov, 1); | 738 | &x->async_iov, 1); |
775 | } | 739 | } |
776 | 740 | ||
777 | static ssize_t do_sock_write(struct msghdr *msg, struct kiocb *iocb, | 741 | static ssize_t do_sock_write(struct msghdr *msg, struct kiocb *iocb, |
778 | struct file *file, struct iovec *iov, unsigned long nr_segs) | 742 | struct file *file, struct iovec *iov, |
743 | unsigned long nr_segs) | ||
779 | { | 744 | { |
780 | struct socket *sock = file->private_data; | 745 | struct socket *sock = file->private_data; |
781 | size_t size = 0; | 746 | size_t size = 0; |
782 | int i; | 747 | int i; |
783 | 748 | ||
784 | for (i = 0 ; i < nr_segs ; i++) | 749 | for (i = 0; i < nr_segs; i++) |
785 | size += iov[i].iov_len; | 750 | size += iov[i].iov_len; |
786 | 751 | ||
787 | msg->msg_name = NULL; | 752 | msg->msg_name = NULL; |
788 | msg->msg_namelen = 0; | 753 | msg->msg_namelen = 0; |
789 | msg->msg_control = NULL; | 754 | msg->msg_control = NULL; |
790 | msg->msg_controllen = 0; | 755 | msg->msg_controllen = 0; |
791 | msg->msg_iov = (struct iovec *) iov; | 756 | msg->msg_iov = (struct iovec *)iov; |
792 | msg->msg_iovlen = nr_segs; | 757 | msg->msg_iovlen = nr_segs; |
793 | msg->msg_flags = (file->f_flags & O_NONBLOCK) ? MSG_DONTWAIT : 0; | 758 | msg->msg_flags = (file->f_flags & O_NONBLOCK) ? MSG_DONTWAIT : 0; |
794 | if (sock->type == SOCK_SEQPACKET) | 759 | if (sock->type == SOCK_SEQPACKET) |
@@ -815,7 +780,7 @@ static ssize_t sock_writev(struct file *file, const struct iovec *iov, | |||
815 | } | 780 | } |
816 | 781 | ||
817 | static ssize_t sock_aio_write(struct kiocb *iocb, const char __user *ubuf, | 782 | static ssize_t sock_aio_write(struct kiocb *iocb, const char __user *ubuf, |
818 | size_t count, loff_t pos) | 783 | size_t count, loff_t pos) |
819 | { | 784 | { |
820 | struct sock_iocb siocb, *x; | 785 | struct sock_iocb siocb, *x; |
821 | 786 | ||
@@ -829,46 +794,48 @@ static ssize_t sock_aio_write(struct kiocb *iocb, const char __user *ubuf, | |||
829 | return -ENOMEM; | 794 | return -ENOMEM; |
830 | 795 | ||
831 | return do_sock_write(&x->async_msg, iocb, iocb->ki_filp, | 796 | return do_sock_write(&x->async_msg, iocb, iocb->ki_filp, |
832 | &x->async_iov, 1); | 797 | &x->async_iov, 1); |
833 | } | 798 | } |
834 | 799 | ||
835 | |||
836 | /* | 800 | /* |
837 | * Atomic setting of ioctl hooks to avoid race | 801 | * Atomic setting of ioctl hooks to avoid race |
838 | * with module unload. | 802 | * with module unload. |
839 | */ | 803 | */ |
840 | 804 | ||
841 | static DEFINE_MUTEX(br_ioctl_mutex); | 805 | static DEFINE_MUTEX(br_ioctl_mutex); |
842 | static int (*br_ioctl_hook)(unsigned int cmd, void __user *arg) = NULL; | 806 | static int (*br_ioctl_hook) (unsigned int cmd, void __user *arg) = NULL; |
843 | 807 | ||
844 | void brioctl_set(int (*hook)(unsigned int, void __user *)) | 808 | void brioctl_set(int (*hook) (unsigned int, void __user *)) |
845 | { | 809 | { |
846 | mutex_lock(&br_ioctl_mutex); | 810 | mutex_lock(&br_ioctl_mutex); |
847 | br_ioctl_hook = hook; | 811 | br_ioctl_hook = hook; |
848 | mutex_unlock(&br_ioctl_mutex); | 812 | mutex_unlock(&br_ioctl_mutex); |
849 | } | 813 | } |
814 | |||
850 | EXPORT_SYMBOL(brioctl_set); | 815 | EXPORT_SYMBOL(brioctl_set); |
851 | 816 | ||
852 | static DEFINE_MUTEX(vlan_ioctl_mutex); | 817 | static DEFINE_MUTEX(vlan_ioctl_mutex); |
853 | static int (*vlan_ioctl_hook)(void __user *arg); | 818 | static int (*vlan_ioctl_hook) (void __user *arg); |
854 | 819 | ||
855 | void vlan_ioctl_set(int (*hook)(void __user *)) | 820 | void vlan_ioctl_set(int (*hook) (void __user *)) |
856 | { | 821 | { |
857 | mutex_lock(&vlan_ioctl_mutex); | 822 | mutex_lock(&vlan_ioctl_mutex); |
858 | vlan_ioctl_hook = hook; | 823 | vlan_ioctl_hook = hook; |
859 | mutex_unlock(&vlan_ioctl_mutex); | 824 | mutex_unlock(&vlan_ioctl_mutex); |
860 | } | 825 | } |
826 | |||
861 | EXPORT_SYMBOL(vlan_ioctl_set); | 827 | EXPORT_SYMBOL(vlan_ioctl_set); |
862 | 828 | ||
863 | static DEFINE_MUTEX(dlci_ioctl_mutex); | 829 | static DEFINE_MUTEX(dlci_ioctl_mutex); |
864 | static int (*dlci_ioctl_hook)(unsigned int, void __user *); | 830 | static int (*dlci_ioctl_hook) (unsigned int, void __user *); |
865 | 831 | ||
866 | void dlci_ioctl_set(int (*hook)(unsigned int, void __user *)) | 832 | void dlci_ioctl_set(int (*hook) (unsigned int, void __user *)) |
867 | { | 833 | { |
868 | mutex_lock(&dlci_ioctl_mutex); | 834 | mutex_lock(&dlci_ioctl_mutex); |
869 | dlci_ioctl_hook = hook; | 835 | dlci_ioctl_hook = hook; |
870 | mutex_unlock(&dlci_ioctl_mutex); | 836 | mutex_unlock(&dlci_ioctl_mutex); |
871 | } | 837 | } |
838 | |||
872 | EXPORT_SYMBOL(dlci_ioctl_set); | 839 | EXPORT_SYMBOL(dlci_ioctl_set); |
873 | 840 | ||
874 | /* | 841 | /* |
@@ -890,8 +857,8 @@ static long sock_ioctl(struct file *file, unsigned cmd, unsigned long arg) | |||
890 | if (cmd >= SIOCIWFIRST && cmd <= SIOCIWLAST) { | 857 | if (cmd >= SIOCIWFIRST && cmd <= SIOCIWLAST) { |
891 | err = dev_ioctl(cmd, argp); | 858 | err = dev_ioctl(cmd, argp); |
892 | } else | 859 | } else |
893 | #endif /* CONFIG_WIRELESS_EXT */ | 860 | #endif /* CONFIG_WIRELESS_EXT */ |
894 | switch (cmd) { | 861 | switch (cmd) { |
895 | case FIOSETOWN: | 862 | case FIOSETOWN: |
896 | case SIOCSPGRP: | 863 | case SIOCSPGRP: |
897 | err = -EFAULT; | 864 | err = -EFAULT; |
@@ -901,7 +868,8 @@ static long sock_ioctl(struct file *file, unsigned cmd, unsigned long arg) | |||
901 | break; | 868 | break; |
902 | case FIOGETOWN: | 869 | case FIOGETOWN: |
903 | case SIOCGPGRP: | 870 | case SIOCGPGRP: |
904 | err = put_user(sock->file->f_owner.pid, (int __user *)argp); | 871 | err = put_user(sock->file->f_owner.pid, |
872 | (int __user *)argp); | ||
905 | break; | 873 | break; |
906 | case SIOCGIFBR: | 874 | case SIOCGIFBR: |
907 | case SIOCSIFBR: | 875 | case SIOCSIFBR: |
@@ -912,7 +880,7 @@ static long sock_ioctl(struct file *file, unsigned cmd, unsigned long arg) | |||
912 | request_module("bridge"); | 880 | request_module("bridge"); |
913 | 881 | ||
914 | mutex_lock(&br_ioctl_mutex); | 882 | mutex_lock(&br_ioctl_mutex); |
915 | if (br_ioctl_hook) | 883 | if (br_ioctl_hook) |
916 | err = br_ioctl_hook(cmd, argp); | 884 | err = br_ioctl_hook(cmd, argp); |
917 | mutex_unlock(&br_ioctl_mutex); | 885 | mutex_unlock(&br_ioctl_mutex); |
918 | break; | 886 | break; |
@@ -929,7 +897,7 @@ static long sock_ioctl(struct file *file, unsigned cmd, unsigned long arg) | |||
929 | break; | 897 | break; |
930 | case SIOCGIFDIVERT: | 898 | case SIOCGIFDIVERT: |
931 | case SIOCSIFDIVERT: | 899 | case SIOCSIFDIVERT: |
932 | /* Convert this to call through a hook */ | 900 | /* Convert this to call through a hook */ |
933 | err = divert_ioctl(cmd, argp); | 901 | err = divert_ioctl(cmd, argp); |
934 | break; | 902 | break; |
935 | case SIOCADDDLCI: | 903 | case SIOCADDDLCI: |
@@ -954,7 +922,7 @@ static long sock_ioctl(struct file *file, unsigned cmd, unsigned long arg) | |||
954 | if (err == -ENOIOCTLCMD) | 922 | if (err == -ENOIOCTLCMD) |
955 | err = dev_ioctl(cmd, argp); | 923 | err = dev_ioctl(cmd, argp); |
956 | break; | 924 | break; |
957 | } | 925 | } |
958 | return err; | 926 | return err; |
959 | } | 927 | } |
960 | 928 | ||
@@ -962,7 +930,7 @@ int sock_create_lite(int family, int type, int protocol, struct socket **res) | |||
962 | { | 930 | { |
963 | int err; | 931 | int err; |
964 | struct socket *sock = NULL; | 932 | struct socket *sock = NULL; |
965 | 933 | ||
966 | err = security_socket_create(family, type, protocol, 1); | 934 | err = security_socket_create(family, type, protocol, 1); |
967 | if (err) | 935 | if (err) |
968 | goto out; | 936 | goto out; |
@@ -973,26 +941,33 @@ int sock_create_lite(int family, int type, int protocol, struct socket **res) | |||
973 | goto out; | 941 | goto out; |
974 | } | 942 | } |
975 | 943 | ||
976 | security_socket_post_create(sock, family, type, protocol, 1); | ||
977 | sock->type = type; | 944 | sock->type = type; |
945 | err = security_socket_post_create(sock, family, type, protocol, 1); | ||
946 | if (err) | ||
947 | goto out_release; | ||
948 | |||
978 | out: | 949 | out: |
979 | *res = sock; | 950 | *res = sock; |
980 | return err; | 951 | return err; |
952 | out_release: | ||
953 | sock_release(sock); | ||
954 | sock = NULL; | ||
955 | goto out; | ||
981 | } | 956 | } |
982 | 957 | ||
983 | /* No kernel lock held - perfect */ | 958 | /* No kernel lock held - perfect */ |
984 | static unsigned int sock_poll(struct file *file, poll_table * wait) | 959 | static unsigned int sock_poll(struct file *file, poll_table *wait) |
985 | { | 960 | { |
986 | struct socket *sock; | 961 | struct socket *sock; |
987 | 962 | ||
988 | /* | 963 | /* |
989 | * We can't return errors to poll, so it's either yes or no. | 964 | * We can't return errors to poll, so it's either yes or no. |
990 | */ | 965 | */ |
991 | sock = file->private_data; | 966 | sock = file->private_data; |
992 | return sock->ops->poll(file, sock, wait); | 967 | return sock->ops->poll(file, sock, wait); |
993 | } | 968 | } |
994 | 969 | ||
995 | static int sock_mmap(struct file * file, struct vm_area_struct * vma) | 970 | static int sock_mmap(struct file *file, struct vm_area_struct *vma) |
996 | { | 971 | { |
997 | struct socket *sock = file->private_data; | 972 | struct socket *sock = file->private_data; |
998 | 973 | ||
@@ -1002,12 +977,11 @@ static int sock_mmap(struct file * file, struct vm_area_struct * vma) | |||
1002 | static int sock_close(struct inode *inode, struct file *filp) | 977 | static int sock_close(struct inode *inode, struct file *filp) |
1003 | { | 978 | { |
1004 | /* | 979 | /* |
1005 | * It was possible the inode is NULL we were | 980 | * It was possible the inode is NULL we were |
1006 | * closing an unfinished socket. | 981 | * closing an unfinished socket. |
1007 | */ | 982 | */ |
1008 | 983 | ||
1009 | if (!inode) | 984 | if (!inode) { |
1010 | { | ||
1011 | printk(KERN_DEBUG "sock_close: NULL inode\n"); | 985 | printk(KERN_DEBUG "sock_close: NULL inode\n"); |
1012 | return 0; | 986 | return 0; |
1013 | } | 987 | } |
@@ -1033,57 +1007,52 @@ static int sock_close(struct inode *inode, struct file *filp) | |||
1033 | 1007 | ||
1034 | static int sock_fasync(int fd, struct file *filp, int on) | 1008 | static int sock_fasync(int fd, struct file *filp, int on) |
1035 | { | 1009 | { |
1036 | struct fasync_struct *fa, *fna=NULL, **prev; | 1010 | struct fasync_struct *fa, *fna = NULL, **prev; |
1037 | struct socket *sock; | 1011 | struct socket *sock; |
1038 | struct sock *sk; | 1012 | struct sock *sk; |
1039 | 1013 | ||
1040 | if (on) | 1014 | if (on) { |
1041 | { | ||
1042 | fna = kmalloc(sizeof(struct fasync_struct), GFP_KERNEL); | 1015 | fna = kmalloc(sizeof(struct fasync_struct), GFP_KERNEL); |
1043 | if(fna==NULL) | 1016 | if (fna == NULL) |
1044 | return -ENOMEM; | 1017 | return -ENOMEM; |
1045 | } | 1018 | } |
1046 | 1019 | ||
1047 | sock = filp->private_data; | 1020 | sock = filp->private_data; |
1048 | 1021 | ||
1049 | if ((sk=sock->sk) == NULL) { | 1022 | sk = sock->sk; |
1023 | if (sk == NULL) { | ||
1050 | kfree(fna); | 1024 | kfree(fna); |
1051 | return -EINVAL; | 1025 | return -EINVAL; |
1052 | } | 1026 | } |
1053 | 1027 | ||
1054 | lock_sock(sk); | 1028 | lock_sock(sk); |
1055 | 1029 | ||
1056 | prev=&(sock->fasync_list); | 1030 | prev = &(sock->fasync_list); |
1057 | 1031 | ||
1058 | for (fa=*prev; fa!=NULL; prev=&fa->fa_next,fa=*prev) | 1032 | for (fa = *prev; fa != NULL; prev = &fa->fa_next, fa = *prev) |
1059 | if (fa->fa_file==filp) | 1033 | if (fa->fa_file == filp) |
1060 | break; | 1034 | break; |
1061 | 1035 | ||
1062 | if(on) | 1036 | if (on) { |
1063 | { | 1037 | if (fa != NULL) { |
1064 | if(fa!=NULL) | ||
1065 | { | ||
1066 | write_lock_bh(&sk->sk_callback_lock); | 1038 | write_lock_bh(&sk->sk_callback_lock); |
1067 | fa->fa_fd=fd; | 1039 | fa->fa_fd = fd; |
1068 | write_unlock_bh(&sk->sk_callback_lock); | 1040 | write_unlock_bh(&sk->sk_callback_lock); |
1069 | 1041 | ||
1070 | kfree(fna); | 1042 | kfree(fna); |
1071 | goto out; | 1043 | goto out; |
1072 | } | 1044 | } |
1073 | fna->fa_file=filp; | 1045 | fna->fa_file = filp; |
1074 | fna->fa_fd=fd; | 1046 | fna->fa_fd = fd; |
1075 | fna->magic=FASYNC_MAGIC; | 1047 | fna->magic = FASYNC_MAGIC; |
1076 | fna->fa_next=sock->fasync_list; | 1048 | fna->fa_next = sock->fasync_list; |
1077 | write_lock_bh(&sk->sk_callback_lock); | 1049 | write_lock_bh(&sk->sk_callback_lock); |
1078 | sock->fasync_list=fna; | 1050 | sock->fasync_list = fna; |
1079 | write_unlock_bh(&sk->sk_callback_lock); | 1051 | write_unlock_bh(&sk->sk_callback_lock); |
1080 | } | 1052 | } else { |
1081 | else | 1053 | if (fa != NULL) { |
1082 | { | ||
1083 | if (fa!=NULL) | ||
1084 | { | ||
1085 | write_lock_bh(&sk->sk_callback_lock); | 1054 | write_lock_bh(&sk->sk_callback_lock); |
1086 | *prev=fa->fa_next; | 1055 | *prev = fa->fa_next; |
1087 | write_unlock_bh(&sk->sk_callback_lock); | 1056 | write_unlock_bh(&sk->sk_callback_lock); |
1088 | kfree(fa); | 1057 | kfree(fa); |
1089 | } | 1058 | } |
@@ -1100,10 +1069,9 @@ int sock_wake_async(struct socket *sock, int how, int band) | |||
1100 | { | 1069 | { |
1101 | if (!sock || !sock->fasync_list) | 1070 | if (!sock || !sock->fasync_list) |
1102 | return -1; | 1071 | return -1; |
1103 | switch (how) | 1072 | switch (how) { |
1104 | { | ||
1105 | case 1: | 1073 | case 1: |
1106 | 1074 | ||
1107 | if (test_bit(SOCK_ASYNC_WAITDATA, &sock->flags)) | 1075 | if (test_bit(SOCK_ASYNC_WAITDATA, &sock->flags)) |
1108 | break; | 1076 | break; |
1109 | goto call_kill; | 1077 | goto call_kill; |
@@ -1112,7 +1080,7 @@ int sock_wake_async(struct socket *sock, int how, int band) | |||
1112 | break; | 1080 | break; |
1113 | /* fall through */ | 1081 | /* fall through */ |
1114 | case 0: | 1082 | case 0: |
1115 | call_kill: | 1083 | call_kill: |
1116 | __kill_fasync(sock->fasync_list, SIGIO, band); | 1084 | __kill_fasync(sock->fasync_list, SIGIO, band); |
1117 | break; | 1085 | break; |
1118 | case 3: | 1086 | case 3: |
@@ -1121,13 +1089,15 @@ int sock_wake_async(struct socket *sock, int how, int band) | |||
1121 | return 0; | 1089 | return 0; |
1122 | } | 1090 | } |
1123 | 1091 | ||
1124 | static int __sock_create(int family, int type, int protocol, struct socket **res, int kern) | 1092 | static int __sock_create(int family, int type, int protocol, |
1093 | struct socket **res, int kern) | ||
1125 | { | 1094 | { |
1126 | int err; | 1095 | int err; |
1127 | struct socket *sock; | 1096 | struct socket *sock; |
1097 | const struct net_proto_family *pf; | ||
1128 | 1098 | ||
1129 | /* | 1099 | /* |
1130 | * Check protocol is in range | 1100 | * Check protocol is in range |
1131 | */ | 1101 | */ |
1132 | if (family < 0 || family >= NPROTO) | 1102 | if (family < 0 || family >= NPROTO) |
1133 | return -EAFNOSUPPORT; | 1103 | return -EAFNOSUPPORT; |
@@ -1140,10 +1110,11 @@ static int __sock_create(int family, int type, int protocol, struct socket **res | |||
1140 | deadlock in module load. | 1110 | deadlock in module load. |
1141 | */ | 1111 | */ |
1142 | if (family == PF_INET && type == SOCK_PACKET) { | 1112 | if (family == PF_INET && type == SOCK_PACKET) { |
1143 | static int warned; | 1113 | static int warned; |
1144 | if (!warned) { | 1114 | if (!warned) { |
1145 | warned = 1; | 1115 | warned = 1; |
1146 | printk(KERN_INFO "%s uses obsolete (PF_INET,SOCK_PACKET)\n", current->comm); | 1116 | printk(KERN_INFO "%s uses obsolete (PF_INET,SOCK_PACKET)\n", |
1117 | current->comm); | ||
1147 | } | 1118 | } |
1148 | family = PF_PACKET; | 1119 | family = PF_PACKET; |
1149 | } | 1120 | } |
@@ -1151,79 +1122,84 @@ static int __sock_create(int family, int type, int protocol, struct socket **res | |||
1151 | err = security_socket_create(family, type, protocol, kern); | 1122 | err = security_socket_create(family, type, protocol, kern); |
1152 | if (err) | 1123 | if (err) |
1153 | return err; | 1124 | return err; |
1154 | 1125 | ||
1126 | /* | ||
1127 | * Allocate the socket and allow the family to set things up. if | ||
1128 | * the protocol is 0, the family is instructed to select an appropriate | ||
1129 | * default. | ||
1130 | */ | ||
1131 | sock = sock_alloc(); | ||
1132 | if (!sock) { | ||
1133 | if (net_ratelimit()) | ||
1134 | printk(KERN_WARNING "socket: no more sockets\n"); | ||
1135 | return -ENFILE; /* Not exactly a match, but its the | ||
1136 | closest posix thing */ | ||
1137 | } | ||
1138 | |||
1139 | sock->type = type; | ||
1140 | |||
1155 | #if defined(CONFIG_KMOD) | 1141 | #if defined(CONFIG_KMOD) |
1156 | /* Attempt to load a protocol module if the find failed. | 1142 | /* Attempt to load a protocol module if the find failed. |
1157 | * | 1143 | * |
1158 | * 12/09/1996 Marcin: But! this makes REALLY only sense, if the user | 1144 | * 12/09/1996 Marcin: But! this makes REALLY only sense, if the user |
1159 | * requested real, full-featured networking support upon configuration. | 1145 | * requested real, full-featured networking support upon configuration. |
1160 | * Otherwise module support will break! | 1146 | * Otherwise module support will break! |
1161 | */ | 1147 | */ |
1162 | if (net_families[family]==NULL) | 1148 | if (net_families[family] == NULL) |
1163 | { | 1149 | request_module("net-pf-%d", family); |
1164 | request_module("net-pf-%d",family); | ||
1165 | } | ||
1166 | #endif | 1150 | #endif |
1167 | 1151 | ||
1168 | net_family_read_lock(); | 1152 | rcu_read_lock(); |
1169 | if (net_families[family] == NULL) { | 1153 | pf = rcu_dereference(net_families[family]); |
1170 | err = -EAFNOSUPPORT; | 1154 | err = -EAFNOSUPPORT; |
1171 | goto out; | 1155 | if (!pf) |
1172 | } | 1156 | goto out_release; |
1173 | |||
1174 | /* | ||
1175 | * Allocate the socket and allow the family to set things up. if | ||
1176 | * the protocol is 0, the family is instructed to select an appropriate | ||
1177 | * default. | ||
1178 | */ | ||
1179 | |||
1180 | if (!(sock = sock_alloc())) { | ||
1181 | if (net_ratelimit()) | ||
1182 | printk(KERN_WARNING "socket: no more sockets\n"); | ||
1183 | err = -ENFILE; /* Not exactly a match, but its the | ||
1184 | closest posix thing */ | ||
1185 | goto out; | ||
1186 | } | ||
1187 | |||
1188 | sock->type = type; | ||
1189 | 1157 | ||
1190 | /* | 1158 | /* |
1191 | * We will call the ->create function, that possibly is in a loadable | 1159 | * We will call the ->create function, that possibly is in a loadable |
1192 | * module, so we have to bump that loadable module refcnt first. | 1160 | * module, so we have to bump that loadable module refcnt first. |
1193 | */ | 1161 | */ |
1194 | err = -EAFNOSUPPORT; | 1162 | if (!try_module_get(pf->owner)) |
1195 | if (!try_module_get(net_families[family]->owner)) | ||
1196 | goto out_release; | 1163 | goto out_release; |
1197 | 1164 | ||
1198 | if ((err = net_families[family]->create(sock, protocol)) < 0) { | 1165 | /* Now protected by module ref count */ |
1199 | sock->ops = NULL; | 1166 | rcu_read_unlock(); |
1167 | |||
1168 | err = pf->create(sock, protocol); | ||
1169 | if (err < 0) | ||
1200 | goto out_module_put; | 1170 | goto out_module_put; |
1201 | } | ||
1202 | 1171 | ||
1203 | /* | 1172 | /* |
1204 | * Now to bump the refcnt of the [loadable] module that owns this | 1173 | * Now to bump the refcnt of the [loadable] module that owns this |
1205 | * socket at sock_release time we decrement its refcnt. | 1174 | * socket at sock_release time we decrement its refcnt. |
1206 | */ | 1175 | */ |
1207 | if (!try_module_get(sock->ops->owner)) { | 1176 | if (!try_module_get(sock->ops->owner)) |
1208 | sock->ops = NULL; | 1177 | goto out_module_busy; |
1209 | goto out_module_put; | 1178 | |
1210 | } | ||
1211 | /* | 1179 | /* |
1212 | * Now that we're done with the ->create function, the [loadable] | 1180 | * Now that we're done with the ->create function, the [loadable] |
1213 | * module can have its refcnt decremented | 1181 | * module can have its refcnt decremented |
1214 | */ | 1182 | */ |
1215 | module_put(net_families[family]->owner); | 1183 | module_put(pf->owner); |
1184 | err = security_socket_post_create(sock, family, type, protocol, kern); | ||
1185 | if (err) | ||
1186 | goto out_release; | ||
1216 | *res = sock; | 1187 | *res = sock; |
1217 | security_socket_post_create(sock, family, type, protocol, kern); | ||
1218 | 1188 | ||
1219 | out: | 1189 | return 0; |
1220 | net_family_read_unlock(); | 1190 | |
1221 | return err; | 1191 | out_module_busy: |
1192 | err = -EAFNOSUPPORT; | ||
1222 | out_module_put: | 1193 | out_module_put: |
1223 | module_put(net_families[family]->owner); | 1194 | sock->ops = NULL; |
1224 | out_release: | 1195 | module_put(pf->owner); |
1196 | out_sock_release: | ||
1225 | sock_release(sock); | 1197 | sock_release(sock); |
1226 | goto out; | 1198 | return err; |
1199 | |||
1200 | out_release: | ||
1201 | rcu_read_unlock(); | ||
1202 | goto out_sock_release; | ||
1227 | } | 1203 | } |
1228 | 1204 | ||
1229 | int sock_create(int family, int type, int protocol, struct socket **res) | 1205 | int sock_create(int family, int type, int protocol, struct socket **res) |
@@ -1262,7 +1238,8 @@ out_release: | |||
1262 | * Create a pair of connected sockets. | 1238 | * Create a pair of connected sockets. |
1263 | */ | 1239 | */ |
1264 | 1240 | ||
1265 | asmlinkage long sys_socketpair(int family, int type, int protocol, int __user *usockvec) | 1241 | asmlinkage long sys_socketpair(int family, int type, int protocol, |
1242 | int __user *usockvec) | ||
1266 | { | 1243 | { |
1267 | struct socket *sock1, *sock2; | 1244 | struct socket *sock1, *sock2; |
1268 | int fd1, fd2, err; | 1245 | int fd1, fd2, err; |
@@ -1281,7 +1258,7 @@ asmlinkage long sys_socketpair(int family, int type, int protocol, int __user *u | |||
1281 | goto out_release_1; | 1258 | goto out_release_1; |
1282 | 1259 | ||
1283 | err = sock1->ops->socketpair(sock1, sock2); | 1260 | err = sock1->ops->socketpair(sock1, sock2); |
1284 | if (err < 0) | 1261 | if (err < 0) |
1285 | goto out_release_both; | 1262 | goto out_release_both; |
1286 | 1263 | ||
1287 | fd1 = fd2 = -1; | 1264 | fd1 = fd2 = -1; |
@@ -1300,7 +1277,7 @@ asmlinkage long sys_socketpair(int family, int type, int protocol, int __user *u | |||
1300 | * Not kernel problem. | 1277 | * Not kernel problem. |
1301 | */ | 1278 | */ |
1302 | 1279 | ||
1303 | err = put_user(fd1, &usockvec[0]); | 1280 | err = put_user(fd1, &usockvec[0]); |
1304 | if (!err) | 1281 | if (!err) |
1305 | err = put_user(fd2, &usockvec[1]); | 1282 | err = put_user(fd2, &usockvec[1]); |
1306 | if (!err) | 1283 | if (!err) |
@@ -1311,19 +1288,18 @@ asmlinkage long sys_socketpair(int family, int type, int protocol, int __user *u | |||
1311 | return err; | 1288 | return err; |
1312 | 1289 | ||
1313 | out_close_1: | 1290 | out_close_1: |
1314 | sock_release(sock2); | 1291 | sock_release(sock2); |
1315 | sys_close(fd1); | 1292 | sys_close(fd1); |
1316 | return err; | 1293 | return err; |
1317 | 1294 | ||
1318 | out_release_both: | 1295 | out_release_both: |
1319 | sock_release(sock2); | 1296 | sock_release(sock2); |
1320 | out_release_1: | 1297 | out_release_1: |
1321 | sock_release(sock1); | 1298 | sock_release(sock1); |
1322 | out: | 1299 | out: |
1323 | return err; | 1300 | return err; |
1324 | } | 1301 | } |
1325 | 1302 | ||
1326 | |||
1327 | /* | 1303 | /* |
1328 | * Bind a name to a socket. Nothing much to do here since it's | 1304 | * Bind a name to a socket. Nothing much to do here since it's |
1329 | * the protocol's responsibility to handle the local address. | 1305 | * the protocol's responsibility to handle the local address. |
@@ -1338,35 +1314,39 @@ asmlinkage long sys_bind(int fd, struct sockaddr __user *umyaddr, int addrlen) | |||
1338 | char address[MAX_SOCK_ADDR]; | 1314 | char address[MAX_SOCK_ADDR]; |
1339 | int err, fput_needed; | 1315 | int err, fput_needed; |
1340 | 1316 | ||
1341 | if((sock = sockfd_lookup_light(fd, &err, &fput_needed))!=NULL) | 1317 | sock = sockfd_lookup_light(fd, &err, &fput_needed); |
1342 | { | 1318 | if(sock) { |
1343 | if((err=move_addr_to_kernel(umyaddr,addrlen,address))>=0) { | 1319 | err = move_addr_to_kernel(umyaddr, addrlen, address); |
1344 | err = security_socket_bind(sock, (struct sockaddr *)address, addrlen); | 1320 | if (err >= 0) { |
1321 | err = security_socket_bind(sock, | ||
1322 | (struct sockaddr *)address, | ||
1323 | addrlen); | ||
1345 | if (!err) | 1324 | if (!err) |
1346 | err = sock->ops->bind(sock, | 1325 | err = sock->ops->bind(sock, |
1347 | (struct sockaddr *)address, addrlen); | 1326 | (struct sockaddr *) |
1327 | address, addrlen); | ||
1348 | } | 1328 | } |
1349 | fput_light(sock->file, fput_needed); | 1329 | fput_light(sock->file, fput_needed); |
1350 | } | 1330 | } |
1351 | return err; | 1331 | return err; |
1352 | } | 1332 | } |
1353 | 1333 | ||
1354 | |||
1355 | /* | 1334 | /* |
1356 | * Perform a listen. Basically, we allow the protocol to do anything | 1335 | * Perform a listen. Basically, we allow the protocol to do anything |
1357 | * necessary for a listen, and if that works, we mark the socket as | 1336 | * necessary for a listen, and if that works, we mark the socket as |
1358 | * ready for listening. | 1337 | * ready for listening. |
1359 | */ | 1338 | */ |
1360 | 1339 | ||
1361 | int sysctl_somaxconn = SOMAXCONN; | 1340 | int sysctl_somaxconn __read_mostly = SOMAXCONN; |
1362 | 1341 | ||
1363 | asmlinkage long sys_listen(int fd, int backlog) | 1342 | asmlinkage long sys_listen(int fd, int backlog) |
1364 | { | 1343 | { |
1365 | struct socket *sock; | 1344 | struct socket *sock; |
1366 | int err, fput_needed; | 1345 | int err, fput_needed; |
1367 | 1346 | ||
1368 | if ((sock = sockfd_lookup_light(fd, &err, &fput_needed)) != NULL) { | 1347 | sock = sockfd_lookup_light(fd, &err, &fput_needed); |
1369 | if ((unsigned) backlog > sysctl_somaxconn) | 1348 | if (sock) { |
1349 | if ((unsigned)backlog > sysctl_somaxconn) | ||
1370 | backlog = sysctl_somaxconn; | 1350 | backlog = sysctl_somaxconn; |
1371 | 1351 | ||
1372 | err = security_socket_listen(sock, backlog); | 1352 | err = security_socket_listen(sock, backlog); |
@@ -1378,7 +1358,6 @@ asmlinkage long sys_listen(int fd, int backlog) | |||
1378 | return err; | 1358 | return err; |
1379 | } | 1359 | } |
1380 | 1360 | ||
1381 | |||
1382 | /* | 1361 | /* |
1383 | * For accept, we attempt to create a new socket, set up the link | 1362 | * For accept, we attempt to create a new socket, set up the link |
1384 | * with the client, wake up the client, then return the new | 1363 | * with the client, wake up the client, then return the new |
@@ -1391,7 +1370,8 @@ asmlinkage long sys_listen(int fd, int backlog) | |||
1391 | * clean when we restucture accept also. | 1370 | * clean when we restucture accept also. |
1392 | */ | 1371 | */ |
1393 | 1372 | ||
1394 | asmlinkage long sys_accept(int fd, struct sockaddr __user *upeer_sockaddr, int __user *upeer_addrlen) | 1373 | asmlinkage long sys_accept(int fd, struct sockaddr __user *upeer_sockaddr, |
1374 | int __user *upeer_addrlen) | ||
1395 | { | 1375 | { |
1396 | struct socket *sock, *newsock; | 1376 | struct socket *sock, *newsock; |
1397 | struct file *newfile; | 1377 | struct file *newfile; |
@@ -1403,7 +1383,7 @@ asmlinkage long sys_accept(int fd, struct sockaddr __user *upeer_sockaddr, int _ | |||
1403 | goto out; | 1383 | goto out; |
1404 | 1384 | ||
1405 | err = -ENFILE; | 1385 | err = -ENFILE; |
1406 | if (!(newsock = sock_alloc())) | 1386 | if (!(newsock = sock_alloc())) |
1407 | goto out_put; | 1387 | goto out_put; |
1408 | 1388 | ||
1409 | newsock->type = sock->type; | 1389 | newsock->type = sock->type; |
@@ -1435,11 +1415,13 @@ asmlinkage long sys_accept(int fd, struct sockaddr __user *upeer_sockaddr, int _ | |||
1435 | goto out_fd; | 1415 | goto out_fd; |
1436 | 1416 | ||
1437 | if (upeer_sockaddr) { | 1417 | if (upeer_sockaddr) { |
1438 | if(newsock->ops->getname(newsock, (struct sockaddr *)address, &len, 2)<0) { | 1418 | if (newsock->ops->getname(newsock, (struct sockaddr *)address, |
1419 | &len, 2) < 0) { | ||
1439 | err = -ECONNABORTED; | 1420 | err = -ECONNABORTED; |
1440 | goto out_fd; | 1421 | goto out_fd; |
1441 | } | 1422 | } |
1442 | err = move_addr_to_user(address, len, upeer_sockaddr, upeer_addrlen); | 1423 | err = move_addr_to_user(address, len, upeer_sockaddr, |
1424 | upeer_addrlen); | ||
1443 | if (err < 0) | 1425 | if (err < 0) |
1444 | goto out_fd; | 1426 | goto out_fd; |
1445 | } | 1427 | } |
@@ -1461,7 +1443,6 @@ out_fd: | |||
1461 | goto out_put; | 1443 | goto out_put; |
1462 | } | 1444 | } |
1463 | 1445 | ||
1464 | |||
1465 | /* | 1446 | /* |
1466 | * Attempt to connect to a socket with the server address. The address | 1447 | * Attempt to connect to a socket with the server address. The address |
1467 | * is in user space so we verify it is OK and move it to kernel space. | 1448 | * is in user space so we verify it is OK and move it to kernel space. |
@@ -1474,7 +1455,8 @@ out_fd: | |||
1474 | * include the -EINPROGRESS status for such sockets. | 1455 | * include the -EINPROGRESS status for such sockets. |
1475 | */ | 1456 | */ |
1476 | 1457 | ||
1477 | asmlinkage long sys_connect(int fd, struct sockaddr __user *uservaddr, int addrlen) | 1458 | asmlinkage long sys_connect(int fd, struct sockaddr __user *uservaddr, |
1459 | int addrlen) | ||
1478 | { | 1460 | { |
1479 | struct socket *sock; | 1461 | struct socket *sock; |
1480 | char address[MAX_SOCK_ADDR]; | 1462 | char address[MAX_SOCK_ADDR]; |
@@ -1487,11 +1469,12 @@ asmlinkage long sys_connect(int fd, struct sockaddr __user *uservaddr, int addrl | |||
1487 | if (err < 0) | 1469 | if (err < 0) |
1488 | goto out_put; | 1470 | goto out_put; |
1489 | 1471 | ||
1490 | err = security_socket_connect(sock, (struct sockaddr *)address, addrlen); | 1472 | err = |
1473 | security_socket_connect(sock, (struct sockaddr *)address, addrlen); | ||
1491 | if (err) | 1474 | if (err) |
1492 | goto out_put; | 1475 | goto out_put; |
1493 | 1476 | ||
1494 | err = sock->ops->connect(sock, (struct sockaddr *) address, addrlen, | 1477 | err = sock->ops->connect(sock, (struct sockaddr *)address, addrlen, |
1495 | sock->file->f_flags); | 1478 | sock->file->f_flags); |
1496 | out_put: | 1479 | out_put: |
1497 | fput_light(sock->file, fput_needed); | 1480 | fput_light(sock->file, fput_needed); |
@@ -1504,12 +1487,13 @@ out: | |||
1504 | * name to user space. | 1487 | * name to user space. |
1505 | */ | 1488 | */ |
1506 | 1489 | ||
1507 | asmlinkage long sys_getsockname(int fd, struct sockaddr __user *usockaddr, int __user *usockaddr_len) | 1490 | asmlinkage long sys_getsockname(int fd, struct sockaddr __user *usockaddr, |
1491 | int __user *usockaddr_len) | ||
1508 | { | 1492 | { |
1509 | struct socket *sock; | 1493 | struct socket *sock; |
1510 | char address[MAX_SOCK_ADDR]; | 1494 | char address[MAX_SOCK_ADDR]; |
1511 | int len, err, fput_needed; | 1495 | int len, err, fput_needed; |
1512 | 1496 | ||
1513 | sock = sockfd_lookup_light(fd, &err, &fput_needed); | 1497 | sock = sockfd_lookup_light(fd, &err, &fput_needed); |
1514 | if (!sock) | 1498 | if (!sock) |
1515 | goto out; | 1499 | goto out; |
@@ -1534,22 +1518,27 @@ out: | |||
1534 | * name to user space. | 1518 | * name to user space. |
1535 | */ | 1519 | */ |
1536 | 1520 | ||
1537 | asmlinkage long sys_getpeername(int fd, struct sockaddr __user *usockaddr, int __user *usockaddr_len) | 1521 | asmlinkage long sys_getpeername(int fd, struct sockaddr __user *usockaddr, |
1522 | int __user *usockaddr_len) | ||
1538 | { | 1523 | { |
1539 | struct socket *sock; | 1524 | struct socket *sock; |
1540 | char address[MAX_SOCK_ADDR]; | 1525 | char address[MAX_SOCK_ADDR]; |
1541 | int len, err, fput_needed; | 1526 | int len, err, fput_needed; |
1542 | 1527 | ||
1543 | if ((sock = sockfd_lookup_light(fd, &err, &fput_needed)) != NULL) { | 1528 | sock = sockfd_lookup_light(fd, &err, &fput_needed); |
1529 | if (sock != NULL) { | ||
1544 | err = security_socket_getpeername(sock); | 1530 | err = security_socket_getpeername(sock); |
1545 | if (err) { | 1531 | if (err) { |
1546 | fput_light(sock->file, fput_needed); | 1532 | fput_light(sock->file, fput_needed); |
1547 | return err; | 1533 | return err; |
1548 | } | 1534 | } |
1549 | 1535 | ||
1550 | err = sock->ops->getname(sock, (struct sockaddr *)address, &len, 1); | 1536 | err = |
1537 | sock->ops->getname(sock, (struct sockaddr *)address, &len, | ||
1538 | 1); | ||
1551 | if (!err) | 1539 | if (!err) |
1552 | err=move_addr_to_user(address,len, usockaddr, usockaddr_len); | 1540 | err = move_addr_to_user(address, len, usockaddr, |
1541 | usockaddr_len); | ||
1553 | fput_light(sock->file, fput_needed); | 1542 | fput_light(sock->file, fput_needed); |
1554 | } | 1543 | } |
1555 | return err; | 1544 | return err; |
@@ -1561,8 +1550,9 @@ asmlinkage long sys_getpeername(int fd, struct sockaddr __user *usockaddr, int _ | |||
1561 | * the protocol. | 1550 | * the protocol. |
1562 | */ | 1551 | */ |
1563 | 1552 | ||
1564 | asmlinkage long sys_sendto(int fd, void __user * buff, size_t len, unsigned flags, | 1553 | asmlinkage long sys_sendto(int fd, void __user *buff, size_t len, |
1565 | struct sockaddr __user *addr, int addr_len) | 1554 | unsigned flags, struct sockaddr __user *addr, |
1555 | int addr_len) | ||
1566 | { | 1556 | { |
1567 | struct socket *sock; | 1557 | struct socket *sock; |
1568 | char address[MAX_SOCK_ADDR]; | 1558 | char address[MAX_SOCK_ADDR]; |
@@ -1579,54 +1569,55 @@ asmlinkage long sys_sendto(int fd, void __user * buff, size_t len, unsigned flag | |||
1579 | sock = sock_from_file(sock_file, &err); | 1569 | sock = sock_from_file(sock_file, &err); |
1580 | if (!sock) | 1570 | if (!sock) |
1581 | goto out_put; | 1571 | goto out_put; |
1582 | iov.iov_base=buff; | 1572 | iov.iov_base = buff; |
1583 | iov.iov_len=len; | 1573 | iov.iov_len = len; |
1584 | msg.msg_name=NULL; | 1574 | msg.msg_name = NULL; |
1585 | msg.msg_iov=&iov; | 1575 | msg.msg_iov = &iov; |
1586 | msg.msg_iovlen=1; | 1576 | msg.msg_iovlen = 1; |
1587 | msg.msg_control=NULL; | 1577 | msg.msg_control = NULL; |
1588 | msg.msg_controllen=0; | 1578 | msg.msg_controllen = 0; |
1589 | msg.msg_namelen=0; | 1579 | msg.msg_namelen = 0; |
1590 | if (addr) { | 1580 | if (addr) { |
1591 | err = move_addr_to_kernel(addr, addr_len, address); | 1581 | err = move_addr_to_kernel(addr, addr_len, address); |
1592 | if (err < 0) | 1582 | if (err < 0) |
1593 | goto out_put; | 1583 | goto out_put; |
1594 | msg.msg_name=address; | 1584 | msg.msg_name = address; |
1595 | msg.msg_namelen=addr_len; | 1585 | msg.msg_namelen = addr_len; |
1596 | } | 1586 | } |
1597 | if (sock->file->f_flags & O_NONBLOCK) | 1587 | if (sock->file->f_flags & O_NONBLOCK) |
1598 | flags |= MSG_DONTWAIT; | 1588 | flags |= MSG_DONTWAIT; |
1599 | msg.msg_flags = flags; | 1589 | msg.msg_flags = flags; |
1600 | err = sock_sendmsg(sock, &msg, len); | 1590 | err = sock_sendmsg(sock, &msg, len); |
1601 | 1591 | ||
1602 | out_put: | 1592 | out_put: |
1603 | fput_light(sock_file, fput_needed); | 1593 | fput_light(sock_file, fput_needed); |
1604 | return err; | 1594 | return err; |
1605 | } | 1595 | } |
1606 | 1596 | ||
1607 | /* | 1597 | /* |
1608 | * Send a datagram down a socket. | 1598 | * Send a datagram down a socket. |
1609 | */ | 1599 | */ |
1610 | 1600 | ||
1611 | asmlinkage long sys_send(int fd, void __user * buff, size_t len, unsigned flags) | 1601 | asmlinkage long sys_send(int fd, void __user *buff, size_t len, unsigned flags) |
1612 | { | 1602 | { |
1613 | return sys_sendto(fd, buff, len, flags, NULL, 0); | 1603 | return sys_sendto(fd, buff, len, flags, NULL, 0); |
1614 | } | 1604 | } |
1615 | 1605 | ||
1616 | /* | 1606 | /* |
1617 | * Receive a frame from the socket and optionally record the address of the | 1607 | * Receive a frame from the socket and optionally record the address of the |
1618 | * sender. We verify the buffers are writable and if needed move the | 1608 | * sender. We verify the buffers are writable and if needed move the |
1619 | * sender address from kernel to user space. | 1609 | * sender address from kernel to user space. |
1620 | */ | 1610 | */ |
1621 | 1611 | ||
1622 | asmlinkage long sys_recvfrom(int fd, void __user * ubuf, size_t size, unsigned flags, | 1612 | asmlinkage long sys_recvfrom(int fd, void __user *ubuf, size_t size, |
1623 | struct sockaddr __user *addr, int __user *addr_len) | 1613 | unsigned flags, struct sockaddr __user *addr, |
1614 | int __user *addr_len) | ||
1624 | { | 1615 | { |
1625 | struct socket *sock; | 1616 | struct socket *sock; |
1626 | struct iovec iov; | 1617 | struct iovec iov; |
1627 | struct msghdr msg; | 1618 | struct msghdr msg; |
1628 | char address[MAX_SOCK_ADDR]; | 1619 | char address[MAX_SOCK_ADDR]; |
1629 | int err,err2; | 1620 | int err, err2; |
1630 | struct file *sock_file; | 1621 | struct file *sock_file; |
1631 | int fput_needed; | 1622 | int fput_needed; |
1632 | 1623 | ||
@@ -1638,23 +1629,22 @@ asmlinkage long sys_recvfrom(int fd, void __user * ubuf, size_t size, unsigned f | |||
1638 | if (!sock) | 1629 | if (!sock) |
1639 | goto out; | 1630 | goto out; |
1640 | 1631 | ||
1641 | msg.msg_control=NULL; | 1632 | msg.msg_control = NULL; |
1642 | msg.msg_controllen=0; | 1633 | msg.msg_controllen = 0; |
1643 | msg.msg_iovlen=1; | 1634 | msg.msg_iovlen = 1; |
1644 | msg.msg_iov=&iov; | 1635 | msg.msg_iov = &iov; |
1645 | iov.iov_len=size; | 1636 | iov.iov_len = size; |
1646 | iov.iov_base=ubuf; | 1637 | iov.iov_base = ubuf; |
1647 | msg.msg_name=address; | 1638 | msg.msg_name = address; |
1648 | msg.msg_namelen=MAX_SOCK_ADDR; | 1639 | msg.msg_namelen = MAX_SOCK_ADDR; |
1649 | if (sock->file->f_flags & O_NONBLOCK) | 1640 | if (sock->file->f_flags & O_NONBLOCK) |
1650 | flags |= MSG_DONTWAIT; | 1641 | flags |= MSG_DONTWAIT; |
1651 | err=sock_recvmsg(sock, &msg, size, flags); | 1642 | err = sock_recvmsg(sock, &msg, size, flags); |
1652 | 1643 | ||
1653 | if(err >= 0 && addr != NULL) | 1644 | if (err >= 0 && addr != NULL) { |
1654 | { | 1645 | err2 = move_addr_to_user(address, msg.msg_namelen, addr, addr_len); |
1655 | err2=move_addr_to_user(address, msg.msg_namelen, addr, addr_len); | 1646 | if (err2 < 0) |
1656 | if(err2<0) | 1647 | err = err2; |
1657 | err=err2; | ||
1658 | } | 1648 | } |
1659 | out: | 1649 | out: |
1660 | fput_light(sock_file, fput_needed); | 1650 | fput_light(sock_file, fput_needed); |
@@ -1662,10 +1652,11 @@ out: | |||
1662 | } | 1652 | } |
1663 | 1653 | ||
1664 | /* | 1654 | /* |
1665 | * Receive a datagram from a socket. | 1655 | * Receive a datagram from a socket. |
1666 | */ | 1656 | */ |
1667 | 1657 | ||
1668 | asmlinkage long sys_recv(int fd, void __user * ubuf, size_t size, unsigned flags) | 1658 | asmlinkage long sys_recv(int fd, void __user *ubuf, size_t size, |
1659 | unsigned flags) | ||
1669 | { | 1660 | { |
1670 | return sys_recvfrom(fd, ubuf, size, flags, NULL, NULL); | 1661 | return sys_recvfrom(fd, ubuf, size, flags, NULL, NULL); |
1671 | } | 1662 | } |
@@ -1675,24 +1666,29 @@ asmlinkage long sys_recv(int fd, void __user * ubuf, size_t size, unsigned flags | |||
1675 | * to pass the user mode parameter for the protocols to sort out. | 1666 | * to pass the user mode parameter for the protocols to sort out. |
1676 | */ | 1667 | */ |
1677 | 1668 | ||
1678 | asmlinkage long sys_setsockopt(int fd, int level, int optname, char __user *optval, int optlen) | 1669 | asmlinkage long sys_setsockopt(int fd, int level, int optname, |
1670 | char __user *optval, int optlen) | ||
1679 | { | 1671 | { |
1680 | int err, fput_needed; | 1672 | int err, fput_needed; |
1681 | struct socket *sock; | 1673 | struct socket *sock; |
1682 | 1674 | ||
1683 | if (optlen < 0) | 1675 | if (optlen < 0) |
1684 | return -EINVAL; | 1676 | return -EINVAL; |
1685 | 1677 | ||
1686 | if ((sock = sockfd_lookup_light(fd, &err, &fput_needed)) != NULL) | 1678 | sock = sockfd_lookup_light(fd, &err, &fput_needed); |
1687 | { | 1679 | if (sock != NULL) { |
1688 | err = security_socket_setsockopt(sock,level,optname); | 1680 | err = security_socket_setsockopt(sock, level, optname); |
1689 | if (err) | 1681 | if (err) |
1690 | goto out_put; | 1682 | goto out_put; |
1691 | 1683 | ||
1692 | if (level == SOL_SOCKET) | 1684 | if (level == SOL_SOCKET) |
1693 | err=sock_setsockopt(sock,level,optname,optval,optlen); | 1685 | err = |
1686 | sock_setsockopt(sock, level, optname, optval, | ||
1687 | optlen); | ||
1694 | else | 1688 | else |
1695 | err=sock->ops->setsockopt(sock, level, optname, optval, optlen); | 1689 | err = |
1690 | sock->ops->setsockopt(sock, level, optname, optval, | ||
1691 | optlen); | ||
1696 | out_put: | 1692 | out_put: |
1697 | fput_light(sock->file, fput_needed); | 1693 | fput_light(sock->file, fput_needed); |
1698 | } | 1694 | } |
@@ -1704,27 +1700,32 @@ out_put: | |||
1704 | * to pass a user mode parameter for the protocols to sort out. | 1700 | * to pass a user mode parameter for the protocols to sort out. |
1705 | */ | 1701 | */ |
1706 | 1702 | ||
1707 | asmlinkage long sys_getsockopt(int fd, int level, int optname, char __user *optval, int __user *optlen) | 1703 | asmlinkage long sys_getsockopt(int fd, int level, int optname, |
1704 | char __user *optval, int __user *optlen) | ||
1708 | { | 1705 | { |
1709 | int err, fput_needed; | 1706 | int err, fput_needed; |
1710 | struct socket *sock; | 1707 | struct socket *sock; |
1711 | 1708 | ||
1712 | if ((sock = sockfd_lookup_light(fd, &err, &fput_needed)) != NULL) { | 1709 | sock = sockfd_lookup_light(fd, &err, &fput_needed); |
1710 | if (sock != NULL) { | ||
1713 | err = security_socket_getsockopt(sock, level, optname); | 1711 | err = security_socket_getsockopt(sock, level, optname); |
1714 | if (err) | 1712 | if (err) |
1715 | goto out_put; | 1713 | goto out_put; |
1716 | 1714 | ||
1717 | if (level == SOL_SOCKET) | 1715 | if (level == SOL_SOCKET) |
1718 | err=sock_getsockopt(sock,level,optname,optval,optlen); | 1716 | err = |
1717 | sock_getsockopt(sock, level, optname, optval, | ||
1718 | optlen); | ||
1719 | else | 1719 | else |
1720 | err=sock->ops->getsockopt(sock, level, optname, optval, optlen); | 1720 | err = |
1721 | sock->ops->getsockopt(sock, level, optname, optval, | ||
1722 | optlen); | ||
1721 | out_put: | 1723 | out_put: |
1722 | fput_light(sock->file, fput_needed); | 1724 | fput_light(sock->file, fput_needed); |
1723 | } | 1725 | } |
1724 | return err; | 1726 | return err; |
1725 | } | 1727 | } |
1726 | 1728 | ||
1727 | |||
1728 | /* | 1729 | /* |
1729 | * Shutdown a socket. | 1730 | * Shutdown a socket. |
1730 | */ | 1731 | */ |
@@ -1734,8 +1735,8 @@ asmlinkage long sys_shutdown(int fd, int how) | |||
1734 | int err, fput_needed; | 1735 | int err, fput_needed; |
1735 | struct socket *sock; | 1736 | struct socket *sock; |
1736 | 1737 | ||
1737 | if ((sock = sockfd_lookup_light(fd, &err, &fput_needed))!=NULL) | 1738 | sock = sockfd_lookup_light(fd, &err, &fput_needed); |
1738 | { | 1739 | if (sock != NULL) { |
1739 | err = security_socket_shutdown(sock, how); | 1740 | err = security_socket_shutdown(sock, how); |
1740 | if (!err) | 1741 | if (!err) |
1741 | err = sock->ops->shutdown(sock, how); | 1742 | err = sock->ops->shutdown(sock, how); |
@@ -1744,41 +1745,42 @@ asmlinkage long sys_shutdown(int fd, int how) | |||
1744 | return err; | 1745 | return err; |
1745 | } | 1746 | } |
1746 | 1747 | ||
1747 | /* A couple of helpful macros for getting the address of the 32/64 bit | 1748 | /* A couple of helpful macros for getting the address of the 32/64 bit |
1748 | * fields which are the same type (int / unsigned) on our platforms. | 1749 | * fields which are the same type (int / unsigned) on our platforms. |
1749 | */ | 1750 | */ |
1750 | #define COMPAT_MSG(msg, member) ((MSG_CMSG_COMPAT & flags) ? &msg##_compat->member : &msg->member) | 1751 | #define COMPAT_MSG(msg, member) ((MSG_CMSG_COMPAT & flags) ? &msg##_compat->member : &msg->member) |
1751 | #define COMPAT_NAMELEN(msg) COMPAT_MSG(msg, msg_namelen) | 1752 | #define COMPAT_NAMELEN(msg) COMPAT_MSG(msg, msg_namelen) |
1752 | #define COMPAT_FLAGS(msg) COMPAT_MSG(msg, msg_flags) | 1753 | #define COMPAT_FLAGS(msg) COMPAT_MSG(msg, msg_flags) |
1753 | 1754 | ||
1754 | |||
1755 | /* | 1755 | /* |
1756 | * BSD sendmsg interface | 1756 | * BSD sendmsg interface |
1757 | */ | 1757 | */ |
1758 | 1758 | ||
1759 | asmlinkage long sys_sendmsg(int fd, struct msghdr __user *msg, unsigned flags) | 1759 | asmlinkage long sys_sendmsg(int fd, struct msghdr __user *msg, unsigned flags) |
1760 | { | 1760 | { |
1761 | struct compat_msghdr __user *msg_compat = (struct compat_msghdr __user *)msg; | 1761 | struct compat_msghdr __user *msg_compat = |
1762 | (struct compat_msghdr __user *)msg; | ||
1762 | struct socket *sock; | 1763 | struct socket *sock; |
1763 | char address[MAX_SOCK_ADDR]; | 1764 | char address[MAX_SOCK_ADDR]; |
1764 | struct iovec iovstack[UIO_FASTIOV], *iov = iovstack; | 1765 | struct iovec iovstack[UIO_FASTIOV], *iov = iovstack; |
1765 | unsigned char ctl[sizeof(struct cmsghdr) + 20] | 1766 | unsigned char ctl[sizeof(struct cmsghdr) + 20] |
1766 | __attribute__ ((aligned (sizeof(__kernel_size_t)))); | 1767 | __attribute__ ((aligned(sizeof(__kernel_size_t)))); |
1767 | /* 20 is size of ipv6_pktinfo */ | 1768 | /* 20 is size of ipv6_pktinfo */ |
1768 | unsigned char *ctl_buf = ctl; | 1769 | unsigned char *ctl_buf = ctl; |
1769 | struct msghdr msg_sys; | 1770 | struct msghdr msg_sys; |
1770 | int err, ctl_len, iov_size, total_len; | 1771 | int err, ctl_len, iov_size, total_len; |
1771 | int fput_needed; | 1772 | int fput_needed; |
1772 | 1773 | ||
1773 | err = -EFAULT; | 1774 | err = -EFAULT; |
1774 | if (MSG_CMSG_COMPAT & flags) { | 1775 | if (MSG_CMSG_COMPAT & flags) { |
1775 | if (get_compat_msghdr(&msg_sys, msg_compat)) | 1776 | if (get_compat_msghdr(&msg_sys, msg_compat)) |
1776 | return -EFAULT; | 1777 | return -EFAULT; |
1777 | } else if (copy_from_user(&msg_sys, msg, sizeof(struct msghdr))) | 1778 | } |
1779 | else if (copy_from_user(&msg_sys, msg, sizeof(struct msghdr))) | ||
1778 | return -EFAULT; | 1780 | return -EFAULT; |
1779 | 1781 | ||
1780 | sock = sockfd_lookup_light(fd, &err, &fput_needed); | 1782 | sock = sockfd_lookup_light(fd, &err, &fput_needed); |
1781 | if (!sock) | 1783 | if (!sock) |
1782 | goto out; | 1784 | goto out; |
1783 | 1785 | ||
1784 | /* do not move before msg_sys is valid */ | 1786 | /* do not move before msg_sys is valid */ |
@@ -1786,7 +1788,7 @@ asmlinkage long sys_sendmsg(int fd, struct msghdr __user *msg, unsigned flags) | |||
1786 | if (msg_sys.msg_iovlen > UIO_MAXIOV) | 1788 | if (msg_sys.msg_iovlen > UIO_MAXIOV) |
1787 | goto out_put; | 1789 | goto out_put; |
1788 | 1790 | ||
1789 | /* Check whether to allocate the iovec area*/ | 1791 | /* Check whether to allocate the iovec area */ |
1790 | err = -ENOMEM; | 1792 | err = -ENOMEM; |
1791 | iov_size = msg_sys.msg_iovlen * sizeof(struct iovec); | 1793 | iov_size = msg_sys.msg_iovlen * sizeof(struct iovec); |
1792 | if (msg_sys.msg_iovlen > UIO_FASTIOV) { | 1794 | if (msg_sys.msg_iovlen > UIO_FASTIOV) { |
@@ -1800,7 +1802,7 @@ asmlinkage long sys_sendmsg(int fd, struct msghdr __user *msg, unsigned flags) | |||
1800 | err = verify_compat_iovec(&msg_sys, iov, address, VERIFY_READ); | 1802 | err = verify_compat_iovec(&msg_sys, iov, address, VERIFY_READ); |
1801 | } else | 1803 | } else |
1802 | err = verify_iovec(&msg_sys, iov, address, VERIFY_READ); | 1804 | err = verify_iovec(&msg_sys, iov, address, VERIFY_READ); |
1803 | if (err < 0) | 1805 | if (err < 0) |
1804 | goto out_freeiov; | 1806 | goto out_freeiov; |
1805 | total_len = err; | 1807 | total_len = err; |
1806 | 1808 | ||
@@ -1808,18 +1810,19 @@ asmlinkage long sys_sendmsg(int fd, struct msghdr __user *msg, unsigned flags) | |||
1808 | 1810 | ||
1809 | if (msg_sys.msg_controllen > INT_MAX) | 1811 | if (msg_sys.msg_controllen > INT_MAX) |
1810 | goto out_freeiov; | 1812 | goto out_freeiov; |
1811 | ctl_len = msg_sys.msg_controllen; | 1813 | ctl_len = msg_sys.msg_controllen; |
1812 | if ((MSG_CMSG_COMPAT & flags) && ctl_len) { | 1814 | if ((MSG_CMSG_COMPAT & flags) && ctl_len) { |
1813 | err = cmsghdr_from_user_compat_to_kern(&msg_sys, sock->sk, ctl, sizeof(ctl)); | 1815 | err = |
1816 | cmsghdr_from_user_compat_to_kern(&msg_sys, sock->sk, ctl, | ||
1817 | sizeof(ctl)); | ||
1814 | if (err) | 1818 | if (err) |
1815 | goto out_freeiov; | 1819 | goto out_freeiov; |
1816 | ctl_buf = msg_sys.msg_control; | 1820 | ctl_buf = msg_sys.msg_control; |
1817 | ctl_len = msg_sys.msg_controllen; | 1821 | ctl_len = msg_sys.msg_controllen; |
1818 | } else if (ctl_len) { | 1822 | } else if (ctl_len) { |
1819 | if (ctl_len > sizeof(ctl)) | 1823 | if (ctl_len > sizeof(ctl)) { |
1820 | { | ||
1821 | ctl_buf = sock_kmalloc(sock->sk, ctl_len, GFP_KERNEL); | 1824 | ctl_buf = sock_kmalloc(sock->sk, ctl_len, GFP_KERNEL); |
1822 | if (ctl_buf == NULL) | 1825 | if (ctl_buf == NULL) |
1823 | goto out_freeiov; | 1826 | goto out_freeiov; |
1824 | } | 1827 | } |
1825 | err = -EFAULT; | 1828 | err = -EFAULT; |
@@ -1828,7 +1831,8 @@ asmlinkage long sys_sendmsg(int fd, struct msghdr __user *msg, unsigned flags) | |||
1828 | * Afterwards, it will be a kernel pointer. Thus the compiler-assisted | 1831 | * Afterwards, it will be a kernel pointer. Thus the compiler-assisted |
1829 | * checking falls down on this. | 1832 | * checking falls down on this. |
1830 | */ | 1833 | */ |
1831 | if (copy_from_user(ctl_buf, (void __user *) msg_sys.msg_control, ctl_len)) | 1834 | if (copy_from_user(ctl_buf, (void __user *)msg_sys.msg_control, |
1835 | ctl_len)) | ||
1832 | goto out_freectl; | 1836 | goto out_freectl; |
1833 | msg_sys.msg_control = ctl_buf; | 1837 | msg_sys.msg_control = ctl_buf; |
1834 | } | 1838 | } |
@@ -1839,14 +1843,14 @@ asmlinkage long sys_sendmsg(int fd, struct msghdr __user *msg, unsigned flags) | |||
1839 | err = sock_sendmsg(sock, &msg_sys, total_len); | 1843 | err = sock_sendmsg(sock, &msg_sys, total_len); |
1840 | 1844 | ||
1841 | out_freectl: | 1845 | out_freectl: |
1842 | if (ctl_buf != ctl) | 1846 | if (ctl_buf != ctl) |
1843 | sock_kfree_s(sock->sk, ctl_buf, ctl_len); | 1847 | sock_kfree_s(sock->sk, ctl_buf, ctl_len); |
1844 | out_freeiov: | 1848 | out_freeiov: |
1845 | if (iov != iovstack) | 1849 | if (iov != iovstack) |
1846 | sock_kfree_s(sock->sk, iov, iov_size); | 1850 | sock_kfree_s(sock->sk, iov, iov_size); |
1847 | out_put: | 1851 | out_put: |
1848 | fput_light(sock->file, fput_needed); | 1852 | fput_light(sock->file, fput_needed); |
1849 | out: | 1853 | out: |
1850 | return err; | 1854 | return err; |
1851 | } | 1855 | } |
1852 | 1856 | ||
@@ -1854,12 +1858,14 @@ out: | |||
1854 | * BSD recvmsg interface | 1858 | * BSD recvmsg interface |
1855 | */ | 1859 | */ |
1856 | 1860 | ||
1857 | asmlinkage long sys_recvmsg(int fd, struct msghdr __user *msg, unsigned int flags) | 1861 | asmlinkage long sys_recvmsg(int fd, struct msghdr __user *msg, |
1862 | unsigned int flags) | ||
1858 | { | 1863 | { |
1859 | struct compat_msghdr __user *msg_compat = (struct compat_msghdr __user *)msg; | 1864 | struct compat_msghdr __user *msg_compat = |
1865 | (struct compat_msghdr __user *)msg; | ||
1860 | struct socket *sock; | 1866 | struct socket *sock; |
1861 | struct iovec iovstack[UIO_FASTIOV]; | 1867 | struct iovec iovstack[UIO_FASTIOV]; |
1862 | struct iovec *iov=iovstack; | 1868 | struct iovec *iov = iovstack; |
1863 | struct msghdr msg_sys; | 1869 | struct msghdr msg_sys; |
1864 | unsigned long cmsg_ptr; | 1870 | unsigned long cmsg_ptr; |
1865 | int err, iov_size, total_len, len; | 1871 | int err, iov_size, total_len, len; |
@@ -1871,13 +1877,13 @@ asmlinkage long sys_recvmsg(int fd, struct msghdr __user *msg, unsigned int flag | |||
1871 | /* user mode address pointers */ | 1877 | /* user mode address pointers */ |
1872 | struct sockaddr __user *uaddr; | 1878 | struct sockaddr __user *uaddr; |
1873 | int __user *uaddr_len; | 1879 | int __user *uaddr_len; |
1874 | 1880 | ||
1875 | if (MSG_CMSG_COMPAT & flags) { | 1881 | if (MSG_CMSG_COMPAT & flags) { |
1876 | if (get_compat_msghdr(&msg_sys, msg_compat)) | 1882 | if (get_compat_msghdr(&msg_sys, msg_compat)) |
1877 | return -EFAULT; | 1883 | return -EFAULT; |
1878 | } else | 1884 | } |
1879 | if (copy_from_user(&msg_sys,msg,sizeof(struct msghdr))) | 1885 | else if (copy_from_user(&msg_sys, msg, sizeof(struct msghdr))) |
1880 | return -EFAULT; | 1886 | return -EFAULT; |
1881 | 1887 | ||
1882 | sock = sockfd_lookup_light(fd, &err, &fput_needed); | 1888 | sock = sockfd_lookup_light(fd, &err, &fput_needed); |
1883 | if (!sock) | 1889 | if (!sock) |
@@ -1886,8 +1892,8 @@ asmlinkage long sys_recvmsg(int fd, struct msghdr __user *msg, unsigned int flag | |||
1886 | err = -EMSGSIZE; | 1892 | err = -EMSGSIZE; |
1887 | if (msg_sys.msg_iovlen > UIO_MAXIOV) | 1893 | if (msg_sys.msg_iovlen > UIO_MAXIOV) |
1888 | goto out_put; | 1894 | goto out_put; |
1889 | 1895 | ||
1890 | /* Check whether to allocate the iovec area*/ | 1896 | /* Check whether to allocate the iovec area */ |
1891 | err = -ENOMEM; | 1897 | err = -ENOMEM; |
1892 | iov_size = msg_sys.msg_iovlen * sizeof(struct iovec); | 1898 | iov_size = msg_sys.msg_iovlen * sizeof(struct iovec); |
1893 | if (msg_sys.msg_iovlen > UIO_FASTIOV) { | 1899 | if (msg_sys.msg_iovlen > UIO_FASTIOV) { |
@@ -1897,11 +1903,11 @@ asmlinkage long sys_recvmsg(int fd, struct msghdr __user *msg, unsigned int flag | |||
1897 | } | 1903 | } |
1898 | 1904 | ||
1899 | /* | 1905 | /* |
1900 | * Save the user-mode address (verify_iovec will change the | 1906 | * Save the user-mode address (verify_iovec will change the |
1901 | * kernel msghdr to use the kernel address space) | 1907 | * kernel msghdr to use the kernel address space) |
1902 | */ | 1908 | */ |
1903 | 1909 | ||
1904 | uaddr = (void __user *) msg_sys.msg_name; | 1910 | uaddr = (void __user *)msg_sys.msg_name; |
1905 | uaddr_len = COMPAT_NAMELEN(msg); | 1911 | uaddr_len = COMPAT_NAMELEN(msg); |
1906 | if (MSG_CMSG_COMPAT & flags) { | 1912 | if (MSG_CMSG_COMPAT & flags) { |
1907 | err = verify_compat_iovec(&msg_sys, iov, addr, VERIFY_WRITE); | 1913 | err = verify_compat_iovec(&msg_sys, iov, addr, VERIFY_WRITE); |
@@ -1909,13 +1915,13 @@ asmlinkage long sys_recvmsg(int fd, struct msghdr __user *msg, unsigned int flag | |||
1909 | err = verify_iovec(&msg_sys, iov, addr, VERIFY_WRITE); | 1915 | err = verify_iovec(&msg_sys, iov, addr, VERIFY_WRITE); |
1910 | if (err < 0) | 1916 | if (err < 0) |
1911 | goto out_freeiov; | 1917 | goto out_freeiov; |
1912 | total_len=err; | 1918 | total_len = err; |
1913 | 1919 | ||
1914 | cmsg_ptr = (unsigned long)msg_sys.msg_control; | 1920 | cmsg_ptr = (unsigned long)msg_sys.msg_control; |
1915 | msg_sys.msg_flags = 0; | 1921 | msg_sys.msg_flags = 0; |
1916 | if (MSG_CMSG_COMPAT & flags) | 1922 | if (MSG_CMSG_COMPAT & flags) |
1917 | msg_sys.msg_flags = MSG_CMSG_COMPAT; | 1923 | msg_sys.msg_flags = MSG_CMSG_COMPAT; |
1918 | 1924 | ||
1919 | if (sock->file->f_flags & O_NONBLOCK) | 1925 | if (sock->file->f_flags & O_NONBLOCK) |
1920 | flags |= MSG_DONTWAIT; | 1926 | flags |= MSG_DONTWAIT; |
1921 | err = sock_recvmsg(sock, &msg_sys, total_len, flags); | 1927 | err = sock_recvmsg(sock, &msg_sys, total_len, flags); |
@@ -1924,7 +1930,8 @@ asmlinkage long sys_recvmsg(int fd, struct msghdr __user *msg, unsigned int flag | |||
1924 | len = err; | 1930 | len = err; |
1925 | 1931 | ||
1926 | if (uaddr != NULL) { | 1932 | if (uaddr != NULL) { |
1927 | err = move_addr_to_user(addr, msg_sys.msg_namelen, uaddr, uaddr_len); | 1933 | err = move_addr_to_user(addr, msg_sys.msg_namelen, uaddr, |
1934 | uaddr_len); | ||
1928 | if (err < 0) | 1935 | if (err < 0) |
1929 | goto out_freeiov; | 1936 | goto out_freeiov; |
1930 | } | 1937 | } |
@@ -1933,10 +1940,10 @@ asmlinkage long sys_recvmsg(int fd, struct msghdr __user *msg, unsigned int flag | |||
1933 | if (err) | 1940 | if (err) |
1934 | goto out_freeiov; | 1941 | goto out_freeiov; |
1935 | if (MSG_CMSG_COMPAT & flags) | 1942 | if (MSG_CMSG_COMPAT & flags) |
1936 | err = __put_user((unsigned long)msg_sys.msg_control-cmsg_ptr, | 1943 | err = __put_user((unsigned long)msg_sys.msg_control - cmsg_ptr, |
1937 | &msg_compat->msg_controllen); | 1944 | &msg_compat->msg_controllen); |
1938 | else | 1945 | else |
1939 | err = __put_user((unsigned long)msg_sys.msg_control-cmsg_ptr, | 1946 | err = __put_user((unsigned long)msg_sys.msg_control - cmsg_ptr, |
1940 | &msg->msg_controllen); | 1947 | &msg->msg_controllen); |
1941 | if (err) | 1948 | if (err) |
1942 | goto out_freeiov; | 1949 | goto out_freeiov; |
@@ -1955,163 +1962,187 @@ out: | |||
1955 | 1962 | ||
1956 | /* Argument list sizes for sys_socketcall */ | 1963 | /* Argument list sizes for sys_socketcall */ |
1957 | #define AL(x) ((x) * sizeof(unsigned long)) | 1964 | #define AL(x) ((x) * sizeof(unsigned long)) |
1958 | static unsigned char nargs[18]={AL(0),AL(3),AL(3),AL(3),AL(2),AL(3), | 1965 | static const unsigned char nargs[18]={ |
1959 | AL(3),AL(3),AL(4),AL(4),AL(4),AL(6), | 1966 | AL(0),AL(3),AL(3),AL(3),AL(2),AL(3), |
1960 | AL(6),AL(2),AL(5),AL(5),AL(3),AL(3)}; | 1967 | AL(3),AL(3),AL(4),AL(4),AL(4),AL(6), |
1968 | AL(6),AL(2),AL(5),AL(5),AL(3),AL(3) | ||
1969 | }; | ||
1970 | |||
1961 | #undef AL | 1971 | #undef AL |
1962 | 1972 | ||
1963 | /* | 1973 | /* |
1964 | * System call vectors. | 1974 | * System call vectors. |
1965 | * | 1975 | * |
1966 | * Argument checking cleaned up. Saved 20% in size. | 1976 | * Argument checking cleaned up. Saved 20% in size. |
1967 | * This function doesn't need to set the kernel lock because | 1977 | * This function doesn't need to set the kernel lock because |
1968 | * it is set by the callees. | 1978 | * it is set by the callees. |
1969 | */ | 1979 | */ |
1970 | 1980 | ||
1971 | asmlinkage long sys_socketcall(int call, unsigned long __user *args) | 1981 | asmlinkage long sys_socketcall(int call, unsigned long __user *args) |
1972 | { | 1982 | { |
1973 | unsigned long a[6]; | 1983 | unsigned long a[6]; |
1974 | unsigned long a0,a1; | 1984 | unsigned long a0, a1; |
1975 | int err; | 1985 | int err; |
1976 | 1986 | ||
1977 | if(call<1||call>SYS_RECVMSG) | 1987 | if (call < 1 || call > SYS_RECVMSG) |
1978 | return -EINVAL; | 1988 | return -EINVAL; |
1979 | 1989 | ||
1980 | /* copy_from_user should be SMP safe. */ | 1990 | /* copy_from_user should be SMP safe. */ |
1981 | if (copy_from_user(a, args, nargs[call])) | 1991 | if (copy_from_user(a, args, nargs[call])) |
1982 | return -EFAULT; | 1992 | return -EFAULT; |
1983 | 1993 | ||
1984 | err = audit_socketcall(nargs[call]/sizeof(unsigned long), a); | 1994 | err = audit_socketcall(nargs[call] / sizeof(unsigned long), a); |
1985 | if (err) | 1995 | if (err) |
1986 | return err; | 1996 | return err; |
1987 | 1997 | ||
1988 | a0=a[0]; | 1998 | a0 = a[0]; |
1989 | a1=a[1]; | 1999 | a1 = a[1]; |
1990 | 2000 | ||
1991 | switch(call) | 2001 | switch (call) { |
1992 | { | 2002 | case SYS_SOCKET: |
1993 | case SYS_SOCKET: | 2003 | err = sys_socket(a0, a1, a[2]); |
1994 | err = sys_socket(a0,a1,a[2]); | 2004 | break; |
1995 | break; | 2005 | case SYS_BIND: |
1996 | case SYS_BIND: | 2006 | err = sys_bind(a0, (struct sockaddr __user *)a1, a[2]); |
1997 | err = sys_bind(a0,(struct sockaddr __user *)a1, a[2]); | 2007 | break; |
1998 | break; | 2008 | case SYS_CONNECT: |
1999 | case SYS_CONNECT: | 2009 | err = sys_connect(a0, (struct sockaddr __user *)a1, a[2]); |
2000 | err = sys_connect(a0, (struct sockaddr __user *)a1, a[2]); | 2010 | break; |
2001 | break; | 2011 | case SYS_LISTEN: |
2002 | case SYS_LISTEN: | 2012 | err = sys_listen(a0, a1); |
2003 | err = sys_listen(a0,a1); | 2013 | break; |
2004 | break; | 2014 | case SYS_ACCEPT: |
2005 | case SYS_ACCEPT: | 2015 | err = |
2006 | err = sys_accept(a0,(struct sockaddr __user *)a1, (int __user *)a[2]); | 2016 | sys_accept(a0, (struct sockaddr __user *)a1, |
2007 | break; | 2017 | (int __user *)a[2]); |
2008 | case SYS_GETSOCKNAME: | 2018 | break; |
2009 | err = sys_getsockname(a0,(struct sockaddr __user *)a1, (int __user *)a[2]); | 2019 | case SYS_GETSOCKNAME: |
2010 | break; | 2020 | err = |
2011 | case SYS_GETPEERNAME: | 2021 | sys_getsockname(a0, (struct sockaddr __user *)a1, |
2012 | err = sys_getpeername(a0, (struct sockaddr __user *)a1, (int __user *)a[2]); | 2022 | (int __user *)a[2]); |
2013 | break; | 2023 | break; |
2014 | case SYS_SOCKETPAIR: | 2024 | case SYS_GETPEERNAME: |
2015 | err = sys_socketpair(a0,a1, a[2], (int __user *)a[3]); | 2025 | err = |
2016 | break; | 2026 | sys_getpeername(a0, (struct sockaddr __user *)a1, |
2017 | case SYS_SEND: | 2027 | (int __user *)a[2]); |
2018 | err = sys_send(a0, (void __user *)a1, a[2], a[3]); | 2028 | break; |
2019 | break; | 2029 | case SYS_SOCKETPAIR: |
2020 | case SYS_SENDTO: | 2030 | err = sys_socketpair(a0, a1, a[2], (int __user *)a[3]); |
2021 | err = sys_sendto(a0,(void __user *)a1, a[2], a[3], | 2031 | break; |
2022 | (struct sockaddr __user *)a[4], a[5]); | 2032 | case SYS_SEND: |
2023 | break; | 2033 | err = sys_send(a0, (void __user *)a1, a[2], a[3]); |
2024 | case SYS_RECV: | 2034 | break; |
2025 | err = sys_recv(a0, (void __user *)a1, a[2], a[3]); | 2035 | case SYS_SENDTO: |
2026 | break; | 2036 | err = sys_sendto(a0, (void __user *)a1, a[2], a[3], |
2027 | case SYS_RECVFROM: | 2037 | (struct sockaddr __user *)a[4], a[5]); |
2028 | err = sys_recvfrom(a0, (void __user *)a1, a[2], a[3], | 2038 | break; |
2029 | (struct sockaddr __user *)a[4], (int __user *)a[5]); | 2039 | case SYS_RECV: |
2030 | break; | 2040 | err = sys_recv(a0, (void __user *)a1, a[2], a[3]); |
2031 | case SYS_SHUTDOWN: | 2041 | break; |
2032 | err = sys_shutdown(a0,a1); | 2042 | case SYS_RECVFROM: |
2033 | break; | 2043 | err = sys_recvfrom(a0, (void __user *)a1, a[2], a[3], |
2034 | case SYS_SETSOCKOPT: | 2044 | (struct sockaddr __user *)a[4], |
2035 | err = sys_setsockopt(a0, a1, a[2], (char __user *)a[3], a[4]); | 2045 | (int __user *)a[5]); |
2036 | break; | 2046 | break; |
2037 | case SYS_GETSOCKOPT: | 2047 | case SYS_SHUTDOWN: |
2038 | err = sys_getsockopt(a0, a1, a[2], (char __user *)a[3], (int __user *)a[4]); | 2048 | err = sys_shutdown(a0, a1); |
2039 | break; | 2049 | break; |
2040 | case SYS_SENDMSG: | 2050 | case SYS_SETSOCKOPT: |
2041 | err = sys_sendmsg(a0, (struct msghdr __user *) a1, a[2]); | 2051 | err = sys_setsockopt(a0, a1, a[2], (char __user *)a[3], a[4]); |
2042 | break; | 2052 | break; |
2043 | case SYS_RECVMSG: | 2053 | case SYS_GETSOCKOPT: |
2044 | err = sys_recvmsg(a0, (struct msghdr __user *) a1, a[2]); | 2054 | err = |
2045 | break; | 2055 | sys_getsockopt(a0, a1, a[2], (char __user *)a[3], |
2046 | default: | 2056 | (int __user *)a[4]); |
2047 | err = -EINVAL; | 2057 | break; |
2048 | break; | 2058 | case SYS_SENDMSG: |
2059 | err = sys_sendmsg(a0, (struct msghdr __user *)a1, a[2]); | ||
2060 | break; | ||
2061 | case SYS_RECVMSG: | ||
2062 | err = sys_recvmsg(a0, (struct msghdr __user *)a1, a[2]); | ||
2063 | break; | ||
2064 | default: | ||
2065 | err = -EINVAL; | ||
2066 | break; | ||
2049 | } | 2067 | } |
2050 | return err; | 2068 | return err; |
2051 | } | 2069 | } |
2052 | 2070 | ||
2053 | #endif /* __ARCH_WANT_SYS_SOCKETCALL */ | 2071 | #endif /* __ARCH_WANT_SYS_SOCKETCALL */ |
2054 | 2072 | ||
2055 | /* | 2073 | /** |
2074 | * sock_register - add a socket protocol handler | ||
2075 | * @ops: description of protocol | ||
2076 | * | ||
2056 | * This function is called by a protocol handler that wants to | 2077 | * This function is called by a protocol handler that wants to |
2057 | * advertise its address family, and have it linked into the | 2078 | * advertise its address family, and have it linked into the |
2058 | * SOCKET module. | 2079 | * socket interface. The value ops->family coresponds to the |
2080 | * socket system call protocol family. | ||
2059 | */ | 2081 | */ |
2060 | 2082 | int sock_register(const struct net_proto_family *ops) | |
2061 | int sock_register(struct net_proto_family *ops) | ||
2062 | { | 2083 | { |
2063 | int err; | 2084 | int err; |
2064 | 2085 | ||
2065 | if (ops->family >= NPROTO) { | 2086 | if (ops->family >= NPROTO) { |
2066 | printk(KERN_CRIT "protocol %d >= NPROTO(%d)\n", ops->family, NPROTO); | 2087 | printk(KERN_CRIT "protocol %d >= NPROTO(%d)\n", ops->family, |
2088 | NPROTO); | ||
2067 | return -ENOBUFS; | 2089 | return -ENOBUFS; |
2068 | } | 2090 | } |
2069 | net_family_write_lock(); | 2091 | |
2070 | err = -EEXIST; | 2092 | spin_lock(&net_family_lock); |
2071 | if (net_families[ops->family] == NULL) { | 2093 | if (net_families[ops->family]) |
2072 | net_families[ops->family]=ops; | 2094 | err = -EEXIST; |
2095 | else { | ||
2096 | net_families[ops->family] = ops; | ||
2073 | err = 0; | 2097 | err = 0; |
2074 | } | 2098 | } |
2075 | net_family_write_unlock(); | 2099 | spin_unlock(&net_family_lock); |
2076 | printk(KERN_INFO "NET: Registered protocol family %d\n", | 2100 | |
2077 | ops->family); | 2101 | printk(KERN_INFO "NET: Registered protocol family %d\n", ops->family); |
2078 | return err; | 2102 | return err; |
2079 | } | 2103 | } |
2080 | 2104 | ||
2081 | /* | 2105 | /** |
2106 | * sock_unregister - remove a protocol handler | ||
2107 | * @family: protocol family to remove | ||
2108 | * | ||
2082 | * This function is called by a protocol handler that wants to | 2109 | * This function is called by a protocol handler that wants to |
2083 | * remove its address family, and have it unlinked from the | 2110 | * remove its address family, and have it unlinked from the |
2084 | * SOCKET module. | 2111 | * new socket creation. |
2112 | * | ||
2113 | * If protocol handler is a module, then it can use module reference | ||
2114 | * counts to protect against new references. If protocol handler is not | ||
2115 | * a module then it needs to provide its own protection in | ||
2116 | * the ops->create routine. | ||
2085 | */ | 2117 | */ |
2086 | 2118 | void sock_unregister(int family) | |
2087 | int sock_unregister(int family) | ||
2088 | { | 2119 | { |
2089 | if (family < 0 || family >= NPROTO) | 2120 | BUG_ON(family < 0 || family >= NPROTO); |
2090 | return -1; | ||
2091 | 2121 | ||
2092 | net_family_write_lock(); | 2122 | spin_lock(&net_family_lock); |
2093 | net_families[family]=NULL; | 2123 | net_families[family] = NULL; |
2094 | net_family_write_unlock(); | 2124 | spin_unlock(&net_family_lock); |
2095 | printk(KERN_INFO "NET: Unregistered protocol family %d\n", | 2125 | |
2096 | family); | 2126 | synchronize_rcu(); |
2097 | return 0; | 2127 | |
2128 | printk(KERN_INFO "NET: Unregistered protocol family %d\n", family); | ||
2098 | } | 2129 | } |
2099 | 2130 | ||
2100 | static int __init sock_init(void) | 2131 | static int __init sock_init(void) |
2101 | { | 2132 | { |
2102 | /* | 2133 | /* |
2103 | * Initialize sock SLAB cache. | 2134 | * Initialize sock SLAB cache. |
2104 | */ | 2135 | */ |
2105 | 2136 | ||
2106 | sk_init(); | 2137 | sk_init(); |
2107 | 2138 | ||
2108 | /* | 2139 | /* |
2109 | * Initialize skbuff SLAB cache | 2140 | * Initialize skbuff SLAB cache |
2110 | */ | 2141 | */ |
2111 | skb_init(); | 2142 | skb_init(); |
2112 | 2143 | ||
2113 | /* | 2144 | /* |
2114 | * Initialize the protocols module. | 2145 | * Initialize the protocols module. |
2115 | */ | 2146 | */ |
2116 | 2147 | ||
2117 | init_inodecache(); | 2148 | init_inodecache(); |
@@ -2137,7 +2168,7 @@ void socket_seq_show(struct seq_file *seq) | |||
2137 | int counter = 0; | 2168 | int counter = 0; |
2138 | 2169 | ||
2139 | for_each_possible_cpu(cpu) | 2170 | for_each_possible_cpu(cpu) |
2140 | counter += per_cpu(sockets_in_use, cpu); | 2171 | counter += per_cpu(sockets_in_use, cpu); |
2141 | 2172 | ||
2142 | /* It can be negative, by the way. 8) */ | 2173 | /* It can be negative, by the way. 8) */ |
2143 | if (counter < 0) | 2174 | if (counter < 0) |
@@ -2145,11 +2176,11 @@ void socket_seq_show(struct seq_file *seq) | |||
2145 | 2176 | ||
2146 | seq_printf(seq, "sockets: used %d\n", counter); | 2177 | seq_printf(seq, "sockets: used %d\n", counter); |
2147 | } | 2178 | } |
2148 | #endif /* CONFIG_PROC_FS */ | 2179 | #endif /* CONFIG_PROC_FS */ |
2149 | 2180 | ||
2150 | #ifdef CONFIG_COMPAT | 2181 | #ifdef CONFIG_COMPAT |
2151 | static long compat_sock_ioctl(struct file *file, unsigned cmd, | 2182 | static long compat_sock_ioctl(struct file *file, unsigned cmd, |
2152 | unsigned long arg) | 2183 | unsigned long arg) |
2153 | { | 2184 | { |
2154 | struct socket *sock = file->private_data; | 2185 | struct socket *sock = file->private_data; |
2155 | int ret = -ENOIOCTLCMD; | 2186 | int ret = -ENOIOCTLCMD; |
@@ -2161,6 +2192,109 @@ static long compat_sock_ioctl(struct file *file, unsigned cmd, | |||
2161 | } | 2192 | } |
2162 | #endif | 2193 | #endif |
2163 | 2194 | ||
2195 | int kernel_bind(struct socket *sock, struct sockaddr *addr, int addrlen) | ||
2196 | { | ||
2197 | return sock->ops->bind(sock, addr, addrlen); | ||
2198 | } | ||
2199 | |||
2200 | int kernel_listen(struct socket *sock, int backlog) | ||
2201 | { | ||
2202 | return sock->ops->listen(sock, backlog); | ||
2203 | } | ||
2204 | |||
2205 | int kernel_accept(struct socket *sock, struct socket **newsock, int flags) | ||
2206 | { | ||
2207 | struct sock *sk = sock->sk; | ||
2208 | int err; | ||
2209 | |||
2210 | err = sock_create_lite(sk->sk_family, sk->sk_type, sk->sk_protocol, | ||
2211 | newsock); | ||
2212 | if (err < 0) | ||
2213 | goto done; | ||
2214 | |||
2215 | err = sock->ops->accept(sock, *newsock, flags); | ||
2216 | if (err < 0) { | ||
2217 | sock_release(*newsock); | ||
2218 | goto done; | ||
2219 | } | ||
2220 | |||
2221 | (*newsock)->ops = sock->ops; | ||
2222 | |||
2223 | done: | ||
2224 | return err; | ||
2225 | } | ||
2226 | |||
2227 | int kernel_connect(struct socket *sock, struct sockaddr *addr, int addrlen, | ||
2228 | int flags) | ||
2229 | { | ||
2230 | return sock->ops->connect(sock, addr, addrlen, flags); | ||
2231 | } | ||
2232 | |||
2233 | int kernel_getsockname(struct socket *sock, struct sockaddr *addr, | ||
2234 | int *addrlen) | ||
2235 | { | ||
2236 | return sock->ops->getname(sock, addr, addrlen, 0); | ||
2237 | } | ||
2238 | |||
2239 | int kernel_getpeername(struct socket *sock, struct sockaddr *addr, | ||
2240 | int *addrlen) | ||
2241 | { | ||
2242 | return sock->ops->getname(sock, addr, addrlen, 1); | ||
2243 | } | ||
2244 | |||
2245 | int kernel_getsockopt(struct socket *sock, int level, int optname, | ||
2246 | char *optval, int *optlen) | ||
2247 | { | ||
2248 | mm_segment_t oldfs = get_fs(); | ||
2249 | int err; | ||
2250 | |||
2251 | set_fs(KERNEL_DS); | ||
2252 | if (level == SOL_SOCKET) | ||
2253 | err = sock_getsockopt(sock, level, optname, optval, optlen); | ||
2254 | else | ||
2255 | err = sock->ops->getsockopt(sock, level, optname, optval, | ||
2256 | optlen); | ||
2257 | set_fs(oldfs); | ||
2258 | return err; | ||
2259 | } | ||
2260 | |||
2261 | int kernel_setsockopt(struct socket *sock, int level, int optname, | ||
2262 | char *optval, int optlen) | ||
2263 | { | ||
2264 | mm_segment_t oldfs = get_fs(); | ||
2265 | int err; | ||
2266 | |||
2267 | set_fs(KERNEL_DS); | ||
2268 | if (level == SOL_SOCKET) | ||
2269 | err = sock_setsockopt(sock, level, optname, optval, optlen); | ||
2270 | else | ||
2271 | err = sock->ops->setsockopt(sock, level, optname, optval, | ||
2272 | optlen); | ||
2273 | set_fs(oldfs); | ||
2274 | return err; | ||
2275 | } | ||
2276 | |||
2277 | int kernel_sendpage(struct socket *sock, struct page *page, int offset, | ||
2278 | size_t size, int flags) | ||
2279 | { | ||
2280 | if (sock->ops->sendpage) | ||
2281 | return sock->ops->sendpage(sock, page, offset, size, flags); | ||
2282 | |||
2283 | return sock_no_sendpage(sock, page, offset, size, flags); | ||
2284 | } | ||
2285 | |||
2286 | int kernel_sock_ioctl(struct socket *sock, int cmd, unsigned long arg) | ||
2287 | { | ||
2288 | mm_segment_t oldfs = get_fs(); | ||
2289 | int err; | ||
2290 | |||
2291 | set_fs(KERNEL_DS); | ||
2292 | err = sock->ops->ioctl(sock, cmd, arg); | ||
2293 | set_fs(oldfs); | ||
2294 | |||
2295 | return err; | ||
2296 | } | ||
2297 | |||
2164 | /* ABI emulation layers need these two */ | 2298 | /* ABI emulation layers need these two */ |
2165 | EXPORT_SYMBOL(move_addr_to_kernel); | 2299 | EXPORT_SYMBOL(move_addr_to_kernel); |
2166 | EXPORT_SYMBOL(move_addr_to_user); | 2300 | EXPORT_SYMBOL(move_addr_to_user); |
@@ -2177,3 +2311,13 @@ EXPORT_SYMBOL(sock_wake_async); | |||
2177 | EXPORT_SYMBOL(sockfd_lookup); | 2311 | EXPORT_SYMBOL(sockfd_lookup); |
2178 | EXPORT_SYMBOL(kernel_sendmsg); | 2312 | EXPORT_SYMBOL(kernel_sendmsg); |
2179 | EXPORT_SYMBOL(kernel_recvmsg); | 2313 | EXPORT_SYMBOL(kernel_recvmsg); |
2314 | EXPORT_SYMBOL(kernel_bind); | ||
2315 | EXPORT_SYMBOL(kernel_listen); | ||
2316 | EXPORT_SYMBOL(kernel_accept); | ||
2317 | EXPORT_SYMBOL(kernel_connect); | ||
2318 | EXPORT_SYMBOL(kernel_getsockname); | ||
2319 | EXPORT_SYMBOL(kernel_getpeername); | ||
2320 | EXPORT_SYMBOL(kernel_getsockopt); | ||
2321 | EXPORT_SYMBOL(kernel_setsockopt); | ||
2322 | EXPORT_SYMBOL(kernel_sendpage); | ||
2323 | EXPORT_SYMBOL(kernel_sock_ioctl); | ||
diff --git a/net/sunrpc/auth_gss/auth_gss.c b/net/sunrpc/auth_gss/auth_gss.c index ef1cf5b476c8..6eed3e166ba3 100644 --- a/net/sunrpc/auth_gss/auth_gss.c +++ b/net/sunrpc/auth_gss/auth_gss.c | |||
@@ -88,7 +88,6 @@ struct gss_auth { | |||
88 | struct list_head upcalls; | 88 | struct list_head upcalls; |
89 | struct rpc_clnt *client; | 89 | struct rpc_clnt *client; |
90 | struct dentry *dentry; | 90 | struct dentry *dentry; |
91 | char path[48]; | ||
92 | spinlock_t lock; | 91 | spinlock_t lock; |
93 | }; | 92 | }; |
94 | 93 | ||
@@ -690,10 +689,8 @@ gss_create(struct rpc_clnt *clnt, rpc_authflavor_t flavor) | |||
690 | if (err) | 689 | if (err) |
691 | goto err_put_mech; | 690 | goto err_put_mech; |
692 | 691 | ||
693 | snprintf(gss_auth->path, sizeof(gss_auth->path), "%s/%s", | 692 | gss_auth->dentry = rpc_mkpipe(clnt->cl_dentry, gss_auth->mech->gm_name, |
694 | clnt->cl_pathname, | 693 | clnt, &gss_upcall_ops, RPC_PIPE_WAIT_FOR_OPEN); |
695 | gss_auth->mech->gm_name); | ||
696 | gss_auth->dentry = rpc_mkpipe(gss_auth->path, clnt, &gss_upcall_ops, RPC_PIPE_WAIT_FOR_OPEN); | ||
697 | if (IS_ERR(gss_auth->dentry)) { | 694 | if (IS_ERR(gss_auth->dentry)) { |
698 | err = PTR_ERR(gss_auth->dentry); | 695 | err = PTR_ERR(gss_auth->dentry); |
699 | goto err_put_mech; | 696 | goto err_put_mech; |
diff --git a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c index 3e19d321067a..084a0ad5c64e 100644 --- a/net/sunrpc/clnt.c +++ b/net/sunrpc/clnt.c | |||
@@ -97,17 +97,7 @@ rpc_setup_pipedir(struct rpc_clnt *clnt, char *dir_name) | |||
97 | } | 97 | } |
98 | } | 98 | } |
99 | 99 | ||
100 | /* | 100 | static struct rpc_clnt * rpc_new_client(struct rpc_xprt *xprt, char *servname, struct rpc_program *program, u32 vers, rpc_authflavor_t flavor) |
101 | * Create an RPC client | ||
102 | * FIXME: This should also take a flags argument (as in task->tk_flags). | ||
103 | * It's called (among others) from pmap_create_client, which may in | ||
104 | * turn be called by an async task. In this case, rpciod should not be | ||
105 | * made to sleep too long. | ||
106 | */ | ||
107 | struct rpc_clnt * | ||
108 | rpc_new_client(struct rpc_xprt *xprt, char *servname, | ||
109 | struct rpc_program *program, u32 vers, | ||
110 | rpc_authflavor_t flavor) | ||
111 | { | 101 | { |
112 | struct rpc_version *version; | 102 | struct rpc_version *version; |
113 | struct rpc_clnt *clnt = NULL; | 103 | struct rpc_clnt *clnt = NULL; |
@@ -147,16 +137,12 @@ rpc_new_client(struct rpc_xprt *xprt, char *servname, | |||
147 | clnt->cl_procinfo = version->procs; | 137 | clnt->cl_procinfo = version->procs; |
148 | clnt->cl_maxproc = version->nrprocs; | 138 | clnt->cl_maxproc = version->nrprocs; |
149 | clnt->cl_protname = program->name; | 139 | clnt->cl_protname = program->name; |
150 | clnt->cl_pmap = &clnt->cl_pmap_default; | ||
151 | clnt->cl_port = xprt->addr.sin_port; | ||
152 | clnt->cl_prog = program->number; | 140 | clnt->cl_prog = program->number; |
153 | clnt->cl_vers = version->number; | 141 | clnt->cl_vers = version->number; |
154 | clnt->cl_prot = xprt->prot; | ||
155 | clnt->cl_stats = program->stats; | 142 | clnt->cl_stats = program->stats; |
156 | clnt->cl_metrics = rpc_alloc_iostats(clnt); | 143 | clnt->cl_metrics = rpc_alloc_iostats(clnt); |
157 | rpc_init_wait_queue(&clnt->cl_pmap_default.pm_bindwait, "bindwait"); | ||
158 | 144 | ||
159 | if (!clnt->cl_port) | 145 | if (!xprt_bound(clnt->cl_xprt)) |
160 | clnt->cl_autobind = 1; | 146 | clnt->cl_autobind = 1; |
161 | 147 | ||
162 | clnt->cl_rtt = &clnt->cl_rtt_default; | 148 | clnt->cl_rtt = &clnt->cl_rtt_default; |
@@ -191,40 +177,71 @@ out_no_path: | |||
191 | kfree(clnt->cl_server); | 177 | kfree(clnt->cl_server); |
192 | kfree(clnt); | 178 | kfree(clnt); |
193 | out_err: | 179 | out_err: |
194 | xprt_destroy(xprt); | 180 | xprt_put(xprt); |
195 | out_no_xprt: | 181 | out_no_xprt: |
196 | return ERR_PTR(err); | 182 | return ERR_PTR(err); |
197 | } | 183 | } |
198 | 184 | ||
199 | /** | 185 | /* |
200 | * Create an RPC client | 186 | * rpc_create - create an RPC client and transport with one call |
201 | * @xprt - pointer to xprt struct | 187 | * @args: rpc_clnt create argument structure |
202 | * @servname - name of server | ||
203 | * @info - rpc_program | ||
204 | * @version - rpc_program version | ||
205 | * @authflavor - rpc_auth flavour to use | ||
206 | * | 188 | * |
207 | * Creates an RPC client structure, then pings the server in order to | 189 | * Creates and initializes an RPC transport and an RPC client. |
208 | * determine if it is up, and if it supports this program and version. | ||
209 | * | 190 | * |
210 | * This function should never be called by asynchronous tasks such as | 191 | * It can ping the server in order to determine if it is up, and to see if |
211 | * the portmapper. | 192 | * it supports this program and version. RPC_CLNT_CREATE_NOPING disables |
193 | * this behavior so asynchronous tasks can also use rpc_create. | ||
212 | */ | 194 | */ |
213 | struct rpc_clnt *rpc_create_client(struct rpc_xprt *xprt, char *servname, | 195 | struct rpc_clnt *rpc_create(struct rpc_create_args *args) |
214 | struct rpc_program *info, u32 version, rpc_authflavor_t authflavor) | ||
215 | { | 196 | { |
197 | struct rpc_xprt *xprt; | ||
216 | struct rpc_clnt *clnt; | 198 | struct rpc_clnt *clnt; |
217 | int err; | 199 | |
218 | 200 | xprt = xprt_create_transport(args->protocol, args->address, | |
219 | clnt = rpc_new_client(xprt, servname, info, version, authflavor); | 201 | args->addrsize, args->timeout); |
202 | if (IS_ERR(xprt)) | ||
203 | return (struct rpc_clnt *)xprt; | ||
204 | |||
205 | /* | ||
206 | * By default, kernel RPC client connects from a reserved port. | ||
207 | * CAP_NET_BIND_SERVICE will not be set for unprivileged requesters, | ||
208 | * but it is always enabled for rpciod, which handles the connect | ||
209 | * operation. | ||
210 | */ | ||
211 | xprt->resvport = 1; | ||
212 | if (args->flags & RPC_CLNT_CREATE_NONPRIVPORT) | ||
213 | xprt->resvport = 0; | ||
214 | |||
215 | dprintk("RPC: creating %s client for %s (xprt %p)\n", | ||
216 | args->program->name, args->servername, xprt); | ||
217 | |||
218 | clnt = rpc_new_client(xprt, args->servername, args->program, | ||
219 | args->version, args->authflavor); | ||
220 | if (IS_ERR(clnt)) | 220 | if (IS_ERR(clnt)) |
221 | return clnt; | 221 | return clnt; |
222 | err = rpc_ping(clnt, RPC_TASK_SOFT|RPC_TASK_NOINTR); | 222 | |
223 | if (err == 0) | 223 | if (!(args->flags & RPC_CLNT_CREATE_NOPING)) { |
224 | return clnt; | 224 | int err = rpc_ping(clnt, RPC_TASK_SOFT|RPC_TASK_NOINTR); |
225 | rpc_shutdown_client(clnt); | 225 | if (err != 0) { |
226 | return ERR_PTR(err); | 226 | rpc_shutdown_client(clnt); |
227 | return ERR_PTR(err); | ||
228 | } | ||
229 | } | ||
230 | |||
231 | clnt->cl_softrtry = 1; | ||
232 | if (args->flags & RPC_CLNT_CREATE_HARDRTRY) | ||
233 | clnt->cl_softrtry = 0; | ||
234 | |||
235 | if (args->flags & RPC_CLNT_CREATE_INTR) | ||
236 | clnt->cl_intr = 1; | ||
237 | if (args->flags & RPC_CLNT_CREATE_AUTOBIND) | ||
238 | clnt->cl_autobind = 1; | ||
239 | if (args->flags & RPC_CLNT_CREATE_ONESHOT) | ||
240 | clnt->cl_oneshot = 1; | ||
241 | |||
242 | return clnt; | ||
227 | } | 243 | } |
244 | EXPORT_SYMBOL_GPL(rpc_create); | ||
228 | 245 | ||
229 | /* | 246 | /* |
230 | * This function clones the RPC client structure. It allows us to share the | 247 | * This function clones the RPC client structure. It allows us to share the |
@@ -244,8 +261,7 @@ rpc_clone_client(struct rpc_clnt *clnt) | |||
244 | atomic_set(&new->cl_users, 0); | 261 | atomic_set(&new->cl_users, 0); |
245 | new->cl_parent = clnt; | 262 | new->cl_parent = clnt; |
246 | atomic_inc(&clnt->cl_count); | 263 | atomic_inc(&clnt->cl_count); |
247 | /* Duplicate portmapper */ | 264 | new->cl_xprt = xprt_get(clnt->cl_xprt); |
248 | rpc_init_wait_queue(&new->cl_pmap_default.pm_bindwait, "bindwait"); | ||
249 | /* Turn off autobind on clones */ | 265 | /* Turn off autobind on clones */ |
250 | new->cl_autobind = 0; | 266 | new->cl_autobind = 0; |
251 | new->cl_oneshot = 0; | 267 | new->cl_oneshot = 0; |
@@ -255,8 +271,7 @@ rpc_clone_client(struct rpc_clnt *clnt) | |||
255 | rpc_init_rtt(&new->cl_rtt_default, clnt->cl_xprt->timeout.to_initval); | 271 | rpc_init_rtt(&new->cl_rtt_default, clnt->cl_xprt->timeout.to_initval); |
256 | if (new->cl_auth) | 272 | if (new->cl_auth) |
257 | atomic_inc(&new->cl_auth->au_count); | 273 | atomic_inc(&new->cl_auth->au_count); |
258 | new->cl_pmap = &new->cl_pmap_default; | 274 | new->cl_metrics = rpc_alloc_iostats(clnt); |
259 | new->cl_metrics = rpc_alloc_iostats(clnt); | ||
260 | return new; | 275 | return new; |
261 | out_no_clnt: | 276 | out_no_clnt: |
262 | printk(KERN_INFO "RPC: out of memory in %s\n", __FUNCTION__); | 277 | printk(KERN_INFO "RPC: out of memory in %s\n", __FUNCTION__); |
@@ -323,15 +338,12 @@ rpc_destroy_client(struct rpc_clnt *clnt) | |||
323 | rpc_rmdir(clnt->cl_dentry); | 338 | rpc_rmdir(clnt->cl_dentry); |
324 | rpc_put_mount(); | 339 | rpc_put_mount(); |
325 | } | 340 | } |
326 | if (clnt->cl_xprt) { | ||
327 | xprt_destroy(clnt->cl_xprt); | ||
328 | clnt->cl_xprt = NULL; | ||
329 | } | ||
330 | if (clnt->cl_server != clnt->cl_inline_name) | 341 | if (clnt->cl_server != clnt->cl_inline_name) |
331 | kfree(clnt->cl_server); | 342 | kfree(clnt->cl_server); |
332 | out_free: | 343 | out_free: |
333 | rpc_free_iostats(clnt->cl_metrics); | 344 | rpc_free_iostats(clnt->cl_metrics); |
334 | clnt->cl_metrics = NULL; | 345 | clnt->cl_metrics = NULL; |
346 | xprt_put(clnt->cl_xprt); | ||
335 | kfree(clnt); | 347 | kfree(clnt); |
336 | return 0; | 348 | return 0; |
337 | } | 349 | } |
@@ -540,6 +552,40 @@ rpc_call_setup(struct rpc_task *task, struct rpc_message *msg, int flags) | |||
540 | task->tk_action = rpc_exit_task; | 552 | task->tk_action = rpc_exit_task; |
541 | } | 553 | } |
542 | 554 | ||
555 | /** | ||
556 | * rpc_peeraddr - extract remote peer address from clnt's xprt | ||
557 | * @clnt: RPC client structure | ||
558 | * @buf: target buffer | ||
559 | * @size: length of target buffer | ||
560 | * | ||
561 | * Returns the number of bytes that are actually in the stored address. | ||
562 | */ | ||
563 | size_t rpc_peeraddr(struct rpc_clnt *clnt, struct sockaddr *buf, size_t bufsize) | ||
564 | { | ||
565 | size_t bytes; | ||
566 | struct rpc_xprt *xprt = clnt->cl_xprt; | ||
567 | |||
568 | bytes = sizeof(xprt->addr); | ||
569 | if (bytes > bufsize) | ||
570 | bytes = bufsize; | ||
571 | memcpy(buf, &clnt->cl_xprt->addr, bytes); | ||
572 | return xprt->addrlen; | ||
573 | } | ||
574 | EXPORT_SYMBOL_GPL(rpc_peeraddr); | ||
575 | |||
576 | /** | ||
577 | * rpc_peeraddr2str - return remote peer address in printable format | ||
578 | * @clnt: RPC client structure | ||
579 | * @format: address format | ||
580 | * | ||
581 | */ | ||
582 | char *rpc_peeraddr2str(struct rpc_clnt *clnt, enum rpc_display_format_t format) | ||
583 | { | ||
584 | struct rpc_xprt *xprt = clnt->cl_xprt; | ||
585 | return xprt->ops->print_addr(xprt, format); | ||
586 | } | ||
587 | EXPORT_SYMBOL_GPL(rpc_peeraddr2str); | ||
588 | |||
543 | void | 589 | void |
544 | rpc_setbufsize(struct rpc_clnt *clnt, unsigned int sndsize, unsigned int rcvsize) | 590 | rpc_setbufsize(struct rpc_clnt *clnt, unsigned int sndsize, unsigned int rcvsize) |
545 | { | 591 | { |
@@ -560,7 +606,7 @@ size_t rpc_max_payload(struct rpc_clnt *clnt) | |||
560 | { | 606 | { |
561 | return clnt->cl_xprt->max_payload; | 607 | return clnt->cl_xprt->max_payload; |
562 | } | 608 | } |
563 | EXPORT_SYMBOL(rpc_max_payload); | 609 | EXPORT_SYMBOL_GPL(rpc_max_payload); |
564 | 610 | ||
565 | /** | 611 | /** |
566 | * rpc_force_rebind - force transport to check that remote port is unchanged | 612 | * rpc_force_rebind - force transport to check that remote port is unchanged |
@@ -570,9 +616,9 @@ EXPORT_SYMBOL(rpc_max_payload); | |||
570 | void rpc_force_rebind(struct rpc_clnt *clnt) | 616 | void rpc_force_rebind(struct rpc_clnt *clnt) |
571 | { | 617 | { |
572 | if (clnt->cl_autobind) | 618 | if (clnt->cl_autobind) |
573 | clnt->cl_port = 0; | 619 | xprt_clear_bound(clnt->cl_xprt); |
574 | } | 620 | } |
575 | EXPORT_SYMBOL(rpc_force_rebind); | 621 | EXPORT_SYMBOL_GPL(rpc_force_rebind); |
576 | 622 | ||
577 | /* | 623 | /* |
578 | * Restart an (async) RPC call. Usually called from within the | 624 | * Restart an (async) RPC call. Usually called from within the |
@@ -781,16 +827,16 @@ call_encode(struct rpc_task *task) | |||
781 | static void | 827 | static void |
782 | call_bind(struct rpc_task *task) | 828 | call_bind(struct rpc_task *task) |
783 | { | 829 | { |
784 | struct rpc_clnt *clnt = task->tk_client; | 830 | struct rpc_xprt *xprt = task->tk_xprt; |
785 | 831 | ||
786 | dprintk("RPC: %4d call_bind (status %d)\n", | 832 | dprintk("RPC: %4d call_bind (status %d)\n", |
787 | task->tk_pid, task->tk_status); | 833 | task->tk_pid, task->tk_status); |
788 | 834 | ||
789 | task->tk_action = call_connect; | 835 | task->tk_action = call_connect; |
790 | if (!clnt->cl_port) { | 836 | if (!xprt_bound(xprt)) { |
791 | task->tk_action = call_bind_status; | 837 | task->tk_action = call_bind_status; |
792 | task->tk_timeout = task->tk_xprt->bind_timeout; | 838 | task->tk_timeout = xprt->bind_timeout; |
793 | rpc_getport(task, clnt); | 839 | xprt->ops->rpcbind(task); |
794 | } | 840 | } |
795 | } | 841 | } |
796 | 842 | ||
@@ -815,15 +861,11 @@ call_bind_status(struct rpc_task *task) | |||
815 | dprintk("RPC: %4d remote rpcbind: RPC program/version unavailable\n", | 861 | dprintk("RPC: %4d remote rpcbind: RPC program/version unavailable\n", |
816 | task->tk_pid); | 862 | task->tk_pid); |
817 | rpc_delay(task, 3*HZ); | 863 | rpc_delay(task, 3*HZ); |
818 | goto retry_bind; | 864 | goto retry_timeout; |
819 | case -ETIMEDOUT: | 865 | case -ETIMEDOUT: |
820 | dprintk("RPC: %4d rpcbind request timed out\n", | 866 | dprintk("RPC: %4d rpcbind request timed out\n", |
821 | task->tk_pid); | 867 | task->tk_pid); |
822 | if (RPC_IS_SOFT(task)) { | 868 | goto retry_timeout; |
823 | status = -EIO; | ||
824 | break; | ||
825 | } | ||
826 | goto retry_bind; | ||
827 | case -EPFNOSUPPORT: | 869 | case -EPFNOSUPPORT: |
828 | dprintk("RPC: %4d remote rpcbind service unavailable\n", | 870 | dprintk("RPC: %4d remote rpcbind service unavailable\n", |
829 | task->tk_pid); | 871 | task->tk_pid); |
@@ -836,16 +878,13 @@ call_bind_status(struct rpc_task *task) | |||
836 | dprintk("RPC: %4d unrecognized rpcbind error (%d)\n", | 878 | dprintk("RPC: %4d unrecognized rpcbind error (%d)\n", |
837 | task->tk_pid, -task->tk_status); | 879 | task->tk_pid, -task->tk_status); |
838 | status = -EIO; | 880 | status = -EIO; |
839 | break; | ||
840 | } | 881 | } |
841 | 882 | ||
842 | rpc_exit(task, status); | 883 | rpc_exit(task, status); |
843 | return; | 884 | return; |
844 | 885 | ||
845 | retry_bind: | 886 | retry_timeout: |
846 | task->tk_status = 0; | 887 | task->tk_action = call_timeout; |
847 | task->tk_action = call_bind; | ||
848 | return; | ||
849 | } | 888 | } |
850 | 889 | ||
851 | /* | 890 | /* |
@@ -893,14 +932,16 @@ call_connect_status(struct rpc_task *task) | |||
893 | 932 | ||
894 | switch (status) { | 933 | switch (status) { |
895 | case -ENOTCONN: | 934 | case -ENOTCONN: |
896 | case -ETIMEDOUT: | ||
897 | case -EAGAIN: | 935 | case -EAGAIN: |
898 | task->tk_action = call_bind; | 936 | task->tk_action = call_bind; |
899 | break; | 937 | if (!RPC_IS_SOFT(task)) |
900 | default: | 938 | return; |
901 | rpc_exit(task, -EIO); | 939 | /* if soft mounted, test if we've timed out */ |
902 | break; | 940 | case -ETIMEDOUT: |
941 | task->tk_action = call_timeout; | ||
942 | return; | ||
903 | } | 943 | } |
944 | rpc_exit(task, -EIO); | ||
904 | } | 945 | } |
905 | 946 | ||
906 | /* | 947 | /* |
@@ -982,6 +1023,14 @@ call_status(struct rpc_task *task) | |||
982 | 1023 | ||
983 | task->tk_status = 0; | 1024 | task->tk_status = 0; |
984 | switch(status) { | 1025 | switch(status) { |
1026 | case -EHOSTDOWN: | ||
1027 | case -EHOSTUNREACH: | ||
1028 | case -ENETUNREACH: | ||
1029 | /* | ||
1030 | * Delay any retries for 3 seconds, then handle as if it | ||
1031 | * were a timeout. | ||
1032 | */ | ||
1033 | rpc_delay(task, 3*HZ); | ||
985 | case -ETIMEDOUT: | 1034 | case -ETIMEDOUT: |
986 | task->tk_action = call_timeout; | 1035 | task->tk_action = call_timeout; |
987 | break; | 1036 | break; |
@@ -1001,7 +1050,6 @@ call_status(struct rpc_task *task) | |||
1001 | printk("%s: RPC call returned error %d\n", | 1050 | printk("%s: RPC call returned error %d\n", |
1002 | clnt->cl_protname, -status); | 1051 | clnt->cl_protname, -status); |
1003 | rpc_exit(task, status); | 1052 | rpc_exit(task, status); |
1004 | break; | ||
1005 | } | 1053 | } |
1006 | } | 1054 | } |
1007 | 1055 | ||
@@ -1069,10 +1117,10 @@ call_decode(struct rpc_task *task) | |||
1069 | clnt->cl_stats->rpcretrans++; | 1117 | clnt->cl_stats->rpcretrans++; |
1070 | goto out_retry; | 1118 | goto out_retry; |
1071 | } | 1119 | } |
1072 | printk(KERN_WARNING "%s: too small RPC reply size (%d bytes)\n", | 1120 | dprintk("%s: too small RPC reply size (%d bytes)\n", |
1073 | clnt->cl_protname, task->tk_status); | 1121 | clnt->cl_protname, task->tk_status); |
1074 | rpc_exit(task, -EIO); | 1122 | task->tk_action = call_timeout; |
1075 | return; | 1123 | goto out_retry; |
1076 | } | 1124 | } |
1077 | 1125 | ||
1078 | /* | 1126 | /* |
diff --git a/net/sunrpc/pmap_clnt.c b/net/sunrpc/pmap_clnt.c index 623180f224c9..c04609d3476a 100644 --- a/net/sunrpc/pmap_clnt.c +++ b/net/sunrpc/pmap_clnt.c | |||
@@ -1,7 +1,9 @@ | |||
1 | /* | 1 | /* |
2 | * linux/net/sunrpc/pmap.c | 2 | * linux/net/sunrpc/pmap_clnt.c |
3 | * | 3 | * |
4 | * Portmapper client. | 4 | * In-kernel RPC portmapper client. |
5 | * | ||
6 | * Portmapper supports version 2 of the rpcbind protocol (RFC 1833). | ||
5 | * | 7 | * |
6 | * Copyright (C) 1996, Olaf Kirch <okir@monad.swb.de> | 8 | * Copyright (C) 1996, Olaf Kirch <okir@monad.swb.de> |
7 | */ | 9 | */ |
@@ -13,7 +15,6 @@ | |||
13 | #include <linux/uio.h> | 15 | #include <linux/uio.h> |
14 | #include <linux/in.h> | 16 | #include <linux/in.h> |
15 | #include <linux/sunrpc/clnt.h> | 17 | #include <linux/sunrpc/clnt.h> |
16 | #include <linux/sunrpc/xprt.h> | ||
17 | #include <linux/sunrpc/sched.h> | 18 | #include <linux/sunrpc/sched.h> |
18 | 19 | ||
19 | #ifdef RPC_DEBUG | 20 | #ifdef RPC_DEBUG |
@@ -24,80 +25,141 @@ | |||
24 | #define PMAP_UNSET 2 | 25 | #define PMAP_UNSET 2 |
25 | #define PMAP_GETPORT 3 | 26 | #define PMAP_GETPORT 3 |
26 | 27 | ||
28 | struct portmap_args { | ||
29 | u32 pm_prog; | ||
30 | u32 pm_vers; | ||
31 | u32 pm_prot; | ||
32 | unsigned short pm_port; | ||
33 | struct rpc_xprt * pm_xprt; | ||
34 | }; | ||
35 | |||
27 | static struct rpc_procinfo pmap_procedures[]; | 36 | static struct rpc_procinfo pmap_procedures[]; |
28 | static struct rpc_clnt * pmap_create(char *, struct sockaddr_in *, int, int); | 37 | static struct rpc_clnt * pmap_create(char *, struct sockaddr_in *, int, int); |
29 | static void pmap_getport_done(struct rpc_task *); | 38 | static void pmap_getport_done(struct rpc_task *, void *); |
30 | static struct rpc_program pmap_program; | 39 | static struct rpc_program pmap_program; |
31 | static DEFINE_SPINLOCK(pmap_lock); | ||
32 | 40 | ||
33 | /* | 41 | static void pmap_getport_prepare(struct rpc_task *task, void *calldata) |
34 | * Obtain the port for a given RPC service on a given host. This one can | ||
35 | * be called for an ongoing RPC request. | ||
36 | */ | ||
37 | void | ||
38 | rpc_getport(struct rpc_task *task, struct rpc_clnt *clnt) | ||
39 | { | 42 | { |
40 | struct rpc_portmap *map = clnt->cl_pmap; | 43 | struct portmap_args *map = calldata; |
41 | struct sockaddr_in *sap = &clnt->cl_xprt->addr; | ||
42 | struct rpc_message msg = { | 44 | struct rpc_message msg = { |
43 | .rpc_proc = &pmap_procedures[PMAP_GETPORT], | 45 | .rpc_proc = &pmap_procedures[PMAP_GETPORT], |
44 | .rpc_argp = map, | 46 | .rpc_argp = map, |
45 | .rpc_resp = &clnt->cl_port, | 47 | .rpc_resp = &map->pm_port, |
46 | .rpc_cred = NULL | ||
47 | }; | 48 | }; |
49 | |||
50 | rpc_call_setup(task, &msg, 0); | ||
51 | } | ||
52 | |||
53 | static inline struct portmap_args *pmap_map_alloc(void) | ||
54 | { | ||
55 | return kmalloc(sizeof(struct portmap_args), GFP_NOFS); | ||
56 | } | ||
57 | |||
58 | static inline void pmap_map_free(struct portmap_args *map) | ||
59 | { | ||
60 | kfree(map); | ||
61 | } | ||
62 | |||
63 | static void pmap_map_release(void *data) | ||
64 | { | ||
65 | pmap_map_free(data); | ||
66 | } | ||
67 | |||
68 | static const struct rpc_call_ops pmap_getport_ops = { | ||
69 | .rpc_call_prepare = pmap_getport_prepare, | ||
70 | .rpc_call_done = pmap_getport_done, | ||
71 | .rpc_release = pmap_map_release, | ||
72 | }; | ||
73 | |||
74 | static inline void pmap_wake_portmap_waiters(struct rpc_xprt *xprt, int status) | ||
75 | { | ||
76 | xprt_clear_binding(xprt); | ||
77 | rpc_wake_up_status(&xprt->binding, status); | ||
78 | } | ||
79 | |||
80 | /** | ||
81 | * rpc_getport - obtain the port for a given RPC service on a given host | ||
82 | * @task: task that is waiting for portmapper request | ||
83 | * | ||
84 | * This one can be called for an ongoing RPC request, and can be used in | ||
85 | * an async (rpciod) context. | ||
86 | */ | ||
87 | void rpc_getport(struct rpc_task *task) | ||
88 | { | ||
89 | struct rpc_clnt *clnt = task->tk_client; | ||
90 | struct rpc_xprt *xprt = task->tk_xprt; | ||
91 | struct sockaddr_in addr; | ||
92 | struct portmap_args *map; | ||
48 | struct rpc_clnt *pmap_clnt; | 93 | struct rpc_clnt *pmap_clnt; |
49 | struct rpc_task *child; | 94 | struct rpc_task *child; |
95 | int status; | ||
50 | 96 | ||
51 | dprintk("RPC: %4d rpc_getport(%s, %d, %d, %d)\n", | 97 | dprintk("RPC: %4d rpc_getport(%s, %u, %u, %d)\n", |
52 | task->tk_pid, clnt->cl_server, | 98 | task->tk_pid, clnt->cl_server, |
53 | map->pm_prog, map->pm_vers, map->pm_prot); | 99 | clnt->cl_prog, clnt->cl_vers, xprt->prot); |
54 | 100 | ||
55 | /* Autobind on cloned rpc clients is discouraged */ | 101 | /* Autobind on cloned rpc clients is discouraged */ |
56 | BUG_ON(clnt->cl_parent != clnt); | 102 | BUG_ON(clnt->cl_parent != clnt); |
57 | 103 | ||
58 | spin_lock(&pmap_lock); | 104 | if (xprt_test_and_set_binding(xprt)) { |
59 | if (map->pm_binding) { | 105 | task->tk_status = -EACCES; /* tell caller to check again */ |
60 | rpc_sleep_on(&map->pm_bindwait, task, NULL, NULL); | 106 | rpc_sleep_on(&xprt->binding, task, NULL, NULL); |
61 | spin_unlock(&pmap_lock); | ||
62 | return; | 107 | return; |
63 | } | 108 | } |
64 | map->pm_binding = 1; | ||
65 | spin_unlock(&pmap_lock); | ||
66 | 109 | ||
67 | pmap_clnt = pmap_create(clnt->cl_server, sap, map->pm_prot, 0); | 110 | /* Someone else may have bound if we slept */ |
68 | if (IS_ERR(pmap_clnt)) { | 111 | status = 0; |
69 | task->tk_status = PTR_ERR(pmap_clnt); | 112 | if (xprt_bound(xprt)) |
113 | goto bailout_nofree; | ||
114 | |||
115 | status = -ENOMEM; | ||
116 | map = pmap_map_alloc(); | ||
117 | if (!map) | ||
118 | goto bailout_nofree; | ||
119 | map->pm_prog = clnt->cl_prog; | ||
120 | map->pm_vers = clnt->cl_vers; | ||
121 | map->pm_prot = xprt->prot; | ||
122 | map->pm_port = 0; | ||
123 | map->pm_xprt = xprt_get(xprt); | ||
124 | |||
125 | rpc_peeraddr(clnt, (struct sockaddr *) &addr, sizeof(addr)); | ||
126 | pmap_clnt = pmap_create(clnt->cl_server, &addr, map->pm_prot, 0); | ||
127 | status = PTR_ERR(pmap_clnt); | ||
128 | if (IS_ERR(pmap_clnt)) | ||
70 | goto bailout; | 129 | goto bailout; |
71 | } | ||
72 | task->tk_status = 0; | ||
73 | 130 | ||
74 | /* | 131 | status = -EIO; |
75 | * Note: rpc_new_child will release client after a failure. | 132 | child = rpc_run_task(pmap_clnt, RPC_TASK_ASYNC, &pmap_getport_ops, map); |
76 | */ | 133 | if (IS_ERR(child)) |
77 | if (!(child = rpc_new_child(pmap_clnt, task))) | ||
78 | goto bailout; | 134 | goto bailout; |
135 | rpc_release_task(child); | ||
79 | 136 | ||
80 | /* Setup the call info struct */ | 137 | rpc_sleep_on(&xprt->binding, task, NULL, NULL); |
81 | rpc_call_setup(child, &msg, 0); | ||
82 | 138 | ||
83 | /* ... and run the child task */ | ||
84 | task->tk_xprt->stat.bind_count++; | 139 | task->tk_xprt->stat.bind_count++; |
85 | rpc_run_child(task, child, pmap_getport_done); | ||
86 | return; | 140 | return; |
87 | 141 | ||
88 | bailout: | 142 | bailout: |
89 | spin_lock(&pmap_lock); | 143 | pmap_map_free(map); |
90 | map->pm_binding = 0; | 144 | xprt_put(xprt); |
91 | rpc_wake_up(&map->pm_bindwait); | 145 | bailout_nofree: |
92 | spin_unlock(&pmap_lock); | 146 | task->tk_status = status; |
93 | rpc_exit(task, -EIO); | 147 | pmap_wake_portmap_waiters(xprt, status); |
94 | } | 148 | } |
95 | 149 | ||
96 | #ifdef CONFIG_ROOT_NFS | 150 | #ifdef CONFIG_ROOT_NFS |
97 | int | 151 | /** |
98 | rpc_getport_external(struct sockaddr_in *sin, __u32 prog, __u32 vers, int prot) | 152 | * rpc_getport_external - obtain the port for a given RPC service on a given host |
153 | * @sin: address of remote peer | ||
154 | * @prog: RPC program number to bind | ||
155 | * @vers: RPC version number to bind | ||
156 | * @prot: transport protocol to use to make this request | ||
157 | * | ||
158 | * This one is called from outside the RPC client in a synchronous task context. | ||
159 | */ | ||
160 | int rpc_getport_external(struct sockaddr_in *sin, __u32 prog, __u32 vers, int prot) | ||
99 | { | 161 | { |
100 | struct rpc_portmap map = { | 162 | struct portmap_args map = { |
101 | .pm_prog = prog, | 163 | .pm_prog = prog, |
102 | .pm_vers = vers, | 164 | .pm_vers = vers, |
103 | .pm_prot = prot, | 165 | .pm_prot = prot, |
@@ -112,7 +174,7 @@ rpc_getport_external(struct sockaddr_in *sin, __u32 prog, __u32 vers, int prot) | |||
112 | char hostname[32]; | 174 | char hostname[32]; |
113 | int status; | 175 | int status; |
114 | 176 | ||
115 | dprintk("RPC: rpc_getport_external(%u.%u.%u.%u, %d, %d, %d)\n", | 177 | dprintk("RPC: rpc_getport_external(%u.%u.%u.%u, %u, %u, %d)\n", |
116 | NIPQUAD(sin->sin_addr.s_addr), prog, vers, prot); | 178 | NIPQUAD(sin->sin_addr.s_addr), prog, vers, prot); |
117 | 179 | ||
118 | sprintf(hostname, "%u.%u.%u.%u", NIPQUAD(sin->sin_addr.s_addr)); | 180 | sprintf(hostname, "%u.%u.%u.%u", NIPQUAD(sin->sin_addr.s_addr)); |
@@ -132,45 +194,53 @@ rpc_getport_external(struct sockaddr_in *sin, __u32 prog, __u32 vers, int prot) | |||
132 | } | 194 | } |
133 | #endif | 195 | #endif |
134 | 196 | ||
135 | static void | 197 | /* |
136 | pmap_getport_done(struct rpc_task *task) | 198 | * Portmapper child task invokes this callback via tk_exit. |
199 | */ | ||
200 | static void pmap_getport_done(struct rpc_task *child, void *data) | ||
137 | { | 201 | { |
138 | struct rpc_clnt *clnt = task->tk_client; | 202 | struct portmap_args *map = data; |
139 | struct rpc_xprt *xprt = task->tk_xprt; | 203 | struct rpc_xprt *xprt = map->pm_xprt; |
140 | struct rpc_portmap *map = clnt->cl_pmap; | 204 | int status = child->tk_status; |
141 | 205 | ||
142 | dprintk("RPC: %4d pmap_getport_done(status %d, port %d)\n", | 206 | if (status < 0) { |
143 | task->tk_pid, task->tk_status, clnt->cl_port); | 207 | /* Portmapper not available */ |
144 | 208 | xprt->ops->set_port(xprt, 0); | |
145 | xprt->ops->set_port(xprt, 0); | 209 | } else if (map->pm_port == 0) { |
146 | if (task->tk_status < 0) { | 210 | /* Requested RPC service wasn't registered */ |
147 | /* Make the calling task exit with an error */ | 211 | xprt->ops->set_port(xprt, 0); |
148 | task->tk_action = rpc_exit_task; | 212 | status = -EACCES; |
149 | } else if (clnt->cl_port == 0) { | ||
150 | /* Program not registered */ | ||
151 | rpc_exit(task, -EACCES); | ||
152 | } else { | 213 | } else { |
153 | xprt->ops->set_port(xprt, clnt->cl_port); | 214 | /* Succeeded */ |
154 | clnt->cl_port = htons(clnt->cl_port); | 215 | xprt->ops->set_port(xprt, map->pm_port); |
216 | xprt_set_bound(xprt); | ||
217 | status = 0; | ||
155 | } | 218 | } |
156 | spin_lock(&pmap_lock); | 219 | |
157 | map->pm_binding = 0; | 220 | dprintk("RPC: %4d pmap_getport_done(status %d, port %u)\n", |
158 | rpc_wake_up(&map->pm_bindwait); | 221 | child->tk_pid, status, map->pm_port); |
159 | spin_unlock(&pmap_lock); | 222 | |
223 | pmap_wake_portmap_waiters(xprt, status); | ||
224 | xprt_put(xprt); | ||
160 | } | 225 | } |
161 | 226 | ||
162 | /* | 227 | /** |
163 | * Set or unset a port registration with the local portmapper. | 228 | * rpc_register - set or unset a port registration with the local portmapper |
229 | * @prog: RPC program number to bind | ||
230 | * @vers: RPC version number to bind | ||
231 | * @prot: transport protocol to use to make this request | ||
232 | * @port: port value to register | ||
233 | * @okay: result code | ||
234 | * | ||
164 | * port == 0 means unregister, port != 0 means register. | 235 | * port == 0 means unregister, port != 0 means register. |
165 | */ | 236 | */ |
166 | int | 237 | int rpc_register(u32 prog, u32 vers, int prot, unsigned short port, int *okay) |
167 | rpc_register(u32 prog, u32 vers, int prot, unsigned short port, int *okay) | ||
168 | { | 238 | { |
169 | struct sockaddr_in sin = { | 239 | struct sockaddr_in sin = { |
170 | .sin_family = AF_INET, | 240 | .sin_family = AF_INET, |
171 | .sin_addr.s_addr = htonl(INADDR_LOOPBACK), | 241 | .sin_addr.s_addr = htonl(INADDR_LOOPBACK), |
172 | }; | 242 | }; |
173 | struct rpc_portmap map = { | 243 | struct portmap_args map = { |
174 | .pm_prog = prog, | 244 | .pm_prog = prog, |
175 | .pm_vers = vers, | 245 | .pm_vers = vers, |
176 | .pm_prot = prot, | 246 | .pm_prot = prot, |
@@ -184,7 +254,7 @@ rpc_register(u32 prog, u32 vers, int prot, unsigned short port, int *okay) | |||
184 | struct rpc_clnt *pmap_clnt; | 254 | struct rpc_clnt *pmap_clnt; |
185 | int error = 0; | 255 | int error = 0; |
186 | 256 | ||
187 | dprintk("RPC: registering (%d, %d, %d, %d) with portmapper.\n", | 257 | dprintk("RPC: registering (%u, %u, %d, %u) with portmapper.\n", |
188 | prog, vers, prot, port); | 258 | prog, vers, prot, port); |
189 | 259 | ||
190 | pmap_clnt = pmap_create("localhost", &sin, IPPROTO_UDP, 1); | 260 | pmap_clnt = pmap_create("localhost", &sin, IPPROTO_UDP, 1); |
@@ -207,38 +277,32 @@ rpc_register(u32 prog, u32 vers, int prot, unsigned short port, int *okay) | |||
207 | return error; | 277 | return error; |
208 | } | 278 | } |
209 | 279 | ||
210 | static struct rpc_clnt * | 280 | static struct rpc_clnt *pmap_create(char *hostname, struct sockaddr_in *srvaddr, int proto, int privileged) |
211 | pmap_create(char *hostname, struct sockaddr_in *srvaddr, int proto, int privileged) | ||
212 | { | 281 | { |
213 | struct rpc_xprt *xprt; | 282 | struct rpc_create_args args = { |
214 | struct rpc_clnt *clnt; | 283 | .protocol = proto, |
215 | 284 | .address = (struct sockaddr *)srvaddr, | |
216 | /* printk("pmap: create xprt\n"); */ | 285 | .addrsize = sizeof(*srvaddr), |
217 | xprt = xprt_create_proto(proto, srvaddr, NULL); | 286 | .servername = hostname, |
218 | if (IS_ERR(xprt)) | 287 | .program = &pmap_program, |
219 | return (struct rpc_clnt *)xprt; | 288 | .version = RPC_PMAP_VERSION, |
220 | xprt->ops->set_port(xprt, RPC_PMAP_PORT); | 289 | .authflavor = RPC_AUTH_UNIX, |
290 | .flags = (RPC_CLNT_CREATE_ONESHOT | | ||
291 | RPC_CLNT_CREATE_NOPING), | ||
292 | }; | ||
293 | |||
294 | srvaddr->sin_port = htons(RPC_PMAP_PORT); | ||
221 | if (!privileged) | 295 | if (!privileged) |
222 | xprt->resvport = 0; | 296 | args.flags |= RPC_CLNT_CREATE_NONPRIVPORT; |
223 | 297 | return rpc_create(&args); | |
224 | /* printk("pmap: create clnt\n"); */ | ||
225 | clnt = rpc_new_client(xprt, hostname, | ||
226 | &pmap_program, RPC_PMAP_VERSION, | ||
227 | RPC_AUTH_UNIX); | ||
228 | if (!IS_ERR(clnt)) { | ||
229 | clnt->cl_softrtry = 1; | ||
230 | clnt->cl_oneshot = 1; | ||
231 | } | ||
232 | return clnt; | ||
233 | } | 298 | } |
234 | 299 | ||
235 | /* | 300 | /* |
236 | * XDR encode/decode functions for PMAP | 301 | * XDR encode/decode functions for PMAP |
237 | */ | 302 | */ |
238 | static int | 303 | static int xdr_encode_mapping(struct rpc_rqst *req, u32 *p, struct portmap_args *map) |
239 | xdr_encode_mapping(struct rpc_rqst *req, u32 *p, struct rpc_portmap *map) | ||
240 | { | 304 | { |
241 | dprintk("RPC: xdr_encode_mapping(%d, %d, %d, %d)\n", | 305 | dprintk("RPC: xdr_encode_mapping(%u, %u, %u, %u)\n", |
242 | map->pm_prog, map->pm_vers, map->pm_prot, map->pm_port); | 306 | map->pm_prog, map->pm_vers, map->pm_prot, map->pm_port); |
243 | *p++ = htonl(map->pm_prog); | 307 | *p++ = htonl(map->pm_prog); |
244 | *p++ = htonl(map->pm_vers); | 308 | *p++ = htonl(map->pm_vers); |
@@ -249,15 +313,13 @@ xdr_encode_mapping(struct rpc_rqst *req, u32 *p, struct rpc_portmap *map) | |||
249 | return 0; | 313 | return 0; |
250 | } | 314 | } |
251 | 315 | ||
252 | static int | 316 | static int xdr_decode_port(struct rpc_rqst *req, u32 *p, unsigned short *portp) |
253 | xdr_decode_port(struct rpc_rqst *req, u32 *p, unsigned short *portp) | ||
254 | { | 317 | { |
255 | *portp = (unsigned short) ntohl(*p++); | 318 | *portp = (unsigned short) ntohl(*p++); |
256 | return 0; | 319 | return 0; |
257 | } | 320 | } |
258 | 321 | ||
259 | static int | 322 | static int xdr_decode_bool(struct rpc_rqst *req, u32 *p, unsigned int *boolp) |
260 | xdr_decode_bool(struct rpc_rqst *req, u32 *p, unsigned int *boolp) | ||
261 | { | 323 | { |
262 | *boolp = (unsigned int) ntohl(*p++); | 324 | *boolp = (unsigned int) ntohl(*p++); |
263 | return 0; | 325 | return 0; |
diff --git a/net/sunrpc/rpc_pipe.c b/net/sunrpc/rpc_pipe.c index 0b1a1ac8a4bc..dfa504fe383f 100644 --- a/net/sunrpc/rpc_pipe.c +++ b/net/sunrpc/rpc_pipe.c | |||
@@ -327,10 +327,8 @@ rpc_show_info(struct seq_file *m, void *v) | |||
327 | seq_printf(m, "RPC server: %s\n", clnt->cl_server); | 327 | seq_printf(m, "RPC server: %s\n", clnt->cl_server); |
328 | seq_printf(m, "service: %s (%d) version %d\n", clnt->cl_protname, | 328 | seq_printf(m, "service: %s (%d) version %d\n", clnt->cl_protname, |
329 | clnt->cl_prog, clnt->cl_vers); | 329 | clnt->cl_prog, clnt->cl_vers); |
330 | seq_printf(m, "address: %u.%u.%u.%u\n", | 330 | seq_printf(m, "address: %s\n", rpc_peeraddr2str(clnt, RPC_DISPLAY_ADDR)); |
331 | NIPQUAD(clnt->cl_xprt->addr.sin_addr.s_addr)); | 331 | seq_printf(m, "protocol: %s\n", rpc_peeraddr2str(clnt, RPC_DISPLAY_PROTO)); |
332 | seq_printf(m, "protocol: %s\n", | ||
333 | clnt->cl_xprt->prot == IPPROTO_UDP ? "udp" : "tcp"); | ||
334 | return 0; | 332 | return 0; |
335 | } | 333 | } |
336 | 334 | ||
@@ -623,17 +621,13 @@ __rpc_rmdir(struct inode *dir, struct dentry *dentry) | |||
623 | } | 621 | } |
624 | 622 | ||
625 | static struct dentry * | 623 | static struct dentry * |
626 | rpc_lookup_negative(char *path, struct nameidata *nd) | 624 | rpc_lookup_create(struct dentry *parent, const char *name, int len) |
627 | { | 625 | { |
626 | struct inode *dir = parent->d_inode; | ||
628 | struct dentry *dentry; | 627 | struct dentry *dentry; |
629 | struct inode *dir; | ||
630 | int error; | ||
631 | 628 | ||
632 | if ((error = rpc_lookup_parent(path, nd)) != 0) | ||
633 | return ERR_PTR(error); | ||
634 | dir = nd->dentry->d_inode; | ||
635 | mutex_lock_nested(&dir->i_mutex, I_MUTEX_PARENT); | 629 | mutex_lock_nested(&dir->i_mutex, I_MUTEX_PARENT); |
636 | dentry = lookup_one_len(nd->last.name, nd->dentry, nd->last.len); | 630 | dentry = lookup_one_len(name, parent, len); |
637 | if (IS_ERR(dentry)) | 631 | if (IS_ERR(dentry)) |
638 | goto out_err; | 632 | goto out_err; |
639 | if (dentry->d_inode) { | 633 | if (dentry->d_inode) { |
@@ -644,7 +638,20 @@ rpc_lookup_negative(char *path, struct nameidata *nd) | |||
644 | return dentry; | 638 | return dentry; |
645 | out_err: | 639 | out_err: |
646 | mutex_unlock(&dir->i_mutex); | 640 | mutex_unlock(&dir->i_mutex); |
647 | rpc_release_path(nd); | 641 | return dentry; |
642 | } | ||
643 | |||
644 | static struct dentry * | ||
645 | rpc_lookup_negative(char *path, struct nameidata *nd) | ||
646 | { | ||
647 | struct dentry *dentry; | ||
648 | int error; | ||
649 | |||
650 | if ((error = rpc_lookup_parent(path, nd)) != 0) | ||
651 | return ERR_PTR(error); | ||
652 | dentry = rpc_lookup_create(nd->dentry, nd->last.name, nd->last.len); | ||
653 | if (IS_ERR(dentry)) | ||
654 | rpc_release_path(nd); | ||
648 | return dentry; | 655 | return dentry; |
649 | } | 656 | } |
650 | 657 | ||
@@ -703,18 +710,17 @@ rpc_rmdir(struct dentry *dentry) | |||
703 | } | 710 | } |
704 | 711 | ||
705 | struct dentry * | 712 | struct dentry * |
706 | rpc_mkpipe(char *path, void *private, struct rpc_pipe_ops *ops, int flags) | 713 | rpc_mkpipe(struct dentry *parent, const char *name, void *private, struct rpc_pipe_ops *ops, int flags) |
707 | { | 714 | { |
708 | struct nameidata nd; | ||
709 | struct dentry *dentry; | 715 | struct dentry *dentry; |
710 | struct inode *dir, *inode; | 716 | struct inode *dir, *inode; |
711 | struct rpc_inode *rpci; | 717 | struct rpc_inode *rpci; |
712 | 718 | ||
713 | dentry = rpc_lookup_negative(path, &nd); | 719 | dentry = rpc_lookup_create(parent, name, strlen(name)); |
714 | if (IS_ERR(dentry)) | 720 | if (IS_ERR(dentry)) |
715 | return dentry; | 721 | return dentry; |
716 | dir = nd.dentry->d_inode; | 722 | dir = parent->d_inode; |
717 | inode = rpc_get_inode(dir->i_sb, S_IFSOCK | S_IRUSR | S_IWUSR); | 723 | inode = rpc_get_inode(dir->i_sb, S_IFIFO | S_IRUSR | S_IWUSR); |
718 | if (!inode) | 724 | if (!inode) |
719 | goto err_dput; | 725 | goto err_dput; |
720 | inode->i_ino = iunique(dir->i_sb, 100); | 726 | inode->i_ino = iunique(dir->i_sb, 100); |
@@ -728,13 +734,13 @@ rpc_mkpipe(char *path, void *private, struct rpc_pipe_ops *ops, int flags) | |||
728 | dget(dentry); | 734 | dget(dentry); |
729 | out: | 735 | out: |
730 | mutex_unlock(&dir->i_mutex); | 736 | mutex_unlock(&dir->i_mutex); |
731 | rpc_release_path(&nd); | ||
732 | return dentry; | 737 | return dentry; |
733 | err_dput: | 738 | err_dput: |
734 | dput(dentry); | 739 | dput(dentry); |
735 | dentry = ERR_PTR(-ENOMEM); | 740 | dentry = ERR_PTR(-ENOMEM); |
736 | printk(KERN_WARNING "%s: %s() failed to create pipe %s (errno = %d)\n", | 741 | printk(KERN_WARNING "%s: %s() failed to create pipe %s/%s (errno = %d)\n", |
737 | __FILE__, __FUNCTION__, path, -ENOMEM); | 742 | __FILE__, __FUNCTION__, parent->d_name.name, name, |
743 | -ENOMEM); | ||
738 | goto out; | 744 | goto out; |
739 | } | 745 | } |
740 | 746 | ||
diff --git a/net/sunrpc/sched.c b/net/sunrpc/sched.c index 5c3eee768504..6390461a9756 100644 --- a/net/sunrpc/sched.c +++ b/net/sunrpc/sched.c | |||
@@ -21,7 +21,6 @@ | |||
21 | #include <linux/mutex.h> | 21 | #include <linux/mutex.h> |
22 | 22 | ||
23 | #include <linux/sunrpc/clnt.h> | 23 | #include <linux/sunrpc/clnt.h> |
24 | #include <linux/sunrpc/xprt.h> | ||
25 | 24 | ||
26 | #ifdef RPC_DEBUG | 25 | #ifdef RPC_DEBUG |
27 | #define RPCDBG_FACILITY RPCDBG_SCHED | 26 | #define RPCDBG_FACILITY RPCDBG_SCHED |
@@ -45,12 +44,6 @@ static void rpciod_killall(void); | |||
45 | static void rpc_async_schedule(void *); | 44 | static void rpc_async_schedule(void *); |
46 | 45 | ||
47 | /* | 46 | /* |
48 | * RPC tasks that create another task (e.g. for contacting the portmapper) | ||
49 | * will wait on this queue for their child's completion | ||
50 | */ | ||
51 | static RPC_WAITQ(childq, "childq"); | ||
52 | |||
53 | /* | ||
54 | * RPC tasks sit here while waiting for conditions to improve. | 47 | * RPC tasks sit here while waiting for conditions to improve. |
55 | */ | 48 | */ |
56 | static RPC_WAITQ(delay_queue, "delayq"); | 49 | static RPC_WAITQ(delay_queue, "delayq"); |
@@ -324,16 +317,6 @@ static void rpc_make_runnable(struct rpc_task *task) | |||
324 | } | 317 | } |
325 | 318 | ||
326 | /* | 319 | /* |
327 | * Place a newly initialized task on the workqueue. | ||
328 | */ | ||
329 | static inline void | ||
330 | rpc_schedule_run(struct rpc_task *task) | ||
331 | { | ||
332 | rpc_set_active(task); | ||
333 | rpc_make_runnable(task); | ||
334 | } | ||
335 | |||
336 | /* | ||
337 | * Prepare for sleeping on a wait queue. | 320 | * Prepare for sleeping on a wait queue. |
338 | * By always appending tasks to the list we ensure FIFO behavior. | 321 | * By always appending tasks to the list we ensure FIFO behavior. |
339 | * NB: An RPC task will only receive interrupt-driven events as long | 322 | * NB: An RPC task will only receive interrupt-driven events as long |
@@ -559,24 +542,20 @@ void rpc_wake_up_status(struct rpc_wait_queue *queue, int status) | |||
559 | spin_unlock_bh(&queue->lock); | 542 | spin_unlock_bh(&queue->lock); |
560 | } | 543 | } |
561 | 544 | ||
545 | static void __rpc_atrun(struct rpc_task *task) | ||
546 | { | ||
547 | rpc_wake_up_task(task); | ||
548 | } | ||
549 | |||
562 | /* | 550 | /* |
563 | * Run a task at a later time | 551 | * Run a task at a later time |
564 | */ | 552 | */ |
565 | static void __rpc_atrun(struct rpc_task *); | 553 | void rpc_delay(struct rpc_task *task, unsigned long delay) |
566 | void | ||
567 | rpc_delay(struct rpc_task *task, unsigned long delay) | ||
568 | { | 554 | { |
569 | task->tk_timeout = delay; | 555 | task->tk_timeout = delay; |
570 | rpc_sleep_on(&delay_queue, task, NULL, __rpc_atrun); | 556 | rpc_sleep_on(&delay_queue, task, NULL, __rpc_atrun); |
571 | } | 557 | } |
572 | 558 | ||
573 | static void | ||
574 | __rpc_atrun(struct rpc_task *task) | ||
575 | { | ||
576 | task->tk_status = 0; | ||
577 | rpc_wake_up_task(task); | ||
578 | } | ||
579 | |||
580 | /* | 559 | /* |
581 | * Helper to call task->tk_ops->rpc_call_prepare | 560 | * Helper to call task->tk_ops->rpc_call_prepare |
582 | */ | 561 | */ |
@@ -933,72 +912,6 @@ struct rpc_task *rpc_run_task(struct rpc_clnt *clnt, int flags, | |||
933 | } | 912 | } |
934 | EXPORT_SYMBOL(rpc_run_task); | 913 | EXPORT_SYMBOL(rpc_run_task); |
935 | 914 | ||
936 | /** | ||
937 | * rpc_find_parent - find the parent of a child task. | ||
938 | * @child: child task | ||
939 | * @parent: parent task | ||
940 | * | ||
941 | * Checks that the parent task is still sleeping on the | ||
942 | * queue 'childq'. If so returns a pointer to the parent. | ||
943 | * Upon failure returns NULL. | ||
944 | * | ||
945 | * Caller must hold childq.lock | ||
946 | */ | ||
947 | static inline struct rpc_task *rpc_find_parent(struct rpc_task *child, struct rpc_task *parent) | ||
948 | { | ||
949 | struct rpc_task *task; | ||
950 | struct list_head *le; | ||
951 | |||
952 | task_for_each(task, le, &childq.tasks[0]) | ||
953 | if (task == parent) | ||
954 | return parent; | ||
955 | |||
956 | return NULL; | ||
957 | } | ||
958 | |||
959 | static void rpc_child_exit(struct rpc_task *child, void *calldata) | ||
960 | { | ||
961 | struct rpc_task *parent; | ||
962 | |||
963 | spin_lock_bh(&childq.lock); | ||
964 | if ((parent = rpc_find_parent(child, calldata)) != NULL) { | ||
965 | parent->tk_status = child->tk_status; | ||
966 | __rpc_wake_up_task(parent); | ||
967 | } | ||
968 | spin_unlock_bh(&childq.lock); | ||
969 | } | ||
970 | |||
971 | static const struct rpc_call_ops rpc_child_ops = { | ||
972 | .rpc_call_done = rpc_child_exit, | ||
973 | }; | ||
974 | |||
975 | /* | ||
976 | * Note: rpc_new_task releases the client after a failure. | ||
977 | */ | ||
978 | struct rpc_task * | ||
979 | rpc_new_child(struct rpc_clnt *clnt, struct rpc_task *parent) | ||
980 | { | ||
981 | struct rpc_task *task; | ||
982 | |||
983 | task = rpc_new_task(clnt, RPC_TASK_ASYNC | RPC_TASK_CHILD, &rpc_child_ops, parent); | ||
984 | if (!task) | ||
985 | goto fail; | ||
986 | return task; | ||
987 | |||
988 | fail: | ||
989 | parent->tk_status = -ENOMEM; | ||
990 | return NULL; | ||
991 | } | ||
992 | |||
993 | void rpc_run_child(struct rpc_task *task, struct rpc_task *child, rpc_action func) | ||
994 | { | ||
995 | spin_lock_bh(&childq.lock); | ||
996 | /* N.B. Is it possible for the child to have already finished? */ | ||
997 | __rpc_sleep_on(&childq, task, func, NULL); | ||
998 | rpc_schedule_run(child); | ||
999 | spin_unlock_bh(&childq.lock); | ||
1000 | } | ||
1001 | |||
1002 | /* | 915 | /* |
1003 | * Kill all tasks for the given client. | 916 | * Kill all tasks for the given client. |
1004 | * XXX: kill their descendants as well? | 917 | * XXX: kill their descendants as well? |
diff --git a/net/sunrpc/socklib.c b/net/sunrpc/socklib.c index eb330d4f66d6..6f17527b9e69 100644 --- a/net/sunrpc/socklib.c +++ b/net/sunrpc/socklib.c | |||
@@ -168,7 +168,7 @@ int csum_partial_copy_to_xdr(struct xdr_buf *xdr, struct sk_buff *skb) | |||
168 | return -1; | 168 | return -1; |
169 | if ((unsigned short)csum_fold(desc.csum)) | 169 | if ((unsigned short)csum_fold(desc.csum)) |
170 | return -1; | 170 | return -1; |
171 | if (unlikely(skb->ip_summed == CHECKSUM_HW)) | 171 | if (unlikely(skb->ip_summed == CHECKSUM_COMPLETE)) |
172 | netdev_rx_csum_fault(skb->dev); | 172 | netdev_rx_csum_fault(skb->dev); |
173 | return 0; | 173 | return 0; |
174 | no_checksum: | 174 | no_checksum: |
diff --git a/net/sunrpc/sunrpc_syms.c b/net/sunrpc/sunrpc_syms.c index f38f939ce95f..26c0531d7e25 100644 --- a/net/sunrpc/sunrpc_syms.c +++ b/net/sunrpc/sunrpc_syms.c | |||
@@ -36,8 +36,6 @@ EXPORT_SYMBOL(rpc_wake_up_status); | |||
36 | EXPORT_SYMBOL(rpc_release_task); | 36 | EXPORT_SYMBOL(rpc_release_task); |
37 | 37 | ||
38 | /* RPC client functions */ | 38 | /* RPC client functions */ |
39 | EXPORT_SYMBOL(rpc_create_client); | ||
40 | EXPORT_SYMBOL(rpc_new_client); | ||
41 | EXPORT_SYMBOL(rpc_clone_client); | 39 | EXPORT_SYMBOL(rpc_clone_client); |
42 | EXPORT_SYMBOL(rpc_bind_new_program); | 40 | EXPORT_SYMBOL(rpc_bind_new_program); |
43 | EXPORT_SYMBOL(rpc_destroy_client); | 41 | EXPORT_SYMBOL(rpc_destroy_client); |
@@ -57,7 +55,6 @@ EXPORT_SYMBOL(rpc_queue_upcall); | |||
57 | EXPORT_SYMBOL(rpc_mkpipe); | 55 | EXPORT_SYMBOL(rpc_mkpipe); |
58 | 56 | ||
59 | /* Client transport */ | 57 | /* Client transport */ |
60 | EXPORT_SYMBOL(xprt_create_proto); | ||
61 | EXPORT_SYMBOL(xprt_set_timeout); | 58 | EXPORT_SYMBOL(xprt_set_timeout); |
62 | 59 | ||
63 | /* Client credential cache */ | 60 | /* Client credential cache */ |
diff --git a/net/sunrpc/svcsock.c b/net/sunrpc/svcsock.c index d9a95732df46..953aff89bcac 100644 --- a/net/sunrpc/svcsock.c +++ b/net/sunrpc/svcsock.c | |||
@@ -388,7 +388,7 @@ svc_sendto(struct svc_rqst *rqstp, struct xdr_buf *xdr) | |||
388 | /* send head */ | 388 | /* send head */ |
389 | if (slen == xdr->head[0].iov_len) | 389 | if (slen == xdr->head[0].iov_len) |
390 | flags = 0; | 390 | flags = 0; |
391 | len = sock->ops->sendpage(sock, rqstp->rq_respages[0], 0, xdr->head[0].iov_len, flags); | 391 | len = kernel_sendpage(sock, rqstp->rq_respages[0], 0, xdr->head[0].iov_len, flags); |
392 | if (len != xdr->head[0].iov_len) | 392 | if (len != xdr->head[0].iov_len) |
393 | goto out; | 393 | goto out; |
394 | slen -= xdr->head[0].iov_len; | 394 | slen -= xdr->head[0].iov_len; |
@@ -400,7 +400,7 @@ svc_sendto(struct svc_rqst *rqstp, struct xdr_buf *xdr) | |||
400 | while (pglen > 0) { | 400 | while (pglen > 0) { |
401 | if (slen == size) | 401 | if (slen == size) |
402 | flags = 0; | 402 | flags = 0; |
403 | result = sock->ops->sendpage(sock, *ppage, base, size, flags); | 403 | result = kernel_sendpage(sock, *ppage, base, size, flags); |
404 | if (result > 0) | 404 | if (result > 0) |
405 | len += result; | 405 | len += result; |
406 | if (result != size) | 406 | if (result != size) |
@@ -413,7 +413,7 @@ svc_sendto(struct svc_rqst *rqstp, struct xdr_buf *xdr) | |||
413 | } | 413 | } |
414 | /* send tail */ | 414 | /* send tail */ |
415 | if (xdr->tail[0].iov_len) { | 415 | if (xdr->tail[0].iov_len) { |
416 | result = sock->ops->sendpage(sock, rqstp->rq_respages[rqstp->rq_restailpage], | 416 | result = kernel_sendpage(sock, rqstp->rq_respages[rqstp->rq_restailpage], |
417 | ((unsigned long)xdr->tail[0].iov_base)& (PAGE_SIZE-1), | 417 | ((unsigned long)xdr->tail[0].iov_base)& (PAGE_SIZE-1), |
418 | xdr->tail[0].iov_len, 0); | 418 | xdr->tail[0].iov_len, 0); |
419 | 419 | ||
@@ -434,13 +434,10 @@ out: | |||
434 | static int | 434 | static int |
435 | svc_recv_available(struct svc_sock *svsk) | 435 | svc_recv_available(struct svc_sock *svsk) |
436 | { | 436 | { |
437 | mm_segment_t oldfs; | ||
438 | struct socket *sock = svsk->sk_sock; | 437 | struct socket *sock = svsk->sk_sock; |
439 | int avail, err; | 438 | int avail, err; |
440 | 439 | ||
441 | oldfs = get_fs(); set_fs(KERNEL_DS); | 440 | err = kernel_sock_ioctl(sock, TIOCINQ, (unsigned long) &avail); |
442 | err = sock->ops->ioctl(sock, TIOCINQ, (unsigned long) &avail); | ||
443 | set_fs(oldfs); | ||
444 | 441 | ||
445 | return (err >= 0)? avail : err; | 442 | return (err >= 0)? avail : err; |
446 | } | 443 | } |
@@ -472,7 +469,7 @@ svc_recvfrom(struct svc_rqst *rqstp, struct kvec *iov, int nr, int buflen) | |||
472 | * at accept time. FIXME | 469 | * at accept time. FIXME |
473 | */ | 470 | */ |
474 | alen = sizeof(rqstp->rq_addr); | 471 | alen = sizeof(rqstp->rq_addr); |
475 | sock->ops->getname(sock, (struct sockaddr *)&rqstp->rq_addr, &alen, 1); | 472 | kernel_getpeername(sock, (struct sockaddr *)&rqstp->rq_addr, &alen); |
476 | 473 | ||
477 | dprintk("svc: socket %p recvfrom(%p, %Zu) = %d\n", | 474 | dprintk("svc: socket %p recvfrom(%p, %Zu) = %d\n", |
478 | rqstp->rq_sock, iov[0].iov_base, iov[0].iov_len, len); | 475 | rqstp->rq_sock, iov[0].iov_base, iov[0].iov_len, len); |
@@ -758,7 +755,6 @@ svc_tcp_accept(struct svc_sock *svsk) | |||
758 | struct svc_serv *serv = svsk->sk_server; | 755 | struct svc_serv *serv = svsk->sk_server; |
759 | struct socket *sock = svsk->sk_sock; | 756 | struct socket *sock = svsk->sk_sock; |
760 | struct socket *newsock; | 757 | struct socket *newsock; |
761 | const struct proto_ops *ops; | ||
762 | struct svc_sock *newsvsk; | 758 | struct svc_sock *newsvsk; |
763 | int err, slen; | 759 | int err, slen; |
764 | 760 | ||
@@ -766,29 +762,23 @@ svc_tcp_accept(struct svc_sock *svsk) | |||
766 | if (!sock) | 762 | if (!sock) |
767 | return; | 763 | return; |
768 | 764 | ||
769 | err = sock_create_lite(PF_INET, SOCK_STREAM, IPPROTO_TCP, &newsock); | 765 | clear_bit(SK_CONN, &svsk->sk_flags); |
770 | if (err) { | 766 | err = kernel_accept(sock, &newsock, O_NONBLOCK); |
767 | if (err < 0) { | ||
771 | if (err == -ENOMEM) | 768 | if (err == -ENOMEM) |
772 | printk(KERN_WARNING "%s: no more sockets!\n", | 769 | printk(KERN_WARNING "%s: no more sockets!\n", |
773 | serv->sv_name); | 770 | serv->sv_name); |
774 | return; | 771 | else if (err != -EAGAIN && net_ratelimit()) |
775 | } | ||
776 | |||
777 | dprintk("svc: tcp_accept %p allocated\n", newsock); | ||
778 | newsock->ops = ops = sock->ops; | ||
779 | |||
780 | clear_bit(SK_CONN, &svsk->sk_flags); | ||
781 | if ((err = ops->accept(sock, newsock, O_NONBLOCK)) < 0) { | ||
782 | if (err != -EAGAIN && net_ratelimit()) | ||
783 | printk(KERN_WARNING "%s: accept failed (err %d)!\n", | 772 | printk(KERN_WARNING "%s: accept failed (err %d)!\n", |
784 | serv->sv_name, -err); | 773 | serv->sv_name, -err); |
785 | goto failed; /* aborted connection or whatever */ | 774 | return; |
786 | } | 775 | } |
776 | |||
787 | set_bit(SK_CONN, &svsk->sk_flags); | 777 | set_bit(SK_CONN, &svsk->sk_flags); |
788 | svc_sock_enqueue(svsk); | 778 | svc_sock_enqueue(svsk); |
789 | 779 | ||
790 | slen = sizeof(sin); | 780 | slen = sizeof(sin); |
791 | err = ops->getname(newsock, (struct sockaddr *) &sin, &slen, 1); | 781 | err = kernel_getpeername(newsock, (struct sockaddr *) &sin, &slen); |
792 | if (err < 0) { | 782 | if (err < 0) { |
793 | if (net_ratelimit()) | 783 | if (net_ratelimit()) |
794 | printk(KERN_WARNING "%s: peername failed (err %d)!\n", | 784 | printk(KERN_WARNING "%s: peername failed (err %d)!\n", |
@@ -1406,14 +1396,14 @@ svc_create_socket(struct svc_serv *serv, int protocol, struct sockaddr_in *sin) | |||
1406 | if (sin != NULL) { | 1396 | if (sin != NULL) { |
1407 | if (type == SOCK_STREAM) | 1397 | if (type == SOCK_STREAM) |
1408 | sock->sk->sk_reuse = 1; /* allow address reuse */ | 1398 | sock->sk->sk_reuse = 1; /* allow address reuse */ |
1409 | error = sock->ops->bind(sock, (struct sockaddr *) sin, | 1399 | error = kernel_bind(sock, (struct sockaddr *) sin, |
1410 | sizeof(*sin)); | 1400 | sizeof(*sin)); |
1411 | if (error < 0) | 1401 | if (error < 0) |
1412 | goto bummer; | 1402 | goto bummer; |
1413 | } | 1403 | } |
1414 | 1404 | ||
1415 | if (protocol == IPPROTO_TCP) { | 1405 | if (protocol == IPPROTO_TCP) { |
1416 | if ((error = sock->ops->listen(sock, 64)) < 0) | 1406 | if ((error = kernel_listen(sock, 64)) < 0) |
1417 | goto bummer; | 1407 | goto bummer; |
1418 | } | 1408 | } |
1419 | 1409 | ||
diff --git a/net/sunrpc/timer.c b/net/sunrpc/timer.c index bcbdf6430d5c..8142fdb8a930 100644 --- a/net/sunrpc/timer.c +++ b/net/sunrpc/timer.c | |||
@@ -19,8 +19,6 @@ | |||
19 | #include <linux/unistd.h> | 19 | #include <linux/unistd.h> |
20 | 20 | ||
21 | #include <linux/sunrpc/clnt.h> | 21 | #include <linux/sunrpc/clnt.h> |
22 | #include <linux/sunrpc/xprt.h> | ||
23 | #include <linux/sunrpc/timer.h> | ||
24 | 22 | ||
25 | #define RPC_RTO_MAX (60*HZ) | 23 | #define RPC_RTO_MAX (60*HZ) |
26 | #define RPC_RTO_INIT (HZ/5) | 24 | #define RPC_RTO_INIT (HZ/5) |
diff --git a/net/sunrpc/xprt.c b/net/sunrpc/xprt.c index e8c2bc4977f3..1f786f68729d 100644 --- a/net/sunrpc/xprt.c +++ b/net/sunrpc/xprt.c | |||
@@ -534,7 +534,7 @@ void xprt_connect(struct rpc_task *task) | |||
534 | dprintk("RPC: %4d xprt_connect xprt %p %s connected\n", task->tk_pid, | 534 | dprintk("RPC: %4d xprt_connect xprt %p %s connected\n", task->tk_pid, |
535 | xprt, (xprt_connected(xprt) ? "is" : "is not")); | 535 | xprt, (xprt_connected(xprt) ? "is" : "is not")); |
536 | 536 | ||
537 | if (!xprt->addr.sin_port) { | 537 | if (!xprt_bound(xprt)) { |
538 | task->tk_status = -EIO; | 538 | task->tk_status = -EIO; |
539 | return; | 539 | return; |
540 | } | 540 | } |
@@ -585,13 +585,6 @@ static void xprt_connect_status(struct rpc_task *task) | |||
585 | task->tk_pid, -task->tk_status, task->tk_client->cl_server); | 585 | task->tk_pid, -task->tk_status, task->tk_client->cl_server); |
586 | xprt_release_write(xprt, task); | 586 | xprt_release_write(xprt, task); |
587 | task->tk_status = -EIO; | 587 | task->tk_status = -EIO; |
588 | return; | ||
589 | } | ||
590 | |||
591 | /* if soft mounted, just cause this RPC to fail */ | ||
592 | if (RPC_IS_SOFT(task)) { | ||
593 | xprt_release_write(xprt, task); | ||
594 | task->tk_status = -EIO; | ||
595 | } | 588 | } |
596 | } | 589 | } |
597 | 590 | ||
@@ -829,6 +822,7 @@ static void xprt_request_init(struct rpc_task *task, struct rpc_xprt *xprt) | |||
829 | req->rq_bufsize = 0; | 822 | req->rq_bufsize = 0; |
830 | req->rq_xid = xprt_alloc_xid(xprt); | 823 | req->rq_xid = xprt_alloc_xid(xprt); |
831 | req->rq_release_snd_buf = NULL; | 824 | req->rq_release_snd_buf = NULL; |
825 | xprt_reset_majortimeo(req); | ||
832 | dprintk("RPC: %4d reserved req %p xid %08x\n", task->tk_pid, | 826 | dprintk("RPC: %4d reserved req %p xid %08x\n", task->tk_pid, |
833 | req, ntohl(req->rq_xid)); | 827 | req, ntohl(req->rq_xid)); |
834 | } | 828 | } |
@@ -887,16 +881,32 @@ void xprt_set_timeout(struct rpc_timeout *to, unsigned int retr, unsigned long i | |||
887 | to->to_exponential = 0; | 881 | to->to_exponential = 0; |
888 | } | 882 | } |
889 | 883 | ||
890 | static struct rpc_xprt *xprt_setup(int proto, struct sockaddr_in *ap, struct rpc_timeout *to) | 884 | /** |
885 | * xprt_create_transport - create an RPC transport | ||
886 | * @proto: requested transport protocol | ||
887 | * @ap: remote peer address | ||
888 | * @size: length of address | ||
889 | * @to: timeout parameters | ||
890 | * | ||
891 | */ | ||
892 | struct rpc_xprt *xprt_create_transport(int proto, struct sockaddr *ap, size_t size, struct rpc_timeout *to) | ||
891 | { | 893 | { |
892 | int result; | 894 | int result; |
893 | struct rpc_xprt *xprt; | 895 | struct rpc_xprt *xprt; |
894 | struct rpc_rqst *req; | 896 | struct rpc_rqst *req; |
895 | 897 | ||
896 | if ((xprt = kzalloc(sizeof(struct rpc_xprt), GFP_KERNEL)) == NULL) | 898 | if ((xprt = kzalloc(sizeof(struct rpc_xprt), GFP_KERNEL)) == NULL) { |
899 | dprintk("RPC: xprt_create_transport: no memory\n"); | ||
897 | return ERR_PTR(-ENOMEM); | 900 | return ERR_PTR(-ENOMEM); |
898 | 901 | } | |
899 | xprt->addr = *ap; | 902 | if (size <= sizeof(xprt->addr)) { |
903 | memcpy(&xprt->addr, ap, size); | ||
904 | xprt->addrlen = size; | ||
905 | } else { | ||
906 | kfree(xprt); | ||
907 | dprintk("RPC: xprt_create_transport: address too large\n"); | ||
908 | return ERR_PTR(-EBADF); | ||
909 | } | ||
900 | 910 | ||
901 | switch (proto) { | 911 | switch (proto) { |
902 | case IPPROTO_UDP: | 912 | case IPPROTO_UDP: |
@@ -908,14 +918,15 @@ static struct rpc_xprt *xprt_setup(int proto, struct sockaddr_in *ap, struct rpc | |||
908 | default: | 918 | default: |
909 | printk(KERN_ERR "RPC: unrecognized transport protocol: %d\n", | 919 | printk(KERN_ERR "RPC: unrecognized transport protocol: %d\n", |
910 | proto); | 920 | proto); |
911 | result = -EIO; | 921 | return ERR_PTR(-EIO); |
912 | break; | ||
913 | } | 922 | } |
914 | if (result) { | 923 | if (result) { |
915 | kfree(xprt); | 924 | kfree(xprt); |
925 | dprintk("RPC: xprt_create_transport: failed, %d\n", result); | ||
916 | return ERR_PTR(result); | 926 | return ERR_PTR(result); |
917 | } | 927 | } |
918 | 928 | ||
929 | kref_init(&xprt->kref); | ||
919 | spin_lock_init(&xprt->transport_lock); | 930 | spin_lock_init(&xprt->transport_lock); |
920 | spin_lock_init(&xprt->reserve_lock); | 931 | spin_lock_init(&xprt->reserve_lock); |
921 | 932 | ||
@@ -928,6 +939,7 @@ static struct rpc_xprt *xprt_setup(int proto, struct sockaddr_in *ap, struct rpc | |||
928 | xprt->last_used = jiffies; | 939 | xprt->last_used = jiffies; |
929 | xprt->cwnd = RPC_INITCWND; | 940 | xprt->cwnd = RPC_INITCWND; |
930 | 941 | ||
942 | rpc_init_wait_queue(&xprt->binding, "xprt_binding"); | ||
931 | rpc_init_wait_queue(&xprt->pending, "xprt_pending"); | 943 | rpc_init_wait_queue(&xprt->pending, "xprt_pending"); |
932 | rpc_init_wait_queue(&xprt->sending, "xprt_sending"); | 944 | rpc_init_wait_queue(&xprt->sending, "xprt_sending"); |
933 | rpc_init_wait_queue(&xprt->resend, "xprt_resend"); | 945 | rpc_init_wait_queue(&xprt->resend, "xprt_resend"); |
@@ -941,41 +953,43 @@ static struct rpc_xprt *xprt_setup(int proto, struct sockaddr_in *ap, struct rpc | |||
941 | 953 | ||
942 | dprintk("RPC: created transport %p with %u slots\n", xprt, | 954 | dprintk("RPC: created transport %p with %u slots\n", xprt, |
943 | xprt->max_reqs); | 955 | xprt->max_reqs); |
944 | |||
945 | return xprt; | ||
946 | } | ||
947 | 956 | ||
948 | /** | ||
949 | * xprt_create_proto - create an RPC client transport | ||
950 | * @proto: requested transport protocol | ||
951 | * @sap: remote peer's address | ||
952 | * @to: timeout parameters for new transport | ||
953 | * | ||
954 | */ | ||
955 | struct rpc_xprt *xprt_create_proto(int proto, struct sockaddr_in *sap, struct rpc_timeout *to) | ||
956 | { | ||
957 | struct rpc_xprt *xprt; | ||
958 | |||
959 | xprt = xprt_setup(proto, sap, to); | ||
960 | if (IS_ERR(xprt)) | ||
961 | dprintk("RPC: xprt_create_proto failed\n"); | ||
962 | else | ||
963 | dprintk("RPC: xprt_create_proto created xprt %p\n", xprt); | ||
964 | return xprt; | 957 | return xprt; |
965 | } | 958 | } |
966 | 959 | ||
967 | /** | 960 | /** |
968 | * xprt_destroy - destroy an RPC transport, killing off all requests. | 961 | * xprt_destroy - destroy an RPC transport, killing off all requests. |
969 | * @xprt: transport to destroy | 962 | * @kref: kref for the transport to destroy |
970 | * | 963 | * |
971 | */ | 964 | */ |
972 | int xprt_destroy(struct rpc_xprt *xprt) | 965 | static void xprt_destroy(struct kref *kref) |
973 | { | 966 | { |
967 | struct rpc_xprt *xprt = container_of(kref, struct rpc_xprt, kref); | ||
968 | |||
974 | dprintk("RPC: destroying transport %p\n", xprt); | 969 | dprintk("RPC: destroying transport %p\n", xprt); |
975 | xprt->shutdown = 1; | 970 | xprt->shutdown = 1; |
976 | del_timer_sync(&xprt->timer); | 971 | del_timer_sync(&xprt->timer); |
977 | xprt->ops->destroy(xprt); | 972 | xprt->ops->destroy(xprt); |
978 | kfree(xprt); | 973 | kfree(xprt); |
974 | } | ||
979 | 975 | ||
980 | return 0; | 976 | /** |
977 | * xprt_put - release a reference to an RPC transport. | ||
978 | * @xprt: pointer to the transport | ||
979 | * | ||
980 | */ | ||
981 | void xprt_put(struct rpc_xprt *xprt) | ||
982 | { | ||
983 | kref_put(&xprt->kref, xprt_destroy); | ||
984 | } | ||
985 | |||
986 | /** | ||
987 | * xprt_get - return a reference to an RPC transport. | ||
988 | * @xprt: pointer to the transport | ||
989 | * | ||
990 | */ | ||
991 | struct rpc_xprt *xprt_get(struct rpc_xprt *xprt) | ||
992 | { | ||
993 | kref_get(&xprt->kref); | ||
994 | return xprt; | ||
981 | } | 995 | } |
diff --git a/net/sunrpc/xprtsock.c b/net/sunrpc/xprtsock.c index 441bd53f5eca..9b62923a9c06 100644 --- a/net/sunrpc/xprtsock.c +++ b/net/sunrpc/xprtsock.c | |||
@@ -125,6 +125,47 @@ static inline void xs_pktdump(char *msg, u32 *packet, unsigned int count) | |||
125 | } | 125 | } |
126 | #endif | 126 | #endif |
127 | 127 | ||
128 | static void xs_format_peer_addresses(struct rpc_xprt *xprt) | ||
129 | { | ||
130 | struct sockaddr_in *addr = (struct sockaddr_in *) &xprt->addr; | ||
131 | char *buf; | ||
132 | |||
133 | buf = kzalloc(20, GFP_KERNEL); | ||
134 | if (buf) { | ||
135 | snprintf(buf, 20, "%u.%u.%u.%u", | ||
136 | NIPQUAD(addr->sin_addr.s_addr)); | ||
137 | } | ||
138 | xprt->address_strings[RPC_DISPLAY_ADDR] = buf; | ||
139 | |||
140 | buf = kzalloc(8, GFP_KERNEL); | ||
141 | if (buf) { | ||
142 | snprintf(buf, 8, "%u", | ||
143 | ntohs(addr->sin_port)); | ||
144 | } | ||
145 | xprt->address_strings[RPC_DISPLAY_PORT] = buf; | ||
146 | |||
147 | if (xprt->prot == IPPROTO_UDP) | ||
148 | xprt->address_strings[RPC_DISPLAY_PROTO] = "udp"; | ||
149 | else | ||
150 | xprt->address_strings[RPC_DISPLAY_PROTO] = "tcp"; | ||
151 | |||
152 | buf = kzalloc(48, GFP_KERNEL); | ||
153 | if (buf) { | ||
154 | snprintf(buf, 48, "addr=%u.%u.%u.%u port=%u proto=%s", | ||
155 | NIPQUAD(addr->sin_addr.s_addr), | ||
156 | ntohs(addr->sin_port), | ||
157 | xprt->prot == IPPROTO_UDP ? "udp" : "tcp"); | ||
158 | } | ||
159 | xprt->address_strings[RPC_DISPLAY_ALL] = buf; | ||
160 | } | ||
161 | |||
162 | static void xs_free_peer_addresses(struct rpc_xprt *xprt) | ||
163 | { | ||
164 | kfree(xprt->address_strings[RPC_DISPLAY_ADDR]); | ||
165 | kfree(xprt->address_strings[RPC_DISPLAY_PORT]); | ||
166 | kfree(xprt->address_strings[RPC_DISPLAY_ALL]); | ||
167 | } | ||
168 | |||
128 | #define XS_SENDMSG_FLAGS (MSG_DONTWAIT | MSG_NOSIGNAL) | 169 | #define XS_SENDMSG_FLAGS (MSG_DONTWAIT | MSG_NOSIGNAL) |
129 | 170 | ||
130 | static inline int xs_send_head(struct socket *sock, struct sockaddr *addr, int addrlen, struct xdr_buf *xdr, unsigned int base, unsigned int len) | 171 | static inline int xs_send_head(struct socket *sock, struct sockaddr *addr, int addrlen, struct xdr_buf *xdr, unsigned int base, unsigned int len) |
@@ -174,7 +215,6 @@ static inline int xs_sendpages(struct socket *sock, struct sockaddr *addr, int a | |||
174 | struct page **ppage = xdr->pages; | 215 | struct page **ppage = xdr->pages; |
175 | unsigned int len, pglen = xdr->page_len; | 216 | unsigned int len, pglen = xdr->page_len; |
176 | int err, ret = 0; | 217 | int err, ret = 0; |
177 | ssize_t (*sendpage)(struct socket *, struct page *, int, size_t, int); | ||
178 | 218 | ||
179 | if (unlikely(!sock)) | 219 | if (unlikely(!sock)) |
180 | return -ENOTCONN; | 220 | return -ENOTCONN; |
@@ -207,7 +247,6 @@ static inline int xs_sendpages(struct socket *sock, struct sockaddr *addr, int a | |||
207 | base &= ~PAGE_CACHE_MASK; | 247 | base &= ~PAGE_CACHE_MASK; |
208 | } | 248 | } |
209 | 249 | ||
210 | sendpage = sock->ops->sendpage ? : sock_no_sendpage; | ||
211 | do { | 250 | do { |
212 | int flags = XS_SENDMSG_FLAGS; | 251 | int flags = XS_SENDMSG_FLAGS; |
213 | 252 | ||
@@ -220,10 +259,7 @@ static inline int xs_sendpages(struct socket *sock, struct sockaddr *addr, int a | |||
220 | if (pglen != len || xdr->tail[0].iov_len != 0) | 259 | if (pglen != len || xdr->tail[0].iov_len != 0) |
221 | flags |= MSG_MORE; | 260 | flags |= MSG_MORE; |
222 | 261 | ||
223 | /* Hmm... We might be dealing with highmem pages */ | 262 | err = kernel_sendpage(sock, *ppage, base, len, flags); |
224 | if (PageHighMem(*ppage)) | ||
225 | sendpage = sock_no_sendpage; | ||
226 | err = sendpage(sock, *ppage, base, len, flags); | ||
227 | if (ret == 0) | 263 | if (ret == 0) |
228 | ret = err; | 264 | ret = err; |
229 | else if (err > 0) | 265 | else if (err > 0) |
@@ -300,7 +336,7 @@ static int xs_udp_send_request(struct rpc_task *task) | |||
300 | 336 | ||
301 | req->rq_xtime = jiffies; | 337 | req->rq_xtime = jiffies; |
302 | status = xs_sendpages(xprt->sock, (struct sockaddr *) &xprt->addr, | 338 | status = xs_sendpages(xprt->sock, (struct sockaddr *) &xprt->addr, |
303 | sizeof(xprt->addr), xdr, req->rq_bytes_sent); | 339 | xprt->addrlen, xdr, req->rq_bytes_sent); |
304 | 340 | ||
305 | dprintk("RPC: xs_udp_send_request(%u) = %d\n", | 341 | dprintk("RPC: xs_udp_send_request(%u) = %d\n", |
306 | xdr->len - req->rq_bytes_sent, status); | 342 | xdr->len - req->rq_bytes_sent, status); |
@@ -490,6 +526,7 @@ static void xs_destroy(struct rpc_xprt *xprt) | |||
490 | 526 | ||
491 | xprt_disconnect(xprt); | 527 | xprt_disconnect(xprt); |
492 | xs_close(xprt); | 528 | xs_close(xprt); |
529 | xs_free_peer_addresses(xprt); | ||
493 | kfree(xprt->slot); | 530 | kfree(xprt->slot); |
494 | } | 531 | } |
495 | 532 | ||
@@ -965,6 +1002,19 @@ static unsigned short xs_get_random_port(void) | |||
965 | } | 1002 | } |
966 | 1003 | ||
967 | /** | 1004 | /** |
1005 | * xs_print_peer_address - format an IPv4 address for printing | ||
1006 | * @xprt: generic transport | ||
1007 | * @format: flags field indicating which parts of the address to render | ||
1008 | */ | ||
1009 | static char *xs_print_peer_address(struct rpc_xprt *xprt, enum rpc_display_format_t format) | ||
1010 | { | ||
1011 | if (xprt->address_strings[format] != NULL) | ||
1012 | return xprt->address_strings[format]; | ||
1013 | else | ||
1014 | return "unprintable"; | ||
1015 | } | ||
1016 | |||
1017 | /** | ||
968 | * xs_set_port - reset the port number in the remote endpoint address | 1018 | * xs_set_port - reset the port number in the remote endpoint address |
969 | * @xprt: generic transport | 1019 | * @xprt: generic transport |
970 | * @port: new port number | 1020 | * @port: new port number |
@@ -972,8 +1022,11 @@ static unsigned short xs_get_random_port(void) | |||
972 | */ | 1022 | */ |
973 | static void xs_set_port(struct rpc_xprt *xprt, unsigned short port) | 1023 | static void xs_set_port(struct rpc_xprt *xprt, unsigned short port) |
974 | { | 1024 | { |
1025 | struct sockaddr_in *sap = (struct sockaddr_in *) &xprt->addr; | ||
1026 | |||
975 | dprintk("RPC: setting port for xprt %p to %u\n", xprt, port); | 1027 | dprintk("RPC: setting port for xprt %p to %u\n", xprt, port); |
976 | xprt->addr.sin_port = htons(port); | 1028 | |
1029 | sap->sin_port = htons(port); | ||
977 | } | 1030 | } |
978 | 1031 | ||
979 | static int xs_bindresvport(struct rpc_xprt *xprt, struct socket *sock) | 1032 | static int xs_bindresvport(struct rpc_xprt *xprt, struct socket *sock) |
@@ -986,7 +1039,7 @@ static int xs_bindresvport(struct rpc_xprt *xprt, struct socket *sock) | |||
986 | 1039 | ||
987 | do { | 1040 | do { |
988 | myaddr.sin_port = htons(port); | 1041 | myaddr.sin_port = htons(port); |
989 | err = sock->ops->bind(sock, (struct sockaddr *) &myaddr, | 1042 | err = kernel_bind(sock, (struct sockaddr *) &myaddr, |
990 | sizeof(myaddr)); | 1043 | sizeof(myaddr)); |
991 | if (err == 0) { | 1044 | if (err == 0) { |
992 | xprt->port = port; | 1045 | xprt->port = port; |
@@ -1016,11 +1069,9 @@ static void xs_udp_connect_worker(void *args) | |||
1016 | struct socket *sock = xprt->sock; | 1069 | struct socket *sock = xprt->sock; |
1017 | int err, status = -EIO; | 1070 | int err, status = -EIO; |
1018 | 1071 | ||
1019 | if (xprt->shutdown || xprt->addr.sin_port == 0) | 1072 | if (xprt->shutdown || !xprt_bound(xprt)) |
1020 | goto out; | 1073 | goto out; |
1021 | 1074 | ||
1022 | dprintk("RPC: xs_udp_connect_worker for xprt %p\n", xprt); | ||
1023 | |||
1024 | /* Start by resetting any existing state */ | 1075 | /* Start by resetting any existing state */ |
1025 | xs_close(xprt); | 1076 | xs_close(xprt); |
1026 | 1077 | ||
@@ -1034,6 +1085,9 @@ static void xs_udp_connect_worker(void *args) | |||
1034 | goto out; | 1085 | goto out; |
1035 | } | 1086 | } |
1036 | 1087 | ||
1088 | dprintk("RPC: worker connecting xprt %p to address: %s\n", | ||
1089 | xprt, xs_print_peer_address(xprt, RPC_DISPLAY_ALL)); | ||
1090 | |||
1037 | if (!xprt->inet) { | 1091 | if (!xprt->inet) { |
1038 | struct sock *sk = sock->sk; | 1092 | struct sock *sk = sock->sk; |
1039 | 1093 | ||
@@ -1081,7 +1135,7 @@ static void xs_tcp_reuse_connection(struct rpc_xprt *xprt) | |||
1081 | */ | 1135 | */ |
1082 | memset(&any, 0, sizeof(any)); | 1136 | memset(&any, 0, sizeof(any)); |
1083 | any.sa_family = AF_UNSPEC; | 1137 | any.sa_family = AF_UNSPEC; |
1084 | result = sock->ops->connect(sock, &any, sizeof(any), 0); | 1138 | result = kernel_connect(sock, &any, sizeof(any), 0); |
1085 | if (result) | 1139 | if (result) |
1086 | dprintk("RPC: AF_UNSPEC connect return code %d\n", | 1140 | dprintk("RPC: AF_UNSPEC connect return code %d\n", |
1087 | result); | 1141 | result); |
@@ -1099,11 +1153,9 @@ static void xs_tcp_connect_worker(void *args) | |||
1099 | struct socket *sock = xprt->sock; | 1153 | struct socket *sock = xprt->sock; |
1100 | int err, status = -EIO; | 1154 | int err, status = -EIO; |
1101 | 1155 | ||
1102 | if (xprt->shutdown || xprt->addr.sin_port == 0) | 1156 | if (xprt->shutdown || !xprt_bound(xprt)) |
1103 | goto out; | 1157 | goto out; |
1104 | 1158 | ||
1105 | dprintk("RPC: xs_tcp_connect_worker for xprt %p\n", xprt); | ||
1106 | |||
1107 | if (!xprt->sock) { | 1159 | if (!xprt->sock) { |
1108 | /* start from scratch */ | 1160 | /* start from scratch */ |
1109 | if ((err = sock_create_kern(PF_INET, SOCK_STREAM, IPPROTO_TCP, &sock)) < 0) { | 1161 | if ((err = sock_create_kern(PF_INET, SOCK_STREAM, IPPROTO_TCP, &sock)) < 0) { |
@@ -1119,6 +1171,9 @@ static void xs_tcp_connect_worker(void *args) | |||
1119 | /* "close" the socket, preserving the local port */ | 1171 | /* "close" the socket, preserving the local port */ |
1120 | xs_tcp_reuse_connection(xprt); | 1172 | xs_tcp_reuse_connection(xprt); |
1121 | 1173 | ||
1174 | dprintk("RPC: worker connecting xprt %p to address: %s\n", | ||
1175 | xprt, xs_print_peer_address(xprt, RPC_DISPLAY_ALL)); | ||
1176 | |||
1122 | if (!xprt->inet) { | 1177 | if (!xprt->inet) { |
1123 | struct sock *sk = sock->sk; | 1178 | struct sock *sk = sock->sk; |
1124 | 1179 | ||
@@ -1151,8 +1206,8 @@ static void xs_tcp_connect_worker(void *args) | |||
1151 | /* Tell the socket layer to start connecting... */ | 1206 | /* Tell the socket layer to start connecting... */ |
1152 | xprt->stat.connect_count++; | 1207 | xprt->stat.connect_count++; |
1153 | xprt->stat.connect_start = jiffies; | 1208 | xprt->stat.connect_start = jiffies; |
1154 | status = sock->ops->connect(sock, (struct sockaddr *) &xprt->addr, | 1209 | status = kernel_connect(sock, (struct sockaddr *) &xprt->addr, |
1155 | sizeof(xprt->addr), O_NONBLOCK); | 1210 | xprt->addrlen, O_NONBLOCK); |
1156 | dprintk("RPC: %p connect status %d connected %d sock state %d\n", | 1211 | dprintk("RPC: %p connect status %d connected %d sock state %d\n", |
1157 | xprt, -status, xprt_connected(xprt), sock->sk->sk_state); | 1212 | xprt, -status, xprt_connected(xprt), sock->sk->sk_state); |
1158 | if (status < 0) { | 1213 | if (status < 0) { |
@@ -1260,8 +1315,10 @@ static void xs_tcp_print_stats(struct rpc_xprt *xprt, struct seq_file *seq) | |||
1260 | 1315 | ||
1261 | static struct rpc_xprt_ops xs_udp_ops = { | 1316 | static struct rpc_xprt_ops xs_udp_ops = { |
1262 | .set_buffer_size = xs_udp_set_buffer_size, | 1317 | .set_buffer_size = xs_udp_set_buffer_size, |
1318 | .print_addr = xs_print_peer_address, | ||
1263 | .reserve_xprt = xprt_reserve_xprt_cong, | 1319 | .reserve_xprt = xprt_reserve_xprt_cong, |
1264 | .release_xprt = xprt_release_xprt_cong, | 1320 | .release_xprt = xprt_release_xprt_cong, |
1321 | .rpcbind = rpc_getport, | ||
1265 | .set_port = xs_set_port, | 1322 | .set_port = xs_set_port, |
1266 | .connect = xs_connect, | 1323 | .connect = xs_connect, |
1267 | .buf_alloc = rpc_malloc, | 1324 | .buf_alloc = rpc_malloc, |
@@ -1276,8 +1333,10 @@ static struct rpc_xprt_ops xs_udp_ops = { | |||
1276 | }; | 1333 | }; |
1277 | 1334 | ||
1278 | static struct rpc_xprt_ops xs_tcp_ops = { | 1335 | static struct rpc_xprt_ops xs_tcp_ops = { |
1336 | .print_addr = xs_print_peer_address, | ||
1279 | .reserve_xprt = xprt_reserve_xprt, | 1337 | .reserve_xprt = xprt_reserve_xprt, |
1280 | .release_xprt = xs_tcp_release_xprt, | 1338 | .release_xprt = xs_tcp_release_xprt, |
1339 | .rpcbind = rpc_getport, | ||
1281 | .set_port = xs_set_port, | 1340 | .set_port = xs_set_port, |
1282 | .connect = xs_connect, | 1341 | .connect = xs_connect, |
1283 | .buf_alloc = rpc_malloc, | 1342 | .buf_alloc = rpc_malloc, |
@@ -1298,8 +1357,7 @@ static struct rpc_xprt_ops xs_tcp_ops = { | |||
1298 | int xs_setup_udp(struct rpc_xprt *xprt, struct rpc_timeout *to) | 1357 | int xs_setup_udp(struct rpc_xprt *xprt, struct rpc_timeout *to) |
1299 | { | 1358 | { |
1300 | size_t slot_table_size; | 1359 | size_t slot_table_size; |
1301 | 1360 | struct sockaddr_in *addr = (struct sockaddr_in *) &xprt->addr; | |
1302 | dprintk("RPC: setting up udp-ipv4 transport...\n"); | ||
1303 | 1361 | ||
1304 | xprt->max_reqs = xprt_udp_slot_table_entries; | 1362 | xprt->max_reqs = xprt_udp_slot_table_entries; |
1305 | slot_table_size = xprt->max_reqs * sizeof(xprt->slot[0]); | 1363 | slot_table_size = xprt->max_reqs * sizeof(xprt->slot[0]); |
@@ -1307,10 +1365,12 @@ int xs_setup_udp(struct rpc_xprt *xprt, struct rpc_timeout *to) | |||
1307 | if (xprt->slot == NULL) | 1365 | if (xprt->slot == NULL) |
1308 | return -ENOMEM; | 1366 | return -ENOMEM; |
1309 | 1367 | ||
1310 | xprt->prot = IPPROTO_UDP; | 1368 | if (ntohs(addr->sin_port != 0)) |
1369 | xprt_set_bound(xprt); | ||
1311 | xprt->port = xs_get_random_port(); | 1370 | xprt->port = xs_get_random_port(); |
1371 | |||
1372 | xprt->prot = IPPROTO_UDP; | ||
1312 | xprt->tsh_size = 0; | 1373 | xprt->tsh_size = 0; |
1313 | xprt->resvport = capable(CAP_NET_BIND_SERVICE) ? 1 : 0; | ||
1314 | /* XXX: header size can vary due to auth type, IPv6, etc. */ | 1374 | /* XXX: header size can vary due to auth type, IPv6, etc. */ |
1315 | xprt->max_payload = (1U << 16) - (MAX_HEADER << 3); | 1375 | xprt->max_payload = (1U << 16) - (MAX_HEADER << 3); |
1316 | 1376 | ||
@@ -1327,6 +1387,10 @@ int xs_setup_udp(struct rpc_xprt *xprt, struct rpc_timeout *to) | |||
1327 | else | 1387 | else |
1328 | xprt_set_timeout(&xprt->timeout, 5, 5 * HZ); | 1388 | xprt_set_timeout(&xprt->timeout, 5, 5 * HZ); |
1329 | 1389 | ||
1390 | xs_format_peer_addresses(xprt); | ||
1391 | dprintk("RPC: set up transport to address %s\n", | ||
1392 | xs_print_peer_address(xprt, RPC_DISPLAY_ALL)); | ||
1393 | |||
1330 | return 0; | 1394 | return 0; |
1331 | } | 1395 | } |
1332 | 1396 | ||
@@ -1339,8 +1403,7 @@ int xs_setup_udp(struct rpc_xprt *xprt, struct rpc_timeout *to) | |||
1339 | int xs_setup_tcp(struct rpc_xprt *xprt, struct rpc_timeout *to) | 1403 | int xs_setup_tcp(struct rpc_xprt *xprt, struct rpc_timeout *to) |
1340 | { | 1404 | { |
1341 | size_t slot_table_size; | 1405 | size_t slot_table_size; |
1342 | 1406 | struct sockaddr_in *addr = (struct sockaddr_in *) &xprt->addr; | |
1343 | dprintk("RPC: setting up tcp-ipv4 transport...\n"); | ||
1344 | 1407 | ||
1345 | xprt->max_reqs = xprt_tcp_slot_table_entries; | 1408 | xprt->max_reqs = xprt_tcp_slot_table_entries; |
1346 | slot_table_size = xprt->max_reqs * sizeof(xprt->slot[0]); | 1409 | slot_table_size = xprt->max_reqs * sizeof(xprt->slot[0]); |
@@ -1348,10 +1411,12 @@ int xs_setup_tcp(struct rpc_xprt *xprt, struct rpc_timeout *to) | |||
1348 | if (xprt->slot == NULL) | 1411 | if (xprt->slot == NULL) |
1349 | return -ENOMEM; | 1412 | return -ENOMEM; |
1350 | 1413 | ||
1351 | xprt->prot = IPPROTO_TCP; | 1414 | if (ntohs(addr->sin_port) != 0) |
1415 | xprt_set_bound(xprt); | ||
1352 | xprt->port = xs_get_random_port(); | 1416 | xprt->port = xs_get_random_port(); |
1417 | |||
1418 | xprt->prot = IPPROTO_TCP; | ||
1353 | xprt->tsh_size = sizeof(rpc_fraghdr) / sizeof(u32); | 1419 | xprt->tsh_size = sizeof(rpc_fraghdr) / sizeof(u32); |
1354 | xprt->resvport = capable(CAP_NET_BIND_SERVICE) ? 1 : 0; | ||
1355 | xprt->max_payload = RPC_MAX_FRAGMENT_SIZE; | 1420 | xprt->max_payload = RPC_MAX_FRAGMENT_SIZE; |
1356 | 1421 | ||
1357 | INIT_WORK(&xprt->connect_worker, xs_tcp_connect_worker, xprt); | 1422 | INIT_WORK(&xprt->connect_worker, xs_tcp_connect_worker, xprt); |
@@ -1367,5 +1432,9 @@ int xs_setup_tcp(struct rpc_xprt *xprt, struct rpc_timeout *to) | |||
1367 | else | 1432 | else |
1368 | xprt_set_timeout(&xprt->timeout, 2, 60 * HZ); | 1433 | xprt_set_timeout(&xprt->timeout, 2, 60 * HZ); |
1369 | 1434 | ||
1435 | xs_format_peer_addresses(xprt); | ||
1436 | dprintk("RPC: set up transport to address %s\n", | ||
1437 | xs_print_peer_address(xprt, RPC_DISPLAY_ALL)); | ||
1438 | |||
1370 | return 0; | 1439 | return 0; |
1371 | } | 1440 | } |
diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c index de6ec519272e..b43a27828df5 100644 --- a/net/unix/af_unix.c +++ b/net/unix/af_unix.c | |||
@@ -117,7 +117,7 @@ | |||
117 | #include <net/checksum.h> | 117 | #include <net/checksum.h> |
118 | #include <linux/security.h> | 118 | #include <linux/security.h> |
119 | 119 | ||
120 | int sysctl_unix_max_dgram_qlen = 10; | 120 | int sysctl_unix_max_dgram_qlen __read_mostly = 10; |
121 | 121 | ||
122 | struct hlist_head unix_socket_table[UNIX_HASH_SIZE + 1]; | 122 | struct hlist_head unix_socket_table[UNIX_HASH_SIZE + 1]; |
123 | DEFINE_SPINLOCK(unix_table_lock); | 123 | DEFINE_SPINLOCK(unix_table_lock); |
@@ -2060,10 +2060,7 @@ static int __init af_unix_init(void) | |||
2060 | int rc = -1; | 2060 | int rc = -1; |
2061 | struct sk_buff *dummy_skb; | 2061 | struct sk_buff *dummy_skb; |
2062 | 2062 | ||
2063 | if (sizeof(struct unix_skb_parms) > sizeof(dummy_skb->cb)) { | 2063 | BUILD_BUG_ON(sizeof(struct unix_skb_parms) > sizeof(dummy_skb->cb)); |
2064 | printk(KERN_CRIT "%s: panic\n", __FUNCTION__); | ||
2065 | goto out; | ||
2066 | } | ||
2067 | 2064 | ||
2068 | rc = proto_register(&unix_proto, 1); | 2065 | rc = proto_register(&unix_proto, 1); |
2069 | if (rc != 0) { | 2066 | if (rc != 0) { |
diff --git a/net/xfrm/Kconfig b/net/xfrm/Kconfig index 0c1c04322baf..0faab6332586 100644 --- a/net/xfrm/Kconfig +++ b/net/xfrm/Kconfig | |||
@@ -6,14 +6,24 @@ config XFRM | |||
6 | depends on NET | 6 | depends on NET |
7 | 7 | ||
8 | config XFRM_USER | 8 | config XFRM_USER |
9 | tristate "IPsec user configuration interface" | 9 | tristate "Transformation user configuration interface" |
10 | depends on INET && XFRM | 10 | depends on INET && XFRM |
11 | ---help--- | 11 | ---help--- |
12 | Support for IPsec user configuration interface used | 12 | Support for Transformation(XFRM) user configuration interface |
13 | by native Linux tools. | 13 | like IPsec used by native Linux tools. |
14 | 14 | ||
15 | If unsure, say Y. | 15 | If unsure, say Y. |
16 | 16 | ||
17 | config XFRM_SUB_POLICY | ||
18 | bool "Transformation sub policy support (EXPERIMENTAL)" | ||
19 | depends on XFRM && EXPERIMENTAL | ||
20 | ---help--- | ||
21 | Support sub policy for developers. By using sub policy with main | ||
22 | one, two policies can be applied to the same packet at once. | ||
23 | Policy which lives shorter time in kernel should be a sub. | ||
24 | |||
25 | If unsure, say N. | ||
26 | |||
17 | config NET_KEY | 27 | config NET_KEY |
18 | tristate "PF_KEY sockets" | 28 | tristate "PF_KEY sockets" |
19 | select XFRM | 29 | select XFRM |
diff --git a/net/xfrm/Makefile b/net/xfrm/Makefile index 693aac1aa833..de3c1a625a46 100644 --- a/net/xfrm/Makefile +++ b/net/xfrm/Makefile | |||
@@ -2,6 +2,7 @@ | |||
2 | # Makefile for the XFRM subsystem. | 2 | # Makefile for the XFRM subsystem. |
3 | # | 3 | # |
4 | 4 | ||
5 | obj-$(CONFIG_XFRM) := xfrm_policy.o xfrm_state.o xfrm_input.o xfrm_algo.o | 5 | obj-$(CONFIG_XFRM) := xfrm_policy.o xfrm_state.o xfrm_hash.o \ |
6 | xfrm_input.o xfrm_algo.o | ||
6 | obj-$(CONFIG_XFRM_USER) += xfrm_user.o | 7 | obj-$(CONFIG_XFRM_USER) += xfrm_user.o |
7 | 8 | ||
diff --git a/net/xfrm/xfrm_hash.c b/net/xfrm/xfrm_hash.c new file mode 100644 index 000000000000..37643bb8768a --- /dev/null +++ b/net/xfrm/xfrm_hash.c | |||
@@ -0,0 +1,41 @@ | |||
1 | /* xfrm_hash.c: Common hash table code. | ||
2 | * | ||
3 | * Copyright (C) 2006 David S. Miller (davem@davemloft.net) | ||
4 | */ | ||
5 | |||
6 | #include <linux/kernel.h> | ||
7 | #include <linux/mm.h> | ||
8 | #include <linux/bootmem.h> | ||
9 | #include <linux/vmalloc.h> | ||
10 | #include <linux/slab.h> | ||
11 | #include <linux/xfrm.h> | ||
12 | |||
13 | #include "xfrm_hash.h" | ||
14 | |||
15 | struct hlist_head *xfrm_hash_alloc(unsigned int sz) | ||
16 | { | ||
17 | struct hlist_head *n; | ||
18 | |||
19 | if (sz <= PAGE_SIZE) | ||
20 | n = kmalloc(sz, GFP_KERNEL); | ||
21 | else if (hashdist) | ||
22 | n = __vmalloc(sz, GFP_KERNEL, PAGE_KERNEL); | ||
23 | else | ||
24 | n = (struct hlist_head *) | ||
25 | __get_free_pages(GFP_KERNEL, get_order(sz)); | ||
26 | |||
27 | if (n) | ||
28 | memset(n, 0, sz); | ||
29 | |||
30 | return n; | ||
31 | } | ||
32 | |||
33 | void xfrm_hash_free(struct hlist_head *n, unsigned int sz) | ||
34 | { | ||
35 | if (sz <= PAGE_SIZE) | ||
36 | kfree(n); | ||
37 | else if (hashdist) | ||
38 | vfree(n); | ||
39 | else | ||
40 | free_pages((unsigned long)n, get_order(sz)); | ||
41 | } | ||
diff --git a/net/xfrm/xfrm_hash.h b/net/xfrm/xfrm_hash.h new file mode 100644 index 000000000000..d3abb0b7dc62 --- /dev/null +++ b/net/xfrm/xfrm_hash.h | |||
@@ -0,0 +1,128 @@ | |||
1 | #ifndef _XFRM_HASH_H | ||
2 | #define _XFRM_HASH_H | ||
3 | |||
4 | #include <linux/xfrm.h> | ||
5 | #include <linux/socket.h> | ||
6 | |||
7 | static inline unsigned int __xfrm4_addr_hash(xfrm_address_t *addr) | ||
8 | { | ||
9 | return ntohl(addr->a4); | ||
10 | } | ||
11 | |||
12 | static inline unsigned int __xfrm6_addr_hash(xfrm_address_t *addr) | ||
13 | { | ||
14 | return ntohl(addr->a6[2] ^ addr->a6[3]); | ||
15 | } | ||
16 | |||
17 | static inline unsigned int __xfrm4_daddr_saddr_hash(xfrm_address_t *daddr, xfrm_address_t *saddr) | ||
18 | { | ||
19 | return ntohl(daddr->a4 ^ saddr->a4); | ||
20 | } | ||
21 | |||
22 | static inline unsigned int __xfrm6_daddr_saddr_hash(xfrm_address_t *daddr, xfrm_address_t *saddr) | ||
23 | { | ||
24 | return ntohl(daddr->a6[2] ^ daddr->a6[3] ^ | ||
25 | saddr->a6[2] ^ saddr->a6[3]); | ||
26 | } | ||
27 | |||
28 | static inline unsigned int __xfrm_dst_hash(xfrm_address_t *daddr, xfrm_address_t *saddr, | ||
29 | u32 reqid, unsigned short family, | ||
30 | unsigned int hmask) | ||
31 | { | ||
32 | unsigned int h = family ^ reqid; | ||
33 | switch (family) { | ||
34 | case AF_INET: | ||
35 | h ^= __xfrm4_daddr_saddr_hash(daddr, saddr); | ||
36 | break; | ||
37 | case AF_INET6: | ||
38 | h ^= __xfrm6_daddr_saddr_hash(daddr, saddr); | ||
39 | break; | ||
40 | } | ||
41 | return (h ^ (h >> 16)) & hmask; | ||
42 | } | ||
43 | |||
44 | static inline unsigned __xfrm_src_hash(xfrm_address_t *saddr, | ||
45 | unsigned short family, | ||
46 | unsigned int hmask) | ||
47 | { | ||
48 | unsigned int h = family; | ||
49 | switch (family) { | ||
50 | case AF_INET: | ||
51 | h ^= __xfrm4_addr_hash(saddr); | ||
52 | break; | ||
53 | case AF_INET6: | ||
54 | h ^= __xfrm6_addr_hash(saddr); | ||
55 | break; | ||
56 | }; | ||
57 | return (h ^ (h >> 16)) & hmask; | ||
58 | } | ||
59 | |||
60 | static inline unsigned int | ||
61 | __xfrm_spi_hash(xfrm_address_t *daddr, u32 spi, u8 proto, unsigned short family, | ||
62 | unsigned int hmask) | ||
63 | { | ||
64 | unsigned int h = spi ^ proto; | ||
65 | switch (family) { | ||
66 | case AF_INET: | ||
67 | h ^= __xfrm4_addr_hash(daddr); | ||
68 | break; | ||
69 | case AF_INET6: | ||
70 | h ^= __xfrm6_addr_hash(daddr); | ||
71 | break; | ||
72 | } | ||
73 | return (h ^ (h >> 10) ^ (h >> 20)) & hmask; | ||
74 | } | ||
75 | |||
76 | static inline unsigned int __idx_hash(u32 index, unsigned int hmask) | ||
77 | { | ||
78 | return (index ^ (index >> 8)) & hmask; | ||
79 | } | ||
80 | |||
81 | static inline unsigned int __sel_hash(struct xfrm_selector *sel, unsigned short family, unsigned int hmask) | ||
82 | { | ||
83 | xfrm_address_t *daddr = &sel->daddr; | ||
84 | xfrm_address_t *saddr = &sel->saddr; | ||
85 | unsigned int h = 0; | ||
86 | |||
87 | switch (family) { | ||
88 | case AF_INET: | ||
89 | if (sel->prefixlen_d != 32 || | ||
90 | sel->prefixlen_s != 32) | ||
91 | return hmask + 1; | ||
92 | |||
93 | h = __xfrm4_daddr_saddr_hash(daddr, saddr); | ||
94 | break; | ||
95 | |||
96 | case AF_INET6: | ||
97 | if (sel->prefixlen_d != 128 || | ||
98 | sel->prefixlen_s != 128) | ||
99 | return hmask + 1; | ||
100 | |||
101 | h = __xfrm6_daddr_saddr_hash(daddr, saddr); | ||
102 | break; | ||
103 | }; | ||
104 | h ^= (h >> 16); | ||
105 | return h & hmask; | ||
106 | } | ||
107 | |||
108 | static inline unsigned int __addr_hash(xfrm_address_t *daddr, xfrm_address_t *saddr, unsigned short family, unsigned int hmask) | ||
109 | { | ||
110 | unsigned int h = 0; | ||
111 | |||
112 | switch (family) { | ||
113 | case AF_INET: | ||
114 | h = __xfrm4_daddr_saddr_hash(daddr, saddr); | ||
115 | break; | ||
116 | |||
117 | case AF_INET6: | ||
118 | h = __xfrm6_daddr_saddr_hash(daddr, saddr); | ||
119 | break; | ||
120 | }; | ||
121 | h ^= (h >> 16); | ||
122 | return h & hmask; | ||
123 | } | ||
124 | |||
125 | extern struct hlist_head *xfrm_hash_alloc(unsigned int sz); | ||
126 | extern void xfrm_hash_free(struct hlist_head *n, unsigned int sz); | ||
127 | |||
128 | #endif /* _XFRM_HASH_H */ | ||
diff --git a/net/xfrm/xfrm_input.c b/net/xfrm/xfrm_input.c index 891a6090cc09..dfc90bb1cf1f 100644 --- a/net/xfrm/xfrm_input.c +++ b/net/xfrm/xfrm_input.c | |||
@@ -82,8 +82,6 @@ void __init xfrm_input_init(void) | |||
82 | { | 82 | { |
83 | secpath_cachep = kmem_cache_create("secpath_cache", | 83 | secpath_cachep = kmem_cache_create("secpath_cache", |
84 | sizeof(struct sec_path), | 84 | sizeof(struct sec_path), |
85 | 0, SLAB_HWCACHE_ALIGN, | 85 | 0, SLAB_HWCACHE_ALIGN|SLAB_PANIC, |
86 | NULL, NULL); | 86 | NULL, NULL); |
87 | if (!secpath_cachep) | ||
88 | panic("XFRM: failed to allocate secpath_cache\n"); | ||
89 | } | 87 | } |
diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c index 3da67ca2c3ce..b6e2e79d7261 100644 --- a/net/xfrm/xfrm_policy.c +++ b/net/xfrm/xfrm_policy.c | |||
@@ -22,16 +22,19 @@ | |||
22 | #include <linux/netdevice.h> | 22 | #include <linux/netdevice.h> |
23 | #include <linux/netfilter.h> | 23 | #include <linux/netfilter.h> |
24 | #include <linux/module.h> | 24 | #include <linux/module.h> |
25 | #include <linux/cache.h> | ||
25 | #include <net/xfrm.h> | 26 | #include <net/xfrm.h> |
26 | #include <net/ip.h> | 27 | #include <net/ip.h> |
27 | 28 | ||
29 | #include "xfrm_hash.h" | ||
30 | |||
28 | DEFINE_MUTEX(xfrm_cfg_mutex); | 31 | DEFINE_MUTEX(xfrm_cfg_mutex); |
29 | EXPORT_SYMBOL(xfrm_cfg_mutex); | 32 | EXPORT_SYMBOL(xfrm_cfg_mutex); |
30 | 33 | ||
31 | static DEFINE_RWLOCK(xfrm_policy_lock); | 34 | static DEFINE_RWLOCK(xfrm_policy_lock); |
32 | 35 | ||
33 | struct xfrm_policy *xfrm_policy_list[XFRM_POLICY_MAX*2]; | 36 | unsigned int xfrm_policy_count[XFRM_POLICY_MAX*2]; |
34 | EXPORT_SYMBOL(xfrm_policy_list); | 37 | EXPORT_SYMBOL(xfrm_policy_count); |
35 | 38 | ||
36 | static DEFINE_RWLOCK(xfrm_policy_afinfo_lock); | 39 | static DEFINE_RWLOCK(xfrm_policy_afinfo_lock); |
37 | static struct xfrm_policy_afinfo *xfrm_policy_afinfo[NPROTO]; | 40 | static struct xfrm_policy_afinfo *xfrm_policy_afinfo[NPROTO]; |
@@ -39,8 +42,7 @@ static struct xfrm_policy_afinfo *xfrm_policy_afinfo[NPROTO]; | |||
39 | static kmem_cache_t *xfrm_dst_cache __read_mostly; | 42 | static kmem_cache_t *xfrm_dst_cache __read_mostly; |
40 | 43 | ||
41 | static struct work_struct xfrm_policy_gc_work; | 44 | static struct work_struct xfrm_policy_gc_work; |
42 | static struct list_head xfrm_policy_gc_list = | 45 | static HLIST_HEAD(xfrm_policy_gc_list); |
43 | LIST_HEAD_INIT(xfrm_policy_gc_list); | ||
44 | static DEFINE_SPINLOCK(xfrm_policy_gc_lock); | 46 | static DEFINE_SPINLOCK(xfrm_policy_gc_lock); |
45 | 47 | ||
46 | static struct xfrm_policy_afinfo *xfrm_policy_get_afinfo(unsigned short family); | 48 | static struct xfrm_policy_afinfo *xfrm_policy_get_afinfo(unsigned short family); |
@@ -310,8 +312,10 @@ struct xfrm_policy *xfrm_policy_alloc(gfp_t gfp) | |||
310 | policy = kzalloc(sizeof(struct xfrm_policy), gfp); | 312 | policy = kzalloc(sizeof(struct xfrm_policy), gfp); |
311 | 313 | ||
312 | if (policy) { | 314 | if (policy) { |
313 | atomic_set(&policy->refcnt, 1); | 315 | INIT_HLIST_NODE(&policy->bydst); |
316 | INIT_HLIST_NODE(&policy->byidx); | ||
314 | rwlock_init(&policy->lock); | 317 | rwlock_init(&policy->lock); |
318 | atomic_set(&policy->refcnt, 1); | ||
315 | init_timer(&policy->timer); | 319 | init_timer(&policy->timer); |
316 | policy->timer.data = (unsigned long)policy; | 320 | policy->timer.data = (unsigned long)policy; |
317 | policy->timer.function = xfrm_policy_timer; | 321 | policy->timer.function = xfrm_policy_timer; |
@@ -357,17 +361,16 @@ static void xfrm_policy_gc_kill(struct xfrm_policy *policy) | |||
357 | static void xfrm_policy_gc_task(void *data) | 361 | static void xfrm_policy_gc_task(void *data) |
358 | { | 362 | { |
359 | struct xfrm_policy *policy; | 363 | struct xfrm_policy *policy; |
360 | struct list_head *entry, *tmp; | 364 | struct hlist_node *entry, *tmp; |
361 | struct list_head gc_list = LIST_HEAD_INIT(gc_list); | 365 | struct hlist_head gc_list; |
362 | 366 | ||
363 | spin_lock_bh(&xfrm_policy_gc_lock); | 367 | spin_lock_bh(&xfrm_policy_gc_lock); |
364 | list_splice_init(&xfrm_policy_gc_list, &gc_list); | 368 | gc_list.first = xfrm_policy_gc_list.first; |
369 | INIT_HLIST_HEAD(&xfrm_policy_gc_list); | ||
365 | spin_unlock_bh(&xfrm_policy_gc_lock); | 370 | spin_unlock_bh(&xfrm_policy_gc_lock); |
366 | 371 | ||
367 | list_for_each_safe(entry, tmp, &gc_list) { | 372 | hlist_for_each_entry_safe(policy, entry, tmp, &gc_list, bydst) |
368 | policy = list_entry(entry, struct xfrm_policy, list); | ||
369 | xfrm_policy_gc_kill(policy); | 373 | xfrm_policy_gc_kill(policy); |
370 | } | ||
371 | } | 374 | } |
372 | 375 | ||
373 | /* Rule must be locked. Release descentant resources, announce | 376 | /* Rule must be locked. Release descentant resources, announce |
@@ -389,70 +392,275 @@ static void xfrm_policy_kill(struct xfrm_policy *policy) | |||
389 | } | 392 | } |
390 | 393 | ||
391 | spin_lock(&xfrm_policy_gc_lock); | 394 | spin_lock(&xfrm_policy_gc_lock); |
392 | list_add(&policy->list, &xfrm_policy_gc_list); | 395 | hlist_add_head(&policy->bydst, &xfrm_policy_gc_list); |
393 | spin_unlock(&xfrm_policy_gc_lock); | 396 | spin_unlock(&xfrm_policy_gc_lock); |
394 | 397 | ||
395 | schedule_work(&xfrm_policy_gc_work); | 398 | schedule_work(&xfrm_policy_gc_work); |
396 | } | 399 | } |
397 | 400 | ||
401 | struct xfrm_policy_hash { | ||
402 | struct hlist_head *table; | ||
403 | unsigned int hmask; | ||
404 | }; | ||
405 | |||
406 | static struct hlist_head xfrm_policy_inexact[XFRM_POLICY_MAX*2]; | ||
407 | static struct xfrm_policy_hash xfrm_policy_bydst[XFRM_POLICY_MAX*2] __read_mostly; | ||
408 | static struct hlist_head *xfrm_policy_byidx __read_mostly; | ||
409 | static unsigned int xfrm_idx_hmask __read_mostly; | ||
410 | static unsigned int xfrm_policy_hashmax __read_mostly = 1 * 1024 * 1024; | ||
411 | |||
412 | static inline unsigned int idx_hash(u32 index) | ||
413 | { | ||
414 | return __idx_hash(index, xfrm_idx_hmask); | ||
415 | } | ||
416 | |||
417 | static struct hlist_head *policy_hash_bysel(struct xfrm_selector *sel, unsigned short family, int dir) | ||
418 | { | ||
419 | unsigned int hmask = xfrm_policy_bydst[dir].hmask; | ||
420 | unsigned int hash = __sel_hash(sel, family, hmask); | ||
421 | |||
422 | return (hash == hmask + 1 ? | ||
423 | &xfrm_policy_inexact[dir] : | ||
424 | xfrm_policy_bydst[dir].table + hash); | ||
425 | } | ||
426 | |||
427 | static struct hlist_head *policy_hash_direct(xfrm_address_t *daddr, xfrm_address_t *saddr, unsigned short family, int dir) | ||
428 | { | ||
429 | unsigned int hmask = xfrm_policy_bydst[dir].hmask; | ||
430 | unsigned int hash = __addr_hash(daddr, saddr, family, hmask); | ||
431 | |||
432 | return xfrm_policy_bydst[dir].table + hash; | ||
433 | } | ||
434 | |||
435 | static void xfrm_dst_hash_transfer(struct hlist_head *list, | ||
436 | struct hlist_head *ndsttable, | ||
437 | unsigned int nhashmask) | ||
438 | { | ||
439 | struct hlist_node *entry, *tmp; | ||
440 | struct xfrm_policy *pol; | ||
441 | |||
442 | hlist_for_each_entry_safe(pol, entry, tmp, list, bydst) { | ||
443 | unsigned int h; | ||
444 | |||
445 | h = __addr_hash(&pol->selector.daddr, &pol->selector.saddr, | ||
446 | pol->family, nhashmask); | ||
447 | hlist_add_head(&pol->bydst, ndsttable+h); | ||
448 | } | ||
449 | } | ||
450 | |||
451 | static void xfrm_idx_hash_transfer(struct hlist_head *list, | ||
452 | struct hlist_head *nidxtable, | ||
453 | unsigned int nhashmask) | ||
454 | { | ||
455 | struct hlist_node *entry, *tmp; | ||
456 | struct xfrm_policy *pol; | ||
457 | |||
458 | hlist_for_each_entry_safe(pol, entry, tmp, list, byidx) { | ||
459 | unsigned int h; | ||
460 | |||
461 | h = __idx_hash(pol->index, nhashmask); | ||
462 | hlist_add_head(&pol->byidx, nidxtable+h); | ||
463 | } | ||
464 | } | ||
465 | |||
466 | static unsigned long xfrm_new_hash_mask(unsigned int old_hmask) | ||
467 | { | ||
468 | return ((old_hmask + 1) << 1) - 1; | ||
469 | } | ||
470 | |||
471 | static void xfrm_bydst_resize(int dir) | ||
472 | { | ||
473 | unsigned int hmask = xfrm_policy_bydst[dir].hmask; | ||
474 | unsigned int nhashmask = xfrm_new_hash_mask(hmask); | ||
475 | unsigned int nsize = (nhashmask + 1) * sizeof(struct hlist_head); | ||
476 | struct hlist_head *odst = xfrm_policy_bydst[dir].table; | ||
477 | struct hlist_head *ndst = xfrm_hash_alloc(nsize); | ||
478 | int i; | ||
479 | |||
480 | if (!ndst) | ||
481 | return; | ||
482 | |||
483 | write_lock_bh(&xfrm_policy_lock); | ||
484 | |||
485 | for (i = hmask; i >= 0; i--) | ||
486 | xfrm_dst_hash_transfer(odst + i, ndst, nhashmask); | ||
487 | |||
488 | xfrm_policy_bydst[dir].table = ndst; | ||
489 | xfrm_policy_bydst[dir].hmask = nhashmask; | ||
490 | |||
491 | write_unlock_bh(&xfrm_policy_lock); | ||
492 | |||
493 | xfrm_hash_free(odst, (hmask + 1) * sizeof(struct hlist_head)); | ||
494 | } | ||
495 | |||
496 | static void xfrm_byidx_resize(int total) | ||
497 | { | ||
498 | unsigned int hmask = xfrm_idx_hmask; | ||
499 | unsigned int nhashmask = xfrm_new_hash_mask(hmask); | ||
500 | unsigned int nsize = (nhashmask + 1) * sizeof(struct hlist_head); | ||
501 | struct hlist_head *oidx = xfrm_policy_byidx; | ||
502 | struct hlist_head *nidx = xfrm_hash_alloc(nsize); | ||
503 | int i; | ||
504 | |||
505 | if (!nidx) | ||
506 | return; | ||
507 | |||
508 | write_lock_bh(&xfrm_policy_lock); | ||
509 | |||
510 | for (i = hmask; i >= 0; i--) | ||
511 | xfrm_idx_hash_transfer(oidx + i, nidx, nhashmask); | ||
512 | |||
513 | xfrm_policy_byidx = nidx; | ||
514 | xfrm_idx_hmask = nhashmask; | ||
515 | |||
516 | write_unlock_bh(&xfrm_policy_lock); | ||
517 | |||
518 | xfrm_hash_free(oidx, (hmask + 1) * sizeof(struct hlist_head)); | ||
519 | } | ||
520 | |||
521 | static inline int xfrm_bydst_should_resize(int dir, int *total) | ||
522 | { | ||
523 | unsigned int cnt = xfrm_policy_count[dir]; | ||
524 | unsigned int hmask = xfrm_policy_bydst[dir].hmask; | ||
525 | |||
526 | if (total) | ||
527 | *total += cnt; | ||
528 | |||
529 | if ((hmask + 1) < xfrm_policy_hashmax && | ||
530 | cnt > hmask) | ||
531 | return 1; | ||
532 | |||
533 | return 0; | ||
534 | } | ||
535 | |||
536 | static inline int xfrm_byidx_should_resize(int total) | ||
537 | { | ||
538 | unsigned int hmask = xfrm_idx_hmask; | ||
539 | |||
540 | if ((hmask + 1) < xfrm_policy_hashmax && | ||
541 | total > hmask) | ||
542 | return 1; | ||
543 | |||
544 | return 0; | ||
545 | } | ||
546 | |||
547 | static DEFINE_MUTEX(hash_resize_mutex); | ||
548 | |||
549 | static void xfrm_hash_resize(void *__unused) | ||
550 | { | ||
551 | int dir, total; | ||
552 | |||
553 | mutex_lock(&hash_resize_mutex); | ||
554 | |||
555 | total = 0; | ||
556 | for (dir = 0; dir < XFRM_POLICY_MAX * 2; dir++) { | ||
557 | if (xfrm_bydst_should_resize(dir, &total)) | ||
558 | xfrm_bydst_resize(dir); | ||
559 | } | ||
560 | if (xfrm_byidx_should_resize(total)) | ||
561 | xfrm_byidx_resize(total); | ||
562 | |||
563 | mutex_unlock(&hash_resize_mutex); | ||
564 | } | ||
565 | |||
566 | static DECLARE_WORK(xfrm_hash_work, xfrm_hash_resize, NULL); | ||
567 | |||
398 | /* Generate new index... KAME seems to generate them ordered by cost | 568 | /* Generate new index... KAME seems to generate them ordered by cost |
399 | * of an absolute inpredictability of ordering of rules. This will not pass. */ | 569 | * of an absolute inpredictability of ordering of rules. This will not pass. */ |
400 | static u32 xfrm_gen_index(int dir) | 570 | static u32 xfrm_gen_index(u8 type, int dir) |
401 | { | 571 | { |
402 | u32 idx; | ||
403 | struct xfrm_policy *p; | ||
404 | static u32 idx_generator; | 572 | static u32 idx_generator; |
405 | 573 | ||
406 | for (;;) { | 574 | for (;;) { |
575 | struct hlist_node *entry; | ||
576 | struct hlist_head *list; | ||
577 | struct xfrm_policy *p; | ||
578 | u32 idx; | ||
579 | int found; | ||
580 | |||
407 | idx = (idx_generator | dir); | 581 | idx = (idx_generator | dir); |
408 | idx_generator += 8; | 582 | idx_generator += 8; |
409 | if (idx == 0) | 583 | if (idx == 0) |
410 | idx = 8; | 584 | idx = 8; |
411 | for (p = xfrm_policy_list[dir]; p; p = p->next) { | 585 | list = xfrm_policy_byidx + idx_hash(idx); |
412 | if (p->index == idx) | 586 | found = 0; |
587 | hlist_for_each_entry(p, entry, list, byidx) { | ||
588 | if (p->index == idx) { | ||
589 | found = 1; | ||
413 | break; | 590 | break; |
591 | } | ||
414 | } | 592 | } |
415 | if (!p) | 593 | if (!found) |
416 | return idx; | 594 | return idx; |
417 | } | 595 | } |
418 | } | 596 | } |
419 | 597 | ||
598 | static inline int selector_cmp(struct xfrm_selector *s1, struct xfrm_selector *s2) | ||
599 | { | ||
600 | u32 *p1 = (u32 *) s1; | ||
601 | u32 *p2 = (u32 *) s2; | ||
602 | int len = sizeof(struct xfrm_selector) / sizeof(u32); | ||
603 | int i; | ||
604 | |||
605 | for (i = 0; i < len; i++) { | ||
606 | if (p1[i] != p2[i]) | ||
607 | return 1; | ||
608 | } | ||
609 | |||
610 | return 0; | ||
611 | } | ||
612 | |||
420 | int xfrm_policy_insert(int dir, struct xfrm_policy *policy, int excl) | 613 | int xfrm_policy_insert(int dir, struct xfrm_policy *policy, int excl) |
421 | { | 614 | { |
422 | struct xfrm_policy *pol, **p; | 615 | struct xfrm_policy *pol; |
423 | struct xfrm_policy *delpol = NULL; | 616 | struct xfrm_policy *delpol; |
424 | struct xfrm_policy **newpos = NULL; | 617 | struct hlist_head *chain; |
618 | struct hlist_node *entry, *newpos, *last; | ||
425 | struct dst_entry *gc_list; | 619 | struct dst_entry *gc_list; |
426 | 620 | ||
427 | write_lock_bh(&xfrm_policy_lock); | 621 | write_lock_bh(&xfrm_policy_lock); |
428 | for (p = &xfrm_policy_list[dir]; (pol=*p)!=NULL;) { | 622 | chain = policy_hash_bysel(&policy->selector, policy->family, dir); |
429 | if (!delpol && memcmp(&policy->selector, &pol->selector, sizeof(pol->selector)) == 0 && | 623 | delpol = NULL; |
624 | newpos = NULL; | ||
625 | last = NULL; | ||
626 | hlist_for_each_entry(pol, entry, chain, bydst) { | ||
627 | if (!delpol && | ||
628 | pol->type == policy->type && | ||
629 | !selector_cmp(&pol->selector, &policy->selector) && | ||
430 | xfrm_sec_ctx_match(pol->security, policy->security)) { | 630 | xfrm_sec_ctx_match(pol->security, policy->security)) { |
431 | if (excl) { | 631 | if (excl) { |
432 | write_unlock_bh(&xfrm_policy_lock); | 632 | write_unlock_bh(&xfrm_policy_lock); |
433 | return -EEXIST; | 633 | return -EEXIST; |
434 | } | 634 | } |
435 | *p = pol->next; | ||
436 | delpol = pol; | 635 | delpol = pol; |
437 | if (policy->priority > pol->priority) | 636 | if (policy->priority > pol->priority) |
438 | continue; | 637 | continue; |
439 | } else if (policy->priority >= pol->priority) { | 638 | } else if (policy->priority >= pol->priority) { |
440 | p = &pol->next; | 639 | last = &pol->bydst; |
441 | continue; | 640 | continue; |
442 | } | 641 | } |
443 | if (!newpos) | 642 | if (!newpos) |
444 | newpos = p; | 643 | newpos = &pol->bydst; |
445 | if (delpol) | 644 | if (delpol) |
446 | break; | 645 | break; |
447 | p = &pol->next; | 646 | last = &pol->bydst; |
448 | } | 647 | } |
648 | if (!newpos) | ||
649 | newpos = last; | ||
449 | if (newpos) | 650 | if (newpos) |
450 | p = newpos; | 651 | hlist_add_after(newpos, &policy->bydst); |
652 | else | ||
653 | hlist_add_head(&policy->bydst, chain); | ||
451 | xfrm_pol_hold(policy); | 654 | xfrm_pol_hold(policy); |
452 | policy->next = *p; | 655 | xfrm_policy_count[dir]++; |
453 | *p = policy; | ||
454 | atomic_inc(&flow_cache_genid); | 656 | atomic_inc(&flow_cache_genid); |
455 | policy->index = delpol ? delpol->index : xfrm_gen_index(dir); | 657 | if (delpol) { |
658 | hlist_del(&delpol->bydst); | ||
659 | hlist_del(&delpol->byidx); | ||
660 | xfrm_policy_count[dir]--; | ||
661 | } | ||
662 | policy->index = delpol ? delpol->index : xfrm_gen_index(policy->type, dir); | ||
663 | hlist_add_head(&policy->byidx, xfrm_policy_byidx+idx_hash(policy->index)); | ||
456 | policy->curlft.add_time = (unsigned long)xtime.tv_sec; | 664 | policy->curlft.add_time = (unsigned long)xtime.tv_sec; |
457 | policy->curlft.use_time = 0; | 665 | policy->curlft.use_time = 0; |
458 | if (!mod_timer(&policy->timer, jiffies + HZ)) | 666 | if (!mod_timer(&policy->timer, jiffies + HZ)) |
@@ -461,10 +669,13 @@ int xfrm_policy_insert(int dir, struct xfrm_policy *policy, int excl) | |||
461 | 669 | ||
462 | if (delpol) | 670 | if (delpol) |
463 | xfrm_policy_kill(delpol); | 671 | xfrm_policy_kill(delpol); |
672 | else if (xfrm_bydst_should_resize(dir, NULL)) | ||
673 | schedule_work(&xfrm_hash_work); | ||
464 | 674 | ||
465 | read_lock_bh(&xfrm_policy_lock); | 675 | read_lock_bh(&xfrm_policy_lock); |
466 | gc_list = NULL; | 676 | gc_list = NULL; |
467 | for (policy = policy->next; policy; policy = policy->next) { | 677 | entry = &policy->bydst; |
678 | hlist_for_each_entry_continue(policy, entry, bydst) { | ||
468 | struct dst_entry *dst; | 679 | struct dst_entry *dst; |
469 | 680 | ||
470 | write_lock(&policy->lock); | 681 | write_lock(&policy->lock); |
@@ -493,87 +704,146 @@ int xfrm_policy_insert(int dir, struct xfrm_policy *policy, int excl) | |||
493 | } | 704 | } |
494 | EXPORT_SYMBOL(xfrm_policy_insert); | 705 | EXPORT_SYMBOL(xfrm_policy_insert); |
495 | 706 | ||
496 | struct xfrm_policy *xfrm_policy_bysel_ctx(int dir, struct xfrm_selector *sel, | 707 | struct xfrm_policy *xfrm_policy_bysel_ctx(u8 type, int dir, |
708 | struct xfrm_selector *sel, | ||
497 | struct xfrm_sec_ctx *ctx, int delete) | 709 | struct xfrm_sec_ctx *ctx, int delete) |
498 | { | 710 | { |
499 | struct xfrm_policy *pol, **p; | 711 | struct xfrm_policy *pol, *ret; |
712 | struct hlist_head *chain; | ||
713 | struct hlist_node *entry; | ||
500 | 714 | ||
501 | write_lock_bh(&xfrm_policy_lock); | 715 | write_lock_bh(&xfrm_policy_lock); |
502 | for (p = &xfrm_policy_list[dir]; (pol=*p)!=NULL; p = &pol->next) { | 716 | chain = policy_hash_bysel(sel, sel->family, dir); |
503 | if ((memcmp(sel, &pol->selector, sizeof(*sel)) == 0) && | 717 | ret = NULL; |
504 | (xfrm_sec_ctx_match(ctx, pol->security))) { | 718 | hlist_for_each_entry(pol, entry, chain, bydst) { |
719 | if (pol->type == type && | ||
720 | !selector_cmp(sel, &pol->selector) && | ||
721 | xfrm_sec_ctx_match(ctx, pol->security)) { | ||
505 | xfrm_pol_hold(pol); | 722 | xfrm_pol_hold(pol); |
506 | if (delete) | 723 | if (delete) { |
507 | *p = pol->next; | 724 | hlist_del(&pol->bydst); |
725 | hlist_del(&pol->byidx); | ||
726 | xfrm_policy_count[dir]--; | ||
727 | } | ||
728 | ret = pol; | ||
508 | break; | 729 | break; |
509 | } | 730 | } |
510 | } | 731 | } |
511 | write_unlock_bh(&xfrm_policy_lock); | 732 | write_unlock_bh(&xfrm_policy_lock); |
512 | 733 | ||
513 | if (pol && delete) { | 734 | if (ret && delete) { |
514 | atomic_inc(&flow_cache_genid); | 735 | atomic_inc(&flow_cache_genid); |
515 | xfrm_policy_kill(pol); | 736 | xfrm_policy_kill(ret); |
516 | } | 737 | } |
517 | return pol; | 738 | return ret; |
518 | } | 739 | } |
519 | EXPORT_SYMBOL(xfrm_policy_bysel_ctx); | 740 | EXPORT_SYMBOL(xfrm_policy_bysel_ctx); |
520 | 741 | ||
521 | struct xfrm_policy *xfrm_policy_byid(int dir, u32 id, int delete) | 742 | struct xfrm_policy *xfrm_policy_byid(u8 type, int dir, u32 id, int delete) |
522 | { | 743 | { |
523 | struct xfrm_policy *pol, **p; | 744 | struct xfrm_policy *pol, *ret; |
745 | struct hlist_head *chain; | ||
746 | struct hlist_node *entry; | ||
524 | 747 | ||
525 | write_lock_bh(&xfrm_policy_lock); | 748 | write_lock_bh(&xfrm_policy_lock); |
526 | for (p = &xfrm_policy_list[dir]; (pol=*p)!=NULL; p = &pol->next) { | 749 | chain = xfrm_policy_byidx + idx_hash(id); |
527 | if (pol->index == id) { | 750 | ret = NULL; |
751 | hlist_for_each_entry(pol, entry, chain, byidx) { | ||
752 | if (pol->type == type && pol->index == id) { | ||
528 | xfrm_pol_hold(pol); | 753 | xfrm_pol_hold(pol); |
529 | if (delete) | 754 | if (delete) { |
530 | *p = pol->next; | 755 | hlist_del(&pol->bydst); |
756 | hlist_del(&pol->byidx); | ||
757 | xfrm_policy_count[dir]--; | ||
758 | } | ||
759 | ret = pol; | ||
531 | break; | 760 | break; |
532 | } | 761 | } |
533 | } | 762 | } |
534 | write_unlock_bh(&xfrm_policy_lock); | 763 | write_unlock_bh(&xfrm_policy_lock); |
535 | 764 | ||
536 | if (pol && delete) { | 765 | if (ret && delete) { |
537 | atomic_inc(&flow_cache_genid); | 766 | atomic_inc(&flow_cache_genid); |
538 | xfrm_policy_kill(pol); | 767 | xfrm_policy_kill(ret); |
539 | } | 768 | } |
540 | return pol; | 769 | return ret; |
541 | } | 770 | } |
542 | EXPORT_SYMBOL(xfrm_policy_byid); | 771 | EXPORT_SYMBOL(xfrm_policy_byid); |
543 | 772 | ||
544 | void xfrm_policy_flush(void) | 773 | void xfrm_policy_flush(u8 type) |
545 | { | 774 | { |
546 | struct xfrm_policy *xp; | ||
547 | int dir; | 775 | int dir; |
548 | 776 | ||
549 | write_lock_bh(&xfrm_policy_lock); | 777 | write_lock_bh(&xfrm_policy_lock); |
550 | for (dir = 0; dir < XFRM_POLICY_MAX; dir++) { | 778 | for (dir = 0; dir < XFRM_POLICY_MAX; dir++) { |
551 | while ((xp = xfrm_policy_list[dir]) != NULL) { | 779 | struct xfrm_policy *pol; |
552 | xfrm_policy_list[dir] = xp->next; | 780 | struct hlist_node *entry; |
781 | int i; | ||
782 | |||
783 | again1: | ||
784 | hlist_for_each_entry(pol, entry, | ||
785 | &xfrm_policy_inexact[dir], bydst) { | ||
786 | if (pol->type != type) | ||
787 | continue; | ||
788 | hlist_del(&pol->bydst); | ||
789 | hlist_del(&pol->byidx); | ||
553 | write_unlock_bh(&xfrm_policy_lock); | 790 | write_unlock_bh(&xfrm_policy_lock); |
554 | 791 | ||
555 | xfrm_policy_kill(xp); | 792 | xfrm_policy_kill(pol); |
556 | 793 | ||
557 | write_lock_bh(&xfrm_policy_lock); | 794 | write_lock_bh(&xfrm_policy_lock); |
795 | goto again1; | ||
558 | } | 796 | } |
797 | |||
798 | for (i = xfrm_policy_bydst[dir].hmask; i >= 0; i--) { | ||
799 | again2: | ||
800 | hlist_for_each_entry(pol, entry, | ||
801 | xfrm_policy_bydst[dir].table + i, | ||
802 | bydst) { | ||
803 | if (pol->type != type) | ||
804 | continue; | ||
805 | hlist_del(&pol->bydst); | ||
806 | hlist_del(&pol->byidx); | ||
807 | write_unlock_bh(&xfrm_policy_lock); | ||
808 | |||
809 | xfrm_policy_kill(pol); | ||
810 | |||
811 | write_lock_bh(&xfrm_policy_lock); | ||
812 | goto again2; | ||
813 | } | ||
814 | } | ||
815 | |||
816 | xfrm_policy_count[dir] = 0; | ||
559 | } | 817 | } |
560 | atomic_inc(&flow_cache_genid); | 818 | atomic_inc(&flow_cache_genid); |
561 | write_unlock_bh(&xfrm_policy_lock); | 819 | write_unlock_bh(&xfrm_policy_lock); |
562 | } | 820 | } |
563 | EXPORT_SYMBOL(xfrm_policy_flush); | 821 | EXPORT_SYMBOL(xfrm_policy_flush); |
564 | 822 | ||
565 | int xfrm_policy_walk(int (*func)(struct xfrm_policy *, int, int, void*), | 823 | int xfrm_policy_walk(u8 type, int (*func)(struct xfrm_policy *, int, int, void*), |
566 | void *data) | 824 | void *data) |
567 | { | 825 | { |
568 | struct xfrm_policy *xp; | 826 | struct xfrm_policy *pol; |
569 | int dir; | 827 | struct hlist_node *entry; |
570 | int count = 0; | 828 | int dir, count, error; |
571 | int error = 0; | ||
572 | 829 | ||
573 | read_lock_bh(&xfrm_policy_lock); | 830 | read_lock_bh(&xfrm_policy_lock); |
831 | count = 0; | ||
574 | for (dir = 0; dir < 2*XFRM_POLICY_MAX; dir++) { | 832 | for (dir = 0; dir < 2*XFRM_POLICY_MAX; dir++) { |
575 | for (xp = xfrm_policy_list[dir]; xp; xp = xp->next) | 833 | struct hlist_head *table = xfrm_policy_bydst[dir].table; |
576 | count++; | 834 | int i; |
835 | |||
836 | hlist_for_each_entry(pol, entry, | ||
837 | &xfrm_policy_inexact[dir], bydst) { | ||
838 | if (pol->type == type) | ||
839 | count++; | ||
840 | } | ||
841 | for (i = xfrm_policy_bydst[dir].hmask; i >= 0; i--) { | ||
842 | hlist_for_each_entry(pol, entry, table + i, bydst) { | ||
843 | if (pol->type == type) | ||
844 | count++; | ||
845 | } | ||
846 | } | ||
577 | } | 847 | } |
578 | 848 | ||
579 | if (count == 0) { | 849 | if (count == 0) { |
@@ -582,13 +852,28 @@ int xfrm_policy_walk(int (*func)(struct xfrm_policy *, int, int, void*), | |||
582 | } | 852 | } |
583 | 853 | ||
584 | for (dir = 0; dir < 2*XFRM_POLICY_MAX; dir++) { | 854 | for (dir = 0; dir < 2*XFRM_POLICY_MAX; dir++) { |
585 | for (xp = xfrm_policy_list[dir]; xp; xp = xp->next) { | 855 | struct hlist_head *table = xfrm_policy_bydst[dir].table; |
586 | error = func(xp, dir%XFRM_POLICY_MAX, --count, data); | 856 | int i; |
857 | |||
858 | hlist_for_each_entry(pol, entry, | ||
859 | &xfrm_policy_inexact[dir], bydst) { | ||
860 | if (pol->type != type) | ||
861 | continue; | ||
862 | error = func(pol, dir % XFRM_POLICY_MAX, --count, data); | ||
587 | if (error) | 863 | if (error) |
588 | goto out; | 864 | goto out; |
589 | } | 865 | } |
866 | for (i = xfrm_policy_bydst[dir].hmask; i >= 0; i--) { | ||
867 | hlist_for_each_entry(pol, entry, table + i, bydst) { | ||
868 | if (pol->type != type) | ||
869 | continue; | ||
870 | error = func(pol, dir % XFRM_POLICY_MAX, --count, data); | ||
871 | if (error) | ||
872 | goto out; | ||
873 | } | ||
874 | } | ||
590 | } | 875 | } |
591 | 876 | error = 0; | |
592 | out: | 877 | out: |
593 | read_unlock_bh(&xfrm_policy_lock); | 878 | read_unlock_bh(&xfrm_policy_lock); |
594 | return error; | 879 | return error; |
@@ -597,29 +882,79 @@ EXPORT_SYMBOL(xfrm_policy_walk); | |||
597 | 882 | ||
598 | /* Find policy to apply to this flow. */ | 883 | /* Find policy to apply to this flow. */ |
599 | 884 | ||
600 | static void xfrm_policy_lookup(struct flowi *fl, u32 sk_sid, u16 family, u8 dir, | 885 | static int xfrm_policy_match(struct xfrm_policy *pol, struct flowi *fl, |
601 | void **objp, atomic_t **obj_refp) | 886 | u8 type, u16 family, int dir) |
602 | { | 887 | { |
603 | struct xfrm_policy *pol; | 888 | struct xfrm_selector *sel = &pol->selector; |
889 | int match; | ||
604 | 890 | ||
605 | read_lock_bh(&xfrm_policy_lock); | 891 | if (pol->family != family || |
606 | for (pol = xfrm_policy_list[dir]; pol; pol = pol->next) { | 892 | pol->type != type) |
607 | struct xfrm_selector *sel = &pol->selector; | 893 | return 0; |
608 | int match; | ||
609 | 894 | ||
610 | if (pol->family != family) | 895 | match = xfrm_selector_match(sel, fl, family); |
611 | continue; | 896 | if (match) { |
897 | if (!security_xfrm_policy_lookup(pol, fl->secid, dir)) | ||
898 | return 1; | ||
899 | } | ||
612 | 900 | ||
613 | match = xfrm_selector_match(sel, fl, family); | 901 | return 0; |
902 | } | ||
614 | 903 | ||
615 | if (match) { | 904 | static struct xfrm_policy *xfrm_policy_lookup_bytype(u8 type, struct flowi *fl, |
616 | if (!security_xfrm_policy_lookup(pol, sk_sid, dir)) { | 905 | u16 family, u8 dir) |
617 | xfrm_pol_hold(pol); | 906 | { |
618 | break; | 907 | struct xfrm_policy *pol, *ret; |
619 | } | 908 | xfrm_address_t *daddr, *saddr; |
909 | struct hlist_node *entry; | ||
910 | struct hlist_head *chain; | ||
911 | u32 priority = ~0U; | ||
912 | |||
913 | daddr = xfrm_flowi_daddr(fl, family); | ||
914 | saddr = xfrm_flowi_saddr(fl, family); | ||
915 | if (unlikely(!daddr || !saddr)) | ||
916 | return NULL; | ||
917 | |||
918 | read_lock_bh(&xfrm_policy_lock); | ||
919 | chain = policy_hash_direct(daddr, saddr, family, dir); | ||
920 | ret = NULL; | ||
921 | hlist_for_each_entry(pol, entry, chain, bydst) { | ||
922 | if (xfrm_policy_match(pol, fl, type, family, dir)) { | ||
923 | ret = pol; | ||
924 | priority = ret->priority; | ||
925 | break; | ||
926 | } | ||
927 | } | ||
928 | chain = &xfrm_policy_inexact[dir]; | ||
929 | hlist_for_each_entry(pol, entry, chain, bydst) { | ||
930 | if (xfrm_policy_match(pol, fl, type, family, dir) && | ||
931 | pol->priority < priority) { | ||
932 | ret = pol; | ||
933 | break; | ||
620 | } | 934 | } |
621 | } | 935 | } |
936 | if (ret) | ||
937 | xfrm_pol_hold(ret); | ||
622 | read_unlock_bh(&xfrm_policy_lock); | 938 | read_unlock_bh(&xfrm_policy_lock); |
939 | |||
940 | return ret; | ||
941 | } | ||
942 | |||
943 | static void xfrm_policy_lookup(struct flowi *fl, u16 family, u8 dir, | ||
944 | void **objp, atomic_t **obj_refp) | ||
945 | { | ||
946 | struct xfrm_policy *pol; | ||
947 | |||
948 | #ifdef CONFIG_XFRM_SUB_POLICY | ||
949 | pol = xfrm_policy_lookup_bytype(XFRM_POLICY_TYPE_SUB, fl, family, dir); | ||
950 | if (pol) | ||
951 | goto end; | ||
952 | #endif | ||
953 | pol = xfrm_policy_lookup_bytype(XFRM_POLICY_TYPE_MAIN, fl, family, dir); | ||
954 | |||
955 | #ifdef CONFIG_XFRM_SUB_POLICY | ||
956 | end: | ||
957 | #endif | ||
623 | if ((*objp = (void *) pol) != NULL) | 958 | if ((*objp = (void *) pol) != NULL) |
624 | *obj_refp = &pol->refcnt; | 959 | *obj_refp = &pol->refcnt; |
625 | } | 960 | } |
@@ -641,7 +976,7 @@ static inline int policy_to_flow_dir(int dir) | |||
641 | }; | 976 | }; |
642 | } | 977 | } |
643 | 978 | ||
644 | static struct xfrm_policy *xfrm_sk_policy_lookup(struct sock *sk, int dir, struct flowi *fl, u32 sk_sid) | 979 | static struct xfrm_policy *xfrm_sk_policy_lookup(struct sock *sk, int dir, struct flowi *fl) |
645 | { | 980 | { |
646 | struct xfrm_policy *pol; | 981 | struct xfrm_policy *pol; |
647 | 982 | ||
@@ -652,7 +987,7 @@ static struct xfrm_policy *xfrm_sk_policy_lookup(struct sock *sk, int dir, struc | |||
652 | int err = 0; | 987 | int err = 0; |
653 | 988 | ||
654 | if (match) | 989 | if (match) |
655 | err = security_xfrm_policy_lookup(pol, sk_sid, policy_to_flow_dir(dir)); | 990 | err = security_xfrm_policy_lookup(pol, fl->secid, policy_to_flow_dir(dir)); |
656 | 991 | ||
657 | if (match && !err) | 992 | if (match && !err) |
658 | xfrm_pol_hold(pol); | 993 | xfrm_pol_hold(pol); |
@@ -665,24 +1000,29 @@ static struct xfrm_policy *xfrm_sk_policy_lookup(struct sock *sk, int dir, struc | |||
665 | 1000 | ||
666 | static void __xfrm_policy_link(struct xfrm_policy *pol, int dir) | 1001 | static void __xfrm_policy_link(struct xfrm_policy *pol, int dir) |
667 | { | 1002 | { |
668 | pol->next = xfrm_policy_list[dir]; | 1003 | struct hlist_head *chain = policy_hash_bysel(&pol->selector, |
669 | xfrm_policy_list[dir] = pol; | 1004 | pol->family, dir); |
1005 | |||
1006 | hlist_add_head(&pol->bydst, chain); | ||
1007 | hlist_add_head(&pol->byidx, xfrm_policy_byidx+idx_hash(pol->index)); | ||
1008 | xfrm_policy_count[dir]++; | ||
670 | xfrm_pol_hold(pol); | 1009 | xfrm_pol_hold(pol); |
1010 | |||
1011 | if (xfrm_bydst_should_resize(dir, NULL)) | ||
1012 | schedule_work(&xfrm_hash_work); | ||
671 | } | 1013 | } |
672 | 1014 | ||
673 | static struct xfrm_policy *__xfrm_policy_unlink(struct xfrm_policy *pol, | 1015 | static struct xfrm_policy *__xfrm_policy_unlink(struct xfrm_policy *pol, |
674 | int dir) | 1016 | int dir) |
675 | { | 1017 | { |
676 | struct xfrm_policy **polp; | 1018 | if (hlist_unhashed(&pol->bydst)) |
1019 | return NULL; | ||
677 | 1020 | ||
678 | for (polp = &xfrm_policy_list[dir]; | 1021 | hlist_del(&pol->bydst); |
679 | *polp != NULL; polp = &(*polp)->next) { | 1022 | hlist_del(&pol->byidx); |
680 | if (*polp == pol) { | 1023 | xfrm_policy_count[dir]--; |
681 | *polp = pol->next; | 1024 | |
682 | return pol; | 1025 | return pol; |
683 | } | ||
684 | } | ||
685 | return NULL; | ||
686 | } | 1026 | } |
687 | 1027 | ||
688 | int xfrm_policy_delete(struct xfrm_policy *pol, int dir) | 1028 | int xfrm_policy_delete(struct xfrm_policy *pol, int dir) |
@@ -704,12 +1044,17 @@ int xfrm_sk_policy_insert(struct sock *sk, int dir, struct xfrm_policy *pol) | |||
704 | { | 1044 | { |
705 | struct xfrm_policy *old_pol; | 1045 | struct xfrm_policy *old_pol; |
706 | 1046 | ||
1047 | #ifdef CONFIG_XFRM_SUB_POLICY | ||
1048 | if (pol && pol->type != XFRM_POLICY_TYPE_MAIN) | ||
1049 | return -EINVAL; | ||
1050 | #endif | ||
1051 | |||
707 | write_lock_bh(&xfrm_policy_lock); | 1052 | write_lock_bh(&xfrm_policy_lock); |
708 | old_pol = sk->sk_policy[dir]; | 1053 | old_pol = sk->sk_policy[dir]; |
709 | sk->sk_policy[dir] = pol; | 1054 | sk->sk_policy[dir] = pol; |
710 | if (pol) { | 1055 | if (pol) { |
711 | pol->curlft.add_time = (unsigned long)xtime.tv_sec; | 1056 | pol->curlft.add_time = (unsigned long)xtime.tv_sec; |
712 | pol->index = xfrm_gen_index(XFRM_POLICY_MAX+dir); | 1057 | pol->index = xfrm_gen_index(pol->type, XFRM_POLICY_MAX+dir); |
713 | __xfrm_policy_link(pol, XFRM_POLICY_MAX+dir); | 1058 | __xfrm_policy_link(pol, XFRM_POLICY_MAX+dir); |
714 | } | 1059 | } |
715 | if (old_pol) | 1060 | if (old_pol) |
@@ -738,6 +1083,7 @@ static struct xfrm_policy *clone_policy(struct xfrm_policy *old, int dir) | |||
738 | newp->flags = old->flags; | 1083 | newp->flags = old->flags; |
739 | newp->xfrm_nr = old->xfrm_nr; | 1084 | newp->xfrm_nr = old->xfrm_nr; |
740 | newp->index = old->index; | 1085 | newp->index = old->index; |
1086 | newp->type = old->type; | ||
741 | memcpy(newp->xfrm_vec, old->xfrm_vec, | 1087 | memcpy(newp->xfrm_vec, old->xfrm_vec, |
742 | newp->xfrm_nr*sizeof(struct xfrm_tmpl)); | 1088 | newp->xfrm_nr*sizeof(struct xfrm_tmpl)); |
743 | write_lock_bh(&xfrm_policy_lock); | 1089 | write_lock_bh(&xfrm_policy_lock); |
@@ -761,17 +1107,32 @@ int __xfrm_sk_clone_policy(struct sock *sk) | |||
761 | return 0; | 1107 | return 0; |
762 | } | 1108 | } |
763 | 1109 | ||
1110 | static int | ||
1111 | xfrm_get_saddr(xfrm_address_t *local, xfrm_address_t *remote, | ||
1112 | unsigned short family) | ||
1113 | { | ||
1114 | int err; | ||
1115 | struct xfrm_policy_afinfo *afinfo = xfrm_policy_get_afinfo(family); | ||
1116 | |||
1117 | if (unlikely(afinfo == NULL)) | ||
1118 | return -EINVAL; | ||
1119 | err = afinfo->get_saddr(local, remote); | ||
1120 | xfrm_policy_put_afinfo(afinfo); | ||
1121 | return err; | ||
1122 | } | ||
1123 | |||
764 | /* Resolve list of templates for the flow, given policy. */ | 1124 | /* Resolve list of templates for the flow, given policy. */ |
765 | 1125 | ||
766 | static int | 1126 | static int |
767 | xfrm_tmpl_resolve(struct xfrm_policy *policy, struct flowi *fl, | 1127 | xfrm_tmpl_resolve_one(struct xfrm_policy *policy, struct flowi *fl, |
768 | struct xfrm_state **xfrm, | 1128 | struct xfrm_state **xfrm, |
769 | unsigned short family) | 1129 | unsigned short family) |
770 | { | 1130 | { |
771 | int nx; | 1131 | int nx; |
772 | int i, error; | 1132 | int i, error; |
773 | xfrm_address_t *daddr = xfrm_flowi_daddr(fl, family); | 1133 | xfrm_address_t *daddr = xfrm_flowi_daddr(fl, family); |
774 | xfrm_address_t *saddr = xfrm_flowi_saddr(fl, family); | 1134 | xfrm_address_t *saddr = xfrm_flowi_saddr(fl, family); |
1135 | xfrm_address_t tmp; | ||
775 | 1136 | ||
776 | for (nx=0, i = 0; i < policy->xfrm_nr; i++) { | 1137 | for (nx=0, i = 0; i < policy->xfrm_nr; i++) { |
777 | struct xfrm_state *x; | 1138 | struct xfrm_state *x; |
@@ -779,9 +1140,15 @@ xfrm_tmpl_resolve(struct xfrm_policy *policy, struct flowi *fl, | |||
779 | xfrm_address_t *local = saddr; | 1140 | xfrm_address_t *local = saddr; |
780 | struct xfrm_tmpl *tmpl = &policy->xfrm_vec[i]; | 1141 | struct xfrm_tmpl *tmpl = &policy->xfrm_vec[i]; |
781 | 1142 | ||
782 | if (tmpl->mode) { | 1143 | if (tmpl->mode == XFRM_MODE_TUNNEL) { |
783 | remote = &tmpl->id.daddr; | 1144 | remote = &tmpl->id.daddr; |
784 | local = &tmpl->saddr; | 1145 | local = &tmpl->saddr; |
1146 | if (xfrm_addr_any(local, family)) { | ||
1147 | error = xfrm_get_saddr(&tmp, remote, family); | ||
1148 | if (error) | ||
1149 | goto fail; | ||
1150 | local = &tmp; | ||
1151 | } | ||
785 | } | 1152 | } |
786 | 1153 | ||
787 | x = xfrm_state_find(remote, local, fl, tmpl, policy, &error, family); | 1154 | x = xfrm_state_find(remote, local, fl, tmpl, policy, &error, family); |
@@ -809,6 +1176,45 @@ fail: | |||
809 | return error; | 1176 | return error; |
810 | } | 1177 | } |
811 | 1178 | ||
1179 | static int | ||
1180 | xfrm_tmpl_resolve(struct xfrm_policy **pols, int npols, struct flowi *fl, | ||
1181 | struct xfrm_state **xfrm, | ||
1182 | unsigned short family) | ||
1183 | { | ||
1184 | struct xfrm_state *tp[XFRM_MAX_DEPTH]; | ||
1185 | struct xfrm_state **tpp = (npols > 1) ? tp : xfrm; | ||
1186 | int cnx = 0; | ||
1187 | int error; | ||
1188 | int ret; | ||
1189 | int i; | ||
1190 | |||
1191 | for (i = 0; i < npols; i++) { | ||
1192 | if (cnx + pols[i]->xfrm_nr >= XFRM_MAX_DEPTH) { | ||
1193 | error = -ENOBUFS; | ||
1194 | goto fail; | ||
1195 | } | ||
1196 | |||
1197 | ret = xfrm_tmpl_resolve_one(pols[i], fl, &tpp[cnx], family); | ||
1198 | if (ret < 0) { | ||
1199 | error = ret; | ||
1200 | goto fail; | ||
1201 | } else | ||
1202 | cnx += ret; | ||
1203 | } | ||
1204 | |||
1205 | /* found states are sorted for outbound processing */ | ||
1206 | if (npols > 1) | ||
1207 | xfrm_state_sort(xfrm, tpp, cnx, family); | ||
1208 | |||
1209 | return cnx; | ||
1210 | |||
1211 | fail: | ||
1212 | for (cnx--; cnx>=0; cnx--) | ||
1213 | xfrm_state_put(tpp[cnx]); | ||
1214 | return error; | ||
1215 | |||
1216 | } | ||
1217 | |||
812 | /* Check that the bundle accepts the flow and its components are | 1218 | /* Check that the bundle accepts the flow and its components are |
813 | * still valid. | 1219 | * still valid. |
814 | */ | 1220 | */ |
@@ -855,6 +1261,11 @@ int xfrm_lookup(struct dst_entry **dst_p, struct flowi *fl, | |||
855 | struct sock *sk, int flags) | 1261 | struct sock *sk, int flags) |
856 | { | 1262 | { |
857 | struct xfrm_policy *policy; | 1263 | struct xfrm_policy *policy; |
1264 | struct xfrm_policy *pols[XFRM_POLICY_TYPE_MAX]; | ||
1265 | int npols; | ||
1266 | int pol_dead; | ||
1267 | int xfrm_nr; | ||
1268 | int pi; | ||
858 | struct xfrm_state *xfrm[XFRM_MAX_DEPTH]; | 1269 | struct xfrm_state *xfrm[XFRM_MAX_DEPTH]; |
859 | struct dst_entry *dst, *dst_orig = *dst_p; | 1270 | struct dst_entry *dst, *dst_orig = *dst_p; |
860 | int nx = 0; | 1271 | int nx = 0; |
@@ -862,19 +1273,26 @@ int xfrm_lookup(struct dst_entry **dst_p, struct flowi *fl, | |||
862 | u32 genid; | 1273 | u32 genid; |
863 | u16 family; | 1274 | u16 family; |
864 | u8 dir = policy_to_flow_dir(XFRM_POLICY_OUT); | 1275 | u8 dir = policy_to_flow_dir(XFRM_POLICY_OUT); |
865 | u32 sk_sid = security_sk_sid(sk, fl, dir); | 1276 | |
866 | restart: | 1277 | restart: |
867 | genid = atomic_read(&flow_cache_genid); | 1278 | genid = atomic_read(&flow_cache_genid); |
868 | policy = NULL; | 1279 | policy = NULL; |
1280 | for (pi = 0; pi < ARRAY_SIZE(pols); pi++) | ||
1281 | pols[pi] = NULL; | ||
1282 | npols = 0; | ||
1283 | pol_dead = 0; | ||
1284 | xfrm_nr = 0; | ||
1285 | |||
869 | if (sk && sk->sk_policy[1]) | 1286 | if (sk && sk->sk_policy[1]) |
870 | policy = xfrm_sk_policy_lookup(sk, XFRM_POLICY_OUT, fl, sk_sid); | 1287 | policy = xfrm_sk_policy_lookup(sk, XFRM_POLICY_OUT, fl); |
871 | 1288 | ||
872 | if (!policy) { | 1289 | if (!policy) { |
873 | /* To accelerate a bit... */ | 1290 | /* To accelerate a bit... */ |
874 | if ((dst_orig->flags & DST_NOXFRM) || !xfrm_policy_list[XFRM_POLICY_OUT]) | 1291 | if ((dst_orig->flags & DST_NOXFRM) || |
1292 | !xfrm_policy_count[XFRM_POLICY_OUT]) | ||
875 | return 0; | 1293 | return 0; |
876 | 1294 | ||
877 | policy = flow_cache_lookup(fl, sk_sid, dst_orig->ops->family, | 1295 | policy = flow_cache_lookup(fl, dst_orig->ops->family, |
878 | dir, xfrm_policy_lookup); | 1296 | dir, xfrm_policy_lookup); |
879 | } | 1297 | } |
880 | 1298 | ||
@@ -883,6 +1301,9 @@ restart: | |||
883 | 1301 | ||
884 | family = dst_orig->ops->family; | 1302 | family = dst_orig->ops->family; |
885 | policy->curlft.use_time = (unsigned long)xtime.tv_sec; | 1303 | policy->curlft.use_time = (unsigned long)xtime.tv_sec; |
1304 | pols[0] = policy; | ||
1305 | npols ++; | ||
1306 | xfrm_nr += pols[0]->xfrm_nr; | ||
886 | 1307 | ||
887 | switch (policy->action) { | 1308 | switch (policy->action) { |
888 | case XFRM_POLICY_BLOCK: | 1309 | case XFRM_POLICY_BLOCK: |
@@ -891,11 +1312,13 @@ restart: | |||
891 | goto error; | 1312 | goto error; |
892 | 1313 | ||
893 | case XFRM_POLICY_ALLOW: | 1314 | case XFRM_POLICY_ALLOW: |
1315 | #ifndef CONFIG_XFRM_SUB_POLICY | ||
894 | if (policy->xfrm_nr == 0) { | 1316 | if (policy->xfrm_nr == 0) { |
895 | /* Flow passes not transformed. */ | 1317 | /* Flow passes not transformed. */ |
896 | xfrm_pol_put(policy); | 1318 | xfrm_pol_put(policy); |
897 | return 0; | 1319 | return 0; |
898 | } | 1320 | } |
1321 | #endif | ||
899 | 1322 | ||
900 | /* Try to find matching bundle. | 1323 | /* Try to find matching bundle. |
901 | * | 1324 | * |
@@ -911,7 +1334,36 @@ restart: | |||
911 | if (dst) | 1334 | if (dst) |
912 | break; | 1335 | break; |
913 | 1336 | ||
914 | nx = xfrm_tmpl_resolve(policy, fl, xfrm, family); | 1337 | #ifdef CONFIG_XFRM_SUB_POLICY |
1338 | if (pols[0]->type != XFRM_POLICY_TYPE_MAIN) { | ||
1339 | pols[1] = xfrm_policy_lookup_bytype(XFRM_POLICY_TYPE_MAIN, | ||
1340 | fl, family, | ||
1341 | XFRM_POLICY_OUT); | ||
1342 | if (pols[1]) { | ||
1343 | if (pols[1]->action == XFRM_POLICY_BLOCK) { | ||
1344 | err = -EPERM; | ||
1345 | goto error; | ||
1346 | } | ||
1347 | npols ++; | ||
1348 | xfrm_nr += pols[1]->xfrm_nr; | ||
1349 | } | ||
1350 | } | ||
1351 | |||
1352 | /* | ||
1353 | * Because neither flowi nor bundle information knows about | ||
1354 | * transformation template size. On more than one policy usage | ||
1355 | * we can realize whether all of them is bypass or not after | ||
1356 | * they are searched. See above not-transformed bypass | ||
1357 | * is surrounded by non-sub policy configuration, too. | ||
1358 | */ | ||
1359 | if (xfrm_nr == 0) { | ||
1360 | /* Flow passes not transformed. */ | ||
1361 | xfrm_pols_put(pols, npols); | ||
1362 | return 0; | ||
1363 | } | ||
1364 | |||
1365 | #endif | ||
1366 | nx = xfrm_tmpl_resolve(pols, npols, fl, xfrm, family); | ||
915 | 1367 | ||
916 | if (unlikely(nx<0)) { | 1368 | if (unlikely(nx<0)) { |
917 | err = nx; | 1369 | err = nx; |
@@ -924,7 +1376,7 @@ restart: | |||
924 | set_current_state(TASK_RUNNING); | 1376 | set_current_state(TASK_RUNNING); |
925 | remove_wait_queue(&km_waitq, &wait); | 1377 | remove_wait_queue(&km_waitq, &wait); |
926 | 1378 | ||
927 | nx = xfrm_tmpl_resolve(policy, fl, xfrm, family); | 1379 | nx = xfrm_tmpl_resolve(pols, npols, fl, xfrm, family); |
928 | 1380 | ||
929 | if (nx == -EAGAIN && signal_pending(current)) { | 1381 | if (nx == -EAGAIN && signal_pending(current)) { |
930 | err = -ERESTART; | 1382 | err = -ERESTART; |
@@ -932,7 +1384,7 @@ restart: | |||
932 | } | 1384 | } |
933 | if (nx == -EAGAIN || | 1385 | if (nx == -EAGAIN || |
934 | genid != atomic_read(&flow_cache_genid)) { | 1386 | genid != atomic_read(&flow_cache_genid)) { |
935 | xfrm_pol_put(policy); | 1387 | xfrm_pols_put(pols, npols); |
936 | goto restart; | 1388 | goto restart; |
937 | } | 1389 | } |
938 | err = nx; | 1390 | err = nx; |
@@ -942,7 +1394,7 @@ restart: | |||
942 | } | 1394 | } |
943 | if (nx == 0) { | 1395 | if (nx == 0) { |
944 | /* Flow passes not transformed. */ | 1396 | /* Flow passes not transformed. */ |
945 | xfrm_pol_put(policy); | 1397 | xfrm_pols_put(pols, npols); |
946 | return 0; | 1398 | return 0; |
947 | } | 1399 | } |
948 | 1400 | ||
@@ -956,8 +1408,14 @@ restart: | |||
956 | goto error; | 1408 | goto error; |
957 | } | 1409 | } |
958 | 1410 | ||
1411 | for (pi = 0; pi < npols; pi++) { | ||
1412 | read_lock_bh(&pols[pi]->lock); | ||
1413 | pol_dead |= pols[pi]->dead; | ||
1414 | read_unlock_bh(&pols[pi]->lock); | ||
1415 | } | ||
1416 | |||
959 | write_lock_bh(&policy->lock); | 1417 | write_lock_bh(&policy->lock); |
960 | if (unlikely(policy->dead || stale_bundle(dst))) { | 1418 | if (unlikely(pol_dead || stale_bundle(dst))) { |
961 | /* Wow! While we worked on resolving, this | 1419 | /* Wow! While we worked on resolving, this |
962 | * policy has gone. Retry. It is not paranoia, | 1420 | * policy has gone. Retry. It is not paranoia, |
963 | * we just cannot enlist new bundle to dead object. | 1421 | * we just cannot enlist new bundle to dead object. |
@@ -977,17 +1435,34 @@ restart: | |||
977 | } | 1435 | } |
978 | *dst_p = dst; | 1436 | *dst_p = dst; |
979 | dst_release(dst_orig); | 1437 | dst_release(dst_orig); |
980 | xfrm_pol_put(policy); | 1438 | xfrm_pols_put(pols, npols); |
981 | return 0; | 1439 | return 0; |
982 | 1440 | ||
983 | error: | 1441 | error: |
984 | dst_release(dst_orig); | 1442 | dst_release(dst_orig); |
985 | xfrm_pol_put(policy); | 1443 | xfrm_pols_put(pols, npols); |
986 | *dst_p = NULL; | 1444 | *dst_p = NULL; |
987 | return err; | 1445 | return err; |
988 | } | 1446 | } |
989 | EXPORT_SYMBOL(xfrm_lookup); | 1447 | EXPORT_SYMBOL(xfrm_lookup); |
990 | 1448 | ||
1449 | static inline int | ||
1450 | xfrm_secpath_reject(int idx, struct sk_buff *skb, struct flowi *fl) | ||
1451 | { | ||
1452 | struct xfrm_state *x; | ||
1453 | int err; | ||
1454 | |||
1455 | if (!skb->sp || idx < 0 || idx >= skb->sp->len) | ||
1456 | return 0; | ||
1457 | x = skb->sp->xvec[idx]; | ||
1458 | if (!x->type->reject) | ||
1459 | return 0; | ||
1460 | xfrm_state_hold(x); | ||
1461 | err = x->type->reject(x, skb, fl); | ||
1462 | xfrm_state_put(x); | ||
1463 | return err; | ||
1464 | } | ||
1465 | |||
991 | /* When skb is transformed back to its "native" form, we have to | 1466 | /* When skb is transformed back to its "native" form, we have to |
992 | * check policy restrictions. At the moment we make this in maximally | 1467 | * check policy restrictions. At the moment we make this in maximally |
993 | * stupid way. Shame on me. :-) Of course, connected sockets must | 1468 | * stupid way. Shame on me. :-) Of course, connected sockets must |
@@ -1004,10 +1479,19 @@ xfrm_state_ok(struct xfrm_tmpl *tmpl, struct xfrm_state *x, | |||
1004 | (x->id.spi == tmpl->id.spi || !tmpl->id.spi) && | 1479 | (x->id.spi == tmpl->id.spi || !tmpl->id.spi) && |
1005 | (x->props.reqid == tmpl->reqid || !tmpl->reqid) && | 1480 | (x->props.reqid == tmpl->reqid || !tmpl->reqid) && |
1006 | x->props.mode == tmpl->mode && | 1481 | x->props.mode == tmpl->mode && |
1007 | (tmpl->aalgos & (1<<x->props.aalgo)) && | 1482 | ((tmpl->aalgos & (1<<x->props.aalgo)) || |
1008 | !(x->props.mode && xfrm_state_addr_cmp(tmpl, x, family)); | 1483 | !(xfrm_id_proto_match(tmpl->id.proto, IPSEC_PROTO_ANY))) && |
1484 | !(x->props.mode != XFRM_MODE_TRANSPORT && | ||
1485 | xfrm_state_addr_cmp(tmpl, x, family)); | ||
1009 | } | 1486 | } |
1010 | 1487 | ||
1488 | /* | ||
1489 | * 0 or more than 0 is returned when validation is succeeded (either bypass | ||
1490 | * because of optional transport mode, or next index of the mathced secpath | ||
1491 | * state with the template. | ||
1492 | * -1 is returned when no matching template is found. | ||
1493 | * Otherwise "-2 - errored_index" is returned. | ||
1494 | */ | ||
1011 | static inline int | 1495 | static inline int |
1012 | xfrm_policy_ok(struct xfrm_tmpl *tmpl, struct sec_path *sp, int start, | 1496 | xfrm_policy_ok(struct xfrm_tmpl *tmpl, struct sec_path *sp, int start, |
1013 | unsigned short family) | 1497 | unsigned short family) |
@@ -1015,15 +1499,18 @@ xfrm_policy_ok(struct xfrm_tmpl *tmpl, struct sec_path *sp, int start, | |||
1015 | int idx = start; | 1499 | int idx = start; |
1016 | 1500 | ||
1017 | if (tmpl->optional) { | 1501 | if (tmpl->optional) { |
1018 | if (!tmpl->mode) | 1502 | if (tmpl->mode == XFRM_MODE_TRANSPORT) |
1019 | return start; | 1503 | return start; |
1020 | } else | 1504 | } else |
1021 | start = -1; | 1505 | start = -1; |
1022 | for (; idx < sp->len; idx++) { | 1506 | for (; idx < sp->len; idx++) { |
1023 | if (xfrm_state_ok(tmpl, sp->xvec[idx], family)) | 1507 | if (xfrm_state_ok(tmpl, sp->xvec[idx], family)) |
1024 | return ++idx; | 1508 | return ++idx; |
1025 | if (sp->xvec[idx]->props.mode) | 1509 | if (sp->xvec[idx]->props.mode != XFRM_MODE_TRANSPORT) { |
1510 | if (start == -1) | ||
1511 | start = -2-idx; | ||
1026 | break; | 1512 | break; |
1513 | } | ||
1027 | } | 1514 | } |
1028 | return start; | 1515 | return start; |
1029 | } | 1516 | } |
@@ -1032,21 +1519,25 @@ int | |||
1032 | xfrm_decode_session(struct sk_buff *skb, struct flowi *fl, unsigned short family) | 1519 | xfrm_decode_session(struct sk_buff *skb, struct flowi *fl, unsigned short family) |
1033 | { | 1520 | { |
1034 | struct xfrm_policy_afinfo *afinfo = xfrm_policy_get_afinfo(family); | 1521 | struct xfrm_policy_afinfo *afinfo = xfrm_policy_get_afinfo(family); |
1522 | int err; | ||
1035 | 1523 | ||
1036 | if (unlikely(afinfo == NULL)) | 1524 | if (unlikely(afinfo == NULL)) |
1037 | return -EAFNOSUPPORT; | 1525 | return -EAFNOSUPPORT; |
1038 | 1526 | ||
1039 | afinfo->decode_session(skb, fl); | 1527 | afinfo->decode_session(skb, fl); |
1528 | err = security_xfrm_decode_session(skb, &fl->secid); | ||
1040 | xfrm_policy_put_afinfo(afinfo); | 1529 | xfrm_policy_put_afinfo(afinfo); |
1041 | return 0; | 1530 | return err; |
1042 | } | 1531 | } |
1043 | EXPORT_SYMBOL(xfrm_decode_session); | 1532 | EXPORT_SYMBOL(xfrm_decode_session); |
1044 | 1533 | ||
1045 | static inline int secpath_has_tunnel(struct sec_path *sp, int k) | 1534 | static inline int secpath_has_nontransport(struct sec_path *sp, int k, int *idxp) |
1046 | { | 1535 | { |
1047 | for (; k < sp->len; k++) { | 1536 | for (; k < sp->len; k++) { |
1048 | if (sp->xvec[k]->props.mode) | 1537 | if (sp->xvec[k]->props.mode != XFRM_MODE_TRANSPORT) { |
1538 | *idxp = k; | ||
1049 | return 1; | 1539 | return 1; |
1540 | } | ||
1050 | } | 1541 | } |
1051 | 1542 | ||
1052 | return 0; | 1543 | return 0; |
@@ -1056,16 +1547,18 @@ int __xfrm_policy_check(struct sock *sk, int dir, struct sk_buff *skb, | |||
1056 | unsigned short family) | 1547 | unsigned short family) |
1057 | { | 1548 | { |
1058 | struct xfrm_policy *pol; | 1549 | struct xfrm_policy *pol; |
1550 | struct xfrm_policy *pols[XFRM_POLICY_TYPE_MAX]; | ||
1551 | int npols = 0; | ||
1552 | int xfrm_nr; | ||
1553 | int pi; | ||
1059 | struct flowi fl; | 1554 | struct flowi fl; |
1060 | u8 fl_dir = policy_to_flow_dir(dir); | 1555 | u8 fl_dir = policy_to_flow_dir(dir); |
1061 | u32 sk_sid; | 1556 | int xerr_idx = -1; |
1062 | 1557 | ||
1063 | if (xfrm_decode_session(skb, &fl, family) < 0) | 1558 | if (xfrm_decode_session(skb, &fl, family) < 0) |
1064 | return 0; | 1559 | return 0; |
1065 | nf_nat_decode_session(skb, &fl, family); | 1560 | nf_nat_decode_session(skb, &fl, family); |
1066 | 1561 | ||
1067 | sk_sid = security_sk_sid(sk, &fl, fl_dir); | ||
1068 | |||
1069 | /* First, check used SA against their selectors. */ | 1562 | /* First, check used SA against their selectors. */ |
1070 | if (skb->sp) { | 1563 | if (skb->sp) { |
1071 | int i; | 1564 | int i; |
@@ -1079,46 +1572,90 @@ int __xfrm_policy_check(struct sock *sk, int dir, struct sk_buff *skb, | |||
1079 | 1572 | ||
1080 | pol = NULL; | 1573 | pol = NULL; |
1081 | if (sk && sk->sk_policy[dir]) | 1574 | if (sk && sk->sk_policy[dir]) |
1082 | pol = xfrm_sk_policy_lookup(sk, dir, &fl, sk_sid); | 1575 | pol = xfrm_sk_policy_lookup(sk, dir, &fl); |
1083 | 1576 | ||
1084 | if (!pol) | 1577 | if (!pol) |
1085 | pol = flow_cache_lookup(&fl, sk_sid, family, fl_dir, | 1578 | pol = flow_cache_lookup(&fl, family, fl_dir, |
1086 | xfrm_policy_lookup); | 1579 | xfrm_policy_lookup); |
1087 | 1580 | ||
1088 | if (!pol) | 1581 | if (!pol) { |
1089 | return !skb->sp || !secpath_has_tunnel(skb->sp, 0); | 1582 | if (skb->sp && secpath_has_nontransport(skb->sp, 0, &xerr_idx)) { |
1583 | xfrm_secpath_reject(xerr_idx, skb, &fl); | ||
1584 | return 0; | ||
1585 | } | ||
1586 | return 1; | ||
1587 | } | ||
1090 | 1588 | ||
1091 | pol->curlft.use_time = (unsigned long)xtime.tv_sec; | 1589 | pol->curlft.use_time = (unsigned long)xtime.tv_sec; |
1092 | 1590 | ||
1591 | pols[0] = pol; | ||
1592 | npols ++; | ||
1593 | #ifdef CONFIG_XFRM_SUB_POLICY | ||
1594 | if (pols[0]->type != XFRM_POLICY_TYPE_MAIN) { | ||
1595 | pols[1] = xfrm_policy_lookup_bytype(XFRM_POLICY_TYPE_MAIN, | ||
1596 | &fl, family, | ||
1597 | XFRM_POLICY_IN); | ||
1598 | if (pols[1]) { | ||
1599 | pols[1]->curlft.use_time = (unsigned long)xtime.tv_sec; | ||
1600 | npols ++; | ||
1601 | } | ||
1602 | } | ||
1603 | #endif | ||
1604 | |||
1093 | if (pol->action == XFRM_POLICY_ALLOW) { | 1605 | if (pol->action == XFRM_POLICY_ALLOW) { |
1094 | struct sec_path *sp; | 1606 | struct sec_path *sp; |
1095 | static struct sec_path dummy; | 1607 | static struct sec_path dummy; |
1608 | struct xfrm_tmpl *tp[XFRM_MAX_DEPTH]; | ||
1609 | struct xfrm_tmpl *stp[XFRM_MAX_DEPTH]; | ||
1610 | struct xfrm_tmpl **tpp = tp; | ||
1611 | int ti = 0; | ||
1096 | int i, k; | 1612 | int i, k; |
1097 | 1613 | ||
1098 | if ((sp = skb->sp) == NULL) | 1614 | if ((sp = skb->sp) == NULL) |
1099 | sp = &dummy; | 1615 | sp = &dummy; |
1100 | 1616 | ||
1617 | for (pi = 0; pi < npols; pi++) { | ||
1618 | if (pols[pi] != pol && | ||
1619 | pols[pi]->action != XFRM_POLICY_ALLOW) | ||
1620 | goto reject; | ||
1621 | if (ti + pols[pi]->xfrm_nr >= XFRM_MAX_DEPTH) | ||
1622 | goto reject_error; | ||
1623 | for (i = 0; i < pols[pi]->xfrm_nr; i++) | ||
1624 | tpp[ti++] = &pols[pi]->xfrm_vec[i]; | ||
1625 | } | ||
1626 | xfrm_nr = ti; | ||
1627 | if (npols > 1) { | ||
1628 | xfrm_tmpl_sort(stp, tpp, xfrm_nr, family); | ||
1629 | tpp = stp; | ||
1630 | } | ||
1631 | |||
1101 | /* For each tunnel xfrm, find the first matching tmpl. | 1632 | /* For each tunnel xfrm, find the first matching tmpl. |
1102 | * For each tmpl before that, find corresponding xfrm. | 1633 | * For each tmpl before that, find corresponding xfrm. |
1103 | * Order is _important_. Later we will implement | 1634 | * Order is _important_. Later we will implement |
1104 | * some barriers, but at the moment barriers | 1635 | * some barriers, but at the moment barriers |
1105 | * are implied between each two transformations. | 1636 | * are implied between each two transformations. |
1106 | */ | 1637 | */ |
1107 | for (i = pol->xfrm_nr-1, k = 0; i >= 0; i--) { | 1638 | for (i = xfrm_nr-1, k = 0; i >= 0; i--) { |
1108 | k = xfrm_policy_ok(pol->xfrm_vec+i, sp, k, family); | 1639 | k = xfrm_policy_ok(tpp[i], sp, k, family); |
1109 | if (k < 0) | 1640 | if (k < 0) { |
1641 | if (k < -1) | ||
1642 | /* "-2 - errored_index" returned */ | ||
1643 | xerr_idx = -(2+k); | ||
1110 | goto reject; | 1644 | goto reject; |
1645 | } | ||
1111 | } | 1646 | } |
1112 | 1647 | ||
1113 | if (secpath_has_tunnel(sp, k)) | 1648 | if (secpath_has_nontransport(sp, k, &xerr_idx)) |
1114 | goto reject; | 1649 | goto reject; |
1115 | 1650 | ||
1116 | xfrm_pol_put(pol); | 1651 | xfrm_pols_put(pols, npols); |
1117 | return 1; | 1652 | return 1; |
1118 | } | 1653 | } |
1119 | 1654 | ||
1120 | reject: | 1655 | reject: |
1121 | xfrm_pol_put(pol); | 1656 | xfrm_secpath_reject(xerr_idx, skb, &fl); |
1657 | reject_error: | ||
1658 | xfrm_pols_put(pols, npols); | ||
1122 | return 0; | 1659 | return 0; |
1123 | } | 1660 | } |
1124 | EXPORT_SYMBOL(__xfrm_policy_check); | 1661 | EXPORT_SYMBOL(__xfrm_policy_check); |
@@ -1166,7 +1703,7 @@ static struct dst_entry *xfrm_dst_check(struct dst_entry *dst, u32 cookie) | |||
1166 | 1703 | ||
1167 | static int stale_bundle(struct dst_entry *dst) | 1704 | static int stale_bundle(struct dst_entry *dst) |
1168 | { | 1705 | { |
1169 | return !xfrm_bundle_ok((struct xfrm_dst *)dst, NULL, AF_UNSPEC); | 1706 | return !xfrm_bundle_ok((struct xfrm_dst *)dst, NULL, AF_UNSPEC, 0); |
1170 | } | 1707 | } |
1171 | 1708 | ||
1172 | void xfrm_dst_ifdown(struct dst_entry *dst, struct net_device *dev) | 1709 | void xfrm_dst_ifdown(struct dst_entry *dst, struct net_device *dev) |
@@ -1196,33 +1733,50 @@ static struct dst_entry *xfrm_negative_advice(struct dst_entry *dst) | |||
1196 | return dst; | 1733 | return dst; |
1197 | } | 1734 | } |
1198 | 1735 | ||
1736 | static void prune_one_bundle(struct xfrm_policy *pol, int (*func)(struct dst_entry *), struct dst_entry **gc_list_p) | ||
1737 | { | ||
1738 | struct dst_entry *dst, **dstp; | ||
1739 | |||
1740 | write_lock(&pol->lock); | ||
1741 | dstp = &pol->bundles; | ||
1742 | while ((dst=*dstp) != NULL) { | ||
1743 | if (func(dst)) { | ||
1744 | *dstp = dst->next; | ||
1745 | dst->next = *gc_list_p; | ||
1746 | *gc_list_p = dst; | ||
1747 | } else { | ||
1748 | dstp = &dst->next; | ||
1749 | } | ||
1750 | } | ||
1751 | write_unlock(&pol->lock); | ||
1752 | } | ||
1753 | |||
1199 | static void xfrm_prune_bundles(int (*func)(struct dst_entry *)) | 1754 | static void xfrm_prune_bundles(int (*func)(struct dst_entry *)) |
1200 | { | 1755 | { |
1201 | int i; | 1756 | struct dst_entry *gc_list = NULL; |
1202 | struct xfrm_policy *pol; | 1757 | int dir; |
1203 | struct dst_entry *dst, **dstp, *gc_list = NULL; | ||
1204 | 1758 | ||
1205 | read_lock_bh(&xfrm_policy_lock); | 1759 | read_lock_bh(&xfrm_policy_lock); |
1206 | for (i=0; i<2*XFRM_POLICY_MAX; i++) { | 1760 | for (dir = 0; dir < XFRM_POLICY_MAX * 2; dir++) { |
1207 | for (pol = xfrm_policy_list[i]; pol; pol = pol->next) { | 1761 | struct xfrm_policy *pol; |
1208 | write_lock(&pol->lock); | 1762 | struct hlist_node *entry; |
1209 | dstp = &pol->bundles; | 1763 | struct hlist_head *table; |
1210 | while ((dst=*dstp) != NULL) { | 1764 | int i; |
1211 | if (func(dst)) { | 1765 | |
1212 | *dstp = dst->next; | 1766 | hlist_for_each_entry(pol, entry, |
1213 | dst->next = gc_list; | 1767 | &xfrm_policy_inexact[dir], bydst) |
1214 | gc_list = dst; | 1768 | prune_one_bundle(pol, func, &gc_list); |
1215 | } else { | 1769 | |
1216 | dstp = &dst->next; | 1770 | table = xfrm_policy_bydst[dir].table; |
1217 | } | 1771 | for (i = xfrm_policy_bydst[dir].hmask; i >= 0; i--) { |
1218 | } | 1772 | hlist_for_each_entry(pol, entry, table + i, bydst) |
1219 | write_unlock(&pol->lock); | 1773 | prune_one_bundle(pol, func, &gc_list); |
1220 | } | 1774 | } |
1221 | } | 1775 | } |
1222 | read_unlock_bh(&xfrm_policy_lock); | 1776 | read_unlock_bh(&xfrm_policy_lock); |
1223 | 1777 | ||
1224 | while (gc_list) { | 1778 | while (gc_list) { |
1225 | dst = gc_list; | 1779 | struct dst_entry *dst = gc_list; |
1226 | gc_list = dst->next; | 1780 | gc_list = dst->next; |
1227 | dst_free(dst); | 1781 | dst_free(dst); |
1228 | } | 1782 | } |
@@ -1238,22 +1792,12 @@ static void __xfrm_garbage_collect(void) | |||
1238 | xfrm_prune_bundles(unused_bundle); | 1792 | xfrm_prune_bundles(unused_bundle); |
1239 | } | 1793 | } |
1240 | 1794 | ||
1241 | int xfrm_flush_bundles(void) | 1795 | static int xfrm_flush_bundles(void) |
1242 | { | 1796 | { |
1243 | xfrm_prune_bundles(stale_bundle); | 1797 | xfrm_prune_bundles(stale_bundle); |
1244 | return 0; | 1798 | return 0; |
1245 | } | 1799 | } |
1246 | 1800 | ||
1247 | static int always_true(struct dst_entry *dst) | ||
1248 | { | ||
1249 | return 1; | ||
1250 | } | ||
1251 | |||
1252 | void xfrm_flush_all_bundles(void) | ||
1253 | { | ||
1254 | xfrm_prune_bundles(always_true); | ||
1255 | } | ||
1256 | |||
1257 | void xfrm_init_pmtu(struct dst_entry *dst) | 1801 | void xfrm_init_pmtu(struct dst_entry *dst) |
1258 | { | 1802 | { |
1259 | do { | 1803 | do { |
@@ -1281,7 +1825,7 @@ EXPORT_SYMBOL(xfrm_init_pmtu); | |||
1281 | * still valid. | 1825 | * still valid. |
1282 | */ | 1826 | */ |
1283 | 1827 | ||
1284 | int xfrm_bundle_ok(struct xfrm_dst *first, struct flowi *fl, int family) | 1828 | int xfrm_bundle_ok(struct xfrm_dst *first, struct flowi *fl, int family, int strict) |
1285 | { | 1829 | { |
1286 | struct dst_entry *dst = &first->u.dst; | 1830 | struct dst_entry *dst = &first->u.dst; |
1287 | struct xfrm_dst *last; | 1831 | struct xfrm_dst *last; |
@@ -1298,8 +1842,16 @@ int xfrm_bundle_ok(struct xfrm_dst *first, struct flowi *fl, int family) | |||
1298 | 1842 | ||
1299 | if (fl && !xfrm_selector_match(&dst->xfrm->sel, fl, family)) | 1843 | if (fl && !xfrm_selector_match(&dst->xfrm->sel, fl, family)) |
1300 | return 0; | 1844 | return 0; |
1845 | if (fl && !security_xfrm_flow_state_match(fl, dst->xfrm)) | ||
1846 | return 0; | ||
1301 | if (dst->xfrm->km.state != XFRM_STATE_VALID) | 1847 | if (dst->xfrm->km.state != XFRM_STATE_VALID) |
1302 | return 0; | 1848 | return 0; |
1849 | if (xdst->genid != dst->xfrm->genid) | ||
1850 | return 0; | ||
1851 | |||
1852 | if (strict && fl && dst->xfrm->props.mode != XFRM_MODE_TUNNEL && | ||
1853 | !xfrm_state_addr_flow_check(dst->xfrm, fl, family)) | ||
1854 | return 0; | ||
1303 | 1855 | ||
1304 | mtu = dst_mtu(dst->child); | 1856 | mtu = dst_mtu(dst->child); |
1305 | if (xdst->child_mtu_cached != mtu) { | 1857 | if (xdst->child_mtu_cached != mtu) { |
@@ -1448,12 +2000,33 @@ static struct notifier_block xfrm_dev_notifier = { | |||
1448 | 2000 | ||
1449 | static void __init xfrm_policy_init(void) | 2001 | static void __init xfrm_policy_init(void) |
1450 | { | 2002 | { |
2003 | unsigned int hmask, sz; | ||
2004 | int dir; | ||
2005 | |||
1451 | xfrm_dst_cache = kmem_cache_create("xfrm_dst_cache", | 2006 | xfrm_dst_cache = kmem_cache_create("xfrm_dst_cache", |
1452 | sizeof(struct xfrm_dst), | 2007 | sizeof(struct xfrm_dst), |
1453 | 0, SLAB_HWCACHE_ALIGN, | 2008 | 0, SLAB_HWCACHE_ALIGN|SLAB_PANIC, |
1454 | NULL, NULL); | 2009 | NULL, NULL); |
1455 | if (!xfrm_dst_cache) | 2010 | |
1456 | panic("XFRM: failed to allocate xfrm_dst_cache\n"); | 2011 | hmask = 8 - 1; |
2012 | sz = (hmask+1) * sizeof(struct hlist_head); | ||
2013 | |||
2014 | xfrm_policy_byidx = xfrm_hash_alloc(sz); | ||
2015 | xfrm_idx_hmask = hmask; | ||
2016 | if (!xfrm_policy_byidx) | ||
2017 | panic("XFRM: failed to allocate byidx hash\n"); | ||
2018 | |||
2019 | for (dir = 0; dir < XFRM_POLICY_MAX * 2; dir++) { | ||
2020 | struct xfrm_policy_hash *htab; | ||
2021 | |||
2022 | INIT_HLIST_HEAD(&xfrm_policy_inexact[dir]); | ||
2023 | |||
2024 | htab = &xfrm_policy_bydst[dir]; | ||
2025 | htab->table = xfrm_hash_alloc(sz); | ||
2026 | htab->hmask = hmask; | ||
2027 | if (!htab->table) | ||
2028 | panic("XFRM: failed to allocate bydst hash\n"); | ||
2029 | } | ||
1457 | 2030 | ||
1458 | INIT_WORK(&xfrm_policy_gc_work, xfrm_policy_gc_task, NULL); | 2031 | INIT_WORK(&xfrm_policy_gc_work, xfrm_policy_gc_task, NULL); |
1459 | register_netdevice_notifier(&xfrm_dev_notifier); | 2032 | register_netdevice_notifier(&xfrm_dev_notifier); |
diff --git a/net/xfrm/xfrm_state.c b/net/xfrm/xfrm_state.c index 0021aad5db43..9f63edd39346 100644 --- a/net/xfrm/xfrm_state.c +++ b/net/xfrm/xfrm_state.c | |||
@@ -18,8 +18,11 @@ | |||
18 | #include <linux/pfkeyv2.h> | 18 | #include <linux/pfkeyv2.h> |
19 | #include <linux/ipsec.h> | 19 | #include <linux/ipsec.h> |
20 | #include <linux/module.h> | 20 | #include <linux/module.h> |
21 | #include <linux/cache.h> | ||
21 | #include <asm/uaccess.h> | 22 | #include <asm/uaccess.h> |
22 | 23 | ||
24 | #include "xfrm_hash.h" | ||
25 | |||
23 | struct sock *xfrm_nl; | 26 | struct sock *xfrm_nl; |
24 | EXPORT_SYMBOL(xfrm_nl); | 27 | EXPORT_SYMBOL(xfrm_nl); |
25 | 28 | ||
@@ -32,7 +35,7 @@ EXPORT_SYMBOL(sysctl_xfrm_aevent_rseqth); | |||
32 | /* Each xfrm_state may be linked to two tables: | 35 | /* Each xfrm_state may be linked to two tables: |
33 | 36 | ||
34 | 1. Hash table by (spi,daddr,ah/esp) to find SA by SPI. (input,ctl) | 37 | 1. Hash table by (spi,daddr,ah/esp) to find SA by SPI. (input,ctl) |
35 | 2. Hash table by daddr to find what SAs exist for given | 38 | 2. Hash table by (daddr,family,reqid) to find what SAs exist for given |
36 | destination/tunnel endpoint. (output) | 39 | destination/tunnel endpoint. (output) |
37 | */ | 40 | */ |
38 | 41 | ||
@@ -44,8 +47,123 @@ static DEFINE_SPINLOCK(xfrm_state_lock); | |||
44 | * Main use is finding SA after policy selected tunnel or transport mode. | 47 | * Main use is finding SA after policy selected tunnel or transport mode. |
45 | * Also, it can be used by ah/esp icmp error handler to find offending SA. | 48 | * Also, it can be used by ah/esp icmp error handler to find offending SA. |
46 | */ | 49 | */ |
47 | static struct list_head xfrm_state_bydst[XFRM_DST_HSIZE]; | 50 | static struct hlist_head *xfrm_state_bydst __read_mostly; |
48 | static struct list_head xfrm_state_byspi[XFRM_DST_HSIZE]; | 51 | static struct hlist_head *xfrm_state_bysrc __read_mostly; |
52 | static struct hlist_head *xfrm_state_byspi __read_mostly; | ||
53 | static unsigned int xfrm_state_hmask __read_mostly; | ||
54 | static unsigned int xfrm_state_hashmax __read_mostly = 1 * 1024 * 1024; | ||
55 | static unsigned int xfrm_state_num; | ||
56 | static unsigned int xfrm_state_genid; | ||
57 | |||
58 | static inline unsigned int xfrm_dst_hash(xfrm_address_t *daddr, | ||
59 | xfrm_address_t *saddr, | ||
60 | u32 reqid, | ||
61 | unsigned short family) | ||
62 | { | ||
63 | return __xfrm_dst_hash(daddr, saddr, reqid, family, xfrm_state_hmask); | ||
64 | } | ||
65 | |||
66 | static inline unsigned int xfrm_src_hash(xfrm_address_t *addr, | ||
67 | unsigned short family) | ||
68 | { | ||
69 | return __xfrm_src_hash(addr, family, xfrm_state_hmask); | ||
70 | } | ||
71 | |||
72 | static inline unsigned int | ||
73 | xfrm_spi_hash(xfrm_address_t *daddr, u32 spi, u8 proto, unsigned short family) | ||
74 | { | ||
75 | return __xfrm_spi_hash(daddr, spi, proto, family, xfrm_state_hmask); | ||
76 | } | ||
77 | |||
78 | static void xfrm_hash_transfer(struct hlist_head *list, | ||
79 | struct hlist_head *ndsttable, | ||
80 | struct hlist_head *nsrctable, | ||
81 | struct hlist_head *nspitable, | ||
82 | unsigned int nhashmask) | ||
83 | { | ||
84 | struct hlist_node *entry, *tmp; | ||
85 | struct xfrm_state *x; | ||
86 | |||
87 | hlist_for_each_entry_safe(x, entry, tmp, list, bydst) { | ||
88 | unsigned int h; | ||
89 | |||
90 | h = __xfrm_dst_hash(&x->id.daddr, &x->props.saddr, | ||
91 | x->props.reqid, x->props.family, | ||
92 | nhashmask); | ||
93 | hlist_add_head(&x->bydst, ndsttable+h); | ||
94 | |||
95 | h = __xfrm_src_hash(&x->props.saddr, x->props.family, | ||
96 | nhashmask); | ||
97 | hlist_add_head(&x->bysrc, nsrctable+h); | ||
98 | |||
99 | h = __xfrm_spi_hash(&x->id.daddr, x->id.spi, x->id.proto, | ||
100 | x->props.family, nhashmask); | ||
101 | hlist_add_head(&x->byspi, nspitable+h); | ||
102 | } | ||
103 | } | ||
104 | |||
105 | static unsigned long xfrm_hash_new_size(void) | ||
106 | { | ||
107 | return ((xfrm_state_hmask + 1) << 1) * | ||
108 | sizeof(struct hlist_head); | ||
109 | } | ||
110 | |||
111 | static DEFINE_MUTEX(hash_resize_mutex); | ||
112 | |||
113 | static void xfrm_hash_resize(void *__unused) | ||
114 | { | ||
115 | struct hlist_head *ndst, *nsrc, *nspi, *odst, *osrc, *ospi; | ||
116 | unsigned long nsize, osize; | ||
117 | unsigned int nhashmask, ohashmask; | ||
118 | int i; | ||
119 | |||
120 | mutex_lock(&hash_resize_mutex); | ||
121 | |||
122 | nsize = xfrm_hash_new_size(); | ||
123 | ndst = xfrm_hash_alloc(nsize); | ||
124 | if (!ndst) | ||
125 | goto out_unlock; | ||
126 | nsrc = xfrm_hash_alloc(nsize); | ||
127 | if (!nsrc) { | ||
128 | xfrm_hash_free(ndst, nsize); | ||
129 | goto out_unlock; | ||
130 | } | ||
131 | nspi = xfrm_hash_alloc(nsize); | ||
132 | if (!nspi) { | ||
133 | xfrm_hash_free(ndst, nsize); | ||
134 | xfrm_hash_free(nsrc, nsize); | ||
135 | goto out_unlock; | ||
136 | } | ||
137 | |||
138 | spin_lock_bh(&xfrm_state_lock); | ||
139 | |||
140 | nhashmask = (nsize / sizeof(struct hlist_head)) - 1U; | ||
141 | for (i = xfrm_state_hmask; i >= 0; i--) | ||
142 | xfrm_hash_transfer(xfrm_state_bydst+i, ndst, nsrc, nspi, | ||
143 | nhashmask); | ||
144 | |||
145 | odst = xfrm_state_bydst; | ||
146 | osrc = xfrm_state_bysrc; | ||
147 | ospi = xfrm_state_byspi; | ||
148 | ohashmask = xfrm_state_hmask; | ||
149 | |||
150 | xfrm_state_bydst = ndst; | ||
151 | xfrm_state_bysrc = nsrc; | ||
152 | xfrm_state_byspi = nspi; | ||
153 | xfrm_state_hmask = nhashmask; | ||
154 | |||
155 | spin_unlock_bh(&xfrm_state_lock); | ||
156 | |||
157 | osize = (ohashmask + 1) * sizeof(struct hlist_head); | ||
158 | xfrm_hash_free(odst, osize); | ||
159 | xfrm_hash_free(osrc, osize); | ||
160 | xfrm_hash_free(ospi, osize); | ||
161 | |||
162 | out_unlock: | ||
163 | mutex_unlock(&hash_resize_mutex); | ||
164 | } | ||
165 | |||
166 | static DECLARE_WORK(xfrm_hash_work, xfrm_hash_resize, NULL); | ||
49 | 167 | ||
50 | DECLARE_WAIT_QUEUE_HEAD(km_waitq); | 168 | DECLARE_WAIT_QUEUE_HEAD(km_waitq); |
51 | EXPORT_SYMBOL(km_waitq); | 169 | EXPORT_SYMBOL(km_waitq); |
@@ -54,11 +172,9 @@ static DEFINE_RWLOCK(xfrm_state_afinfo_lock); | |||
54 | static struct xfrm_state_afinfo *xfrm_state_afinfo[NPROTO]; | 172 | static struct xfrm_state_afinfo *xfrm_state_afinfo[NPROTO]; |
55 | 173 | ||
56 | static struct work_struct xfrm_state_gc_work; | 174 | static struct work_struct xfrm_state_gc_work; |
57 | static struct list_head xfrm_state_gc_list = LIST_HEAD_INIT(xfrm_state_gc_list); | 175 | static HLIST_HEAD(xfrm_state_gc_list); |
58 | static DEFINE_SPINLOCK(xfrm_state_gc_lock); | 176 | static DEFINE_SPINLOCK(xfrm_state_gc_lock); |
59 | 177 | ||
60 | static int xfrm_state_gc_flush_bundles; | ||
61 | |||
62 | int __xfrm_state_delete(struct xfrm_state *x); | 178 | int __xfrm_state_delete(struct xfrm_state *x); |
63 | 179 | ||
64 | static struct xfrm_state_afinfo *xfrm_state_get_afinfo(unsigned short family); | 180 | static struct xfrm_state_afinfo *xfrm_state_get_afinfo(unsigned short family); |
@@ -69,14 +185,13 @@ void km_state_expired(struct xfrm_state *x, int hard, u32 pid); | |||
69 | 185 | ||
70 | static void xfrm_state_gc_destroy(struct xfrm_state *x) | 186 | static void xfrm_state_gc_destroy(struct xfrm_state *x) |
71 | { | 187 | { |
72 | if (del_timer(&x->timer)) | 188 | del_timer_sync(&x->timer); |
73 | BUG(); | 189 | del_timer_sync(&x->rtimer); |
74 | if (del_timer(&x->rtimer)) | ||
75 | BUG(); | ||
76 | kfree(x->aalg); | 190 | kfree(x->aalg); |
77 | kfree(x->ealg); | 191 | kfree(x->ealg); |
78 | kfree(x->calg); | 192 | kfree(x->calg); |
79 | kfree(x->encap); | 193 | kfree(x->encap); |
194 | kfree(x->coaddr); | ||
80 | if (x->mode) | 195 | if (x->mode) |
81 | xfrm_put_mode(x->mode); | 196 | xfrm_put_mode(x->mode); |
82 | if (x->type) { | 197 | if (x->type) { |
@@ -90,22 +205,17 @@ static void xfrm_state_gc_destroy(struct xfrm_state *x) | |||
90 | static void xfrm_state_gc_task(void *data) | 205 | static void xfrm_state_gc_task(void *data) |
91 | { | 206 | { |
92 | struct xfrm_state *x; | 207 | struct xfrm_state *x; |
93 | struct list_head *entry, *tmp; | 208 | struct hlist_node *entry, *tmp; |
94 | struct list_head gc_list = LIST_HEAD_INIT(gc_list); | 209 | struct hlist_head gc_list; |
95 | |||
96 | if (xfrm_state_gc_flush_bundles) { | ||
97 | xfrm_state_gc_flush_bundles = 0; | ||
98 | xfrm_flush_bundles(); | ||
99 | } | ||
100 | 210 | ||
101 | spin_lock_bh(&xfrm_state_gc_lock); | 211 | spin_lock_bh(&xfrm_state_gc_lock); |
102 | list_splice_init(&xfrm_state_gc_list, &gc_list); | 212 | gc_list.first = xfrm_state_gc_list.first; |
213 | INIT_HLIST_HEAD(&xfrm_state_gc_list); | ||
103 | spin_unlock_bh(&xfrm_state_gc_lock); | 214 | spin_unlock_bh(&xfrm_state_gc_lock); |
104 | 215 | ||
105 | list_for_each_safe(entry, tmp, &gc_list) { | 216 | hlist_for_each_entry_safe(x, entry, tmp, &gc_list, bydst) |
106 | x = list_entry(entry, struct xfrm_state, bydst); | ||
107 | xfrm_state_gc_destroy(x); | 217 | xfrm_state_gc_destroy(x); |
108 | } | 218 | |
109 | wake_up(&km_waitq); | 219 | wake_up(&km_waitq); |
110 | } | 220 | } |
111 | 221 | ||
@@ -168,9 +278,9 @@ static void xfrm_timer_handler(unsigned long data) | |||
168 | if (warn) | 278 | if (warn) |
169 | km_state_expired(x, 0, 0); | 279 | km_state_expired(x, 0, 0); |
170 | resched: | 280 | resched: |
171 | if (next != LONG_MAX && | 281 | if (next != LONG_MAX) |
172 | !mod_timer(&x->timer, jiffies + make_jiffies(next))) | 282 | mod_timer(&x->timer, jiffies + make_jiffies(next)); |
173 | xfrm_state_hold(x); | 283 | |
174 | goto out; | 284 | goto out; |
175 | 285 | ||
176 | expired: | 286 | expired: |
@@ -185,7 +295,6 @@ expired: | |||
185 | 295 | ||
186 | out: | 296 | out: |
187 | spin_unlock(&x->lock); | 297 | spin_unlock(&x->lock); |
188 | xfrm_state_put(x); | ||
189 | } | 298 | } |
190 | 299 | ||
191 | static void xfrm_replay_timer_handler(unsigned long data); | 300 | static void xfrm_replay_timer_handler(unsigned long data); |
@@ -199,8 +308,9 @@ struct xfrm_state *xfrm_state_alloc(void) | |||
199 | if (x) { | 308 | if (x) { |
200 | atomic_set(&x->refcnt, 1); | 309 | atomic_set(&x->refcnt, 1); |
201 | atomic_set(&x->tunnel_users, 0); | 310 | atomic_set(&x->tunnel_users, 0); |
202 | INIT_LIST_HEAD(&x->bydst); | 311 | INIT_HLIST_NODE(&x->bydst); |
203 | INIT_LIST_HEAD(&x->byspi); | 312 | INIT_HLIST_NODE(&x->bysrc); |
313 | INIT_HLIST_NODE(&x->byspi); | ||
204 | init_timer(&x->timer); | 314 | init_timer(&x->timer); |
205 | x->timer.function = xfrm_timer_handler; | 315 | x->timer.function = xfrm_timer_handler; |
206 | x->timer.data = (unsigned long)x; | 316 | x->timer.data = (unsigned long)x; |
@@ -225,7 +335,7 @@ void __xfrm_state_destroy(struct xfrm_state *x) | |||
225 | BUG_TRAP(x->km.state == XFRM_STATE_DEAD); | 335 | BUG_TRAP(x->km.state == XFRM_STATE_DEAD); |
226 | 336 | ||
227 | spin_lock_bh(&xfrm_state_gc_lock); | 337 | spin_lock_bh(&xfrm_state_gc_lock); |
228 | list_add(&x->bydst, &xfrm_state_gc_list); | 338 | hlist_add_head(&x->bydst, &xfrm_state_gc_list); |
229 | spin_unlock_bh(&xfrm_state_gc_lock); | 339 | spin_unlock_bh(&xfrm_state_gc_lock); |
230 | schedule_work(&xfrm_state_gc_work); | 340 | schedule_work(&xfrm_state_gc_work); |
231 | } | 341 | } |
@@ -238,27 +348,12 @@ int __xfrm_state_delete(struct xfrm_state *x) | |||
238 | if (x->km.state != XFRM_STATE_DEAD) { | 348 | if (x->km.state != XFRM_STATE_DEAD) { |
239 | x->km.state = XFRM_STATE_DEAD; | 349 | x->km.state = XFRM_STATE_DEAD; |
240 | spin_lock(&xfrm_state_lock); | 350 | spin_lock(&xfrm_state_lock); |
241 | list_del(&x->bydst); | 351 | hlist_del(&x->bydst); |
242 | __xfrm_state_put(x); | 352 | hlist_del(&x->bysrc); |
243 | if (x->id.spi) { | 353 | if (x->id.spi) |
244 | list_del(&x->byspi); | 354 | hlist_del(&x->byspi); |
245 | __xfrm_state_put(x); | 355 | xfrm_state_num--; |
246 | } | ||
247 | spin_unlock(&xfrm_state_lock); | 356 | spin_unlock(&xfrm_state_lock); |
248 | if (del_timer(&x->timer)) | ||
249 | __xfrm_state_put(x); | ||
250 | if (del_timer(&x->rtimer)) | ||
251 | __xfrm_state_put(x); | ||
252 | |||
253 | /* The number two in this test is the reference | ||
254 | * mentioned in the comment below plus the reference | ||
255 | * our caller holds. A larger value means that | ||
256 | * there are DSTs attached to this xfrm_state. | ||
257 | */ | ||
258 | if (atomic_read(&x->refcnt) > 2) { | ||
259 | xfrm_state_gc_flush_bundles = 1; | ||
260 | schedule_work(&xfrm_state_gc_work); | ||
261 | } | ||
262 | 357 | ||
263 | /* All xfrm_state objects are created by xfrm_state_alloc. | 358 | /* All xfrm_state objects are created by xfrm_state_alloc. |
264 | * The xfrm_state_alloc call gives a reference, and that | 359 | * The xfrm_state_alloc call gives a reference, and that |
@@ -287,14 +382,15 @@ EXPORT_SYMBOL(xfrm_state_delete); | |||
287 | void xfrm_state_flush(u8 proto) | 382 | void xfrm_state_flush(u8 proto) |
288 | { | 383 | { |
289 | int i; | 384 | int i; |
290 | struct xfrm_state *x; | ||
291 | 385 | ||
292 | spin_lock_bh(&xfrm_state_lock); | 386 | spin_lock_bh(&xfrm_state_lock); |
293 | for (i = 0; i < XFRM_DST_HSIZE; i++) { | 387 | for (i = 0; i <= xfrm_state_hmask; i++) { |
388 | struct hlist_node *entry; | ||
389 | struct xfrm_state *x; | ||
294 | restart: | 390 | restart: |
295 | list_for_each_entry(x, xfrm_state_bydst+i, bydst) { | 391 | hlist_for_each_entry(x, entry, xfrm_state_bydst+i, bydst) { |
296 | if (!xfrm_state_kern(x) && | 392 | if (!xfrm_state_kern(x) && |
297 | (proto == IPSEC_PROTO_ANY || x->id.proto == proto)) { | 393 | xfrm_id_proto_match(x->id.proto, proto)) { |
298 | xfrm_state_hold(x); | 394 | xfrm_state_hold(x); |
299 | spin_unlock_bh(&xfrm_state_lock); | 395 | spin_unlock_bh(&xfrm_state_lock); |
300 | 396 | ||
@@ -325,29 +421,103 @@ xfrm_init_tempsel(struct xfrm_state *x, struct flowi *fl, | |||
325 | return 0; | 421 | return 0; |
326 | } | 422 | } |
327 | 423 | ||
424 | static struct xfrm_state *__xfrm_state_lookup(xfrm_address_t *daddr, u32 spi, u8 proto, unsigned short family) | ||
425 | { | ||
426 | unsigned int h = xfrm_spi_hash(daddr, spi, proto, family); | ||
427 | struct xfrm_state *x; | ||
428 | struct hlist_node *entry; | ||
429 | |||
430 | hlist_for_each_entry(x, entry, xfrm_state_byspi+h, byspi) { | ||
431 | if (x->props.family != family || | ||
432 | x->id.spi != spi || | ||
433 | x->id.proto != proto) | ||
434 | continue; | ||
435 | |||
436 | switch (family) { | ||
437 | case AF_INET: | ||
438 | if (x->id.daddr.a4 != daddr->a4) | ||
439 | continue; | ||
440 | break; | ||
441 | case AF_INET6: | ||
442 | if (!ipv6_addr_equal((struct in6_addr *)daddr, | ||
443 | (struct in6_addr *) | ||
444 | x->id.daddr.a6)) | ||
445 | continue; | ||
446 | break; | ||
447 | }; | ||
448 | |||
449 | xfrm_state_hold(x); | ||
450 | return x; | ||
451 | } | ||
452 | |||
453 | return NULL; | ||
454 | } | ||
455 | |||
456 | static struct xfrm_state *__xfrm_state_lookup_byaddr(xfrm_address_t *daddr, xfrm_address_t *saddr, u8 proto, unsigned short family) | ||
457 | { | ||
458 | unsigned int h = xfrm_src_hash(saddr, family); | ||
459 | struct xfrm_state *x; | ||
460 | struct hlist_node *entry; | ||
461 | |||
462 | hlist_for_each_entry(x, entry, xfrm_state_bysrc+h, bysrc) { | ||
463 | if (x->props.family != family || | ||
464 | x->id.proto != proto) | ||
465 | continue; | ||
466 | |||
467 | switch (family) { | ||
468 | case AF_INET: | ||
469 | if (x->id.daddr.a4 != daddr->a4 || | ||
470 | x->props.saddr.a4 != saddr->a4) | ||
471 | continue; | ||
472 | break; | ||
473 | case AF_INET6: | ||
474 | if (!ipv6_addr_equal((struct in6_addr *)daddr, | ||
475 | (struct in6_addr *) | ||
476 | x->id.daddr.a6) || | ||
477 | !ipv6_addr_equal((struct in6_addr *)saddr, | ||
478 | (struct in6_addr *) | ||
479 | x->props.saddr.a6)) | ||
480 | continue; | ||
481 | break; | ||
482 | }; | ||
483 | |||
484 | xfrm_state_hold(x); | ||
485 | return x; | ||
486 | } | ||
487 | |||
488 | return NULL; | ||
489 | } | ||
490 | |||
491 | static inline struct xfrm_state * | ||
492 | __xfrm_state_locate(struct xfrm_state *x, int use_spi, int family) | ||
493 | { | ||
494 | if (use_spi) | ||
495 | return __xfrm_state_lookup(&x->id.daddr, x->id.spi, | ||
496 | x->id.proto, family); | ||
497 | else | ||
498 | return __xfrm_state_lookup_byaddr(&x->id.daddr, | ||
499 | &x->props.saddr, | ||
500 | x->id.proto, family); | ||
501 | } | ||
502 | |||
328 | struct xfrm_state * | 503 | struct xfrm_state * |
329 | xfrm_state_find(xfrm_address_t *daddr, xfrm_address_t *saddr, | 504 | xfrm_state_find(xfrm_address_t *daddr, xfrm_address_t *saddr, |
330 | struct flowi *fl, struct xfrm_tmpl *tmpl, | 505 | struct flowi *fl, struct xfrm_tmpl *tmpl, |
331 | struct xfrm_policy *pol, int *err, | 506 | struct xfrm_policy *pol, int *err, |
332 | unsigned short family) | 507 | unsigned short family) |
333 | { | 508 | { |
334 | unsigned h = xfrm_dst_hash(daddr, family); | 509 | unsigned int h = xfrm_dst_hash(daddr, saddr, tmpl->reqid, family); |
510 | struct hlist_node *entry; | ||
335 | struct xfrm_state *x, *x0; | 511 | struct xfrm_state *x, *x0; |
336 | int acquire_in_progress = 0; | 512 | int acquire_in_progress = 0; |
337 | int error = 0; | 513 | int error = 0; |
338 | struct xfrm_state *best = NULL; | 514 | struct xfrm_state *best = NULL; |
339 | struct xfrm_state_afinfo *afinfo; | ||
340 | 515 | ||
341 | afinfo = xfrm_state_get_afinfo(family); | ||
342 | if (afinfo == NULL) { | ||
343 | *err = -EAFNOSUPPORT; | ||
344 | return NULL; | ||
345 | } | ||
346 | |||
347 | spin_lock_bh(&xfrm_state_lock); | 516 | spin_lock_bh(&xfrm_state_lock); |
348 | list_for_each_entry(x, xfrm_state_bydst+h, bydst) { | 517 | hlist_for_each_entry(x, entry, xfrm_state_bydst+h, bydst) { |
349 | if (x->props.family == family && | 518 | if (x->props.family == family && |
350 | x->props.reqid == tmpl->reqid && | 519 | x->props.reqid == tmpl->reqid && |
520 | !(x->props.flags & XFRM_STATE_WILDRECV) && | ||
351 | xfrm_state_addr_check(x, daddr, saddr, family) && | 521 | xfrm_state_addr_check(x, daddr, saddr, family) && |
352 | tmpl->mode == x->props.mode && | 522 | tmpl->mode == x->props.mode && |
353 | tmpl->id.proto == x->id.proto && | 523 | tmpl->id.proto == x->id.proto && |
@@ -367,7 +537,7 @@ xfrm_state_find(xfrm_address_t *daddr, xfrm_address_t *saddr, | |||
367 | */ | 537 | */ |
368 | if (x->km.state == XFRM_STATE_VALID) { | 538 | if (x->km.state == XFRM_STATE_VALID) { |
369 | if (!xfrm_selector_match(&x->sel, fl, family) || | 539 | if (!xfrm_selector_match(&x->sel, fl, family) || |
370 | !xfrm_sec_ctx_match(pol->security, x->security)) | 540 | !security_xfrm_state_pol_flow_match(x, pol, fl)) |
371 | continue; | 541 | continue; |
372 | if (!best || | 542 | if (!best || |
373 | best->km.dying > x->km.dying || | 543 | best->km.dying > x->km.dying || |
@@ -379,7 +549,7 @@ xfrm_state_find(xfrm_address_t *daddr, xfrm_address_t *saddr, | |||
379 | } else if (x->km.state == XFRM_STATE_ERROR || | 549 | } else if (x->km.state == XFRM_STATE_ERROR || |
380 | x->km.state == XFRM_STATE_EXPIRED) { | 550 | x->km.state == XFRM_STATE_EXPIRED) { |
381 | if (xfrm_selector_match(&x->sel, fl, family) && | 551 | if (xfrm_selector_match(&x->sel, fl, family) && |
382 | xfrm_sec_ctx_match(pol->security, x->security)) | 552 | security_xfrm_state_pol_flow_match(x, pol, fl)) |
383 | error = -ESRCH; | 553 | error = -ESRCH; |
384 | } | 554 | } |
385 | } | 555 | } |
@@ -388,8 +558,8 @@ xfrm_state_find(xfrm_address_t *daddr, xfrm_address_t *saddr, | |||
388 | x = best; | 558 | x = best; |
389 | if (!x && !error && !acquire_in_progress) { | 559 | if (!x && !error && !acquire_in_progress) { |
390 | if (tmpl->id.spi && | 560 | if (tmpl->id.spi && |
391 | (x0 = afinfo->state_lookup(daddr, tmpl->id.spi, | 561 | (x0 = __xfrm_state_lookup(daddr, tmpl->id.spi, |
392 | tmpl->id.proto)) != NULL) { | 562 | tmpl->id.proto, family)) != NULL) { |
393 | xfrm_state_put(x0); | 563 | xfrm_state_put(x0); |
394 | error = -EEXIST; | 564 | error = -EEXIST; |
395 | goto out; | 565 | goto out; |
@@ -403,17 +573,24 @@ xfrm_state_find(xfrm_address_t *daddr, xfrm_address_t *saddr, | |||
403 | * to current session. */ | 573 | * to current session. */ |
404 | xfrm_init_tempsel(x, fl, tmpl, daddr, saddr, family); | 574 | xfrm_init_tempsel(x, fl, tmpl, daddr, saddr, family); |
405 | 575 | ||
576 | error = security_xfrm_state_alloc_acquire(x, pol->security, fl->secid); | ||
577 | if (error) { | ||
578 | x->km.state = XFRM_STATE_DEAD; | ||
579 | xfrm_state_put(x); | ||
580 | x = NULL; | ||
581 | goto out; | ||
582 | } | ||
583 | |||
406 | if (km_query(x, tmpl, pol) == 0) { | 584 | if (km_query(x, tmpl, pol) == 0) { |
407 | x->km.state = XFRM_STATE_ACQ; | 585 | x->km.state = XFRM_STATE_ACQ; |
408 | list_add_tail(&x->bydst, xfrm_state_bydst+h); | 586 | hlist_add_head(&x->bydst, xfrm_state_bydst+h); |
409 | xfrm_state_hold(x); | 587 | h = xfrm_src_hash(saddr, family); |
588 | hlist_add_head(&x->bysrc, xfrm_state_bysrc+h); | ||
410 | if (x->id.spi) { | 589 | if (x->id.spi) { |
411 | h = xfrm_spi_hash(&x->id.daddr, x->id.spi, x->id.proto, family); | 590 | h = xfrm_spi_hash(&x->id.daddr, x->id.spi, x->id.proto, family); |
412 | list_add(&x->byspi, xfrm_state_byspi+h); | 591 | hlist_add_head(&x->byspi, xfrm_state_byspi+h); |
413 | xfrm_state_hold(x); | ||
414 | } | 592 | } |
415 | x->lft.hard_add_expires_seconds = XFRM_ACQ_EXPIRES; | 593 | x->lft.hard_add_expires_seconds = XFRM_ACQ_EXPIRES; |
416 | xfrm_state_hold(x); | ||
417 | x->timer.expires = jiffies + XFRM_ACQ_EXPIRES*HZ; | 594 | x->timer.expires = jiffies + XFRM_ACQ_EXPIRES*HZ; |
418 | add_timer(&x->timer); | 595 | add_timer(&x->timer); |
419 | } else { | 596 | } else { |
@@ -429,59 +606,167 @@ out: | |||
429 | else | 606 | else |
430 | *err = acquire_in_progress ? -EAGAIN : error; | 607 | *err = acquire_in_progress ? -EAGAIN : error; |
431 | spin_unlock_bh(&xfrm_state_lock); | 608 | spin_unlock_bh(&xfrm_state_lock); |
432 | xfrm_state_put_afinfo(afinfo); | ||
433 | return x; | 609 | return x; |
434 | } | 610 | } |
435 | 611 | ||
436 | static void __xfrm_state_insert(struct xfrm_state *x) | 612 | static void __xfrm_state_insert(struct xfrm_state *x) |
437 | { | 613 | { |
438 | unsigned h = xfrm_dst_hash(&x->id.daddr, x->props.family); | 614 | unsigned int h; |
439 | 615 | ||
440 | list_add(&x->bydst, xfrm_state_bydst+h); | 616 | x->genid = ++xfrm_state_genid; |
441 | xfrm_state_hold(x); | ||
442 | 617 | ||
443 | h = xfrm_spi_hash(&x->id.daddr, x->id.spi, x->id.proto, x->props.family); | 618 | h = xfrm_dst_hash(&x->id.daddr, &x->props.saddr, |
619 | x->props.reqid, x->props.family); | ||
620 | hlist_add_head(&x->bydst, xfrm_state_bydst+h); | ||
444 | 621 | ||
445 | list_add(&x->byspi, xfrm_state_byspi+h); | 622 | h = xfrm_src_hash(&x->props.saddr, x->props.family); |
446 | xfrm_state_hold(x); | 623 | hlist_add_head(&x->bysrc, xfrm_state_bysrc+h); |
447 | 624 | ||
448 | if (!mod_timer(&x->timer, jiffies + HZ)) | 625 | if (xfrm_id_proto_match(x->id.proto, IPSEC_PROTO_ANY)) { |
449 | xfrm_state_hold(x); | 626 | h = xfrm_spi_hash(&x->id.daddr, x->id.spi, x->id.proto, |
627 | x->props.family); | ||
450 | 628 | ||
451 | if (x->replay_maxage && | 629 | hlist_add_head(&x->byspi, xfrm_state_byspi+h); |
452 | !mod_timer(&x->rtimer, jiffies + x->replay_maxage)) | 630 | } |
453 | xfrm_state_hold(x); | 631 | |
632 | mod_timer(&x->timer, jiffies + HZ); | ||
633 | if (x->replay_maxage) | ||
634 | mod_timer(&x->rtimer, jiffies + x->replay_maxage); | ||
454 | 635 | ||
455 | wake_up(&km_waitq); | 636 | wake_up(&km_waitq); |
637 | |||
638 | xfrm_state_num++; | ||
639 | |||
640 | if (x->bydst.next != NULL && | ||
641 | (xfrm_state_hmask + 1) < xfrm_state_hashmax && | ||
642 | xfrm_state_num > xfrm_state_hmask) | ||
643 | schedule_work(&xfrm_hash_work); | ||
644 | } | ||
645 | |||
646 | /* xfrm_state_lock is held */ | ||
647 | static void __xfrm_state_bump_genids(struct xfrm_state *xnew) | ||
648 | { | ||
649 | unsigned short family = xnew->props.family; | ||
650 | u32 reqid = xnew->props.reqid; | ||
651 | struct xfrm_state *x; | ||
652 | struct hlist_node *entry; | ||
653 | unsigned int h; | ||
654 | |||
655 | h = xfrm_dst_hash(&xnew->id.daddr, &xnew->props.saddr, reqid, family); | ||
656 | hlist_for_each_entry(x, entry, xfrm_state_bydst+h, bydst) { | ||
657 | if (x->props.family == family && | ||
658 | x->props.reqid == reqid && | ||
659 | !xfrm_addr_cmp(&x->id.daddr, &xnew->id.daddr, family) && | ||
660 | !xfrm_addr_cmp(&x->props.saddr, &xnew->props.saddr, family)) | ||
661 | x->genid = xfrm_state_genid; | ||
662 | } | ||
456 | } | 663 | } |
457 | 664 | ||
458 | void xfrm_state_insert(struct xfrm_state *x) | 665 | void xfrm_state_insert(struct xfrm_state *x) |
459 | { | 666 | { |
460 | spin_lock_bh(&xfrm_state_lock); | 667 | spin_lock_bh(&xfrm_state_lock); |
668 | __xfrm_state_bump_genids(x); | ||
461 | __xfrm_state_insert(x); | 669 | __xfrm_state_insert(x); |
462 | spin_unlock_bh(&xfrm_state_lock); | 670 | spin_unlock_bh(&xfrm_state_lock); |
463 | |||
464 | xfrm_flush_all_bundles(); | ||
465 | } | 671 | } |
466 | EXPORT_SYMBOL(xfrm_state_insert); | 672 | EXPORT_SYMBOL(xfrm_state_insert); |
467 | 673 | ||
674 | /* xfrm_state_lock is held */ | ||
675 | static struct xfrm_state *__find_acq_core(unsigned short family, u8 mode, u32 reqid, u8 proto, xfrm_address_t *daddr, xfrm_address_t *saddr, int create) | ||
676 | { | ||
677 | unsigned int h = xfrm_dst_hash(daddr, saddr, reqid, family); | ||
678 | struct hlist_node *entry; | ||
679 | struct xfrm_state *x; | ||
680 | |||
681 | hlist_for_each_entry(x, entry, xfrm_state_bydst+h, bydst) { | ||
682 | if (x->props.reqid != reqid || | ||
683 | x->props.mode != mode || | ||
684 | x->props.family != family || | ||
685 | x->km.state != XFRM_STATE_ACQ || | ||
686 | x->id.spi != 0) | ||
687 | continue; | ||
688 | |||
689 | switch (family) { | ||
690 | case AF_INET: | ||
691 | if (x->id.daddr.a4 != daddr->a4 || | ||
692 | x->props.saddr.a4 != saddr->a4) | ||
693 | continue; | ||
694 | break; | ||
695 | case AF_INET6: | ||
696 | if (!ipv6_addr_equal((struct in6_addr *)x->id.daddr.a6, | ||
697 | (struct in6_addr *)daddr) || | ||
698 | !ipv6_addr_equal((struct in6_addr *) | ||
699 | x->props.saddr.a6, | ||
700 | (struct in6_addr *)saddr)) | ||
701 | continue; | ||
702 | break; | ||
703 | }; | ||
704 | |||
705 | xfrm_state_hold(x); | ||
706 | return x; | ||
707 | } | ||
708 | |||
709 | if (!create) | ||
710 | return NULL; | ||
711 | |||
712 | x = xfrm_state_alloc(); | ||
713 | if (likely(x)) { | ||
714 | switch (family) { | ||
715 | case AF_INET: | ||
716 | x->sel.daddr.a4 = daddr->a4; | ||
717 | x->sel.saddr.a4 = saddr->a4; | ||
718 | x->sel.prefixlen_d = 32; | ||
719 | x->sel.prefixlen_s = 32; | ||
720 | x->props.saddr.a4 = saddr->a4; | ||
721 | x->id.daddr.a4 = daddr->a4; | ||
722 | break; | ||
723 | |||
724 | case AF_INET6: | ||
725 | ipv6_addr_copy((struct in6_addr *)x->sel.daddr.a6, | ||
726 | (struct in6_addr *)daddr); | ||
727 | ipv6_addr_copy((struct in6_addr *)x->sel.saddr.a6, | ||
728 | (struct in6_addr *)saddr); | ||
729 | x->sel.prefixlen_d = 128; | ||
730 | x->sel.prefixlen_s = 128; | ||
731 | ipv6_addr_copy((struct in6_addr *)x->props.saddr.a6, | ||
732 | (struct in6_addr *)saddr); | ||
733 | ipv6_addr_copy((struct in6_addr *)x->id.daddr.a6, | ||
734 | (struct in6_addr *)daddr); | ||
735 | break; | ||
736 | }; | ||
737 | |||
738 | x->km.state = XFRM_STATE_ACQ; | ||
739 | x->id.proto = proto; | ||
740 | x->props.family = family; | ||
741 | x->props.mode = mode; | ||
742 | x->props.reqid = reqid; | ||
743 | x->lft.hard_add_expires_seconds = XFRM_ACQ_EXPIRES; | ||
744 | xfrm_state_hold(x); | ||
745 | x->timer.expires = jiffies + XFRM_ACQ_EXPIRES*HZ; | ||
746 | add_timer(&x->timer); | ||
747 | hlist_add_head(&x->bydst, xfrm_state_bydst+h); | ||
748 | h = xfrm_src_hash(saddr, family); | ||
749 | hlist_add_head(&x->bysrc, xfrm_state_bysrc+h); | ||
750 | wake_up(&km_waitq); | ||
751 | } | ||
752 | |||
753 | return x; | ||
754 | } | ||
755 | |||
468 | static struct xfrm_state *__xfrm_find_acq_byseq(u32 seq); | 756 | static struct xfrm_state *__xfrm_find_acq_byseq(u32 seq); |
469 | 757 | ||
470 | int xfrm_state_add(struct xfrm_state *x) | 758 | int xfrm_state_add(struct xfrm_state *x) |
471 | { | 759 | { |
472 | struct xfrm_state_afinfo *afinfo; | ||
473 | struct xfrm_state *x1; | 760 | struct xfrm_state *x1; |
474 | int family; | 761 | int family; |
475 | int err; | 762 | int err; |
763 | int use_spi = xfrm_id_proto_match(x->id.proto, IPSEC_PROTO_ANY); | ||
476 | 764 | ||
477 | family = x->props.family; | 765 | family = x->props.family; |
478 | afinfo = xfrm_state_get_afinfo(family); | ||
479 | if (unlikely(afinfo == NULL)) | ||
480 | return -EAFNOSUPPORT; | ||
481 | 766 | ||
482 | spin_lock_bh(&xfrm_state_lock); | 767 | spin_lock_bh(&xfrm_state_lock); |
483 | 768 | ||
484 | x1 = afinfo->state_lookup(&x->id.daddr, x->id.spi, x->id.proto); | 769 | x1 = __xfrm_state_locate(x, use_spi, family); |
485 | if (x1) { | 770 | if (x1) { |
486 | xfrm_state_put(x1); | 771 | xfrm_state_put(x1); |
487 | x1 = NULL; | 772 | x1 = NULL; |
@@ -489,7 +774,7 @@ int xfrm_state_add(struct xfrm_state *x) | |||
489 | goto out; | 774 | goto out; |
490 | } | 775 | } |
491 | 776 | ||
492 | if (x->km.seq) { | 777 | if (use_spi && x->km.seq) { |
493 | x1 = __xfrm_find_acq_byseq(x->km.seq); | 778 | x1 = __xfrm_find_acq_byseq(x->km.seq); |
494 | if (x1 && xfrm_addr_cmp(&x1->id.daddr, &x->id.daddr, family)) { | 779 | if (x1 && xfrm_addr_cmp(&x1->id.daddr, &x->id.daddr, family)) { |
495 | xfrm_state_put(x1); | 780 | xfrm_state_put(x1); |
@@ -497,20 +782,17 @@ int xfrm_state_add(struct xfrm_state *x) | |||
497 | } | 782 | } |
498 | } | 783 | } |
499 | 784 | ||
500 | if (!x1) | 785 | if (use_spi && !x1) |
501 | x1 = afinfo->find_acq( | 786 | x1 = __find_acq_core(family, x->props.mode, x->props.reqid, |
502 | x->props.mode, x->props.reqid, x->id.proto, | 787 | x->id.proto, |
503 | &x->id.daddr, &x->props.saddr, 0); | 788 | &x->id.daddr, &x->props.saddr, 0); |
504 | 789 | ||
790 | __xfrm_state_bump_genids(x); | ||
505 | __xfrm_state_insert(x); | 791 | __xfrm_state_insert(x); |
506 | err = 0; | 792 | err = 0; |
507 | 793 | ||
508 | out: | 794 | out: |
509 | spin_unlock_bh(&xfrm_state_lock); | 795 | spin_unlock_bh(&xfrm_state_lock); |
510 | xfrm_state_put_afinfo(afinfo); | ||
511 | |||
512 | if (!err) | ||
513 | xfrm_flush_all_bundles(); | ||
514 | 796 | ||
515 | if (x1) { | 797 | if (x1) { |
516 | xfrm_state_delete(x1); | 798 | xfrm_state_delete(x1); |
@@ -523,16 +805,12 @@ EXPORT_SYMBOL(xfrm_state_add); | |||
523 | 805 | ||
524 | int xfrm_state_update(struct xfrm_state *x) | 806 | int xfrm_state_update(struct xfrm_state *x) |
525 | { | 807 | { |
526 | struct xfrm_state_afinfo *afinfo; | ||
527 | struct xfrm_state *x1; | 808 | struct xfrm_state *x1; |
528 | int err; | 809 | int err; |
529 | 810 | int use_spi = xfrm_id_proto_match(x->id.proto, IPSEC_PROTO_ANY); | |
530 | afinfo = xfrm_state_get_afinfo(x->props.family); | ||
531 | if (unlikely(afinfo == NULL)) | ||
532 | return -EAFNOSUPPORT; | ||
533 | 811 | ||
534 | spin_lock_bh(&xfrm_state_lock); | 812 | spin_lock_bh(&xfrm_state_lock); |
535 | x1 = afinfo->state_lookup(&x->id.daddr, x->id.spi, x->id.proto); | 813 | x1 = __xfrm_state_locate(x, use_spi, x->props.family); |
536 | 814 | ||
537 | err = -ESRCH; | 815 | err = -ESRCH; |
538 | if (!x1) | 816 | if (!x1) |
@@ -552,7 +830,6 @@ int xfrm_state_update(struct xfrm_state *x) | |||
552 | 830 | ||
553 | out: | 831 | out: |
554 | spin_unlock_bh(&xfrm_state_lock); | 832 | spin_unlock_bh(&xfrm_state_lock); |
555 | xfrm_state_put_afinfo(afinfo); | ||
556 | 833 | ||
557 | if (err) | 834 | if (err) |
558 | return err; | 835 | return err; |
@@ -568,11 +845,15 @@ out: | |||
568 | if (likely(x1->km.state == XFRM_STATE_VALID)) { | 845 | if (likely(x1->km.state == XFRM_STATE_VALID)) { |
569 | if (x->encap && x1->encap) | 846 | if (x->encap && x1->encap) |
570 | memcpy(x1->encap, x->encap, sizeof(*x1->encap)); | 847 | memcpy(x1->encap, x->encap, sizeof(*x1->encap)); |
848 | if (x->coaddr && x1->coaddr) { | ||
849 | memcpy(x1->coaddr, x->coaddr, sizeof(*x1->coaddr)); | ||
850 | } | ||
851 | if (!use_spi && memcmp(&x1->sel, &x->sel, sizeof(x1->sel))) | ||
852 | memcpy(&x1->sel, &x->sel, sizeof(x1->sel)); | ||
571 | memcpy(&x1->lft, &x->lft, sizeof(x1->lft)); | 853 | memcpy(&x1->lft, &x->lft, sizeof(x1->lft)); |
572 | x1->km.dying = 0; | 854 | x1->km.dying = 0; |
573 | 855 | ||
574 | if (!mod_timer(&x1->timer, jiffies + HZ)) | 856 | mod_timer(&x1->timer, jiffies + HZ); |
575 | xfrm_state_hold(x1); | ||
576 | if (x1->curlft.use_time) | 857 | if (x1->curlft.use_time) |
577 | xfrm_state_check_expire(x1); | 858 | xfrm_state_check_expire(x1); |
578 | 859 | ||
@@ -597,8 +878,7 @@ int xfrm_state_check_expire(struct xfrm_state *x) | |||
597 | if (x->curlft.bytes >= x->lft.hard_byte_limit || | 878 | if (x->curlft.bytes >= x->lft.hard_byte_limit || |
598 | x->curlft.packets >= x->lft.hard_packet_limit) { | 879 | x->curlft.packets >= x->lft.hard_packet_limit) { |
599 | x->km.state = XFRM_STATE_EXPIRED; | 880 | x->km.state = XFRM_STATE_EXPIRED; |
600 | if (!mod_timer(&x->timer, jiffies)) | 881 | mod_timer(&x->timer, jiffies); |
601 | xfrm_state_hold(x); | ||
602 | return -EINVAL; | 882 | return -EINVAL; |
603 | } | 883 | } |
604 | 884 | ||
@@ -640,46 +920,93 @@ xfrm_state_lookup(xfrm_address_t *daddr, u32 spi, u8 proto, | |||
640 | unsigned short family) | 920 | unsigned short family) |
641 | { | 921 | { |
642 | struct xfrm_state *x; | 922 | struct xfrm_state *x; |
643 | struct xfrm_state_afinfo *afinfo = xfrm_state_get_afinfo(family); | ||
644 | if (!afinfo) | ||
645 | return NULL; | ||
646 | 923 | ||
647 | spin_lock_bh(&xfrm_state_lock); | 924 | spin_lock_bh(&xfrm_state_lock); |
648 | x = afinfo->state_lookup(daddr, spi, proto); | 925 | x = __xfrm_state_lookup(daddr, spi, proto, family); |
649 | spin_unlock_bh(&xfrm_state_lock); | 926 | spin_unlock_bh(&xfrm_state_lock); |
650 | xfrm_state_put_afinfo(afinfo); | ||
651 | return x; | 927 | return x; |
652 | } | 928 | } |
653 | EXPORT_SYMBOL(xfrm_state_lookup); | 929 | EXPORT_SYMBOL(xfrm_state_lookup); |
654 | 930 | ||
655 | struct xfrm_state * | 931 | struct xfrm_state * |
932 | xfrm_state_lookup_byaddr(xfrm_address_t *daddr, xfrm_address_t *saddr, | ||
933 | u8 proto, unsigned short family) | ||
934 | { | ||
935 | struct xfrm_state *x; | ||
936 | |||
937 | spin_lock_bh(&xfrm_state_lock); | ||
938 | x = __xfrm_state_lookup_byaddr(daddr, saddr, proto, family); | ||
939 | spin_unlock_bh(&xfrm_state_lock); | ||
940 | return x; | ||
941 | } | ||
942 | EXPORT_SYMBOL(xfrm_state_lookup_byaddr); | ||
943 | |||
944 | struct xfrm_state * | ||
656 | xfrm_find_acq(u8 mode, u32 reqid, u8 proto, | 945 | xfrm_find_acq(u8 mode, u32 reqid, u8 proto, |
657 | xfrm_address_t *daddr, xfrm_address_t *saddr, | 946 | xfrm_address_t *daddr, xfrm_address_t *saddr, |
658 | int create, unsigned short family) | 947 | int create, unsigned short family) |
659 | { | 948 | { |
660 | struct xfrm_state *x; | 949 | struct xfrm_state *x; |
950 | |||
951 | spin_lock_bh(&xfrm_state_lock); | ||
952 | x = __find_acq_core(family, mode, reqid, proto, daddr, saddr, create); | ||
953 | spin_unlock_bh(&xfrm_state_lock); | ||
954 | |||
955 | return x; | ||
956 | } | ||
957 | EXPORT_SYMBOL(xfrm_find_acq); | ||
958 | |||
959 | #ifdef CONFIG_XFRM_SUB_POLICY | ||
960 | int | ||
961 | xfrm_tmpl_sort(struct xfrm_tmpl **dst, struct xfrm_tmpl **src, int n, | ||
962 | unsigned short family) | ||
963 | { | ||
964 | int err = 0; | ||
661 | struct xfrm_state_afinfo *afinfo = xfrm_state_get_afinfo(family); | 965 | struct xfrm_state_afinfo *afinfo = xfrm_state_get_afinfo(family); |
662 | if (!afinfo) | 966 | if (!afinfo) |
663 | return NULL; | 967 | return -EAFNOSUPPORT; |
664 | 968 | ||
665 | spin_lock_bh(&xfrm_state_lock); | 969 | spin_lock_bh(&xfrm_state_lock); |
666 | x = afinfo->find_acq(mode, reqid, proto, daddr, saddr, create); | 970 | if (afinfo->tmpl_sort) |
971 | err = afinfo->tmpl_sort(dst, src, n); | ||
667 | spin_unlock_bh(&xfrm_state_lock); | 972 | spin_unlock_bh(&xfrm_state_lock); |
668 | xfrm_state_put_afinfo(afinfo); | 973 | xfrm_state_put_afinfo(afinfo); |
669 | return x; | 974 | return err; |
670 | } | 975 | } |
671 | EXPORT_SYMBOL(xfrm_find_acq); | 976 | EXPORT_SYMBOL(xfrm_tmpl_sort); |
977 | |||
978 | int | ||
979 | xfrm_state_sort(struct xfrm_state **dst, struct xfrm_state **src, int n, | ||
980 | unsigned short family) | ||
981 | { | ||
982 | int err = 0; | ||
983 | struct xfrm_state_afinfo *afinfo = xfrm_state_get_afinfo(family); | ||
984 | if (!afinfo) | ||
985 | return -EAFNOSUPPORT; | ||
986 | |||
987 | spin_lock_bh(&xfrm_state_lock); | ||
988 | if (afinfo->state_sort) | ||
989 | err = afinfo->state_sort(dst, src, n); | ||
990 | spin_unlock_bh(&xfrm_state_lock); | ||
991 | xfrm_state_put_afinfo(afinfo); | ||
992 | return err; | ||
993 | } | ||
994 | EXPORT_SYMBOL(xfrm_state_sort); | ||
995 | #endif | ||
672 | 996 | ||
673 | /* Silly enough, but I'm lazy to build resolution list */ | 997 | /* Silly enough, but I'm lazy to build resolution list */ |
674 | 998 | ||
675 | static struct xfrm_state *__xfrm_find_acq_byseq(u32 seq) | 999 | static struct xfrm_state *__xfrm_find_acq_byseq(u32 seq) |
676 | { | 1000 | { |
677 | int i; | 1001 | int i; |
678 | struct xfrm_state *x; | ||
679 | 1002 | ||
680 | for (i = 0; i < XFRM_DST_HSIZE; i++) { | 1003 | for (i = 0; i <= xfrm_state_hmask; i++) { |
681 | list_for_each_entry(x, xfrm_state_bydst+i, bydst) { | 1004 | struct hlist_node *entry; |
682 | if (x->km.seq == seq && x->km.state == XFRM_STATE_ACQ) { | 1005 | struct xfrm_state *x; |
1006 | |||
1007 | hlist_for_each_entry(x, entry, xfrm_state_bydst+i, bydst) { | ||
1008 | if (x->km.seq == seq && | ||
1009 | x->km.state == XFRM_STATE_ACQ) { | ||
683 | xfrm_state_hold(x); | 1010 | xfrm_state_hold(x); |
684 | return x; | 1011 | return x; |
685 | } | 1012 | } |
@@ -715,7 +1042,7 @@ EXPORT_SYMBOL(xfrm_get_acqseq); | |||
715 | void | 1042 | void |
716 | xfrm_alloc_spi(struct xfrm_state *x, u32 minspi, u32 maxspi) | 1043 | xfrm_alloc_spi(struct xfrm_state *x, u32 minspi, u32 maxspi) |
717 | { | 1044 | { |
718 | u32 h; | 1045 | unsigned int h; |
719 | struct xfrm_state *x0; | 1046 | struct xfrm_state *x0; |
720 | 1047 | ||
721 | if (x->id.spi) | 1048 | if (x->id.spi) |
@@ -745,8 +1072,7 @@ xfrm_alloc_spi(struct xfrm_state *x, u32 minspi, u32 maxspi) | |||
745 | if (x->id.spi) { | 1072 | if (x->id.spi) { |
746 | spin_lock_bh(&xfrm_state_lock); | 1073 | spin_lock_bh(&xfrm_state_lock); |
747 | h = xfrm_spi_hash(&x->id.daddr, x->id.spi, x->id.proto, x->props.family); | 1074 | h = xfrm_spi_hash(&x->id.daddr, x->id.spi, x->id.proto, x->props.family); |
748 | list_add(&x->byspi, xfrm_state_byspi+h); | 1075 | hlist_add_head(&x->byspi, xfrm_state_byspi+h); |
749 | xfrm_state_hold(x); | ||
750 | spin_unlock_bh(&xfrm_state_lock); | 1076 | spin_unlock_bh(&xfrm_state_lock); |
751 | wake_up(&km_waitq); | 1077 | wake_up(&km_waitq); |
752 | } | 1078 | } |
@@ -758,13 +1084,14 @@ int xfrm_state_walk(u8 proto, int (*func)(struct xfrm_state *, int, void*), | |||
758 | { | 1084 | { |
759 | int i; | 1085 | int i; |
760 | struct xfrm_state *x; | 1086 | struct xfrm_state *x; |
1087 | struct hlist_node *entry; | ||
761 | int count = 0; | 1088 | int count = 0; |
762 | int err = 0; | 1089 | int err = 0; |
763 | 1090 | ||
764 | spin_lock_bh(&xfrm_state_lock); | 1091 | spin_lock_bh(&xfrm_state_lock); |
765 | for (i = 0; i < XFRM_DST_HSIZE; i++) { | 1092 | for (i = 0; i <= xfrm_state_hmask; i++) { |
766 | list_for_each_entry(x, xfrm_state_bydst+i, bydst) { | 1093 | hlist_for_each_entry(x, entry, xfrm_state_bydst+i, bydst) { |
767 | if (proto == IPSEC_PROTO_ANY || x->id.proto == proto) | 1094 | if (xfrm_id_proto_match(x->id.proto, proto)) |
768 | count++; | 1095 | count++; |
769 | } | 1096 | } |
770 | } | 1097 | } |
@@ -773,9 +1100,9 @@ int xfrm_state_walk(u8 proto, int (*func)(struct xfrm_state *, int, void*), | |||
773 | goto out; | 1100 | goto out; |
774 | } | 1101 | } |
775 | 1102 | ||
776 | for (i = 0; i < XFRM_DST_HSIZE; i++) { | 1103 | for (i = 0; i <= xfrm_state_hmask; i++) { |
777 | list_for_each_entry(x, xfrm_state_bydst+i, bydst) { | 1104 | hlist_for_each_entry(x, entry, xfrm_state_bydst+i, bydst) { |
778 | if (proto != IPSEC_PROTO_ANY && x->id.proto != proto) | 1105 | if (!xfrm_id_proto_match(x->id.proto, proto)) |
779 | continue; | 1106 | continue; |
780 | err = func(x, --count, data); | 1107 | err = func(x, --count, data); |
781 | if (err) | 1108 | if (err) |
@@ -832,10 +1159,8 @@ void xfrm_replay_notify(struct xfrm_state *x, int event) | |||
832 | km_state_notify(x, &c); | 1159 | km_state_notify(x, &c); |
833 | 1160 | ||
834 | if (x->replay_maxage && | 1161 | if (x->replay_maxage && |
835 | !mod_timer(&x->rtimer, jiffies + x->replay_maxage)) { | 1162 | !mod_timer(&x->rtimer, jiffies + x->replay_maxage)) |
836 | xfrm_state_hold(x); | ||
837 | x->xflags &= ~XFRM_TIME_DEFER; | 1163 | x->xflags &= ~XFRM_TIME_DEFER; |
838 | } | ||
839 | } | 1164 | } |
840 | EXPORT_SYMBOL(xfrm_replay_notify); | 1165 | EXPORT_SYMBOL(xfrm_replay_notify); |
841 | 1166 | ||
@@ -853,7 +1178,6 @@ static void xfrm_replay_timer_handler(unsigned long data) | |||
853 | } | 1178 | } |
854 | 1179 | ||
855 | spin_unlock(&x->lock); | 1180 | spin_unlock(&x->lock); |
856 | xfrm_state_put(x); | ||
857 | } | 1181 | } |
858 | 1182 | ||
859 | int xfrm_replay_check(struct xfrm_state *x, u32 seq) | 1183 | int xfrm_replay_check(struct xfrm_state *x, u32 seq) |
@@ -997,6 +1321,25 @@ void km_policy_expired(struct xfrm_policy *pol, int dir, int hard, u32 pid) | |||
997 | } | 1321 | } |
998 | EXPORT_SYMBOL(km_policy_expired); | 1322 | EXPORT_SYMBOL(km_policy_expired); |
999 | 1323 | ||
1324 | int km_report(u8 proto, struct xfrm_selector *sel, xfrm_address_t *addr) | ||
1325 | { | ||
1326 | int err = -EINVAL; | ||
1327 | int ret; | ||
1328 | struct xfrm_mgr *km; | ||
1329 | |||
1330 | read_lock(&xfrm_km_lock); | ||
1331 | list_for_each_entry(km, &xfrm_km_list, list) { | ||
1332 | if (km->report) { | ||
1333 | ret = km->report(proto, sel, addr); | ||
1334 | if (!ret) | ||
1335 | err = ret; | ||
1336 | } | ||
1337 | } | ||
1338 | read_unlock(&xfrm_km_lock); | ||
1339 | return err; | ||
1340 | } | ||
1341 | EXPORT_SYMBOL(km_report); | ||
1342 | |||
1000 | int xfrm_user_policy(struct sock *sk, int optname, u8 __user *optval, int optlen) | 1343 | int xfrm_user_policy(struct sock *sk, int optname, u8 __user *optval, int optlen) |
1001 | { | 1344 | { |
1002 | int err; | 1345 | int err; |
@@ -1018,7 +1361,7 @@ int xfrm_user_policy(struct sock *sk, int optname, u8 __user *optval, int optlen | |||
1018 | err = -EINVAL; | 1361 | err = -EINVAL; |
1019 | read_lock(&xfrm_km_lock); | 1362 | read_lock(&xfrm_km_lock); |
1020 | list_for_each_entry(km, &xfrm_km_list, list) { | 1363 | list_for_each_entry(km, &xfrm_km_list, list) { |
1021 | pol = km->compile_policy(sk->sk_family, optname, data, | 1364 | pol = km->compile_policy(sk, optname, data, |
1022 | optlen, &err); | 1365 | optlen, &err); |
1023 | if (err >= 0) | 1366 | if (err >= 0) |
1024 | break; | 1367 | break; |
@@ -1065,11 +1408,8 @@ int xfrm_state_register_afinfo(struct xfrm_state_afinfo *afinfo) | |||
1065 | write_lock_bh(&xfrm_state_afinfo_lock); | 1408 | write_lock_bh(&xfrm_state_afinfo_lock); |
1066 | if (unlikely(xfrm_state_afinfo[afinfo->family] != NULL)) | 1409 | if (unlikely(xfrm_state_afinfo[afinfo->family] != NULL)) |
1067 | err = -ENOBUFS; | 1410 | err = -ENOBUFS; |
1068 | else { | 1411 | else |
1069 | afinfo->state_bydst = xfrm_state_bydst; | ||
1070 | afinfo->state_byspi = xfrm_state_byspi; | ||
1071 | xfrm_state_afinfo[afinfo->family] = afinfo; | 1412 | xfrm_state_afinfo[afinfo->family] = afinfo; |
1072 | } | ||
1073 | write_unlock_bh(&xfrm_state_afinfo_lock); | 1413 | write_unlock_bh(&xfrm_state_afinfo_lock); |
1074 | return err; | 1414 | return err; |
1075 | } | 1415 | } |
@@ -1086,11 +1426,8 @@ int xfrm_state_unregister_afinfo(struct xfrm_state_afinfo *afinfo) | |||
1086 | if (likely(xfrm_state_afinfo[afinfo->family] != NULL)) { | 1426 | if (likely(xfrm_state_afinfo[afinfo->family] != NULL)) { |
1087 | if (unlikely(xfrm_state_afinfo[afinfo->family] != afinfo)) | 1427 | if (unlikely(xfrm_state_afinfo[afinfo->family] != afinfo)) |
1088 | err = -EINVAL; | 1428 | err = -EINVAL; |
1089 | else { | 1429 | else |
1090 | xfrm_state_afinfo[afinfo->family] = NULL; | 1430 | xfrm_state_afinfo[afinfo->family] = NULL; |
1091 | afinfo->state_byspi = NULL; | ||
1092 | afinfo->state_bydst = NULL; | ||
1093 | } | ||
1094 | } | 1431 | } |
1095 | write_unlock_bh(&xfrm_state_afinfo_lock); | 1432 | write_unlock_bh(&xfrm_state_afinfo_lock); |
1096 | return err; | 1433 | return err; |
@@ -1206,12 +1543,17 @@ EXPORT_SYMBOL(xfrm_init_state); | |||
1206 | 1543 | ||
1207 | void __init xfrm_state_init(void) | 1544 | void __init xfrm_state_init(void) |
1208 | { | 1545 | { |
1209 | int i; | 1546 | unsigned int sz; |
1547 | |||
1548 | sz = sizeof(struct hlist_head) * 8; | ||
1549 | |||
1550 | xfrm_state_bydst = xfrm_hash_alloc(sz); | ||
1551 | xfrm_state_bysrc = xfrm_hash_alloc(sz); | ||
1552 | xfrm_state_byspi = xfrm_hash_alloc(sz); | ||
1553 | if (!xfrm_state_bydst || !xfrm_state_bysrc || !xfrm_state_byspi) | ||
1554 | panic("XFRM: Cannot allocate bydst/bysrc/byspi hashes."); | ||
1555 | xfrm_state_hmask = ((sz / sizeof(struct hlist_head)) - 1); | ||
1210 | 1556 | ||
1211 | for (i=0; i<XFRM_DST_HSIZE; i++) { | ||
1212 | INIT_LIST_HEAD(&xfrm_state_bydst[i]); | ||
1213 | INIT_LIST_HEAD(&xfrm_state_byspi[i]); | ||
1214 | } | ||
1215 | INIT_WORK(&xfrm_state_gc_work, xfrm_state_gc_task, NULL); | 1557 | INIT_WORK(&xfrm_state_gc_work, xfrm_state_gc_task, NULL); |
1216 | } | 1558 | } |
1217 | 1559 | ||
diff --git a/net/xfrm/xfrm_user.c b/net/xfrm/xfrm_user.c index fa79ddc4239e..c59a78d2923a 100644 --- a/net/xfrm/xfrm_user.c +++ b/net/xfrm/xfrm_user.c | |||
@@ -28,6 +28,9 @@ | |||
28 | #include <net/xfrm.h> | 28 | #include <net/xfrm.h> |
29 | #include <net/netlink.h> | 29 | #include <net/netlink.h> |
30 | #include <asm/uaccess.h> | 30 | #include <asm/uaccess.h> |
31 | #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) | ||
32 | #include <linux/in6.h> | ||
33 | #endif | ||
31 | 34 | ||
32 | static int verify_one_alg(struct rtattr **xfrma, enum xfrm_attr_type_t type) | 35 | static int verify_one_alg(struct rtattr **xfrma, enum xfrm_attr_type_t type) |
33 | { | 36 | { |
@@ -87,6 +90,22 @@ static int verify_encap_tmpl(struct rtattr **xfrma) | |||
87 | return 0; | 90 | return 0; |
88 | } | 91 | } |
89 | 92 | ||
93 | static int verify_one_addr(struct rtattr **xfrma, enum xfrm_attr_type_t type, | ||
94 | xfrm_address_t **addrp) | ||
95 | { | ||
96 | struct rtattr *rt = xfrma[type - 1]; | ||
97 | |||
98 | if (!rt) | ||
99 | return 0; | ||
100 | |||
101 | if ((rt->rta_len - sizeof(*rt)) < sizeof(**addrp)) | ||
102 | return -EINVAL; | ||
103 | |||
104 | if (addrp) | ||
105 | *addrp = RTA_DATA(rt); | ||
106 | |||
107 | return 0; | ||
108 | } | ||
90 | 109 | ||
91 | static inline int verify_sec_ctx_len(struct rtattr **xfrma) | 110 | static inline int verify_sec_ctx_len(struct rtattr **xfrma) |
92 | { | 111 | { |
@@ -157,6 +176,19 @@ static int verify_newsa_info(struct xfrm_usersa_info *p, | |||
157 | goto out; | 176 | goto out; |
158 | break; | 177 | break; |
159 | 178 | ||
179 | #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) | ||
180 | case IPPROTO_DSTOPTS: | ||
181 | case IPPROTO_ROUTING: | ||
182 | if (xfrma[XFRMA_ALG_COMP-1] || | ||
183 | xfrma[XFRMA_ALG_AUTH-1] || | ||
184 | xfrma[XFRMA_ALG_CRYPT-1] || | ||
185 | xfrma[XFRMA_ENCAP-1] || | ||
186 | xfrma[XFRMA_SEC_CTX-1] || | ||
187 | !xfrma[XFRMA_COADDR-1]) | ||
188 | goto out; | ||
189 | break; | ||
190 | #endif | ||
191 | |||
160 | default: | 192 | default: |
161 | goto out; | 193 | goto out; |
162 | }; | 194 | }; |
@@ -171,11 +203,14 @@ static int verify_newsa_info(struct xfrm_usersa_info *p, | |||
171 | goto out; | 203 | goto out; |
172 | if ((err = verify_sec_ctx_len(xfrma))) | 204 | if ((err = verify_sec_ctx_len(xfrma))) |
173 | goto out; | 205 | goto out; |
206 | if ((err = verify_one_addr(xfrma, XFRMA_COADDR, NULL))) | ||
207 | goto out; | ||
174 | 208 | ||
175 | err = -EINVAL; | 209 | err = -EINVAL; |
176 | switch (p->mode) { | 210 | switch (p->mode) { |
177 | case 0: | 211 | case XFRM_MODE_TRANSPORT: |
178 | case 1: | 212 | case XFRM_MODE_TUNNEL: |
213 | case XFRM_MODE_ROUTEOPTIMIZATION: | ||
179 | break; | 214 | break; |
180 | 215 | ||
181 | default: | 216 | default: |
@@ -260,6 +295,24 @@ static int attach_sec_ctx(struct xfrm_state *x, struct rtattr *u_arg) | |||
260 | return security_xfrm_state_alloc(x, uctx); | 295 | return security_xfrm_state_alloc(x, uctx); |
261 | } | 296 | } |
262 | 297 | ||
298 | static int attach_one_addr(xfrm_address_t **addrpp, struct rtattr *u_arg) | ||
299 | { | ||
300 | struct rtattr *rta = u_arg; | ||
301 | xfrm_address_t *p, *uaddrp; | ||
302 | |||
303 | if (!rta) | ||
304 | return 0; | ||
305 | |||
306 | uaddrp = RTA_DATA(rta); | ||
307 | p = kmalloc(sizeof(*p), GFP_KERNEL); | ||
308 | if (!p) | ||
309 | return -ENOMEM; | ||
310 | |||
311 | memcpy(p, uaddrp, sizeof(*p)); | ||
312 | *addrpp = p; | ||
313 | return 0; | ||
314 | } | ||
315 | |||
263 | static void copy_from_user_state(struct xfrm_state *x, struct xfrm_usersa_info *p) | 316 | static void copy_from_user_state(struct xfrm_state *x, struct xfrm_usersa_info *p) |
264 | { | 317 | { |
265 | memcpy(&x->id, &p->id, sizeof(x->id)); | 318 | memcpy(&x->id, &p->id, sizeof(x->id)); |
@@ -349,7 +402,8 @@ static struct xfrm_state *xfrm_state_construct(struct xfrm_usersa_info *p, | |||
349 | goto error; | 402 | goto error; |
350 | if ((err = attach_encap_tmpl(&x->encap, xfrma[XFRMA_ENCAP-1]))) | 403 | if ((err = attach_encap_tmpl(&x->encap, xfrma[XFRMA_ENCAP-1]))) |
351 | goto error; | 404 | goto error; |
352 | 405 | if ((err = attach_one_addr(&x->coaddr, xfrma[XFRMA_COADDR-1]))) | |
406 | goto error; | ||
353 | err = xfrm_init_state(x); | 407 | err = xfrm_init_state(x); |
354 | if (err) | 408 | if (err) |
355 | goto error; | 409 | goto error; |
@@ -418,16 +472,48 @@ out: | |||
418 | return err; | 472 | return err; |
419 | } | 473 | } |
420 | 474 | ||
475 | static struct xfrm_state *xfrm_user_state_lookup(struct xfrm_usersa_id *p, | ||
476 | struct rtattr **xfrma, | ||
477 | int *errp) | ||
478 | { | ||
479 | struct xfrm_state *x = NULL; | ||
480 | int err; | ||
481 | |||
482 | if (xfrm_id_proto_match(p->proto, IPSEC_PROTO_ANY)) { | ||
483 | err = -ESRCH; | ||
484 | x = xfrm_state_lookup(&p->daddr, p->spi, p->proto, p->family); | ||
485 | } else { | ||
486 | xfrm_address_t *saddr = NULL; | ||
487 | |||
488 | err = verify_one_addr(xfrma, XFRMA_SRCADDR, &saddr); | ||
489 | if (err) | ||
490 | goto out; | ||
491 | |||
492 | if (!saddr) { | ||
493 | err = -EINVAL; | ||
494 | goto out; | ||
495 | } | ||
496 | |||
497 | x = xfrm_state_lookup_byaddr(&p->daddr, saddr, p->proto, | ||
498 | p->family); | ||
499 | } | ||
500 | |||
501 | out: | ||
502 | if (!x && errp) | ||
503 | *errp = err; | ||
504 | return x; | ||
505 | } | ||
506 | |||
421 | static int xfrm_del_sa(struct sk_buff *skb, struct nlmsghdr *nlh, void **xfrma) | 507 | static int xfrm_del_sa(struct sk_buff *skb, struct nlmsghdr *nlh, void **xfrma) |
422 | { | 508 | { |
423 | struct xfrm_state *x; | 509 | struct xfrm_state *x; |
424 | int err; | 510 | int err = -ESRCH; |
425 | struct km_event c; | 511 | struct km_event c; |
426 | struct xfrm_usersa_id *p = NLMSG_DATA(nlh); | 512 | struct xfrm_usersa_id *p = NLMSG_DATA(nlh); |
427 | 513 | ||
428 | x = xfrm_state_lookup(&p->daddr, p->spi, p->proto, p->family); | 514 | x = xfrm_user_state_lookup(p, (struct rtattr **)xfrma, &err); |
429 | if (x == NULL) | 515 | if (x == NULL) |
430 | return -ESRCH; | 516 | return err; |
431 | 517 | ||
432 | if ((err = security_xfrm_state_delete(x)) != 0) | 518 | if ((err = security_xfrm_state_delete(x)) != 0) |
433 | goto out; | 519 | goto out; |
@@ -521,6 +607,13 @@ static int dump_one_state(struct xfrm_state *x, int count, void *ptr) | |||
521 | uctx->ctx_len = x->security->ctx_len; | 607 | uctx->ctx_len = x->security->ctx_len; |
522 | memcpy(uctx + 1, x->security->ctx_str, x->security->ctx_len); | 608 | memcpy(uctx + 1, x->security->ctx_str, x->security->ctx_len); |
523 | } | 609 | } |
610 | |||
611 | if (x->coaddr) | ||
612 | RTA_PUT(skb, XFRMA_COADDR, sizeof(*x->coaddr), x->coaddr); | ||
613 | |||
614 | if (x->lastused) | ||
615 | RTA_PUT(skb, XFRMA_LASTUSED, sizeof(x->lastused), &x->lastused); | ||
616 | |||
524 | nlh->nlmsg_len = skb->tail - b; | 617 | nlh->nlmsg_len = skb->tail - b; |
525 | out: | 618 | out: |
526 | sp->this_idx++; | 619 | sp->this_idx++; |
@@ -542,7 +635,7 @@ static int xfrm_dump_sa(struct sk_buff *skb, struct netlink_callback *cb) | |||
542 | info.nlmsg_flags = NLM_F_MULTI; | 635 | info.nlmsg_flags = NLM_F_MULTI; |
543 | info.this_idx = 0; | 636 | info.this_idx = 0; |
544 | info.start_idx = cb->args[0]; | 637 | info.start_idx = cb->args[0]; |
545 | (void) xfrm_state_walk(IPSEC_PROTO_ANY, dump_one_state, &info); | 638 | (void) xfrm_state_walk(0, dump_one_state, &info); |
546 | cb->args[0] = info.this_idx; | 639 | cb->args[0] = info.this_idx; |
547 | 640 | ||
548 | return skb->len; | 641 | return skb->len; |
@@ -578,10 +671,9 @@ static int xfrm_get_sa(struct sk_buff *skb, struct nlmsghdr *nlh, void **xfrma) | |||
578 | struct xfrm_usersa_id *p = NLMSG_DATA(nlh); | 671 | struct xfrm_usersa_id *p = NLMSG_DATA(nlh); |
579 | struct xfrm_state *x; | 672 | struct xfrm_state *x; |
580 | struct sk_buff *resp_skb; | 673 | struct sk_buff *resp_skb; |
581 | int err; | 674 | int err = -ESRCH; |
582 | 675 | ||
583 | x = xfrm_state_lookup(&p->daddr, p->spi, p->proto, p->family); | 676 | x = xfrm_user_state_lookup(p, (struct rtattr **)xfrma, &err); |
584 | err = -ESRCH; | ||
585 | if (x == NULL) | 677 | if (x == NULL) |
586 | goto out_noput; | 678 | goto out_noput; |
587 | 679 | ||
@@ -694,6 +786,22 @@ static int verify_policy_dir(__u8 dir) | |||
694 | return 0; | 786 | return 0; |
695 | } | 787 | } |
696 | 788 | ||
789 | static int verify_policy_type(__u8 type) | ||
790 | { | ||
791 | switch (type) { | ||
792 | case XFRM_POLICY_TYPE_MAIN: | ||
793 | #ifdef CONFIG_XFRM_SUB_POLICY | ||
794 | case XFRM_POLICY_TYPE_SUB: | ||
795 | #endif | ||
796 | break; | ||
797 | |||
798 | default: | ||
799 | return -EINVAL; | ||
800 | }; | ||
801 | |||
802 | return 0; | ||
803 | } | ||
804 | |||
697 | static int verify_newpolicy_info(struct xfrm_userpolicy_info *p) | 805 | static int verify_newpolicy_info(struct xfrm_userpolicy_info *p) |
698 | { | 806 | { |
699 | switch (p->share) { | 807 | switch (p->share) { |
@@ -787,6 +895,29 @@ static int copy_from_user_tmpl(struct xfrm_policy *pol, struct rtattr **xfrma) | |||
787 | return 0; | 895 | return 0; |
788 | } | 896 | } |
789 | 897 | ||
898 | static int copy_from_user_policy_type(u8 *tp, struct rtattr **xfrma) | ||
899 | { | ||
900 | struct rtattr *rt = xfrma[XFRMA_POLICY_TYPE-1]; | ||
901 | struct xfrm_userpolicy_type *upt; | ||
902 | __u8 type = XFRM_POLICY_TYPE_MAIN; | ||
903 | int err; | ||
904 | |||
905 | if (rt) { | ||
906 | if (rt->rta_len < sizeof(*upt)) | ||
907 | return -EINVAL; | ||
908 | |||
909 | upt = RTA_DATA(rt); | ||
910 | type = upt->type; | ||
911 | } | ||
912 | |||
913 | err = verify_policy_type(type); | ||
914 | if (err) | ||
915 | return err; | ||
916 | |||
917 | *tp = type; | ||
918 | return 0; | ||
919 | } | ||
920 | |||
790 | static void copy_from_user_policy(struct xfrm_policy *xp, struct xfrm_userpolicy_info *p) | 921 | static void copy_from_user_policy(struct xfrm_policy *xp, struct xfrm_userpolicy_info *p) |
791 | { | 922 | { |
792 | xp->priority = p->priority; | 923 | xp->priority = p->priority; |
@@ -825,16 +956,20 @@ static struct xfrm_policy *xfrm_policy_construct(struct xfrm_userpolicy_info *p, | |||
825 | 956 | ||
826 | copy_from_user_policy(xp, p); | 957 | copy_from_user_policy(xp, p); |
827 | 958 | ||
959 | err = copy_from_user_policy_type(&xp->type, xfrma); | ||
960 | if (err) | ||
961 | goto error; | ||
962 | |||
828 | if (!(err = copy_from_user_tmpl(xp, xfrma))) | 963 | if (!(err = copy_from_user_tmpl(xp, xfrma))) |
829 | err = copy_from_user_sec_ctx(xp, xfrma); | 964 | err = copy_from_user_sec_ctx(xp, xfrma); |
830 | 965 | if (err) | |
831 | if (err) { | 966 | goto error; |
832 | *errp = err; | ||
833 | kfree(xp); | ||
834 | xp = NULL; | ||
835 | } | ||
836 | 967 | ||
837 | return xp; | 968 | return xp; |
969 | error: | ||
970 | *errp = err; | ||
971 | kfree(xp); | ||
972 | return NULL; | ||
838 | } | 973 | } |
839 | 974 | ||
840 | static int xfrm_add_policy(struct sk_buff *skb, struct nlmsghdr *nlh, void **xfrma) | 975 | static int xfrm_add_policy(struct sk_buff *skb, struct nlmsghdr *nlh, void **xfrma) |
@@ -911,27 +1046,63 @@ rtattr_failure: | |||
911 | return -1; | 1046 | return -1; |
912 | } | 1047 | } |
913 | 1048 | ||
914 | static int copy_to_user_sec_ctx(struct xfrm_policy *xp, struct sk_buff *skb) | 1049 | static int copy_sec_ctx(struct xfrm_sec_ctx *s, struct sk_buff *skb) |
915 | { | 1050 | { |
916 | if (xp->security) { | 1051 | int ctx_size = sizeof(struct xfrm_sec_ctx) + s->ctx_len; |
917 | int ctx_size = sizeof(struct xfrm_sec_ctx) + | 1052 | struct rtattr *rt = __RTA_PUT(skb, XFRMA_SEC_CTX, ctx_size); |
918 | xp->security->ctx_len; | 1053 | struct xfrm_user_sec_ctx *uctx = RTA_DATA(rt); |
919 | struct rtattr *rt = __RTA_PUT(skb, XFRMA_SEC_CTX, ctx_size); | 1054 | |
920 | struct xfrm_user_sec_ctx *uctx = RTA_DATA(rt); | 1055 | uctx->exttype = XFRMA_SEC_CTX; |
1056 | uctx->len = ctx_size; | ||
1057 | uctx->ctx_doi = s->ctx_doi; | ||
1058 | uctx->ctx_alg = s->ctx_alg; | ||
1059 | uctx->ctx_len = s->ctx_len; | ||
1060 | memcpy(uctx + 1, s->ctx_str, s->ctx_len); | ||
1061 | return 0; | ||
921 | 1062 | ||
922 | uctx->exttype = XFRMA_SEC_CTX; | 1063 | rtattr_failure: |
923 | uctx->len = ctx_size; | 1064 | return -1; |
924 | uctx->ctx_doi = xp->security->ctx_doi; | 1065 | } |
925 | uctx->ctx_alg = xp->security->ctx_alg; | 1066 | |
926 | uctx->ctx_len = xp->security->ctx_len; | 1067 | static inline int copy_to_user_state_sec_ctx(struct xfrm_state *x, struct sk_buff *skb) |
927 | memcpy(uctx + 1, xp->security->ctx_str, xp->security->ctx_len); | 1068 | { |
1069 | if (x->security) { | ||
1070 | return copy_sec_ctx(x->security, skb); | ||
928 | } | 1071 | } |
929 | return 0; | 1072 | return 0; |
1073 | } | ||
930 | 1074 | ||
931 | rtattr_failure: | 1075 | static inline int copy_to_user_sec_ctx(struct xfrm_policy *xp, struct sk_buff *skb) |
1076 | { | ||
1077 | if (xp->security) { | ||
1078 | return copy_sec_ctx(xp->security, skb); | ||
1079 | } | ||
1080 | return 0; | ||
1081 | } | ||
1082 | |||
1083 | #ifdef CONFIG_XFRM_SUB_POLICY | ||
1084 | static int copy_to_user_policy_type(struct xfrm_policy *xp, struct sk_buff *skb) | ||
1085 | { | ||
1086 | struct xfrm_userpolicy_type upt; | ||
1087 | |||
1088 | memset(&upt, 0, sizeof(upt)); | ||
1089 | upt.type = xp->type; | ||
1090 | |||
1091 | RTA_PUT(skb, XFRMA_POLICY_TYPE, sizeof(upt), &upt); | ||
1092 | |||
1093 | return 0; | ||
1094 | |||
1095 | rtattr_failure: | ||
932 | return -1; | 1096 | return -1; |
933 | } | 1097 | } |
934 | 1098 | ||
1099 | #else | ||
1100 | static inline int copy_to_user_policy_type(struct xfrm_policy *xp, struct sk_buff *skb) | ||
1101 | { | ||
1102 | return 0; | ||
1103 | } | ||
1104 | #endif | ||
1105 | |||
935 | static int dump_one_policy(struct xfrm_policy *xp, int dir, int count, void *ptr) | 1106 | static int dump_one_policy(struct xfrm_policy *xp, int dir, int count, void *ptr) |
936 | { | 1107 | { |
937 | struct xfrm_dump_info *sp = ptr; | 1108 | struct xfrm_dump_info *sp = ptr; |
@@ -955,6 +1126,8 @@ static int dump_one_policy(struct xfrm_policy *xp, int dir, int count, void *ptr | |||
955 | goto nlmsg_failure; | 1126 | goto nlmsg_failure; |
956 | if (copy_to_user_sec_ctx(xp, skb)) | 1127 | if (copy_to_user_sec_ctx(xp, skb)) |
957 | goto nlmsg_failure; | 1128 | goto nlmsg_failure; |
1129 | if (copy_to_user_policy_type(xp, skb) < 0) | ||
1130 | goto nlmsg_failure; | ||
958 | 1131 | ||
959 | nlh->nlmsg_len = skb->tail - b; | 1132 | nlh->nlmsg_len = skb->tail - b; |
960 | out: | 1133 | out: |
@@ -976,7 +1149,10 @@ static int xfrm_dump_policy(struct sk_buff *skb, struct netlink_callback *cb) | |||
976 | info.nlmsg_flags = NLM_F_MULTI; | 1149 | info.nlmsg_flags = NLM_F_MULTI; |
977 | info.this_idx = 0; | 1150 | info.this_idx = 0; |
978 | info.start_idx = cb->args[0]; | 1151 | info.start_idx = cb->args[0]; |
979 | (void) xfrm_policy_walk(dump_one_policy, &info); | 1152 | (void) xfrm_policy_walk(XFRM_POLICY_TYPE_MAIN, dump_one_policy, &info); |
1153 | #ifdef CONFIG_XFRM_SUB_POLICY | ||
1154 | (void) xfrm_policy_walk(XFRM_POLICY_TYPE_SUB, dump_one_policy, &info); | ||
1155 | #endif | ||
980 | cb->args[0] = info.this_idx; | 1156 | cb->args[0] = info.this_idx; |
981 | 1157 | ||
982 | return skb->len; | 1158 | return skb->len; |
@@ -1012,6 +1188,7 @@ static int xfrm_get_policy(struct sk_buff *skb, struct nlmsghdr *nlh, void **xfr | |||
1012 | { | 1188 | { |
1013 | struct xfrm_policy *xp; | 1189 | struct xfrm_policy *xp; |
1014 | struct xfrm_userpolicy_id *p; | 1190 | struct xfrm_userpolicy_id *p; |
1191 | __u8 type = XFRM_POLICY_TYPE_MAIN; | ||
1015 | int err; | 1192 | int err; |
1016 | struct km_event c; | 1193 | struct km_event c; |
1017 | int delete; | 1194 | int delete; |
@@ -1019,12 +1196,16 @@ static int xfrm_get_policy(struct sk_buff *skb, struct nlmsghdr *nlh, void **xfr | |||
1019 | p = NLMSG_DATA(nlh); | 1196 | p = NLMSG_DATA(nlh); |
1020 | delete = nlh->nlmsg_type == XFRM_MSG_DELPOLICY; | 1197 | delete = nlh->nlmsg_type == XFRM_MSG_DELPOLICY; |
1021 | 1198 | ||
1199 | err = copy_from_user_policy_type(&type, (struct rtattr **)xfrma); | ||
1200 | if (err) | ||
1201 | return err; | ||
1202 | |||
1022 | err = verify_policy_dir(p->dir); | 1203 | err = verify_policy_dir(p->dir); |
1023 | if (err) | 1204 | if (err) |
1024 | return err; | 1205 | return err; |
1025 | 1206 | ||
1026 | if (p->index) | 1207 | if (p->index) |
1027 | xp = xfrm_policy_byid(p->dir, p->index, delete); | 1208 | xp = xfrm_policy_byid(type, p->dir, p->index, delete); |
1028 | else { | 1209 | else { |
1029 | struct rtattr **rtattrs = (struct rtattr **)xfrma; | 1210 | struct rtattr **rtattrs = (struct rtattr **)xfrma; |
1030 | struct rtattr *rt = rtattrs[XFRMA_SEC_CTX-1]; | 1211 | struct rtattr *rt = rtattrs[XFRMA_SEC_CTX-1]; |
@@ -1041,7 +1222,7 @@ static int xfrm_get_policy(struct sk_buff *skb, struct nlmsghdr *nlh, void **xfr | |||
1041 | if ((err = security_xfrm_policy_alloc(&tmp, uctx))) | 1222 | if ((err = security_xfrm_policy_alloc(&tmp, uctx))) |
1042 | return err; | 1223 | return err; |
1043 | } | 1224 | } |
1044 | xp = xfrm_policy_bysel_ctx(p->dir, &p->sel, tmp.security, delete); | 1225 | xp = xfrm_policy_bysel_ctx(type, p->dir, &p->sel, tmp.security, delete); |
1045 | security_xfrm_policy_free(&tmp); | 1226 | security_xfrm_policy_free(&tmp); |
1046 | } | 1227 | } |
1047 | if (xp == NULL) | 1228 | if (xp == NULL) |
@@ -1224,9 +1405,16 @@ out: | |||
1224 | 1405 | ||
1225 | static int xfrm_flush_policy(struct sk_buff *skb, struct nlmsghdr *nlh, void **xfrma) | 1406 | static int xfrm_flush_policy(struct sk_buff *skb, struct nlmsghdr *nlh, void **xfrma) |
1226 | { | 1407 | { |
1227 | struct km_event c; | 1408 | struct km_event c; |
1409 | __u8 type = XFRM_POLICY_TYPE_MAIN; | ||
1410 | int err; | ||
1411 | |||
1412 | err = copy_from_user_policy_type(&type, (struct rtattr **)xfrma); | ||
1413 | if (err) | ||
1414 | return err; | ||
1228 | 1415 | ||
1229 | xfrm_policy_flush(); | 1416 | xfrm_policy_flush(type); |
1417 | c.data.type = type; | ||
1230 | c.event = nlh->nlmsg_type; | 1418 | c.event = nlh->nlmsg_type; |
1231 | c.seq = nlh->nlmsg_seq; | 1419 | c.seq = nlh->nlmsg_seq; |
1232 | c.pid = nlh->nlmsg_pid; | 1420 | c.pid = nlh->nlmsg_pid; |
@@ -1239,10 +1427,15 @@ static int xfrm_add_pol_expire(struct sk_buff *skb, struct nlmsghdr *nlh, void * | |||
1239 | struct xfrm_policy *xp; | 1427 | struct xfrm_policy *xp; |
1240 | struct xfrm_user_polexpire *up = NLMSG_DATA(nlh); | 1428 | struct xfrm_user_polexpire *up = NLMSG_DATA(nlh); |
1241 | struct xfrm_userpolicy_info *p = &up->pol; | 1429 | struct xfrm_userpolicy_info *p = &up->pol; |
1430 | __u8 type = XFRM_POLICY_TYPE_MAIN; | ||
1242 | int err = -ENOENT; | 1431 | int err = -ENOENT; |
1243 | 1432 | ||
1433 | err = copy_from_user_policy_type(&type, (struct rtattr **)xfrma); | ||
1434 | if (err) | ||
1435 | return err; | ||
1436 | |||
1244 | if (p->index) | 1437 | if (p->index) |
1245 | xp = xfrm_policy_byid(p->dir, p->index, 0); | 1438 | xp = xfrm_policy_byid(type, p->dir, p->index, 0); |
1246 | else { | 1439 | else { |
1247 | struct rtattr **rtattrs = (struct rtattr **)xfrma; | 1440 | struct rtattr **rtattrs = (struct rtattr **)xfrma; |
1248 | struct rtattr *rt = rtattrs[XFRMA_SEC_CTX-1]; | 1441 | struct rtattr *rt = rtattrs[XFRMA_SEC_CTX-1]; |
@@ -1259,7 +1452,7 @@ static int xfrm_add_pol_expire(struct sk_buff *skb, struct nlmsghdr *nlh, void * | |||
1259 | if ((err = security_xfrm_policy_alloc(&tmp, uctx))) | 1452 | if ((err = security_xfrm_policy_alloc(&tmp, uctx))) |
1260 | return err; | 1453 | return err; |
1261 | } | 1454 | } |
1262 | xp = xfrm_policy_bysel_ctx(p->dir, &p->sel, tmp.security, 0); | 1455 | xp = xfrm_policy_bysel_ctx(type, p->dir, &p->sel, tmp.security, 0); |
1263 | security_xfrm_policy_free(&tmp); | 1456 | security_xfrm_policy_free(&tmp); |
1264 | } | 1457 | } |
1265 | 1458 | ||
@@ -1386,6 +1579,7 @@ static const int xfrm_msg_min[XFRM_NR_MSGTYPES] = { | |||
1386 | [XFRM_MSG_FLUSHPOLICY - XFRM_MSG_BASE] = NLMSG_LENGTH(0), | 1579 | [XFRM_MSG_FLUSHPOLICY - XFRM_MSG_BASE] = NLMSG_LENGTH(0), |
1387 | [XFRM_MSG_NEWAE - XFRM_MSG_BASE] = XMSGSIZE(xfrm_aevent_id), | 1580 | [XFRM_MSG_NEWAE - XFRM_MSG_BASE] = XMSGSIZE(xfrm_aevent_id), |
1388 | [XFRM_MSG_GETAE - XFRM_MSG_BASE] = XMSGSIZE(xfrm_aevent_id), | 1581 | [XFRM_MSG_GETAE - XFRM_MSG_BASE] = XMSGSIZE(xfrm_aevent_id), |
1582 | [XFRM_MSG_REPORT - XFRM_MSG_BASE] = XMSGSIZE(xfrm_user_report), | ||
1389 | }; | 1583 | }; |
1390 | 1584 | ||
1391 | #undef XMSGSIZE | 1585 | #undef XMSGSIZE |
@@ -1710,7 +1904,9 @@ static int build_acquire(struct sk_buff *skb, struct xfrm_state *x, | |||
1710 | 1904 | ||
1711 | if (copy_to_user_tmpl(xp, skb) < 0) | 1905 | if (copy_to_user_tmpl(xp, skb) < 0) |
1712 | goto nlmsg_failure; | 1906 | goto nlmsg_failure; |
1713 | if (copy_to_user_sec_ctx(xp, skb)) | 1907 | if (copy_to_user_state_sec_ctx(x, skb)) |
1908 | goto nlmsg_failure; | ||
1909 | if (copy_to_user_policy_type(xp, skb) < 0) | ||
1714 | goto nlmsg_failure; | 1910 | goto nlmsg_failure; |
1715 | 1911 | ||
1716 | nlh->nlmsg_len = skb->tail - b; | 1912 | nlh->nlmsg_len = skb->tail - b; |
@@ -1744,7 +1940,7 @@ static int xfrm_send_acquire(struct xfrm_state *x, struct xfrm_tmpl *xt, | |||
1744 | /* User gives us xfrm_user_policy_info followed by an array of 0 | 1940 | /* User gives us xfrm_user_policy_info followed by an array of 0 |
1745 | * or more templates. | 1941 | * or more templates. |
1746 | */ | 1942 | */ |
1747 | static struct xfrm_policy *xfrm_compile_policy(u16 family, int opt, | 1943 | static struct xfrm_policy *xfrm_compile_policy(struct sock *sk, int opt, |
1748 | u8 *data, int len, int *dir) | 1944 | u8 *data, int len, int *dir) |
1749 | { | 1945 | { |
1750 | struct xfrm_userpolicy_info *p = (struct xfrm_userpolicy_info *)data; | 1946 | struct xfrm_userpolicy_info *p = (struct xfrm_userpolicy_info *)data; |
@@ -1752,7 +1948,7 @@ static struct xfrm_policy *xfrm_compile_policy(u16 family, int opt, | |||
1752 | struct xfrm_policy *xp; | 1948 | struct xfrm_policy *xp; |
1753 | int nr; | 1949 | int nr; |
1754 | 1950 | ||
1755 | switch (family) { | 1951 | switch (sk->sk_family) { |
1756 | case AF_INET: | 1952 | case AF_INET: |
1757 | if (opt != IP_XFRM_POLICY) { | 1953 | if (opt != IP_XFRM_POLICY) { |
1758 | *dir = -EOPNOTSUPP; | 1954 | *dir = -EOPNOTSUPP; |
@@ -1792,8 +1988,18 @@ static struct xfrm_policy *xfrm_compile_policy(u16 family, int opt, | |||
1792 | } | 1988 | } |
1793 | 1989 | ||
1794 | copy_from_user_policy(xp, p); | 1990 | copy_from_user_policy(xp, p); |
1991 | xp->type = XFRM_POLICY_TYPE_MAIN; | ||
1795 | copy_templates(xp, ut, nr); | 1992 | copy_templates(xp, ut, nr); |
1796 | 1993 | ||
1994 | if (!xp->security) { | ||
1995 | int err = security_xfrm_sock_policy_alloc(xp, sk); | ||
1996 | if (err) { | ||
1997 | kfree(xp); | ||
1998 | *dir = err; | ||
1999 | return NULL; | ||
2000 | } | ||
2001 | } | ||
2002 | |||
1797 | *dir = p->dir; | 2003 | *dir = p->dir; |
1798 | 2004 | ||
1799 | return xp; | 2005 | return xp; |
@@ -1816,6 +2022,8 @@ static int build_polexpire(struct sk_buff *skb, struct xfrm_policy *xp, | |||
1816 | goto nlmsg_failure; | 2022 | goto nlmsg_failure; |
1817 | if (copy_to_user_sec_ctx(xp, skb)) | 2023 | if (copy_to_user_sec_ctx(xp, skb)) |
1818 | goto nlmsg_failure; | 2024 | goto nlmsg_failure; |
2025 | if (copy_to_user_policy_type(xp, skb) < 0) | ||
2026 | goto nlmsg_failure; | ||
1819 | upe->hard = !!hard; | 2027 | upe->hard = !!hard; |
1820 | 2028 | ||
1821 | nlh->nlmsg_len = skb->tail - b; | 2029 | nlh->nlmsg_len = skb->tail - b; |
@@ -1887,6 +2095,8 @@ static int xfrm_notify_policy(struct xfrm_policy *xp, int dir, struct km_event * | |||
1887 | copy_to_user_policy(xp, p, dir); | 2095 | copy_to_user_policy(xp, p, dir); |
1888 | if (copy_to_user_tmpl(xp, skb) < 0) | 2096 | if (copy_to_user_tmpl(xp, skb) < 0) |
1889 | goto nlmsg_failure; | 2097 | goto nlmsg_failure; |
2098 | if (copy_to_user_policy_type(xp, skb) < 0) | ||
2099 | goto nlmsg_failure; | ||
1890 | 2100 | ||
1891 | nlh->nlmsg_len = skb->tail - b; | 2101 | nlh->nlmsg_len = skb->tail - b; |
1892 | 2102 | ||
@@ -1904,6 +2114,9 @@ static int xfrm_notify_policy_flush(struct km_event *c) | |||
1904 | struct nlmsghdr *nlh; | 2114 | struct nlmsghdr *nlh; |
1905 | struct sk_buff *skb; | 2115 | struct sk_buff *skb; |
1906 | unsigned char *b; | 2116 | unsigned char *b; |
2117 | #ifdef CONFIG_XFRM_SUB_POLICY | ||
2118 | struct xfrm_userpolicy_type upt; | ||
2119 | #endif | ||
1907 | int len = NLMSG_LENGTH(0); | 2120 | int len = NLMSG_LENGTH(0); |
1908 | 2121 | ||
1909 | skb = alloc_skb(len, GFP_ATOMIC); | 2122 | skb = alloc_skb(len, GFP_ATOMIC); |
@@ -1913,6 +2126,13 @@ static int xfrm_notify_policy_flush(struct km_event *c) | |||
1913 | 2126 | ||
1914 | 2127 | ||
1915 | nlh = NLMSG_PUT(skb, c->pid, c->seq, XFRM_MSG_FLUSHPOLICY, 0); | 2128 | nlh = NLMSG_PUT(skb, c->pid, c->seq, XFRM_MSG_FLUSHPOLICY, 0); |
2129 | nlh->nlmsg_flags = 0; | ||
2130 | |||
2131 | #ifdef CONFIG_XFRM_SUB_POLICY | ||
2132 | memset(&upt, 0, sizeof(upt)); | ||
2133 | upt.type = c->data.type; | ||
2134 | RTA_PUT(skb, XFRMA_POLICY_TYPE, sizeof(upt), &upt); | ||
2135 | #endif | ||
1916 | 2136 | ||
1917 | nlh->nlmsg_len = skb->tail - b; | 2137 | nlh->nlmsg_len = skb->tail - b; |
1918 | 2138 | ||
@@ -1920,6 +2140,9 @@ static int xfrm_notify_policy_flush(struct km_event *c) | |||
1920 | return netlink_broadcast(xfrm_nl, skb, 0, XFRMNLGRP_POLICY, GFP_ATOMIC); | 2140 | return netlink_broadcast(xfrm_nl, skb, 0, XFRMNLGRP_POLICY, GFP_ATOMIC); |
1921 | 2141 | ||
1922 | nlmsg_failure: | 2142 | nlmsg_failure: |
2143 | #ifdef CONFIG_XFRM_SUB_POLICY | ||
2144 | rtattr_failure: | ||
2145 | #endif | ||
1923 | kfree_skb(skb); | 2146 | kfree_skb(skb); |
1924 | return -1; | 2147 | return -1; |
1925 | } | 2148 | } |
@@ -1944,19 +2167,64 @@ static int xfrm_send_policy_notify(struct xfrm_policy *xp, int dir, struct km_ev | |||
1944 | 2167 | ||
1945 | } | 2168 | } |
1946 | 2169 | ||
2170 | static int build_report(struct sk_buff *skb, u8 proto, | ||
2171 | struct xfrm_selector *sel, xfrm_address_t *addr) | ||
2172 | { | ||
2173 | struct xfrm_user_report *ur; | ||
2174 | struct nlmsghdr *nlh; | ||
2175 | unsigned char *b = skb->tail; | ||
2176 | |||
2177 | nlh = NLMSG_PUT(skb, 0, 0, XFRM_MSG_REPORT, sizeof(*ur)); | ||
2178 | ur = NLMSG_DATA(nlh); | ||
2179 | nlh->nlmsg_flags = 0; | ||
2180 | |||
2181 | ur->proto = proto; | ||
2182 | memcpy(&ur->sel, sel, sizeof(ur->sel)); | ||
2183 | |||
2184 | if (addr) | ||
2185 | RTA_PUT(skb, XFRMA_COADDR, sizeof(*addr), addr); | ||
2186 | |||
2187 | nlh->nlmsg_len = skb->tail - b; | ||
2188 | return skb->len; | ||
2189 | |||
2190 | nlmsg_failure: | ||
2191 | rtattr_failure: | ||
2192 | skb_trim(skb, b - skb->data); | ||
2193 | return -1; | ||
2194 | } | ||
2195 | |||
2196 | static int xfrm_send_report(u8 proto, struct xfrm_selector *sel, | ||
2197 | xfrm_address_t *addr) | ||
2198 | { | ||
2199 | struct sk_buff *skb; | ||
2200 | size_t len; | ||
2201 | |||
2202 | len = NLMSG_ALIGN(NLMSG_LENGTH(sizeof(struct xfrm_user_report))); | ||
2203 | skb = alloc_skb(len, GFP_ATOMIC); | ||
2204 | if (skb == NULL) | ||
2205 | return -ENOMEM; | ||
2206 | |||
2207 | if (build_report(skb, proto, sel, addr) < 0) | ||
2208 | BUG(); | ||
2209 | |||
2210 | NETLINK_CB(skb).dst_group = XFRMNLGRP_REPORT; | ||
2211 | return netlink_broadcast(xfrm_nl, skb, 0, XFRMNLGRP_REPORT, GFP_ATOMIC); | ||
2212 | } | ||
2213 | |||
1947 | static struct xfrm_mgr netlink_mgr = { | 2214 | static struct xfrm_mgr netlink_mgr = { |
1948 | .id = "netlink", | 2215 | .id = "netlink", |
1949 | .notify = xfrm_send_state_notify, | 2216 | .notify = xfrm_send_state_notify, |
1950 | .acquire = xfrm_send_acquire, | 2217 | .acquire = xfrm_send_acquire, |
1951 | .compile_policy = xfrm_compile_policy, | 2218 | .compile_policy = xfrm_compile_policy, |
1952 | .notify_policy = xfrm_send_policy_notify, | 2219 | .notify_policy = xfrm_send_policy_notify, |
2220 | .report = xfrm_send_report, | ||
1953 | }; | 2221 | }; |
1954 | 2222 | ||
1955 | static int __init xfrm_user_init(void) | 2223 | static int __init xfrm_user_init(void) |
1956 | { | 2224 | { |
1957 | struct sock *nlsk; | 2225 | struct sock *nlsk; |
1958 | 2226 | ||
1959 | printk(KERN_INFO "Initializing IPsec netlink socket\n"); | 2227 | printk(KERN_INFO "Initializing XFRM netlink socket\n"); |
1960 | 2228 | ||
1961 | nlsk = netlink_kernel_create(NETLINK_XFRM, XFRMNLGRP_MAX, | 2229 | nlsk = netlink_kernel_create(NETLINK_XFRM, XFRMNLGRP_MAX, |
1962 | xfrm_netlink_rcv, THIS_MODULE); | 2230 | xfrm_netlink_rcv, THIS_MODULE); |
diff --git a/security/dummy.c b/security/dummy.c index 58c6d399c844..aeee70565509 100644 --- a/security/dummy.c +++ b/security/dummy.c | |||
@@ -709,10 +709,10 @@ static int dummy_socket_create (int family, int type, | |||
709 | return 0; | 709 | return 0; |
710 | } | 710 | } |
711 | 711 | ||
712 | static void dummy_socket_post_create (struct socket *sock, int family, int type, | 712 | static int dummy_socket_post_create (struct socket *sock, int family, int type, |
713 | int protocol, int kern) | 713 | int protocol, int kern) |
714 | { | 714 | { |
715 | return; | 715 | return 0; |
716 | } | 716 | } |
717 | 717 | ||
718 | static int dummy_socket_bind (struct socket *sock, struct sockaddr *address, | 718 | static int dummy_socket_bind (struct socket *sock, struct sockaddr *address, |
@@ -805,14 +805,38 @@ static inline void dummy_sk_free_security (struct sock *sk) | |||
805 | { | 805 | { |
806 | } | 806 | } |
807 | 807 | ||
808 | static unsigned int dummy_sk_getsid(struct sock *sk, struct flowi *fl, u8 dir) | 808 | static inline void dummy_sk_clone_security (const struct sock *sk, struct sock *newsk) |
809 | { | ||
810 | } | ||
811 | |||
812 | static inline void dummy_sk_getsecid(struct sock *sk, u32 *secid) | ||
813 | { | ||
814 | } | ||
815 | |||
816 | static inline void dummy_sock_graft(struct sock* sk, struct socket *parent) | ||
817 | { | ||
818 | } | ||
819 | |||
820 | static inline int dummy_inet_conn_request(struct sock *sk, | ||
821 | struct sk_buff *skb, struct request_sock *req) | ||
809 | { | 822 | { |
810 | return 0; | 823 | return 0; |
811 | } | 824 | } |
825 | |||
826 | static inline void dummy_inet_csk_clone(struct sock *newsk, | ||
827 | const struct request_sock *req) | ||
828 | { | ||
829 | } | ||
830 | |||
831 | static inline void dummy_req_classify_flow(const struct request_sock *req, | ||
832 | struct flowi *fl) | ||
833 | { | ||
834 | } | ||
812 | #endif /* CONFIG_SECURITY_NETWORK */ | 835 | #endif /* CONFIG_SECURITY_NETWORK */ |
813 | 836 | ||
814 | #ifdef CONFIG_SECURITY_NETWORK_XFRM | 837 | #ifdef CONFIG_SECURITY_NETWORK_XFRM |
815 | static int dummy_xfrm_policy_alloc_security(struct xfrm_policy *xp, struct xfrm_user_sec_ctx *sec_ctx) | 838 | static int dummy_xfrm_policy_alloc_security(struct xfrm_policy *xp, |
839 | struct xfrm_user_sec_ctx *sec_ctx, struct sock *sk) | ||
816 | { | 840 | { |
817 | return 0; | 841 | return 0; |
818 | } | 842 | } |
@@ -831,7 +855,8 @@ static int dummy_xfrm_policy_delete_security(struct xfrm_policy *xp) | |||
831 | return 0; | 855 | return 0; |
832 | } | 856 | } |
833 | 857 | ||
834 | static int dummy_xfrm_state_alloc_security(struct xfrm_state *x, struct xfrm_user_sec_ctx *sec_ctx) | 858 | static int dummy_xfrm_state_alloc_security(struct xfrm_state *x, |
859 | struct xfrm_user_sec_ctx *sec_ctx, struct xfrm_sec_ctx *pol, u32 secid) | ||
835 | { | 860 | { |
836 | return 0; | 861 | return 0; |
837 | } | 862 | } |
@@ -849,6 +874,23 @@ static int dummy_xfrm_policy_lookup(struct xfrm_policy *xp, u32 sk_sid, u8 dir) | |||
849 | { | 874 | { |
850 | return 0; | 875 | return 0; |
851 | } | 876 | } |
877 | |||
878 | static int dummy_xfrm_state_pol_flow_match(struct xfrm_state *x, | ||
879 | struct xfrm_policy *xp, struct flowi *fl) | ||
880 | { | ||
881 | return 1; | ||
882 | } | ||
883 | |||
884 | static int dummy_xfrm_flow_state_match(struct flowi *fl, struct xfrm_state *xfrm) | ||
885 | { | ||
886 | return 1; | ||
887 | } | ||
888 | |||
889 | static int dummy_xfrm_decode_session(struct sk_buff *skb, u32 *fl, int ckall) | ||
890 | { | ||
891 | return 0; | ||
892 | } | ||
893 | |||
852 | #endif /* CONFIG_SECURITY_NETWORK_XFRM */ | 894 | #endif /* CONFIG_SECURITY_NETWORK_XFRM */ |
853 | static int dummy_register_security (const char *name, struct security_operations *ops) | 895 | static int dummy_register_security (const char *name, struct security_operations *ops) |
854 | { | 896 | { |
@@ -1060,7 +1102,12 @@ void security_fixup_ops (struct security_operations *ops) | |||
1060 | set_to_dummy_if_null(ops, socket_getpeersec_dgram); | 1102 | set_to_dummy_if_null(ops, socket_getpeersec_dgram); |
1061 | set_to_dummy_if_null(ops, sk_alloc_security); | 1103 | set_to_dummy_if_null(ops, sk_alloc_security); |
1062 | set_to_dummy_if_null(ops, sk_free_security); | 1104 | set_to_dummy_if_null(ops, sk_free_security); |
1063 | set_to_dummy_if_null(ops, sk_getsid); | 1105 | set_to_dummy_if_null(ops, sk_clone_security); |
1106 | set_to_dummy_if_null(ops, sk_getsecid); | ||
1107 | set_to_dummy_if_null(ops, sock_graft); | ||
1108 | set_to_dummy_if_null(ops, inet_conn_request); | ||
1109 | set_to_dummy_if_null(ops, inet_csk_clone); | ||
1110 | set_to_dummy_if_null(ops, req_classify_flow); | ||
1064 | #endif /* CONFIG_SECURITY_NETWORK */ | 1111 | #endif /* CONFIG_SECURITY_NETWORK */ |
1065 | #ifdef CONFIG_SECURITY_NETWORK_XFRM | 1112 | #ifdef CONFIG_SECURITY_NETWORK_XFRM |
1066 | set_to_dummy_if_null(ops, xfrm_policy_alloc_security); | 1113 | set_to_dummy_if_null(ops, xfrm_policy_alloc_security); |
@@ -1071,6 +1118,9 @@ void security_fixup_ops (struct security_operations *ops) | |||
1071 | set_to_dummy_if_null(ops, xfrm_state_free_security); | 1118 | set_to_dummy_if_null(ops, xfrm_state_free_security); |
1072 | set_to_dummy_if_null(ops, xfrm_state_delete_security); | 1119 | set_to_dummy_if_null(ops, xfrm_state_delete_security); |
1073 | set_to_dummy_if_null(ops, xfrm_policy_lookup); | 1120 | set_to_dummy_if_null(ops, xfrm_policy_lookup); |
1121 | set_to_dummy_if_null(ops, xfrm_state_pol_flow_match); | ||
1122 | set_to_dummy_if_null(ops, xfrm_flow_state_match); | ||
1123 | set_to_dummy_if_null(ops, xfrm_decode_session); | ||
1074 | #endif /* CONFIG_SECURITY_NETWORK_XFRM */ | 1124 | #endif /* CONFIG_SECURITY_NETWORK_XFRM */ |
1075 | #ifdef CONFIG_KEYS | 1125 | #ifdef CONFIG_KEYS |
1076 | set_to_dummy_if_null(ops, key_alloc); | 1126 | set_to_dummy_if_null(ops, key_alloc); |
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index 5d1b8c733199..5a66c4c09f7a 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c | |||
@@ -12,6 +12,8 @@ | |||
12 | * Copyright (C) 2003 Red Hat, Inc., James Morris <jmorris@redhat.com> | 12 | * Copyright (C) 2003 Red Hat, Inc., James Morris <jmorris@redhat.com> |
13 | * Copyright (C) 2004-2005 Trusted Computer Solutions, Inc. | 13 | * Copyright (C) 2004-2005 Trusted Computer Solutions, Inc. |
14 | * <dgoeddel@trustedcs.com> | 14 | * <dgoeddel@trustedcs.com> |
15 | * Copyright (C) 2006 Hewlett-Packard Development Company, L.P. | ||
16 | * Paul Moore, <paul.moore@hp.com> | ||
15 | * | 17 | * |
16 | * This program is free software; you can redistribute it and/or modify | 18 | * This program is free software; you can redistribute it and/or modify |
17 | * it under the terms of the GNU General Public License version 2, | 19 | * it under the terms of the GNU General Public License version 2, |
@@ -74,6 +76,7 @@ | |||
74 | #include "objsec.h" | 76 | #include "objsec.h" |
75 | #include "netif.h" | 77 | #include "netif.h" |
76 | #include "xfrm.h" | 78 | #include "xfrm.h" |
79 | #include "selinux_netlabel.h" | ||
77 | 80 | ||
78 | #define XATTR_SELINUX_SUFFIX "selinux" | 81 | #define XATTR_SELINUX_SUFFIX "selinux" |
79 | #define XATTR_NAME_SELINUX XATTR_SECURITY_PREFIX XATTR_SELINUX_SUFFIX | 82 | #define XATTR_NAME_SELINUX XATTR_SECURITY_PREFIX XATTR_SELINUX_SUFFIX |
@@ -269,17 +272,17 @@ static int sk_alloc_security(struct sock *sk, int family, gfp_t priority) | |||
269 | { | 272 | { |
270 | struct sk_security_struct *ssec; | 273 | struct sk_security_struct *ssec; |
271 | 274 | ||
272 | if (family != PF_UNIX) | ||
273 | return 0; | ||
274 | |||
275 | ssec = kzalloc(sizeof(*ssec), priority); | 275 | ssec = kzalloc(sizeof(*ssec), priority); |
276 | if (!ssec) | 276 | if (!ssec) |
277 | return -ENOMEM; | 277 | return -ENOMEM; |
278 | 278 | ||
279 | ssec->sk = sk; | 279 | ssec->sk = sk; |
280 | ssec->peer_sid = SECINITSID_UNLABELED; | 280 | ssec->peer_sid = SECINITSID_UNLABELED; |
281 | ssec->sid = SECINITSID_UNLABELED; | ||
281 | sk->sk_security = ssec; | 282 | sk->sk_security = ssec; |
282 | 283 | ||
284 | selinux_netlbl_sk_security_init(ssec, family); | ||
285 | |||
283 | return 0; | 286 | return 0; |
284 | } | 287 | } |
285 | 288 | ||
@@ -287,9 +290,6 @@ static void sk_free_security(struct sock *sk) | |||
287 | { | 290 | { |
288 | struct sk_security_struct *ssec = sk->sk_security; | 291 | struct sk_security_struct *ssec = sk->sk_security; |
289 | 292 | ||
290 | if (sk->sk_family != PF_UNIX) | ||
291 | return; | ||
292 | |||
293 | sk->sk_security = NULL; | 293 | sk->sk_security = NULL; |
294 | kfree(ssec); | 294 | kfree(ssec); |
295 | } | 295 | } |
@@ -2400,6 +2400,7 @@ static int selinux_inode_listsecurity(struct inode *inode, char *buffer, size_t | |||
2400 | 2400 | ||
2401 | static int selinux_file_permission(struct file *file, int mask) | 2401 | static int selinux_file_permission(struct file *file, int mask) |
2402 | { | 2402 | { |
2403 | int rc; | ||
2403 | struct inode *inode = file->f_dentry->d_inode; | 2404 | struct inode *inode = file->f_dentry->d_inode; |
2404 | 2405 | ||
2405 | if (!mask) { | 2406 | if (!mask) { |
@@ -2411,8 +2412,12 @@ static int selinux_file_permission(struct file *file, int mask) | |||
2411 | if ((file->f_flags & O_APPEND) && (mask & MAY_WRITE)) | 2412 | if ((file->f_flags & O_APPEND) && (mask & MAY_WRITE)) |
2412 | mask |= MAY_APPEND; | 2413 | mask |= MAY_APPEND; |
2413 | 2414 | ||
2414 | return file_has_perm(current, file, | 2415 | rc = file_has_perm(current, file, |
2415 | file_mask_to_av(inode->i_mode, mask)); | 2416 | file_mask_to_av(inode->i_mode, mask)); |
2417 | if (rc) | ||
2418 | return rc; | ||
2419 | |||
2420 | return selinux_netlbl_inode_permission(inode, mask); | ||
2416 | } | 2421 | } |
2417 | 2422 | ||
2418 | static int selinux_file_alloc_security(struct file *file) | 2423 | static int selinux_file_alloc_security(struct file *file) |
@@ -3063,11 +3068,13 @@ out: | |||
3063 | return err; | 3068 | return err; |
3064 | } | 3069 | } |
3065 | 3070 | ||
3066 | static void selinux_socket_post_create(struct socket *sock, int family, | 3071 | static int selinux_socket_post_create(struct socket *sock, int family, |
3067 | int type, int protocol, int kern) | 3072 | int type, int protocol, int kern) |
3068 | { | 3073 | { |
3074 | int err = 0; | ||
3069 | struct inode_security_struct *isec; | 3075 | struct inode_security_struct *isec; |
3070 | struct task_security_struct *tsec; | 3076 | struct task_security_struct *tsec; |
3077 | struct sk_security_struct *sksec; | ||
3071 | u32 newsid; | 3078 | u32 newsid; |
3072 | 3079 | ||
3073 | isec = SOCK_INODE(sock)->i_security; | 3080 | isec = SOCK_INODE(sock)->i_security; |
@@ -3078,7 +3085,15 @@ static void selinux_socket_post_create(struct socket *sock, int family, | |||
3078 | isec->sid = kern ? SECINITSID_KERNEL : newsid; | 3085 | isec->sid = kern ? SECINITSID_KERNEL : newsid; |
3079 | isec->initialized = 1; | 3086 | isec->initialized = 1; |
3080 | 3087 | ||
3081 | return; | 3088 | if (sock->sk) { |
3089 | sksec = sock->sk->sk_security; | ||
3090 | sksec->sid = isec->sid; | ||
3091 | err = selinux_netlbl_socket_post_create(sock, | ||
3092 | family, | ||
3093 | isec->sid); | ||
3094 | } | ||
3095 | |||
3096 | return err; | ||
3082 | } | 3097 | } |
3083 | 3098 | ||
3084 | /* Range of port numbers used to automatically bind. | 3099 | /* Range of port numbers used to automatically bind. |
@@ -3259,7 +3274,13 @@ static int selinux_socket_accept(struct socket *sock, struct socket *newsock) | |||
3259 | static int selinux_socket_sendmsg(struct socket *sock, struct msghdr *msg, | 3274 | static int selinux_socket_sendmsg(struct socket *sock, struct msghdr *msg, |
3260 | int size) | 3275 | int size) |
3261 | { | 3276 | { |
3262 | return socket_has_perm(current, sock, SOCKET__WRITE); | 3277 | int rc; |
3278 | |||
3279 | rc = socket_has_perm(current, sock, SOCKET__WRITE); | ||
3280 | if (rc) | ||
3281 | return rc; | ||
3282 | |||
3283 | return selinux_netlbl_inode_permission(SOCK_INODE(sock), MAY_WRITE); | ||
3263 | } | 3284 | } |
3264 | 3285 | ||
3265 | static int selinux_socket_recvmsg(struct socket *sock, struct msghdr *msg, | 3286 | static int selinux_socket_recvmsg(struct socket *sock, struct msghdr *msg, |
@@ -3327,8 +3348,9 @@ static int selinux_socket_unix_stream_connect(struct socket *sock, | |||
3327 | /* server child socket */ | 3348 | /* server child socket */ |
3328 | ssec = newsk->sk_security; | 3349 | ssec = newsk->sk_security; |
3329 | ssec->peer_sid = isec->sid; | 3350 | ssec->peer_sid = isec->sid; |
3330 | 3351 | err = security_sid_mls_copy(other_isec->sid, ssec->peer_sid, &ssec->sid); | |
3331 | return 0; | 3352 | |
3353 | return err; | ||
3332 | } | 3354 | } |
3333 | 3355 | ||
3334 | static int selinux_socket_unix_may_send(struct socket *sock, | 3356 | static int selinux_socket_unix_may_send(struct socket *sock, |
@@ -3354,11 +3376,29 @@ static int selinux_socket_unix_may_send(struct socket *sock, | |||
3354 | } | 3376 | } |
3355 | 3377 | ||
3356 | static int selinux_sock_rcv_skb_compat(struct sock *sk, struct sk_buff *skb, | 3378 | static int selinux_sock_rcv_skb_compat(struct sock *sk, struct sk_buff *skb, |
3357 | struct avc_audit_data *ad, u32 sock_sid, u16 sock_class, | 3379 | struct avc_audit_data *ad, u16 family, char *addrp, int len) |
3358 | u16 family, char *addrp, int len) | ||
3359 | { | 3380 | { |
3360 | int err = 0; | 3381 | int err = 0; |
3361 | u32 netif_perm, node_perm, node_sid, if_sid, recv_perm = 0; | 3382 | u32 netif_perm, node_perm, node_sid, if_sid, recv_perm = 0; |
3383 | struct socket *sock; | ||
3384 | u16 sock_class = 0; | ||
3385 | u32 sock_sid = 0; | ||
3386 | |||
3387 | read_lock_bh(&sk->sk_callback_lock); | ||
3388 | sock = sk->sk_socket; | ||
3389 | if (sock) { | ||
3390 | struct inode *inode; | ||
3391 | inode = SOCK_INODE(sock); | ||
3392 | if (inode) { | ||
3393 | struct inode_security_struct *isec; | ||
3394 | isec = inode->i_security; | ||
3395 | sock_sid = isec->sid; | ||
3396 | sock_class = isec->sclass; | ||
3397 | } | ||
3398 | } | ||
3399 | read_unlock_bh(&sk->sk_callback_lock); | ||
3400 | if (!sock_sid) | ||
3401 | goto out; | ||
3362 | 3402 | ||
3363 | if (!skb->dev) | 3403 | if (!skb->dev) |
3364 | goto out; | 3404 | goto out; |
@@ -3418,12 +3458,10 @@ out: | |||
3418 | static int selinux_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb) | 3458 | static int selinux_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb) |
3419 | { | 3459 | { |
3420 | u16 family; | 3460 | u16 family; |
3421 | u16 sock_class = 0; | ||
3422 | char *addrp; | 3461 | char *addrp; |
3423 | int len, err = 0; | 3462 | int len, err = 0; |
3424 | u32 sock_sid = 0; | ||
3425 | struct socket *sock; | ||
3426 | struct avc_audit_data ad; | 3463 | struct avc_audit_data ad; |
3464 | struct sk_security_struct *sksec = sk->sk_security; | ||
3427 | 3465 | ||
3428 | family = sk->sk_family; | 3466 | family = sk->sk_family; |
3429 | if (family != PF_INET && family != PF_INET6) | 3467 | if (family != PF_INET && family != PF_INET6) |
@@ -3433,22 +3471,6 @@ static int selinux_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb) | |||
3433 | if (family == PF_INET6 && skb->protocol == ntohs(ETH_P_IP)) | 3471 | if (family == PF_INET6 && skb->protocol == ntohs(ETH_P_IP)) |
3434 | family = PF_INET; | 3472 | family = PF_INET; |
3435 | 3473 | ||
3436 | read_lock_bh(&sk->sk_callback_lock); | ||
3437 | sock = sk->sk_socket; | ||
3438 | if (sock) { | ||
3439 | struct inode *inode; | ||
3440 | inode = SOCK_INODE(sock); | ||
3441 | if (inode) { | ||
3442 | struct inode_security_struct *isec; | ||
3443 | isec = inode->i_security; | ||
3444 | sock_sid = isec->sid; | ||
3445 | sock_class = isec->sclass; | ||
3446 | } | ||
3447 | } | ||
3448 | read_unlock_bh(&sk->sk_callback_lock); | ||
3449 | if (!sock_sid) | ||
3450 | goto out; | ||
3451 | |||
3452 | AVC_AUDIT_DATA_INIT(&ad, NET); | 3474 | AVC_AUDIT_DATA_INIT(&ad, NET); |
3453 | ad.u.net.netif = skb->dev ? skb->dev->name : "[unknown]"; | 3475 | ad.u.net.netif = skb->dev ? skb->dev->name : "[unknown]"; |
3454 | ad.u.net.family = family; | 3476 | ad.u.net.family = family; |
@@ -3458,16 +3480,19 @@ static int selinux_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb) | |||
3458 | goto out; | 3480 | goto out; |
3459 | 3481 | ||
3460 | if (selinux_compat_net) | 3482 | if (selinux_compat_net) |
3461 | err = selinux_sock_rcv_skb_compat(sk, skb, &ad, sock_sid, | 3483 | err = selinux_sock_rcv_skb_compat(sk, skb, &ad, family, |
3462 | sock_class, family, | ||
3463 | addrp, len); | 3484 | addrp, len); |
3464 | else | 3485 | else |
3465 | err = avc_has_perm(sock_sid, skb->secmark, SECCLASS_PACKET, | 3486 | err = avc_has_perm(sksec->sid, skb->secmark, SECCLASS_PACKET, |
3466 | PACKET__RECV, &ad); | 3487 | PACKET__RECV, &ad); |
3467 | if (err) | 3488 | if (err) |
3468 | goto out; | 3489 | goto out; |
3469 | 3490 | ||
3470 | err = selinux_xfrm_sock_rcv_skb(sock_sid, skb); | 3491 | err = selinux_netlbl_sock_rcv_skb(sksec, skb, &ad); |
3492 | if (err) | ||
3493 | goto out; | ||
3494 | |||
3495 | err = selinux_xfrm_sock_rcv_skb(sksec->sid, skb, &ad); | ||
3471 | out: | 3496 | out: |
3472 | return err; | 3497 | return err; |
3473 | } | 3498 | } |
@@ -3490,8 +3515,9 @@ static int selinux_socket_getpeersec_stream(struct socket *sock, char __user *op | |||
3490 | peer_sid = ssec->peer_sid; | 3515 | peer_sid = ssec->peer_sid; |
3491 | } | 3516 | } |
3492 | else if (isec->sclass == SECCLASS_TCP_SOCKET) { | 3517 | else if (isec->sclass == SECCLASS_TCP_SOCKET) { |
3493 | peer_sid = selinux_socket_getpeer_stream(sock->sk); | 3518 | peer_sid = selinux_netlbl_socket_getpeersec_stream(sock); |
3494 | 3519 | if (peer_sid == SECSID_NULL) | |
3520 | peer_sid = selinux_socket_getpeer_stream(sock->sk); | ||
3495 | if (peer_sid == SECSID_NULL) { | 3521 | if (peer_sid == SECSID_NULL) { |
3496 | err = -ENOPROTOOPT; | 3522 | err = -ENOPROTOOPT; |
3497 | goto out; | 3523 | goto out; |
@@ -3531,8 +3557,11 @@ static int selinux_socket_getpeersec_dgram(struct socket *sock, struct sk_buff * | |||
3531 | 3557 | ||
3532 | if (sock && (sock->sk->sk_family == PF_UNIX)) | 3558 | if (sock && (sock->sk->sk_family == PF_UNIX)) |
3533 | selinux_get_inode_sid(SOCK_INODE(sock), &peer_secid); | 3559 | selinux_get_inode_sid(SOCK_INODE(sock), &peer_secid); |
3534 | else if (skb) | 3560 | else if (skb) { |
3535 | peer_secid = selinux_socket_getpeer_dgram(skb); | 3561 | peer_secid = selinux_netlbl_socket_getpeersec_dgram(skb); |
3562 | if (peer_secid == SECSID_NULL) | ||
3563 | peer_secid = selinux_socket_getpeer_dgram(skb); | ||
3564 | } | ||
3536 | 3565 | ||
3537 | if (peer_secid == SECSID_NULL) | 3566 | if (peer_secid == SECSID_NULL) |
3538 | err = -EINVAL; | 3567 | err = -EINVAL; |
@@ -3551,22 +3580,86 @@ static void selinux_sk_free_security(struct sock *sk) | |||
3551 | sk_free_security(sk); | 3580 | sk_free_security(sk); |
3552 | } | 3581 | } |
3553 | 3582 | ||
3554 | static unsigned int selinux_sk_getsid_security(struct sock *sk, struct flowi *fl, u8 dir) | 3583 | static void selinux_sk_clone_security(const struct sock *sk, struct sock *newsk) |
3555 | { | 3584 | { |
3556 | struct inode_security_struct *isec; | 3585 | struct sk_security_struct *ssec = sk->sk_security; |
3557 | u32 sock_sid = SECINITSID_ANY_SOCKET; | 3586 | struct sk_security_struct *newssec = newsk->sk_security; |
3587 | |||
3588 | newssec->sid = ssec->sid; | ||
3589 | newssec->peer_sid = ssec->peer_sid; | ||
3558 | 3590 | ||
3591 | selinux_netlbl_sk_clone_security(ssec, newssec); | ||
3592 | } | ||
3593 | |||
3594 | static void selinux_sk_getsecid(struct sock *sk, u32 *secid) | ||
3595 | { | ||
3559 | if (!sk) | 3596 | if (!sk) |
3560 | return selinux_no_sk_sid(fl); | 3597 | *secid = SECINITSID_ANY_SOCKET; |
3598 | else { | ||
3599 | struct sk_security_struct *sksec = sk->sk_security; | ||
3600 | |||
3601 | *secid = sksec->sid; | ||
3602 | } | ||
3603 | } | ||
3604 | |||
3605 | static void selinux_sock_graft(struct sock* sk, struct socket *parent) | ||
3606 | { | ||
3607 | struct inode_security_struct *isec = SOCK_INODE(parent)->i_security; | ||
3608 | struct sk_security_struct *sksec = sk->sk_security; | ||
3609 | |||
3610 | isec->sid = sksec->sid; | ||
3611 | |||
3612 | selinux_netlbl_sock_graft(sk, parent); | ||
3613 | } | ||
3614 | |||
3615 | static int selinux_inet_conn_request(struct sock *sk, struct sk_buff *skb, | ||
3616 | struct request_sock *req) | ||
3617 | { | ||
3618 | struct sk_security_struct *sksec = sk->sk_security; | ||
3619 | int err; | ||
3620 | u32 newsid; | ||
3621 | u32 peersid; | ||
3622 | |||
3623 | newsid = selinux_netlbl_inet_conn_request(skb, sksec->sid); | ||
3624 | if (newsid != SECSID_NULL) { | ||
3625 | req->secid = newsid; | ||
3626 | return 0; | ||
3627 | } | ||
3628 | |||
3629 | err = selinux_xfrm_decode_session(skb, &peersid, 0); | ||
3630 | BUG_ON(err); | ||
3631 | |||
3632 | if (peersid == SECSID_NULL) { | ||
3633 | req->secid = sksec->sid; | ||
3634 | return 0; | ||
3635 | } | ||
3636 | |||
3637 | err = security_sid_mls_copy(sksec->sid, peersid, &newsid); | ||
3638 | if (err) | ||
3639 | return err; | ||
3640 | |||
3641 | req->secid = newsid; | ||
3642 | return 0; | ||
3643 | } | ||
3644 | |||
3645 | static void selinux_inet_csk_clone(struct sock *newsk, | ||
3646 | const struct request_sock *req) | ||
3647 | { | ||
3648 | struct sk_security_struct *newsksec = newsk->sk_security; | ||
3561 | 3649 | ||
3562 | read_lock_bh(&sk->sk_callback_lock); | 3650 | newsksec->sid = req->secid; |
3563 | isec = get_sock_isec(sk); | 3651 | /* NOTE: Ideally, we should also get the isec->sid for the |
3652 | new socket in sync, but we don't have the isec available yet. | ||
3653 | So we will wait until sock_graft to do it, by which | ||
3654 | time it will have been created and available. */ | ||
3564 | 3655 | ||
3565 | if (isec) | 3656 | selinux_netlbl_sk_security_init(newsksec, req->rsk_ops->family); |
3566 | sock_sid = isec->sid; | 3657 | } |
3567 | 3658 | ||
3568 | read_unlock_bh(&sk->sk_callback_lock); | 3659 | static void selinux_req_classify_flow(const struct request_sock *req, |
3569 | return sock_sid; | 3660 | struct flowi *fl) |
3661 | { | ||
3662 | fl->secid = req->secid; | ||
3570 | } | 3663 | } |
3571 | 3664 | ||
3572 | static int selinux_nlmsg_perm(struct sock *sk, struct sk_buff *skb) | 3665 | static int selinux_nlmsg_perm(struct sock *sk, struct sk_buff *skb) |
@@ -3608,12 +3701,24 @@ out: | |||
3608 | #ifdef CONFIG_NETFILTER | 3701 | #ifdef CONFIG_NETFILTER |
3609 | 3702 | ||
3610 | static int selinux_ip_postroute_last_compat(struct sock *sk, struct net_device *dev, | 3703 | static int selinux_ip_postroute_last_compat(struct sock *sk, struct net_device *dev, |
3611 | struct inode_security_struct *isec, | ||
3612 | struct avc_audit_data *ad, | 3704 | struct avc_audit_data *ad, |
3613 | u16 family, char *addrp, int len) | 3705 | u16 family, char *addrp, int len) |
3614 | { | 3706 | { |
3615 | int err; | 3707 | int err = 0; |
3616 | u32 netif_perm, node_perm, node_sid, if_sid, send_perm = 0; | 3708 | u32 netif_perm, node_perm, node_sid, if_sid, send_perm = 0; |
3709 | struct socket *sock; | ||
3710 | struct inode *inode; | ||
3711 | struct inode_security_struct *isec; | ||
3712 | |||
3713 | sock = sk->sk_socket; | ||
3714 | if (!sock) | ||
3715 | goto out; | ||
3716 | |||
3717 | inode = SOCK_INODE(sock); | ||
3718 | if (!inode) | ||
3719 | goto out; | ||
3720 | |||
3721 | isec = inode->i_security; | ||
3617 | 3722 | ||
3618 | err = sel_netif_sids(dev, &if_sid, NULL); | 3723 | err = sel_netif_sids(dev, &if_sid, NULL); |
3619 | if (err) | 3724 | if (err) |
@@ -3678,26 +3783,16 @@ static unsigned int selinux_ip_postroute_last(unsigned int hooknum, | |||
3678 | char *addrp; | 3783 | char *addrp; |
3679 | int len, err = 0; | 3784 | int len, err = 0; |
3680 | struct sock *sk; | 3785 | struct sock *sk; |
3681 | struct socket *sock; | ||
3682 | struct inode *inode; | ||
3683 | struct sk_buff *skb = *pskb; | 3786 | struct sk_buff *skb = *pskb; |
3684 | struct inode_security_struct *isec; | ||
3685 | struct avc_audit_data ad; | 3787 | struct avc_audit_data ad; |
3686 | struct net_device *dev = (struct net_device *)out; | 3788 | struct net_device *dev = (struct net_device *)out; |
3789 | struct sk_security_struct *sksec; | ||
3687 | 3790 | ||
3688 | sk = skb->sk; | 3791 | sk = skb->sk; |
3689 | if (!sk) | 3792 | if (!sk) |
3690 | goto out; | 3793 | goto out; |
3691 | 3794 | ||
3692 | sock = sk->sk_socket; | 3795 | sksec = sk->sk_security; |
3693 | if (!sock) | ||
3694 | goto out; | ||
3695 | |||
3696 | inode = SOCK_INODE(sock); | ||
3697 | if (!inode) | ||
3698 | goto out; | ||
3699 | |||
3700 | isec = inode->i_security; | ||
3701 | 3796 | ||
3702 | AVC_AUDIT_DATA_INIT(&ad, NET); | 3797 | AVC_AUDIT_DATA_INIT(&ad, NET); |
3703 | ad.u.net.netif = dev->name; | 3798 | ad.u.net.netif = dev->name; |
@@ -3708,16 +3803,16 @@ static unsigned int selinux_ip_postroute_last(unsigned int hooknum, | |||
3708 | goto out; | 3803 | goto out; |
3709 | 3804 | ||
3710 | if (selinux_compat_net) | 3805 | if (selinux_compat_net) |
3711 | err = selinux_ip_postroute_last_compat(sk, dev, isec, &ad, | 3806 | err = selinux_ip_postroute_last_compat(sk, dev, &ad, |
3712 | family, addrp, len); | 3807 | family, addrp, len); |
3713 | else | 3808 | else |
3714 | err = avc_has_perm(isec->sid, skb->secmark, SECCLASS_PACKET, | 3809 | err = avc_has_perm(sksec->sid, skb->secmark, SECCLASS_PACKET, |
3715 | PACKET__SEND, &ad); | 3810 | PACKET__SEND, &ad); |
3716 | 3811 | ||
3717 | if (err) | 3812 | if (err) |
3718 | goto out; | 3813 | goto out; |
3719 | 3814 | ||
3720 | err = selinux_xfrm_postroute_last(isec->sid, skb); | 3815 | err = selinux_xfrm_postroute_last(sksec->sid, skb, &ad); |
3721 | out: | 3816 | out: |
3722 | return err ? NF_DROP : NF_ACCEPT; | 3817 | return err ? NF_DROP : NF_ACCEPT; |
3723 | } | 3818 | } |
@@ -4618,7 +4713,12 @@ static struct security_operations selinux_ops = { | |||
4618 | .socket_getpeersec_dgram = selinux_socket_getpeersec_dgram, | 4713 | .socket_getpeersec_dgram = selinux_socket_getpeersec_dgram, |
4619 | .sk_alloc_security = selinux_sk_alloc_security, | 4714 | .sk_alloc_security = selinux_sk_alloc_security, |
4620 | .sk_free_security = selinux_sk_free_security, | 4715 | .sk_free_security = selinux_sk_free_security, |
4621 | .sk_getsid = selinux_sk_getsid_security, | 4716 | .sk_clone_security = selinux_sk_clone_security, |
4717 | .sk_getsecid = selinux_sk_getsecid, | ||
4718 | .sock_graft = selinux_sock_graft, | ||
4719 | .inet_conn_request = selinux_inet_conn_request, | ||
4720 | .inet_csk_clone = selinux_inet_csk_clone, | ||
4721 | .req_classify_flow = selinux_req_classify_flow, | ||
4622 | 4722 | ||
4623 | #ifdef CONFIG_SECURITY_NETWORK_XFRM | 4723 | #ifdef CONFIG_SECURITY_NETWORK_XFRM |
4624 | .xfrm_policy_alloc_security = selinux_xfrm_policy_alloc, | 4724 | .xfrm_policy_alloc_security = selinux_xfrm_policy_alloc, |
@@ -4629,6 +4729,9 @@ static struct security_operations selinux_ops = { | |||
4629 | .xfrm_state_free_security = selinux_xfrm_state_free, | 4729 | .xfrm_state_free_security = selinux_xfrm_state_free, |
4630 | .xfrm_state_delete_security = selinux_xfrm_state_delete, | 4730 | .xfrm_state_delete_security = selinux_xfrm_state_delete, |
4631 | .xfrm_policy_lookup = selinux_xfrm_policy_lookup, | 4731 | .xfrm_policy_lookup = selinux_xfrm_policy_lookup, |
4732 | .xfrm_state_pol_flow_match = selinux_xfrm_state_pol_flow_match, | ||
4733 | .xfrm_flow_state_match = selinux_xfrm_flow_state_match, | ||
4734 | .xfrm_decode_session = selinux_xfrm_decode_session, | ||
4632 | #endif | 4735 | #endif |
4633 | 4736 | ||
4634 | #ifdef CONFIG_KEYS | 4737 | #ifdef CONFIG_KEYS |
diff --git a/security/selinux/include/av_perm_to_string.h b/security/selinux/include/av_perm_to_string.h index 7c9b58380833..09fc8a2345eb 100644 --- a/security/selinux/include/av_perm_to_string.h +++ b/security/selinux/include/av_perm_to_string.h | |||
@@ -241,6 +241,7 @@ | |||
241 | S_(SECCLASS_ASSOCIATION, ASSOCIATION__SENDTO, "sendto") | 241 | S_(SECCLASS_ASSOCIATION, ASSOCIATION__SENDTO, "sendto") |
242 | S_(SECCLASS_ASSOCIATION, ASSOCIATION__RECVFROM, "recvfrom") | 242 | S_(SECCLASS_ASSOCIATION, ASSOCIATION__RECVFROM, "recvfrom") |
243 | S_(SECCLASS_ASSOCIATION, ASSOCIATION__SETCONTEXT, "setcontext") | 243 | S_(SECCLASS_ASSOCIATION, ASSOCIATION__SETCONTEXT, "setcontext") |
244 | S_(SECCLASS_ASSOCIATION, ASSOCIATION__POLMATCH, "polmatch") | ||
244 | S_(SECCLASS_PACKET, PACKET__SEND, "send") | 245 | S_(SECCLASS_PACKET, PACKET__SEND, "send") |
245 | S_(SECCLASS_PACKET, PACKET__RECV, "recv") | 246 | S_(SECCLASS_PACKET, PACKET__RECV, "recv") |
246 | S_(SECCLASS_PACKET, PACKET__RELABELTO, "relabelto") | 247 | S_(SECCLASS_PACKET, PACKET__RELABELTO, "relabelto") |
diff --git a/security/selinux/include/av_permissions.h b/security/selinux/include/av_permissions.h index 69fd4b48202c..81f4f526c8b1 100644 --- a/security/selinux/include/av_permissions.h +++ b/security/selinux/include/av_permissions.h | |||
@@ -911,6 +911,7 @@ | |||
911 | #define ASSOCIATION__SENDTO 0x00000001UL | 911 | #define ASSOCIATION__SENDTO 0x00000001UL |
912 | #define ASSOCIATION__RECVFROM 0x00000002UL | 912 | #define ASSOCIATION__RECVFROM 0x00000002UL |
913 | #define ASSOCIATION__SETCONTEXT 0x00000004UL | 913 | #define ASSOCIATION__SETCONTEXT 0x00000004UL |
914 | #define ASSOCIATION__POLMATCH 0x00000008UL | ||
914 | 915 | ||
915 | #define NETLINK_KOBJECT_UEVENT_SOCKET__IOCTL 0x00000001UL | 916 | #define NETLINK_KOBJECT_UEVENT_SOCKET__IOCTL 0x00000001UL |
916 | #define NETLINK_KOBJECT_UEVENT_SOCKET__READ 0x00000002UL | 917 | #define NETLINK_KOBJECT_UEVENT_SOCKET__READ 0x00000002UL |
diff --git a/security/selinux/include/objsec.h b/security/selinux/include/objsec.h index 940178865fc7..0a39bfd1319f 100644 --- a/security/selinux/include/objsec.h +++ b/security/selinux/include/objsec.h | |||
@@ -99,7 +99,16 @@ struct netif_security_struct { | |||
99 | 99 | ||
100 | struct sk_security_struct { | 100 | struct sk_security_struct { |
101 | struct sock *sk; /* back pointer to sk object */ | 101 | struct sock *sk; /* back pointer to sk object */ |
102 | u32 sid; /* SID of this object */ | ||
102 | u32 peer_sid; /* SID of peer */ | 103 | u32 peer_sid; /* SID of peer */ |
104 | #ifdef CONFIG_NETLABEL | ||
105 | u16 sclass; /* sock security class */ | ||
106 | enum { /* NetLabel state */ | ||
107 | NLBL_UNSET = 0, | ||
108 | NLBL_REQUIRE, | ||
109 | NLBL_LABELED, | ||
110 | } nlbl_state; | ||
111 | #endif | ||
103 | }; | 112 | }; |
104 | 113 | ||
105 | struct key_security_struct { | 114 | struct key_security_struct { |
diff --git a/security/selinux/include/security.h b/security/selinux/include/security.h index 063af47bb231..911954a692fa 100644 --- a/security/selinux/include/security.h +++ b/security/selinux/include/security.h | |||
@@ -78,6 +78,8 @@ int security_node_sid(u16 domain, void *addr, u32 addrlen, | |||
78 | int security_validate_transition(u32 oldsid, u32 newsid, u32 tasksid, | 78 | int security_validate_transition(u32 oldsid, u32 newsid, u32 tasksid, |
79 | u16 tclass); | 79 | u16 tclass); |
80 | 80 | ||
81 | int security_sid_mls_copy(u32 sid, u32 mls_sid, u32 *new_sid); | ||
82 | |||
81 | #define SECURITY_FS_USE_XATTR 1 /* use xattr */ | 83 | #define SECURITY_FS_USE_XATTR 1 /* use xattr */ |
82 | #define SECURITY_FS_USE_TRANS 2 /* use transition SIDs, e.g. devpts/tmpfs */ | 84 | #define SECURITY_FS_USE_TRANS 2 /* use transition SIDs, e.g. devpts/tmpfs */ |
83 | #define SECURITY_FS_USE_TASK 3 /* use task SIDs, e.g. pipefs/sockfs */ | 85 | #define SECURITY_FS_USE_TASK 3 /* use task SIDs, e.g. pipefs/sockfs */ |
diff --git a/security/selinux/include/selinux_netlabel.h b/security/selinux/include/selinux_netlabel.h new file mode 100644 index 000000000000..ecab4bddaaf4 --- /dev/null +++ b/security/selinux/include/selinux_netlabel.h | |||
@@ -0,0 +1,119 @@ | |||
1 | /* | ||
2 | * SELinux interface to the NetLabel subsystem | ||
3 | * | ||
4 | * Author : Paul Moore <paul.moore@hp.com> | ||
5 | * | ||
6 | */ | ||
7 | |||
8 | /* | ||
9 | * (c) Copyright Hewlett-Packard Development Company, L.P., 2006 | ||
10 | * | ||
11 | * This program is free software; you can redistribute it and/or modify | ||
12 | * it under the terms of the GNU General Public License as published by | ||
13 | * the Free Software Foundation; either version 2 of the License, or | ||
14 | * (at your option) any later version. | ||
15 | * | ||
16 | * This program is distributed in the hope that it will be useful, | ||
17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See | ||
19 | * the GNU General Public License for more details. | ||
20 | * | ||
21 | * You should have received a copy of the GNU General Public License | ||
22 | * along with this program; if not, write to the Free Software | ||
23 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
24 | * | ||
25 | */ | ||
26 | |||
27 | #ifndef _SELINUX_NETLABEL_H_ | ||
28 | #define _SELINUX_NETLABEL_H_ | ||
29 | |||
30 | #include <linux/types.h> | ||
31 | #include <linux/fs.h> | ||
32 | #include <linux/net.h> | ||
33 | #include <linux/skbuff.h> | ||
34 | #include <net/sock.h> | ||
35 | |||
36 | #include "avc.h" | ||
37 | #include "objsec.h" | ||
38 | |||
39 | #ifdef CONFIG_NETLABEL | ||
40 | void selinux_netlbl_cache_invalidate(void); | ||
41 | int selinux_netlbl_socket_post_create(struct socket *sock, | ||
42 | int sock_family, | ||
43 | u32 sid); | ||
44 | void selinux_netlbl_sock_graft(struct sock *sk, struct socket *sock); | ||
45 | u32 selinux_netlbl_inet_conn_request(struct sk_buff *skb, u32 sock_sid); | ||
46 | int selinux_netlbl_sock_rcv_skb(struct sk_security_struct *sksec, | ||
47 | struct sk_buff *skb, | ||
48 | struct avc_audit_data *ad); | ||
49 | u32 selinux_netlbl_socket_getpeersec_stream(struct socket *sock); | ||
50 | u32 selinux_netlbl_socket_getpeersec_dgram(struct sk_buff *skb); | ||
51 | void selinux_netlbl_sk_security_init(struct sk_security_struct *ssec, | ||
52 | int family); | ||
53 | void selinux_netlbl_sk_clone_security(struct sk_security_struct *ssec, | ||
54 | struct sk_security_struct *newssec); | ||
55 | int selinux_netlbl_inode_permission(struct inode *inode, int mask); | ||
56 | #else | ||
57 | static inline void selinux_netlbl_cache_invalidate(void) | ||
58 | { | ||
59 | return; | ||
60 | } | ||
61 | |||
62 | static inline int selinux_netlbl_socket_post_create(struct socket *sock, | ||
63 | int sock_family, | ||
64 | u32 sid) | ||
65 | { | ||
66 | return 0; | ||
67 | } | ||
68 | |||
69 | static inline void selinux_netlbl_sock_graft(struct sock *sk, | ||
70 | struct socket *sock) | ||
71 | { | ||
72 | return; | ||
73 | } | ||
74 | |||
75 | static inline u32 selinux_netlbl_inet_conn_request(struct sk_buff *skb, | ||
76 | u32 sock_sid) | ||
77 | { | ||
78 | return SECSID_NULL; | ||
79 | } | ||
80 | |||
81 | static inline int selinux_netlbl_sock_rcv_skb(struct sk_security_struct *sksec, | ||
82 | struct sk_buff *skb, | ||
83 | struct avc_audit_data *ad) | ||
84 | { | ||
85 | return 0; | ||
86 | } | ||
87 | |||
88 | static inline u32 selinux_netlbl_socket_getpeersec_stream(struct socket *sock) | ||
89 | { | ||
90 | return SECSID_NULL; | ||
91 | } | ||
92 | |||
93 | static inline u32 selinux_netlbl_socket_getpeersec_dgram(struct sk_buff *skb) | ||
94 | { | ||
95 | return SECSID_NULL; | ||
96 | } | ||
97 | |||
98 | static inline void selinux_netlbl_sk_security_init( | ||
99 | struct sk_security_struct *ssec, | ||
100 | int family) | ||
101 | { | ||
102 | return; | ||
103 | } | ||
104 | |||
105 | static inline void selinux_netlbl_sk_clone_security( | ||
106 | struct sk_security_struct *ssec, | ||
107 | struct sk_security_struct *newssec) | ||
108 | { | ||
109 | return; | ||
110 | } | ||
111 | |||
112 | static inline int selinux_netlbl_inode_permission(struct inode *inode, | ||
113 | int mask) | ||
114 | { | ||
115 | return 0; | ||
116 | } | ||
117 | #endif /* CONFIG_NETLABEL */ | ||
118 | |||
119 | #endif | ||
diff --git a/security/selinux/include/xfrm.h b/security/selinux/include/xfrm.h index c96498a10eb8..81eb59890162 100644 --- a/security/selinux/include/xfrm.h +++ b/security/selinux/include/xfrm.h | |||
@@ -2,18 +2,25 @@ | |||
2 | * SELinux support for the XFRM LSM hooks | 2 | * SELinux support for the XFRM LSM hooks |
3 | * | 3 | * |
4 | * Author : Trent Jaeger, <jaegert@us.ibm.com> | 4 | * Author : Trent Jaeger, <jaegert@us.ibm.com> |
5 | * Updated : Venkat Yekkirala, <vyekkirala@TrustedCS.com> | ||
5 | */ | 6 | */ |
6 | #ifndef _SELINUX_XFRM_H_ | 7 | #ifndef _SELINUX_XFRM_H_ |
7 | #define _SELINUX_XFRM_H_ | 8 | #define _SELINUX_XFRM_H_ |
8 | 9 | ||
9 | int selinux_xfrm_policy_alloc(struct xfrm_policy *xp, struct xfrm_user_sec_ctx *sec_ctx); | 10 | int selinux_xfrm_policy_alloc(struct xfrm_policy *xp, |
11 | struct xfrm_user_sec_ctx *sec_ctx, struct sock *sk); | ||
10 | int selinux_xfrm_policy_clone(struct xfrm_policy *old, struct xfrm_policy *new); | 12 | int selinux_xfrm_policy_clone(struct xfrm_policy *old, struct xfrm_policy *new); |
11 | void selinux_xfrm_policy_free(struct xfrm_policy *xp); | 13 | void selinux_xfrm_policy_free(struct xfrm_policy *xp); |
12 | int selinux_xfrm_policy_delete(struct xfrm_policy *xp); | 14 | int selinux_xfrm_policy_delete(struct xfrm_policy *xp); |
13 | int selinux_xfrm_state_alloc(struct xfrm_state *x, struct xfrm_user_sec_ctx *sec_ctx); | 15 | int selinux_xfrm_state_alloc(struct xfrm_state *x, |
16 | struct xfrm_user_sec_ctx *sec_ctx, struct xfrm_sec_ctx *pol, u32 secid); | ||
14 | void selinux_xfrm_state_free(struct xfrm_state *x); | 17 | void selinux_xfrm_state_free(struct xfrm_state *x); |
15 | int selinux_xfrm_state_delete(struct xfrm_state *x); | 18 | int selinux_xfrm_state_delete(struct xfrm_state *x); |
16 | int selinux_xfrm_policy_lookup(struct xfrm_policy *xp, u32 sk_sid, u8 dir); | 19 | int selinux_xfrm_policy_lookup(struct xfrm_policy *xp, u32 fl_secid, u8 dir); |
20 | int selinux_xfrm_state_pol_flow_match(struct xfrm_state *x, | ||
21 | struct xfrm_policy *xp, struct flowi *fl); | ||
22 | int selinux_xfrm_flow_state_match(struct flowi *fl, struct xfrm_state *xfrm); | ||
23 | |||
17 | 24 | ||
18 | /* | 25 | /* |
19 | * Extract the security blob from the sock (it's actually on the socket) | 26 | * Extract the security blob from the sock (it's actually on the socket) |
@@ -26,30 +33,23 @@ static inline struct inode_security_struct *get_sock_isec(struct sock *sk) | |||
26 | return SOCK_INODE(sk->sk_socket)->i_security; | 33 | return SOCK_INODE(sk->sk_socket)->i_security; |
27 | } | 34 | } |
28 | 35 | ||
29 | |||
30 | static inline u32 selinux_no_sk_sid(struct flowi *fl) | ||
31 | { | ||
32 | /* NOTE: no sock occurs on ICMP reply, forwards, ... */ | ||
33 | /* icmp_reply: authorize as kernel packet */ | ||
34 | if (fl && fl->proto == IPPROTO_ICMP) { | ||
35 | return SECINITSID_KERNEL; | ||
36 | } | ||
37 | |||
38 | return SECINITSID_ANY_SOCKET; | ||
39 | } | ||
40 | |||
41 | #ifdef CONFIG_SECURITY_NETWORK_XFRM | 36 | #ifdef CONFIG_SECURITY_NETWORK_XFRM |
42 | int selinux_xfrm_sock_rcv_skb(u32 sid, struct sk_buff *skb); | 37 | int selinux_xfrm_sock_rcv_skb(u32 sid, struct sk_buff *skb, |
43 | int selinux_xfrm_postroute_last(u32 isec_sid, struct sk_buff *skb); | 38 | struct avc_audit_data *ad); |
39 | int selinux_xfrm_postroute_last(u32 isec_sid, struct sk_buff *skb, | ||
40 | struct avc_audit_data *ad); | ||
44 | u32 selinux_socket_getpeer_stream(struct sock *sk); | 41 | u32 selinux_socket_getpeer_stream(struct sock *sk); |
45 | u32 selinux_socket_getpeer_dgram(struct sk_buff *skb); | 42 | u32 selinux_socket_getpeer_dgram(struct sk_buff *skb); |
43 | int selinux_xfrm_decode_session(struct sk_buff *skb, u32 *sid, int ckall); | ||
46 | #else | 44 | #else |
47 | static inline int selinux_xfrm_sock_rcv_skb(u32 isec_sid, struct sk_buff *skb) | 45 | static inline int selinux_xfrm_sock_rcv_skb(u32 isec_sid, struct sk_buff *skb, |
46 | struct avc_audit_data *ad) | ||
48 | { | 47 | { |
49 | return 0; | 48 | return 0; |
50 | } | 49 | } |
51 | 50 | ||
52 | static inline int selinux_xfrm_postroute_last(u32 isec_sid, struct sk_buff *skb) | 51 | static inline int selinux_xfrm_postroute_last(u32 isec_sid, struct sk_buff *skb, |
52 | struct avc_audit_data *ad) | ||
53 | { | 53 | { |
54 | return 0; | 54 | return 0; |
55 | } | 55 | } |
@@ -63,6 +63,11 @@ static inline int selinux_socket_getpeer_dgram(struct sk_buff *skb) | |||
63 | { | 63 | { |
64 | return SECSID_NULL; | 64 | return SECSID_NULL; |
65 | } | 65 | } |
66 | static inline int selinux_xfrm_decode_session(struct sk_buff *skb, u32 *sid, int ckall) | ||
67 | { | ||
68 | *sid = SECSID_NULL; | ||
69 | return 0; | ||
70 | } | ||
66 | #endif | 71 | #endif |
67 | 72 | ||
68 | #endif /* _SELINUX_XFRM_H_ */ | 73 | #endif /* _SELINUX_XFRM_H_ */ |
diff --git a/security/selinux/ss/ebitmap.c b/security/selinux/ss/ebitmap.c index 47024a6e1844..cfed1d30fa6a 100644 --- a/security/selinux/ss/ebitmap.c +++ b/security/selinux/ss/ebitmap.c | |||
@@ -3,6 +3,14 @@ | |||
3 | * | 3 | * |
4 | * Author : Stephen Smalley, <sds@epoch.ncsc.mil> | 4 | * Author : Stephen Smalley, <sds@epoch.ncsc.mil> |
5 | */ | 5 | */ |
6 | /* | ||
7 | * Updated: Hewlett-Packard <paul.moore@hp.com> | ||
8 | * | ||
9 | * Added ebitmap_export() and ebitmap_import() | ||
10 | * | ||
11 | * (c) Copyright Hewlett-Packard Development Company, L.P., 2006 | ||
12 | */ | ||
13 | |||
6 | #include <linux/kernel.h> | 14 | #include <linux/kernel.h> |
7 | #include <linux/slab.h> | 15 | #include <linux/slab.h> |
8 | #include <linux/errno.h> | 16 | #include <linux/errno.h> |
@@ -59,6 +67,138 @@ int ebitmap_cpy(struct ebitmap *dst, struct ebitmap *src) | |||
59 | return 0; | 67 | return 0; |
60 | } | 68 | } |
61 | 69 | ||
70 | /** | ||
71 | * ebitmap_export - Export an ebitmap to a unsigned char bitmap string | ||
72 | * @src: the ebitmap to export | ||
73 | * @dst: the resulting bitmap string | ||
74 | * @dst_len: length of dst in bytes | ||
75 | * | ||
76 | * Description: | ||
77 | * Allocate a buffer at least src->highbit bits long and export the extensible | ||
78 | * bitmap into the buffer. The bitmap string will be in little endian format, | ||
79 | * i.e. LSB first. The value returned in dst_len may not the true size of the | ||
80 | * buffer as the length of the buffer is rounded up to a multiple of MAPTYPE. | ||
81 | * The caller must free the buffer when finished. Returns zero on success, | ||
82 | * negative values on failure. | ||
83 | * | ||
84 | */ | ||
85 | int ebitmap_export(const struct ebitmap *src, | ||
86 | unsigned char **dst, | ||
87 | size_t *dst_len) | ||
88 | { | ||
89 | size_t bitmap_len; | ||
90 | unsigned char *bitmap; | ||
91 | struct ebitmap_node *iter_node; | ||
92 | MAPTYPE node_val; | ||
93 | size_t bitmap_byte; | ||
94 | unsigned char bitmask; | ||
95 | |||
96 | bitmap_len = src->highbit / 8; | ||
97 | if (src->highbit % 7) | ||
98 | bitmap_len += 1; | ||
99 | if (bitmap_len == 0) | ||
100 | return -EINVAL; | ||
101 | |||
102 | bitmap = kzalloc((bitmap_len & ~(sizeof(MAPTYPE) - 1)) + | ||
103 | sizeof(MAPTYPE), | ||
104 | GFP_ATOMIC); | ||
105 | if (bitmap == NULL) | ||
106 | return -ENOMEM; | ||
107 | |||
108 | iter_node = src->node; | ||
109 | do { | ||
110 | bitmap_byte = iter_node->startbit / 8; | ||
111 | bitmask = 0x80; | ||
112 | node_val = iter_node->map; | ||
113 | do { | ||
114 | if (bitmask == 0) { | ||
115 | bitmap_byte++; | ||
116 | bitmask = 0x80; | ||
117 | } | ||
118 | if (node_val & (MAPTYPE)0x01) | ||
119 | bitmap[bitmap_byte] |= bitmask; | ||
120 | node_val >>= 1; | ||
121 | bitmask >>= 1; | ||
122 | } while (node_val > 0); | ||
123 | iter_node = iter_node->next; | ||
124 | } while (iter_node); | ||
125 | |||
126 | *dst = bitmap; | ||
127 | *dst_len = bitmap_len; | ||
128 | return 0; | ||
129 | } | ||
130 | |||
131 | /** | ||
132 | * ebitmap_import - Import an unsigned char bitmap string into an ebitmap | ||
133 | * @src: the bitmap string | ||
134 | * @src_len: the bitmap length in bytes | ||
135 | * @dst: the empty ebitmap | ||
136 | * | ||
137 | * Description: | ||
138 | * This function takes a little endian bitmap string in src and imports it into | ||
139 | * the ebitmap pointed to by dst. Returns zero on success, negative values on | ||
140 | * failure. | ||
141 | * | ||
142 | */ | ||
143 | int ebitmap_import(const unsigned char *src, | ||
144 | size_t src_len, | ||
145 | struct ebitmap *dst) | ||
146 | { | ||
147 | size_t src_off = 0; | ||
148 | size_t node_limit; | ||
149 | struct ebitmap_node *node_new; | ||
150 | struct ebitmap_node *node_last = NULL; | ||
151 | u32 i_byte; | ||
152 | u32 i_bit; | ||
153 | unsigned char src_byte; | ||
154 | |||
155 | while (src_off < src_len) { | ||
156 | if (src_len - src_off >= sizeof(MAPTYPE)) { | ||
157 | if (*(MAPTYPE *)&src[src_off] == 0) { | ||
158 | src_off += sizeof(MAPTYPE); | ||
159 | continue; | ||
160 | } | ||
161 | node_limit = sizeof(MAPTYPE); | ||
162 | } else { | ||
163 | for (src_byte = 0, i_byte = src_off; | ||
164 | i_byte < src_len && src_byte == 0; | ||
165 | i_byte++) | ||
166 | src_byte |= src[i_byte]; | ||
167 | if (src_byte == 0) | ||
168 | break; | ||
169 | node_limit = src_len - src_off; | ||
170 | } | ||
171 | |||
172 | node_new = kzalloc(sizeof(*node_new), GFP_ATOMIC); | ||
173 | if (unlikely(node_new == NULL)) { | ||
174 | ebitmap_destroy(dst); | ||
175 | return -ENOMEM; | ||
176 | } | ||
177 | node_new->startbit = src_off * 8; | ||
178 | for (i_byte = 0; i_byte < node_limit; i_byte++) { | ||
179 | src_byte = src[src_off++]; | ||
180 | for (i_bit = i_byte * 8; src_byte != 0; i_bit++) { | ||
181 | if (src_byte & 0x80) | ||
182 | node_new->map |= MAPBIT << i_bit; | ||
183 | src_byte <<= 1; | ||
184 | } | ||
185 | } | ||
186 | |||
187 | if (node_last != NULL) | ||
188 | node_last->next = node_new; | ||
189 | else | ||
190 | dst->node = node_new; | ||
191 | node_last = node_new; | ||
192 | } | ||
193 | |||
194 | if (likely(node_last != NULL)) | ||
195 | dst->highbit = node_last->startbit + MAPSIZE; | ||
196 | else | ||
197 | ebitmap_init(dst); | ||
198 | |||
199 | return 0; | ||
200 | } | ||
201 | |||
62 | int ebitmap_contains(struct ebitmap *e1, struct ebitmap *e2) | 202 | int ebitmap_contains(struct ebitmap *e1, struct ebitmap *e2) |
63 | { | 203 | { |
64 | struct ebitmap_node *n1, *n2; | 204 | struct ebitmap_node *n1, *n2; |
diff --git a/security/selinux/ss/ebitmap.h b/security/selinux/ss/ebitmap.h index 8bf41055a6cb..da2d4651b10d 100644 --- a/security/selinux/ss/ebitmap.h +++ b/security/selinux/ss/ebitmap.h | |||
@@ -69,6 +69,12 @@ static inline int ebitmap_node_get_bit(struct ebitmap_node * n, | |||
69 | 69 | ||
70 | int ebitmap_cmp(struct ebitmap *e1, struct ebitmap *e2); | 70 | int ebitmap_cmp(struct ebitmap *e1, struct ebitmap *e2); |
71 | int ebitmap_cpy(struct ebitmap *dst, struct ebitmap *src); | 71 | int ebitmap_cpy(struct ebitmap *dst, struct ebitmap *src); |
72 | int ebitmap_export(const struct ebitmap *src, | ||
73 | unsigned char **dst, | ||
74 | size_t *dst_len); | ||
75 | int ebitmap_import(const unsigned char *src, | ||
76 | size_t src_len, | ||
77 | struct ebitmap *dst); | ||
72 | int ebitmap_contains(struct ebitmap *e1, struct ebitmap *e2); | 78 | int ebitmap_contains(struct ebitmap *e1, struct ebitmap *e2); |
73 | int ebitmap_get_bit(struct ebitmap *e, unsigned long bit); | 79 | int ebitmap_get_bit(struct ebitmap *e, unsigned long bit); |
74 | int ebitmap_set_bit(struct ebitmap *e, unsigned long bit, int value); | 80 | int ebitmap_set_bit(struct ebitmap *e, unsigned long bit, int value); |
diff --git a/security/selinux/ss/mls.c b/security/selinux/ss/mls.c index 7bc5b6440f70..119bd6078ba1 100644 --- a/security/selinux/ss/mls.c +++ b/security/selinux/ss/mls.c | |||
@@ -10,6 +10,13 @@ | |||
10 | * | 10 | * |
11 | * Copyright (C) 2004-2006 Trusted Computer Solutions, Inc. | 11 | * Copyright (C) 2004-2006 Trusted Computer Solutions, Inc. |
12 | */ | 12 | */ |
13 | /* | ||
14 | * Updated: Hewlett-Packard <paul.moore@hp.com> | ||
15 | * | ||
16 | * Added support to import/export the MLS label | ||
17 | * | ||
18 | * (c) Copyright Hewlett-Packard Development Company, L.P., 2006 | ||
19 | */ | ||
13 | 20 | ||
14 | #include <linux/kernel.h> | 21 | #include <linux/kernel.h> |
15 | #include <linux/slab.h> | 22 | #include <linux/slab.h> |
@@ -212,26 +219,6 @@ int mls_context_isvalid(struct policydb *p, struct context *c) | |||
212 | } | 219 | } |
213 | 220 | ||
214 | /* | 221 | /* |
215 | * Copies the MLS range from `src' into `dst'. | ||
216 | */ | ||
217 | static inline int mls_copy_context(struct context *dst, | ||
218 | struct context *src) | ||
219 | { | ||
220 | int l, rc = 0; | ||
221 | |||
222 | /* Copy the MLS range from the source context */ | ||
223 | for (l = 0; l < 2; l++) { | ||
224 | dst->range.level[l].sens = src->range.level[l].sens; | ||
225 | rc = ebitmap_cpy(&dst->range.level[l].cat, | ||
226 | &src->range.level[l].cat); | ||
227 | if (rc) | ||
228 | break; | ||
229 | } | ||
230 | |||
231 | return rc; | ||
232 | } | ||
233 | |||
234 | /* | ||
235 | * Set the MLS fields in the security context structure | 222 | * Set the MLS fields in the security context structure |
236 | * `context' based on the string representation in | 223 | * `context' based on the string representation in |
237 | * the string `*scontext'. Update `*scontext' to | 224 | * the string `*scontext'. Update `*scontext' to |
@@ -585,3 +572,152 @@ int mls_compute_sid(struct context *scontext, | |||
585 | return -EINVAL; | 572 | return -EINVAL; |
586 | } | 573 | } |
587 | 574 | ||
575 | /** | ||
576 | * mls_export_lvl - Export the MLS sensitivity levels | ||
577 | * @context: the security context | ||
578 | * @low: the low sensitivity level | ||
579 | * @high: the high sensitivity level | ||
580 | * | ||
581 | * Description: | ||
582 | * Given the security context copy the low MLS sensitivity level into lvl_low | ||
583 | * and the high sensitivity level in lvl_high. The MLS levels are only | ||
584 | * exported if the pointers are not NULL, if they are NULL then that level is | ||
585 | * not exported. | ||
586 | * | ||
587 | */ | ||
588 | void mls_export_lvl(const struct context *context, u32 *low, u32 *high) | ||
589 | { | ||
590 | if (!selinux_mls_enabled) | ||
591 | return; | ||
592 | |||
593 | if (low != NULL) | ||
594 | *low = context->range.level[0].sens - 1; | ||
595 | if (high != NULL) | ||
596 | *high = context->range.level[1].sens - 1; | ||
597 | } | ||
598 | |||
599 | /** | ||
600 | * mls_import_lvl - Import the MLS sensitivity levels | ||
601 | * @context: the security context | ||
602 | * @low: the low sensitivity level | ||
603 | * @high: the high sensitivity level | ||
604 | * | ||
605 | * Description: | ||
606 | * Given the security context and the two sensitivty levels, set the MLS levels | ||
607 | * in the context according the two given as parameters. Returns zero on | ||
608 | * success, negative values on failure. | ||
609 | * | ||
610 | */ | ||
611 | void mls_import_lvl(struct context *context, u32 low, u32 high) | ||
612 | { | ||
613 | if (!selinux_mls_enabled) | ||
614 | return; | ||
615 | |||
616 | context->range.level[0].sens = low + 1; | ||
617 | context->range.level[1].sens = high + 1; | ||
618 | } | ||
619 | |||
620 | /** | ||
621 | * mls_export_cat - Export the MLS categories | ||
622 | * @context: the security context | ||
623 | * @low: the low category | ||
624 | * @low_len: length of the cat_low bitmap in bytes | ||
625 | * @high: the high category | ||
626 | * @high_len: length of the cat_high bitmap in bytes | ||
627 | * | ||
628 | * Description: | ||
629 | * Given the security context export the low MLS category bitmap into cat_low | ||
630 | * and the high category bitmap into cat_high. The MLS categories are only | ||
631 | * exported if the pointers are not NULL, if they are NULL then that level is | ||
632 | * not exported. The caller is responsibile for freeing the memory when | ||
633 | * finished. Returns zero on success, negative values on failure. | ||
634 | * | ||
635 | */ | ||
636 | int mls_export_cat(const struct context *context, | ||
637 | unsigned char **low, | ||
638 | size_t *low_len, | ||
639 | unsigned char **high, | ||
640 | size_t *high_len) | ||
641 | { | ||
642 | int rc = -EPERM; | ||
643 | |||
644 | if (!selinux_mls_enabled) | ||
645 | return 0; | ||
646 | |||
647 | if (low != NULL) { | ||
648 | rc = ebitmap_export(&context->range.level[0].cat, | ||
649 | low, | ||
650 | low_len); | ||
651 | if (rc != 0) | ||
652 | goto export_cat_failure; | ||
653 | } | ||
654 | if (high != NULL) { | ||
655 | rc = ebitmap_export(&context->range.level[1].cat, | ||
656 | high, | ||
657 | high_len); | ||
658 | if (rc != 0) | ||
659 | goto export_cat_failure; | ||
660 | } | ||
661 | |||
662 | return 0; | ||
663 | |||
664 | export_cat_failure: | ||
665 | if (low != NULL) | ||
666 | kfree(*low); | ||
667 | if (high != NULL) | ||
668 | kfree(*high); | ||
669 | return rc; | ||
670 | } | ||
671 | |||
672 | /** | ||
673 | * mls_import_cat - Import the MLS categories | ||
674 | * @context: the security context | ||
675 | * @low: the low category | ||
676 | * @low_len: length of the cat_low bitmap in bytes | ||
677 | * @high: the high category | ||
678 | * @high_len: length of the cat_high bitmap in bytes | ||
679 | * | ||
680 | * Description: | ||
681 | * Given the security context and the two category bitmap strings import the | ||
682 | * categories into the security context. The MLS categories are only imported | ||
683 | * if the pointers are not NULL, if they are NULL they are skipped. Returns | ||
684 | * zero on success, negative values on failure. | ||
685 | * | ||
686 | */ | ||
687 | int mls_import_cat(struct context *context, | ||
688 | const unsigned char *low, | ||
689 | size_t low_len, | ||
690 | const unsigned char *high, | ||
691 | size_t high_len) | ||
692 | { | ||
693 | int rc = -EPERM; | ||
694 | |||
695 | if (!selinux_mls_enabled) | ||
696 | return 0; | ||
697 | |||
698 | if (low != NULL) { | ||
699 | rc = ebitmap_import(low, | ||
700 | low_len, | ||
701 | &context->range.level[0].cat); | ||
702 | if (rc != 0) | ||
703 | goto import_cat_failure; | ||
704 | } | ||
705 | if (high != NULL) { | ||
706 | if (high == low) | ||
707 | rc = ebitmap_cpy(&context->range.level[1].cat, | ||
708 | &context->range.level[0].cat); | ||
709 | else | ||
710 | rc = ebitmap_import(high, | ||
711 | high_len, | ||
712 | &context->range.level[1].cat); | ||
713 | if (rc != 0) | ||
714 | goto import_cat_failure; | ||
715 | } | ||
716 | |||
717 | return 0; | ||
718 | |||
719 | import_cat_failure: | ||
720 | ebitmap_destroy(&context->range.level[0].cat); | ||
721 | ebitmap_destroy(&context->range.level[1].cat); | ||
722 | return rc; | ||
723 | } | ||
diff --git a/security/selinux/ss/mls.h b/security/selinux/ss/mls.h index fbb42f07dd7c..df6032c6d492 100644 --- a/security/selinux/ss/mls.h +++ b/security/selinux/ss/mls.h | |||
@@ -10,6 +10,13 @@ | |||
10 | * | 10 | * |
11 | * Copyright (C) 2004-2006 Trusted Computer Solutions, Inc. | 11 | * Copyright (C) 2004-2006 Trusted Computer Solutions, Inc. |
12 | */ | 12 | */ |
13 | /* | ||
14 | * Updated: Hewlett-Packard <paul.moore@hp.com> | ||
15 | * | ||
16 | * Added support to import/export the MLS label | ||
17 | * | ||
18 | * (c) Copyright Hewlett-Packard Development Company, L.P., 2006 | ||
19 | */ | ||
13 | 20 | ||
14 | #ifndef _SS_MLS_H_ | 21 | #ifndef _SS_MLS_H_ |
15 | #define _SS_MLS_H_ | 22 | #define _SS_MLS_H_ |
@@ -17,6 +24,26 @@ | |||
17 | #include "context.h" | 24 | #include "context.h" |
18 | #include "policydb.h" | 25 | #include "policydb.h" |
19 | 26 | ||
27 | /* | ||
28 | * Copies the MLS range from `src' into `dst'. | ||
29 | */ | ||
30 | static inline int mls_copy_context(struct context *dst, | ||
31 | struct context *src) | ||
32 | { | ||
33 | int l, rc = 0; | ||
34 | |||
35 | /* Copy the MLS range from the source context */ | ||
36 | for (l = 0; l < 2; l++) { | ||
37 | dst->range.level[l].sens = src->range.level[l].sens; | ||
38 | rc = ebitmap_cpy(&dst->range.level[l].cat, | ||
39 | &src->range.level[l].cat); | ||
40 | if (rc) | ||
41 | break; | ||
42 | } | ||
43 | |||
44 | return rc; | ||
45 | } | ||
46 | |||
20 | int mls_compute_context_len(struct context *context); | 47 | int mls_compute_context_len(struct context *context); |
21 | void mls_sid_to_context(struct context *context, char **scontext); | 48 | void mls_sid_to_context(struct context *context, char **scontext); |
22 | int mls_context_isvalid(struct policydb *p, struct context *c); | 49 | int mls_context_isvalid(struct policydb *p, struct context *c); |
@@ -42,5 +69,19 @@ int mls_compute_sid(struct context *scontext, | |||
42 | int mls_setup_user_range(struct context *fromcon, struct user_datum *user, | 69 | int mls_setup_user_range(struct context *fromcon, struct user_datum *user, |
43 | struct context *usercon); | 70 | struct context *usercon); |
44 | 71 | ||
72 | void mls_export_lvl(const struct context *context, u32 *low, u32 *high); | ||
73 | void mls_import_lvl(struct context *context, u32 low, u32 high); | ||
74 | |||
75 | int mls_export_cat(const struct context *context, | ||
76 | unsigned char **low, | ||
77 | size_t *low_len, | ||
78 | unsigned char **high, | ||
79 | size_t *high_len); | ||
80 | int mls_import_cat(struct context *context, | ||
81 | const unsigned char *low, | ||
82 | size_t low_len, | ||
83 | const unsigned char *high, | ||
84 | size_t high_len); | ||
85 | |||
45 | #endif /* _SS_MLS_H */ | 86 | #endif /* _SS_MLS_H */ |
46 | 87 | ||
diff --git a/security/selinux/ss/services.c b/security/selinux/ss/services.c index 85e429884393..7eb69a602d8f 100644 --- a/security/selinux/ss/services.c +++ b/security/selinux/ss/services.c | |||
@@ -13,6 +13,11 @@ | |||
13 | * | 13 | * |
14 | * Added conditional policy language extensions | 14 | * Added conditional policy language extensions |
15 | * | 15 | * |
16 | * Updated: Hewlett-Packard <paul.moore@hp.com> | ||
17 | * | ||
18 | * Added support for NetLabel | ||
19 | * | ||
20 | * Copyright (C) 2006 Hewlett-Packard Development Company, L.P. | ||
16 | * Copyright (C) 2004-2006 Trusted Computer Solutions, Inc. | 21 | * Copyright (C) 2004-2006 Trusted Computer Solutions, Inc. |
17 | * Copyright (C) 2003 - 2004 Tresys Technology, LLC | 22 | * Copyright (C) 2003 - 2004 Tresys Technology, LLC |
18 | * Copyright (C) 2003 Red Hat, Inc., James Morris <jmorris@redhat.com> | 23 | * Copyright (C) 2003 Red Hat, Inc., James Morris <jmorris@redhat.com> |
@@ -29,6 +34,8 @@ | |||
29 | #include <linux/sched.h> | 34 | #include <linux/sched.h> |
30 | #include <linux/audit.h> | 35 | #include <linux/audit.h> |
31 | #include <linux/mutex.h> | 36 | #include <linux/mutex.h> |
37 | #include <net/sock.h> | ||
38 | #include <net/netlabel.h> | ||
32 | 39 | ||
33 | #include "flask.h" | 40 | #include "flask.h" |
34 | #include "avc.h" | 41 | #include "avc.h" |
@@ -40,6 +47,8 @@ | |||
40 | #include "services.h" | 47 | #include "services.h" |
41 | #include "conditional.h" | 48 | #include "conditional.h" |
42 | #include "mls.h" | 49 | #include "mls.h" |
50 | #include "objsec.h" | ||
51 | #include "selinux_netlabel.h" | ||
43 | 52 | ||
44 | extern void selnl_notify_policyload(u32 seqno); | 53 | extern void selnl_notify_policyload(u32 seqno); |
45 | unsigned int policydb_loaded_version; | 54 | unsigned int policydb_loaded_version; |
@@ -1241,6 +1250,7 @@ int security_load_policy(void *data, size_t len) | |||
1241 | selinux_complete_init(); | 1250 | selinux_complete_init(); |
1242 | avc_ss_reset(seqno); | 1251 | avc_ss_reset(seqno); |
1243 | selnl_notify_policyload(seqno); | 1252 | selnl_notify_policyload(seqno); |
1253 | selinux_netlbl_cache_invalidate(); | ||
1244 | return 0; | 1254 | return 0; |
1245 | } | 1255 | } |
1246 | 1256 | ||
@@ -1295,6 +1305,7 @@ int security_load_policy(void *data, size_t len) | |||
1295 | 1305 | ||
1296 | avc_ss_reset(seqno); | 1306 | avc_ss_reset(seqno); |
1297 | selnl_notify_policyload(seqno); | 1307 | selnl_notify_policyload(seqno); |
1308 | selinux_netlbl_cache_invalidate(); | ||
1298 | 1309 | ||
1299 | return 0; | 1310 | return 0; |
1300 | 1311 | ||
@@ -1817,6 +1828,75 @@ out: | |||
1817 | return rc; | 1828 | return rc; |
1818 | } | 1829 | } |
1819 | 1830 | ||
1831 | /* | ||
1832 | * security_sid_mls_copy() - computes a new sid based on the given | ||
1833 | * sid and the mls portion of mls_sid. | ||
1834 | */ | ||
1835 | int security_sid_mls_copy(u32 sid, u32 mls_sid, u32 *new_sid) | ||
1836 | { | ||
1837 | struct context *context1; | ||
1838 | struct context *context2; | ||
1839 | struct context newcon; | ||
1840 | char *s; | ||
1841 | u32 len; | ||
1842 | int rc = 0; | ||
1843 | |||
1844 | if (!ss_initialized || !selinux_mls_enabled) { | ||
1845 | *new_sid = sid; | ||
1846 | goto out; | ||
1847 | } | ||
1848 | |||
1849 | context_init(&newcon); | ||
1850 | |||
1851 | POLICY_RDLOCK; | ||
1852 | context1 = sidtab_search(&sidtab, sid); | ||
1853 | if (!context1) { | ||
1854 | printk(KERN_ERR "security_sid_mls_copy: unrecognized SID " | ||
1855 | "%d\n", sid); | ||
1856 | rc = -EINVAL; | ||
1857 | goto out_unlock; | ||
1858 | } | ||
1859 | |||
1860 | context2 = sidtab_search(&sidtab, mls_sid); | ||
1861 | if (!context2) { | ||
1862 | printk(KERN_ERR "security_sid_mls_copy: unrecognized SID " | ||
1863 | "%d\n", mls_sid); | ||
1864 | rc = -EINVAL; | ||
1865 | goto out_unlock; | ||
1866 | } | ||
1867 | |||
1868 | newcon.user = context1->user; | ||
1869 | newcon.role = context1->role; | ||
1870 | newcon.type = context1->type; | ||
1871 | rc = mls_copy_context(&newcon, context2); | ||
1872 | if (rc) | ||
1873 | goto out_unlock; | ||
1874 | |||
1875 | |||
1876 | /* Check the validity of the new context. */ | ||
1877 | if (!policydb_context_isvalid(&policydb, &newcon)) { | ||
1878 | rc = convert_context_handle_invalid_context(&newcon); | ||
1879 | if (rc) | ||
1880 | goto bad; | ||
1881 | } | ||
1882 | |||
1883 | rc = sidtab_context_to_sid(&sidtab, &newcon, new_sid); | ||
1884 | goto out_unlock; | ||
1885 | |||
1886 | bad: | ||
1887 | if (!context_struct_to_string(&newcon, &s, &len)) { | ||
1888 | audit_log(current->audit_context, GFP_ATOMIC, AUDIT_SELINUX_ERR, | ||
1889 | "security_sid_mls_copy: invalid context %s", s); | ||
1890 | kfree(s); | ||
1891 | } | ||
1892 | |||
1893 | out_unlock: | ||
1894 | POLICY_RDUNLOCK; | ||
1895 | context_destroy(&newcon); | ||
1896 | out: | ||
1897 | return rc; | ||
1898 | } | ||
1899 | |||
1820 | struct selinux_audit_rule { | 1900 | struct selinux_audit_rule { |
1821 | u32 au_seqno; | 1901 | u32 au_seqno; |
1822 | struct context au_ctxt; | 1902 | struct context au_ctxt; |
@@ -2064,3 +2144,536 @@ void selinux_audit_set_callback(int (*callback)(void)) | |||
2064 | { | 2144 | { |
2065 | aurule_callback = callback; | 2145 | aurule_callback = callback; |
2066 | } | 2146 | } |
2147 | |||
2148 | #ifdef CONFIG_NETLABEL | ||
2149 | /* | ||
2150 | * This is the structure we store inside the NetLabel cache block. | ||
2151 | */ | ||
2152 | #define NETLBL_CACHE(x) ((struct netlbl_cache *)(x)) | ||
2153 | #define NETLBL_CACHE_T_NONE 0 | ||
2154 | #define NETLBL_CACHE_T_SID 1 | ||
2155 | #define NETLBL_CACHE_T_MLS 2 | ||
2156 | struct netlbl_cache { | ||
2157 | u32 type; | ||
2158 | union { | ||
2159 | u32 sid; | ||
2160 | struct mls_range mls_label; | ||
2161 | } data; | ||
2162 | }; | ||
2163 | |||
2164 | /** | ||
2165 | * selinux_netlbl_cache_free - Free the NetLabel cached data | ||
2166 | * @data: the data to free | ||
2167 | * | ||
2168 | * Description: | ||
2169 | * This function is intended to be used as the free() callback inside the | ||
2170 | * netlbl_lsm_cache structure. | ||
2171 | * | ||
2172 | */ | ||
2173 | static void selinux_netlbl_cache_free(const void *data) | ||
2174 | { | ||
2175 | struct netlbl_cache *cache = NETLBL_CACHE(data); | ||
2176 | switch (cache->type) { | ||
2177 | case NETLBL_CACHE_T_MLS: | ||
2178 | ebitmap_destroy(&cache->data.mls_label.level[0].cat); | ||
2179 | break; | ||
2180 | } | ||
2181 | kfree(data); | ||
2182 | } | ||
2183 | |||
2184 | /** | ||
2185 | * selinux_netlbl_cache_add - Add an entry to the NetLabel cache | ||
2186 | * @skb: the packet | ||
2187 | * @ctx: the SELinux context | ||
2188 | * | ||
2189 | * Description: | ||
2190 | * Attempt to cache the context in @ctx, which was derived from the packet in | ||
2191 | * @skb, in the NetLabel subsystem cache. | ||
2192 | * | ||
2193 | */ | ||
2194 | static void selinux_netlbl_cache_add(struct sk_buff *skb, struct context *ctx) | ||
2195 | { | ||
2196 | struct netlbl_cache *cache = NULL; | ||
2197 | struct netlbl_lsm_secattr secattr; | ||
2198 | |||
2199 | netlbl_secattr_init(&secattr); | ||
2200 | |||
2201 | cache = kzalloc(sizeof(*cache), GFP_ATOMIC); | ||
2202 | if (cache == NULL) | ||
2203 | goto netlbl_cache_add_failure; | ||
2204 | secattr.cache.free = selinux_netlbl_cache_free; | ||
2205 | secattr.cache.data = (void *)cache; | ||
2206 | |||
2207 | cache->type = NETLBL_CACHE_T_MLS; | ||
2208 | if (ebitmap_cpy(&cache->data.mls_label.level[0].cat, | ||
2209 | &ctx->range.level[0].cat) != 0) | ||
2210 | goto netlbl_cache_add_failure; | ||
2211 | cache->data.mls_label.level[1].cat.highbit = | ||
2212 | cache->data.mls_label.level[0].cat.highbit; | ||
2213 | cache->data.mls_label.level[1].cat.node = | ||
2214 | cache->data.mls_label.level[0].cat.node; | ||
2215 | cache->data.mls_label.level[0].sens = ctx->range.level[0].sens; | ||
2216 | cache->data.mls_label.level[1].sens = ctx->range.level[0].sens; | ||
2217 | |||
2218 | if (netlbl_cache_add(skb, &secattr) != 0) | ||
2219 | goto netlbl_cache_add_failure; | ||
2220 | |||
2221 | return; | ||
2222 | |||
2223 | netlbl_cache_add_failure: | ||
2224 | netlbl_secattr_destroy(&secattr, 1); | ||
2225 | } | ||
2226 | |||
2227 | /** | ||
2228 | * selinux_netlbl_cache_invalidate - Invalidate the NetLabel cache | ||
2229 | * | ||
2230 | * Description: | ||
2231 | * Invalidate the NetLabel security attribute mapping cache. | ||
2232 | * | ||
2233 | */ | ||
2234 | void selinux_netlbl_cache_invalidate(void) | ||
2235 | { | ||
2236 | netlbl_cache_invalidate(); | ||
2237 | } | ||
2238 | |||
2239 | /** | ||
2240 | * selinux_netlbl_secattr_to_sid - Convert a NetLabel secattr to a SELinux SID | ||
2241 | * @skb: the network packet | ||
2242 | * @secattr: the NetLabel packet security attributes | ||
2243 | * @base_sid: the SELinux SID to use as a context for MLS only attributes | ||
2244 | * @sid: the SELinux SID | ||
2245 | * | ||
2246 | * Description: | ||
2247 | * Convert the given NetLabel packet security attributes in @secattr into a | ||
2248 | * SELinux SID. If the @secattr field does not contain a full SELinux | ||
2249 | * SID/context then use the context in @base_sid as the foundation. If @skb | ||
2250 | * is not NULL attempt to cache as much data as possibile. Returns zero on | ||
2251 | * success, negative values on failure. | ||
2252 | * | ||
2253 | */ | ||
2254 | static int selinux_netlbl_secattr_to_sid(struct sk_buff *skb, | ||
2255 | struct netlbl_lsm_secattr *secattr, | ||
2256 | u32 base_sid, | ||
2257 | u32 *sid) | ||
2258 | { | ||
2259 | int rc = -EIDRM; | ||
2260 | struct context *ctx; | ||
2261 | struct context ctx_new; | ||
2262 | struct netlbl_cache *cache; | ||
2263 | |||
2264 | POLICY_RDLOCK; | ||
2265 | |||
2266 | if (secattr->cache.data) { | ||
2267 | cache = NETLBL_CACHE(secattr->cache.data); | ||
2268 | switch (cache->type) { | ||
2269 | case NETLBL_CACHE_T_SID: | ||
2270 | *sid = cache->data.sid; | ||
2271 | rc = 0; | ||
2272 | break; | ||
2273 | case NETLBL_CACHE_T_MLS: | ||
2274 | ctx = sidtab_search(&sidtab, base_sid); | ||
2275 | if (ctx == NULL) | ||
2276 | goto netlbl_secattr_to_sid_return; | ||
2277 | |||
2278 | ctx_new.user = ctx->user; | ||
2279 | ctx_new.role = ctx->role; | ||
2280 | ctx_new.type = ctx->type; | ||
2281 | ctx_new.range.level[0].sens = | ||
2282 | cache->data.mls_label.level[0].sens; | ||
2283 | ctx_new.range.level[0].cat.highbit = | ||
2284 | cache->data.mls_label.level[0].cat.highbit; | ||
2285 | ctx_new.range.level[0].cat.node = | ||
2286 | cache->data.mls_label.level[0].cat.node; | ||
2287 | ctx_new.range.level[1].sens = | ||
2288 | cache->data.mls_label.level[1].sens; | ||
2289 | ctx_new.range.level[1].cat.highbit = | ||
2290 | cache->data.mls_label.level[1].cat.highbit; | ||
2291 | ctx_new.range.level[1].cat.node = | ||
2292 | cache->data.mls_label.level[1].cat.node; | ||
2293 | |||
2294 | rc = sidtab_context_to_sid(&sidtab, &ctx_new, sid); | ||
2295 | break; | ||
2296 | default: | ||
2297 | goto netlbl_secattr_to_sid_return; | ||
2298 | } | ||
2299 | } else if (secattr->mls_lvl_vld) { | ||
2300 | ctx = sidtab_search(&sidtab, base_sid); | ||
2301 | if (ctx == NULL) | ||
2302 | goto netlbl_secattr_to_sid_return; | ||
2303 | |||
2304 | ctx_new.user = ctx->user; | ||
2305 | ctx_new.role = ctx->role; | ||
2306 | ctx_new.type = ctx->type; | ||
2307 | mls_import_lvl(&ctx_new, secattr->mls_lvl, secattr->mls_lvl); | ||
2308 | if (secattr->mls_cat) { | ||
2309 | if (mls_import_cat(&ctx_new, | ||
2310 | secattr->mls_cat, | ||
2311 | secattr->mls_cat_len, | ||
2312 | NULL, | ||
2313 | 0) != 0) | ||
2314 | goto netlbl_secattr_to_sid_return; | ||
2315 | ctx_new.range.level[1].cat.highbit = | ||
2316 | ctx_new.range.level[0].cat.highbit; | ||
2317 | ctx_new.range.level[1].cat.node = | ||
2318 | ctx_new.range.level[0].cat.node; | ||
2319 | } else { | ||
2320 | ebitmap_init(&ctx_new.range.level[0].cat); | ||
2321 | ebitmap_init(&ctx_new.range.level[1].cat); | ||
2322 | } | ||
2323 | if (mls_context_isvalid(&policydb, &ctx_new) != 1) | ||
2324 | goto netlbl_secattr_to_sid_return_cleanup; | ||
2325 | |||
2326 | rc = sidtab_context_to_sid(&sidtab, &ctx_new, sid); | ||
2327 | if (rc != 0) | ||
2328 | goto netlbl_secattr_to_sid_return_cleanup; | ||
2329 | |||
2330 | if (skb != NULL) | ||
2331 | selinux_netlbl_cache_add(skb, &ctx_new); | ||
2332 | ebitmap_destroy(&ctx_new.range.level[0].cat); | ||
2333 | } else { | ||
2334 | *sid = SECINITSID_UNLABELED; | ||
2335 | rc = 0; | ||
2336 | } | ||
2337 | |||
2338 | netlbl_secattr_to_sid_return: | ||
2339 | POLICY_RDUNLOCK; | ||
2340 | return rc; | ||
2341 | netlbl_secattr_to_sid_return_cleanup: | ||
2342 | ebitmap_destroy(&ctx_new.range.level[0].cat); | ||
2343 | goto netlbl_secattr_to_sid_return; | ||
2344 | } | ||
2345 | |||
2346 | /** | ||
2347 | * selinux_netlbl_skbuff_getsid - Get the sid of a packet using NetLabel | ||
2348 | * @skb: the packet | ||
2349 | * @base_sid: the SELinux SID to use as a context for MLS only attributes | ||
2350 | * @sid: the SID | ||
2351 | * | ||
2352 | * Description: | ||
2353 | * Call the NetLabel mechanism to get the security attributes of the given | ||
2354 | * packet and use those attributes to determine the correct context/SID to | ||
2355 | * assign to the packet. Returns zero on success, negative values on failure. | ||
2356 | * | ||
2357 | */ | ||
2358 | static int selinux_netlbl_skbuff_getsid(struct sk_buff *skb, | ||
2359 | u32 base_sid, | ||
2360 | u32 *sid) | ||
2361 | { | ||
2362 | int rc; | ||
2363 | struct netlbl_lsm_secattr secattr; | ||
2364 | |||
2365 | netlbl_secattr_init(&secattr); | ||
2366 | rc = netlbl_skbuff_getattr(skb, &secattr); | ||
2367 | if (rc == 0) | ||
2368 | rc = selinux_netlbl_secattr_to_sid(skb, | ||
2369 | &secattr, | ||
2370 | base_sid, | ||
2371 | sid); | ||
2372 | netlbl_secattr_destroy(&secattr, 0); | ||
2373 | |||
2374 | return rc; | ||
2375 | } | ||
2376 | |||
2377 | /** | ||
2378 | * selinux_netlbl_socket_setsid - Label a socket using the NetLabel mechanism | ||
2379 | * @sock: the socket to label | ||
2380 | * @sid: the SID to use | ||
2381 | * | ||
2382 | * Description: | ||
2383 | * Attempt to label a socket using the NetLabel mechanism using the given | ||
2384 | * SID. Returns zero values on success, negative values on failure. | ||
2385 | * | ||
2386 | */ | ||
2387 | static int selinux_netlbl_socket_setsid(struct socket *sock, u32 sid) | ||
2388 | { | ||
2389 | int rc = -ENOENT; | ||
2390 | struct sk_security_struct *sksec = sock->sk->sk_security; | ||
2391 | struct netlbl_lsm_secattr secattr; | ||
2392 | struct context *ctx; | ||
2393 | |||
2394 | if (!ss_initialized) | ||
2395 | return 0; | ||
2396 | |||
2397 | POLICY_RDLOCK; | ||
2398 | |||
2399 | ctx = sidtab_search(&sidtab, sid); | ||
2400 | if (ctx == NULL) | ||
2401 | goto netlbl_socket_setsid_return; | ||
2402 | |||
2403 | netlbl_secattr_init(&secattr); | ||
2404 | secattr.domain = kstrdup(policydb.p_type_val_to_name[ctx->type - 1], | ||
2405 | GFP_ATOMIC); | ||
2406 | mls_export_lvl(ctx, &secattr.mls_lvl, NULL); | ||
2407 | secattr.mls_lvl_vld = 1; | ||
2408 | mls_export_cat(ctx, | ||
2409 | &secattr.mls_cat, | ||
2410 | &secattr.mls_cat_len, | ||
2411 | NULL, | ||
2412 | NULL); | ||
2413 | |||
2414 | rc = netlbl_socket_setattr(sock, &secattr); | ||
2415 | if (rc == 0) | ||
2416 | sksec->nlbl_state = NLBL_LABELED; | ||
2417 | |||
2418 | netlbl_secattr_destroy(&secattr, 0); | ||
2419 | |||
2420 | netlbl_socket_setsid_return: | ||
2421 | POLICY_RDUNLOCK; | ||
2422 | return rc; | ||
2423 | } | ||
2424 | |||
2425 | /** | ||
2426 | * selinux_netlbl_sk_security_init - Setup the NetLabel fields | ||
2427 | * @ssec: the sk_security_struct | ||
2428 | * @family: the socket family | ||
2429 | * | ||
2430 | * Description: | ||
2431 | * Called when a new sk_security_struct is allocated to initialize the NetLabel | ||
2432 | * fields. | ||
2433 | * | ||
2434 | */ | ||
2435 | void selinux_netlbl_sk_security_init(struct sk_security_struct *ssec, | ||
2436 | int family) | ||
2437 | { | ||
2438 | if (family == PF_INET) | ||
2439 | ssec->nlbl_state = NLBL_REQUIRE; | ||
2440 | else | ||
2441 | ssec->nlbl_state = NLBL_UNSET; | ||
2442 | } | ||
2443 | |||
2444 | /** | ||
2445 | * selinux_netlbl_sk_clone_security - Copy the NetLabel fields | ||
2446 | * @ssec: the original sk_security_struct | ||
2447 | * @newssec: the cloned sk_security_struct | ||
2448 | * | ||
2449 | * Description: | ||
2450 | * Clone the NetLabel specific sk_security_struct fields from @ssec to | ||
2451 | * @newssec. | ||
2452 | * | ||
2453 | */ | ||
2454 | void selinux_netlbl_sk_clone_security(struct sk_security_struct *ssec, | ||
2455 | struct sk_security_struct *newssec) | ||
2456 | { | ||
2457 | newssec->sclass = ssec->sclass; | ||
2458 | if (ssec->nlbl_state != NLBL_UNSET) | ||
2459 | newssec->nlbl_state = NLBL_REQUIRE; | ||
2460 | else | ||
2461 | newssec->nlbl_state = NLBL_UNSET; | ||
2462 | } | ||
2463 | |||
2464 | /** | ||
2465 | * selinux_netlbl_socket_post_create - Label a socket using NetLabel | ||
2466 | * @sock: the socket to label | ||
2467 | * @sock_family: the socket family | ||
2468 | * @sid: the SID to use | ||
2469 | * | ||
2470 | * Description: | ||
2471 | * Attempt to label a socket using the NetLabel mechanism using the given | ||
2472 | * SID. Returns zero values on success, negative values on failure. | ||
2473 | * | ||
2474 | */ | ||
2475 | int selinux_netlbl_socket_post_create(struct socket *sock, | ||
2476 | int sock_family, | ||
2477 | u32 sid) | ||
2478 | { | ||
2479 | struct inode_security_struct *isec = SOCK_INODE(sock)->i_security; | ||
2480 | struct sk_security_struct *sksec = sock->sk->sk_security; | ||
2481 | |||
2482 | sksec->sclass = isec->sclass; | ||
2483 | |||
2484 | if (sock_family != PF_INET) | ||
2485 | return 0; | ||
2486 | |||
2487 | sksec->nlbl_state = NLBL_REQUIRE; | ||
2488 | return selinux_netlbl_socket_setsid(sock, sid); | ||
2489 | } | ||
2490 | |||
2491 | /** | ||
2492 | * selinux_netlbl_sock_graft - Netlabel the new socket | ||
2493 | * @sk: the new connection | ||
2494 | * @sock: the new socket | ||
2495 | * | ||
2496 | * Description: | ||
2497 | * The connection represented by @sk is being grafted onto @sock so set the | ||
2498 | * socket's NetLabel to match the SID of @sk. | ||
2499 | * | ||
2500 | */ | ||
2501 | void selinux_netlbl_sock_graft(struct sock *sk, struct socket *sock) | ||
2502 | { | ||
2503 | struct inode_security_struct *isec = SOCK_INODE(sock)->i_security; | ||
2504 | struct sk_security_struct *sksec = sk->sk_security; | ||
2505 | |||
2506 | sksec->sclass = isec->sclass; | ||
2507 | |||
2508 | if (sk->sk_family != PF_INET) | ||
2509 | return; | ||
2510 | |||
2511 | sksec->nlbl_state = NLBL_REQUIRE; | ||
2512 | sksec->peer_sid = sksec->sid; | ||
2513 | |||
2514 | /* Try to set the NetLabel on the socket to save time later, if we fail | ||
2515 | * here we will pick up the pieces in later calls to | ||
2516 | * selinux_netlbl_inode_permission(). */ | ||
2517 | selinux_netlbl_socket_setsid(sock, sksec->sid); | ||
2518 | } | ||
2519 | |||
2520 | /** | ||
2521 | * selinux_netlbl_inet_conn_request - Handle a new connection request | ||
2522 | * @skb: the packet | ||
2523 | * @sock_sid: the SID of the parent socket | ||
2524 | * | ||
2525 | * Description: | ||
2526 | * If present, use the security attributes of the packet in @skb and the | ||
2527 | * parent sock's SID to arrive at a SID for the new child sock. Returns the | ||
2528 | * SID of the connection or SECSID_NULL on failure. | ||
2529 | * | ||
2530 | */ | ||
2531 | u32 selinux_netlbl_inet_conn_request(struct sk_buff *skb, u32 sock_sid) | ||
2532 | { | ||
2533 | int rc; | ||
2534 | u32 peer_sid; | ||
2535 | |||
2536 | rc = selinux_netlbl_skbuff_getsid(skb, sock_sid, &peer_sid); | ||
2537 | if (rc != 0) | ||
2538 | return SECSID_NULL; | ||
2539 | |||
2540 | if (peer_sid == SECINITSID_UNLABELED) | ||
2541 | return SECSID_NULL; | ||
2542 | |||
2543 | return peer_sid; | ||
2544 | } | ||
2545 | |||
2546 | /** | ||
2547 | * selinux_netlbl_inode_permission - Verify the socket is NetLabel labeled | ||
2548 | * @inode: the file descriptor's inode | ||
2549 | * @mask: the permission mask | ||
2550 | * | ||
2551 | * Description: | ||
2552 | * Looks at a file's inode and if it is marked as a socket protected by | ||
2553 | * NetLabel then verify that the socket has been labeled, if not try to label | ||
2554 | * the socket now with the inode's SID. Returns zero on success, negative | ||
2555 | * values on failure. | ||
2556 | * | ||
2557 | */ | ||
2558 | int selinux_netlbl_inode_permission(struct inode *inode, int mask) | ||
2559 | { | ||
2560 | int rc; | ||
2561 | struct inode_security_struct *isec; | ||
2562 | struct sk_security_struct *sksec; | ||
2563 | struct socket *sock; | ||
2564 | |||
2565 | if (!S_ISSOCK(inode->i_mode)) | ||
2566 | return 0; | ||
2567 | |||
2568 | sock = SOCKET_I(inode); | ||
2569 | isec = inode->i_security; | ||
2570 | sksec = sock->sk->sk_security; | ||
2571 | down(&isec->sem); | ||
2572 | if (unlikely(sksec->nlbl_state == NLBL_REQUIRE && | ||
2573 | (mask & (MAY_WRITE | MAY_APPEND)))) { | ||
2574 | lock_sock(sock->sk); | ||
2575 | rc = selinux_netlbl_socket_setsid(sock, sksec->sid); | ||
2576 | release_sock(sock->sk); | ||
2577 | } else | ||
2578 | rc = 0; | ||
2579 | up(&isec->sem); | ||
2580 | |||
2581 | return rc; | ||
2582 | } | ||
2583 | |||
2584 | /** | ||
2585 | * selinux_netlbl_sock_rcv_skb - Do an inbound access check using NetLabel | ||
2586 | * @sksec: the sock's sk_security_struct | ||
2587 | * @skb: the packet | ||
2588 | * @ad: the audit data | ||
2589 | * | ||
2590 | * Description: | ||
2591 | * Fetch the NetLabel security attributes from @skb and perform an access check | ||
2592 | * against the receiving socket. Returns zero on success, negative values on | ||
2593 | * error. | ||
2594 | * | ||
2595 | */ | ||
2596 | int selinux_netlbl_sock_rcv_skb(struct sk_security_struct *sksec, | ||
2597 | struct sk_buff *skb, | ||
2598 | struct avc_audit_data *ad) | ||
2599 | { | ||
2600 | int rc; | ||
2601 | u32 netlbl_sid; | ||
2602 | u32 recv_perm; | ||
2603 | |||
2604 | rc = selinux_netlbl_skbuff_getsid(skb, sksec->sid, &netlbl_sid); | ||
2605 | if (rc != 0) | ||
2606 | return rc; | ||
2607 | |||
2608 | if (netlbl_sid == SECINITSID_UNLABELED) | ||
2609 | return 0; | ||
2610 | |||
2611 | switch (sksec->sclass) { | ||
2612 | case SECCLASS_UDP_SOCKET: | ||
2613 | recv_perm = UDP_SOCKET__RECV_MSG; | ||
2614 | break; | ||
2615 | case SECCLASS_TCP_SOCKET: | ||
2616 | recv_perm = TCP_SOCKET__RECV_MSG; | ||
2617 | break; | ||
2618 | default: | ||
2619 | recv_perm = RAWIP_SOCKET__RECV_MSG; | ||
2620 | } | ||
2621 | |||
2622 | rc = avc_has_perm(sksec->sid, | ||
2623 | netlbl_sid, | ||
2624 | sksec->sclass, | ||
2625 | recv_perm, | ||
2626 | ad); | ||
2627 | if (rc == 0) | ||
2628 | return 0; | ||
2629 | |||
2630 | netlbl_skbuff_err(skb, rc); | ||
2631 | return rc; | ||
2632 | } | ||
2633 | |||
2634 | /** | ||
2635 | * selinux_netlbl_socket_getpeersec_stream - Return the connected peer's SID | ||
2636 | * @sock: the socket | ||
2637 | * | ||
2638 | * Description: | ||
2639 | * Examine @sock to find the connected peer's SID. Returns the SID on success | ||
2640 | * or SECSID_NULL on error. | ||
2641 | * | ||
2642 | */ | ||
2643 | u32 selinux_netlbl_socket_getpeersec_stream(struct socket *sock) | ||
2644 | { | ||
2645 | struct sk_security_struct *sksec = sock->sk->sk_security; | ||
2646 | |||
2647 | if (sksec->peer_sid == SECINITSID_UNLABELED) | ||
2648 | return SECSID_NULL; | ||
2649 | |||
2650 | return sksec->peer_sid; | ||
2651 | } | ||
2652 | |||
2653 | /** | ||
2654 | * selinux_netlbl_socket_getpeersec_dgram - Return the SID of a NetLabel packet | ||
2655 | * @skb: the packet | ||
2656 | * | ||
2657 | * Description: | ||
2658 | * Examine @skb to find the SID assigned to it by NetLabel. Returns the SID on | ||
2659 | * success, SECSID_NULL on error. | ||
2660 | * | ||
2661 | */ | ||
2662 | u32 selinux_netlbl_socket_getpeersec_dgram(struct sk_buff *skb) | ||
2663 | { | ||
2664 | int peer_sid; | ||
2665 | struct sock *sk = skb->sk; | ||
2666 | struct inode_security_struct *isec; | ||
2667 | |||
2668 | if (sk == NULL || sk->sk_socket == NULL) | ||
2669 | return SECSID_NULL; | ||
2670 | |||
2671 | isec = SOCK_INODE(sk->sk_socket)->i_security; | ||
2672 | if (selinux_netlbl_skbuff_getsid(skb, isec->sid, &peer_sid) != 0) | ||
2673 | return SECSID_NULL; | ||
2674 | if (peer_sid == SECINITSID_UNLABELED) | ||
2675 | return SECSID_NULL; | ||
2676 | |||
2677 | return peer_sid; | ||
2678 | } | ||
2679 | #endif /* CONFIG_NETLABEL */ | ||
diff --git a/security/selinux/xfrm.c b/security/selinux/xfrm.c index 6c985ced8102..3e742b850af6 100644 --- a/security/selinux/xfrm.c +++ b/security/selinux/xfrm.c | |||
@@ -6,7 +6,12 @@ | |||
6 | * Authors: Serge Hallyn <sergeh@us.ibm.com> | 6 | * Authors: Serge Hallyn <sergeh@us.ibm.com> |
7 | * Trent Jaeger <jaegert@us.ibm.com> | 7 | * Trent Jaeger <jaegert@us.ibm.com> |
8 | * | 8 | * |
9 | * Updated: Venkat Yekkirala <vyekkirala@TrustedCS.com> | ||
10 | * | ||
11 | * Granular IPSec Associations for use in MLS environments. | ||
12 | * | ||
9 | * Copyright (C) 2005 International Business Machines Corporation | 13 | * Copyright (C) 2005 International Business Machines Corporation |
14 | * Copyright (C) 2006 Trusted Computer Solutions, Inc. | ||
10 | * | 15 | * |
11 | * This program is free software; you can redistribute it and/or modify | 16 | * This program is free software; you can redistribute it and/or modify |
12 | * it under the terms of the GNU General Public License version 2, | 17 | * it under the terms of the GNU General Public License version 2, |
@@ -67,10 +72,10 @@ static inline int selinux_authorizable_xfrm(struct xfrm_state *x) | |||
67 | } | 72 | } |
68 | 73 | ||
69 | /* | 74 | /* |
70 | * LSM hook implementation that authorizes that a socket can be used | 75 | * LSM hook implementation that authorizes that a flow can use |
71 | * with the corresponding xfrm_sec_ctx and direction. | 76 | * a xfrm policy rule. |
72 | */ | 77 | */ |
73 | int selinux_xfrm_policy_lookup(struct xfrm_policy *xp, u32 sk_sid, u8 dir) | 78 | int selinux_xfrm_policy_lookup(struct xfrm_policy *xp, u32 fl_secid, u8 dir) |
74 | { | 79 | { |
75 | int rc = 0; | 80 | int rc = 0; |
76 | u32 sel_sid = SECINITSID_UNLABELED; | 81 | u32 sel_sid = SECINITSID_UNLABELED; |
@@ -84,27 +89,130 @@ int selinux_xfrm_policy_lookup(struct xfrm_policy *xp, u32 sk_sid, u8 dir) | |||
84 | sel_sid = ctx->ctx_sid; | 89 | sel_sid = ctx->ctx_sid; |
85 | } | 90 | } |
86 | 91 | ||
87 | rc = avc_has_perm(sk_sid, sel_sid, SECCLASS_ASSOCIATION, | 92 | rc = avc_has_perm(fl_secid, sel_sid, SECCLASS_ASSOCIATION, |
88 | ((dir == FLOW_DIR_IN) ? ASSOCIATION__RECVFROM : | 93 | ASSOCIATION__POLMATCH, |
89 | ((dir == FLOW_DIR_OUT) ? ASSOCIATION__SENDTO : | ||
90 | (ASSOCIATION__SENDTO | ASSOCIATION__RECVFROM))), | ||
91 | NULL); | 94 | NULL); |
92 | 95 | ||
93 | return rc; | 96 | return rc; |
94 | } | 97 | } |
95 | 98 | ||
96 | /* | 99 | /* |
100 | * LSM hook implementation that authorizes that a state matches | ||
101 | * the given policy, flow combo. | ||
102 | */ | ||
103 | |||
104 | int selinux_xfrm_state_pol_flow_match(struct xfrm_state *x, struct xfrm_policy *xp, | ||
105 | struct flowi *fl) | ||
106 | { | ||
107 | u32 state_sid; | ||
108 | u32 pol_sid; | ||
109 | int err; | ||
110 | |||
111 | if (x->security) | ||
112 | state_sid = x->security->ctx_sid; | ||
113 | else | ||
114 | state_sid = SECINITSID_UNLABELED; | ||
115 | |||
116 | if (xp->security) | ||
117 | pol_sid = xp->security->ctx_sid; | ||
118 | else | ||
119 | pol_sid = SECINITSID_UNLABELED; | ||
120 | |||
121 | err = avc_has_perm(state_sid, pol_sid, SECCLASS_ASSOCIATION, | ||
122 | ASSOCIATION__POLMATCH, | ||
123 | NULL); | ||
124 | |||
125 | if (err) | ||
126 | return 0; | ||
127 | |||
128 | return selinux_xfrm_flow_state_match(fl, x); | ||
129 | } | ||
130 | |||
131 | /* | ||
132 | * LSM hook implementation that authorizes that a particular outgoing flow | ||
133 | * can use a given security association. | ||
134 | */ | ||
135 | |||
136 | int selinux_xfrm_flow_state_match(struct flowi *fl, struct xfrm_state *xfrm) | ||
137 | { | ||
138 | int rc = 0; | ||
139 | u32 sel_sid = SECINITSID_UNLABELED; | ||
140 | struct xfrm_sec_ctx *ctx; | ||
141 | |||
142 | /* Context sid is either set to label or ANY_ASSOC */ | ||
143 | if ((ctx = xfrm->security)) { | ||
144 | if (!selinux_authorizable_ctx(ctx)) | ||
145 | return 0; | ||
146 | |||
147 | sel_sid = ctx->ctx_sid; | ||
148 | } | ||
149 | |||
150 | rc = avc_has_perm(fl->secid, sel_sid, SECCLASS_ASSOCIATION, | ||
151 | ASSOCIATION__SENDTO, | ||
152 | NULL)? 0:1; | ||
153 | |||
154 | return rc; | ||
155 | } | ||
156 | |||
157 | /* | ||
158 | * LSM hook implementation that determines the sid for the session. | ||
159 | */ | ||
160 | |||
161 | int selinux_xfrm_decode_session(struct sk_buff *skb, u32 *sid, int ckall) | ||
162 | { | ||
163 | struct sec_path *sp; | ||
164 | |||
165 | *sid = SECSID_NULL; | ||
166 | |||
167 | if (skb == NULL) | ||
168 | return 0; | ||
169 | |||
170 | sp = skb->sp; | ||
171 | if (sp) { | ||
172 | int i, sid_set = 0; | ||
173 | |||
174 | for (i = sp->len-1; i >= 0; i--) { | ||
175 | struct xfrm_state *x = sp->xvec[i]; | ||
176 | if (selinux_authorizable_xfrm(x)) { | ||
177 | struct xfrm_sec_ctx *ctx = x->security; | ||
178 | |||
179 | if (!sid_set) { | ||
180 | *sid = ctx->ctx_sid; | ||
181 | sid_set = 1; | ||
182 | |||
183 | if (!ckall) | ||
184 | break; | ||
185 | } | ||
186 | else if (*sid != ctx->ctx_sid) | ||
187 | return -EINVAL; | ||
188 | } | ||
189 | } | ||
190 | } | ||
191 | |||
192 | return 0; | ||
193 | } | ||
194 | |||
195 | /* | ||
97 | * Security blob allocation for xfrm_policy and xfrm_state | 196 | * Security blob allocation for xfrm_policy and xfrm_state |
98 | * CTX does not have a meaningful value on input | 197 | * CTX does not have a meaningful value on input |
99 | */ | 198 | */ |
100 | static int selinux_xfrm_sec_ctx_alloc(struct xfrm_sec_ctx **ctxp, struct xfrm_user_sec_ctx *uctx) | 199 | static int selinux_xfrm_sec_ctx_alloc(struct xfrm_sec_ctx **ctxp, |
200 | struct xfrm_user_sec_ctx *uctx, struct xfrm_sec_ctx *pol, u32 sid) | ||
101 | { | 201 | { |
102 | int rc = 0; | 202 | int rc = 0; |
103 | struct task_security_struct *tsec = current->security; | 203 | struct task_security_struct *tsec = current->security; |
104 | struct xfrm_sec_ctx *ctx; | 204 | struct xfrm_sec_ctx *ctx = NULL; |
205 | char *ctx_str = NULL; | ||
206 | u32 str_len; | ||
207 | u32 ctx_sid; | ||
208 | |||
209 | BUG_ON(uctx && pol); | ||
210 | |||
211 | if (!uctx) | ||
212 | goto not_from_user; | ||
105 | 213 | ||
106 | BUG_ON(!uctx); | 214 | if (uctx->ctx_doi != XFRM_SC_ALG_SELINUX) |
107 | BUG_ON(uctx->ctx_doi != XFRM_SC_ALG_SELINUX); | 215 | return -EINVAL; |
108 | 216 | ||
109 | if (uctx->ctx_len >= PAGE_SIZE) | 217 | if (uctx->ctx_len >= PAGE_SIZE) |
110 | return -ENOMEM; | 218 | return -ENOMEM; |
@@ -141,9 +249,43 @@ static int selinux_xfrm_sec_ctx_alloc(struct xfrm_sec_ctx **ctxp, struct xfrm_us | |||
141 | 249 | ||
142 | return rc; | 250 | return rc; |
143 | 251 | ||
252 | not_from_user: | ||
253 | if (pol) { | ||
254 | rc = security_sid_mls_copy(pol->ctx_sid, sid, &ctx_sid); | ||
255 | if (rc) | ||
256 | goto out; | ||
257 | } | ||
258 | else | ||
259 | ctx_sid = sid; | ||
260 | |||
261 | rc = security_sid_to_context(ctx_sid, &ctx_str, &str_len); | ||
262 | if (rc) | ||
263 | goto out; | ||
264 | |||
265 | *ctxp = ctx = kmalloc(sizeof(*ctx) + | ||
266 | str_len, | ||
267 | GFP_ATOMIC); | ||
268 | |||
269 | if (!ctx) { | ||
270 | rc = -ENOMEM; | ||
271 | goto out; | ||
272 | } | ||
273 | |||
274 | ctx->ctx_doi = XFRM_SC_DOI_LSM; | ||
275 | ctx->ctx_alg = XFRM_SC_ALG_SELINUX; | ||
276 | ctx->ctx_sid = ctx_sid; | ||
277 | ctx->ctx_len = str_len; | ||
278 | memcpy(ctx->ctx_str, | ||
279 | ctx_str, | ||
280 | str_len); | ||
281 | |||
282 | goto out2; | ||
283 | |||
144 | out: | 284 | out: |
145 | *ctxp = NULL; | 285 | *ctxp = NULL; |
146 | kfree(ctx); | 286 | kfree(ctx); |
287 | out2: | ||
288 | kfree(ctx_str); | ||
147 | return rc; | 289 | return rc; |
148 | } | 290 | } |
149 | 291 | ||
@@ -151,13 +293,23 @@ out: | |||
151 | * LSM hook implementation that allocs and transfers uctx spec to | 293 | * LSM hook implementation that allocs and transfers uctx spec to |
152 | * xfrm_policy. | 294 | * xfrm_policy. |
153 | */ | 295 | */ |
154 | int selinux_xfrm_policy_alloc(struct xfrm_policy *xp, struct xfrm_user_sec_ctx *uctx) | 296 | int selinux_xfrm_policy_alloc(struct xfrm_policy *xp, |
297 | struct xfrm_user_sec_ctx *uctx, struct sock *sk) | ||
155 | { | 298 | { |
156 | int err; | 299 | int err; |
300 | u32 sid; | ||
157 | 301 | ||
158 | BUG_ON(!xp); | 302 | BUG_ON(!xp); |
303 | BUG_ON(uctx && sk); | ||
159 | 304 | ||
160 | err = selinux_xfrm_sec_ctx_alloc(&xp->security, uctx); | 305 | if (sk) { |
306 | struct sk_security_struct *ssec = sk->sk_security; | ||
307 | sid = ssec->sid; | ||
308 | } | ||
309 | else | ||
310 | sid = SECSID_NULL; | ||
311 | |||
312 | err = selinux_xfrm_sec_ctx_alloc(&xp->security, uctx, NULL, sid); | ||
161 | return err; | 313 | return err; |
162 | } | 314 | } |
163 | 315 | ||
@@ -217,13 +369,14 @@ int selinux_xfrm_policy_delete(struct xfrm_policy *xp) | |||
217 | * LSM hook implementation that allocs and transfers sec_ctx spec to | 369 | * LSM hook implementation that allocs and transfers sec_ctx spec to |
218 | * xfrm_state. | 370 | * xfrm_state. |
219 | */ | 371 | */ |
220 | int selinux_xfrm_state_alloc(struct xfrm_state *x, struct xfrm_user_sec_ctx *uctx) | 372 | int selinux_xfrm_state_alloc(struct xfrm_state *x, struct xfrm_user_sec_ctx *uctx, |
373 | struct xfrm_sec_ctx *pol, u32 secid) | ||
221 | { | 374 | { |
222 | int err; | 375 | int err; |
223 | 376 | ||
224 | BUG_ON(!x); | 377 | BUG_ON(!x); |
225 | 378 | ||
226 | err = selinux_xfrm_sec_ctx_alloc(&x->security, uctx); | 379 | err = selinux_xfrm_sec_ctx_alloc(&x->security, uctx, pol, secid); |
227 | return err; | 380 | return err; |
228 | } | 381 | } |
229 | 382 | ||
@@ -329,38 +482,30 @@ int selinux_xfrm_state_delete(struct xfrm_state *x) | |||
329 | * we need to check for unlabelled access since this may not have | 482 | * we need to check for unlabelled access since this may not have |
330 | * gone thru the IPSec process. | 483 | * gone thru the IPSec process. |
331 | */ | 484 | */ |
332 | int selinux_xfrm_sock_rcv_skb(u32 isec_sid, struct sk_buff *skb) | 485 | int selinux_xfrm_sock_rcv_skb(u32 isec_sid, struct sk_buff *skb, |
486 | struct avc_audit_data *ad) | ||
333 | { | 487 | { |
334 | int i, rc = 0; | 488 | int i, rc = 0; |
335 | struct sec_path *sp; | 489 | struct sec_path *sp; |
490 | u32 sel_sid = SECINITSID_UNLABELED; | ||
336 | 491 | ||
337 | sp = skb->sp; | 492 | sp = skb->sp; |
338 | 493 | ||
339 | if (sp) { | 494 | if (sp) { |
340 | /* | ||
341 | * __xfrm_policy_check does not approve unless xfrm_policy_ok | ||
342 | * says that spi's match for policy and the socket. | ||
343 | * | ||
344 | * Only need to verify the existence of an authorizable sp. | ||
345 | */ | ||
346 | for (i = 0; i < sp->len; i++) { | 495 | for (i = 0; i < sp->len; i++) { |
347 | struct xfrm_state *x = sp->xvec[i]; | 496 | struct xfrm_state *x = sp->xvec[i]; |
348 | 497 | ||
349 | if (x && selinux_authorizable_xfrm(x)) | 498 | if (x && selinux_authorizable_xfrm(x)) { |
350 | goto accept; | 499 | struct xfrm_sec_ctx *ctx = x->security; |
500 | sel_sid = ctx->ctx_sid; | ||
501 | break; | ||
502 | } | ||
351 | } | 503 | } |
352 | } | 504 | } |
353 | 505 | ||
354 | /* check SELinux sock for unlabelled access */ | 506 | rc = avc_has_perm(isec_sid, sel_sid, SECCLASS_ASSOCIATION, |
355 | rc = avc_has_perm(isec_sid, SECINITSID_UNLABELED, SECCLASS_ASSOCIATION, | 507 | ASSOCIATION__RECVFROM, ad); |
356 | ASSOCIATION__RECVFROM, NULL); | ||
357 | if (rc) | ||
358 | goto drop; | ||
359 | |||
360 | accept: | ||
361 | return 0; | ||
362 | 508 | ||
363 | drop: | ||
364 | return rc; | 509 | return rc; |
365 | } | 510 | } |
366 | 511 | ||
@@ -371,7 +516,8 @@ drop: | |||
371 | * If we do have a authorizable security association, then it has already been | 516 | * If we do have a authorizable security association, then it has already been |
372 | * checked in xfrm_policy_lookup hook. | 517 | * checked in xfrm_policy_lookup hook. |
373 | */ | 518 | */ |
374 | int selinux_xfrm_postroute_last(u32 isec_sid, struct sk_buff *skb) | 519 | int selinux_xfrm_postroute_last(u32 isec_sid, struct sk_buff *skb, |
520 | struct avc_audit_data *ad) | ||
375 | { | 521 | { |
376 | struct dst_entry *dst; | 522 | struct dst_entry *dst; |
377 | int rc = 0; | 523 | int rc = 0; |
@@ -391,7 +537,7 @@ int selinux_xfrm_postroute_last(u32 isec_sid, struct sk_buff *skb) | |||
391 | } | 537 | } |
392 | 538 | ||
393 | rc = avc_has_perm(isec_sid, SECINITSID_UNLABELED, SECCLASS_ASSOCIATION, | 539 | rc = avc_has_perm(isec_sid, SECINITSID_UNLABELED, SECCLASS_ASSOCIATION, |
394 | ASSOCIATION__SENDTO, NULL); | 540 | ASSOCIATION__SENDTO, ad); |
395 | out: | 541 | out: |
396 | return rc; | 542 | return rc; |
397 | } | 543 | } |
diff --git a/sound/aoa/codecs/Kconfig b/sound/aoa/codecs/Kconfig index 90cf58f68630..d5fbd6016e93 100644 --- a/sound/aoa/codecs/Kconfig +++ b/sound/aoa/codecs/Kconfig | |||
@@ -1,6 +1,8 @@ | |||
1 | config SND_AOA_ONYX | 1 | config SND_AOA_ONYX |
2 | tristate "support Onyx chip" | 2 | tristate "support Onyx chip" |
3 | depends on SND_AOA | 3 | depends on SND_AOA |
4 | select I2C | ||
5 | select I2C_POWERMAC | ||
4 | ---help--- | 6 | ---help--- |
5 | This option enables support for the Onyx (pcm3052) | 7 | This option enables support for the Onyx (pcm3052) |
6 | codec chip found in the latest Apple machines | 8 | codec chip found in the latest Apple machines |
@@ -18,6 +20,8 @@ config SND_AOA_ONYX | |||
18 | config SND_AOA_TAS | 20 | config SND_AOA_TAS |
19 | tristate "support TAS chips" | 21 | tristate "support TAS chips" |
20 | depends on SND_AOA | 22 | depends on SND_AOA |
23 | select I2C | ||
24 | select I2C_POWERMAC | ||
21 | ---help--- | 25 | ---help--- |
22 | This option enables support for the tas chips | 26 | This option enables support for the tas chips |
23 | found in a lot of Apple Machines, especially | 27 | found in a lot of Apple Machines, especially |
diff --git a/sound/aoa/codecs/snd-aoa-codec-tas.c b/sound/aoa/codecs/snd-aoa-codec-tas.c index 16c0b6b0a805..2ef55a17917c 100644 --- a/sound/aoa/codecs/snd-aoa-codec-tas.c +++ b/sound/aoa/codecs/snd-aoa-codec-tas.c | |||
@@ -66,6 +66,8 @@ | |||
66 | #include <asm/prom.h> | 66 | #include <asm/prom.h> |
67 | #include <linux/delay.h> | 67 | #include <linux/delay.h> |
68 | #include <linux/module.h> | 68 | #include <linux/module.h> |
69 | #include <linux/mutex.h> | ||
70 | |||
69 | MODULE_AUTHOR("Johannes Berg <johannes@sipsolutions.net>"); | 71 | MODULE_AUTHOR("Johannes Berg <johannes@sipsolutions.net>"); |
70 | MODULE_LICENSE("GPL"); | 72 | MODULE_LICENSE("GPL"); |
71 | MODULE_DESCRIPTION("tas codec driver for snd-aoa"); | 73 | MODULE_DESCRIPTION("tas codec driver for snd-aoa"); |
@@ -91,6 +93,10 @@ struct tas { | |||
91 | u8 bass, treble; | 93 | u8 bass, treble; |
92 | u8 acr; | 94 | u8 acr; |
93 | int drc_range; | 95 | int drc_range; |
96 | /* protects hardware access against concurrency from | ||
97 | * userspace when hitting controls and during | ||
98 | * codec init/suspend/resume */ | ||
99 | struct mutex mtx; | ||
94 | }; | 100 | }; |
95 | 101 | ||
96 | static int tas_reset_init(struct tas *tas); | 102 | static int tas_reset_init(struct tas *tas); |
@@ -231,8 +237,10 @@ static int tas_snd_vol_get(struct snd_kcontrol *kcontrol, | |||
231 | { | 237 | { |
232 | struct tas *tas = snd_kcontrol_chip(kcontrol); | 238 | struct tas *tas = snd_kcontrol_chip(kcontrol); |
233 | 239 | ||
240 | mutex_lock(&tas->mtx); | ||
234 | ucontrol->value.integer.value[0] = tas->cached_volume_l; | 241 | ucontrol->value.integer.value[0] = tas->cached_volume_l; |
235 | ucontrol->value.integer.value[1] = tas->cached_volume_r; | 242 | ucontrol->value.integer.value[1] = tas->cached_volume_r; |
243 | mutex_unlock(&tas->mtx); | ||
236 | return 0; | 244 | return 0; |
237 | } | 245 | } |
238 | 246 | ||
@@ -241,14 +249,18 @@ static int tas_snd_vol_put(struct snd_kcontrol *kcontrol, | |||
241 | { | 249 | { |
242 | struct tas *tas = snd_kcontrol_chip(kcontrol); | 250 | struct tas *tas = snd_kcontrol_chip(kcontrol); |
243 | 251 | ||
252 | mutex_lock(&tas->mtx); | ||
244 | if (tas->cached_volume_l == ucontrol->value.integer.value[0] | 253 | if (tas->cached_volume_l == ucontrol->value.integer.value[0] |
245 | && tas->cached_volume_r == ucontrol->value.integer.value[1]) | 254 | && tas->cached_volume_r == ucontrol->value.integer.value[1]) { |
255 | mutex_unlock(&tas->mtx); | ||
246 | return 0; | 256 | return 0; |
257 | } | ||
247 | 258 | ||
248 | tas->cached_volume_l = ucontrol->value.integer.value[0]; | 259 | tas->cached_volume_l = ucontrol->value.integer.value[0]; |
249 | tas->cached_volume_r = ucontrol->value.integer.value[1]; | 260 | tas->cached_volume_r = ucontrol->value.integer.value[1]; |
250 | if (tas->hw_enabled) | 261 | if (tas->hw_enabled) |
251 | tas_set_volume(tas); | 262 | tas_set_volume(tas); |
263 | mutex_unlock(&tas->mtx); | ||
252 | return 1; | 264 | return 1; |
253 | } | 265 | } |
254 | 266 | ||
@@ -276,8 +288,10 @@ static int tas_snd_mute_get(struct snd_kcontrol *kcontrol, | |||
276 | { | 288 | { |
277 | struct tas *tas = snd_kcontrol_chip(kcontrol); | 289 | struct tas *tas = snd_kcontrol_chip(kcontrol); |
278 | 290 | ||
291 | mutex_lock(&tas->mtx); | ||
279 | ucontrol->value.integer.value[0] = !tas->mute_l; | 292 | ucontrol->value.integer.value[0] = !tas->mute_l; |
280 | ucontrol->value.integer.value[1] = !tas->mute_r; | 293 | ucontrol->value.integer.value[1] = !tas->mute_r; |
294 | mutex_unlock(&tas->mtx); | ||
281 | return 0; | 295 | return 0; |
282 | } | 296 | } |
283 | 297 | ||
@@ -286,14 +300,18 @@ static int tas_snd_mute_put(struct snd_kcontrol *kcontrol, | |||
286 | { | 300 | { |
287 | struct tas *tas = snd_kcontrol_chip(kcontrol); | 301 | struct tas *tas = snd_kcontrol_chip(kcontrol); |
288 | 302 | ||
303 | mutex_lock(&tas->mtx); | ||
289 | if (tas->mute_l == !ucontrol->value.integer.value[0] | 304 | if (tas->mute_l == !ucontrol->value.integer.value[0] |
290 | && tas->mute_r == !ucontrol->value.integer.value[1]) | 305 | && tas->mute_r == !ucontrol->value.integer.value[1]) { |
306 | mutex_unlock(&tas->mtx); | ||
291 | return 0; | 307 | return 0; |
308 | } | ||
292 | 309 | ||
293 | tas->mute_l = !ucontrol->value.integer.value[0]; | 310 | tas->mute_l = !ucontrol->value.integer.value[0]; |
294 | tas->mute_r = !ucontrol->value.integer.value[1]; | 311 | tas->mute_r = !ucontrol->value.integer.value[1]; |
295 | if (tas->hw_enabled) | 312 | if (tas->hw_enabled) |
296 | tas_set_volume(tas); | 313 | tas_set_volume(tas); |
314 | mutex_unlock(&tas->mtx); | ||
297 | return 1; | 315 | return 1; |
298 | } | 316 | } |
299 | 317 | ||
@@ -322,8 +340,10 @@ static int tas_snd_mixer_get(struct snd_kcontrol *kcontrol, | |||
322 | struct tas *tas = snd_kcontrol_chip(kcontrol); | 340 | struct tas *tas = snd_kcontrol_chip(kcontrol); |
323 | int idx = kcontrol->private_value; | 341 | int idx = kcontrol->private_value; |
324 | 342 | ||
343 | mutex_lock(&tas->mtx); | ||
325 | ucontrol->value.integer.value[0] = tas->mixer_l[idx]; | 344 | ucontrol->value.integer.value[0] = tas->mixer_l[idx]; |
326 | ucontrol->value.integer.value[1] = tas->mixer_r[idx]; | 345 | ucontrol->value.integer.value[1] = tas->mixer_r[idx]; |
346 | mutex_unlock(&tas->mtx); | ||
327 | 347 | ||
328 | return 0; | 348 | return 0; |
329 | } | 349 | } |
@@ -334,15 +354,19 @@ static int tas_snd_mixer_put(struct snd_kcontrol *kcontrol, | |||
334 | struct tas *tas = snd_kcontrol_chip(kcontrol); | 354 | struct tas *tas = snd_kcontrol_chip(kcontrol); |
335 | int idx = kcontrol->private_value; | 355 | int idx = kcontrol->private_value; |
336 | 356 | ||
357 | mutex_lock(&tas->mtx); | ||
337 | if (tas->mixer_l[idx] == ucontrol->value.integer.value[0] | 358 | if (tas->mixer_l[idx] == ucontrol->value.integer.value[0] |
338 | && tas->mixer_r[idx] == ucontrol->value.integer.value[1]) | 359 | && tas->mixer_r[idx] == ucontrol->value.integer.value[1]) { |
360 | mutex_unlock(&tas->mtx); | ||
339 | return 0; | 361 | return 0; |
362 | } | ||
340 | 363 | ||
341 | tas->mixer_l[idx] = ucontrol->value.integer.value[0]; | 364 | tas->mixer_l[idx] = ucontrol->value.integer.value[0]; |
342 | tas->mixer_r[idx] = ucontrol->value.integer.value[1]; | 365 | tas->mixer_r[idx] = ucontrol->value.integer.value[1]; |
343 | 366 | ||
344 | if (tas->hw_enabled) | 367 | if (tas->hw_enabled) |
345 | tas_set_mixer(tas); | 368 | tas_set_mixer(tas); |
369 | mutex_unlock(&tas->mtx); | ||
346 | return 1; | 370 | return 1; |
347 | } | 371 | } |
348 | 372 | ||
@@ -375,7 +399,9 @@ static int tas_snd_drc_range_get(struct snd_kcontrol *kcontrol, | |||
375 | { | 399 | { |
376 | struct tas *tas = snd_kcontrol_chip(kcontrol); | 400 | struct tas *tas = snd_kcontrol_chip(kcontrol); |
377 | 401 | ||
402 | mutex_lock(&tas->mtx); | ||
378 | ucontrol->value.integer.value[0] = tas->drc_range; | 403 | ucontrol->value.integer.value[0] = tas->drc_range; |
404 | mutex_unlock(&tas->mtx); | ||
379 | return 0; | 405 | return 0; |
380 | } | 406 | } |
381 | 407 | ||
@@ -384,12 +410,16 @@ static int tas_snd_drc_range_put(struct snd_kcontrol *kcontrol, | |||
384 | { | 410 | { |
385 | struct tas *tas = snd_kcontrol_chip(kcontrol); | 411 | struct tas *tas = snd_kcontrol_chip(kcontrol); |
386 | 412 | ||
387 | if (tas->drc_range == ucontrol->value.integer.value[0]) | 413 | mutex_lock(&tas->mtx); |
414 | if (tas->drc_range == ucontrol->value.integer.value[0]) { | ||
415 | mutex_unlock(&tas->mtx); | ||
388 | return 0; | 416 | return 0; |
417 | } | ||
389 | 418 | ||
390 | tas->drc_range = ucontrol->value.integer.value[0]; | 419 | tas->drc_range = ucontrol->value.integer.value[0]; |
391 | if (tas->hw_enabled) | 420 | if (tas->hw_enabled) |
392 | tas3004_set_drc(tas); | 421 | tas3004_set_drc(tas); |
422 | mutex_unlock(&tas->mtx); | ||
393 | return 1; | 423 | return 1; |
394 | } | 424 | } |
395 | 425 | ||
@@ -417,7 +447,9 @@ static int tas_snd_drc_switch_get(struct snd_kcontrol *kcontrol, | |||
417 | { | 447 | { |
418 | struct tas *tas = snd_kcontrol_chip(kcontrol); | 448 | struct tas *tas = snd_kcontrol_chip(kcontrol); |
419 | 449 | ||
450 | mutex_lock(&tas->mtx); | ||
420 | ucontrol->value.integer.value[0] = tas->drc_enabled; | 451 | ucontrol->value.integer.value[0] = tas->drc_enabled; |
452 | mutex_unlock(&tas->mtx); | ||
421 | return 0; | 453 | return 0; |
422 | } | 454 | } |
423 | 455 | ||
@@ -426,12 +458,16 @@ static int tas_snd_drc_switch_put(struct snd_kcontrol *kcontrol, | |||
426 | { | 458 | { |
427 | struct tas *tas = snd_kcontrol_chip(kcontrol); | 459 | struct tas *tas = snd_kcontrol_chip(kcontrol); |
428 | 460 | ||
429 | if (tas->drc_enabled == ucontrol->value.integer.value[0]) | 461 | mutex_lock(&tas->mtx); |
462 | if (tas->drc_enabled == ucontrol->value.integer.value[0]) { | ||
463 | mutex_unlock(&tas->mtx); | ||
430 | return 0; | 464 | return 0; |
465 | } | ||
431 | 466 | ||
432 | tas->drc_enabled = ucontrol->value.integer.value[0]; | 467 | tas->drc_enabled = ucontrol->value.integer.value[0]; |
433 | if (tas->hw_enabled) | 468 | if (tas->hw_enabled) |
434 | tas3004_set_drc(tas); | 469 | tas3004_set_drc(tas); |
470 | mutex_unlock(&tas->mtx); | ||
435 | return 1; | 471 | return 1; |
436 | } | 472 | } |
437 | 473 | ||
@@ -463,7 +499,9 @@ static int tas_snd_capture_source_get(struct snd_kcontrol *kcontrol, | |||
463 | { | 499 | { |
464 | struct tas *tas = snd_kcontrol_chip(kcontrol); | 500 | struct tas *tas = snd_kcontrol_chip(kcontrol); |
465 | 501 | ||
502 | mutex_lock(&tas->mtx); | ||
466 | ucontrol->value.enumerated.item[0] = !!(tas->acr & TAS_ACR_INPUT_B); | 503 | ucontrol->value.enumerated.item[0] = !!(tas->acr & TAS_ACR_INPUT_B); |
504 | mutex_unlock(&tas->mtx); | ||
467 | return 0; | 505 | return 0; |
468 | } | 506 | } |
469 | 507 | ||
@@ -471,15 +509,21 @@ static int tas_snd_capture_source_put(struct snd_kcontrol *kcontrol, | |||
471 | struct snd_ctl_elem_value *ucontrol) | 509 | struct snd_ctl_elem_value *ucontrol) |
472 | { | 510 | { |
473 | struct tas *tas = snd_kcontrol_chip(kcontrol); | 511 | struct tas *tas = snd_kcontrol_chip(kcontrol); |
474 | int oldacr = tas->acr; | 512 | int oldacr; |
513 | |||
514 | mutex_lock(&tas->mtx); | ||
515 | oldacr = tas->acr; | ||
475 | 516 | ||
476 | tas->acr &= ~TAS_ACR_INPUT_B; | 517 | tas->acr &= ~TAS_ACR_INPUT_B; |
477 | if (ucontrol->value.enumerated.item[0]) | 518 | if (ucontrol->value.enumerated.item[0]) |
478 | tas->acr |= TAS_ACR_INPUT_B; | 519 | tas->acr |= TAS_ACR_INPUT_B; |
479 | if (oldacr == tas->acr) | 520 | if (oldacr == tas->acr) { |
521 | mutex_unlock(&tas->mtx); | ||
480 | return 0; | 522 | return 0; |
523 | } | ||
481 | if (tas->hw_enabled) | 524 | if (tas->hw_enabled) |
482 | tas_write_reg(tas, TAS_REG_ACR, 1, &tas->acr); | 525 | tas_write_reg(tas, TAS_REG_ACR, 1, &tas->acr); |
526 | mutex_unlock(&tas->mtx); | ||
483 | return 1; | 527 | return 1; |
484 | } | 528 | } |
485 | 529 | ||
@@ -518,7 +562,9 @@ static int tas_snd_treble_get(struct snd_kcontrol *kcontrol, | |||
518 | { | 562 | { |
519 | struct tas *tas = snd_kcontrol_chip(kcontrol); | 563 | struct tas *tas = snd_kcontrol_chip(kcontrol); |
520 | 564 | ||
565 | mutex_lock(&tas->mtx); | ||
521 | ucontrol->value.integer.value[0] = tas->treble; | 566 | ucontrol->value.integer.value[0] = tas->treble; |
567 | mutex_unlock(&tas->mtx); | ||
522 | return 0; | 568 | return 0; |
523 | } | 569 | } |
524 | 570 | ||
@@ -527,12 +573,16 @@ static int tas_snd_treble_put(struct snd_kcontrol *kcontrol, | |||
527 | { | 573 | { |
528 | struct tas *tas = snd_kcontrol_chip(kcontrol); | 574 | struct tas *tas = snd_kcontrol_chip(kcontrol); |
529 | 575 | ||
530 | if (tas->treble == ucontrol->value.integer.value[0]) | 576 | mutex_lock(&tas->mtx); |
577 | if (tas->treble == ucontrol->value.integer.value[0]) { | ||
578 | mutex_unlock(&tas->mtx); | ||
531 | return 0; | 579 | return 0; |
580 | } | ||
532 | 581 | ||
533 | tas->treble = ucontrol->value.integer.value[0]; | 582 | tas->treble = ucontrol->value.integer.value[0]; |
534 | if (tas->hw_enabled) | 583 | if (tas->hw_enabled) |
535 | tas_set_treble(tas); | 584 | tas_set_treble(tas); |
585 | mutex_unlock(&tas->mtx); | ||
536 | return 1; | 586 | return 1; |
537 | } | 587 | } |
538 | 588 | ||
@@ -560,7 +610,9 @@ static int tas_snd_bass_get(struct snd_kcontrol *kcontrol, | |||
560 | { | 610 | { |
561 | struct tas *tas = snd_kcontrol_chip(kcontrol); | 611 | struct tas *tas = snd_kcontrol_chip(kcontrol); |
562 | 612 | ||
613 | mutex_lock(&tas->mtx); | ||
563 | ucontrol->value.integer.value[0] = tas->bass; | 614 | ucontrol->value.integer.value[0] = tas->bass; |
615 | mutex_unlock(&tas->mtx); | ||
564 | return 0; | 616 | return 0; |
565 | } | 617 | } |
566 | 618 | ||
@@ -569,12 +621,16 @@ static int tas_snd_bass_put(struct snd_kcontrol *kcontrol, | |||
569 | { | 621 | { |
570 | struct tas *tas = snd_kcontrol_chip(kcontrol); | 622 | struct tas *tas = snd_kcontrol_chip(kcontrol); |
571 | 623 | ||
572 | if (tas->bass == ucontrol->value.integer.value[0]) | 624 | mutex_lock(&tas->mtx); |
625 | if (tas->bass == ucontrol->value.integer.value[0]) { | ||
626 | mutex_unlock(&tas->mtx); | ||
573 | return 0; | 627 | return 0; |
628 | } | ||
574 | 629 | ||
575 | tas->bass = ucontrol->value.integer.value[0]; | 630 | tas->bass = ucontrol->value.integer.value[0]; |
576 | if (tas->hw_enabled) | 631 | if (tas->hw_enabled) |
577 | tas_set_bass(tas); | 632 | tas_set_bass(tas); |
633 | mutex_unlock(&tas->mtx); | ||
578 | return 1; | 634 | return 1; |
579 | } | 635 | } |
580 | 636 | ||
@@ -628,16 +684,16 @@ static int tas_reset_init(struct tas *tas) | |||
628 | 684 | ||
629 | tmp = TAS_MCS_SCLK64 | TAS_MCS_SPORT_MODE_I2S | TAS_MCS_SPORT_WL_24BIT; | 685 | tmp = TAS_MCS_SCLK64 | TAS_MCS_SPORT_MODE_I2S | TAS_MCS_SPORT_WL_24BIT; |
630 | if (tas_write_reg(tas, TAS_REG_MCS, 1, &tmp)) | 686 | if (tas_write_reg(tas, TAS_REG_MCS, 1, &tmp)) |
631 | return -ENODEV; | 687 | goto outerr; |
632 | 688 | ||
633 | tas->acr |= TAS_ACR_ANALOG_PDOWN | TAS_ACR_B_MONAUREAL | | 689 | tas->acr |= TAS_ACR_ANALOG_PDOWN | TAS_ACR_B_MONAUREAL | |
634 | TAS_ACR_B_MON_SEL_RIGHT; | 690 | TAS_ACR_B_MON_SEL_RIGHT; |
635 | if (tas_write_reg(tas, TAS_REG_ACR, 1, &tas->acr)) | 691 | if (tas_write_reg(tas, TAS_REG_ACR, 1, &tas->acr)) |
636 | return -ENODEV; | 692 | goto outerr; |
637 | 693 | ||
638 | tmp = 0; | 694 | tmp = 0; |
639 | if (tas_write_reg(tas, TAS_REG_MCS2, 1, &tmp)) | 695 | if (tas_write_reg(tas, TAS_REG_MCS2, 1, &tmp)) |
640 | return -ENODEV; | 696 | goto outerr; |
641 | 697 | ||
642 | tas3004_set_drc(tas); | 698 | tas3004_set_drc(tas); |
643 | 699 | ||
@@ -649,9 +705,11 @@ static int tas_reset_init(struct tas *tas) | |||
649 | 705 | ||
650 | tas->acr &= ~TAS_ACR_ANALOG_PDOWN; | 706 | tas->acr &= ~TAS_ACR_ANALOG_PDOWN; |
651 | if (tas_write_reg(tas, TAS_REG_ACR, 1, &tas->acr)) | 707 | if (tas_write_reg(tas, TAS_REG_ACR, 1, &tas->acr)) |
652 | return -ENODEV; | 708 | goto outerr; |
653 | 709 | ||
654 | return 0; | 710 | return 0; |
711 | outerr: | ||
712 | return -ENODEV; | ||
655 | } | 713 | } |
656 | 714 | ||
657 | static int tas_switch_clock(struct codec_info_item *cii, enum clock_switch clock) | 715 | static int tas_switch_clock(struct codec_info_item *cii, enum clock_switch clock) |
@@ -666,11 +724,13 @@ static int tas_switch_clock(struct codec_info_item *cii, enum clock_switch clock | |||
666 | break; | 724 | break; |
667 | case CLOCK_SWITCH_SLAVE: | 725 | case CLOCK_SWITCH_SLAVE: |
668 | /* Clocks are back, re-init the codec */ | 726 | /* Clocks are back, re-init the codec */ |
727 | mutex_lock(&tas->mtx); | ||
669 | tas_reset_init(tas); | 728 | tas_reset_init(tas); |
670 | tas_set_volume(tas); | 729 | tas_set_volume(tas); |
671 | tas_set_mixer(tas); | 730 | tas_set_mixer(tas); |
672 | tas->hw_enabled = 1; | 731 | tas->hw_enabled = 1; |
673 | tas->codec.gpio->methods->all_amps_restore(tas->codec.gpio); | 732 | tas->codec.gpio->methods->all_amps_restore(tas->codec.gpio); |
733 | mutex_unlock(&tas->mtx); | ||
674 | break; | 734 | break; |
675 | default: | 735 | default: |
676 | /* doesn't happen as of now */ | 736 | /* doesn't happen as of now */ |
@@ -684,19 +744,23 @@ static int tas_switch_clock(struct codec_info_item *cii, enum clock_switch clock | |||
684 | * our i2c device is suspended, and then take note of that! */ | 744 | * our i2c device is suspended, and then take note of that! */ |
685 | static int tas_suspend(struct tas *tas) | 745 | static int tas_suspend(struct tas *tas) |
686 | { | 746 | { |
747 | mutex_lock(&tas->mtx); | ||
687 | tas->hw_enabled = 0; | 748 | tas->hw_enabled = 0; |
688 | tas->acr |= TAS_ACR_ANALOG_PDOWN; | 749 | tas->acr |= TAS_ACR_ANALOG_PDOWN; |
689 | tas_write_reg(tas, TAS_REG_ACR, 1, &tas->acr); | 750 | tas_write_reg(tas, TAS_REG_ACR, 1, &tas->acr); |
751 | mutex_unlock(&tas->mtx); | ||
690 | return 0; | 752 | return 0; |
691 | } | 753 | } |
692 | 754 | ||
693 | static int tas_resume(struct tas *tas) | 755 | static int tas_resume(struct tas *tas) |
694 | { | 756 | { |
695 | /* reset codec */ | 757 | /* reset codec */ |
758 | mutex_lock(&tas->mtx); | ||
696 | tas_reset_init(tas); | 759 | tas_reset_init(tas); |
697 | tas_set_volume(tas); | 760 | tas_set_volume(tas); |
698 | tas_set_mixer(tas); | 761 | tas_set_mixer(tas); |
699 | tas->hw_enabled = 1; | 762 | tas->hw_enabled = 1; |
763 | mutex_unlock(&tas->mtx); | ||
700 | return 0; | 764 | return 0; |
701 | } | 765 | } |
702 | 766 | ||
@@ -739,11 +803,14 @@ static int tas_init_codec(struct aoa_codec *codec) | |||
739 | return -EINVAL; | 803 | return -EINVAL; |
740 | } | 804 | } |
741 | 805 | ||
806 | mutex_lock(&tas->mtx); | ||
742 | if (tas_reset_init(tas)) { | 807 | if (tas_reset_init(tas)) { |
743 | printk(KERN_ERR PFX "tas failed to initialise\n"); | 808 | printk(KERN_ERR PFX "tas failed to initialise\n"); |
809 | mutex_unlock(&tas->mtx); | ||
744 | return -ENXIO; | 810 | return -ENXIO; |
745 | } | 811 | } |
746 | tas->hw_enabled = 1; | 812 | tas->hw_enabled = 1; |
813 | mutex_unlock(&tas->mtx); | ||
747 | 814 | ||
748 | if (tas->codec.soundbus_dev->attach_codec(tas->codec.soundbus_dev, | 815 | if (tas->codec.soundbus_dev->attach_codec(tas->codec.soundbus_dev, |
749 | aoa_get_card(), | 816 | aoa_get_card(), |
@@ -822,6 +889,7 @@ static int tas_create(struct i2c_adapter *adapter, | |||
822 | if (!tas) | 889 | if (!tas) |
823 | return -ENOMEM; | 890 | return -ENOMEM; |
824 | 891 | ||
892 | mutex_init(&tas->mtx); | ||
825 | tas->i2c.driver = &tas_driver; | 893 | tas->i2c.driver = &tas_driver; |
826 | tas->i2c.adapter = adapter; | 894 | tas->i2c.adapter = adapter; |
827 | tas->i2c.addr = addr; | 895 | tas->i2c.addr = addr; |
@@ -850,6 +918,7 @@ static int tas_create(struct i2c_adapter *adapter, | |||
850 | detach: | 918 | detach: |
851 | i2c_detach_client(&tas->i2c); | 919 | i2c_detach_client(&tas->i2c); |
852 | fail: | 920 | fail: |
921 | mutex_destroy(&tas->mtx); | ||
853 | kfree(tas); | 922 | kfree(tas); |
854 | return -EINVAL; | 923 | return -EINVAL; |
855 | } | 924 | } |
@@ -908,6 +977,7 @@ static int tas_i2c_detach(struct i2c_client *client) | |||
908 | /* power down codec chip */ | 977 | /* power down codec chip */ |
909 | tas_write_reg(tas, TAS_REG_ACR, 1, &tmp); | 978 | tas_write_reg(tas, TAS_REG_ACR, 1, &tmp); |
910 | 979 | ||
980 | mutex_destroy(&tas->mtx); | ||
911 | kfree(tas); | 981 | kfree(tas); |
912 | return 0; | 982 | return 0; |
913 | } | 983 | } |
diff --git a/sound/core/control.c b/sound/core/control.c index bb397eaa7187..6973a9686b67 100644 --- a/sound/core/control.c +++ b/sound/core/control.c | |||
@@ -75,6 +75,8 @@ static int snd_ctl_open(struct inode *inode, struct file *file) | |||
75 | init_waitqueue_head(&ctl->change_sleep); | 75 | init_waitqueue_head(&ctl->change_sleep); |
76 | spin_lock_init(&ctl->read_lock); | 76 | spin_lock_init(&ctl->read_lock); |
77 | ctl->card = card; | 77 | ctl->card = card; |
78 | ctl->prefer_pcm_subdevice = -1; | ||
79 | ctl->prefer_rawmidi_subdevice = -1; | ||
78 | ctl->pid = current->pid; | 80 | ctl->pid = current->pid; |
79 | file->private_data = ctl; | 81 | file->private_data = ctl; |
80 | write_lock_irqsave(&card->ctl_files_rwlock, flags); | 82 | write_lock_irqsave(&card->ctl_files_rwlock, flags); |
@@ -236,11 +238,16 @@ struct snd_kcontrol *snd_ctl_new1(const struct snd_kcontrol_new *ncontrol, | |||
236 | kctl.id.index = ncontrol->index; | 238 | kctl.id.index = ncontrol->index; |
237 | kctl.count = ncontrol->count ? ncontrol->count : 1; | 239 | kctl.count = ncontrol->count ? ncontrol->count : 1; |
238 | access = ncontrol->access == 0 ? SNDRV_CTL_ELEM_ACCESS_READWRITE : | 240 | access = ncontrol->access == 0 ? SNDRV_CTL_ELEM_ACCESS_READWRITE : |
239 | (ncontrol->access & (SNDRV_CTL_ELEM_ACCESS_READWRITE|SNDRV_CTL_ELEM_ACCESS_INACTIVE| | 241 | (ncontrol->access & (SNDRV_CTL_ELEM_ACCESS_READWRITE| |
240 | SNDRV_CTL_ELEM_ACCESS_DINDIRECT|SNDRV_CTL_ELEM_ACCESS_INDIRECT)); | 242 | SNDRV_CTL_ELEM_ACCESS_INACTIVE| |
243 | SNDRV_CTL_ELEM_ACCESS_DINDIRECT| | ||
244 | SNDRV_CTL_ELEM_ACCESS_INDIRECT| | ||
245 | SNDRV_CTL_ELEM_ACCESS_TLV_READWRITE| | ||
246 | SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK)); | ||
241 | kctl.info = ncontrol->info; | 247 | kctl.info = ncontrol->info; |
242 | kctl.get = ncontrol->get; | 248 | kctl.get = ncontrol->get; |
243 | kctl.put = ncontrol->put; | 249 | kctl.put = ncontrol->put; |
250 | kctl.tlv.p = ncontrol->tlv.p; | ||
244 | kctl.private_value = ncontrol->private_value; | 251 | kctl.private_value = ncontrol->private_value; |
245 | kctl.private_data = private_data; | 252 | kctl.private_data = private_data; |
246 | return snd_ctl_new(&kctl, access); | 253 | return snd_ctl_new(&kctl, access); |
@@ -882,6 +889,8 @@ struct user_element { | |||
882 | struct snd_ctl_elem_info info; | 889 | struct snd_ctl_elem_info info; |
883 | void *elem_data; /* element data */ | 890 | void *elem_data; /* element data */ |
884 | unsigned long elem_data_size; /* size of element data in bytes */ | 891 | unsigned long elem_data_size; /* size of element data in bytes */ |
892 | void *tlv_data; /* TLV data */ | ||
893 | unsigned long tlv_data_size; /* TLV data size */ | ||
885 | void *priv_data; /* private data (like strings for enumerated type) */ | 894 | void *priv_data; /* private data (like strings for enumerated type) */ |
886 | unsigned long priv_data_size; /* size of private data in bytes */ | 895 | unsigned long priv_data_size; /* size of private data in bytes */ |
887 | }; | 896 | }; |
@@ -916,9 +925,48 @@ static int snd_ctl_elem_user_put(struct snd_kcontrol *kcontrol, | |||
916 | return change; | 925 | return change; |
917 | } | 926 | } |
918 | 927 | ||
928 | static int snd_ctl_elem_user_tlv(struct snd_kcontrol *kcontrol, | ||
929 | int op_flag, | ||
930 | unsigned int size, | ||
931 | unsigned int __user *tlv) | ||
932 | { | ||
933 | struct user_element *ue = kcontrol->private_data; | ||
934 | int change = 0; | ||
935 | void *new_data; | ||
936 | |||
937 | if (op_flag > 0) { | ||
938 | if (size > 1024 * 128) /* sane value */ | ||
939 | return -EINVAL; | ||
940 | new_data = kmalloc(size, GFP_KERNEL); | ||
941 | if (new_data == NULL) | ||
942 | return -ENOMEM; | ||
943 | if (copy_from_user(new_data, tlv, size)) { | ||
944 | kfree(new_data); | ||
945 | return -EFAULT; | ||
946 | } | ||
947 | change = ue->tlv_data_size != size; | ||
948 | if (!change) | ||
949 | change = memcmp(ue->tlv_data, new_data, size); | ||
950 | kfree(ue->tlv_data); | ||
951 | ue->tlv_data = new_data; | ||
952 | ue->tlv_data_size = size; | ||
953 | } else { | ||
954 | if (! ue->tlv_data_size || ! ue->tlv_data) | ||
955 | return -ENXIO; | ||
956 | if (size < ue->tlv_data_size) | ||
957 | return -ENOSPC; | ||
958 | if (copy_to_user(tlv, ue->tlv_data, ue->tlv_data_size)) | ||
959 | return -EFAULT; | ||
960 | } | ||
961 | return change; | ||
962 | } | ||
963 | |||
919 | static void snd_ctl_elem_user_free(struct snd_kcontrol *kcontrol) | 964 | static void snd_ctl_elem_user_free(struct snd_kcontrol *kcontrol) |
920 | { | 965 | { |
921 | kfree(kcontrol->private_data); | 966 | struct user_element *ue = kcontrol->private_data; |
967 | if (ue->tlv_data) | ||
968 | kfree(ue->tlv_data); | ||
969 | kfree(ue); | ||
922 | } | 970 | } |
923 | 971 | ||
924 | static int snd_ctl_elem_add(struct snd_ctl_file *file, | 972 | static int snd_ctl_elem_add(struct snd_ctl_file *file, |
@@ -937,7 +985,8 @@ static int snd_ctl_elem_add(struct snd_ctl_file *file, | |||
937 | return -EINVAL; | 985 | return -EINVAL; |
938 | access = info->access == 0 ? SNDRV_CTL_ELEM_ACCESS_READWRITE : | 986 | access = info->access == 0 ? SNDRV_CTL_ELEM_ACCESS_READWRITE : |
939 | (info->access & (SNDRV_CTL_ELEM_ACCESS_READWRITE| | 987 | (info->access & (SNDRV_CTL_ELEM_ACCESS_READWRITE| |
940 | SNDRV_CTL_ELEM_ACCESS_INACTIVE)); | 988 | SNDRV_CTL_ELEM_ACCESS_INACTIVE| |
989 | SNDRV_CTL_ELEM_ACCESS_TLV_READWRITE)); | ||
941 | info->id.numid = 0; | 990 | info->id.numid = 0; |
942 | memset(&kctl, 0, sizeof(kctl)); | 991 | memset(&kctl, 0, sizeof(kctl)); |
943 | down_write(&card->controls_rwsem); | 992 | down_write(&card->controls_rwsem); |
@@ -963,6 +1012,10 @@ static int snd_ctl_elem_add(struct snd_ctl_file *file, | |||
963 | kctl.get = snd_ctl_elem_user_get; | 1012 | kctl.get = snd_ctl_elem_user_get; |
964 | if (access & SNDRV_CTL_ELEM_ACCESS_WRITE) | 1013 | if (access & SNDRV_CTL_ELEM_ACCESS_WRITE) |
965 | kctl.put = snd_ctl_elem_user_put; | 1014 | kctl.put = snd_ctl_elem_user_put; |
1015 | if (access & SNDRV_CTL_ELEM_ACCESS_TLV_READWRITE) { | ||
1016 | kctl.tlv.c = snd_ctl_elem_user_tlv; | ||
1017 | access |= SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK; | ||
1018 | } | ||
966 | switch (info->type) { | 1019 | switch (info->type) { |
967 | case SNDRV_CTL_ELEM_TYPE_BOOLEAN: | 1020 | case SNDRV_CTL_ELEM_TYPE_BOOLEAN: |
968 | private_size = sizeof(char); | 1021 | private_size = sizeof(char); |
@@ -997,6 +1050,7 @@ static int snd_ctl_elem_add(struct snd_ctl_file *file, | |||
997 | if (ue == NULL) | 1050 | if (ue == NULL) |
998 | return -ENOMEM; | 1051 | return -ENOMEM; |
999 | ue->info = *info; | 1052 | ue->info = *info; |
1053 | ue->info.access = 0; | ||
1000 | ue->elem_data = (char *)ue + sizeof(*ue); | 1054 | ue->elem_data = (char *)ue + sizeof(*ue); |
1001 | ue->elem_data_size = private_size; | 1055 | ue->elem_data_size = private_size; |
1002 | kctl.private_free = snd_ctl_elem_user_free; | 1056 | kctl.private_free = snd_ctl_elem_user_free; |
@@ -1067,6 +1121,67 @@ static int snd_ctl_subscribe_events(struct snd_ctl_file *file, int __user *ptr) | |||
1067 | return 0; | 1121 | return 0; |
1068 | } | 1122 | } |
1069 | 1123 | ||
1124 | static int snd_ctl_tlv_ioctl(struct snd_ctl_file *file, | ||
1125 | struct snd_ctl_tlv __user *_tlv, | ||
1126 | int op_flag) | ||
1127 | { | ||
1128 | struct snd_card *card = file->card; | ||
1129 | struct snd_ctl_tlv tlv; | ||
1130 | struct snd_kcontrol *kctl; | ||
1131 | struct snd_kcontrol_volatile *vd; | ||
1132 | unsigned int len; | ||
1133 | int err = 0; | ||
1134 | |||
1135 | if (copy_from_user(&tlv, _tlv, sizeof(tlv))) | ||
1136 | return -EFAULT; | ||
1137 | if (tlv.length < sizeof(unsigned int) * 3) | ||
1138 | return -EINVAL; | ||
1139 | down_read(&card->controls_rwsem); | ||
1140 | kctl = snd_ctl_find_numid(card, tlv.numid); | ||
1141 | if (kctl == NULL) { | ||
1142 | err = -ENOENT; | ||
1143 | goto __kctl_end; | ||
1144 | } | ||
1145 | if (kctl->tlv.p == NULL) { | ||
1146 | err = -ENXIO; | ||
1147 | goto __kctl_end; | ||
1148 | } | ||
1149 | vd = &kctl->vd[tlv.numid - kctl->id.numid]; | ||
1150 | if ((op_flag == 0 && (vd->access & SNDRV_CTL_ELEM_ACCESS_TLV_READ) == 0) || | ||
1151 | (op_flag > 0 && (vd->access & SNDRV_CTL_ELEM_ACCESS_TLV_WRITE) == 0) || | ||
1152 | (op_flag < 0 && (vd->access & SNDRV_CTL_ELEM_ACCESS_TLV_COMMAND) == 0)) { | ||
1153 | err = -ENXIO; | ||
1154 | goto __kctl_end; | ||
1155 | } | ||
1156 | if (vd->access & SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK) { | ||
1157 | if (file && vd->owner != NULL && vd->owner != file) { | ||
1158 | err = -EPERM; | ||
1159 | goto __kctl_end; | ||
1160 | } | ||
1161 | err = kctl->tlv.c(kctl, op_flag, tlv.length, _tlv->tlv); | ||
1162 | if (err > 0) { | ||
1163 | up_read(&card->controls_rwsem); | ||
1164 | snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_TLV, &kctl->id); | ||
1165 | return 0; | ||
1166 | } | ||
1167 | } else { | ||
1168 | if (op_flag) { | ||
1169 | err = -ENXIO; | ||
1170 | goto __kctl_end; | ||
1171 | } | ||
1172 | len = kctl->tlv.p[1] + 2 * sizeof(unsigned int); | ||
1173 | if (tlv.length < len) { | ||
1174 | err = -ENOMEM; | ||
1175 | goto __kctl_end; | ||
1176 | } | ||
1177 | if (copy_to_user(_tlv->tlv, kctl->tlv.p, len)) | ||
1178 | err = -EFAULT; | ||
1179 | } | ||
1180 | __kctl_end: | ||
1181 | up_read(&card->controls_rwsem); | ||
1182 | return err; | ||
1183 | } | ||
1184 | |||
1070 | static long snd_ctl_ioctl(struct file *file, unsigned int cmd, unsigned long arg) | 1185 | static long snd_ctl_ioctl(struct file *file, unsigned int cmd, unsigned long arg) |
1071 | { | 1186 | { |
1072 | struct snd_ctl_file *ctl; | 1187 | struct snd_ctl_file *ctl; |
@@ -1086,11 +1201,11 @@ static long snd_ctl_ioctl(struct file *file, unsigned int cmd, unsigned long arg | |||
1086 | case SNDRV_CTL_IOCTL_CARD_INFO: | 1201 | case SNDRV_CTL_IOCTL_CARD_INFO: |
1087 | return snd_ctl_card_info(card, ctl, cmd, argp); | 1202 | return snd_ctl_card_info(card, ctl, cmd, argp); |
1088 | case SNDRV_CTL_IOCTL_ELEM_LIST: | 1203 | case SNDRV_CTL_IOCTL_ELEM_LIST: |
1089 | return snd_ctl_elem_list(ctl->card, argp); | 1204 | return snd_ctl_elem_list(card, argp); |
1090 | case SNDRV_CTL_IOCTL_ELEM_INFO: | 1205 | case SNDRV_CTL_IOCTL_ELEM_INFO: |
1091 | return snd_ctl_elem_info_user(ctl, argp); | 1206 | return snd_ctl_elem_info_user(ctl, argp); |
1092 | case SNDRV_CTL_IOCTL_ELEM_READ: | 1207 | case SNDRV_CTL_IOCTL_ELEM_READ: |
1093 | return snd_ctl_elem_read_user(ctl->card, argp); | 1208 | return snd_ctl_elem_read_user(card, argp); |
1094 | case SNDRV_CTL_IOCTL_ELEM_WRITE: | 1209 | case SNDRV_CTL_IOCTL_ELEM_WRITE: |
1095 | return snd_ctl_elem_write_user(ctl, argp); | 1210 | return snd_ctl_elem_write_user(ctl, argp); |
1096 | case SNDRV_CTL_IOCTL_ELEM_LOCK: | 1211 | case SNDRV_CTL_IOCTL_ELEM_LOCK: |
@@ -1105,6 +1220,12 @@ static long snd_ctl_ioctl(struct file *file, unsigned int cmd, unsigned long arg | |||
1105 | return snd_ctl_elem_remove(ctl, argp); | 1220 | return snd_ctl_elem_remove(ctl, argp); |
1106 | case SNDRV_CTL_IOCTL_SUBSCRIBE_EVENTS: | 1221 | case SNDRV_CTL_IOCTL_SUBSCRIBE_EVENTS: |
1107 | return snd_ctl_subscribe_events(ctl, ip); | 1222 | return snd_ctl_subscribe_events(ctl, ip); |
1223 | case SNDRV_CTL_IOCTL_TLV_READ: | ||
1224 | return snd_ctl_tlv_ioctl(ctl, argp, 0); | ||
1225 | case SNDRV_CTL_IOCTL_TLV_WRITE: | ||
1226 | return snd_ctl_tlv_ioctl(ctl, argp, 1); | ||
1227 | case SNDRV_CTL_IOCTL_TLV_COMMAND: | ||
1228 | return snd_ctl_tlv_ioctl(ctl, argp, -1); | ||
1108 | case SNDRV_CTL_IOCTL_POWER: | 1229 | case SNDRV_CTL_IOCTL_POWER: |
1109 | return -ENOPROTOOPT; | 1230 | return -ENOPROTOOPT; |
1110 | case SNDRV_CTL_IOCTL_POWER_STATE: | 1231 | case SNDRV_CTL_IOCTL_POWER_STATE: |
@@ -1338,6 +1459,11 @@ static int snd_ctl_dev_disconnect(struct snd_device *device) | |||
1338 | struct snd_card *card = device->device_data; | 1459 | struct snd_card *card = device->device_data; |
1339 | struct list_head *flist; | 1460 | struct list_head *flist; |
1340 | struct snd_ctl_file *ctl; | 1461 | struct snd_ctl_file *ctl; |
1462 | int err, cardnum; | ||
1463 | |||
1464 | snd_assert(card != NULL, return -ENXIO); | ||
1465 | cardnum = card->number; | ||
1466 | snd_assert(cardnum >= 0 && cardnum < SNDRV_CARDS, return -ENXIO); | ||
1341 | 1467 | ||
1342 | down_read(&card->controls_rwsem); | 1468 | down_read(&card->controls_rwsem); |
1343 | list_for_each(flist, &card->ctl_files) { | 1469 | list_for_each(flist, &card->ctl_files) { |
@@ -1346,6 +1472,10 @@ static int snd_ctl_dev_disconnect(struct snd_device *device) | |||
1346 | kill_fasync(&ctl->fasync, SIGIO, POLL_ERR); | 1472 | kill_fasync(&ctl->fasync, SIGIO, POLL_ERR); |
1347 | } | 1473 | } |
1348 | up_read(&card->controls_rwsem); | 1474 | up_read(&card->controls_rwsem); |
1475 | |||
1476 | if ((err = snd_unregister_device(SNDRV_DEVICE_TYPE_CONTROL, | ||
1477 | card, -1)) < 0) | ||
1478 | return err; | ||
1349 | return 0; | 1479 | return 0; |
1350 | } | 1480 | } |
1351 | 1481 | ||
@@ -1367,23 +1497,6 @@ static int snd_ctl_dev_free(struct snd_device *device) | |||
1367 | } | 1497 | } |
1368 | 1498 | ||
1369 | /* | 1499 | /* |
1370 | * de-registration of the control device | ||
1371 | */ | ||
1372 | static int snd_ctl_dev_unregister(struct snd_device *device) | ||
1373 | { | ||
1374 | struct snd_card *card = device->device_data; | ||
1375 | int err, cardnum; | ||
1376 | |||
1377 | snd_assert(card != NULL, return -ENXIO); | ||
1378 | cardnum = card->number; | ||
1379 | snd_assert(cardnum >= 0 && cardnum < SNDRV_CARDS, return -ENXIO); | ||
1380 | if ((err = snd_unregister_device(SNDRV_DEVICE_TYPE_CONTROL, | ||
1381 | card, -1)) < 0) | ||
1382 | return err; | ||
1383 | return snd_ctl_dev_free(device); | ||
1384 | } | ||
1385 | |||
1386 | /* | ||
1387 | * create control core: | 1500 | * create control core: |
1388 | * called from init.c | 1501 | * called from init.c |
1389 | */ | 1502 | */ |
@@ -1393,7 +1506,6 @@ int snd_ctl_create(struct snd_card *card) | |||
1393 | .dev_free = snd_ctl_dev_free, | 1506 | .dev_free = snd_ctl_dev_free, |
1394 | .dev_register = snd_ctl_dev_register, | 1507 | .dev_register = snd_ctl_dev_register, |
1395 | .dev_disconnect = snd_ctl_dev_disconnect, | 1508 | .dev_disconnect = snd_ctl_dev_disconnect, |
1396 | .dev_unregister = snd_ctl_dev_unregister | ||
1397 | }; | 1509 | }; |
1398 | 1510 | ||
1399 | snd_assert(card != NULL, return -ENXIO); | 1511 | snd_assert(card != NULL, return -ENXIO); |
diff --git a/sound/core/control_compat.c b/sound/core/control_compat.c index 3c0161bb5ba4..ab48962c48ce 100644 --- a/sound/core/control_compat.c +++ b/sound/core/control_compat.c | |||
@@ -407,6 +407,10 @@ static inline long snd_ctl_ioctl_compat(struct file *file, unsigned int cmd, uns | |||
407 | case SNDRV_CTL_IOCTL_POWER_STATE: | 407 | case SNDRV_CTL_IOCTL_POWER_STATE: |
408 | case SNDRV_CTL_IOCTL_ELEM_LOCK: | 408 | case SNDRV_CTL_IOCTL_ELEM_LOCK: |
409 | case SNDRV_CTL_IOCTL_ELEM_UNLOCK: | 409 | case SNDRV_CTL_IOCTL_ELEM_UNLOCK: |
410 | case SNDRV_CTL_IOCTL_ELEM_REMOVE: | ||
411 | case SNDRV_CTL_IOCTL_TLV_READ: | ||
412 | case SNDRV_CTL_IOCTL_TLV_WRITE: | ||
413 | case SNDRV_CTL_IOCTL_TLV_COMMAND: | ||
410 | return snd_ctl_ioctl(file, cmd, (unsigned long)argp); | 414 | return snd_ctl_ioctl(file, cmd, (unsigned long)argp); |
411 | case SNDRV_CTL_IOCTL_ELEM_LIST32: | 415 | case SNDRV_CTL_IOCTL_ELEM_LIST32: |
412 | return snd_ctl_elem_list_compat(ctl->card, argp); | 416 | return snd_ctl_elem_list_compat(ctl->card, argp); |
diff --git a/sound/core/device.c b/sound/core/device.c index 6ce4da4a1081..ccb25816ac9e 100644 --- a/sound/core/device.c +++ b/sound/core/device.c | |||
@@ -71,7 +71,7 @@ EXPORT_SYMBOL(snd_device_new); | |||
71 | * @device_data: the data pointer to release | 71 | * @device_data: the data pointer to release |
72 | * | 72 | * |
73 | * Removes the device from the list on the card and invokes the | 73 | * Removes the device from the list on the card and invokes the |
74 | * callback, dev_unregister or dev_free, corresponding to the state. | 74 | * callbacks, dev_disconnect and dev_free, corresponding to the state. |
75 | * Then release the device. | 75 | * Then release the device. |
76 | * | 76 | * |
77 | * Returns zero if successful, or a negative error code on failure or if the | 77 | * Returns zero if successful, or a negative error code on failure or if the |
@@ -90,16 +90,14 @@ int snd_device_free(struct snd_card *card, void *device_data) | |||
90 | continue; | 90 | continue; |
91 | /* unlink */ | 91 | /* unlink */ |
92 | list_del(&dev->list); | 92 | list_del(&dev->list); |
93 | if ((dev->state == SNDRV_DEV_REGISTERED || | 93 | if (dev->state == SNDRV_DEV_REGISTERED && |
94 | dev->state == SNDRV_DEV_DISCONNECTED) && | 94 | dev->ops->dev_disconnect) |
95 | dev->ops->dev_unregister) { | 95 | if (dev->ops->dev_disconnect(dev)) |
96 | if (dev->ops->dev_unregister(dev)) | 96 | snd_printk(KERN_ERR |
97 | snd_printk(KERN_ERR "device unregister failure\n"); | 97 | "device disconnect failure\n"); |
98 | } else { | 98 | if (dev->ops->dev_free) { |
99 | if (dev->ops->dev_free) { | 99 | if (dev->ops->dev_free(dev)) |
100 | if (dev->ops->dev_free(dev)) | 100 | snd_printk(KERN_ERR "device free failure\n"); |
101 | snd_printk(KERN_ERR "device free failure\n"); | ||
102 | } | ||
103 | } | 101 | } |
104 | kfree(dev); | 102 | kfree(dev); |
105 | return 0; | 103 | return 0; |
diff --git a/sound/core/hwdep.c b/sound/core/hwdep.c index 8bd0dcc93eba..9aa9d94891f0 100644 --- a/sound/core/hwdep.c +++ b/sound/core/hwdep.c | |||
@@ -42,7 +42,7 @@ static DEFINE_MUTEX(register_mutex); | |||
42 | static int snd_hwdep_free(struct snd_hwdep *hwdep); | 42 | static int snd_hwdep_free(struct snd_hwdep *hwdep); |
43 | static int snd_hwdep_dev_free(struct snd_device *device); | 43 | static int snd_hwdep_dev_free(struct snd_device *device); |
44 | static int snd_hwdep_dev_register(struct snd_device *device); | 44 | static int snd_hwdep_dev_register(struct snd_device *device); |
45 | static int snd_hwdep_dev_unregister(struct snd_device *device); | 45 | static int snd_hwdep_dev_disconnect(struct snd_device *device); |
46 | 46 | ||
47 | 47 | ||
48 | static struct snd_hwdep *snd_hwdep_search(struct snd_card *card, int device) | 48 | static struct snd_hwdep *snd_hwdep_search(struct snd_card *card, int device) |
@@ -353,7 +353,7 @@ int snd_hwdep_new(struct snd_card *card, char *id, int device, | |||
353 | static struct snd_device_ops ops = { | 353 | static struct snd_device_ops ops = { |
354 | .dev_free = snd_hwdep_dev_free, | 354 | .dev_free = snd_hwdep_dev_free, |
355 | .dev_register = snd_hwdep_dev_register, | 355 | .dev_register = snd_hwdep_dev_register, |
356 | .dev_unregister = snd_hwdep_dev_unregister | 356 | .dev_disconnect = snd_hwdep_dev_disconnect, |
357 | }; | 357 | }; |
358 | 358 | ||
359 | snd_assert(rhwdep != NULL, return -EINVAL); | 359 | snd_assert(rhwdep != NULL, return -EINVAL); |
@@ -439,7 +439,7 @@ static int snd_hwdep_dev_register(struct snd_device *device) | |||
439 | return 0; | 439 | return 0; |
440 | } | 440 | } |
441 | 441 | ||
442 | static int snd_hwdep_dev_unregister(struct snd_device *device) | 442 | static int snd_hwdep_dev_disconnect(struct snd_device *device) |
443 | { | 443 | { |
444 | struct snd_hwdep *hwdep = device->device_data; | 444 | struct snd_hwdep *hwdep = device->device_data; |
445 | 445 | ||
@@ -454,9 +454,9 @@ static int snd_hwdep_dev_unregister(struct snd_device *device) | |||
454 | snd_unregister_oss_device(hwdep->oss_type, hwdep->card, hwdep->device); | 454 | snd_unregister_oss_device(hwdep->oss_type, hwdep->card, hwdep->device); |
455 | #endif | 455 | #endif |
456 | snd_unregister_device(SNDRV_DEVICE_TYPE_HWDEP, hwdep->card, hwdep->device); | 456 | snd_unregister_device(SNDRV_DEVICE_TYPE_HWDEP, hwdep->card, hwdep->device); |
457 | list_del(&hwdep->list); | 457 | list_del_init(&hwdep->list); |
458 | mutex_unlock(®ister_mutex); | 458 | mutex_unlock(®ister_mutex); |
459 | return snd_hwdep_free(hwdep); | 459 | return 0; |
460 | } | 460 | } |
461 | 461 | ||
462 | #ifdef CONFIG_PROC_FS | 462 | #ifdef CONFIG_PROC_FS |
@@ -497,7 +497,7 @@ static void __init snd_hwdep_proc_init(void) | |||
497 | 497 | ||
498 | static void __exit snd_hwdep_proc_done(void) | 498 | static void __exit snd_hwdep_proc_done(void) |
499 | { | 499 | { |
500 | snd_info_unregister(snd_hwdep_proc_entry); | 500 | snd_info_free_entry(snd_hwdep_proc_entry); |
501 | } | 501 | } |
502 | #else /* !CONFIG_PROC_FS */ | 502 | #else /* !CONFIG_PROC_FS */ |
503 | #define snd_hwdep_proc_init() | 503 | #define snd_hwdep_proc_init() |
diff --git a/sound/core/info.c b/sound/core/info.c index 340332c6d973..e43662b33f16 100644 --- a/sound/core/info.c +++ b/sound/core/info.c | |||
@@ -78,6 +78,7 @@ struct snd_info_private_data { | |||
78 | 78 | ||
79 | static int snd_info_version_init(void); | 79 | static int snd_info_version_init(void); |
80 | static int snd_info_version_done(void); | 80 | static int snd_info_version_done(void); |
81 | static void snd_info_disconnect(struct snd_info_entry *entry); | ||
81 | 82 | ||
82 | 83 | ||
83 | /* resize the proc r/w buffer */ | 84 | /* resize the proc r/w buffer */ |
@@ -174,15 +175,15 @@ static loff_t snd_info_entry_llseek(struct file *file, loff_t offset, int orig) | |||
174 | switch (entry->content) { | 175 | switch (entry->content) { |
175 | case SNDRV_INFO_CONTENT_TEXT: | 176 | case SNDRV_INFO_CONTENT_TEXT: |
176 | switch (orig) { | 177 | switch (orig) { |
177 | case 0: /* SEEK_SET */ | 178 | case SEEK_SET: |
178 | file->f_pos = offset; | 179 | file->f_pos = offset; |
179 | ret = file->f_pos; | 180 | ret = file->f_pos; |
180 | goto out; | 181 | goto out; |
181 | case 1: /* SEEK_CUR */ | 182 | case SEEK_CUR: |
182 | file->f_pos += offset; | 183 | file->f_pos += offset; |
183 | ret = file->f_pos; | 184 | ret = file->f_pos; |
184 | goto out; | 185 | goto out; |
185 | case 2: /* SEEK_END */ | 186 | case SEEK_END: |
186 | default: | 187 | default: |
187 | ret = -EINVAL; | 188 | ret = -EINVAL; |
188 | goto out; | 189 | goto out; |
@@ -304,7 +305,7 @@ static int snd_info_entry_open(struct inode *inode, struct file *file) | |||
304 | mutex_lock(&info_mutex); | 305 | mutex_lock(&info_mutex); |
305 | p = PDE(inode); | 306 | p = PDE(inode); |
306 | entry = p == NULL ? NULL : (struct snd_info_entry *)p->data; | 307 | entry = p == NULL ? NULL : (struct snd_info_entry *)p->data; |
307 | if (entry == NULL || entry->disconnected) { | 308 | if (entry == NULL || ! entry->p) { |
308 | mutex_unlock(&info_mutex); | 309 | mutex_unlock(&info_mutex); |
309 | return -ENODEV; | 310 | return -ENODEV; |
310 | } | 311 | } |
@@ -586,10 +587,10 @@ int __exit snd_info_done(void) | |||
586 | snd_info_version_done(); | 587 | snd_info_version_done(); |
587 | if (snd_proc_root) { | 588 | if (snd_proc_root) { |
588 | #if defined(CONFIG_SND_SEQUENCER) || defined(CONFIG_SND_SEQUENCER_MODULE) | 589 | #if defined(CONFIG_SND_SEQUENCER) || defined(CONFIG_SND_SEQUENCER_MODULE) |
589 | snd_info_unregister(snd_seq_root); | 590 | snd_info_free_entry(snd_seq_root); |
590 | #endif | 591 | #endif |
591 | #ifdef CONFIG_SND_OSSEMUL | 592 | #ifdef CONFIG_SND_OSSEMUL |
592 | snd_info_unregister(snd_oss_root); | 593 | snd_info_free_entry(snd_oss_root); |
593 | #endif | 594 | #endif |
594 | snd_remove_proc_entry(&proc_root, snd_proc_root); | 595 | snd_remove_proc_entry(&proc_root, snd_proc_root); |
595 | } | 596 | } |
@@ -648,17 +649,28 @@ int snd_info_card_register(struct snd_card *card) | |||
648 | * de-register the card proc file | 649 | * de-register the card proc file |
649 | * called from init.c | 650 | * called from init.c |
650 | */ | 651 | */ |
651 | int snd_info_card_free(struct snd_card *card) | 652 | void snd_info_card_disconnect(struct snd_card *card) |
652 | { | 653 | { |
653 | snd_assert(card != NULL, return -ENXIO); | 654 | snd_assert(card != NULL, return); |
655 | mutex_lock(&info_mutex); | ||
654 | if (card->proc_root_link) { | 656 | if (card->proc_root_link) { |
655 | snd_remove_proc_entry(snd_proc_root, card->proc_root_link); | 657 | snd_remove_proc_entry(snd_proc_root, card->proc_root_link); |
656 | card->proc_root_link = NULL; | 658 | card->proc_root_link = NULL; |
657 | } | 659 | } |
658 | if (card->proc_root) { | 660 | if (card->proc_root) |
659 | snd_info_unregister(card->proc_root); | 661 | snd_info_disconnect(card->proc_root); |
660 | card->proc_root = NULL; | 662 | mutex_unlock(&info_mutex); |
661 | } | 663 | } |
664 | |||
665 | /* | ||
666 | * release the card proc file resources | ||
667 | * called from init.c | ||
668 | */ | ||
669 | int snd_info_card_free(struct snd_card *card) | ||
670 | { | ||
671 | snd_assert(card != NULL, return -ENXIO); | ||
672 | snd_info_free_entry(card->proc_root); | ||
673 | card->proc_root = NULL; | ||
662 | return 0; | 674 | return 0; |
663 | } | 675 | } |
664 | 676 | ||
@@ -767,6 +779,8 @@ static struct snd_info_entry *snd_info_create_entry(const char *name) | |||
767 | entry->mode = S_IFREG | S_IRUGO; | 779 | entry->mode = S_IFREG | S_IRUGO; |
768 | entry->content = SNDRV_INFO_CONTENT_TEXT; | 780 | entry->content = SNDRV_INFO_CONTENT_TEXT; |
769 | mutex_init(&entry->access); | 781 | mutex_init(&entry->access); |
782 | INIT_LIST_HEAD(&entry->children); | ||
783 | INIT_LIST_HEAD(&entry->list); | ||
770 | return entry; | 784 | return entry; |
771 | } | 785 | } |
772 | 786 | ||
@@ -819,30 +833,35 @@ struct snd_info_entry *snd_info_create_card_entry(struct snd_card *card, | |||
819 | 833 | ||
820 | EXPORT_SYMBOL(snd_info_create_card_entry); | 834 | EXPORT_SYMBOL(snd_info_create_card_entry); |
821 | 835 | ||
822 | static int snd_info_dev_free_entry(struct snd_device *device) | 836 | static void snd_info_disconnect(struct snd_info_entry *entry) |
823 | { | 837 | { |
824 | struct snd_info_entry *entry = device->device_data; | 838 | struct list_head *p, *n; |
825 | snd_info_free_entry(entry); | 839 | struct proc_dir_entry *root; |
826 | return 0; | ||
827 | } | ||
828 | 840 | ||
829 | static int snd_info_dev_register_entry(struct snd_device *device) | 841 | list_for_each_safe(p, n, &entry->children) { |
830 | { | 842 | snd_info_disconnect(list_entry(p, struct snd_info_entry, list)); |
831 | struct snd_info_entry *entry = device->device_data; | 843 | } |
832 | return snd_info_register(entry); | 844 | |
845 | if (! entry->p) | ||
846 | return; | ||
847 | list_del_init(&entry->list); | ||
848 | root = entry->parent == NULL ? snd_proc_root : entry->parent->p; | ||
849 | snd_assert(root, return); | ||
850 | snd_remove_proc_entry(root, entry->p); | ||
851 | entry->p = NULL; | ||
833 | } | 852 | } |
834 | 853 | ||
835 | static int snd_info_dev_disconnect_entry(struct snd_device *device) | 854 | static int snd_info_dev_free_entry(struct snd_device *device) |
836 | { | 855 | { |
837 | struct snd_info_entry *entry = device->device_data; | 856 | struct snd_info_entry *entry = device->device_data; |
838 | entry->disconnected = 1; | 857 | snd_info_free_entry(entry); |
839 | return 0; | 858 | return 0; |
840 | } | 859 | } |
841 | 860 | ||
842 | static int snd_info_dev_unregister_entry(struct snd_device *device) | 861 | static int snd_info_dev_register_entry(struct snd_device *device) |
843 | { | 862 | { |
844 | struct snd_info_entry *entry = device->device_data; | 863 | struct snd_info_entry *entry = device->device_data; |
845 | return snd_info_unregister(entry); | 864 | return snd_info_register(entry); |
846 | } | 865 | } |
847 | 866 | ||
848 | /** | 867 | /** |
@@ -871,8 +890,7 @@ int snd_card_proc_new(struct snd_card *card, const char *name, | |||
871 | static struct snd_device_ops ops = { | 890 | static struct snd_device_ops ops = { |
872 | .dev_free = snd_info_dev_free_entry, | 891 | .dev_free = snd_info_dev_free_entry, |
873 | .dev_register = snd_info_dev_register_entry, | 892 | .dev_register = snd_info_dev_register_entry, |
874 | .dev_disconnect = snd_info_dev_disconnect_entry, | 893 | /* disconnect is done via snd_info_card_disconnect() */ |
875 | .dev_unregister = snd_info_dev_unregister_entry | ||
876 | }; | 894 | }; |
877 | struct snd_info_entry *entry; | 895 | struct snd_info_entry *entry; |
878 | int err; | 896 | int err; |
@@ -901,6 +919,11 @@ void snd_info_free_entry(struct snd_info_entry * entry) | |||
901 | { | 919 | { |
902 | if (entry == NULL) | 920 | if (entry == NULL) |
903 | return; | 921 | return; |
922 | if (entry->p) { | ||
923 | mutex_lock(&info_mutex); | ||
924 | snd_info_disconnect(entry); | ||
925 | mutex_unlock(&info_mutex); | ||
926 | } | ||
904 | kfree(entry->name); | 927 | kfree(entry->name); |
905 | if (entry->private_free) | 928 | if (entry->private_free) |
906 | entry->private_free(entry); | 929 | entry->private_free(entry); |
@@ -935,38 +958,14 @@ int snd_info_register(struct snd_info_entry * entry) | |||
935 | p->size = entry->size; | 958 | p->size = entry->size; |
936 | p->data = entry; | 959 | p->data = entry; |
937 | entry->p = p; | 960 | entry->p = p; |
961 | if (entry->parent) | ||
962 | list_add_tail(&entry->list, &entry->parent->children); | ||
938 | mutex_unlock(&info_mutex); | 963 | mutex_unlock(&info_mutex); |
939 | return 0; | 964 | return 0; |
940 | } | 965 | } |
941 | 966 | ||
942 | EXPORT_SYMBOL(snd_info_register); | 967 | EXPORT_SYMBOL(snd_info_register); |
943 | 968 | ||
944 | /** | ||
945 | * snd_info_unregister - de-register the info entry | ||
946 | * @entry: the info entry | ||
947 | * | ||
948 | * De-registers the info entry and releases the instance. | ||
949 | * | ||
950 | * Returns zero if successful, or a negative error code on failure. | ||
951 | */ | ||
952 | int snd_info_unregister(struct snd_info_entry * entry) | ||
953 | { | ||
954 | struct proc_dir_entry *root; | ||
955 | |||
956 | if (! entry) | ||
957 | return 0; | ||
958 | snd_assert(entry->p != NULL, return -ENXIO); | ||
959 | root = entry->parent == NULL ? snd_proc_root : entry->parent->p; | ||
960 | snd_assert(root, return -ENXIO); | ||
961 | mutex_lock(&info_mutex); | ||
962 | snd_remove_proc_entry(root, entry->p); | ||
963 | mutex_unlock(&info_mutex); | ||
964 | snd_info_free_entry(entry); | ||
965 | return 0; | ||
966 | } | ||
967 | |||
968 | EXPORT_SYMBOL(snd_info_unregister); | ||
969 | |||
970 | /* | 969 | /* |
971 | 970 | ||
972 | */ | 971 | */ |
@@ -999,8 +998,7 @@ static int __init snd_info_version_init(void) | |||
999 | 998 | ||
1000 | static int __exit snd_info_version_done(void) | 999 | static int __exit snd_info_version_done(void) |
1001 | { | 1000 | { |
1002 | if (snd_info_version_entry) | 1001 | snd_info_free_entry(snd_info_version_entry); |
1003 | snd_info_unregister(snd_info_version_entry); | ||
1004 | return 0; | 1002 | return 0; |
1005 | } | 1003 | } |
1006 | 1004 | ||
diff --git a/sound/core/info_oss.c b/sound/core/info_oss.c index bb2c40d0ab66..3ebc34919c76 100644 --- a/sound/core/info_oss.c +++ b/sound/core/info_oss.c | |||
@@ -131,10 +131,8 @@ int snd_info_minor_register(void) | |||
131 | 131 | ||
132 | int snd_info_minor_unregister(void) | 132 | int snd_info_minor_unregister(void) |
133 | { | 133 | { |
134 | if (snd_sndstat_proc_entry) { | 134 | snd_info_free_entry(snd_sndstat_proc_entry); |
135 | snd_info_unregister(snd_sndstat_proc_entry); | 135 | snd_sndstat_proc_entry = NULL; |
136 | snd_sndstat_proc_entry = NULL; | ||
137 | } | ||
138 | return 0; | 136 | return 0; |
139 | } | 137 | } |
140 | 138 | ||
diff --git a/sound/core/init.c b/sound/core/init.c index 4d9258884e44..d7607a25acdf 100644 --- a/sound/core/init.c +++ b/sound/core/init.c | |||
@@ -81,8 +81,6 @@ static inline int init_info_for_card(struct snd_card *card) | |||
81 | #define init_info_for_card(card) | 81 | #define init_info_for_card(card) |
82 | #endif | 82 | #endif |
83 | 83 | ||
84 | static void snd_card_free_thread(void * __card); | ||
85 | |||
86 | /** | 84 | /** |
87 | * snd_card_new - create and initialize a soundcard structure | 85 | * snd_card_new - create and initialize a soundcard structure |
88 | * @idx: card index (address) [0 ... (SNDRV_CARDS-1)] | 86 | * @idx: card index (address) [0 ... (SNDRV_CARDS-1)] |
@@ -145,7 +143,6 @@ struct snd_card *snd_card_new(int idx, const char *xid, | |||
145 | INIT_LIST_HEAD(&card->ctl_files); | 143 | INIT_LIST_HEAD(&card->ctl_files); |
146 | spin_lock_init(&card->files_lock); | 144 | spin_lock_init(&card->files_lock); |
147 | init_waitqueue_head(&card->shutdown_sleep); | 145 | init_waitqueue_head(&card->shutdown_sleep); |
148 | INIT_WORK(&card->free_workq, snd_card_free_thread, card); | ||
149 | #ifdef CONFIG_PM | 146 | #ifdef CONFIG_PM |
150 | mutex_init(&card->power_lock); | 147 | mutex_init(&card->power_lock); |
151 | init_waitqueue_head(&card->power_sleep); | 148 | init_waitqueue_head(&card->power_sleep); |
@@ -310,6 +307,7 @@ int snd_card_disconnect(struct snd_card *card) | |||
310 | if (err < 0) | 307 | if (err < 0) |
311 | snd_printk(KERN_ERR "not all devices for card %i can be disconnected\n", card->number); | 308 | snd_printk(KERN_ERR "not all devices for card %i can be disconnected\n", card->number); |
312 | 309 | ||
310 | snd_info_card_disconnect(card); | ||
313 | return 0; | 311 | return 0; |
314 | } | 312 | } |
315 | 313 | ||
@@ -326,22 +324,10 @@ EXPORT_SYMBOL(snd_card_disconnect); | |||
326 | * Returns zero. Frees all associated devices and frees the control | 324 | * Returns zero. Frees all associated devices and frees the control |
327 | * interface associated to given soundcard. | 325 | * interface associated to given soundcard. |
328 | */ | 326 | */ |
329 | int snd_card_free(struct snd_card *card) | 327 | static int snd_card_do_free(struct snd_card *card) |
330 | { | 328 | { |
331 | struct snd_shutdown_f_ops *s_f_ops; | 329 | struct snd_shutdown_f_ops *s_f_ops; |
332 | 330 | ||
333 | if (card == NULL) | ||
334 | return -EINVAL; | ||
335 | mutex_lock(&snd_card_mutex); | ||
336 | snd_cards[card->number] = NULL; | ||
337 | mutex_unlock(&snd_card_mutex); | ||
338 | |||
339 | #ifdef CONFIG_PM | ||
340 | wake_up(&card->power_sleep); | ||
341 | #endif | ||
342 | /* wait, until all devices are ready for the free operation */ | ||
343 | wait_event(card->shutdown_sleep, card->files == NULL); | ||
344 | |||
345 | #if defined(CONFIG_SND_MIXER_OSS) || defined(CONFIG_SND_MIXER_OSS_MODULE) | 331 | #if defined(CONFIG_SND_MIXER_OSS) || defined(CONFIG_SND_MIXER_OSS_MODULE) |
346 | if (snd_mixer_oss_notify_callback) | 332 | if (snd_mixer_oss_notify_callback) |
347 | snd_mixer_oss_notify_callback(card, SND_MIXER_OSS_NOTIFY_FREE); | 333 | snd_mixer_oss_notify_callback(card, SND_MIXER_OSS_NOTIFY_FREE); |
@@ -360,7 +346,7 @@ int snd_card_free(struct snd_card *card) | |||
360 | } | 346 | } |
361 | if (card->private_free) | 347 | if (card->private_free) |
362 | card->private_free(card); | 348 | card->private_free(card); |
363 | snd_info_unregister(card->proc_id); | 349 | snd_info_free_entry(card->proc_id); |
364 | if (snd_info_card_free(card) < 0) { | 350 | if (snd_info_card_free(card) < 0) { |
365 | snd_printk(KERN_WARNING "unable to free card info\n"); | 351 | snd_printk(KERN_WARNING "unable to free card info\n"); |
366 | /* Not fatal error */ | 352 | /* Not fatal error */ |
@@ -370,61 +356,59 @@ int snd_card_free(struct snd_card *card) | |||
370 | card->s_f_ops = s_f_ops->next; | 356 | card->s_f_ops = s_f_ops->next; |
371 | kfree(s_f_ops); | 357 | kfree(s_f_ops); |
372 | } | 358 | } |
359 | kfree(card); | ||
360 | return 0; | ||
361 | } | ||
362 | |||
363 | static int snd_card_free_prepare(struct snd_card *card) | ||
364 | { | ||
365 | if (card == NULL) | ||
366 | return -EINVAL; | ||
367 | (void) snd_card_disconnect(card); | ||
373 | mutex_lock(&snd_card_mutex); | 368 | mutex_lock(&snd_card_mutex); |
369 | snd_cards[card->number] = NULL; | ||
374 | snd_cards_lock &= ~(1 << card->number); | 370 | snd_cards_lock &= ~(1 << card->number); |
375 | mutex_unlock(&snd_card_mutex); | 371 | mutex_unlock(&snd_card_mutex); |
376 | kfree(card); | 372 | #ifdef CONFIG_PM |
373 | wake_up(&card->power_sleep); | ||
374 | #endif | ||
377 | return 0; | 375 | return 0; |
378 | } | 376 | } |
379 | 377 | ||
380 | EXPORT_SYMBOL(snd_card_free); | 378 | int snd_card_free_when_closed(struct snd_card *card) |
381 | |||
382 | static void snd_card_free_thread(void * __card) | ||
383 | { | 379 | { |
384 | struct snd_card *card = __card; | 380 | int free_now = 0; |
385 | struct module * module = card->module; | 381 | int ret = snd_card_free_prepare(card); |
386 | 382 | if (ret) | |
387 | if (!try_module_get(module)) { | 383 | return ret; |
388 | snd_printk(KERN_ERR "unable to lock toplevel module for card %i in free thread\n", card->number); | ||
389 | module = NULL; | ||
390 | } | ||
391 | 384 | ||
392 | snd_card_free(card); | 385 | spin_lock(&card->files_lock); |
386 | if (card->files == NULL) | ||
387 | free_now = 1; | ||
388 | else | ||
389 | card->free_on_last_close = 1; | ||
390 | spin_unlock(&card->files_lock); | ||
393 | 391 | ||
394 | module_put(module); | 392 | if (free_now) |
393 | snd_card_do_free(card); | ||
394 | return 0; | ||
395 | } | 395 | } |
396 | 396 | ||
397 | /** | 397 | EXPORT_SYMBOL(snd_card_free_when_closed); |
398 | * snd_card_free_in_thread - call snd_card_free() in thread | ||
399 | * @card: soundcard structure | ||
400 | * | ||
401 | * This function schedules the call of snd_card_free() function in a | ||
402 | * work queue. When all devices are released (non-busy), the work | ||
403 | * is woken up and calls snd_card_free(). | ||
404 | * | ||
405 | * When a card can be disconnected at any time by hotplug service, | ||
406 | * this function should be used in disconnect (or detach) callback | ||
407 | * instead of calling snd_card_free() directly. | ||
408 | * | ||
409 | * Returns - zero otherwise a negative error code if the start of thread failed. | ||
410 | */ | ||
411 | int snd_card_free_in_thread(struct snd_card *card) | ||
412 | { | ||
413 | if (card->files == NULL) { | ||
414 | snd_card_free(card); | ||
415 | return 0; | ||
416 | } | ||
417 | 398 | ||
418 | if (schedule_work(&card->free_workq)) | 399 | int snd_card_free(struct snd_card *card) |
419 | return 0; | 400 | { |
401 | int ret = snd_card_free_prepare(card); | ||
402 | if (ret) | ||
403 | return ret; | ||
420 | 404 | ||
421 | snd_printk(KERN_ERR "schedule_work() failed in snd_card_free_in_thread for card %i\n", card->number); | 405 | /* wait, until all devices are ready for the free operation */ |
422 | /* try to free the structure immediately */ | 406 | wait_event(card->shutdown_sleep, card->files == NULL); |
423 | snd_card_free(card); | 407 | snd_card_do_free(card); |
424 | return -EFAULT; | 408 | return 0; |
425 | } | 409 | } |
426 | 410 | ||
427 | EXPORT_SYMBOL(snd_card_free_in_thread); | 411 | EXPORT_SYMBOL(snd_card_free); |
428 | 412 | ||
429 | static void choose_default_id(struct snd_card *card) | 413 | static void choose_default_id(struct snd_card *card) |
430 | { | 414 | { |
@@ -625,9 +609,9 @@ int __init snd_card_info_init(void) | |||
625 | 609 | ||
626 | int __exit snd_card_info_done(void) | 610 | int __exit snd_card_info_done(void) |
627 | { | 611 | { |
628 | snd_info_unregister(snd_card_info_entry); | 612 | snd_info_free_entry(snd_card_info_entry); |
629 | #ifdef MODULE | 613 | #ifdef MODULE |
630 | snd_info_unregister(snd_card_module_info_entry); | 614 | snd_info_free_entry(snd_card_module_info_entry); |
631 | #endif | 615 | #endif |
632 | return 0; | 616 | return 0; |
633 | } | 617 | } |
@@ -708,15 +692,16 @@ EXPORT_SYMBOL(snd_card_file_add); | |||
708 | * | 692 | * |
709 | * This function removes the file formerly added to the card via | 693 | * This function removes the file formerly added to the card via |
710 | * snd_card_file_add() function. | 694 | * snd_card_file_add() function. |
711 | * If all files are removed and the release of the card is | 695 | * If all files are removed and snd_card_free_when_closed() was |
712 | * scheduled, it will wake up the the thread to call snd_card_free() | 696 | * called beforehand, it processes the pending release of |
713 | * (see snd_card_free_in_thread() function). | 697 | * resources. |
714 | * | 698 | * |
715 | * Returns zero or a negative error code. | 699 | * Returns zero or a negative error code. |
716 | */ | 700 | */ |
717 | int snd_card_file_remove(struct snd_card *card, struct file *file) | 701 | int snd_card_file_remove(struct snd_card *card, struct file *file) |
718 | { | 702 | { |
719 | struct snd_monitor_file *mfile, *pfile = NULL; | 703 | struct snd_monitor_file *mfile, *pfile = NULL; |
704 | int last_close = 0; | ||
720 | 705 | ||
721 | spin_lock(&card->files_lock); | 706 | spin_lock(&card->files_lock); |
722 | mfile = card->files; | 707 | mfile = card->files; |
@@ -731,9 +716,14 @@ int snd_card_file_remove(struct snd_card *card, struct file *file) | |||
731 | pfile = mfile; | 716 | pfile = mfile; |
732 | mfile = mfile->next; | 717 | mfile = mfile->next; |
733 | } | 718 | } |
734 | spin_unlock(&card->files_lock); | ||
735 | if (card->files == NULL) | 719 | if (card->files == NULL) |
720 | last_close = 1; | ||
721 | spin_unlock(&card->files_lock); | ||
722 | if (last_close) { | ||
736 | wake_up(&card->shutdown_sleep); | 723 | wake_up(&card->shutdown_sleep); |
724 | if (card->free_on_last_close) | ||
725 | snd_card_do_free(card); | ||
726 | } | ||
737 | if (!mfile) { | 727 | if (!mfile) { |
738 | snd_printk(KERN_ERR "ALSA card file remove problem (%p)\n", file); | 728 | snd_printk(KERN_ERR "ALSA card file remove problem (%p)\n", file); |
739 | return -ENOENT; | 729 | return -ENOENT; |
diff --git a/sound/core/oss/mixer_oss.c b/sound/core/oss/mixer_oss.c index 75a9505c7445..f4c67042e3ac 100644 --- a/sound/core/oss/mixer_oss.c +++ b/sound/core/oss/mixer_oss.c | |||
@@ -1193,10 +1193,8 @@ static void snd_mixer_oss_proc_init(struct snd_mixer_oss *mixer) | |||
1193 | 1193 | ||
1194 | static void snd_mixer_oss_proc_done(struct snd_mixer_oss *mixer) | 1194 | static void snd_mixer_oss_proc_done(struct snd_mixer_oss *mixer) |
1195 | { | 1195 | { |
1196 | if (mixer->proc_entry) { | 1196 | snd_info_free_entry(mixer->proc_entry); |
1197 | snd_info_unregister(mixer->proc_entry); | 1197 | mixer->proc_entry = NULL; |
1198 | mixer->proc_entry = NULL; | ||
1199 | } | ||
1200 | } | 1198 | } |
1201 | #else /* !CONFIG_PROC_FS */ | 1199 | #else /* !CONFIG_PROC_FS */ |
1202 | #define snd_mixer_oss_proc_init(mix) | 1200 | #define snd_mixer_oss_proc_init(mix) |
@@ -1312,21 +1310,19 @@ static int snd_mixer_oss_notify_handler(struct snd_card *card, int cmd) | |||
1312 | card->mixer_oss = mixer; | 1310 | card->mixer_oss = mixer; |
1313 | snd_mixer_oss_build(mixer); | 1311 | snd_mixer_oss_build(mixer); |
1314 | snd_mixer_oss_proc_init(mixer); | 1312 | snd_mixer_oss_proc_init(mixer); |
1315 | } else if (cmd == SND_MIXER_OSS_NOTIFY_DISCONNECT) { | 1313 | } else { |
1316 | mixer = card->mixer_oss; | ||
1317 | if (mixer == NULL || !mixer->oss_dev_alloc) | ||
1318 | return 0; | ||
1319 | snd_unregister_oss_device(SNDRV_OSS_DEVICE_TYPE_MIXER, mixer->card, 0); | ||
1320 | mixer->oss_dev_alloc = 0; | ||
1321 | } else { /* free */ | ||
1322 | mixer = card->mixer_oss; | 1314 | mixer = card->mixer_oss; |
1323 | if (mixer == NULL) | 1315 | if (mixer == NULL) |
1324 | return 0; | 1316 | return 0; |
1317 | if (mixer->oss_dev_alloc) { | ||
1325 | #ifdef SNDRV_OSS_INFO_DEV_MIXERS | 1318 | #ifdef SNDRV_OSS_INFO_DEV_MIXERS |
1326 | snd_oss_info_unregister(SNDRV_OSS_INFO_DEV_MIXERS, mixer->card->number); | 1319 | snd_oss_info_unregister(SNDRV_OSS_INFO_DEV_MIXERS, mixer->card->number); |
1327 | #endif | 1320 | #endif |
1328 | if (mixer->oss_dev_alloc) | ||
1329 | snd_unregister_oss_device(SNDRV_OSS_DEVICE_TYPE_MIXER, mixer->card, 0); | 1321 | snd_unregister_oss_device(SNDRV_OSS_DEVICE_TYPE_MIXER, mixer->card, 0); |
1322 | mixer->oss_dev_alloc = 0; | ||
1323 | } | ||
1324 | if (cmd == SND_MIXER_OSS_NOTIFY_DISCONNECT) | ||
1325 | return 0; | ||
1330 | snd_mixer_oss_proc_done(mixer); | 1326 | snd_mixer_oss_proc_done(mixer); |
1331 | return snd_mixer_oss_free1(mixer); | 1327 | return snd_mixer_oss_free1(mixer); |
1332 | } | 1328 | } |
diff --git a/sound/core/oss/pcm_oss.c b/sound/core/oss/pcm_oss.c index 472fce0ee0e8..505b23ec4058 100644 --- a/sound/core/oss/pcm_oss.c +++ b/sound/core/oss/pcm_oss.c | |||
@@ -2846,11 +2846,9 @@ static void snd_pcm_oss_proc_done(struct snd_pcm *pcm) | |||
2846 | int stream; | 2846 | int stream; |
2847 | for (stream = 0; stream < 2; ++stream) { | 2847 | for (stream = 0; stream < 2; ++stream) { |
2848 | struct snd_pcm_str *pstr = &pcm->streams[stream]; | 2848 | struct snd_pcm_str *pstr = &pcm->streams[stream]; |
2849 | if (pstr->oss.proc_entry) { | 2849 | snd_info_free_entry(pstr->oss.proc_entry); |
2850 | snd_info_unregister(pstr->oss.proc_entry); | 2850 | pstr->oss.proc_entry = NULL; |
2851 | pstr->oss.proc_entry = NULL; | 2851 | snd_pcm_oss_proc_free_setup_list(pstr); |
2852 | snd_pcm_oss_proc_free_setup_list(pstr); | ||
2853 | } | ||
2854 | } | 2852 | } |
2855 | } | 2853 | } |
2856 | #else /* !CONFIG_SND_VERBOSE_PROCFS */ | 2854 | #else /* !CONFIG_SND_VERBOSE_PROCFS */ |
@@ -2931,25 +2929,23 @@ static int snd_pcm_oss_disconnect_minor(struct snd_pcm *pcm) | |||
2931 | snd_unregister_oss_device(SNDRV_OSS_DEVICE_TYPE_PCM, | 2929 | snd_unregister_oss_device(SNDRV_OSS_DEVICE_TYPE_PCM, |
2932 | pcm->card, 1); | 2930 | pcm->card, 1); |
2933 | } | 2931 | } |
2934 | } | ||
2935 | return 0; | ||
2936 | } | ||
2937 | |||
2938 | static int snd_pcm_oss_unregister_minor(struct snd_pcm *pcm) | ||
2939 | { | ||
2940 | snd_pcm_oss_disconnect_minor(pcm); | ||
2941 | if (pcm->oss.reg) { | ||
2942 | if (dsp_map[pcm->card->number] == (int)pcm->device) { | 2932 | if (dsp_map[pcm->card->number] == (int)pcm->device) { |
2943 | #ifdef SNDRV_OSS_INFO_DEV_AUDIO | 2933 | #ifdef SNDRV_OSS_INFO_DEV_AUDIO |
2944 | snd_oss_info_unregister(SNDRV_OSS_INFO_DEV_AUDIO, pcm->card->number); | 2934 | snd_oss_info_unregister(SNDRV_OSS_INFO_DEV_AUDIO, pcm->card->number); |
2945 | #endif | 2935 | #endif |
2946 | } | 2936 | } |
2947 | pcm->oss.reg = 0; | 2937 | pcm->oss.reg = 0; |
2948 | snd_pcm_oss_proc_done(pcm); | ||
2949 | } | 2938 | } |
2950 | return 0; | 2939 | return 0; |
2951 | } | 2940 | } |
2952 | 2941 | ||
2942 | static int snd_pcm_oss_unregister_minor(struct snd_pcm *pcm) | ||
2943 | { | ||
2944 | snd_pcm_oss_disconnect_minor(pcm); | ||
2945 | snd_pcm_oss_proc_done(pcm); | ||
2946 | return 0; | ||
2947 | } | ||
2948 | |||
2953 | static struct snd_pcm_notify snd_pcm_oss_notify = | 2949 | static struct snd_pcm_notify snd_pcm_oss_notify = |
2954 | { | 2950 | { |
2955 | .n_register = snd_pcm_oss_register_minor, | 2951 | .n_register = snd_pcm_oss_register_minor, |
diff --git a/sound/core/pcm.c b/sound/core/pcm.c index 7581edd7b9ff..bf8f412988b8 100644 --- a/sound/core/pcm.c +++ b/sound/core/pcm.c | |||
@@ -42,7 +42,6 @@ static int snd_pcm_free(struct snd_pcm *pcm); | |||
42 | static int snd_pcm_dev_free(struct snd_device *device); | 42 | static int snd_pcm_dev_free(struct snd_device *device); |
43 | static int snd_pcm_dev_register(struct snd_device *device); | 43 | static int snd_pcm_dev_register(struct snd_device *device); |
44 | static int snd_pcm_dev_disconnect(struct snd_device *device); | 44 | static int snd_pcm_dev_disconnect(struct snd_device *device); |
45 | static int snd_pcm_dev_unregister(struct snd_device *device); | ||
46 | 45 | ||
47 | static struct snd_pcm *snd_pcm_search(struct snd_card *card, int device) | 46 | static struct snd_pcm *snd_pcm_search(struct snd_card *card, int device) |
48 | { | 47 | { |
@@ -494,19 +493,13 @@ static int snd_pcm_stream_proc_init(struct snd_pcm_str *pstr) | |||
494 | static int snd_pcm_stream_proc_done(struct snd_pcm_str *pstr) | 493 | static int snd_pcm_stream_proc_done(struct snd_pcm_str *pstr) |
495 | { | 494 | { |
496 | #ifdef CONFIG_SND_PCM_XRUN_DEBUG | 495 | #ifdef CONFIG_SND_PCM_XRUN_DEBUG |
497 | if (pstr->proc_xrun_debug_entry) { | 496 | snd_info_free_entry(pstr->proc_xrun_debug_entry); |
498 | snd_info_unregister(pstr->proc_xrun_debug_entry); | 497 | pstr->proc_xrun_debug_entry = NULL; |
499 | pstr->proc_xrun_debug_entry = NULL; | ||
500 | } | ||
501 | #endif | 498 | #endif |
502 | if (pstr->proc_info_entry) { | 499 | snd_info_free_entry(pstr->proc_info_entry); |
503 | snd_info_unregister(pstr->proc_info_entry); | 500 | pstr->proc_info_entry = NULL; |
504 | pstr->proc_info_entry = NULL; | 501 | snd_info_free_entry(pstr->proc_root); |
505 | } | 502 | pstr->proc_root = NULL; |
506 | if (pstr->proc_root) { | ||
507 | snd_info_unregister(pstr->proc_root); | ||
508 | pstr->proc_root = NULL; | ||
509 | } | ||
510 | return 0; | 503 | return 0; |
511 | } | 504 | } |
512 | 505 | ||
@@ -570,29 +563,19 @@ static int snd_pcm_substream_proc_init(struct snd_pcm_substream *substream) | |||
570 | 563 | ||
571 | return 0; | 564 | return 0; |
572 | } | 565 | } |
573 | 566 | ||
574 | static int snd_pcm_substream_proc_done(struct snd_pcm_substream *substream) | 567 | static int snd_pcm_substream_proc_done(struct snd_pcm_substream *substream) |
575 | { | 568 | { |
576 | if (substream->proc_info_entry) { | 569 | snd_info_free_entry(substream->proc_info_entry); |
577 | snd_info_unregister(substream->proc_info_entry); | 570 | substream->proc_info_entry = NULL; |
578 | substream->proc_info_entry = NULL; | 571 | snd_info_free_entry(substream->proc_hw_params_entry); |
579 | } | 572 | substream->proc_hw_params_entry = NULL; |
580 | if (substream->proc_hw_params_entry) { | 573 | snd_info_free_entry(substream->proc_sw_params_entry); |
581 | snd_info_unregister(substream->proc_hw_params_entry); | 574 | substream->proc_sw_params_entry = NULL; |
582 | substream->proc_hw_params_entry = NULL; | 575 | snd_info_free_entry(substream->proc_status_entry); |
583 | } | 576 | substream->proc_status_entry = NULL; |
584 | if (substream->proc_sw_params_entry) { | 577 | snd_info_free_entry(substream->proc_root); |
585 | snd_info_unregister(substream->proc_sw_params_entry); | 578 | substream->proc_root = NULL; |
586 | substream->proc_sw_params_entry = NULL; | ||
587 | } | ||
588 | if (substream->proc_status_entry) { | ||
589 | snd_info_unregister(substream->proc_status_entry); | ||
590 | substream->proc_status_entry = NULL; | ||
591 | } | ||
592 | if (substream->proc_root) { | ||
593 | snd_info_unregister(substream->proc_root); | ||
594 | substream->proc_root = NULL; | ||
595 | } | ||
596 | return 0; | 579 | return 0; |
597 | } | 580 | } |
598 | #else /* !CONFIG_SND_VERBOSE_PROCFS */ | 581 | #else /* !CONFIG_SND_VERBOSE_PROCFS */ |
@@ -696,7 +679,6 @@ int snd_pcm_new(struct snd_card *card, char *id, int device, | |||
696 | .dev_free = snd_pcm_dev_free, | 679 | .dev_free = snd_pcm_dev_free, |
697 | .dev_register = snd_pcm_dev_register, | 680 | .dev_register = snd_pcm_dev_register, |
698 | .dev_disconnect = snd_pcm_dev_disconnect, | 681 | .dev_disconnect = snd_pcm_dev_disconnect, |
699 | .dev_unregister = snd_pcm_dev_unregister | ||
700 | }; | 682 | }; |
701 | 683 | ||
702 | snd_assert(rpcm != NULL, return -EINVAL); | 684 | snd_assert(rpcm != NULL, return -EINVAL); |
@@ -740,6 +722,7 @@ static void snd_pcm_free_stream(struct snd_pcm_str * pstr) | |||
740 | substream = pstr->substream; | 722 | substream = pstr->substream; |
741 | while (substream) { | 723 | while (substream) { |
742 | substream_next = substream->next; | 724 | substream_next = substream->next; |
725 | snd_pcm_timer_done(substream); | ||
743 | snd_pcm_substream_proc_done(substream); | 726 | snd_pcm_substream_proc_done(substream); |
744 | kfree(substream); | 727 | kfree(substream); |
745 | substream = substream_next; | 728 | substream = substream_next; |
@@ -756,7 +739,12 @@ static void snd_pcm_free_stream(struct snd_pcm_str * pstr) | |||
756 | 739 | ||
757 | static int snd_pcm_free(struct snd_pcm *pcm) | 740 | static int snd_pcm_free(struct snd_pcm *pcm) |
758 | { | 741 | { |
742 | struct snd_pcm_notify *notify; | ||
743 | |||
759 | snd_assert(pcm != NULL, return -ENXIO); | 744 | snd_assert(pcm != NULL, return -ENXIO); |
745 | list_for_each_entry(notify, &snd_pcm_notify_list, list) { | ||
746 | notify->n_unregister(pcm); | ||
747 | } | ||
760 | if (pcm->private_free) | 748 | if (pcm->private_free) |
761 | pcm->private_free(pcm); | 749 | pcm->private_free(pcm); |
762 | snd_pcm_lib_preallocate_free_for_all(pcm); | 750 | snd_pcm_lib_preallocate_free_for_all(pcm); |
@@ -804,7 +792,8 @@ int snd_pcm_attach_substream(struct snd_pcm *pcm, int stream, | |||
804 | kctl = snd_ctl_file(list); | 792 | kctl = snd_ctl_file(list); |
805 | if (kctl->pid == current->pid) { | 793 | if (kctl->pid == current->pid) { |
806 | prefer_subdevice = kctl->prefer_pcm_subdevice; | 794 | prefer_subdevice = kctl->prefer_pcm_subdevice; |
807 | break; | 795 | if (prefer_subdevice != -1) |
796 | break; | ||
808 | } | 797 | } |
809 | } | 798 | } |
810 | up_read(&card->controls_rwsem); | 799 | up_read(&card->controls_rwsem); |
@@ -918,6 +907,28 @@ void snd_pcm_detach_substream(struct snd_pcm_substream *substream) | |||
918 | substream->pstr->substream_opened--; | 907 | substream->pstr->substream_opened--; |
919 | } | 908 | } |
920 | 909 | ||
910 | static ssize_t show_pcm_class(struct class_device *class_device, char *buf) | ||
911 | { | ||
912 | struct snd_pcm *pcm; | ||
913 | const char *str; | ||
914 | static const char *strs[SNDRV_PCM_CLASS_LAST + 1] = { | ||
915 | [SNDRV_PCM_CLASS_GENERIC] = "generic", | ||
916 | [SNDRV_PCM_CLASS_MULTI] = "multi", | ||
917 | [SNDRV_PCM_CLASS_MODEM] = "modem", | ||
918 | [SNDRV_PCM_CLASS_DIGITIZER] = "digitizer", | ||
919 | }; | ||
920 | |||
921 | if (! (pcm = class_get_devdata(class_device)) || | ||
922 | pcm->dev_class > SNDRV_PCM_CLASS_LAST) | ||
923 | str = "none"; | ||
924 | else | ||
925 | str = strs[pcm->dev_class]; | ||
926 | return snprintf(buf, PAGE_SIZE, "%s\n", str); | ||
927 | } | ||
928 | |||
929 | static struct class_device_attribute pcm_attrs = | ||
930 | __ATTR(pcm_class, S_IRUGO, show_pcm_class, NULL); | ||
931 | |||
921 | static int snd_pcm_dev_register(struct snd_device *device) | 932 | static int snd_pcm_dev_register(struct snd_device *device) |
922 | { | 933 | { |
923 | int cidx, err; | 934 | int cidx, err; |
@@ -956,6 +967,8 @@ static int snd_pcm_dev_register(struct snd_device *device) | |||
956 | mutex_unlock(®ister_mutex); | 967 | mutex_unlock(®ister_mutex); |
957 | return err; | 968 | return err; |
958 | } | 969 | } |
970 | snd_add_device_sysfs_file(devtype, pcm->card, pcm->device, | ||
971 | &pcm_attrs); | ||
959 | for (substream = pcm->streams[cidx].substream; substream; substream = substream->next) | 972 | for (substream = pcm->streams[cidx].substream; substream; substream = substream->next) |
960 | snd_pcm_timer_init(substream); | 973 | snd_pcm_timer_init(substream); |
961 | } | 974 | } |
@@ -971,35 +984,22 @@ static int snd_pcm_dev_register(struct snd_device *device) | |||
971 | static int snd_pcm_dev_disconnect(struct snd_device *device) | 984 | static int snd_pcm_dev_disconnect(struct snd_device *device) |
972 | { | 985 | { |
973 | struct snd_pcm *pcm = device->device_data; | 986 | struct snd_pcm *pcm = device->device_data; |
974 | struct list_head *list; | 987 | struct snd_pcm_notify *notify; |
975 | struct snd_pcm_substream *substream; | 988 | struct snd_pcm_substream *substream; |
976 | int cidx; | 989 | int cidx, devtype; |
977 | 990 | ||
978 | mutex_lock(®ister_mutex); | 991 | mutex_lock(®ister_mutex); |
992 | if (list_empty(&pcm->list)) | ||
993 | goto unlock; | ||
994 | |||
979 | list_del_init(&pcm->list); | 995 | list_del_init(&pcm->list); |
980 | for (cidx = 0; cidx < 2; cidx++) | 996 | for (cidx = 0; cidx < 2; cidx++) |
981 | for (substream = pcm->streams[cidx].substream; substream; substream = substream->next) | 997 | for (substream = pcm->streams[cidx].substream; substream; substream = substream->next) |
982 | if (substream->runtime) | 998 | if (substream->runtime) |
983 | substream->runtime->status->state = SNDRV_PCM_STATE_DISCONNECTED; | 999 | substream->runtime->status->state = SNDRV_PCM_STATE_DISCONNECTED; |
984 | list_for_each(list, &snd_pcm_notify_list) { | 1000 | list_for_each_entry(notify, &snd_pcm_notify_list, list) { |
985 | struct snd_pcm_notify *notify; | ||
986 | notify = list_entry(list, struct snd_pcm_notify, list); | ||
987 | notify->n_disconnect(pcm); | 1001 | notify->n_disconnect(pcm); |
988 | } | 1002 | } |
989 | mutex_unlock(®ister_mutex); | ||
990 | return 0; | ||
991 | } | ||
992 | |||
993 | static int snd_pcm_dev_unregister(struct snd_device *device) | ||
994 | { | ||
995 | int cidx, devtype; | ||
996 | struct snd_pcm_substream *substream; | ||
997 | struct list_head *list; | ||
998 | struct snd_pcm *pcm = device->device_data; | ||
999 | |||
1000 | snd_assert(pcm != NULL, return -ENXIO); | ||
1001 | mutex_lock(®ister_mutex); | ||
1002 | list_del(&pcm->list); | ||
1003 | for (cidx = 0; cidx < 2; cidx++) { | 1003 | for (cidx = 0; cidx < 2; cidx++) { |
1004 | devtype = -1; | 1004 | devtype = -1; |
1005 | switch (cidx) { | 1005 | switch (cidx) { |
@@ -1011,23 +1011,20 @@ static int snd_pcm_dev_unregister(struct snd_device *device) | |||
1011 | break; | 1011 | break; |
1012 | } | 1012 | } |
1013 | snd_unregister_device(devtype, pcm->card, pcm->device); | 1013 | snd_unregister_device(devtype, pcm->card, pcm->device); |
1014 | for (substream = pcm->streams[cidx].substream; substream; substream = substream->next) | ||
1015 | snd_pcm_timer_done(substream); | ||
1016 | } | ||
1017 | list_for_each(list, &snd_pcm_notify_list) { | ||
1018 | struct snd_pcm_notify *notify; | ||
1019 | notify = list_entry(list, struct snd_pcm_notify, list); | ||
1020 | notify->n_unregister(pcm); | ||
1021 | } | 1014 | } |
1015 | unlock: | ||
1022 | mutex_unlock(®ister_mutex); | 1016 | mutex_unlock(®ister_mutex); |
1023 | return snd_pcm_free(pcm); | 1017 | return 0; |
1024 | } | 1018 | } |
1025 | 1019 | ||
1026 | int snd_pcm_notify(struct snd_pcm_notify *notify, int nfree) | 1020 | int snd_pcm_notify(struct snd_pcm_notify *notify, int nfree) |
1027 | { | 1021 | { |
1028 | struct list_head *p; | 1022 | struct list_head *p; |
1029 | 1023 | ||
1030 | snd_assert(notify != NULL && notify->n_register != NULL && notify->n_unregister != NULL, return -EINVAL); | 1024 | snd_assert(notify != NULL && |
1025 | notify->n_register != NULL && | ||
1026 | notify->n_unregister != NULL && | ||
1027 | notify->n_disconnect, return -EINVAL); | ||
1031 | mutex_lock(®ister_mutex); | 1028 | mutex_lock(®ister_mutex); |
1032 | if (nfree) { | 1029 | if (nfree) { |
1033 | list_del(¬ify->list); | 1030 | list_del(¬ify->list); |
@@ -1090,8 +1087,7 @@ static void snd_pcm_proc_init(void) | |||
1090 | 1087 | ||
1091 | static void snd_pcm_proc_done(void) | 1088 | static void snd_pcm_proc_done(void) |
1092 | { | 1089 | { |
1093 | if (snd_pcm_proc_entry) | 1090 | snd_info_free_entry(snd_pcm_proc_entry); |
1094 | snd_info_unregister(snd_pcm_proc_entry); | ||
1095 | } | 1091 | } |
1096 | 1092 | ||
1097 | #else /* !CONFIG_PROC_FS */ | 1093 | #else /* !CONFIG_PROC_FS */ |
diff --git a/sound/core/pcm_compat.c b/sound/core/pcm_compat.c index 2b8aab6fd6cd..2b539799d23b 100644 --- a/sound/core/pcm_compat.c +++ b/sound/core/pcm_compat.c | |||
@@ -478,7 +478,7 @@ static long snd_pcm_ioctl_compat(struct file *file, unsigned int cmd, unsigned l | |||
478 | * mmap of PCM status/control records because of the size | 478 | * mmap of PCM status/control records because of the size |
479 | * incompatibility. | 479 | * incompatibility. |
480 | */ | 480 | */ |
481 | substream->no_mmap_ctrl = 1; | 481 | pcm_file->no_compat_mmap = 1; |
482 | 482 | ||
483 | switch (cmd) { | 483 | switch (cmd) { |
484 | case SNDRV_PCM_IOCTL_PVERSION: | 484 | case SNDRV_PCM_IOCTL_PVERSION: |
diff --git a/sound/core/pcm_memory.c b/sound/core/pcm_memory.c index 067d2056db9a..be030cb4d373 100644 --- a/sound/core/pcm_memory.c +++ b/sound/core/pcm_memory.c | |||
@@ -101,7 +101,7 @@ int snd_pcm_lib_preallocate_free(struct snd_pcm_substream *substream) | |||
101 | { | 101 | { |
102 | snd_pcm_lib_preallocate_dma_free(substream); | 102 | snd_pcm_lib_preallocate_dma_free(substream); |
103 | #ifdef CONFIG_SND_VERBOSE_PROCFS | 103 | #ifdef CONFIG_SND_VERBOSE_PROCFS |
104 | snd_info_unregister(substream->proc_prealloc_entry); | 104 | snd_info_free_entry(substream->proc_prealloc_entry); |
105 | substream->proc_prealloc_entry = NULL; | 105 | substream->proc_prealloc_entry = NULL; |
106 | #endif | 106 | #endif |
107 | return 0; | 107 | return 0; |
diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c index 439f047929e1..0224c70414f5 100644 --- a/sound/core/pcm_native.c +++ b/sound/core/pcm_native.c | |||
@@ -1992,35 +1992,9 @@ int snd_pcm_hw_constraints_complete(struct snd_pcm_substream *substream) | |||
1992 | return 0; | 1992 | return 0; |
1993 | } | 1993 | } |
1994 | 1994 | ||
1995 | static void snd_pcm_add_file(struct snd_pcm_str *str, | ||
1996 | struct snd_pcm_file *pcm_file) | ||
1997 | { | ||
1998 | pcm_file->next = str->files; | ||
1999 | str->files = pcm_file; | ||
2000 | } | ||
2001 | |||
2002 | static void snd_pcm_remove_file(struct snd_pcm_str *str, | ||
2003 | struct snd_pcm_file *pcm_file) | ||
2004 | { | ||
2005 | struct snd_pcm_file * pcm_file1; | ||
2006 | if (str->files == pcm_file) { | ||
2007 | str->files = pcm_file->next; | ||
2008 | } else { | ||
2009 | pcm_file1 = str->files; | ||
2010 | while (pcm_file1 && pcm_file1->next != pcm_file) | ||
2011 | pcm_file1 = pcm_file1->next; | ||
2012 | if (pcm_file1 != NULL) | ||
2013 | pcm_file1->next = pcm_file->next; | ||
2014 | } | ||
2015 | } | ||
2016 | |||
2017 | static void pcm_release_private(struct snd_pcm_substream *substream) | 1995 | static void pcm_release_private(struct snd_pcm_substream *substream) |
2018 | { | 1996 | { |
2019 | struct snd_pcm_file *pcm_file = substream->file; | ||
2020 | |||
2021 | snd_pcm_unlink(substream); | 1997 | snd_pcm_unlink(substream); |
2022 | snd_pcm_remove_file(substream->pstr, pcm_file); | ||
2023 | kfree(pcm_file); | ||
2024 | } | 1998 | } |
2025 | 1999 | ||
2026 | void snd_pcm_release_substream(struct snd_pcm_substream *substream) | 2000 | void snd_pcm_release_substream(struct snd_pcm_substream *substream) |
@@ -2060,7 +2034,6 @@ int snd_pcm_open_substream(struct snd_pcm *pcm, int stream, | |||
2060 | return 0; | 2034 | return 0; |
2061 | } | 2035 | } |
2062 | 2036 | ||
2063 | substream->no_mmap_ctrl = 0; | ||
2064 | err = snd_pcm_hw_constraints_init(substream); | 2037 | err = snd_pcm_hw_constraints_init(substream); |
2065 | if (err < 0) { | 2038 | if (err < 0) { |
2066 | snd_printd("snd_pcm_hw_constraints_init failed\n"); | 2039 | snd_printd("snd_pcm_hw_constraints_init failed\n"); |
@@ -2105,19 +2078,16 @@ static int snd_pcm_open_file(struct file *file, | |||
2105 | if (err < 0) | 2078 | if (err < 0) |
2106 | return err; | 2079 | return err; |
2107 | 2080 | ||
2108 | if (substream->ref_count > 1) | 2081 | pcm_file = kzalloc(sizeof(*pcm_file), GFP_KERNEL); |
2109 | pcm_file = substream->file; | 2082 | if (pcm_file == NULL) { |
2110 | else { | 2083 | snd_pcm_release_substream(substream); |
2111 | pcm_file = kzalloc(sizeof(*pcm_file), GFP_KERNEL); | 2084 | return -ENOMEM; |
2112 | if (pcm_file == NULL) { | 2085 | } |
2113 | snd_pcm_release_substream(substream); | 2086 | pcm_file->substream = substream; |
2114 | return -ENOMEM; | 2087 | if (substream->ref_count == 1) { |
2115 | } | ||
2116 | str = substream->pstr; | 2088 | str = substream->pstr; |
2117 | substream->file = pcm_file; | 2089 | substream->file = pcm_file; |
2118 | substream->pcm_release = pcm_release_private; | 2090 | substream->pcm_release = pcm_release_private; |
2119 | pcm_file->substream = substream; | ||
2120 | snd_pcm_add_file(str, pcm_file); | ||
2121 | } | 2091 | } |
2122 | file->private_data = pcm_file; | 2092 | file->private_data = pcm_file; |
2123 | *rpcm_file = pcm_file; | 2093 | *rpcm_file = pcm_file; |
@@ -2209,6 +2179,7 @@ static int snd_pcm_release(struct inode *inode, struct file *file) | |||
2209 | fasync_helper(-1, file, 0, &substream->runtime->fasync); | 2179 | fasync_helper(-1, file, 0, &substream->runtime->fasync); |
2210 | mutex_lock(&pcm->open_mutex); | 2180 | mutex_lock(&pcm->open_mutex); |
2211 | snd_pcm_release_substream(substream); | 2181 | snd_pcm_release_substream(substream); |
2182 | kfree(pcm_file); | ||
2212 | mutex_unlock(&pcm->open_mutex); | 2183 | mutex_unlock(&pcm->open_mutex); |
2213 | wake_up(&pcm->open_wait); | 2184 | wake_up(&pcm->open_wait); |
2214 | module_put(pcm->card->module); | 2185 | module_put(pcm->card->module); |
@@ -3270,11 +3241,11 @@ static int snd_pcm_mmap(struct file *file, struct vm_area_struct *area) | |||
3270 | offset = area->vm_pgoff << PAGE_SHIFT; | 3241 | offset = area->vm_pgoff << PAGE_SHIFT; |
3271 | switch (offset) { | 3242 | switch (offset) { |
3272 | case SNDRV_PCM_MMAP_OFFSET_STATUS: | 3243 | case SNDRV_PCM_MMAP_OFFSET_STATUS: |
3273 | if (substream->no_mmap_ctrl) | 3244 | if (pcm_file->no_compat_mmap) |
3274 | return -ENXIO; | 3245 | return -ENXIO; |
3275 | return snd_pcm_mmap_status(substream, file, area); | 3246 | return snd_pcm_mmap_status(substream, file, area); |
3276 | case SNDRV_PCM_MMAP_OFFSET_CONTROL: | 3247 | case SNDRV_PCM_MMAP_OFFSET_CONTROL: |
3277 | if (substream->no_mmap_ctrl) | 3248 | if (pcm_file->no_compat_mmap) |
3278 | return -ENXIO; | 3249 | return -ENXIO; |
3279 | return snd_pcm_mmap_control(substream, file, area); | 3250 | return snd_pcm_mmap_control(substream, file, area); |
3280 | default: | 3251 | default: |
diff --git a/sound/core/rawmidi.c b/sound/core/rawmidi.c index 8c15c66eb4aa..269c467ca9bb 100644 --- a/sound/core/rawmidi.c +++ b/sound/core/rawmidi.c | |||
@@ -55,7 +55,6 @@ static int snd_rawmidi_free(struct snd_rawmidi *rawmidi); | |||
55 | static int snd_rawmidi_dev_free(struct snd_device *device); | 55 | static int snd_rawmidi_dev_free(struct snd_device *device); |
56 | static int snd_rawmidi_dev_register(struct snd_device *device); | 56 | static int snd_rawmidi_dev_register(struct snd_device *device); |
57 | static int snd_rawmidi_dev_disconnect(struct snd_device *device); | 57 | static int snd_rawmidi_dev_disconnect(struct snd_device *device); |
58 | static int snd_rawmidi_dev_unregister(struct snd_device *device); | ||
59 | 58 | ||
60 | static LIST_HEAD(snd_rawmidi_devices); | 59 | static LIST_HEAD(snd_rawmidi_devices); |
61 | static DEFINE_MUTEX(register_mutex); | 60 | static DEFINE_MUTEX(register_mutex); |
@@ -431,7 +430,8 @@ static int snd_rawmidi_open(struct inode *inode, struct file *file) | |||
431 | kctl = snd_ctl_file(list); | 430 | kctl = snd_ctl_file(list); |
432 | if (kctl->pid == current->pid) { | 431 | if (kctl->pid == current->pid) { |
433 | subdevice = kctl->prefer_rawmidi_subdevice; | 432 | subdevice = kctl->prefer_rawmidi_subdevice; |
434 | break; | 433 | if (subdevice != -1) |
434 | break; | ||
435 | } | 435 | } |
436 | } | 436 | } |
437 | up_read(&card->controls_rwsem); | 437 | up_read(&card->controls_rwsem); |
@@ -1426,7 +1426,6 @@ int snd_rawmidi_new(struct snd_card *card, char *id, int device, | |||
1426 | .dev_free = snd_rawmidi_dev_free, | 1426 | .dev_free = snd_rawmidi_dev_free, |
1427 | .dev_register = snd_rawmidi_dev_register, | 1427 | .dev_register = snd_rawmidi_dev_register, |
1428 | .dev_disconnect = snd_rawmidi_dev_disconnect, | 1428 | .dev_disconnect = snd_rawmidi_dev_disconnect, |
1429 | .dev_unregister = snd_rawmidi_dev_unregister | ||
1430 | }; | 1429 | }; |
1431 | 1430 | ||
1432 | snd_assert(rrawmidi != NULL, return -EINVAL); | 1431 | snd_assert(rrawmidi != NULL, return -EINVAL); |
@@ -1479,6 +1478,14 @@ static void snd_rawmidi_free_substreams(struct snd_rawmidi_str *stream) | |||
1479 | static int snd_rawmidi_free(struct snd_rawmidi *rmidi) | 1478 | static int snd_rawmidi_free(struct snd_rawmidi *rmidi) |
1480 | { | 1479 | { |
1481 | snd_assert(rmidi != NULL, return -ENXIO); | 1480 | snd_assert(rmidi != NULL, return -ENXIO); |
1481 | |||
1482 | snd_info_free_entry(rmidi->proc_entry); | ||
1483 | rmidi->proc_entry = NULL; | ||
1484 | mutex_lock(®ister_mutex); | ||
1485 | if (rmidi->ops && rmidi->ops->dev_unregister) | ||
1486 | rmidi->ops->dev_unregister(rmidi); | ||
1487 | mutex_unlock(®ister_mutex); | ||
1488 | |||
1482 | snd_rawmidi_free_substreams(&rmidi->streams[SNDRV_RAWMIDI_STREAM_INPUT]); | 1489 | snd_rawmidi_free_substreams(&rmidi->streams[SNDRV_RAWMIDI_STREAM_INPUT]); |
1483 | snd_rawmidi_free_substreams(&rmidi->streams[SNDRV_RAWMIDI_STREAM_OUTPUT]); | 1490 | snd_rawmidi_free_substreams(&rmidi->streams[SNDRV_RAWMIDI_STREAM_OUTPUT]); |
1484 | if (rmidi->private_free) | 1491 | if (rmidi->private_free) |
@@ -1587,21 +1594,6 @@ static int snd_rawmidi_dev_disconnect(struct snd_device *device) | |||
1587 | 1594 | ||
1588 | mutex_lock(®ister_mutex); | 1595 | mutex_lock(®ister_mutex); |
1589 | list_del_init(&rmidi->list); | 1596 | list_del_init(&rmidi->list); |
1590 | mutex_unlock(®ister_mutex); | ||
1591 | return 0; | ||
1592 | } | ||
1593 | |||
1594 | static int snd_rawmidi_dev_unregister(struct snd_device *device) | ||
1595 | { | ||
1596 | struct snd_rawmidi *rmidi = device->device_data; | ||
1597 | |||
1598 | snd_assert(rmidi != NULL, return -ENXIO); | ||
1599 | mutex_lock(®ister_mutex); | ||
1600 | list_del(&rmidi->list); | ||
1601 | if (rmidi->proc_entry) { | ||
1602 | snd_info_unregister(rmidi->proc_entry); | ||
1603 | rmidi->proc_entry = NULL; | ||
1604 | } | ||
1605 | #ifdef CONFIG_SND_OSSEMUL | 1597 | #ifdef CONFIG_SND_OSSEMUL |
1606 | if (rmidi->ossreg) { | 1598 | if (rmidi->ossreg) { |
1607 | if ((int)rmidi->device == midi_map[rmidi->card->number]) { | 1599 | if ((int)rmidi->device == midi_map[rmidi->card->number]) { |
@@ -1615,17 +1607,9 @@ static int snd_rawmidi_dev_unregister(struct snd_device *device) | |||
1615 | rmidi->ossreg = 0; | 1607 | rmidi->ossreg = 0; |
1616 | } | 1608 | } |
1617 | #endif /* CONFIG_SND_OSSEMUL */ | 1609 | #endif /* CONFIG_SND_OSSEMUL */ |
1618 | if (rmidi->ops && rmidi->ops->dev_unregister) | ||
1619 | rmidi->ops->dev_unregister(rmidi); | ||
1620 | snd_unregister_device(SNDRV_DEVICE_TYPE_RAWMIDI, rmidi->card, rmidi->device); | 1610 | snd_unregister_device(SNDRV_DEVICE_TYPE_RAWMIDI, rmidi->card, rmidi->device); |
1621 | mutex_unlock(®ister_mutex); | 1611 | mutex_unlock(®ister_mutex); |
1622 | #if defined(CONFIG_SND_SEQUENCER) || (defined(MODULE) && defined(CONFIG_SND_SEQUENCER_MODULE)) | 1612 | return 0; |
1623 | if (rmidi->seq_dev) { | ||
1624 | snd_device_free(rmidi->card, rmidi->seq_dev); | ||
1625 | rmidi->seq_dev = NULL; | ||
1626 | } | ||
1627 | #endif | ||
1628 | return snd_rawmidi_free(rmidi); | ||
1629 | } | 1613 | } |
1630 | 1614 | ||
1631 | /** | 1615 | /** |
diff --git a/sound/core/rtctimer.c b/sound/core/rtctimer.c index 84704ccb1829..412dd62b654e 100644 --- a/sound/core/rtctimer.c +++ b/sound/core/rtctimer.c | |||
@@ -156,7 +156,7 @@ static int __init rtctimer_init(void) | |||
156 | static void __exit rtctimer_exit(void) | 156 | static void __exit rtctimer_exit(void) |
157 | { | 157 | { |
158 | if (rtctimer) { | 158 | if (rtctimer) { |
159 | snd_timer_global_unregister(rtctimer); | 159 | snd_timer_global_free(rtctimer); |
160 | rtctimer = NULL; | 160 | rtctimer = NULL; |
161 | } | 161 | } |
162 | } | 162 | } |
diff --git a/sound/core/seq/oss/seq_oss.c b/sound/core/seq/oss/seq_oss.c index e7234135641c..92858cf8b6eb 100644 --- a/sound/core/seq/oss/seq_oss.c +++ b/sound/core/seq/oss/seq_oss.c | |||
@@ -303,8 +303,7 @@ register_proc(void) | |||
303 | static void | 303 | static void |
304 | unregister_proc(void) | 304 | unregister_proc(void) |
305 | { | 305 | { |
306 | if (info_entry) | 306 | snd_info_free_entry(info_entry); |
307 | snd_info_unregister(info_entry); | ||
308 | info_entry = NULL; | 307 | info_entry = NULL; |
309 | } | 308 | } |
310 | #endif /* CONFIG_PROC_FS */ | 309 | #endif /* CONFIG_PROC_FS */ |
diff --git a/sound/core/seq/seq_device.c b/sound/core/seq/seq_device.c index 102ff548ce69..b79d011813c0 100644 --- a/sound/core/seq/seq_device.c +++ b/sound/core/seq/seq_device.c | |||
@@ -90,7 +90,6 @@ static int snd_seq_device_free(struct snd_seq_device *dev); | |||
90 | static int snd_seq_device_dev_free(struct snd_device *device); | 90 | static int snd_seq_device_dev_free(struct snd_device *device); |
91 | static int snd_seq_device_dev_register(struct snd_device *device); | 91 | static int snd_seq_device_dev_register(struct snd_device *device); |
92 | static int snd_seq_device_dev_disconnect(struct snd_device *device); | 92 | static int snd_seq_device_dev_disconnect(struct snd_device *device); |
93 | static int snd_seq_device_dev_unregister(struct snd_device *device); | ||
94 | 93 | ||
95 | static int init_device(struct snd_seq_device *dev, struct ops_list *ops); | 94 | static int init_device(struct snd_seq_device *dev, struct ops_list *ops); |
96 | static int free_device(struct snd_seq_device *dev, struct ops_list *ops); | 95 | static int free_device(struct snd_seq_device *dev, struct ops_list *ops); |
@@ -189,7 +188,6 @@ int snd_seq_device_new(struct snd_card *card, int device, char *id, int argsize, | |||
189 | .dev_free = snd_seq_device_dev_free, | 188 | .dev_free = snd_seq_device_dev_free, |
190 | .dev_register = snd_seq_device_dev_register, | 189 | .dev_register = snd_seq_device_dev_register, |
191 | .dev_disconnect = snd_seq_device_dev_disconnect, | 190 | .dev_disconnect = snd_seq_device_dev_disconnect, |
192 | .dev_unregister = snd_seq_device_dev_unregister | ||
193 | }; | 191 | }; |
194 | 192 | ||
195 | if (result) | 193 | if (result) |
@@ -309,15 +307,6 @@ static int snd_seq_device_dev_disconnect(struct snd_device *device) | |||
309 | } | 307 | } |
310 | 308 | ||
311 | /* | 309 | /* |
312 | * unregister the existing device | ||
313 | */ | ||
314 | static int snd_seq_device_dev_unregister(struct snd_device *device) | ||
315 | { | ||
316 | struct snd_seq_device *dev = device->device_data; | ||
317 | return snd_seq_device_free(dev); | ||
318 | } | ||
319 | |||
320 | /* | ||
321 | * register device driver | 310 | * register device driver |
322 | * id = driver id | 311 | * id = driver id |
323 | * entry = driver operators - duplicated to each instance | 312 | * entry = driver operators - duplicated to each instance |
@@ -573,7 +562,7 @@ static void __exit alsa_seq_device_exit(void) | |||
573 | { | 562 | { |
574 | remove_drivers(); | 563 | remove_drivers(); |
575 | #ifdef CONFIG_PROC_FS | 564 | #ifdef CONFIG_PROC_FS |
576 | snd_info_unregister(info_entry); | 565 | snd_info_free_entry(info_entry); |
577 | #endif | 566 | #endif |
578 | if (num_ops) | 567 | if (num_ops) |
579 | snd_printk(KERN_ERR "drivers not released (%d)\n", num_ops); | 568 | snd_printk(KERN_ERR "drivers not released (%d)\n", num_ops); |
diff --git a/sound/core/seq/seq_info.c b/sound/core/seq/seq_info.c index 142e9e6882c9..8a7fe5cca1c9 100644 --- a/sound/core/seq/seq_info.c +++ b/sound/core/seq/seq_info.c | |||
@@ -64,9 +64,9 @@ int __init snd_seq_info_init(void) | |||
64 | 64 | ||
65 | int __exit snd_seq_info_done(void) | 65 | int __exit snd_seq_info_done(void) |
66 | { | 66 | { |
67 | snd_info_unregister(queues_entry); | 67 | snd_info_free_entry(queues_entry); |
68 | snd_info_unregister(clients_entry); | 68 | snd_info_free_entry(clients_entry); |
69 | snd_info_unregister(timer_entry); | 69 | snd_info_free_entry(timer_entry); |
70 | return 0; | 70 | return 0; |
71 | } | 71 | } |
72 | #endif | 72 | #endif |
diff --git a/sound/core/sound.c b/sound/core/sound.c index 7edd1fc58b17..efa476c5210a 100644 --- a/sound/core/sound.c +++ b/sound/core/sound.c | |||
@@ -268,7 +268,11 @@ int snd_register_device(int type, struct snd_card *card, int dev, | |||
268 | snd_minors[minor] = preg; | 268 | snd_minors[minor] = preg; |
269 | if (card) | 269 | if (card) |
270 | device = card->dev; | 270 | device = card->dev; |
271 | class_device_create(sound_class, NULL, MKDEV(major, minor), device, "%s", name); | 271 | preg->class_dev = class_device_create(sound_class, NULL, |
272 | MKDEV(major, minor), | ||
273 | device, "%s", name); | ||
274 | if (preg->class_dev) | ||
275 | class_set_devdata(preg->class_dev, private_data); | ||
272 | 276 | ||
273 | mutex_unlock(&sound_mutex); | 277 | mutex_unlock(&sound_mutex); |
274 | return 0; | 278 | return 0; |
@@ -276,6 +280,24 @@ int snd_register_device(int type, struct snd_card *card, int dev, | |||
276 | 280 | ||
277 | EXPORT_SYMBOL(snd_register_device); | 281 | EXPORT_SYMBOL(snd_register_device); |
278 | 282 | ||
283 | /* find the matching minor record | ||
284 | * return the index of snd_minor, or -1 if not found | ||
285 | */ | ||
286 | static int find_snd_minor(int type, struct snd_card *card, int dev) | ||
287 | { | ||
288 | int cardnum, minor; | ||
289 | struct snd_minor *mptr; | ||
290 | |||
291 | cardnum = card ? card->number : -1; | ||
292 | for (minor = 0; minor < ARRAY_SIZE(snd_minors); ++minor) | ||
293 | if ((mptr = snd_minors[minor]) != NULL && | ||
294 | mptr->type == type && | ||
295 | mptr->card == cardnum && | ||
296 | mptr->device == dev) | ||
297 | return minor; | ||
298 | return -1; | ||
299 | } | ||
300 | |||
279 | /** | 301 | /** |
280 | * snd_unregister_device - unregister the device on the given card | 302 | * snd_unregister_device - unregister the device on the given card |
281 | * @type: the device type, SNDRV_DEVICE_TYPE_XXX | 303 | * @type: the device type, SNDRV_DEVICE_TYPE_XXX |
@@ -289,32 +311,42 @@ EXPORT_SYMBOL(snd_register_device); | |||
289 | */ | 311 | */ |
290 | int snd_unregister_device(int type, struct snd_card *card, int dev) | 312 | int snd_unregister_device(int type, struct snd_card *card, int dev) |
291 | { | 313 | { |
292 | int cardnum, minor; | 314 | int minor; |
293 | struct snd_minor *mptr; | ||
294 | 315 | ||
295 | cardnum = card ? card->number : -1; | ||
296 | mutex_lock(&sound_mutex); | 316 | mutex_lock(&sound_mutex); |
297 | for (minor = 0; minor < ARRAY_SIZE(snd_minors); ++minor) | 317 | minor = find_snd_minor(type, card, dev); |
298 | if ((mptr = snd_minors[minor]) != NULL && | 318 | if (minor < 0) { |
299 | mptr->type == type && | ||
300 | mptr->card == cardnum && | ||
301 | mptr->device == dev) | ||
302 | break; | ||
303 | if (minor == ARRAY_SIZE(snd_minors)) { | ||
304 | mutex_unlock(&sound_mutex); | 319 | mutex_unlock(&sound_mutex); |
305 | return -EINVAL; | 320 | return -EINVAL; |
306 | } | 321 | } |
307 | 322 | ||
308 | class_device_destroy(sound_class, MKDEV(major, minor)); | 323 | class_device_destroy(sound_class, MKDEV(major, minor)); |
309 | 324 | ||
325 | kfree(snd_minors[minor]); | ||
310 | snd_minors[minor] = NULL; | 326 | snd_minors[minor] = NULL; |
311 | mutex_unlock(&sound_mutex); | 327 | mutex_unlock(&sound_mutex); |
312 | kfree(mptr); | ||
313 | return 0; | 328 | return 0; |
314 | } | 329 | } |
315 | 330 | ||
316 | EXPORT_SYMBOL(snd_unregister_device); | 331 | EXPORT_SYMBOL(snd_unregister_device); |
317 | 332 | ||
333 | int snd_add_device_sysfs_file(int type, struct snd_card *card, int dev, | ||
334 | const struct class_device_attribute *attr) | ||
335 | { | ||
336 | int minor, ret = -EINVAL; | ||
337 | struct class_device *cdev; | ||
338 | |||
339 | mutex_lock(&sound_mutex); | ||
340 | minor = find_snd_minor(type, card, dev); | ||
341 | if (minor >= 0 && (cdev = snd_minors[minor]->class_dev) != NULL) | ||
342 | ret = class_device_create_file(cdev, attr); | ||
343 | mutex_unlock(&sound_mutex); | ||
344 | return ret; | ||
345 | |||
346 | } | ||
347 | |||
348 | EXPORT_SYMBOL(snd_add_device_sysfs_file); | ||
349 | |||
318 | #ifdef CONFIG_PROC_FS | 350 | #ifdef CONFIG_PROC_FS |
319 | /* | 351 | /* |
320 | * INFO PART | 352 | * INFO PART |
@@ -387,8 +419,7 @@ int __init snd_minor_info_init(void) | |||
387 | 419 | ||
388 | int __exit snd_minor_info_done(void) | 420 | int __exit snd_minor_info_done(void) |
389 | { | 421 | { |
390 | if (snd_minor_info_entry) | 422 | snd_info_free_entry(snd_minor_info_entry); |
391 | snd_info_unregister(snd_minor_info_entry); | ||
392 | return 0; | 423 | return 0; |
393 | } | 424 | } |
394 | #endif /* CONFIG_PROC_FS */ | 425 | #endif /* CONFIG_PROC_FS */ |
diff --git a/sound/core/sound_oss.c b/sound/core/sound_oss.c index 74f0fe5a1ba0..b2fc40aa520b 100644 --- a/sound/core/sound_oss.c +++ b/sound/core/sound_oss.c | |||
@@ -270,8 +270,7 @@ int __init snd_minor_info_oss_init(void) | |||
270 | 270 | ||
271 | int __exit snd_minor_info_oss_done(void) | 271 | int __exit snd_minor_info_oss_done(void) |
272 | { | 272 | { |
273 | if (snd_minor_info_oss_entry) | 273 | snd_info_free_entry(snd_minor_info_oss_entry); |
274 | snd_info_unregister(snd_minor_info_oss_entry); | ||
275 | return 0; | 274 | return 0; |
276 | } | 275 | } |
277 | #endif /* CONFIG_PROC_FS */ | 276 | #endif /* CONFIG_PROC_FS */ |
diff --git a/sound/core/timer.c b/sound/core/timer.c index 0a984e881c10..10a79aed33f8 100644 --- a/sound/core/timer.c +++ b/sound/core/timer.c | |||
@@ -88,7 +88,7 @@ static DEFINE_MUTEX(register_mutex); | |||
88 | static int snd_timer_free(struct snd_timer *timer); | 88 | static int snd_timer_free(struct snd_timer *timer); |
89 | static int snd_timer_dev_free(struct snd_device *device); | 89 | static int snd_timer_dev_free(struct snd_device *device); |
90 | static int snd_timer_dev_register(struct snd_device *device); | 90 | static int snd_timer_dev_register(struct snd_device *device); |
91 | static int snd_timer_dev_unregister(struct snd_device *device); | 91 | static int snd_timer_dev_disconnect(struct snd_device *device); |
92 | 92 | ||
93 | static void snd_timer_reschedule(struct snd_timer * timer, unsigned long ticks_left); | 93 | static void snd_timer_reschedule(struct snd_timer * timer, unsigned long ticks_left); |
94 | 94 | ||
@@ -718,7 +718,7 @@ void snd_timer_interrupt(struct snd_timer * timer, unsigned long ticks_left) | |||
718 | } | 718 | } |
719 | } | 719 | } |
720 | if (timer->flags & SNDRV_TIMER_FLG_RESCHED) | 720 | if (timer->flags & SNDRV_TIMER_FLG_RESCHED) |
721 | snd_timer_reschedule(timer, ticks_left); | 721 | snd_timer_reschedule(timer, timer->sticks); |
722 | if (timer->running) { | 722 | if (timer->running) { |
723 | if (timer->hw.flags & SNDRV_TIMER_HW_STOP) { | 723 | if (timer->hw.flags & SNDRV_TIMER_HW_STOP) { |
724 | timer->hw.stop(timer); | 724 | timer->hw.stop(timer); |
@@ -773,7 +773,7 @@ int snd_timer_new(struct snd_card *card, char *id, struct snd_timer_id *tid, | |||
773 | static struct snd_device_ops ops = { | 773 | static struct snd_device_ops ops = { |
774 | .dev_free = snd_timer_dev_free, | 774 | .dev_free = snd_timer_dev_free, |
775 | .dev_register = snd_timer_dev_register, | 775 | .dev_register = snd_timer_dev_register, |
776 | .dev_unregister = snd_timer_dev_unregister | 776 | .dev_disconnect = snd_timer_dev_disconnect, |
777 | }; | 777 | }; |
778 | 778 | ||
779 | snd_assert(tid != NULL, return -EINVAL); | 779 | snd_assert(tid != NULL, return -EINVAL); |
@@ -813,6 +813,21 @@ int snd_timer_new(struct snd_card *card, char *id, struct snd_timer_id *tid, | |||
813 | static int snd_timer_free(struct snd_timer *timer) | 813 | static int snd_timer_free(struct snd_timer *timer) |
814 | { | 814 | { |
815 | snd_assert(timer != NULL, return -ENXIO); | 815 | snd_assert(timer != NULL, return -ENXIO); |
816 | |||
817 | mutex_lock(®ister_mutex); | ||
818 | if (! list_empty(&timer->open_list_head)) { | ||
819 | struct list_head *p, *n; | ||
820 | struct snd_timer_instance *ti; | ||
821 | snd_printk(KERN_WARNING "timer %p is busy?\n", timer); | ||
822 | list_for_each_safe(p, n, &timer->open_list_head) { | ||
823 | list_del_init(p); | ||
824 | ti = list_entry(p, struct snd_timer_instance, open_list); | ||
825 | ti->timer = NULL; | ||
826 | } | ||
827 | } | ||
828 | list_del(&timer->device_list); | ||
829 | mutex_unlock(®ister_mutex); | ||
830 | |||
816 | if (timer->private_free) | 831 | if (timer->private_free) |
817 | timer->private_free(timer); | 832 | timer->private_free(timer); |
818 | kfree(timer); | 833 | kfree(timer); |
@@ -867,30 +882,13 @@ static int snd_timer_dev_register(struct snd_device *dev) | |||
867 | return 0; | 882 | return 0; |
868 | } | 883 | } |
869 | 884 | ||
870 | static int snd_timer_unregister(struct snd_timer *timer) | 885 | static int snd_timer_dev_disconnect(struct snd_device *device) |
871 | { | 886 | { |
872 | struct list_head *p, *n; | 887 | struct snd_timer *timer = device->device_data; |
873 | struct snd_timer_instance *ti; | ||
874 | |||
875 | snd_assert(timer != NULL, return -ENXIO); | ||
876 | mutex_lock(®ister_mutex); | 888 | mutex_lock(®ister_mutex); |
877 | if (! list_empty(&timer->open_list_head)) { | 889 | list_del_init(&timer->device_list); |
878 | snd_printk(KERN_WARNING "timer 0x%lx is busy?\n", (long)timer); | ||
879 | list_for_each_safe(p, n, &timer->open_list_head) { | ||
880 | list_del_init(p); | ||
881 | ti = list_entry(p, struct snd_timer_instance, open_list); | ||
882 | ti->timer = NULL; | ||
883 | } | ||
884 | } | ||
885 | list_del(&timer->device_list); | ||
886 | mutex_unlock(®ister_mutex); | 890 | mutex_unlock(®ister_mutex); |
887 | return snd_timer_free(timer); | 891 | return 0; |
888 | } | ||
889 | |||
890 | static int snd_timer_dev_unregister(struct snd_device *device) | ||
891 | { | ||
892 | struct snd_timer *timer = device->device_data; | ||
893 | return snd_timer_unregister(timer); | ||
894 | } | 892 | } |
895 | 893 | ||
896 | void snd_timer_notify(struct snd_timer *timer, int event, struct timespec *tstamp) | 894 | void snd_timer_notify(struct snd_timer *timer, int event, struct timespec *tstamp) |
@@ -955,18 +953,12 @@ int snd_timer_global_register(struct snd_timer *timer) | |||
955 | return snd_timer_dev_register(&dev); | 953 | return snd_timer_dev_register(&dev); |
956 | } | 954 | } |
957 | 955 | ||
958 | int snd_timer_global_unregister(struct snd_timer *timer) | ||
959 | { | ||
960 | return snd_timer_unregister(timer); | ||
961 | } | ||
962 | |||
963 | /* | 956 | /* |
964 | * System timer | 957 | * System timer |
965 | */ | 958 | */ |
966 | 959 | ||
967 | struct snd_timer_system_private { | 960 | struct snd_timer_system_private { |
968 | struct timer_list tlist; | 961 | struct timer_list tlist; |
969 | struct timer * timer; | ||
970 | unsigned long last_expires; | 962 | unsigned long last_expires; |
971 | unsigned long last_jiffies; | 963 | unsigned long last_jiffies; |
972 | unsigned long correction; | 964 | unsigned long correction; |
@@ -978,7 +970,7 @@ static void snd_timer_s_function(unsigned long data) | |||
978 | struct snd_timer_system_private *priv = timer->private_data; | 970 | struct snd_timer_system_private *priv = timer->private_data; |
979 | unsigned long jiff = jiffies; | 971 | unsigned long jiff = jiffies; |
980 | if (time_after(jiff, priv->last_expires)) | 972 | if (time_after(jiff, priv->last_expires)) |
981 | priv->correction = (long)jiff - (long)priv->last_expires; | 973 | priv->correction += (long)jiff - (long)priv->last_expires; |
982 | snd_timer_interrupt(timer, (long)jiff - (long)priv->last_jiffies); | 974 | snd_timer_interrupt(timer, (long)jiff - (long)priv->last_jiffies); |
983 | } | 975 | } |
984 | 976 | ||
@@ -994,7 +986,7 @@ static int snd_timer_s_start(struct snd_timer * timer) | |||
994 | njiff++; | 986 | njiff++; |
995 | } else { | 987 | } else { |
996 | njiff += timer->sticks - priv->correction; | 988 | njiff += timer->sticks - priv->correction; |
997 | priv->correction -= timer->sticks; | 989 | priv->correction = 0; |
998 | } | 990 | } |
999 | priv->last_expires = priv->tlist.expires = njiff; | 991 | priv->last_expires = priv->tlist.expires = njiff; |
1000 | add_timer(&priv->tlist); | 992 | add_timer(&priv->tlist); |
@@ -1013,6 +1005,7 @@ static int snd_timer_s_stop(struct snd_timer * timer) | |||
1013 | timer->sticks = priv->last_expires - jiff; | 1005 | timer->sticks = priv->last_expires - jiff; |
1014 | else | 1006 | else |
1015 | timer->sticks = 1; | 1007 | timer->sticks = 1; |
1008 | priv->correction = 0; | ||
1016 | return 0; | 1009 | return 0; |
1017 | } | 1010 | } |
1018 | 1011 | ||
@@ -1126,7 +1119,7 @@ static void __init snd_timer_proc_init(void) | |||
1126 | 1119 | ||
1127 | static void __exit snd_timer_proc_done(void) | 1120 | static void __exit snd_timer_proc_done(void) |
1128 | { | 1121 | { |
1129 | snd_info_unregister(snd_timer_proc_entry); | 1122 | snd_info_free_entry(snd_timer_proc_entry); |
1130 | } | 1123 | } |
1131 | #else /* !CONFIG_PROC_FS */ | 1124 | #else /* !CONFIG_PROC_FS */ |
1132 | #define snd_timer_proc_init() | 1125 | #define snd_timer_proc_init() |
@@ -1982,7 +1975,7 @@ static void __exit alsa_timer_exit(void) | |||
1982 | /* unregister the system timer */ | 1975 | /* unregister the system timer */ |
1983 | list_for_each_safe(p, n, &snd_timer_list) { | 1976 | list_for_each_safe(p, n, &snd_timer_list) { |
1984 | struct snd_timer *timer = list_entry(p, struct snd_timer, device_list); | 1977 | struct snd_timer *timer = list_entry(p, struct snd_timer, device_list); |
1985 | snd_timer_unregister(timer); | 1978 | snd_timer_free(timer); |
1986 | } | 1979 | } |
1987 | snd_timer_proc_done(); | 1980 | snd_timer_proc_done(); |
1988 | #ifdef SNDRV_OSS_INFO_DEV_TIMERS | 1981 | #ifdef SNDRV_OSS_INFO_DEV_TIMERS |
@@ -2005,5 +1998,4 @@ EXPORT_SYMBOL(snd_timer_notify); | |||
2005 | EXPORT_SYMBOL(snd_timer_global_new); | 1998 | EXPORT_SYMBOL(snd_timer_global_new); |
2006 | EXPORT_SYMBOL(snd_timer_global_free); | 1999 | EXPORT_SYMBOL(snd_timer_global_free); |
2007 | EXPORT_SYMBOL(snd_timer_global_register); | 2000 | EXPORT_SYMBOL(snd_timer_global_register); |
2008 | EXPORT_SYMBOL(snd_timer_global_unregister); | ||
2009 | EXPORT_SYMBOL(snd_timer_interrupt); | 2001 | EXPORT_SYMBOL(snd_timer_interrupt); |
diff --git a/sound/drivers/Kconfig b/sound/drivers/Kconfig index 395c4ef52ac9..7971285dfd5b 100644 --- a/sound/drivers/Kconfig +++ b/sound/drivers/Kconfig | |||
@@ -73,6 +73,19 @@ config SND_MTPAV | |||
73 | To compile this driver as a module, choose M here: the module | 73 | To compile this driver as a module, choose M here: the module |
74 | will be called snd-mtpav. | 74 | will be called snd-mtpav. |
75 | 75 | ||
76 | config SND_MTS64 | ||
77 | tristate "ESI Miditerminal 4140 driver" | ||
78 | depends on SND && PARPORT | ||
79 | select SND_RAWMIDI | ||
80 | help | ||
81 | The ESI Miditerminal 4140 is a 4 In 4 Out MIDI Interface with | ||
82 | additional SMPTE Timecode capabilities for the parallel port. | ||
83 | |||
84 | Say 'Y' to include support for this device. | ||
85 | |||
86 | To compile this driver as a module, chose 'M' here: the module | ||
87 | will be called snd-mts64. | ||
88 | |||
76 | config SND_SERIAL_U16550 | 89 | config SND_SERIAL_U16550 |
77 | tristate "UART16550 serial MIDI driver" | 90 | tristate "UART16550 serial MIDI driver" |
78 | depends on SND | 91 | depends on SND |
diff --git a/sound/drivers/Makefile b/sound/drivers/Makefile index cb98c3d662be..c9bad6d67e73 100644 --- a/sound/drivers/Makefile +++ b/sound/drivers/Makefile | |||
@@ -5,6 +5,7 @@ | |||
5 | 5 | ||
6 | snd-dummy-objs := dummy.o | 6 | snd-dummy-objs := dummy.o |
7 | snd-mtpav-objs := mtpav.o | 7 | snd-mtpav-objs := mtpav.o |
8 | snd-mts64-objs := mts64.o | ||
8 | snd-serial-u16550-objs := serial-u16550.o | 9 | snd-serial-u16550-objs := serial-u16550.o |
9 | snd-virmidi-objs := virmidi.o | 10 | snd-virmidi-objs := virmidi.o |
10 | 11 | ||
@@ -13,5 +14,6 @@ obj-$(CONFIG_SND_DUMMY) += snd-dummy.o | |||
13 | obj-$(CONFIG_SND_VIRMIDI) += snd-virmidi.o | 14 | obj-$(CONFIG_SND_VIRMIDI) += snd-virmidi.o |
14 | obj-$(CONFIG_SND_SERIAL_U16550) += snd-serial-u16550.o | 15 | obj-$(CONFIG_SND_SERIAL_U16550) += snd-serial-u16550.o |
15 | obj-$(CONFIG_SND_MTPAV) += snd-mtpav.o | 16 | obj-$(CONFIG_SND_MTPAV) += snd-mtpav.o |
17 | obj-$(CONFIG_SND_MTS64) += snd-mts64.o | ||
16 | 18 | ||
17 | obj-$(CONFIG_SND) += opl3/ opl4/ mpu401/ vx/ | 19 | obj-$(CONFIG_SND) += opl3/ opl4/ mpu401/ vx/ |
diff --git a/sound/drivers/dummy.c b/sound/drivers/dummy.c index ffeafaf2ecca..42001efa9f3e 100644 --- a/sound/drivers/dummy.c +++ b/sound/drivers/dummy.c | |||
@@ -29,6 +29,7 @@ | |||
29 | #include <linux/moduleparam.h> | 29 | #include <linux/moduleparam.h> |
30 | #include <sound/core.h> | 30 | #include <sound/core.h> |
31 | #include <sound/control.h> | 31 | #include <sound/control.h> |
32 | #include <sound/tlv.h> | ||
32 | #include <sound/pcm.h> | 33 | #include <sound/pcm.h> |
33 | #include <sound/rawmidi.h> | 34 | #include <sound/rawmidi.h> |
34 | #include <sound/initval.h> | 35 | #include <sound/initval.h> |
@@ -285,7 +286,7 @@ static struct snd_pcm_hardware snd_card_dummy_playback = | |||
285 | .channels_max = USE_CHANNELS_MAX, | 286 | .channels_max = USE_CHANNELS_MAX, |
286 | .buffer_bytes_max = MAX_BUFFER_SIZE, | 287 | .buffer_bytes_max = MAX_BUFFER_SIZE, |
287 | .period_bytes_min = 64, | 288 | .period_bytes_min = 64, |
288 | .period_bytes_max = MAX_BUFFER_SIZE, | 289 | .period_bytes_max = MAX_PERIOD_SIZE, |
289 | .periods_min = USE_PERIODS_MIN, | 290 | .periods_min = USE_PERIODS_MIN, |
290 | .periods_max = USE_PERIODS_MAX, | 291 | .periods_max = USE_PERIODS_MAX, |
291 | .fifo_size = 0, | 292 | .fifo_size = 0, |
@@ -443,10 +444,13 @@ static int __init snd_card_dummy_pcm(struct snd_dummy *dummy, int device, int su | |||
443 | } | 444 | } |
444 | 445 | ||
445 | #define DUMMY_VOLUME(xname, xindex, addr) \ | 446 | #define DUMMY_VOLUME(xname, xindex, addr) \ |
446 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \ | 447 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ |
448 | .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ, \ | ||
449 | .name = xname, .index = xindex, \ | ||
447 | .info = snd_dummy_volume_info, \ | 450 | .info = snd_dummy_volume_info, \ |
448 | .get = snd_dummy_volume_get, .put = snd_dummy_volume_put, \ | 451 | .get = snd_dummy_volume_get, .put = snd_dummy_volume_put, \ |
449 | .private_value = addr } | 452 | .private_value = addr, \ |
453 | .tlv = { .p = db_scale_dummy } } | ||
450 | 454 | ||
451 | static int snd_dummy_volume_info(struct snd_kcontrol *kcontrol, | 455 | static int snd_dummy_volume_info(struct snd_kcontrol *kcontrol, |
452 | struct snd_ctl_elem_info *uinfo) | 456 | struct snd_ctl_elem_info *uinfo) |
@@ -497,6 +501,8 @@ static int snd_dummy_volume_put(struct snd_kcontrol *kcontrol, | |||
497 | return change; | 501 | return change; |
498 | } | 502 | } |
499 | 503 | ||
504 | static DECLARE_TLV_DB_SCALE(db_scale_dummy, -4500, 30, 0); | ||
505 | |||
500 | #define DUMMY_CAPSRC(xname, xindex, addr) \ | 506 | #define DUMMY_CAPSRC(xname, xindex, addr) \ |
501 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \ | 507 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \ |
502 | .info = snd_dummy_capsrc_info, \ | 508 | .info = snd_dummy_capsrc_info, \ |
@@ -547,13 +553,13 @@ static struct snd_kcontrol_new snd_dummy_controls[] = { | |||
547 | DUMMY_VOLUME("Master Volume", 0, MIXER_ADDR_MASTER), | 553 | DUMMY_VOLUME("Master Volume", 0, MIXER_ADDR_MASTER), |
548 | DUMMY_CAPSRC("Master Capture Switch", 0, MIXER_ADDR_MASTER), | 554 | DUMMY_CAPSRC("Master Capture Switch", 0, MIXER_ADDR_MASTER), |
549 | DUMMY_VOLUME("Synth Volume", 0, MIXER_ADDR_SYNTH), | 555 | DUMMY_VOLUME("Synth Volume", 0, MIXER_ADDR_SYNTH), |
550 | DUMMY_CAPSRC("Synth Capture Switch", 0, MIXER_ADDR_MASTER), | 556 | DUMMY_CAPSRC("Synth Capture Switch", 0, MIXER_ADDR_SYNTH), |
551 | DUMMY_VOLUME("Line Volume", 0, MIXER_ADDR_LINE), | 557 | DUMMY_VOLUME("Line Volume", 0, MIXER_ADDR_LINE), |
552 | DUMMY_CAPSRC("Line Capture Switch", 0, MIXER_ADDR_MASTER), | 558 | DUMMY_CAPSRC("Line Capture Switch", 0, MIXER_ADDR_LINE), |
553 | DUMMY_VOLUME("Mic Volume", 0, MIXER_ADDR_MIC), | 559 | DUMMY_VOLUME("Mic Volume", 0, MIXER_ADDR_MIC), |
554 | DUMMY_CAPSRC("Mic Capture Switch", 0, MIXER_ADDR_MASTER), | 560 | DUMMY_CAPSRC("Mic Capture Switch", 0, MIXER_ADDR_MIC), |
555 | DUMMY_VOLUME("CD Volume", 0, MIXER_ADDR_CD), | 561 | DUMMY_VOLUME("CD Volume", 0, MIXER_ADDR_CD), |
556 | DUMMY_CAPSRC("CD Capture Switch", 0, MIXER_ADDR_MASTER) | 562 | DUMMY_CAPSRC("CD Capture Switch", 0, MIXER_ADDR_CD) |
557 | }; | 563 | }; |
558 | 564 | ||
559 | static int __init snd_card_dummy_new_mixer(struct snd_dummy *dummy) | 565 | static int __init snd_card_dummy_new_mixer(struct snd_dummy *dummy) |
diff --git a/sound/drivers/mpu401/mpu401.c b/sound/drivers/mpu401/mpu401.c index 17cc105b26fc..2de181ad0b05 100644 --- a/sound/drivers/mpu401/mpu401.c +++ b/sound/drivers/mpu401/mpu401.c | |||
@@ -211,7 +211,7 @@ static void __devexit snd_mpu401_pnp_remove(struct pnp_dev *dev) | |||
211 | struct snd_card *card = (struct snd_card *) pnp_get_drvdata(dev); | 211 | struct snd_card *card = (struct snd_card *) pnp_get_drvdata(dev); |
212 | 212 | ||
213 | snd_card_disconnect(card); | 213 | snd_card_disconnect(card); |
214 | snd_card_free_in_thread(card); | 214 | snd_card_free_when_closed(card); |
215 | } | 215 | } |
216 | 216 | ||
217 | static struct pnp_driver snd_mpu401_pnp_driver = { | 217 | static struct pnp_driver snd_mpu401_pnp_driver = { |
diff --git a/sound/drivers/mts64.c b/sound/drivers/mts64.c new file mode 100644 index 000000000000..169987302ae4 --- /dev/null +++ b/sound/drivers/mts64.c | |||
@@ -0,0 +1,1091 @@ | |||
1 | /* | ||
2 | * ALSA Driver for Ego Systems Inc. (ESI) Miditerminal 4140 | ||
3 | * Copyright (c) 2006 by Matthias König <mk@phasorlab.de> | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or modify | ||
6 | * it under the terms of the GNU General Public License as published by | ||
7 | * the Free Software Foundation; either version 2 of the License, or | ||
8 | * (at your option) any later version. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | * GNU General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License | ||
16 | * along with this program; if not, write to the Free Software | ||
17 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | ||
18 | * | ||
19 | */ | ||
20 | |||
21 | #include <sound/driver.h> | ||
22 | #include <linux/init.h> | ||
23 | #include <linux/platform_device.h> | ||
24 | #include <linux/parport.h> | ||
25 | #include <linux/spinlock.h> | ||
26 | #include <linux/delay.h> | ||
27 | #include <sound/core.h> | ||
28 | #include <sound/initval.h> | ||
29 | #include <sound/rawmidi.h> | ||
30 | #include <sound/control.h> | ||
31 | |||
32 | #define CARD_NAME "Miditerminal 4140" | ||
33 | #define DRIVER_NAME "MTS64" | ||
34 | #define PLATFORM_DRIVER "snd_mts64" | ||
35 | |||
36 | static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; | ||
37 | static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; | ||
38 | static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP; | ||
39 | |||
40 | static struct platform_device *platform_devices[SNDRV_CARDS]; | ||
41 | static int device_count; | ||
42 | |||
43 | module_param_array(index, int, NULL, S_IRUGO); | ||
44 | MODULE_PARM_DESC(index, "Index value for " CARD_NAME " soundcard."); | ||
45 | module_param_array(id, charp, NULL, S_IRUGO); | ||
46 | MODULE_PARM_DESC(id, "ID string for " CARD_NAME " soundcard."); | ||
47 | module_param_array(enable, bool, NULL, S_IRUGO); | ||
48 | MODULE_PARM_DESC(enable, "Enable " CARD_NAME " soundcard."); | ||
49 | |||
50 | MODULE_AUTHOR("Matthias Koenig <mk@phasorlab.de>"); | ||
51 | MODULE_DESCRIPTION("ESI Miditerminal 4140"); | ||
52 | MODULE_LICENSE("GPL"); | ||
53 | MODULE_SUPPORTED_DEVICE("{{ESI,Miditerminal 4140}}"); | ||
54 | |||
55 | /********************************************************************* | ||
56 | * Chip specific | ||
57 | *********************************************************************/ | ||
58 | #define MTS64_NUM_INPUT_PORTS 5 | ||
59 | #define MTS64_NUM_OUTPUT_PORTS 4 | ||
60 | #define MTS64_SMPTE_SUBSTREAM 4 | ||
61 | |||
62 | struct mts64 { | ||
63 | spinlock_t lock; | ||
64 | struct snd_card *card; | ||
65 | struct snd_rawmidi *rmidi; | ||
66 | struct pardevice *pardev; | ||
67 | int pardev_claimed; | ||
68 | |||
69 | int open_count; | ||
70 | int current_midi_output_port; | ||
71 | int current_midi_input_port; | ||
72 | u8 mode[MTS64_NUM_INPUT_PORTS]; | ||
73 | struct snd_rawmidi_substream *midi_input_substream[MTS64_NUM_INPUT_PORTS]; | ||
74 | int smpte_switch; | ||
75 | u8 time[4]; /* [0]=hh, [1]=mm, [2]=ss, [3]=ff */ | ||
76 | u8 fps; | ||
77 | }; | ||
78 | |||
79 | static int snd_mts64_free(struct mts64 *mts) | ||
80 | { | ||
81 | kfree(mts); | ||
82 | return 0; | ||
83 | } | ||
84 | |||
85 | static int __devinit snd_mts64_create(struct snd_card *card, | ||
86 | struct pardevice *pardev, | ||
87 | struct mts64 **rchip) | ||
88 | { | ||
89 | struct mts64 *mts; | ||
90 | |||
91 | *rchip = NULL; | ||
92 | |||
93 | mts = kzalloc(sizeof(struct mts64), GFP_KERNEL); | ||
94 | if (mts == NULL) | ||
95 | return -ENOMEM; | ||
96 | |||
97 | /* Init chip specific data */ | ||
98 | spin_lock_init(&mts->lock); | ||
99 | mts->card = card; | ||
100 | mts->pardev = pardev; | ||
101 | mts->current_midi_output_port = -1; | ||
102 | mts->current_midi_input_port = -1; | ||
103 | |||
104 | *rchip = mts; | ||
105 | |||
106 | return 0; | ||
107 | } | ||
108 | |||
109 | /********************************************************************* | ||
110 | * HW register related constants | ||
111 | *********************************************************************/ | ||
112 | |||
113 | /* Status Bits */ | ||
114 | #define MTS64_STAT_BSY 0x80 | ||
115 | #define MTS64_STAT_BIT_SET 0x20 /* readout process, bit is set */ | ||
116 | #define MTS64_STAT_PORT 0x10 /* read byte is a port number */ | ||
117 | |||
118 | /* Control Bits */ | ||
119 | #define MTS64_CTL_READOUT 0x08 /* enable readout */ | ||
120 | #define MTS64_CTL_WRITE_CMD 0x06 | ||
121 | #define MTS64_CTL_WRITE_DATA 0x02 | ||
122 | #define MTS64_CTL_STROBE 0x01 | ||
123 | |||
124 | /* Command */ | ||
125 | #define MTS64_CMD_RESET 0xfe | ||
126 | #define MTS64_CMD_PROBE 0x8f /* Used in probing procedure */ | ||
127 | #define MTS64_CMD_SMPTE_SET_TIME 0xe8 | ||
128 | #define MTS64_CMD_SMPTE_SET_FPS 0xee | ||
129 | #define MTS64_CMD_SMPTE_STOP 0xef | ||
130 | #define MTS64_CMD_SMPTE_FPS_24 0xe3 | ||
131 | #define MTS64_CMD_SMPTE_FPS_25 0xe2 | ||
132 | #define MTS64_CMD_SMPTE_FPS_2997 0xe4 | ||
133 | #define MTS64_CMD_SMPTE_FPS_30D 0xe1 | ||
134 | #define MTS64_CMD_SMPTE_FPS_30 0xe0 | ||
135 | #define MTS64_CMD_COM_OPEN 0xf8 /* setting the communication mode */ | ||
136 | #define MTS64_CMD_COM_CLOSE1 0xff /* clearing communication mode */ | ||
137 | #define MTS64_CMD_COM_CLOSE2 0xf5 | ||
138 | |||
139 | /********************************************************************* | ||
140 | * Hardware specific functions | ||
141 | *********************************************************************/ | ||
142 | static void mts64_enable_readout(struct parport *p); | ||
143 | static void mts64_disable_readout(struct parport *p); | ||
144 | static int mts64_device_ready(struct parport *p); | ||
145 | static int mts64_device_init(struct parport *p); | ||
146 | static int mts64_device_open(struct mts64 *mts); | ||
147 | static int mts64_device_close(struct mts64 *mts); | ||
148 | static u8 mts64_map_midi_input(u8 c); | ||
149 | static int mts64_probe(struct parport *p); | ||
150 | static u16 mts64_read(struct parport *p); | ||
151 | static u8 mts64_read_char(struct parport *p); | ||
152 | static void mts64_smpte_start(struct parport *p, | ||
153 | u8 hours, u8 minutes, | ||
154 | u8 seconds, u8 frames, | ||
155 | u8 idx); | ||
156 | static void mts64_smpte_stop(struct parport *p); | ||
157 | static void mts64_write_command(struct parport *p, u8 c); | ||
158 | static void mts64_write_data(struct parport *p, u8 c); | ||
159 | static void mts64_write_midi(struct mts64 *mts, u8 c, int midiport); | ||
160 | |||
161 | |||
162 | /* Enables the readout procedure | ||
163 | * | ||
164 | * Before we can read a midi byte from the device, we have to set | ||
165 | * bit 3 of control port. | ||
166 | */ | ||
167 | static void mts64_enable_readout(struct parport *p) | ||
168 | { | ||
169 | u8 c; | ||
170 | |||
171 | c = parport_read_control(p); | ||
172 | c |= MTS64_CTL_READOUT; | ||
173 | parport_write_control(p, c); | ||
174 | } | ||
175 | |||
176 | /* Disables readout | ||
177 | * | ||
178 | * Readout is disabled by clearing bit 3 of control | ||
179 | */ | ||
180 | static void mts64_disable_readout(struct parport *p) | ||
181 | { | ||
182 | u8 c; | ||
183 | |||
184 | c = parport_read_control(p); | ||
185 | c &= ~MTS64_CTL_READOUT; | ||
186 | parport_write_control(p, c); | ||
187 | } | ||
188 | |||
189 | /* waits for device ready | ||
190 | * | ||
191 | * Checks if BUSY (Bit 7 of status) is clear | ||
192 | * 1 device ready | ||
193 | * 0 failure | ||
194 | */ | ||
195 | static int mts64_device_ready(struct parport *p) | ||
196 | { | ||
197 | int i; | ||
198 | u8 c; | ||
199 | |||
200 | for (i = 0; i < 0xffff; ++i) { | ||
201 | c = parport_read_status(p); | ||
202 | c &= MTS64_STAT_BSY; | ||
203 | if (c != 0) | ||
204 | return 1; | ||
205 | } | ||
206 | |||
207 | return 0; | ||
208 | } | ||
209 | |||
210 | /* Init device (LED blinking startup magic) | ||
211 | * | ||
212 | * Returns: | ||
213 | * 0 init ok | ||
214 | * -EIO failure | ||
215 | */ | ||
216 | static int __devinit mts64_device_init(struct parport *p) | ||
217 | { | ||
218 | int i; | ||
219 | |||
220 | mts64_write_command(p, MTS64_CMD_RESET); | ||
221 | |||
222 | for (i = 0; i < 64; ++i) { | ||
223 | msleep(100); | ||
224 | |||
225 | if (mts64_probe(p) == 0) { | ||
226 | /* success */ | ||
227 | mts64_disable_readout(p); | ||
228 | return 0; | ||
229 | } | ||
230 | } | ||
231 | mts64_disable_readout(p); | ||
232 | |||
233 | return -EIO; | ||
234 | } | ||
235 | |||
236 | /* | ||
237 | * Opens the device (set communication mode) | ||
238 | */ | ||
239 | static int mts64_device_open(struct mts64 *mts) | ||
240 | { | ||
241 | int i; | ||
242 | struct parport *p = mts->pardev->port; | ||
243 | |||
244 | for (i = 0; i < 5; ++i) | ||
245 | mts64_write_command(p, MTS64_CMD_COM_OPEN); | ||
246 | |||
247 | return 0; | ||
248 | } | ||
249 | |||
250 | /* | ||
251 | * Close device (clear communication mode) | ||
252 | */ | ||
253 | static int mts64_device_close(struct mts64 *mts) | ||
254 | { | ||
255 | int i; | ||
256 | struct parport *p = mts->pardev->port; | ||
257 | |||
258 | for (i = 0; i < 5; ++i) { | ||
259 | mts64_write_command(p, MTS64_CMD_COM_CLOSE1); | ||
260 | mts64_write_command(p, MTS64_CMD_COM_CLOSE2); | ||
261 | } | ||
262 | |||
263 | return 0; | ||
264 | } | ||
265 | |||
266 | /* map hardware port to substream number | ||
267 | * | ||
268 | * When reading a byte from the device, the device tells us | ||
269 | * on what port the byte is. This HW port has to be mapped to | ||
270 | * the midiport (substream number). | ||
271 | * substream 0-3 are Midiports 1-4 | ||
272 | * substream 4 is SMPTE Timecode | ||
273 | * The mapping is done by the table: | ||
274 | * HW | 0 | 1 | 2 | 3 | 4 | ||
275 | * SW | 0 | 1 | 4 | 2 | 3 | ||
276 | */ | ||
277 | static u8 mts64_map_midi_input(u8 c) | ||
278 | { | ||
279 | static u8 map[] = { 0, 1, 4, 2, 3 }; | ||
280 | |||
281 | return map[c]; | ||
282 | } | ||
283 | |||
284 | |||
285 | /* Probe parport for device | ||
286 | * | ||
287 | * Do we have a Miditerminal 4140 on parport? | ||
288 | * Returns: | ||
289 | * 0 device found | ||
290 | * -ENODEV no device | ||
291 | */ | ||
292 | static int __devinit mts64_probe(struct parport *p) | ||
293 | { | ||
294 | u8 c; | ||
295 | |||
296 | mts64_smpte_stop(p); | ||
297 | mts64_write_command(p, MTS64_CMD_PROBE); | ||
298 | |||
299 | msleep(50); | ||
300 | |||
301 | c = mts64_read(p); | ||
302 | |||
303 | c &= 0x00ff; | ||
304 | if (c != MTS64_CMD_PROBE) | ||
305 | return -ENODEV; | ||
306 | else | ||
307 | return 0; | ||
308 | |||
309 | } | ||
310 | |||
311 | /* Read byte incl. status from device | ||
312 | * | ||
313 | * Returns: | ||
314 | * data in lower 8 bits and status in upper 8 bits | ||
315 | */ | ||
316 | static u16 mts64_read(struct parport *p) | ||
317 | { | ||
318 | u8 data, status; | ||
319 | |||
320 | mts64_device_ready(p); | ||
321 | mts64_enable_readout(p); | ||
322 | status = parport_read_status(p); | ||
323 | data = mts64_read_char(p); | ||
324 | mts64_disable_readout(p); | ||
325 | |||
326 | return (status << 8) | data; | ||
327 | } | ||
328 | |||
329 | /* Read a byte from device | ||
330 | * | ||
331 | * Note, that readout mode has to be enabled. | ||
332 | * readout procedure is as follows: | ||
333 | * - Write number of the Bit to read to DATA | ||
334 | * - Read STATUS | ||
335 | * - Bit 5 of STATUS indicates if Bit is set | ||
336 | * | ||
337 | * Returns: | ||
338 | * Byte read from device | ||
339 | */ | ||
340 | static u8 mts64_read_char(struct parport *p) | ||
341 | { | ||
342 | u8 c = 0; | ||
343 | u8 status; | ||
344 | u8 i; | ||
345 | |||
346 | for (i = 0; i < 8; ++i) { | ||
347 | parport_write_data(p, i); | ||
348 | c >>= 1; | ||
349 | status = parport_read_status(p); | ||
350 | if (status & MTS64_STAT_BIT_SET) | ||
351 | c |= 0x80; | ||
352 | } | ||
353 | |||
354 | return c; | ||
355 | } | ||
356 | |||
357 | /* Starts SMPTE Timecode generation | ||
358 | * | ||
359 | * The device creates SMPTE Timecode by hardware. | ||
360 | * 0 24 fps | ||
361 | * 1 25 fps | ||
362 | * 2 29.97 fps | ||
363 | * 3 30 fps (Drop-frame) | ||
364 | * 4 30 fps | ||
365 | */ | ||
366 | static void mts64_smpte_start(struct parport *p, | ||
367 | u8 hours, u8 minutes, | ||
368 | u8 seconds, u8 frames, | ||
369 | u8 idx) | ||
370 | { | ||
371 | static u8 fps[5] = { MTS64_CMD_SMPTE_FPS_24, | ||
372 | MTS64_CMD_SMPTE_FPS_25, | ||
373 | MTS64_CMD_SMPTE_FPS_2997, | ||
374 | MTS64_CMD_SMPTE_FPS_30D, | ||
375 | MTS64_CMD_SMPTE_FPS_30 }; | ||
376 | |||
377 | mts64_write_command(p, MTS64_CMD_SMPTE_SET_TIME); | ||
378 | mts64_write_command(p, frames); | ||
379 | mts64_write_command(p, seconds); | ||
380 | mts64_write_command(p, minutes); | ||
381 | mts64_write_command(p, hours); | ||
382 | |||
383 | mts64_write_command(p, MTS64_CMD_SMPTE_SET_FPS); | ||
384 | mts64_write_command(p, fps[idx]); | ||
385 | } | ||
386 | |||
387 | /* Stops SMPTE Timecode generation | ||
388 | */ | ||
389 | static void mts64_smpte_stop(struct parport *p) | ||
390 | { | ||
391 | mts64_write_command(p, MTS64_CMD_SMPTE_STOP); | ||
392 | } | ||
393 | |||
394 | /* Write a command byte to device | ||
395 | */ | ||
396 | static void mts64_write_command(struct parport *p, u8 c) | ||
397 | { | ||
398 | mts64_device_ready(p); | ||
399 | |||
400 | parport_write_data(p, c); | ||
401 | |||
402 | parport_write_control(p, MTS64_CTL_WRITE_CMD); | ||
403 | parport_write_control(p, MTS64_CTL_WRITE_CMD | MTS64_CTL_STROBE); | ||
404 | parport_write_control(p, MTS64_CTL_WRITE_CMD); | ||
405 | } | ||
406 | |||
407 | /* Write a data byte to device | ||
408 | */ | ||
409 | static void mts64_write_data(struct parport *p, u8 c) | ||
410 | { | ||
411 | mts64_device_ready(p); | ||
412 | |||
413 | parport_write_data(p, c); | ||
414 | |||
415 | parport_write_control(p, MTS64_CTL_WRITE_DATA); | ||
416 | parport_write_control(p, MTS64_CTL_WRITE_DATA | MTS64_CTL_STROBE); | ||
417 | parport_write_control(p, MTS64_CTL_WRITE_DATA); | ||
418 | } | ||
419 | |||
420 | /* Write a MIDI byte to midiport | ||
421 | * | ||
422 | * midiport ranges from 0-3 and maps to Ports 1-4 | ||
423 | * assumptions: communication mode is on | ||
424 | */ | ||
425 | static void mts64_write_midi(struct mts64 *mts, u8 c, | ||
426 | int midiport) | ||
427 | { | ||
428 | struct parport *p = mts->pardev->port; | ||
429 | |||
430 | /* check current midiport */ | ||
431 | if (mts->current_midi_output_port != midiport) | ||
432 | mts64_write_command(p, midiport); | ||
433 | |||
434 | /* write midi byte */ | ||
435 | mts64_write_data(p, c); | ||
436 | } | ||
437 | |||
438 | /********************************************************************* | ||
439 | * Control elements | ||
440 | *********************************************************************/ | ||
441 | |||
442 | /* SMPTE Switch */ | ||
443 | static int snd_mts64_ctl_smpte_switch_info(struct snd_kcontrol *kctl, | ||
444 | struct snd_ctl_elem_info *uinfo) | ||
445 | { | ||
446 | uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; | ||
447 | uinfo->count = 1; | ||
448 | uinfo->value.integer.min = 0; | ||
449 | uinfo->value.integer.max = 1; | ||
450 | return 0; | ||
451 | } | ||
452 | |||
453 | static int snd_mts64_ctl_smpte_switch_get(struct snd_kcontrol* kctl, | ||
454 | struct snd_ctl_elem_value *uctl) | ||
455 | { | ||
456 | struct mts64 *mts = snd_kcontrol_chip(kctl); | ||
457 | |||
458 | spin_lock_irq(&mts->lock); | ||
459 | uctl->value.integer.value[0] = mts->smpte_switch; | ||
460 | spin_unlock_irq(&mts->lock); | ||
461 | |||
462 | return 0; | ||
463 | } | ||
464 | |||
465 | /* smpte_switch is not accessed from IRQ handler, so we just need | ||
466 | to protect the HW access */ | ||
467 | static int snd_mts64_ctl_smpte_switch_put(struct snd_kcontrol* kctl, | ||
468 | struct snd_ctl_elem_value *uctl) | ||
469 | { | ||
470 | struct mts64 *mts = snd_kcontrol_chip(kctl); | ||
471 | int changed = 0; | ||
472 | |||
473 | spin_lock_irq(&mts->lock); | ||
474 | if (mts->smpte_switch == uctl->value.integer.value[0]) | ||
475 | goto __out; | ||
476 | |||
477 | changed = 1; | ||
478 | mts->smpte_switch = uctl->value.integer.value[0]; | ||
479 | if (mts->smpte_switch) { | ||
480 | mts64_smpte_start(mts->pardev->port, | ||
481 | mts->time[0], mts->time[1], | ||
482 | mts->time[2], mts->time[3], | ||
483 | mts->fps); | ||
484 | } else { | ||
485 | mts64_smpte_stop(mts->pardev->port); | ||
486 | } | ||
487 | __out: | ||
488 | spin_unlock_irq(&mts->lock); | ||
489 | return changed; | ||
490 | } | ||
491 | |||
492 | static struct snd_kcontrol_new mts64_ctl_smpte_switch __devinitdata = { | ||
493 | .iface = SNDRV_CTL_ELEM_IFACE_RAWMIDI, | ||
494 | .name = "SMPTE Playback Switch", | ||
495 | .index = 0, | ||
496 | .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, | ||
497 | .private_value = 0, | ||
498 | .info = snd_mts64_ctl_smpte_switch_info, | ||
499 | .get = snd_mts64_ctl_smpte_switch_get, | ||
500 | .put = snd_mts64_ctl_smpte_switch_put | ||
501 | }; | ||
502 | |||
503 | /* Time */ | ||
504 | static int snd_mts64_ctl_smpte_time_h_info(struct snd_kcontrol *kctl, | ||
505 | struct snd_ctl_elem_info *uinfo) | ||
506 | { | ||
507 | uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; | ||
508 | uinfo->count = 1; | ||
509 | uinfo->value.integer.min = 0; | ||
510 | uinfo->value.integer.max = 23; | ||
511 | return 0; | ||
512 | } | ||
513 | |||
514 | static int snd_mts64_ctl_smpte_time_f_info(struct snd_kcontrol *kctl, | ||
515 | struct snd_ctl_elem_info *uinfo) | ||
516 | { | ||
517 | uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; | ||
518 | uinfo->count = 1; | ||
519 | uinfo->value.integer.min = 0; | ||
520 | uinfo->value.integer.max = 99; | ||
521 | return 0; | ||
522 | } | ||
523 | |||
524 | static int snd_mts64_ctl_smpte_time_info(struct snd_kcontrol *kctl, | ||
525 | struct snd_ctl_elem_info *uinfo) | ||
526 | { | ||
527 | uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; | ||
528 | uinfo->count = 1; | ||
529 | uinfo->value.integer.min = 0; | ||
530 | uinfo->value.integer.max = 59; | ||
531 | return 0; | ||
532 | } | ||
533 | |||
534 | static int snd_mts64_ctl_smpte_time_get(struct snd_kcontrol *kctl, | ||
535 | struct snd_ctl_elem_value *uctl) | ||
536 | { | ||
537 | struct mts64 *mts = snd_kcontrol_chip(kctl); | ||
538 | int idx = kctl->private_value; | ||
539 | |||
540 | spin_lock_irq(&mts->lock); | ||
541 | uctl->value.integer.value[0] = mts->time[idx]; | ||
542 | spin_unlock_irq(&mts->lock); | ||
543 | |||
544 | return 0; | ||
545 | } | ||
546 | |||
547 | static int snd_mts64_ctl_smpte_time_put(struct snd_kcontrol *kctl, | ||
548 | struct snd_ctl_elem_value *uctl) | ||
549 | { | ||
550 | struct mts64 *mts = snd_kcontrol_chip(kctl); | ||
551 | int idx = kctl->private_value; | ||
552 | int changed = 0; | ||
553 | |||
554 | spin_lock_irq(&mts->lock); | ||
555 | if (mts->time[idx] != uctl->value.integer.value[0]) { | ||
556 | changed = 1; | ||
557 | mts->time[idx] = uctl->value.integer.value[0]; | ||
558 | } | ||
559 | spin_unlock_irq(&mts->lock); | ||
560 | |||
561 | return changed; | ||
562 | } | ||
563 | |||
564 | static struct snd_kcontrol_new mts64_ctl_smpte_time_hours __devinitdata = { | ||
565 | .iface = SNDRV_CTL_ELEM_IFACE_RAWMIDI, | ||
566 | .name = "SMPTE Time Hours", | ||
567 | .index = 0, | ||
568 | .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, | ||
569 | .private_value = 0, | ||
570 | .info = snd_mts64_ctl_smpte_time_h_info, | ||
571 | .get = snd_mts64_ctl_smpte_time_get, | ||
572 | .put = snd_mts64_ctl_smpte_time_put | ||
573 | }; | ||
574 | |||
575 | static struct snd_kcontrol_new mts64_ctl_smpte_time_minutes __devinitdata = { | ||
576 | .iface = SNDRV_CTL_ELEM_IFACE_RAWMIDI, | ||
577 | .name = "SMPTE Time Minutes", | ||
578 | .index = 0, | ||
579 | .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, | ||
580 | .private_value = 1, | ||
581 | .info = snd_mts64_ctl_smpte_time_info, | ||
582 | .get = snd_mts64_ctl_smpte_time_get, | ||
583 | .put = snd_mts64_ctl_smpte_time_put | ||
584 | }; | ||
585 | |||
586 | static struct snd_kcontrol_new mts64_ctl_smpte_time_seconds __devinitdata = { | ||
587 | .iface = SNDRV_CTL_ELEM_IFACE_RAWMIDI, | ||
588 | .name = "SMPTE Time Seconds", | ||
589 | .index = 0, | ||
590 | .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, | ||
591 | .private_value = 2, | ||
592 | .info = snd_mts64_ctl_smpte_time_info, | ||
593 | .get = snd_mts64_ctl_smpte_time_get, | ||
594 | .put = snd_mts64_ctl_smpte_time_put | ||
595 | }; | ||
596 | |||
597 | static struct snd_kcontrol_new mts64_ctl_smpte_time_frames __devinitdata = { | ||
598 | .iface = SNDRV_CTL_ELEM_IFACE_RAWMIDI, | ||
599 | .name = "SMPTE Time Frames", | ||
600 | .index = 0, | ||
601 | .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, | ||
602 | .private_value = 3, | ||
603 | .info = snd_mts64_ctl_smpte_time_f_info, | ||
604 | .get = snd_mts64_ctl_smpte_time_get, | ||
605 | .put = snd_mts64_ctl_smpte_time_put | ||
606 | }; | ||
607 | |||
608 | /* FPS */ | ||
609 | static int snd_mts64_ctl_smpte_fps_info(struct snd_kcontrol *kctl, | ||
610 | struct snd_ctl_elem_info *uinfo) | ||
611 | { | ||
612 | static char *texts[5] = { "24", | ||
613 | "25", | ||
614 | "29.97", | ||
615 | "30D", | ||
616 | "30" }; | ||
617 | |||
618 | uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; | ||
619 | uinfo->count = 1; | ||
620 | uinfo->value.enumerated.items = 5; | ||
621 | if (uinfo->value.enumerated.item > 4) | ||
622 | uinfo->value.enumerated.item = 4; | ||
623 | strcpy(uinfo->value.enumerated.name, | ||
624 | texts[uinfo->value.enumerated.item]); | ||
625 | |||
626 | return 0; | ||
627 | } | ||
628 | |||
629 | static int snd_mts64_ctl_smpte_fps_get(struct snd_kcontrol *kctl, | ||
630 | struct snd_ctl_elem_value *uctl) | ||
631 | { | ||
632 | struct mts64 *mts = snd_kcontrol_chip(kctl); | ||
633 | |||
634 | spin_lock_irq(&mts->lock); | ||
635 | uctl->value.enumerated.item[0] = mts->fps; | ||
636 | spin_unlock_irq(&mts->lock); | ||
637 | |||
638 | return 0; | ||
639 | } | ||
640 | |||
641 | static int snd_mts64_ctl_smpte_fps_put(struct snd_kcontrol *kctl, | ||
642 | struct snd_ctl_elem_value *uctl) | ||
643 | { | ||
644 | struct mts64 *mts = snd_kcontrol_chip(kctl); | ||
645 | int changed = 0; | ||
646 | |||
647 | spin_lock_irq(&mts->lock); | ||
648 | if (mts->fps != uctl->value.enumerated.item[0]) { | ||
649 | changed = 1; | ||
650 | mts->fps = uctl->value.enumerated.item[0]; | ||
651 | } | ||
652 | spin_unlock_irq(&mts->lock); | ||
653 | |||
654 | return changed; | ||
655 | } | ||
656 | |||
657 | static struct snd_kcontrol_new mts64_ctl_smpte_fps __devinitdata = { | ||
658 | .iface = SNDRV_CTL_ELEM_IFACE_RAWMIDI, | ||
659 | .name = "SMPTE Fps", | ||
660 | .index = 0, | ||
661 | .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, | ||
662 | .private_value = 0, | ||
663 | .info = snd_mts64_ctl_smpte_fps_info, | ||
664 | .get = snd_mts64_ctl_smpte_fps_get, | ||
665 | .put = snd_mts64_ctl_smpte_fps_put | ||
666 | }; | ||
667 | |||
668 | |||
669 | static int __devinit snd_mts64_ctl_create(struct snd_card *card, | ||
670 | struct mts64 *mts) | ||
671 | { | ||
672 | int err, i; | ||
673 | static struct snd_kcontrol_new *control[] = { | ||
674 | &mts64_ctl_smpte_switch, | ||
675 | &mts64_ctl_smpte_time_hours, | ||
676 | &mts64_ctl_smpte_time_minutes, | ||
677 | &mts64_ctl_smpte_time_seconds, | ||
678 | &mts64_ctl_smpte_time_frames, | ||
679 | &mts64_ctl_smpte_fps, | ||
680 | 0 }; | ||
681 | |||
682 | for (i = 0; control[i]; ++i) { | ||
683 | err = snd_ctl_add(card, snd_ctl_new1(control[i], mts)); | ||
684 | if (err < 0) { | ||
685 | snd_printd("Cannot create control: %s\n", | ||
686 | control[i]->name); | ||
687 | return err; | ||
688 | } | ||
689 | } | ||
690 | |||
691 | return 0; | ||
692 | } | ||
693 | |||
694 | /********************************************************************* | ||
695 | * Rawmidi | ||
696 | *********************************************************************/ | ||
697 | #define MTS64_MODE_INPUT_TRIGGERED 0x01 | ||
698 | |||
699 | static int snd_mts64_rawmidi_open(struct snd_rawmidi_substream *substream) | ||
700 | { | ||
701 | struct mts64 *mts = substream->rmidi->private_data; | ||
702 | |||
703 | if (mts->open_count == 0) { | ||
704 | /* We don't need a spinlock here, because this is just called | ||
705 | if the device has not been opened before. | ||
706 | So there aren't any IRQs from the device */ | ||
707 | mts64_device_open(mts); | ||
708 | |||
709 | msleep(50); | ||
710 | } | ||
711 | ++(mts->open_count); | ||
712 | |||
713 | return 0; | ||
714 | } | ||
715 | |||
716 | static int snd_mts64_rawmidi_close(struct snd_rawmidi_substream *substream) | ||
717 | { | ||
718 | struct mts64 *mts = substream->rmidi->private_data; | ||
719 | unsigned long flags; | ||
720 | |||
721 | --(mts->open_count); | ||
722 | if (mts->open_count == 0) { | ||
723 | /* We need the spinlock_irqsave here because we can still | ||
724 | have IRQs at this point */ | ||
725 | spin_lock_irqsave(&mts->lock, flags); | ||
726 | mts64_device_close(mts); | ||
727 | spin_unlock_irqrestore(&mts->lock, flags); | ||
728 | |||
729 | msleep(500); | ||
730 | |||
731 | } else if (mts->open_count < 0) | ||
732 | mts->open_count = 0; | ||
733 | |||
734 | return 0; | ||
735 | } | ||
736 | |||
737 | static void snd_mts64_rawmidi_output_trigger(struct snd_rawmidi_substream *substream, | ||
738 | int up) | ||
739 | { | ||
740 | struct mts64 *mts = substream->rmidi->private_data; | ||
741 | u8 data; | ||
742 | unsigned long flags; | ||
743 | |||
744 | spin_lock_irqsave(&mts->lock, flags); | ||
745 | while (snd_rawmidi_transmit_peek(substream, &data, 1) == 1) { | ||
746 | mts64_write_midi(mts, data, substream->number+1); | ||
747 | snd_rawmidi_transmit_ack(substream, 1); | ||
748 | } | ||
749 | spin_unlock_irqrestore(&mts->lock, flags); | ||
750 | } | ||
751 | |||
752 | static void snd_mts64_rawmidi_input_trigger(struct snd_rawmidi_substream *substream, | ||
753 | int up) | ||
754 | { | ||
755 | struct mts64 *mts = substream->rmidi->private_data; | ||
756 | unsigned long flags; | ||
757 | |||
758 | spin_lock_irqsave(&mts->lock, flags); | ||
759 | if (up) | ||
760 | mts->mode[substream->number] |= MTS64_MODE_INPUT_TRIGGERED; | ||
761 | else | ||
762 | mts->mode[substream->number] &= ~MTS64_MODE_INPUT_TRIGGERED; | ||
763 | |||
764 | spin_unlock_irqrestore(&mts->lock, flags); | ||
765 | } | ||
766 | |||
767 | static struct snd_rawmidi_ops snd_mts64_rawmidi_output_ops = { | ||
768 | .open = snd_mts64_rawmidi_open, | ||
769 | .close = snd_mts64_rawmidi_close, | ||
770 | .trigger = snd_mts64_rawmidi_output_trigger | ||
771 | }; | ||
772 | |||
773 | static struct snd_rawmidi_ops snd_mts64_rawmidi_input_ops = { | ||
774 | .open = snd_mts64_rawmidi_open, | ||
775 | .close = snd_mts64_rawmidi_close, | ||
776 | .trigger = snd_mts64_rawmidi_input_trigger | ||
777 | }; | ||
778 | |||
779 | /* Create and initialize the rawmidi component */ | ||
780 | static int __devinit snd_mts64_rawmidi_create(struct snd_card *card) | ||
781 | { | ||
782 | struct mts64 *mts = card->private_data; | ||
783 | struct snd_rawmidi *rmidi; | ||
784 | struct snd_rawmidi_substream *substream; | ||
785 | struct list_head *list; | ||
786 | int err; | ||
787 | |||
788 | err = snd_rawmidi_new(card, CARD_NAME, 0, | ||
789 | MTS64_NUM_OUTPUT_PORTS, | ||
790 | MTS64_NUM_INPUT_PORTS, | ||
791 | &rmidi); | ||
792 | if (err < 0) | ||
793 | return err; | ||
794 | |||
795 | rmidi->private_data = mts; | ||
796 | strcpy(rmidi->name, CARD_NAME); | ||
797 | rmidi->info_flags = SNDRV_RAWMIDI_INFO_OUTPUT | | ||
798 | SNDRV_RAWMIDI_INFO_INPUT | | ||
799 | SNDRV_RAWMIDI_INFO_DUPLEX; | ||
800 | |||
801 | mts->rmidi = rmidi; | ||
802 | |||
803 | /* register rawmidi ops */ | ||
804 | snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT, | ||
805 | &snd_mts64_rawmidi_output_ops); | ||
806 | snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_INPUT, | ||
807 | &snd_mts64_rawmidi_input_ops); | ||
808 | |||
809 | /* name substreams */ | ||
810 | /* output */ | ||
811 | list_for_each(list, | ||
812 | &rmidi->streams[SNDRV_RAWMIDI_STREAM_OUTPUT].substreams) { | ||
813 | substream = list_entry(list, struct snd_rawmidi_substream, list); | ||
814 | sprintf(substream->name, | ||
815 | "Miditerminal %d", substream->number+1); | ||
816 | } | ||
817 | /* input */ | ||
818 | list_for_each(list, | ||
819 | &rmidi->streams[SNDRV_RAWMIDI_STREAM_INPUT].substreams) { | ||
820 | substream = list_entry(list, struct snd_rawmidi_substream, list); | ||
821 | mts->midi_input_substream[substream->number] = substream; | ||
822 | switch(substream->number) { | ||
823 | case MTS64_SMPTE_SUBSTREAM: | ||
824 | strcpy(substream->name, "Miditerminal SMPTE"); | ||
825 | break; | ||
826 | default: | ||
827 | sprintf(substream->name, | ||
828 | "Miditerminal %d", substream->number+1); | ||
829 | } | ||
830 | } | ||
831 | |||
832 | /* controls */ | ||
833 | err = snd_mts64_ctl_create(card, mts); | ||
834 | |||
835 | return err; | ||
836 | } | ||
837 | |||
838 | /********************************************************************* | ||
839 | * parport stuff | ||
840 | *********************************************************************/ | ||
841 | static void snd_mts64_interrupt(int irq, void *private, struct pt_regs *r) | ||
842 | { | ||
843 | struct mts64 *mts = ((struct snd_card*)private)->private_data; | ||
844 | u16 ret; | ||
845 | u8 status, data; | ||
846 | struct snd_rawmidi_substream *substream; | ||
847 | |||
848 | spin_lock(&mts->lock); | ||
849 | ret = mts64_read(mts->pardev->port); | ||
850 | data = ret & 0x00ff; | ||
851 | status = ret >> 8; | ||
852 | |||
853 | if (status & MTS64_STAT_PORT) { | ||
854 | mts->current_midi_input_port = mts64_map_midi_input(data); | ||
855 | } else { | ||
856 | if (mts->current_midi_input_port == -1) | ||
857 | goto __out; | ||
858 | substream = mts->midi_input_substream[mts->current_midi_input_port]; | ||
859 | if (mts->mode[substream->number] & MTS64_MODE_INPUT_TRIGGERED) | ||
860 | snd_rawmidi_receive(substream, &data, 1); | ||
861 | } | ||
862 | __out: | ||
863 | spin_unlock(&mts->lock); | ||
864 | } | ||
865 | |||
866 | static int __devinit snd_mts64_probe_port(struct parport *p) | ||
867 | { | ||
868 | struct pardevice *pardev; | ||
869 | int res; | ||
870 | |||
871 | pardev = parport_register_device(p, DRIVER_NAME, | ||
872 | NULL, NULL, NULL, | ||
873 | 0, NULL); | ||
874 | if (!pardev) | ||
875 | return -EIO; | ||
876 | |||
877 | if (parport_claim(pardev)) { | ||
878 | parport_unregister_device(pardev); | ||
879 | return -EIO; | ||
880 | } | ||
881 | |||
882 | res = mts64_probe(p); | ||
883 | |||
884 | parport_release(pardev); | ||
885 | parport_unregister_device(pardev); | ||
886 | |||
887 | return res; | ||
888 | } | ||
889 | |||
890 | static void __devinit snd_mts64_attach(struct parport *p) | ||
891 | { | ||
892 | struct platform_device *device; | ||
893 | |||
894 | device = platform_device_alloc(PLATFORM_DRIVER, device_count); | ||
895 | if (!device) | ||
896 | return; | ||
897 | |||
898 | /* Temporary assignment to forward the parport */ | ||
899 | platform_set_drvdata(device, p); | ||
900 | |||
901 | if (platform_device_register(device) < 0) { | ||
902 | platform_device_put(device); | ||
903 | return; | ||
904 | } | ||
905 | |||
906 | /* Since we dont get the return value of probe | ||
907 | * We need to check if device probing succeeded or not */ | ||
908 | if (!platform_get_drvdata(device)) { | ||
909 | platform_device_unregister(device); | ||
910 | return; | ||
911 | } | ||
912 | |||
913 | /* register device in global table */ | ||
914 | platform_devices[device_count] = device; | ||
915 | device_count++; | ||
916 | } | ||
917 | |||
918 | static void snd_mts64_detach(struct parport *p) | ||
919 | { | ||
920 | /* nothing to do here */ | ||
921 | } | ||
922 | |||
923 | static struct parport_driver mts64_parport_driver = { | ||
924 | .name = "mts64", | ||
925 | .attach = snd_mts64_attach, | ||
926 | .detach = snd_mts64_detach | ||
927 | }; | ||
928 | |||
929 | /********************************************************************* | ||
930 | * platform stuff | ||
931 | *********************************************************************/ | ||
932 | static void snd_mts64_card_private_free(struct snd_card *card) | ||
933 | { | ||
934 | struct mts64 *mts = card->private_data; | ||
935 | struct pardevice *pardev = mts->pardev; | ||
936 | |||
937 | if (pardev) { | ||
938 | if (mts->pardev_claimed) | ||
939 | parport_release(pardev); | ||
940 | parport_unregister_device(pardev); | ||
941 | } | ||
942 | |||
943 | snd_mts64_free(mts); | ||
944 | } | ||
945 | |||
946 | static int __devinit snd_mts64_probe(struct platform_device *pdev) | ||
947 | { | ||
948 | struct pardevice *pardev; | ||
949 | struct parport *p; | ||
950 | int dev = pdev->id; | ||
951 | struct snd_card *card = NULL; | ||
952 | struct mts64 *mts = NULL; | ||
953 | int err; | ||
954 | |||
955 | p = platform_get_drvdata(pdev); | ||
956 | platform_set_drvdata(pdev, NULL); | ||
957 | |||
958 | if (dev >= SNDRV_CARDS) | ||
959 | return -ENODEV; | ||
960 | if (!enable[dev]) | ||
961 | return -ENOENT; | ||
962 | if ((err = snd_mts64_probe_port(p)) < 0) | ||
963 | return err; | ||
964 | |||
965 | card = snd_card_new(index[dev], id[dev], THIS_MODULE, 0); | ||
966 | if (card == NULL) { | ||
967 | snd_printd("Cannot create card\n"); | ||
968 | return -ENOMEM; | ||
969 | } | ||
970 | strcpy(card->driver, DRIVER_NAME); | ||
971 | strcpy(card->shortname, "ESI " CARD_NAME); | ||
972 | sprintf(card->longname, "%s at 0x%lx, irq %i", | ||
973 | card->shortname, p->base, p->irq); | ||
974 | |||
975 | pardev = parport_register_device(p, /* port */ | ||
976 | DRIVER_NAME, /* name */ | ||
977 | NULL, /* preempt */ | ||
978 | NULL, /* wakeup */ | ||
979 | snd_mts64_interrupt, /* ISR */ | ||
980 | PARPORT_DEV_EXCL, /* flags */ | ||
981 | (void *)card); /* private */ | ||
982 | if (pardev == NULL) { | ||
983 | snd_printd("Cannot register pardevice\n"); | ||
984 | err = -EIO; | ||
985 | goto __err; | ||
986 | } | ||
987 | |||
988 | if ((err = snd_mts64_create(card, pardev, &mts)) < 0) { | ||
989 | snd_printd("Cannot create main component\n"); | ||
990 | parport_unregister_device(pardev); | ||
991 | goto __err; | ||
992 | } | ||
993 | card->private_data = mts; | ||
994 | card->private_free = snd_mts64_card_private_free; | ||
995 | |||
996 | if ((err = snd_mts64_rawmidi_create(card)) < 0) { | ||
997 | snd_printd("Creating Rawmidi component failed\n"); | ||
998 | goto __err; | ||
999 | } | ||
1000 | |||
1001 | /* claim parport */ | ||
1002 | if (parport_claim(pardev)) { | ||
1003 | snd_printd("Cannot claim parport 0x%lx\n", pardev->port->base); | ||
1004 | err = -EIO; | ||
1005 | goto __err; | ||
1006 | } | ||
1007 | mts->pardev_claimed = 1; | ||
1008 | |||
1009 | /* init device */ | ||
1010 | if ((err = mts64_device_init(p)) < 0) | ||
1011 | goto __err; | ||
1012 | |||
1013 | platform_set_drvdata(pdev, card); | ||
1014 | |||
1015 | /* At this point card will be usable */ | ||
1016 | if ((err = snd_card_register(card)) < 0) { | ||
1017 | snd_printd("Cannot register card\n"); | ||
1018 | goto __err; | ||
1019 | } | ||
1020 | |||
1021 | snd_printk("ESI Miditerminal 4140 on 0x%lx\n", p->base); | ||
1022 | return 0; | ||
1023 | |||
1024 | __err: | ||
1025 | snd_card_free(card); | ||
1026 | return err; | ||
1027 | } | ||
1028 | |||
1029 | static int snd_mts64_remove(struct platform_device *pdev) | ||
1030 | { | ||
1031 | struct snd_card *card = platform_get_drvdata(pdev); | ||
1032 | |||
1033 | if (card) | ||
1034 | snd_card_free(card); | ||
1035 | |||
1036 | return 0; | ||
1037 | } | ||
1038 | |||
1039 | |||
1040 | static struct platform_driver snd_mts64_driver = { | ||
1041 | .probe = snd_mts64_probe, | ||
1042 | .remove = snd_mts64_remove, | ||
1043 | .driver = { | ||
1044 | .name = PLATFORM_DRIVER | ||
1045 | } | ||
1046 | }; | ||
1047 | |||
1048 | /********************************************************************* | ||
1049 | * module init stuff | ||
1050 | *********************************************************************/ | ||
1051 | static void snd_mts64_unregister_all(void) | ||
1052 | { | ||
1053 | int i; | ||
1054 | |||
1055 | for (i = 0; i < SNDRV_CARDS; ++i) { | ||
1056 | if (platform_devices[i]) { | ||
1057 | platform_device_unregister(platform_devices[i]); | ||
1058 | platform_devices[i] = NULL; | ||
1059 | } | ||
1060 | } | ||
1061 | platform_driver_unregister(&snd_mts64_driver); | ||
1062 | parport_unregister_driver(&mts64_parport_driver); | ||
1063 | } | ||
1064 | |||
1065 | static int __init snd_mts64_module_init(void) | ||
1066 | { | ||
1067 | int err; | ||
1068 | |||
1069 | if ((err = platform_driver_register(&snd_mts64_driver)) < 0) | ||
1070 | return err; | ||
1071 | |||
1072 | if (parport_register_driver(&mts64_parport_driver) != 0) { | ||
1073 | platform_driver_unregister(&snd_mts64_driver); | ||
1074 | return -EIO; | ||
1075 | } | ||
1076 | |||
1077 | if (device_count == 0) { | ||
1078 | snd_mts64_unregister_all(); | ||
1079 | return -ENODEV; | ||
1080 | } | ||
1081 | |||
1082 | return 0; | ||
1083 | } | ||
1084 | |||
1085 | static void __exit snd_mts64_module_exit(void) | ||
1086 | { | ||
1087 | snd_mts64_unregister_all(); | ||
1088 | } | ||
1089 | |||
1090 | module_init(snd_mts64_module_init); | ||
1091 | module_exit(snd_mts64_module_exit); | ||
diff --git a/sound/drivers/opl4/opl4_proc.c b/sound/drivers/opl4/opl4_proc.c index e552ec34166f..1679300b7583 100644 --- a/sound/drivers/opl4/opl4_proc.c +++ b/sound/drivers/opl4/opl4_proc.c | |||
@@ -105,13 +105,13 @@ static long long snd_opl4_mem_proc_llseek(struct snd_info_entry *entry, void *fi | |||
105 | struct file *file, long long offset, int orig) | 105 | struct file *file, long long offset, int orig) |
106 | { | 106 | { |
107 | switch (orig) { | 107 | switch (orig) { |
108 | case 0: /* SEEK_SET */ | 108 | case SEEK_SET: |
109 | file->f_pos = offset; | 109 | file->f_pos = offset; |
110 | break; | 110 | break; |
111 | case 1: /* SEEK_CUR */ | 111 | case SEEK_CUR: |
112 | file->f_pos += offset; | 112 | file->f_pos += offset; |
113 | break; | 113 | break; |
114 | case 2: /* SEEK_END, offset is negative */ | 114 | case SEEK_END: /* offset is negative */ |
115 | file->f_pos = entry->size + offset; | 115 | file->f_pos = entry->size + offset; |
116 | break; | 116 | break; |
117 | default: | 117 | default: |
@@ -159,8 +159,7 @@ int snd_opl4_create_proc(struct snd_opl4 *opl4) | |||
159 | 159 | ||
160 | void snd_opl4_free_proc(struct snd_opl4 *opl4) | 160 | void snd_opl4_free_proc(struct snd_opl4 *opl4) |
161 | { | 161 | { |
162 | if (opl4->proc_entry) | 162 | snd_info_free_entry(opl4->proc_entry); |
163 | snd_info_unregister(opl4->proc_entry); | ||
164 | } | 163 | } |
165 | 164 | ||
166 | #endif /* CONFIG_PROC_FS */ | 165 | #endif /* CONFIG_PROC_FS */ |
diff --git a/sound/drivers/vx/vx_mixer.c b/sound/drivers/vx/vx_mixer.c index c1d7fcdd1973..1613ed844ac6 100644 --- a/sound/drivers/vx/vx_mixer.c +++ b/sound/drivers/vx/vx_mixer.c | |||
@@ -23,6 +23,7 @@ | |||
23 | #include <sound/driver.h> | 23 | #include <sound/driver.h> |
24 | #include <sound/core.h> | 24 | #include <sound/core.h> |
25 | #include <sound/control.h> | 25 | #include <sound/control.h> |
26 | #include <sound/tlv.h> | ||
26 | #include <sound/vx_core.h> | 27 | #include <sound/vx_core.h> |
27 | #include "vx_cmd.h" | 28 | #include "vx_cmd.h" |
28 | 29 | ||
@@ -455,10 +456,13 @@ static int vx_output_level_put(struct snd_kcontrol *kcontrol, struct snd_ctl_ele | |||
455 | 456 | ||
456 | static struct snd_kcontrol_new vx_control_output_level = { | 457 | static struct snd_kcontrol_new vx_control_output_level = { |
457 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 458 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
459 | .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | | ||
460 | SNDRV_CTL_ELEM_ACCESS_TLV_READ), | ||
458 | .name = "Master Playback Volume", | 461 | .name = "Master Playback Volume", |
459 | .info = vx_output_level_info, | 462 | .info = vx_output_level_info, |
460 | .get = vx_output_level_get, | 463 | .get = vx_output_level_get, |
461 | .put = vx_output_level_put, | 464 | .put = vx_output_level_put, |
465 | /* tlv will be filled later */ | ||
462 | }; | 466 | }; |
463 | 467 | ||
464 | /* | 468 | /* |
@@ -712,12 +716,17 @@ static int vx_monitor_sw_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_ | |||
712 | return 0; | 716 | return 0; |
713 | } | 717 | } |
714 | 718 | ||
719 | static DECLARE_TLV_DB_SCALE(db_scale_audio_gain, -10975, 25, 0); | ||
720 | |||
715 | static struct snd_kcontrol_new vx_control_audio_gain = { | 721 | static struct snd_kcontrol_new vx_control_audio_gain = { |
716 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 722 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
723 | .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | | ||
724 | SNDRV_CTL_ELEM_ACCESS_TLV_READ), | ||
717 | /* name will be filled later */ | 725 | /* name will be filled later */ |
718 | .info = vx_audio_gain_info, | 726 | .info = vx_audio_gain_info, |
719 | .get = vx_audio_gain_get, | 727 | .get = vx_audio_gain_get, |
720 | .put = vx_audio_gain_put | 728 | .put = vx_audio_gain_put, |
729 | .tlv = { .p = db_scale_audio_gain }, | ||
721 | }; | 730 | }; |
722 | static struct snd_kcontrol_new vx_control_output_switch = { | 731 | static struct snd_kcontrol_new vx_control_output_switch = { |
723 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 732 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
@@ -729,9 +738,12 @@ static struct snd_kcontrol_new vx_control_output_switch = { | |||
729 | static struct snd_kcontrol_new vx_control_monitor_gain = { | 738 | static struct snd_kcontrol_new vx_control_monitor_gain = { |
730 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 739 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
731 | .name = "Monitoring Volume", | 740 | .name = "Monitoring Volume", |
741 | .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | | ||
742 | SNDRV_CTL_ELEM_ACCESS_TLV_READ), | ||
732 | .info = vx_audio_gain_info, /* shared */ | 743 | .info = vx_audio_gain_info, /* shared */ |
733 | .get = vx_audio_monitor_get, | 744 | .get = vx_audio_monitor_get, |
734 | .put = vx_audio_monitor_put | 745 | .put = vx_audio_monitor_put, |
746 | .tlv = { .p = db_scale_audio_gain }, | ||
735 | }; | 747 | }; |
736 | static struct snd_kcontrol_new vx_control_monitor_switch = { | 748 | static struct snd_kcontrol_new vx_control_monitor_switch = { |
737 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 749 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
@@ -918,6 +930,7 @@ int snd_vx_mixer_new(struct vx_core *chip) | |||
918 | for (i = 0; i < chip->hw->num_outs; i++) { | 930 | for (i = 0; i < chip->hw->num_outs; i++) { |
919 | temp = vx_control_output_level; | 931 | temp = vx_control_output_level; |
920 | temp.index = i; | 932 | temp.index = i; |
933 | temp.tlv.p = chip->hw->output_level_db_scale; | ||
921 | if ((err = snd_ctl_add(card, snd_ctl_new1(&temp, chip))) < 0) | 934 | if ((err = snd_ctl_add(card, snd_ctl_new1(&temp, chip))) < 0) |
922 | return err; | 935 | return err; |
923 | } | 936 | } |
diff --git a/sound/i2c/other/ak4xxx-adda.c b/sound/i2c/other/ak4xxx-adda.c index dc7cc2001b74..5da49e2eb350 100644 --- a/sound/i2c/other/ak4xxx-adda.c +++ b/sound/i2c/other/ak4xxx-adda.c | |||
@@ -28,12 +28,14 @@ | |||
28 | #include <linux/init.h> | 28 | #include <linux/init.h> |
29 | #include <sound/core.h> | 29 | #include <sound/core.h> |
30 | #include <sound/control.h> | 30 | #include <sound/control.h> |
31 | #include <sound/tlv.h> | ||
31 | #include <sound/ak4xxx-adda.h> | 32 | #include <sound/ak4xxx-adda.h> |
32 | 33 | ||
33 | MODULE_AUTHOR("Jaroslav Kysela <perex@suse.cz>, Takashi Iwai <tiwai@suse.de>"); | 34 | MODULE_AUTHOR("Jaroslav Kysela <perex@suse.cz>, Takashi Iwai <tiwai@suse.de>"); |
34 | MODULE_DESCRIPTION("Routines for control of AK452x / AK43xx AD/DA converters"); | 35 | MODULE_DESCRIPTION("Routines for control of AK452x / AK43xx AD/DA converters"); |
35 | MODULE_LICENSE("GPL"); | 36 | MODULE_LICENSE("GPL"); |
36 | 37 | ||
38 | /* write the given register and save the data to the cache */ | ||
37 | void snd_akm4xxx_write(struct snd_akm4xxx *ak, int chip, unsigned char reg, | 39 | void snd_akm4xxx_write(struct snd_akm4xxx *ak, int chip, unsigned char reg, |
38 | unsigned char val) | 40 | unsigned char val) |
39 | { | 41 | { |
@@ -41,15 +43,7 @@ void snd_akm4xxx_write(struct snd_akm4xxx *ak, int chip, unsigned char reg, | |||
41 | ak->ops.write(ak, chip, reg, val); | 43 | ak->ops.write(ak, chip, reg, val); |
42 | 44 | ||
43 | /* save the data */ | 45 | /* save the data */ |
44 | if (ak->type == SND_AK4524 || ak->type == SND_AK4528) { | 46 | snd_akm4xxx_set(ak, chip, reg, val); |
45 | if ((reg != 0x04 && reg != 0x05) || (val & 0x80) == 0) | ||
46 | snd_akm4xxx_set(ak, chip, reg, val); | ||
47 | else | ||
48 | snd_akm4xxx_set_ipga(ak, chip, reg, val); | ||
49 | } else { | ||
50 | /* AK4529, or else */ | ||
51 | snd_akm4xxx_set(ak, chip, reg, val); | ||
52 | } | ||
53 | ak->ops.unlock(ak, chip); | 47 | ak->ops.unlock(ak, chip); |
54 | } | 48 | } |
55 | 49 | ||
@@ -73,12 +67,6 @@ static void ak4524_reset(struct snd_akm4xxx *ak, int state) | |||
73 | for (reg = 0x04; reg < maxreg; reg++) | 67 | for (reg = 0x04; reg < maxreg; reg++) |
74 | snd_akm4xxx_write(ak, chip, reg, | 68 | snd_akm4xxx_write(ak, chip, reg, |
75 | snd_akm4xxx_get(ak, chip, reg)); | 69 | snd_akm4xxx_get(ak, chip, reg)); |
76 | if (ak->type == SND_AK4528) | ||
77 | continue; | ||
78 | /* IPGA */ | ||
79 | for (reg = 0x04; reg < 0x06; reg++) | ||
80 | snd_akm4xxx_write(ak, chip, reg, | ||
81 | snd_akm4xxx_get_ipga(ak, chip, reg)); | ||
82 | } | 70 | } |
83 | } | 71 | } |
84 | 72 | ||
@@ -137,11 +125,48 @@ void snd_akm4xxx_reset(struct snd_akm4xxx *ak, int state) | |||
137 | case SND_AK4381: | 125 | case SND_AK4381: |
138 | ak4381_reset(ak, state); | 126 | ak4381_reset(ak, state); |
139 | break; | 127 | break; |
128 | default: | ||
129 | break; | ||
140 | } | 130 | } |
141 | } | 131 | } |
142 | 132 | ||
143 | EXPORT_SYMBOL(snd_akm4xxx_reset); | 133 | EXPORT_SYMBOL(snd_akm4xxx_reset); |
144 | 134 | ||
135 | |||
136 | /* | ||
137 | * Volume conversion table for non-linear volumes | ||
138 | * from -63.5dB (mute) to 0dB step 0.5dB | ||
139 | * | ||
140 | * Used for AK4524 input/ouput attenuation, AK4528, and | ||
141 | * AK5365 input attenuation | ||
142 | */ | ||
143 | static unsigned char vol_cvt_datt[128] = { | ||
144 | 0x00, 0x01, 0x01, 0x02, 0x02, 0x03, 0x03, 0x04, | ||
145 | 0x04, 0x04, 0x04, 0x05, 0x05, 0x05, 0x06, 0x06, | ||
146 | 0x06, 0x07, 0x07, 0x08, 0x08, 0x08, 0x09, 0x0a, | ||
147 | 0x0a, 0x0b, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x0f, | ||
148 | 0x10, 0x10, 0x11, 0x12, 0x12, 0x13, 0x13, 0x14, | ||
149 | 0x15, 0x16, 0x17, 0x17, 0x18, 0x19, 0x1a, 0x1c, | ||
150 | 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, 0x23, | ||
151 | 0x24, 0x25, 0x26, 0x28, 0x29, 0x2a, 0x2b, 0x2d, | ||
152 | 0x2e, 0x30, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, | ||
153 | 0x37, 0x38, 0x39, 0x3b, 0x3c, 0x3e, 0x3f, 0x40, | ||
154 | 0x41, 0x42, 0x43, 0x44, 0x46, 0x47, 0x48, 0x4a, | ||
155 | 0x4b, 0x4d, 0x4e, 0x50, 0x51, 0x52, 0x53, 0x54, | ||
156 | 0x55, 0x56, 0x58, 0x59, 0x5b, 0x5c, 0x5e, 0x5f, | ||
157 | 0x60, 0x61, 0x62, 0x64, 0x65, 0x66, 0x67, 0x69, | ||
158 | 0x6a, 0x6c, 0x6d, 0x6f, 0x70, 0x71, 0x72, 0x73, | ||
159 | 0x75, 0x76, 0x77, 0x79, 0x7a, 0x7c, 0x7d, 0x7f, | ||
160 | }; | ||
161 | |||
162 | /* | ||
163 | * dB tables | ||
164 | */ | ||
165 | static DECLARE_TLV_DB_SCALE(db_scale_vol_datt, -6350, 50, 1); | ||
166 | static DECLARE_TLV_DB_SCALE(db_scale_8bit, -12750, 50, 1); | ||
167 | static DECLARE_TLV_DB_SCALE(db_scale_7bit, -6350, 50, 1); | ||
168 | static DECLARE_TLV_DB_LINEAR(db_scale_linear, TLV_DB_GAIN_MUTE, 0); | ||
169 | |||
145 | /* | 170 | /* |
146 | * initialize all the ak4xxx chips | 171 | * initialize all the ak4xxx chips |
147 | */ | 172 | */ |
@@ -155,8 +180,6 @@ void snd_akm4xxx_init(struct snd_akm4xxx *ak) | |||
155 | 0x01, 0x03, /* 1: ADC/DAC enable */ | 180 | 0x01, 0x03, /* 1: ADC/DAC enable */ |
156 | 0x04, 0x00, /* 4: ADC left muted */ | 181 | 0x04, 0x00, /* 4: ADC left muted */ |
157 | 0x05, 0x00, /* 5: ADC right muted */ | 182 | 0x05, 0x00, /* 5: ADC right muted */ |
158 | 0x04, 0x80, /* 4: ADC IPGA gain 0dB */ | ||
159 | 0x05, 0x80, /* 5: ADC IPGA gain 0dB */ | ||
160 | 0x06, 0x00, /* 6: DAC left muted */ | 183 | 0x06, 0x00, /* 6: DAC left muted */ |
161 | 0x07, 0x00, /* 7: DAC right muted */ | 184 | 0x07, 0x00, /* 7: DAC right muted */ |
162 | 0xff, 0xff | 185 | 0xff, 0xff |
@@ -238,6 +261,9 @@ void snd_akm4xxx_init(struct snd_akm4xxx *ak) | |||
238 | int chip, num_chips; | 261 | int chip, num_chips; |
239 | unsigned char *ptr, reg, data, *inits; | 262 | unsigned char *ptr, reg, data, *inits; |
240 | 263 | ||
264 | memset(ak->images, 0, sizeof(ak->images)); | ||
265 | memset(ak->volumes, 0, sizeof(ak->volumes)); | ||
266 | |||
241 | switch (ak->type) { | 267 | switch (ak->type) { |
242 | case SND_AK4524: | 268 | case SND_AK4524: |
243 | inits = inits_ak4524; | 269 | inits = inits_ak4524; |
@@ -263,6 +289,9 @@ void snd_akm4xxx_init(struct snd_akm4xxx *ak) | |||
263 | inits = inits_ak4381; | 289 | inits = inits_ak4381; |
264 | num_chips = ak->num_dacs / 2; | 290 | num_chips = ak->num_dacs / 2; |
265 | break; | 291 | break; |
292 | case SND_AK5365: | ||
293 | /* FIXME: any init sequence? */ | ||
294 | return; | ||
266 | default: | 295 | default: |
267 | snd_BUG(); | 296 | snd_BUG(); |
268 | return; | 297 | return; |
@@ -280,14 +309,23 @@ void snd_akm4xxx_init(struct snd_akm4xxx *ak) | |||
280 | 309 | ||
281 | EXPORT_SYMBOL(snd_akm4xxx_init); | 310 | EXPORT_SYMBOL(snd_akm4xxx_init); |
282 | 311 | ||
312 | /* | ||
313 | * Mixer callbacks | ||
314 | */ | ||
315 | #define AK_IPGA (1<<20) /* including IPGA */ | ||
316 | #define AK_VOL_CVT (1<<21) /* need dB conversion */ | ||
317 | #define AK_NEEDSMSB (1<<22) /* need MSB update bit */ | ||
318 | #define AK_INVERT (1<<23) /* data is inverted */ | ||
283 | #define AK_GET_CHIP(val) (((val) >> 8) & 0xff) | 319 | #define AK_GET_CHIP(val) (((val) >> 8) & 0xff) |
284 | #define AK_GET_ADDR(val) ((val) & 0xff) | 320 | #define AK_GET_ADDR(val) ((val) & 0xff) |
285 | #define AK_GET_SHIFT(val) (((val) >> 16) & 0x7f) | 321 | #define AK_GET_SHIFT(val) (((val) >> 16) & 0x0f) |
322 | #define AK_GET_VOL_CVT(val) (((val) >> 21) & 1) | ||
323 | #define AK_GET_IPGA(val) (((val) >> 20) & 1) | ||
324 | #define AK_GET_NEEDSMSB(val) (((val) >> 22) & 1) | ||
286 | #define AK_GET_INVERT(val) (((val) >> 23) & 1) | 325 | #define AK_GET_INVERT(val) (((val) >> 23) & 1) |
287 | #define AK_GET_MASK(val) (((val) >> 24) & 0xff) | 326 | #define AK_GET_MASK(val) (((val) >> 24) & 0xff) |
288 | #define AK_COMPOSE(chip,addr,shift,mask) \ | 327 | #define AK_COMPOSE(chip,addr,shift,mask) \ |
289 | (((chip) << 8) | (addr) | ((shift) << 16) | ((mask) << 24)) | 328 | (((chip) << 8) | (addr) | ((shift) << 16) | ((mask) << 24)) |
290 | #define AK_INVERT (1<<23) | ||
291 | 329 | ||
292 | static int snd_akm4xxx_volume_info(struct snd_kcontrol *kcontrol, | 330 | static int snd_akm4xxx_volume_info(struct snd_kcontrol *kcontrol, |
293 | struct snd_ctl_elem_info *uinfo) | 331 | struct snd_ctl_elem_info *uinfo) |
@@ -307,31 +345,39 @@ static int snd_akm4xxx_volume_get(struct snd_kcontrol *kcontrol, | |||
307 | struct snd_akm4xxx *ak = snd_kcontrol_chip(kcontrol); | 345 | struct snd_akm4xxx *ak = snd_kcontrol_chip(kcontrol); |
308 | int chip = AK_GET_CHIP(kcontrol->private_value); | 346 | int chip = AK_GET_CHIP(kcontrol->private_value); |
309 | int addr = AK_GET_ADDR(kcontrol->private_value); | 347 | int addr = AK_GET_ADDR(kcontrol->private_value); |
310 | int invert = AK_GET_INVERT(kcontrol->private_value); | 348 | |
311 | unsigned int mask = AK_GET_MASK(kcontrol->private_value); | 349 | ucontrol->value.integer.value[0] = snd_akm4xxx_get_vol(ak, chip, addr); |
312 | unsigned char val = snd_akm4xxx_get(ak, chip, addr); | ||
313 | |||
314 | ucontrol->value.integer.value[0] = invert ? mask - val : val; | ||
315 | return 0; | 350 | return 0; |
316 | } | 351 | } |
317 | 352 | ||
318 | static int snd_akm4xxx_volume_put(struct snd_kcontrol *kcontrol, | 353 | static int put_ak_reg(struct snd_kcontrol *kcontrol, int addr, |
319 | struct snd_ctl_elem_value *ucontrol) | 354 | unsigned char nval) |
320 | { | 355 | { |
321 | struct snd_akm4xxx *ak = snd_kcontrol_chip(kcontrol); | 356 | struct snd_akm4xxx *ak = snd_kcontrol_chip(kcontrol); |
322 | int chip = AK_GET_CHIP(kcontrol->private_value); | ||
323 | int addr = AK_GET_ADDR(kcontrol->private_value); | ||
324 | int invert = AK_GET_INVERT(kcontrol->private_value); | ||
325 | unsigned int mask = AK_GET_MASK(kcontrol->private_value); | 357 | unsigned int mask = AK_GET_MASK(kcontrol->private_value); |
326 | unsigned char nval = ucontrol->value.integer.value[0] % (mask+1); | 358 | int chip = AK_GET_CHIP(kcontrol->private_value); |
327 | int change; | ||
328 | 359 | ||
329 | if (invert) | 360 | if (snd_akm4xxx_get_vol(ak, chip, addr) == nval) |
361 | return 0; | ||
362 | |||
363 | snd_akm4xxx_set_vol(ak, chip, addr, nval); | ||
364 | if (AK_GET_VOL_CVT(kcontrol->private_value) && nval < 128) | ||
365 | nval = vol_cvt_datt[nval]; | ||
366 | if (AK_GET_IPGA(kcontrol->private_value) && nval >= 128) | ||
367 | nval++; /* need to correct + 1 since both 127 and 128 are 0dB */ | ||
368 | if (AK_GET_INVERT(kcontrol->private_value)) | ||
330 | nval = mask - nval; | 369 | nval = mask - nval; |
331 | change = snd_akm4xxx_get(ak, chip, addr) != nval; | 370 | if (AK_GET_NEEDSMSB(kcontrol->private_value)) |
332 | if (change) | 371 | nval |= 0x80; |
333 | snd_akm4xxx_write(ak, chip, addr, nval); | 372 | snd_akm4xxx_write(ak, chip, addr, nval); |
334 | return change; | 373 | return 1; |
374 | } | ||
375 | |||
376 | static int snd_akm4xxx_volume_put(struct snd_kcontrol *kcontrol, | ||
377 | struct snd_ctl_elem_value *ucontrol) | ||
378 | { | ||
379 | return put_ak_reg(kcontrol, AK_GET_ADDR(kcontrol->private_value), | ||
380 | ucontrol->value.integer.value[0]); | ||
335 | } | 381 | } |
336 | 382 | ||
337 | static int snd_akm4xxx_stereo_volume_info(struct snd_kcontrol *kcontrol, | 383 | static int snd_akm4xxx_stereo_volume_info(struct snd_kcontrol *kcontrol, |
@@ -352,77 +398,21 @@ static int snd_akm4xxx_stereo_volume_get(struct snd_kcontrol *kcontrol, | |||
352 | struct snd_akm4xxx *ak = snd_kcontrol_chip(kcontrol); | 398 | struct snd_akm4xxx *ak = snd_kcontrol_chip(kcontrol); |
353 | int chip = AK_GET_CHIP(kcontrol->private_value); | 399 | int chip = AK_GET_CHIP(kcontrol->private_value); |
354 | int addr = AK_GET_ADDR(kcontrol->private_value); | 400 | int addr = AK_GET_ADDR(kcontrol->private_value); |
355 | int invert = AK_GET_INVERT(kcontrol->private_value); | ||
356 | unsigned int mask = AK_GET_MASK(kcontrol->private_value); | ||
357 | unsigned char val = snd_akm4xxx_get(ak, chip, addr); | ||
358 | |||
359 | ucontrol->value.integer.value[0] = invert ? mask - val : val; | ||
360 | |||
361 | val = snd_akm4xxx_get(ak, chip, addr+1); | ||
362 | ucontrol->value.integer.value[1] = invert ? mask - val : val; | ||
363 | 401 | ||
402 | ucontrol->value.integer.value[0] = snd_akm4xxx_get_vol(ak, chip, addr); | ||
403 | ucontrol->value.integer.value[1] = snd_akm4xxx_get_vol(ak, chip, addr+1); | ||
364 | return 0; | 404 | return 0; |
365 | } | 405 | } |
366 | 406 | ||
367 | static int snd_akm4xxx_stereo_volume_put(struct snd_kcontrol *kcontrol, | 407 | static int snd_akm4xxx_stereo_volume_put(struct snd_kcontrol *kcontrol, |
368 | struct snd_ctl_elem_value *ucontrol) | 408 | struct snd_ctl_elem_value *ucontrol) |
369 | { | 409 | { |
370 | struct snd_akm4xxx *ak = snd_kcontrol_chip(kcontrol); | ||
371 | int chip = AK_GET_CHIP(kcontrol->private_value); | ||
372 | int addr = AK_GET_ADDR(kcontrol->private_value); | ||
373 | int invert = AK_GET_INVERT(kcontrol->private_value); | ||
374 | unsigned int mask = AK_GET_MASK(kcontrol->private_value); | ||
375 | unsigned char nval = ucontrol->value.integer.value[0] % (mask+1); | ||
376 | int change0, change1; | ||
377 | |||
378 | if (invert) | ||
379 | nval = mask - nval; | ||
380 | change0 = snd_akm4xxx_get(ak, chip, addr) != nval; | ||
381 | if (change0) | ||
382 | snd_akm4xxx_write(ak, chip, addr, nval); | ||
383 | |||
384 | nval = ucontrol->value.integer.value[1] % (mask+1); | ||
385 | if (invert) | ||
386 | nval = mask - nval; | ||
387 | change1 = snd_akm4xxx_get(ak, chip, addr+1) != nval; | ||
388 | if (change1) | ||
389 | snd_akm4xxx_write(ak, chip, addr+1, nval); | ||
390 | |||
391 | |||
392 | return change0 || change1; | ||
393 | } | ||
394 | |||
395 | static int snd_akm4xxx_ipga_gain_info(struct snd_kcontrol *kcontrol, | ||
396 | struct snd_ctl_elem_info *uinfo) | ||
397 | { | ||
398 | uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; | ||
399 | uinfo->count = 1; | ||
400 | uinfo->value.integer.min = 0; | ||
401 | uinfo->value.integer.max = 36; | ||
402 | return 0; | ||
403 | } | ||
404 | |||
405 | static int snd_akm4xxx_ipga_gain_get(struct snd_kcontrol *kcontrol, | ||
406 | struct snd_ctl_elem_value *ucontrol) | ||
407 | { | ||
408 | struct snd_akm4xxx *ak = snd_kcontrol_chip(kcontrol); | ||
409 | int chip = AK_GET_CHIP(kcontrol->private_value); | ||
410 | int addr = AK_GET_ADDR(kcontrol->private_value); | 410 | int addr = AK_GET_ADDR(kcontrol->private_value); |
411 | ucontrol->value.integer.value[0] = | 411 | int change; |
412 | snd_akm4xxx_get_ipga(ak, chip, addr) & 0x7f; | ||
413 | return 0; | ||
414 | } | ||
415 | 412 | ||
416 | static int snd_akm4xxx_ipga_gain_put(struct snd_kcontrol *kcontrol, | 413 | change = put_ak_reg(kcontrol, addr, ucontrol->value.integer.value[0]); |
417 | struct snd_ctl_elem_value *ucontrol) | 414 | change |= put_ak_reg(kcontrol, addr + 1, |
418 | { | 415 | ucontrol->value.integer.value[1]); |
419 | struct snd_akm4xxx *ak = snd_kcontrol_chip(kcontrol); | ||
420 | int chip = AK_GET_CHIP(kcontrol->private_value); | ||
421 | int addr = AK_GET_ADDR(kcontrol->private_value); | ||
422 | unsigned char nval = (ucontrol->value.integer.value[0] % 37) | 0x80; | ||
423 | int change = snd_akm4xxx_get_ipga(ak, chip, addr) != nval; | ||
424 | if (change) | ||
425 | snd_akm4xxx_write(ak, chip, addr, nval); | ||
426 | return change; | 416 | return change; |
427 | } | 417 | } |
428 | 418 | ||
@@ -472,179 +462,280 @@ static int snd_akm4xxx_deemphasis_put(struct snd_kcontrol *kcontrol, | |||
472 | return change; | 462 | return change; |
473 | } | 463 | } |
474 | 464 | ||
465 | static int ak4xxx_switch_info(struct snd_kcontrol *kcontrol, | ||
466 | struct snd_ctl_elem_info *uinfo) | ||
467 | { | ||
468 | uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; | ||
469 | uinfo->count = 1; | ||
470 | uinfo->value.integer.min = 0; | ||
471 | uinfo->value.integer.max = 1; | ||
472 | return 0; | ||
473 | } | ||
474 | |||
475 | static int ak4xxx_switch_get(struct snd_kcontrol *kcontrol, | ||
476 | struct snd_ctl_elem_value *ucontrol) | ||
477 | { | ||
478 | struct snd_akm4xxx *ak = snd_kcontrol_chip(kcontrol); | ||
479 | int chip = AK_GET_CHIP(kcontrol->private_value); | ||
480 | int addr = AK_GET_ADDR(kcontrol->private_value); | ||
481 | int shift = AK_GET_SHIFT(kcontrol->private_value); | ||
482 | int invert = AK_GET_INVERT(kcontrol->private_value); | ||
483 | unsigned char val = snd_akm4xxx_get(ak, chip, addr); | ||
484 | |||
485 | if (invert) | ||
486 | val = ! val; | ||
487 | ucontrol->value.integer.value[0] = (val & (1<<shift)) != 0; | ||
488 | return 0; | ||
489 | } | ||
490 | |||
491 | static int ak4xxx_switch_put(struct snd_kcontrol *kcontrol, | ||
492 | struct snd_ctl_elem_value *ucontrol) | ||
493 | { | ||
494 | struct snd_akm4xxx *ak = snd_kcontrol_chip(kcontrol); | ||
495 | int chip = AK_GET_CHIP(kcontrol->private_value); | ||
496 | int addr = AK_GET_ADDR(kcontrol->private_value); | ||
497 | int shift = AK_GET_SHIFT(kcontrol->private_value); | ||
498 | int invert = AK_GET_INVERT(kcontrol->private_value); | ||
499 | long flag = ucontrol->value.integer.value[0]; | ||
500 | unsigned char val, oval; | ||
501 | int change; | ||
502 | |||
503 | if (invert) | ||
504 | flag = ! flag; | ||
505 | oval = snd_akm4xxx_get(ak, chip, addr); | ||
506 | if (flag) | ||
507 | val = oval | (1<<shift); | ||
508 | else | ||
509 | val = oval & ~(1<<shift); | ||
510 | change = (oval != val); | ||
511 | if (change) | ||
512 | snd_akm4xxx_write(ak, chip, addr, val); | ||
513 | return change; | ||
514 | } | ||
515 | |||
475 | /* | 516 | /* |
476 | * build AK4xxx controls | 517 | * build AK4xxx controls |
477 | */ | 518 | */ |
478 | 519 | ||
479 | int snd_akm4xxx_build_controls(struct snd_akm4xxx *ak) | 520 | static int build_dac_controls(struct snd_akm4xxx *ak) |
480 | { | 521 | { |
481 | unsigned int idx, num_emphs; | 522 | int idx, err, mixer_ch, num_stereo; |
482 | struct snd_kcontrol *ctl; | 523 | struct snd_kcontrol_new knew; |
483 | int err; | ||
484 | int mixer_ch = 0; | ||
485 | int num_stereo; | ||
486 | |||
487 | ctl = kmalloc(sizeof(*ctl), GFP_KERNEL); | ||
488 | if (! ctl) | ||
489 | return -ENOMEM; | ||
490 | 524 | ||
525 | mixer_ch = 0; | ||
491 | for (idx = 0; idx < ak->num_dacs; ) { | 526 | for (idx = 0; idx < ak->num_dacs; ) { |
492 | memset(ctl, 0, sizeof(*ctl)); | 527 | memset(&knew, 0, sizeof(knew)); |
493 | if (ak->channel_names == NULL) { | 528 | if (! ak->dac_info || ! ak->dac_info[mixer_ch].name) { |
494 | strcpy(ctl->id.name, "DAC Volume"); | 529 | knew.name = "DAC Volume"; |
530 | knew.index = mixer_ch + ak->idx_offset * 2; | ||
495 | num_stereo = 1; | 531 | num_stereo = 1; |
496 | ctl->id.index = mixer_ch + ak->idx_offset * 2; | ||
497 | } else { | 532 | } else { |
498 | strcpy(ctl->id.name, ak->channel_names[mixer_ch]); | 533 | knew.name = ak->dac_info[mixer_ch].name; |
499 | num_stereo = ak->num_stereo[mixer_ch]; | 534 | num_stereo = ak->dac_info[mixer_ch].num_channels; |
500 | ctl->id.index = 0; | ||
501 | } | 535 | } |
502 | ctl->id.iface = SNDRV_CTL_ELEM_IFACE_MIXER; | 536 | knew.iface = SNDRV_CTL_ELEM_IFACE_MIXER; |
503 | ctl->count = 1; | 537 | knew.count = 1; |
538 | knew.access = SNDRV_CTL_ELEM_ACCESS_READWRITE | | ||
539 | SNDRV_CTL_ELEM_ACCESS_TLV_READ; | ||
504 | if (num_stereo == 2) { | 540 | if (num_stereo == 2) { |
505 | ctl->info = snd_akm4xxx_stereo_volume_info; | 541 | knew.info = snd_akm4xxx_stereo_volume_info; |
506 | ctl->get = snd_akm4xxx_stereo_volume_get; | 542 | knew.get = snd_akm4xxx_stereo_volume_get; |
507 | ctl->put = snd_akm4xxx_stereo_volume_put; | 543 | knew.put = snd_akm4xxx_stereo_volume_put; |
508 | } else { | 544 | } else { |
509 | ctl->info = snd_akm4xxx_volume_info; | 545 | knew.info = snd_akm4xxx_volume_info; |
510 | ctl->get = snd_akm4xxx_volume_get; | 546 | knew.get = snd_akm4xxx_volume_get; |
511 | ctl->put = snd_akm4xxx_volume_put; | 547 | knew.put = snd_akm4xxx_volume_put; |
512 | } | 548 | } |
513 | switch (ak->type) { | 549 | switch (ak->type) { |
514 | case SND_AK4524: | 550 | case SND_AK4524: |
515 | /* register 6 & 7 */ | 551 | /* register 6 & 7 */ |
516 | ctl->private_value = | 552 | knew.private_value = |
517 | AK_COMPOSE(idx/2, (idx%2) + 6, 0, 127); | 553 | AK_COMPOSE(idx/2, (idx%2) + 6, 0, 127) | |
554 | AK_VOL_CVT; | ||
555 | knew.tlv.p = db_scale_vol_datt; | ||
518 | break; | 556 | break; |
519 | case SND_AK4528: | 557 | case SND_AK4528: |
520 | /* register 4 & 5 */ | 558 | /* register 4 & 5 */ |
521 | ctl->private_value = | 559 | knew.private_value = |
522 | AK_COMPOSE(idx/2, (idx%2) + 4, 0, 127); | 560 | AK_COMPOSE(idx/2, (idx%2) + 4, 0, 127) | |
561 | AK_VOL_CVT; | ||
562 | knew.tlv.p = db_scale_vol_datt; | ||
523 | break; | 563 | break; |
524 | case SND_AK4529: { | 564 | case SND_AK4529: { |
525 | /* registers 2-7 and b,c */ | 565 | /* registers 2-7 and b,c */ |
526 | int val = idx < 6 ? idx + 2 : (idx - 6) + 0xb; | 566 | int val = idx < 6 ? idx + 2 : (idx - 6) + 0xb; |
527 | ctl->private_value = | 567 | knew.private_value = |
528 | AK_COMPOSE(0, val, 0, 255) | AK_INVERT; | 568 | AK_COMPOSE(0, val, 0, 255) | AK_INVERT; |
569 | knew.tlv.p = db_scale_8bit; | ||
529 | break; | 570 | break; |
530 | } | 571 | } |
531 | case SND_AK4355: | 572 | case SND_AK4355: |
532 | /* register 4-9, chip #0 only */ | 573 | /* register 4-9, chip #0 only */ |
533 | ctl->private_value = AK_COMPOSE(0, idx + 4, 0, 255); | 574 | knew.private_value = AK_COMPOSE(0, idx + 4, 0, 255); |
575 | knew.tlv.p = db_scale_8bit; | ||
534 | break; | 576 | break; |
535 | case SND_AK4358: | 577 | case SND_AK4358: { |
536 | if (idx >= 6) | 578 | /* register 4-9 and 11-12, chip #0 only */ |
537 | /* register 4-9, chip #0 only */ | 579 | int addr = idx < 6 ? idx + 4 : idx + 5; |
538 | ctl->private_value = | 580 | knew.private_value = |
539 | AK_COMPOSE(0, idx + 5, 0, 255); | 581 | AK_COMPOSE(0, addr, 0, 127) | AK_NEEDSMSB; |
540 | else | 582 | knew.tlv.p = db_scale_7bit; |
541 | /* register 4-9, chip #0 only */ | ||
542 | ctl->private_value = | ||
543 | AK_COMPOSE(0, idx + 4, 0, 255); | ||
544 | break; | 583 | break; |
584 | } | ||
545 | case SND_AK4381: | 585 | case SND_AK4381: |
546 | /* register 3 & 4 */ | 586 | /* register 3 & 4 */ |
547 | ctl->private_value = | 587 | knew.private_value = |
548 | AK_COMPOSE(idx/2, (idx%2) + 3, 0, 255); | 588 | AK_COMPOSE(idx/2, (idx%2) + 3, 0, 255); |
589 | knew.tlv.p = db_scale_linear; | ||
549 | break; | 590 | break; |
550 | default: | 591 | default: |
551 | err = -EINVAL; | 592 | return -EINVAL; |
552 | goto __error; | ||
553 | } | 593 | } |
554 | 594 | ||
555 | ctl->private_data = ak; | 595 | err = snd_ctl_add(ak->card, snd_ctl_new1(&knew, ak)); |
556 | err = snd_ctl_add(ak->card, | ||
557 | snd_ctl_new(ctl, SNDRV_CTL_ELEM_ACCESS_READ| | ||
558 | SNDRV_CTL_ELEM_ACCESS_WRITE)); | ||
559 | if (err < 0) | 596 | if (err < 0) |
560 | goto __error; | 597 | return err; |
561 | 598 | ||
562 | idx += num_stereo; | 599 | idx += num_stereo; |
563 | mixer_ch++; | 600 | mixer_ch++; |
564 | } | 601 | } |
565 | for (idx = 0; idx < ak->num_adcs && ak->type == SND_AK4524; ++idx) { | 602 | return 0; |
566 | memset(ctl, 0, sizeof(*ctl)); | 603 | } |
567 | strcpy(ctl->id.name, "ADC Volume"); | 604 | |
568 | ctl->id.index = idx + ak->idx_offset * 2; | 605 | static int build_adc_controls(struct snd_akm4xxx *ak) |
569 | ctl->id.iface = SNDRV_CTL_ELEM_IFACE_MIXER; | 606 | { |
570 | ctl->count = 1; | 607 | int idx, err, mixer_ch, num_stereo; |
571 | ctl->info = snd_akm4xxx_volume_info; | 608 | struct snd_kcontrol_new knew; |
572 | ctl->get = snd_akm4xxx_volume_get; | 609 | |
573 | ctl->put = snd_akm4xxx_volume_put; | 610 | mixer_ch = 0; |
574 | /* register 4 & 5 */ | 611 | for (idx = 0; idx < ak->num_adcs;) { |
575 | ctl->private_value = | 612 | memset(&knew, 0, sizeof(knew)); |
576 | AK_COMPOSE(idx/2, (idx%2) + 4, 0, 127); | 613 | if (! ak->adc_info || ! ak->adc_info[mixer_ch].name) { |
577 | ctl->private_data = ak; | 614 | knew.name = "ADC Volume"; |
578 | err = snd_ctl_add(ak->card, | 615 | knew.index = mixer_ch + ak->idx_offset * 2; |
579 | snd_ctl_new(ctl, SNDRV_CTL_ELEM_ACCESS_READ| | 616 | num_stereo = 1; |
580 | SNDRV_CTL_ELEM_ACCESS_WRITE)); | 617 | } else { |
581 | if (err < 0) | 618 | knew.name = ak->adc_info[mixer_ch].name; |
582 | goto __error; | 619 | num_stereo = ak->adc_info[mixer_ch].num_channels; |
583 | 620 | } | |
584 | memset(ctl, 0, sizeof(*ctl)); | 621 | knew.iface = SNDRV_CTL_ELEM_IFACE_MIXER; |
585 | strcpy(ctl->id.name, "IPGA Analog Capture Volume"); | 622 | knew.count = 1; |
586 | ctl->id.index = idx + ak->idx_offset * 2; | 623 | knew.access = SNDRV_CTL_ELEM_ACCESS_READWRITE | |
587 | ctl->id.iface = SNDRV_CTL_ELEM_IFACE_MIXER; | 624 | SNDRV_CTL_ELEM_ACCESS_TLV_READ; |
588 | ctl->count = 1; | 625 | if (num_stereo == 2) { |
589 | ctl->info = snd_akm4xxx_ipga_gain_info; | 626 | knew.info = snd_akm4xxx_stereo_volume_info; |
590 | ctl->get = snd_akm4xxx_ipga_gain_get; | 627 | knew.get = snd_akm4xxx_stereo_volume_get; |
591 | ctl->put = snd_akm4xxx_ipga_gain_put; | 628 | knew.put = snd_akm4xxx_stereo_volume_put; |
629 | } else { | ||
630 | knew.info = snd_akm4xxx_volume_info; | ||
631 | knew.get = snd_akm4xxx_volume_get; | ||
632 | knew.put = snd_akm4xxx_volume_put; | ||
633 | } | ||
592 | /* register 4 & 5 */ | 634 | /* register 4 & 5 */ |
593 | ctl->private_value = AK_COMPOSE(idx/2, (idx%2) + 4, 0, 0); | 635 | if (ak->type == SND_AK5365) |
594 | ctl->private_data = ak; | 636 | knew.private_value = |
595 | err = snd_ctl_add(ak->card, | 637 | AK_COMPOSE(idx/2, (idx%2) + 4, 0, 151) | |
596 | snd_ctl_new(ctl, SNDRV_CTL_ELEM_ACCESS_READ| | 638 | AK_VOL_CVT | AK_IPGA; |
597 | SNDRV_CTL_ELEM_ACCESS_WRITE)); | 639 | else |
640 | knew.private_value = | ||
641 | AK_COMPOSE(idx/2, (idx%2) + 4, 0, 163) | | ||
642 | AK_VOL_CVT | AK_IPGA; | ||
643 | knew.tlv.p = db_scale_vol_datt; | ||
644 | err = snd_ctl_add(ak->card, snd_ctl_new1(&knew, ak)); | ||
598 | if (err < 0) | 645 | if (err < 0) |
599 | goto __error; | 646 | return err; |
647 | |||
648 | if (ak->type == SND_AK5365 && (idx % 2) == 0) { | ||
649 | if (! ak->adc_info || | ||
650 | ! ak->adc_info[mixer_ch].switch_name) | ||
651 | knew.name = "Capture Switch"; | ||
652 | else | ||
653 | knew.name = ak->adc_info[mixer_ch].switch_name; | ||
654 | knew.info = ak4xxx_switch_info; | ||
655 | knew.get = ak4xxx_switch_get; | ||
656 | knew.put = ak4xxx_switch_put; | ||
657 | knew.access = 0; | ||
658 | /* register 2, bit 0 (SMUTE): 0 = normal operation, | ||
659 | 1 = mute */ | ||
660 | knew.private_value = | ||
661 | AK_COMPOSE(idx/2, 2, 0, 0) | AK_INVERT; | ||
662 | err = snd_ctl_add(ak->card, snd_ctl_new1(&knew, ak)); | ||
663 | if (err < 0) | ||
664 | return err; | ||
665 | } | ||
666 | |||
667 | idx += num_stereo; | ||
668 | mixer_ch++; | ||
600 | } | 669 | } |
601 | if (ak->type == SND_AK4355 || ak->type == SND_AK4358) | 670 | return 0; |
602 | num_emphs = 1; | 671 | } |
603 | else | 672 | |
604 | num_emphs = ak->num_dacs / 2; | 673 | static int build_deemphasis(struct snd_akm4xxx *ak, int num_emphs) |
674 | { | ||
675 | int idx, err; | ||
676 | struct snd_kcontrol_new knew; | ||
677 | |||
605 | for (idx = 0; idx < num_emphs; idx++) { | 678 | for (idx = 0; idx < num_emphs; idx++) { |
606 | memset(ctl, 0, sizeof(*ctl)); | 679 | memset(&knew, 0, sizeof(knew)); |
607 | strcpy(ctl->id.name, "Deemphasis"); | 680 | knew.name = "Deemphasis"; |
608 | ctl->id.index = idx + ak->idx_offset; | 681 | knew.index = idx + ak->idx_offset; |
609 | ctl->id.iface = SNDRV_CTL_ELEM_IFACE_MIXER; | 682 | knew.iface = SNDRV_CTL_ELEM_IFACE_MIXER; |
610 | ctl->count = 1; | 683 | knew.count = 1; |
611 | ctl->info = snd_akm4xxx_deemphasis_info; | 684 | knew.info = snd_akm4xxx_deemphasis_info; |
612 | ctl->get = snd_akm4xxx_deemphasis_get; | 685 | knew.get = snd_akm4xxx_deemphasis_get; |
613 | ctl->put = snd_akm4xxx_deemphasis_put; | 686 | knew.put = snd_akm4xxx_deemphasis_put; |
614 | switch (ak->type) { | 687 | switch (ak->type) { |
615 | case SND_AK4524: | 688 | case SND_AK4524: |
616 | case SND_AK4528: | 689 | case SND_AK4528: |
617 | /* register 3 */ | 690 | /* register 3 */ |
618 | ctl->private_value = AK_COMPOSE(idx, 3, 0, 0); | 691 | knew.private_value = AK_COMPOSE(idx, 3, 0, 0); |
619 | break; | 692 | break; |
620 | case SND_AK4529: { | 693 | case SND_AK4529: { |
621 | int shift = idx == 3 ? 6 : (2 - idx) * 2; | 694 | int shift = idx == 3 ? 6 : (2 - idx) * 2; |
622 | /* register 8 with shift */ | 695 | /* register 8 with shift */ |
623 | ctl->private_value = AK_COMPOSE(0, 8, shift, 0); | 696 | knew.private_value = AK_COMPOSE(0, 8, shift, 0); |
624 | break; | 697 | break; |
625 | } | 698 | } |
626 | case SND_AK4355: | 699 | case SND_AK4355: |
627 | case SND_AK4358: | 700 | case SND_AK4358: |
628 | ctl->private_value = AK_COMPOSE(idx, 3, 0, 0); | 701 | knew.private_value = AK_COMPOSE(idx, 3, 0, 0); |
629 | break; | 702 | break; |
630 | case SND_AK4381: | 703 | case SND_AK4381: |
631 | ctl->private_value = AK_COMPOSE(idx, 1, 1, 0); | 704 | knew.private_value = AK_COMPOSE(idx, 1, 1, 0); |
632 | break; | 705 | break; |
706 | default: | ||
707 | return -EINVAL; | ||
633 | } | 708 | } |
634 | ctl->private_data = ak; | 709 | err = snd_ctl_add(ak->card, snd_ctl_new1(&knew, ak)); |
635 | err = snd_ctl_add(ak->card, | ||
636 | snd_ctl_new(ctl, SNDRV_CTL_ELEM_ACCESS_READ| | ||
637 | SNDRV_CTL_ELEM_ACCESS_WRITE)); | ||
638 | if (err < 0) | 710 | if (err < 0) |
639 | goto __error; | 711 | return err; |
640 | } | 712 | } |
641 | err = 0; | 713 | return 0; |
642 | |||
643 | __error: | ||
644 | kfree(ctl); | ||
645 | return err; | ||
646 | } | 714 | } |
647 | 715 | ||
716 | int snd_akm4xxx_build_controls(struct snd_akm4xxx *ak) | ||
717 | { | ||
718 | int err, num_emphs; | ||
719 | |||
720 | err = build_dac_controls(ak); | ||
721 | if (err < 0) | ||
722 | return err; | ||
723 | |||
724 | err = build_adc_controls(ak); | ||
725 | if (err < 0) | ||
726 | return err; | ||
727 | |||
728 | if (ak->type == SND_AK4355 || ak->type == SND_AK4358) | ||
729 | num_emphs = 1; | ||
730 | else | ||
731 | num_emphs = ak->num_dacs / 2; | ||
732 | err = build_deemphasis(ak, num_emphs); | ||
733 | if (err < 0) | ||
734 | return err; | ||
735 | |||
736 | return 0; | ||
737 | } | ||
738 | |||
648 | EXPORT_SYMBOL(snd_akm4xxx_build_controls); | 739 | EXPORT_SYMBOL(snd_akm4xxx_build_controls); |
649 | 740 | ||
650 | static int __init alsa_akm4xxx_module_init(void) | 741 | static int __init alsa_akm4xxx_module_init(void) |
diff --git a/sound/isa/ad1816a/ad1816a_lib.c b/sound/isa/ad1816a/ad1816a_lib.c index 8fcf2c151823..fd9b61eda0f3 100644 --- a/sound/isa/ad1816a/ad1816a_lib.c +++ b/sound/isa/ad1816a/ad1816a_lib.c | |||
@@ -24,6 +24,7 @@ | |||
24 | #include <linux/slab.h> | 24 | #include <linux/slab.h> |
25 | #include <linux/ioport.h> | 25 | #include <linux/ioport.h> |
26 | #include <sound/core.h> | 26 | #include <sound/core.h> |
27 | #include <sound/tlv.h> | ||
27 | #include <sound/ad1816a.h> | 28 | #include <sound/ad1816a.h> |
28 | 29 | ||
29 | #include <asm/io.h> | 30 | #include <asm/io.h> |
@@ -765,6 +766,13 @@ static int snd_ad1816a_put_mux(struct snd_kcontrol *kcontrol, struct snd_ctl_ele | |||
765 | return change; | 766 | return change; |
766 | } | 767 | } |
767 | 768 | ||
769 | #define AD1816A_SINGLE_TLV(xname, reg, shift, mask, invert, xtlv) \ | ||
770 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ | ||
771 | .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ, \ | ||
772 | .name = xname, .info = snd_ad1816a_info_single, \ | ||
773 | .get = snd_ad1816a_get_single, .put = snd_ad1816a_put_single, \ | ||
774 | .private_value = reg | (shift << 8) | (mask << 16) | (invert << 24), \ | ||
775 | .tlv = { .p = (xtlv) } } | ||
768 | #define AD1816A_SINGLE(xname, reg, shift, mask, invert) \ | 776 | #define AD1816A_SINGLE(xname, reg, shift, mask, invert) \ |
769 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .info = snd_ad1816a_info_single, \ | 777 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .info = snd_ad1816a_info_single, \ |
770 | .get = snd_ad1816a_get_single, .put = snd_ad1816a_put_single, \ | 778 | .get = snd_ad1816a_get_single, .put = snd_ad1816a_put_single, \ |
@@ -822,6 +830,14 @@ static int snd_ad1816a_put_single(struct snd_kcontrol *kcontrol, struct snd_ctl_ | |||
822 | return change; | 830 | return change; |
823 | } | 831 | } |
824 | 832 | ||
833 | #define AD1816A_DOUBLE_TLV(xname, reg, shift_left, shift_right, mask, invert, xtlv) \ | ||
834 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ | ||
835 | .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ, \ | ||
836 | .name = xname, .info = snd_ad1816a_info_double, \ | ||
837 | .get = snd_ad1816a_get_double, .put = snd_ad1816a_put_double, \ | ||
838 | .private_value = reg | (shift_left << 8) | (shift_right << 12) | (mask << 16) | (invert << 24), \ | ||
839 | .tlv = { .p = (xtlv) } } | ||
840 | |||
825 | #define AD1816A_DOUBLE(xname, reg, shift_left, shift_right, mask, invert) \ | 841 | #define AD1816A_DOUBLE(xname, reg, shift_left, shift_right, mask, invert) \ |
826 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .info = snd_ad1816a_info_double, \ | 842 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .info = snd_ad1816a_info_double, \ |
827 | .get = snd_ad1816a_get_double, .put = snd_ad1816a_put_double, \ | 843 | .get = snd_ad1816a_get_double, .put = snd_ad1816a_put_double, \ |
@@ -890,28 +906,44 @@ static int snd_ad1816a_put_double(struct snd_kcontrol *kcontrol, struct snd_ctl_ | |||
890 | return change; | 906 | return change; |
891 | } | 907 | } |
892 | 908 | ||
909 | static DECLARE_TLV_DB_SCALE(db_scale_4bit, -4500, 300, 0); | ||
910 | static DECLARE_TLV_DB_SCALE(db_scale_5bit, -4650, 150, 0); | ||
911 | static DECLARE_TLV_DB_SCALE(db_scale_6bit, -9450, 150, 0); | ||
912 | static DECLARE_TLV_DB_SCALE(db_scale_5bit_12db_max, -3450, 150, 0); | ||
913 | static DECLARE_TLV_DB_SCALE(db_scale_rec_gain, 0, 150, 0); | ||
914 | |||
893 | static struct snd_kcontrol_new snd_ad1816a_controls[] __devinitdata = { | 915 | static struct snd_kcontrol_new snd_ad1816a_controls[] __devinitdata = { |
894 | AD1816A_DOUBLE("Master Playback Switch", AD1816A_MASTER_ATT, 15, 7, 1, 1), | 916 | AD1816A_DOUBLE("Master Playback Switch", AD1816A_MASTER_ATT, 15, 7, 1, 1), |
895 | AD1816A_DOUBLE("Master Playback Volume", AD1816A_MASTER_ATT, 8, 0, 31, 1), | 917 | AD1816A_DOUBLE_TLV("Master Playback Volume", AD1816A_MASTER_ATT, 8, 0, 31, 1, |
918 | db_scale_5bit), | ||
896 | AD1816A_DOUBLE("PCM Playback Switch", AD1816A_VOICE_ATT, 15, 7, 1, 1), | 919 | AD1816A_DOUBLE("PCM Playback Switch", AD1816A_VOICE_ATT, 15, 7, 1, 1), |
897 | AD1816A_DOUBLE("PCM Playback Volume", AD1816A_VOICE_ATT, 8, 0, 63, 1), | 920 | AD1816A_DOUBLE_TLV("PCM Playback Volume", AD1816A_VOICE_ATT, 8, 0, 63, 1, |
921 | db_scale_6bit), | ||
898 | AD1816A_DOUBLE("Line Playback Switch", AD1816A_LINE_GAIN_ATT, 15, 7, 1, 1), | 922 | AD1816A_DOUBLE("Line Playback Switch", AD1816A_LINE_GAIN_ATT, 15, 7, 1, 1), |
899 | AD1816A_DOUBLE("Line Playback Volume", AD1816A_LINE_GAIN_ATT, 8, 0, 31, 1), | 923 | AD1816A_DOUBLE_TLV("Line Playback Volume", AD1816A_LINE_GAIN_ATT, 8, 0, 31, 1, |
924 | db_scale_5bit_12db_max), | ||
900 | AD1816A_DOUBLE("CD Playback Switch", AD1816A_CD_GAIN_ATT, 15, 7, 1, 1), | 925 | AD1816A_DOUBLE("CD Playback Switch", AD1816A_CD_GAIN_ATT, 15, 7, 1, 1), |
901 | AD1816A_DOUBLE("CD Playback Volume", AD1816A_CD_GAIN_ATT, 8, 0, 31, 1), | 926 | AD1816A_DOUBLE_TLV("CD Playback Volume", AD1816A_CD_GAIN_ATT, 8, 0, 31, 1, |
927 | db_scale_5bit_12db_max), | ||
902 | AD1816A_DOUBLE("Synth Playback Switch", AD1816A_SYNTH_GAIN_ATT, 15, 7, 1, 1), | 928 | AD1816A_DOUBLE("Synth Playback Switch", AD1816A_SYNTH_GAIN_ATT, 15, 7, 1, 1), |
903 | AD1816A_DOUBLE("Synth Playback Volume", AD1816A_SYNTH_GAIN_ATT, 8, 0, 31, 1), | 929 | AD1816A_DOUBLE_TLV("Synth Playback Volume", AD1816A_SYNTH_GAIN_ATT, 8, 0, 31, 1, |
930 | db_scale_5bit_12db_max), | ||
904 | AD1816A_DOUBLE("FM Playback Switch", AD1816A_FM_ATT, 15, 7, 1, 1), | 931 | AD1816A_DOUBLE("FM Playback Switch", AD1816A_FM_ATT, 15, 7, 1, 1), |
905 | AD1816A_DOUBLE("FM Playback Volume", AD1816A_FM_ATT, 8, 0, 63, 1), | 932 | AD1816A_DOUBLE_TLV("FM Playback Volume", AD1816A_FM_ATT, 8, 0, 63, 1, |
933 | db_scale_6bit), | ||
906 | AD1816A_SINGLE("Mic Playback Switch", AD1816A_MIC_GAIN_ATT, 15, 1, 1), | 934 | AD1816A_SINGLE("Mic Playback Switch", AD1816A_MIC_GAIN_ATT, 15, 1, 1), |
907 | AD1816A_SINGLE("Mic Playback Volume", AD1816A_MIC_GAIN_ATT, 8, 31, 1), | 935 | AD1816A_SINGLE_TLV("Mic Playback Volume", AD1816A_MIC_GAIN_ATT, 8, 31, 1, |
936 | db_scale_5bit_12db_max), | ||
908 | AD1816A_SINGLE("Mic Boost", AD1816A_MIC_GAIN_ATT, 14, 1, 0), | 937 | AD1816A_SINGLE("Mic Boost", AD1816A_MIC_GAIN_ATT, 14, 1, 0), |
909 | AD1816A_DOUBLE("Video Playback Switch", AD1816A_VID_GAIN_ATT, 15, 7, 1, 1), | 938 | AD1816A_DOUBLE("Video Playback Switch", AD1816A_VID_GAIN_ATT, 15, 7, 1, 1), |
910 | AD1816A_DOUBLE("Video Playback Volume", AD1816A_VID_GAIN_ATT, 8, 0, 31, 1), | 939 | AD1816A_DOUBLE_TLV("Video Playback Volume", AD1816A_VID_GAIN_ATT, 8, 0, 31, 1, |
940 | db_scale_5bit_12db_max), | ||
911 | AD1816A_SINGLE("Phone Capture Switch", AD1816A_PHONE_IN_GAIN_ATT, 15, 1, 1), | 941 | AD1816A_SINGLE("Phone Capture Switch", AD1816A_PHONE_IN_GAIN_ATT, 15, 1, 1), |
912 | AD1816A_SINGLE("Phone Capture Volume", AD1816A_PHONE_IN_GAIN_ATT, 0, 15, 1), | 942 | AD1816A_SINGLE_TLV("Phone Capture Volume", AD1816A_PHONE_IN_GAIN_ATT, 0, 15, 1, |
943 | db_scale_4bit), | ||
913 | AD1816A_SINGLE("Phone Playback Switch", AD1816A_PHONE_OUT_ATT, 7, 1, 1), | 944 | AD1816A_SINGLE("Phone Playback Switch", AD1816A_PHONE_OUT_ATT, 7, 1, 1), |
914 | AD1816A_SINGLE("Phone Playback Volume", AD1816A_PHONE_OUT_ATT, 0, 31, 1), | 945 | AD1816A_SINGLE_TLV("Phone Playback Volume", AD1816A_PHONE_OUT_ATT, 0, 31, 1, |
946 | db_scale_5bit), | ||
915 | { | 947 | { |
916 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 948 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
917 | .name = "Capture Source", | 949 | .name = "Capture Source", |
@@ -920,7 +952,8 @@ AD1816A_SINGLE("Phone Playback Volume", AD1816A_PHONE_OUT_ATT, 0, 31, 1), | |||
920 | .put = snd_ad1816a_put_mux, | 952 | .put = snd_ad1816a_put_mux, |
921 | }, | 953 | }, |
922 | AD1816A_DOUBLE("Capture Switch", AD1816A_ADC_PGA, 15, 7, 1, 1), | 954 | AD1816A_DOUBLE("Capture Switch", AD1816A_ADC_PGA, 15, 7, 1, 1), |
923 | AD1816A_DOUBLE("Capture Volume", AD1816A_ADC_PGA, 8, 0, 15, 0), | 955 | AD1816A_DOUBLE_TLV("Capture Volume", AD1816A_ADC_PGA, 8, 0, 15, 0, |
956 | db_scale_rec_gain), | ||
924 | AD1816A_SINGLE("3D Control - Switch", AD1816A_3D_PHAT_CTRL, 15, 1, 1), | 957 | AD1816A_SINGLE("3D Control - Switch", AD1816A_3D_PHAT_CTRL, 15, 1, 1), |
925 | AD1816A_SINGLE("3D Control - Level", AD1816A_3D_PHAT_CTRL, 0, 15, 0), | 958 | AD1816A_SINGLE("3D Control - Level", AD1816A_3D_PHAT_CTRL, 0, 15, 0), |
926 | }; | 959 | }; |
diff --git a/sound/isa/ad1848/ad1848_lib.c b/sound/isa/ad1848/ad1848_lib.c index e711f87d5fd1..a6fbd5d1d62f 100644 --- a/sound/isa/ad1848/ad1848_lib.c +++ b/sound/isa/ad1848/ad1848_lib.c | |||
@@ -29,6 +29,7 @@ | |||
29 | #include <sound/core.h> | 29 | #include <sound/core.h> |
30 | #include <sound/ad1848.h> | 30 | #include <sound/ad1848.h> |
31 | #include <sound/control.h> | 31 | #include <sound/control.h> |
32 | #include <sound/tlv.h> | ||
32 | #include <sound/pcm_params.h> | 33 | #include <sound/pcm_params.h> |
33 | 34 | ||
34 | #include <asm/io.h> | 35 | #include <asm/io.h> |
@@ -118,6 +119,8 @@ void snd_ad1848_out(struct snd_ad1848 *chip, | |||
118 | #endif | 119 | #endif |
119 | } | 120 | } |
120 | 121 | ||
122 | EXPORT_SYMBOL(snd_ad1848_out); | ||
123 | |||
121 | static void snd_ad1848_dout(struct snd_ad1848 *chip, | 124 | static void snd_ad1848_dout(struct snd_ad1848 *chip, |
122 | unsigned char reg, unsigned char value) | 125 | unsigned char reg, unsigned char value) |
123 | { | 126 | { |
@@ -941,6 +944,8 @@ int snd_ad1848_create(struct snd_card *card, | |||
941 | return 0; | 944 | return 0; |
942 | } | 945 | } |
943 | 946 | ||
947 | EXPORT_SYMBOL(snd_ad1848_create); | ||
948 | |||
944 | static struct snd_pcm_ops snd_ad1848_playback_ops = { | 949 | static struct snd_pcm_ops snd_ad1848_playback_ops = { |
945 | .open = snd_ad1848_playback_open, | 950 | .open = snd_ad1848_playback_open, |
946 | .close = snd_ad1848_playback_close, | 951 | .close = snd_ad1848_playback_close, |
@@ -988,12 +993,16 @@ int snd_ad1848_pcm(struct snd_ad1848 *chip, int device, struct snd_pcm **rpcm) | |||
988 | return 0; | 993 | return 0; |
989 | } | 994 | } |
990 | 995 | ||
996 | EXPORT_SYMBOL(snd_ad1848_pcm); | ||
997 | |||
991 | const struct snd_pcm_ops *snd_ad1848_get_pcm_ops(int direction) | 998 | const struct snd_pcm_ops *snd_ad1848_get_pcm_ops(int direction) |
992 | { | 999 | { |
993 | return direction == SNDRV_PCM_STREAM_PLAYBACK ? | 1000 | return direction == SNDRV_PCM_STREAM_PLAYBACK ? |
994 | &snd_ad1848_playback_ops : &snd_ad1848_capture_ops; | 1001 | &snd_ad1848_playback_ops : &snd_ad1848_capture_ops; |
995 | } | 1002 | } |
996 | 1003 | ||
1004 | EXPORT_SYMBOL(snd_ad1848_get_pcm_ops); | ||
1005 | |||
997 | /* | 1006 | /* |
998 | * MIXER part | 1007 | * MIXER part |
999 | */ | 1008 | */ |
@@ -1171,7 +1180,8 @@ static int snd_ad1848_put_double(struct snd_kcontrol *kcontrol, struct snd_ctl_e | |||
1171 | 1180 | ||
1172 | /* | 1181 | /* |
1173 | */ | 1182 | */ |
1174 | int snd_ad1848_add_ctl(struct snd_ad1848 *chip, const char *name, int index, int type, unsigned long value) | 1183 | int snd_ad1848_add_ctl_elem(struct snd_ad1848 *chip, |
1184 | const struct ad1848_mix_elem *c) | ||
1175 | { | 1185 | { |
1176 | static struct snd_kcontrol_new newctls[] = { | 1186 | static struct snd_kcontrol_new newctls[] = { |
1177 | [AD1848_MIX_SINGLE] = { | 1187 | [AD1848_MIX_SINGLE] = { |
@@ -1196,32 +1206,46 @@ int snd_ad1848_add_ctl(struct snd_ad1848 *chip, const char *name, int index, int | |||
1196 | struct snd_kcontrol *ctl; | 1206 | struct snd_kcontrol *ctl; |
1197 | int err; | 1207 | int err; |
1198 | 1208 | ||
1199 | ctl = snd_ctl_new1(&newctls[type], chip); | 1209 | ctl = snd_ctl_new1(&newctls[c->type], chip); |
1200 | if (! ctl) | 1210 | if (! ctl) |
1201 | return -ENOMEM; | 1211 | return -ENOMEM; |
1202 | strlcpy(ctl->id.name, name, sizeof(ctl->id.name)); | 1212 | strlcpy(ctl->id.name, c->name, sizeof(ctl->id.name)); |
1203 | ctl->id.index = index; | 1213 | ctl->id.index = c->index; |
1204 | ctl->private_value = value; | 1214 | ctl->private_value = c->private_value; |
1215 | if (c->tlv) { | ||
1216 | ctl->vd[0].access |= SNDRV_CTL_ELEM_ACCESS_TLV_READ; | ||
1217 | ctl->tlv.p = c->tlv; | ||
1218 | } | ||
1205 | if ((err = snd_ctl_add(chip->card, ctl)) < 0) | 1219 | if ((err = snd_ctl_add(chip->card, ctl)) < 0) |
1206 | return err; | 1220 | return err; |
1207 | return 0; | 1221 | return 0; |
1208 | } | 1222 | } |
1209 | 1223 | ||
1224 | EXPORT_SYMBOL(snd_ad1848_add_ctl_elem); | ||
1225 | |||
1226 | static DECLARE_TLV_DB_SCALE(db_scale_6bit, -9450, 150, 0); | ||
1227 | static DECLARE_TLV_DB_SCALE(db_scale_5bit_12db_max, -3450, 150, 0); | ||
1228 | static DECLARE_TLV_DB_SCALE(db_scale_rec_gain, 0, 150, 0); | ||
1210 | 1229 | ||
1211 | static struct ad1848_mix_elem snd_ad1848_controls[] = { | 1230 | static struct ad1848_mix_elem snd_ad1848_controls[] = { |
1212 | AD1848_DOUBLE("PCM Playback Switch", 0, AD1848_LEFT_OUTPUT, AD1848_RIGHT_OUTPUT, 7, 7, 1, 1), | 1231 | AD1848_DOUBLE("PCM Playback Switch", 0, AD1848_LEFT_OUTPUT, AD1848_RIGHT_OUTPUT, 7, 7, 1, 1), |
1213 | AD1848_DOUBLE("PCM Playback Volume", 0, AD1848_LEFT_OUTPUT, AD1848_RIGHT_OUTPUT, 0, 0, 63, 1), | 1232 | AD1848_DOUBLE_TLV("PCM Playback Volume", 0, AD1848_LEFT_OUTPUT, AD1848_RIGHT_OUTPUT, 0, 0, 63, 1, |
1233 | db_scale_6bit), | ||
1214 | AD1848_DOUBLE("Aux Playback Switch", 0, AD1848_AUX1_LEFT_INPUT, AD1848_AUX1_RIGHT_INPUT, 7, 7, 1, 1), | 1234 | AD1848_DOUBLE("Aux Playback Switch", 0, AD1848_AUX1_LEFT_INPUT, AD1848_AUX1_RIGHT_INPUT, 7, 7, 1, 1), |
1215 | AD1848_DOUBLE("Aux Playback Volume", 0, AD1848_AUX1_LEFT_INPUT, AD1848_AUX1_RIGHT_INPUT, 0, 0, 31, 1), | 1235 | AD1848_DOUBLE_TLV("Aux Playback Volume", 0, AD1848_AUX1_LEFT_INPUT, AD1848_AUX1_RIGHT_INPUT, 0, 0, 31, 1, |
1236 | db_scale_5bit_12db_max), | ||
1216 | AD1848_DOUBLE("Aux Playback Switch", 1, AD1848_AUX2_LEFT_INPUT, AD1848_AUX2_RIGHT_INPUT, 7, 7, 1, 1), | 1237 | AD1848_DOUBLE("Aux Playback Switch", 1, AD1848_AUX2_LEFT_INPUT, AD1848_AUX2_RIGHT_INPUT, 7, 7, 1, 1), |
1217 | AD1848_DOUBLE("Aux Playback Volume", 1, AD1848_AUX2_LEFT_INPUT, AD1848_AUX2_RIGHT_INPUT, 0, 0, 31, 1), | 1238 | AD1848_DOUBLE_TLV("Aux Playback Volume", 1, AD1848_AUX2_LEFT_INPUT, AD1848_AUX2_RIGHT_INPUT, 0, 0, 31, 1, |
1218 | AD1848_DOUBLE("Capture Volume", 0, AD1848_LEFT_INPUT, AD1848_RIGHT_INPUT, 0, 0, 15, 0), | 1239 | db_scale_5bit_12db_max), |
1240 | AD1848_DOUBLE_TLV("Capture Volume", 0, AD1848_LEFT_INPUT, AD1848_RIGHT_INPUT, 0, 0, 15, 0, | ||
1241 | db_scale_rec_gain), | ||
1219 | { | 1242 | { |
1220 | .name = "Capture Source", | 1243 | .name = "Capture Source", |
1221 | .type = AD1848_MIX_CAPTURE, | 1244 | .type = AD1848_MIX_CAPTURE, |
1222 | }, | 1245 | }, |
1223 | AD1848_SINGLE("Loopback Capture Switch", 0, AD1848_LOOPBACK, 0, 1, 0), | 1246 | AD1848_SINGLE("Loopback Capture Switch", 0, AD1848_LOOPBACK, 0, 1, 0), |
1224 | AD1848_SINGLE("Loopback Capture Volume", 0, AD1848_LOOPBACK, 1, 63, 0) | 1247 | AD1848_SINGLE_TLV("Loopback Capture Volume", 0, AD1848_LOOPBACK, 1, 63, 0, |
1248 | db_scale_6bit), | ||
1225 | }; | 1249 | }; |
1226 | 1250 | ||
1227 | int snd_ad1848_mixer(struct snd_ad1848 *chip) | 1251 | int snd_ad1848_mixer(struct snd_ad1848 *chip) |
@@ -1245,12 +1269,7 @@ int snd_ad1848_mixer(struct snd_ad1848 *chip) | |||
1245 | return 0; | 1269 | return 0; |
1246 | } | 1270 | } |
1247 | 1271 | ||
1248 | EXPORT_SYMBOL(snd_ad1848_out); | ||
1249 | EXPORT_SYMBOL(snd_ad1848_create); | ||
1250 | EXPORT_SYMBOL(snd_ad1848_pcm); | ||
1251 | EXPORT_SYMBOL(snd_ad1848_get_pcm_ops); | ||
1252 | EXPORT_SYMBOL(snd_ad1848_mixer); | 1272 | EXPORT_SYMBOL(snd_ad1848_mixer); |
1253 | EXPORT_SYMBOL(snd_ad1848_add_ctl); | ||
1254 | 1273 | ||
1255 | /* | 1274 | /* |
1256 | * INIT part | 1275 | * INIT part |
diff --git a/sound/isa/es18xx.c b/sound/isa/es18xx.c index 34998de9968c..85818200333f 100644 --- a/sound/isa/es18xx.c +++ b/sound/isa/es18xx.c | |||
@@ -2038,7 +2038,80 @@ MODULE_PARM_DESC(dma2, "DMA 2 # for ES18xx driver."); | |||
2038 | static struct platform_device *platform_devices[SNDRV_CARDS]; | 2038 | static struct platform_device *platform_devices[SNDRV_CARDS]; |
2039 | 2039 | ||
2040 | #ifdef CONFIG_PNP | 2040 | #ifdef CONFIG_PNP |
2041 | static int pnp_registered; | 2041 | static int pnp_registered, pnpc_registered; |
2042 | |||
2043 | static struct pnp_device_id snd_audiodrive_pnpbiosids[] = { | ||
2044 | { .id = "ESS1869" }, | ||
2045 | { .id = "" } /* end */ | ||
2046 | }; | ||
2047 | |||
2048 | MODULE_DEVICE_TABLE(pnp, snd_audiodrive_pnpbiosids); | ||
2049 | |||
2050 | /* PnP main device initialization */ | ||
2051 | static int __devinit snd_audiodrive_pnp_init_main(int dev, struct pnp_dev *pdev, | ||
2052 | struct pnp_resource_table *cfg) | ||
2053 | { | ||
2054 | int err; | ||
2055 | |||
2056 | pnp_init_resource_table(cfg); | ||
2057 | if (port[dev] != SNDRV_AUTO_PORT) | ||
2058 | pnp_resource_change(&cfg->port_resource[0], port[dev], 16); | ||
2059 | if (fm_port[dev] != SNDRV_AUTO_PORT) | ||
2060 | pnp_resource_change(&cfg->port_resource[1], fm_port[dev], 4); | ||
2061 | if (mpu_port[dev] != SNDRV_AUTO_PORT) | ||
2062 | pnp_resource_change(&cfg->port_resource[2], mpu_port[dev], 2); | ||
2063 | if (dma1[dev] != SNDRV_AUTO_DMA) | ||
2064 | pnp_resource_change(&cfg->dma_resource[0], dma1[dev], 1); | ||
2065 | if (dma2[dev] != SNDRV_AUTO_DMA) | ||
2066 | pnp_resource_change(&cfg->dma_resource[1], dma2[dev], 1); | ||
2067 | if (irq[dev] != SNDRV_AUTO_IRQ) | ||
2068 | pnp_resource_change(&cfg->irq_resource[0], irq[dev], 1); | ||
2069 | if (pnp_device_is_isapnp(pdev)) { | ||
2070 | err = pnp_manual_config_dev(pdev, cfg, 0); | ||
2071 | if (err < 0) | ||
2072 | snd_printk(KERN_ERR PFX "PnP manual resources are invalid, using auto config\n"); | ||
2073 | } | ||
2074 | err = pnp_activate_dev(pdev); | ||
2075 | if (err < 0) { | ||
2076 | snd_printk(KERN_ERR PFX "PnP configure failure (out of resources?)\n"); | ||
2077 | return -EBUSY; | ||
2078 | } | ||
2079 | /* ok. hack using Vendor-Defined Card-Level registers */ | ||
2080 | /* skip csn and logdev initialization - already done in isapnp_configure */ | ||
2081 | if (pnp_device_is_isapnp(pdev)) { | ||
2082 | isapnp_cfg_begin(isapnp_card_number(pdev), isapnp_csn_number(pdev)); | ||
2083 | isapnp_write_byte(0x27, pnp_irq(pdev, 0)); /* Hardware Volume IRQ Number */ | ||
2084 | if (mpu_port[dev] != SNDRV_AUTO_PORT) | ||
2085 | isapnp_write_byte(0x28, pnp_irq(pdev, 0)); /* MPU-401 IRQ Number */ | ||
2086 | isapnp_write_byte(0x72, pnp_irq(pdev, 0)); /* second IRQ */ | ||
2087 | isapnp_cfg_end(); | ||
2088 | } | ||
2089 | port[dev] = pnp_port_start(pdev, 0); | ||
2090 | fm_port[dev] = pnp_port_start(pdev, 1); | ||
2091 | mpu_port[dev] = pnp_port_start(pdev, 2); | ||
2092 | dma1[dev] = pnp_dma(pdev, 0); | ||
2093 | dma2[dev] = pnp_dma(pdev, 1); | ||
2094 | irq[dev] = pnp_irq(pdev, 0); | ||
2095 | snd_printdd("PnP ES18xx: port=0x%lx, fm port=0x%lx, mpu port=0x%lx\n", port[dev], fm_port[dev], mpu_port[dev]); | ||
2096 | snd_printdd("PnP ES18xx: dma1=%i, dma2=%i, irq=%i\n", dma1[dev], dma2[dev], irq[dev]); | ||
2097 | return 0; | ||
2098 | } | ||
2099 | |||
2100 | static int __devinit snd_audiodrive_pnp(int dev, struct snd_audiodrive *acard, | ||
2101 | struct pnp_dev *pdev) | ||
2102 | { | ||
2103 | struct pnp_resource_table * cfg = kmalloc(sizeof(struct pnp_resource_table), GFP_KERNEL); | ||
2104 | |||
2105 | if (!cfg) | ||
2106 | return -ENOMEM; | ||
2107 | acard->dev = pdev; | ||
2108 | if (snd_audiodrive_pnp_init_main(dev, acard->dev, cfg) < 0) { | ||
2109 | kfree(cfg); | ||
2110 | return -EBUSY; | ||
2111 | } | ||
2112 | kfree(cfg); | ||
2113 | return 0; | ||
2114 | } | ||
2042 | 2115 | ||
2043 | static struct pnp_card_device_id snd_audiodrive_pnpids[] = { | 2116 | static struct pnp_card_device_id snd_audiodrive_pnpids[] = { |
2044 | /* ESS 1868 (integrated on Compaq dual P-Pro motherboard and Genius 18PnP 3D) */ | 2117 | /* ESS 1868 (integrated on Compaq dual P-Pro motherboard and Genius 18PnP 3D) */ |
@@ -2061,13 +2134,11 @@ static struct pnp_card_device_id snd_audiodrive_pnpids[] = { | |||
2061 | 2134 | ||
2062 | MODULE_DEVICE_TABLE(pnp_card, snd_audiodrive_pnpids); | 2135 | MODULE_DEVICE_TABLE(pnp_card, snd_audiodrive_pnpids); |
2063 | 2136 | ||
2064 | static int __devinit snd_audiodrive_pnp(int dev, struct snd_audiodrive *acard, | 2137 | static int __devinit snd_audiodrive_pnpc(int dev, struct snd_audiodrive *acard, |
2065 | struct pnp_card_link *card, | 2138 | struct pnp_card_link *card, |
2066 | const struct pnp_card_device_id *id) | 2139 | const struct pnp_card_device_id *id) |
2067 | { | 2140 | { |
2068 | struct pnp_dev *pdev; | ||
2069 | struct pnp_resource_table * cfg = kmalloc(sizeof(struct pnp_resource_table), GFP_KERNEL); | 2141 | struct pnp_resource_table * cfg = kmalloc(sizeof(struct pnp_resource_table), GFP_KERNEL); |
2070 | int err; | ||
2071 | 2142 | ||
2072 | if (!cfg) | 2143 | if (!cfg) |
2073 | return -ENOMEM; | 2144 | return -ENOMEM; |
@@ -2082,58 +2153,16 @@ static int __devinit snd_audiodrive_pnp(int dev, struct snd_audiodrive *acard, | |||
2082 | return -EBUSY; | 2153 | return -EBUSY; |
2083 | } | 2154 | } |
2084 | /* Control port initialization */ | 2155 | /* Control port initialization */ |
2085 | err = pnp_activate_dev(acard->devc); | 2156 | if (pnp_activate_dev(acard->devc) < 0) { |
2086 | if (err < 0) { | ||
2087 | snd_printk(KERN_ERR PFX "PnP control configure failure (out of resources?)\n"); | 2157 | snd_printk(KERN_ERR PFX "PnP control configure failure (out of resources?)\n"); |
2088 | kfree(cfg); | ||
2089 | return -EAGAIN; | 2158 | return -EAGAIN; |
2090 | } | 2159 | } |
2091 | snd_printdd("pnp: port=0x%llx\n", | 2160 | snd_printdd("pnp: port=0x%llx\n", |
2092 | (unsigned long long)pnp_port_start(acard->devc, 0)); | 2161 | (unsigned long long)pnp_port_start(acard->devc, 0)); |
2093 | /* PnP initialization */ | 2162 | if (snd_audiodrive_pnp_init_main(dev, acard->dev, cfg) < 0) { |
2094 | pdev = acard->dev; | ||
2095 | pnp_init_resource_table(cfg); | ||
2096 | if (port[dev] != SNDRV_AUTO_PORT) | ||
2097 | pnp_resource_change(&cfg->port_resource[0], port[dev], 16); | ||
2098 | if (fm_port[dev] != SNDRV_AUTO_PORT) | ||
2099 | pnp_resource_change(&cfg->port_resource[1], fm_port[dev], 4); | ||
2100 | if (mpu_port[dev] != SNDRV_AUTO_PORT) | ||
2101 | pnp_resource_change(&cfg->port_resource[2], mpu_port[dev], 2); | ||
2102 | if (dma1[dev] != SNDRV_AUTO_DMA) | ||
2103 | pnp_resource_change(&cfg->dma_resource[0], dma1[dev], 1); | ||
2104 | if (dma2[dev] != SNDRV_AUTO_DMA) | ||
2105 | pnp_resource_change(&cfg->dma_resource[1], dma2[dev], 1); | ||
2106 | if (irq[dev] != SNDRV_AUTO_IRQ) | ||
2107 | pnp_resource_change(&cfg->irq_resource[0], irq[dev], 1); | ||
2108 | err = pnp_manual_config_dev(pdev, cfg, 0); | ||
2109 | if (err < 0) | ||
2110 | snd_printk(KERN_ERR PFX "PnP manual resources are invalid, using auto config\n"); | ||
2111 | err = pnp_activate_dev(pdev); | ||
2112 | if (err < 0) { | ||
2113 | snd_printk(KERN_ERR PFX "PnP configure failure (out of resources?)\n"); | ||
2114 | kfree(cfg); | 2163 | kfree(cfg); |
2115 | return -EBUSY; | 2164 | return -EBUSY; |
2116 | } | 2165 | } |
2117 | /* ok. hack using Vendor-Defined Card-Level registers */ | ||
2118 | /* skip csn and logdev initialization - already done in isapnp_configure */ | ||
2119 | if (pnp_device_is_isapnp(pdev)) { | ||
2120 | isapnp_cfg_begin(isapnp_card_number(pdev), isapnp_csn_number(pdev)); | ||
2121 | isapnp_write_byte(0x27, pnp_irq(pdev, 0)); /* Hardware Volume IRQ Number */ | ||
2122 | if (mpu_port[dev] != SNDRV_AUTO_PORT) | ||
2123 | isapnp_write_byte(0x28, pnp_irq(pdev, 0)); /* MPU-401 IRQ Number */ | ||
2124 | isapnp_write_byte(0x72, pnp_irq(pdev, 0)); /* second IRQ */ | ||
2125 | isapnp_cfg_end(); | ||
2126 | } else { | ||
2127 | snd_printk(KERN_ERR PFX "unable to install ISA PnP hack, expect malfunction\n"); | ||
2128 | } | ||
2129 | port[dev] = pnp_port_start(pdev, 0); | ||
2130 | fm_port[dev] = pnp_port_start(pdev, 1); | ||
2131 | mpu_port[dev] = pnp_port_start(pdev, 2); | ||
2132 | dma1[dev] = pnp_dma(pdev, 0); | ||
2133 | dma2[dev] = pnp_dma(pdev, 1); | ||
2134 | irq[dev] = pnp_irq(pdev, 0); | ||
2135 | snd_printdd("PnP ES18xx: port=0x%lx, fm port=0x%lx, mpu port=0x%lx\n", port[dev], fm_port[dev], mpu_port[dev]); | ||
2136 | snd_printdd("PnP ES18xx: dma1=%i, dma2=%i, irq=%i\n", dma1[dev], dma2[dev], irq[dev]); | ||
2137 | kfree(cfg); | 2166 | kfree(cfg); |
2138 | return 0; | 2167 | return 0; |
2139 | } | 2168 | } |
@@ -2302,7 +2331,69 @@ static struct platform_driver snd_es18xx_nonpnp_driver = { | |||
2302 | #ifdef CONFIG_PNP | 2331 | #ifdef CONFIG_PNP |
2303 | static unsigned int __devinitdata es18xx_pnp_devices; | 2332 | static unsigned int __devinitdata es18xx_pnp_devices; |
2304 | 2333 | ||
2305 | static int __devinit snd_audiodrive_pnp_detect(struct pnp_card_link *pcard, | 2334 | static int __devinit snd_audiodrive_pnp_detect(struct pnp_dev *pdev, |
2335 | const struct pnp_device_id *id) | ||
2336 | { | ||
2337 | static int dev; | ||
2338 | int err; | ||
2339 | struct snd_card *card; | ||
2340 | |||
2341 | if (pnp_device_is_isapnp(pdev)) | ||
2342 | return -ENOENT; /* we have another procedure - card */ | ||
2343 | for (; dev < SNDRV_CARDS; dev++) { | ||
2344 | if (enable[dev] && isapnp[dev]) | ||
2345 | break; | ||
2346 | } | ||
2347 | if (dev >= SNDRV_CARDS) | ||
2348 | return -ENODEV; | ||
2349 | |||
2350 | card = snd_es18xx_card_new(dev); | ||
2351 | if (! card) | ||
2352 | return -ENOMEM; | ||
2353 | if ((err = snd_audiodrive_pnp(dev, card->private_data, pdev)) < 0) { | ||
2354 | snd_card_free(card); | ||
2355 | return err; | ||
2356 | } | ||
2357 | snd_card_set_dev(card, &pdev->dev); | ||
2358 | if ((err = snd_audiodrive_probe(card, dev)) < 0) { | ||
2359 | snd_card_free(card); | ||
2360 | return err; | ||
2361 | } | ||
2362 | pnp_set_drvdata(pdev, card); | ||
2363 | dev++; | ||
2364 | es18xx_pnp_devices++; | ||
2365 | return 0; | ||
2366 | } | ||
2367 | |||
2368 | static void __devexit snd_audiodrive_pnp_remove(struct pnp_dev * pdev) | ||
2369 | { | ||
2370 | snd_card_free(pnp_get_drvdata(pdev)); | ||
2371 | pnp_set_drvdata(pdev, NULL); | ||
2372 | } | ||
2373 | |||
2374 | #ifdef CONFIG_PM | ||
2375 | static int snd_audiodrive_pnp_suspend(struct pnp_dev *pdev, pm_message_t state) | ||
2376 | { | ||
2377 | return snd_es18xx_suspend(pnp_get_drvdata(pdev), state); | ||
2378 | } | ||
2379 | static int snd_audiodrive_pnp_resume(struct pnp_dev *pdev) | ||
2380 | { | ||
2381 | return snd_es18xx_resume(pnp_get_drvdata(pdev)); | ||
2382 | } | ||
2383 | #endif | ||
2384 | |||
2385 | static struct pnp_driver es18xx_pnp_driver = { | ||
2386 | .name = "es18xx-pnpbios", | ||
2387 | .id_table = snd_audiodrive_pnpbiosids, | ||
2388 | .probe = snd_audiodrive_pnp_detect, | ||
2389 | .remove = __devexit_p(snd_audiodrive_pnp_remove), | ||
2390 | #ifdef CONFIG_PM | ||
2391 | .suspend = snd_audiodrive_pnp_suspend, | ||
2392 | .resume = snd_audiodrive_pnp_resume, | ||
2393 | #endif | ||
2394 | }; | ||
2395 | |||
2396 | static int __devinit snd_audiodrive_pnpc_detect(struct pnp_card_link *pcard, | ||
2306 | const struct pnp_card_device_id *pid) | 2397 | const struct pnp_card_device_id *pid) |
2307 | { | 2398 | { |
2308 | static int dev; | 2399 | static int dev; |
@@ -2320,7 +2411,7 @@ static int __devinit snd_audiodrive_pnp_detect(struct pnp_card_link *pcard, | |||
2320 | if (! card) | 2411 | if (! card) |
2321 | return -ENOMEM; | 2412 | return -ENOMEM; |
2322 | 2413 | ||
2323 | if ((res = snd_audiodrive_pnp(dev, card->private_data, pcard, pid)) < 0) { | 2414 | if ((res = snd_audiodrive_pnpc(dev, card->private_data, pcard, pid)) < 0) { |
2324 | snd_card_free(card); | 2415 | snd_card_free(card); |
2325 | return res; | 2416 | return res; |
2326 | } | 2417 | } |
@@ -2336,19 +2427,19 @@ static int __devinit snd_audiodrive_pnp_detect(struct pnp_card_link *pcard, | |||
2336 | return 0; | 2427 | return 0; |
2337 | } | 2428 | } |
2338 | 2429 | ||
2339 | static void __devexit snd_audiodrive_pnp_remove(struct pnp_card_link * pcard) | 2430 | static void __devexit snd_audiodrive_pnpc_remove(struct pnp_card_link * pcard) |
2340 | { | 2431 | { |
2341 | snd_card_free(pnp_get_card_drvdata(pcard)); | 2432 | snd_card_free(pnp_get_card_drvdata(pcard)); |
2342 | pnp_set_card_drvdata(pcard, NULL); | 2433 | pnp_set_card_drvdata(pcard, NULL); |
2343 | } | 2434 | } |
2344 | 2435 | ||
2345 | #ifdef CONFIG_PM | 2436 | #ifdef CONFIG_PM |
2346 | static int snd_audiodrive_pnp_suspend(struct pnp_card_link *pcard, pm_message_t state) | 2437 | static int snd_audiodrive_pnpc_suspend(struct pnp_card_link *pcard, pm_message_t state) |
2347 | { | 2438 | { |
2348 | return snd_es18xx_suspend(pnp_get_card_drvdata(pcard), state); | 2439 | return snd_es18xx_suspend(pnp_get_card_drvdata(pcard), state); |
2349 | } | 2440 | } |
2350 | 2441 | ||
2351 | static int snd_audiodrive_pnp_resume(struct pnp_card_link *pcard) | 2442 | static int snd_audiodrive_pnpc_resume(struct pnp_card_link *pcard) |
2352 | { | 2443 | { |
2353 | return snd_es18xx_resume(pnp_get_card_drvdata(pcard)); | 2444 | return snd_es18xx_resume(pnp_get_card_drvdata(pcard)); |
2354 | } | 2445 | } |
@@ -2359,11 +2450,11 @@ static struct pnp_card_driver es18xx_pnpc_driver = { | |||
2359 | .flags = PNP_DRIVER_RES_DISABLE, | 2450 | .flags = PNP_DRIVER_RES_DISABLE, |
2360 | .name = "es18xx", | 2451 | .name = "es18xx", |
2361 | .id_table = snd_audiodrive_pnpids, | 2452 | .id_table = snd_audiodrive_pnpids, |
2362 | .probe = snd_audiodrive_pnp_detect, | 2453 | .probe = snd_audiodrive_pnpc_detect, |
2363 | .remove = __devexit_p(snd_audiodrive_pnp_remove), | 2454 | .remove = __devexit_p(snd_audiodrive_pnpc_remove), |
2364 | #ifdef CONFIG_PM | 2455 | #ifdef CONFIG_PM |
2365 | .suspend = snd_audiodrive_pnp_suspend, | 2456 | .suspend = snd_audiodrive_pnpc_suspend, |
2366 | .resume = snd_audiodrive_pnp_resume, | 2457 | .resume = snd_audiodrive_pnpc_resume, |
2367 | #endif | 2458 | #endif |
2368 | }; | 2459 | }; |
2369 | #endif /* CONFIG_PNP */ | 2460 | #endif /* CONFIG_PNP */ |
@@ -2373,8 +2464,10 @@ static void __init_or_module snd_es18xx_unregister_all(void) | |||
2373 | int i; | 2464 | int i; |
2374 | 2465 | ||
2375 | #ifdef CONFIG_PNP | 2466 | #ifdef CONFIG_PNP |
2376 | if (pnp_registered) | 2467 | if (pnpc_registered) |
2377 | pnp_unregister_card_driver(&es18xx_pnpc_driver); | 2468 | pnp_unregister_card_driver(&es18xx_pnpc_driver); |
2469 | if (pnp_registered) | ||
2470 | pnp_unregister_driver(&es18xx_pnp_driver); | ||
2378 | #endif | 2471 | #endif |
2379 | for (i = 0; i < ARRAY_SIZE(platform_devices); ++i) | 2472 | for (i = 0; i < ARRAY_SIZE(platform_devices); ++i) |
2380 | platform_device_unregister(platform_devices[i]); | 2473 | platform_device_unregister(platform_devices[i]); |
@@ -2405,11 +2498,13 @@ static int __init alsa_card_es18xx_init(void) | |||
2405 | } | 2498 | } |
2406 | 2499 | ||
2407 | #ifdef CONFIG_PNP | 2500 | #ifdef CONFIG_PNP |
2408 | err = pnp_register_card_driver(&es18xx_pnpc_driver); | 2501 | err = pnp_register_driver(&es18xx_pnp_driver); |
2409 | if (!err) { | 2502 | if (!err) |
2410 | pnp_registered = 1; | 2503 | pnp_registered = 1; |
2411 | cards += es18xx_pnp_devices; | 2504 | err = pnp_register_card_driver(&es18xx_pnpc_driver); |
2412 | } | 2505 | if (!err) |
2506 | pnpc_registered = 1; | ||
2507 | cards += es18xx_pnp_devices; | ||
2413 | #endif | 2508 | #endif |
2414 | 2509 | ||
2415 | if(!cards) { | 2510 | if(!cards) { |
diff --git a/sound/isa/gus/gus_mem_proc.c b/sound/isa/gus/gus_mem_proc.c index 4080255007d5..80f0a83818b2 100644 --- a/sound/isa/gus/gus_mem_proc.c +++ b/sound/isa/gus/gus_mem_proc.c | |||
@@ -61,13 +61,13 @@ static long long snd_gf1_mem_proc_llseek(struct snd_info_entry *entry, | |||
61 | struct gus_proc_private *priv = entry->private_data; | 61 | struct gus_proc_private *priv = entry->private_data; |
62 | 62 | ||
63 | switch (orig) { | 63 | switch (orig) { |
64 | case 0: /* SEEK_SET */ | 64 | case SEEK_SET: |
65 | file->f_pos = offset; | 65 | file->f_pos = offset; |
66 | break; | 66 | break; |
67 | case 1: /* SEEK_CUR */ | 67 | case SEEK_CUR: |
68 | file->f_pos += offset; | 68 | file->f_pos += offset; |
69 | break; | 69 | break; |
70 | case 2: /* SEEK_END, offset is negative */ | 70 | case SEEK_END: /* offset is negative */ |
71 | file->f_pos = priv->size + offset; | 71 | file->f_pos = priv->size + offset; |
72 | break; | 72 | break; |
73 | default: | 73 | default: |
diff --git a/sound/isa/opl3sa2.c b/sound/isa/opl3sa2.c index 4031b61b797f..da92bf6c392b 100644 --- a/sound/isa/opl3sa2.c +++ b/sound/isa/opl3sa2.c | |||
@@ -33,6 +33,7 @@ | |||
33 | #include <sound/mpu401.h> | 33 | #include <sound/mpu401.h> |
34 | #include <sound/opl3.h> | 34 | #include <sound/opl3.h> |
35 | #include <sound/initval.h> | 35 | #include <sound/initval.h> |
36 | #include <sound/tlv.h> | ||
36 | 37 | ||
37 | #include <asm/io.h> | 38 | #include <asm/io.h> |
38 | 39 | ||
@@ -337,6 +338,14 @@ static irqreturn_t snd_opl3sa2_interrupt(int irq, void *dev_id, struct pt_regs * | |||
337 | .info = snd_opl3sa2_info_single, \ | 338 | .info = snd_opl3sa2_info_single, \ |
338 | .get = snd_opl3sa2_get_single, .put = snd_opl3sa2_put_single, \ | 339 | .get = snd_opl3sa2_get_single, .put = snd_opl3sa2_put_single, \ |
339 | .private_value = reg | (shift << 8) | (mask << 16) | (invert << 24) } | 340 | .private_value = reg | (shift << 8) | (mask << 16) | (invert << 24) } |
341 | #define OPL3SA2_SINGLE_TLV(xname, xindex, reg, shift, mask, invert, xtlv) \ | ||
342 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ | ||
343 | .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ, \ | ||
344 | .name = xname, .index = xindex, \ | ||
345 | .info = snd_opl3sa2_info_single, \ | ||
346 | .get = snd_opl3sa2_get_single, .put = snd_opl3sa2_put_single, \ | ||
347 | .private_value = reg | (shift << 8) | (mask << 16) | (invert << 24), \ | ||
348 | .tlv = { .p = (xtlv) } } | ||
340 | 349 | ||
341 | static int snd_opl3sa2_info_single(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) | 350 | static int snd_opl3sa2_info_single(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) |
342 | { | 351 | { |
@@ -395,6 +404,14 @@ static int snd_opl3sa2_put_single(struct snd_kcontrol *kcontrol, struct snd_ctl_ | |||
395 | .info = snd_opl3sa2_info_double, \ | 404 | .info = snd_opl3sa2_info_double, \ |
396 | .get = snd_opl3sa2_get_double, .put = snd_opl3sa2_put_double, \ | 405 | .get = snd_opl3sa2_get_double, .put = snd_opl3sa2_put_double, \ |
397 | .private_value = left_reg | (right_reg << 8) | (shift_left << 16) | (shift_right << 19) | (mask << 24) | (invert << 22) } | 406 | .private_value = left_reg | (right_reg << 8) | (shift_left << 16) | (shift_right << 19) | (mask << 24) | (invert << 22) } |
407 | #define OPL3SA2_DOUBLE_TLV(xname, xindex, left_reg, right_reg, shift_left, shift_right, mask, invert, xtlv) \ | ||
408 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ | ||
409 | .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ, \ | ||
410 | .name = xname, .index = xindex, \ | ||
411 | .info = snd_opl3sa2_info_double, \ | ||
412 | .get = snd_opl3sa2_get_double, .put = snd_opl3sa2_put_double, \ | ||
413 | .private_value = left_reg | (right_reg << 8) | (shift_left << 16) | (shift_right << 19) | (mask << 24) | (invert << 22), \ | ||
414 | .tlv = { .p = (xtlv) } } | ||
398 | 415 | ||
399 | static int snd_opl3sa2_info_double(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) | 416 | static int snd_opl3sa2_info_double(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) |
400 | { | 417 | { |
@@ -469,11 +486,16 @@ static int snd_opl3sa2_put_double(struct snd_kcontrol *kcontrol, struct snd_ctl_ | |||
469 | return change; | 486 | return change; |
470 | } | 487 | } |
471 | 488 | ||
489 | static DECLARE_TLV_DB_SCALE(db_scale_master, -3000, 200, 0); | ||
490 | static DECLARE_TLV_DB_SCALE(db_scale_5bit_12db_max, -3450, 150, 0); | ||
491 | |||
472 | static struct snd_kcontrol_new snd_opl3sa2_controls[] = { | 492 | static struct snd_kcontrol_new snd_opl3sa2_controls[] = { |
473 | OPL3SA2_DOUBLE("Master Playback Switch", 0, 0x07, 0x08, 7, 7, 1, 1), | 493 | OPL3SA2_DOUBLE("Master Playback Switch", 0, 0x07, 0x08, 7, 7, 1, 1), |
474 | OPL3SA2_DOUBLE("Master Playback Volume", 0, 0x07, 0x08, 0, 0, 15, 1), | 494 | OPL3SA2_DOUBLE_TLV("Master Playback Volume", 0, 0x07, 0x08, 0, 0, 15, 1, |
495 | db_scale_master), | ||
475 | OPL3SA2_SINGLE("Mic Playback Switch", 0, 0x09, 7, 1, 1), | 496 | OPL3SA2_SINGLE("Mic Playback Switch", 0, 0x09, 7, 1, 1), |
476 | OPL3SA2_SINGLE("Mic Playback Volume", 0, 0x09, 0, 31, 1) | 497 | OPL3SA2_SINGLE_TLV("Mic Playback Volume", 0, 0x09, 0, 31, 1, |
498 | db_scale_5bit_12db_max), | ||
477 | }; | 499 | }; |
478 | 500 | ||
479 | static struct snd_kcontrol_new snd_opl3sa2_tone_controls[] = { | 501 | static struct snd_kcontrol_new snd_opl3sa2_tone_controls[] = { |
diff --git a/sound/pci/Kconfig b/sound/pci/Kconfig index e49c0fe21b0d..8a6b1803c763 100644 --- a/sound/pci/Kconfig +++ b/sound/pci/Kconfig | |||
@@ -475,6 +475,7 @@ config SND_FM801_TEA575X | |||
475 | depends on SND_FM801_TEA575X_BOOL | 475 | depends on SND_FM801_TEA575X_BOOL |
476 | default SND_FM801 | 476 | default SND_FM801 |
477 | select VIDEO_V4L1 | 477 | select VIDEO_V4L1 |
478 | select VIDEO_DEV | ||
478 | 479 | ||
479 | config SND_HDA_INTEL | 480 | config SND_HDA_INTEL |
480 | tristate "Intel HD Audio" | 481 | tristate "Intel HD Audio" |
@@ -743,4 +744,17 @@ config SND_YMFPCI | |||
743 | To compile this driver as a module, choose M here: the module | 744 | To compile this driver as a module, choose M here: the module |
744 | will be called snd-ymfpci. | 745 | will be called snd-ymfpci. |
745 | 746 | ||
747 | config SND_AC97_POWER_SAVE | ||
748 | bool "AC97 Power-Saving Mode" | ||
749 | depends on SND_AC97_CODEC && EXPERIMENTAL | ||
750 | default n | ||
751 | help | ||
752 | Say Y here to enable the aggressive power-saving support of | ||
753 | AC97 codecs. In this mode, the power-mode is dynamically | ||
754 | controlled at each open/close. | ||
755 | |||
756 | The mode is activated by passing power_save=1 option to | ||
757 | snd-ac97-codec driver. You can toggle it dynamically over | ||
758 | sysfs, too. | ||
759 | |||
746 | endmenu | 760 | endmenu |
diff --git a/sound/pci/ac97/ac97_codec.c b/sound/pci/ac97/ac97_codec.c index 51e83d7a839a..a79e91850ba3 100644 --- a/sound/pci/ac97/ac97_codec.c +++ b/sound/pci/ac97/ac97_codec.c | |||
@@ -31,6 +31,7 @@ | |||
31 | #include <linux/mutex.h> | 31 | #include <linux/mutex.h> |
32 | #include <sound/core.h> | 32 | #include <sound/core.h> |
33 | #include <sound/pcm.h> | 33 | #include <sound/pcm.h> |
34 | #include <sound/tlv.h> | ||
34 | #include <sound/ac97_codec.h> | 35 | #include <sound/ac97_codec.h> |
35 | #include <sound/asoundef.h> | 36 | #include <sound/asoundef.h> |
36 | #include <sound/initval.h> | 37 | #include <sound/initval.h> |
@@ -47,6 +48,11 @@ static int enable_loopback; | |||
47 | module_param(enable_loopback, bool, 0444); | 48 | module_param(enable_loopback, bool, 0444); |
48 | MODULE_PARM_DESC(enable_loopback, "Enable AC97 ADC/DAC Loopback Control"); | 49 | MODULE_PARM_DESC(enable_loopback, "Enable AC97 ADC/DAC Loopback Control"); |
49 | 50 | ||
51 | #ifdef CONFIG_SND_AC97_POWER_SAVE | ||
52 | static int power_save; | ||
53 | module_param(power_save, bool, 0644); | ||
54 | MODULE_PARM_DESC(power_save, "Enable AC97 power-saving control"); | ||
55 | #endif | ||
50 | /* | 56 | /* |
51 | 57 | ||
52 | */ | 58 | */ |
@@ -151,7 +157,7 @@ static const struct ac97_codec_id snd_ac97_codec_ids[] = { | |||
151 | { 0x4e534300, 0xffffffff, "LM4540,43,45,46,48", NULL, NULL }, // only guess --jk | 157 | { 0x4e534300, 0xffffffff, "LM4540,43,45,46,48", NULL, NULL }, // only guess --jk |
152 | { 0x4e534331, 0xffffffff, "LM4549", NULL, NULL }, | 158 | { 0x4e534331, 0xffffffff, "LM4549", NULL, NULL }, |
153 | { 0x4e534350, 0xffffffff, "LM4550", patch_lm4550, NULL }, // volume wrap fix | 159 | { 0x4e534350, 0xffffffff, "LM4550", patch_lm4550, NULL }, // volume wrap fix |
154 | { 0x50534304, 0xffffffff, "UCB1400", NULL, NULL }, | 160 | { 0x50534304, 0xffffffff, "UCB1400", patch_ucb1400, NULL }, |
155 | { 0x53494c20, 0xffffffe0, "Si3036,8", mpatch_si3036, mpatch_si3036, AC97_MODEM_PATCH }, | 161 | { 0x53494c20, 0xffffffe0, "Si3036,8", mpatch_si3036, mpatch_si3036, AC97_MODEM_PATCH }, |
156 | { 0x54524102, 0xffffffff, "TR28022", NULL, NULL }, | 162 | { 0x54524102, 0xffffffff, "TR28022", NULL, NULL }, |
157 | { 0x54524106, 0xffffffff, "TR28026", NULL, NULL }, | 163 | { 0x54524106, 0xffffffff, "TR28026", NULL, NULL }, |
@@ -187,6 +193,8 @@ static const struct ac97_codec_id snd_ac97_codec_ids[] = { | |||
187 | }; | 193 | }; |
188 | 194 | ||
189 | 195 | ||
196 | static void update_power_regs(struct snd_ac97 *ac97); | ||
197 | |||
190 | /* | 198 | /* |
191 | * I/O routines | 199 | * I/O routines |
192 | */ | 200 | */ |
@@ -554,6 +562,18 @@ int snd_ac97_put_volsw(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value | |||
554 | } | 562 | } |
555 | err = snd_ac97_update_bits(ac97, reg, val_mask, val); | 563 | err = snd_ac97_update_bits(ac97, reg, val_mask, val); |
556 | snd_ac97_page_restore(ac97, page_save); | 564 | snd_ac97_page_restore(ac97, page_save); |
565 | #ifdef CONFIG_SND_AC97_POWER_SAVE | ||
566 | /* check analog mixer power-down */ | ||
567 | if ((val_mask & 0x8000) && | ||
568 | (kcontrol->private_value & (1<<30))) { | ||
569 | if (val & 0x8000) | ||
570 | ac97->power_up &= ~(1 << (reg>>1)); | ||
571 | else | ||
572 | ac97->power_up |= 1 << (reg>>1); | ||
573 | if (power_save) | ||
574 | update_power_regs(ac97); | ||
575 | } | ||
576 | #endif | ||
557 | return err; | 577 | return err; |
558 | } | 578 | } |
559 | 579 | ||
@@ -962,6 +982,10 @@ static int snd_ac97_bus_dev_free(struct snd_device *device) | |||
962 | static int snd_ac97_free(struct snd_ac97 *ac97) | 982 | static int snd_ac97_free(struct snd_ac97 *ac97) |
963 | { | 983 | { |
964 | if (ac97) { | 984 | if (ac97) { |
985 | #ifdef CONFIG_SND_AC97_POWER_SAVE | ||
986 | if (ac97->power_workq) | ||
987 | destroy_workqueue(ac97->power_workq); | ||
988 | #endif | ||
965 | snd_ac97_proc_done(ac97); | 989 | snd_ac97_proc_done(ac97); |
966 | if (ac97->bus) | 990 | if (ac97->bus) |
967 | ac97->bus->codec[ac97->num] = NULL; | 991 | ac97->bus->codec[ac97->num] = NULL; |
@@ -1117,7 +1141,9 @@ struct snd_kcontrol *snd_ac97_cnew(const struct snd_kcontrol_new *_template, str | |||
1117 | /* | 1141 | /* |
1118 | * create mute switch(es) for normal stereo controls | 1142 | * create mute switch(es) for normal stereo controls |
1119 | */ | 1143 | */ |
1120 | static int snd_ac97_cmute_new_stereo(struct snd_card *card, char *name, int reg, int check_stereo, struct snd_ac97 *ac97) | 1144 | static int snd_ac97_cmute_new_stereo(struct snd_card *card, char *name, int reg, |
1145 | int check_stereo, int check_amix, | ||
1146 | struct snd_ac97 *ac97) | ||
1121 | { | 1147 | { |
1122 | struct snd_kcontrol *kctl; | 1148 | struct snd_kcontrol *kctl; |
1123 | int err; | 1149 | int err; |
@@ -1137,10 +1163,14 @@ static int snd_ac97_cmute_new_stereo(struct snd_card *card, char *name, int reg, | |||
1137 | } | 1163 | } |
1138 | if (mute_mask == 0x8080) { | 1164 | if (mute_mask == 0x8080) { |
1139 | struct snd_kcontrol_new tmp = AC97_DOUBLE(name, reg, 15, 7, 1, 1); | 1165 | struct snd_kcontrol_new tmp = AC97_DOUBLE(name, reg, 15, 7, 1, 1); |
1166 | if (check_amix) | ||
1167 | tmp.private_value |= (1 << 30); | ||
1140 | tmp.index = ac97->num; | 1168 | tmp.index = ac97->num; |
1141 | kctl = snd_ctl_new1(&tmp, ac97); | 1169 | kctl = snd_ctl_new1(&tmp, ac97); |
1142 | } else { | 1170 | } else { |
1143 | struct snd_kcontrol_new tmp = AC97_SINGLE(name, reg, 15, 1, 1); | 1171 | struct snd_kcontrol_new tmp = AC97_SINGLE(name, reg, 15, 1, 1); |
1172 | if (check_amix) | ||
1173 | tmp.private_value |= (1 << 30); | ||
1144 | tmp.index = ac97->num; | 1174 | tmp.index = ac97->num; |
1145 | kctl = snd_ctl_new1(&tmp, ac97); | 1175 | kctl = snd_ctl_new1(&tmp, ac97); |
1146 | } | 1176 | } |
@@ -1153,6 +1183,32 @@ static int snd_ac97_cmute_new_stereo(struct snd_card *card, char *name, int reg, | |||
1153 | } | 1183 | } |
1154 | 1184 | ||
1155 | /* | 1185 | /* |
1186 | * set dB information | ||
1187 | */ | ||
1188 | static DECLARE_TLV_DB_SCALE(db_scale_4bit, -4500, 300, 0); | ||
1189 | static DECLARE_TLV_DB_SCALE(db_scale_5bit, -4650, 150, 0); | ||
1190 | static DECLARE_TLV_DB_SCALE(db_scale_6bit, -9450, 150, 0); | ||
1191 | static DECLARE_TLV_DB_SCALE(db_scale_5bit_12db_max, -3450, 150, 0); | ||
1192 | static DECLARE_TLV_DB_SCALE(db_scale_rec_gain, 0, 150, 0); | ||
1193 | |||
1194 | static unsigned int *find_db_scale(unsigned int maxval) | ||
1195 | { | ||
1196 | switch (maxval) { | ||
1197 | case 0x0f: return db_scale_4bit; | ||
1198 | case 0x1f: return db_scale_5bit; | ||
1199 | case 0x3f: return db_scale_6bit; | ||
1200 | } | ||
1201 | return NULL; | ||
1202 | } | ||
1203 | |||
1204 | static void set_tlv_db_scale(struct snd_kcontrol *kctl, unsigned int *tlv) | ||
1205 | { | ||
1206 | kctl->tlv.p = tlv; | ||
1207 | if (tlv) | ||
1208 | kctl->vd[0].access |= SNDRV_CTL_ELEM_ACCESS_TLV_READ; | ||
1209 | } | ||
1210 | |||
1211 | /* | ||
1156 | * create a volume for normal stereo/mono controls | 1212 | * create a volume for normal stereo/mono controls |
1157 | */ | 1213 | */ |
1158 | static int snd_ac97_cvol_new(struct snd_card *card, char *name, int reg, unsigned int lo_max, | 1214 | static int snd_ac97_cvol_new(struct snd_card *card, char *name, int reg, unsigned int lo_max, |
@@ -1174,6 +1230,10 @@ static int snd_ac97_cvol_new(struct snd_card *card, char *name, int reg, unsigne | |||
1174 | tmp.index = ac97->num; | 1230 | tmp.index = ac97->num; |
1175 | kctl = snd_ctl_new1(&tmp, ac97); | 1231 | kctl = snd_ctl_new1(&tmp, ac97); |
1176 | } | 1232 | } |
1233 | if (reg >= AC97_PHONE && reg <= AC97_PCM) | ||
1234 | set_tlv_db_scale(kctl, db_scale_5bit_12db_max); | ||
1235 | else | ||
1236 | set_tlv_db_scale(kctl, find_db_scale(lo_max)); | ||
1177 | err = snd_ctl_add(card, kctl); | 1237 | err = snd_ctl_add(card, kctl); |
1178 | if (err < 0) | 1238 | if (err < 0) |
1179 | return err; | 1239 | return err; |
@@ -1186,7 +1246,9 @@ static int snd_ac97_cvol_new(struct snd_card *card, char *name, int reg, unsigne | |||
1186 | /* | 1246 | /* |
1187 | * create a mute-switch and a volume for normal stereo/mono controls | 1247 | * create a mute-switch and a volume for normal stereo/mono controls |
1188 | */ | 1248 | */ |
1189 | static int snd_ac97_cmix_new_stereo(struct snd_card *card, const char *pfx, int reg, int check_stereo, struct snd_ac97 *ac97) | 1249 | static int snd_ac97_cmix_new_stereo(struct snd_card *card, const char *pfx, |
1250 | int reg, int check_stereo, int check_amix, | ||
1251 | struct snd_ac97 *ac97) | ||
1190 | { | 1252 | { |
1191 | int err; | 1253 | int err; |
1192 | char name[44]; | 1254 | char name[44]; |
@@ -1197,7 +1259,9 @@ static int snd_ac97_cmix_new_stereo(struct snd_card *card, const char *pfx, int | |||
1197 | 1259 | ||
1198 | if (snd_ac97_try_bit(ac97, reg, 15)) { | 1260 | if (snd_ac97_try_bit(ac97, reg, 15)) { |
1199 | sprintf(name, "%s Switch", pfx); | 1261 | sprintf(name, "%s Switch", pfx); |
1200 | if ((err = snd_ac97_cmute_new_stereo(card, name, reg, check_stereo, ac97)) < 0) | 1262 | if ((err = snd_ac97_cmute_new_stereo(card, name, reg, |
1263 | check_stereo, check_amix, | ||
1264 | ac97)) < 0) | ||
1201 | return err; | 1265 | return err; |
1202 | } | 1266 | } |
1203 | check_volume_resolution(ac97, reg, &lo_max, &hi_max); | 1267 | check_volume_resolution(ac97, reg, &lo_max, &hi_max); |
@@ -1209,8 +1273,10 @@ static int snd_ac97_cmix_new_stereo(struct snd_card *card, const char *pfx, int | |||
1209 | return 0; | 1273 | return 0; |
1210 | } | 1274 | } |
1211 | 1275 | ||
1212 | #define snd_ac97_cmix_new(card, pfx, reg, ac97) snd_ac97_cmix_new_stereo(card, pfx, reg, 0, ac97) | 1276 | #define snd_ac97_cmix_new(card, pfx, reg, acheck, ac97) \ |
1213 | #define snd_ac97_cmute_new(card, name, reg, ac97) snd_ac97_cmute_new_stereo(card, name, reg, 0, ac97) | 1277 | snd_ac97_cmix_new_stereo(card, pfx, reg, 0, acheck, ac97) |
1278 | #define snd_ac97_cmute_new(card, name, reg, acheck, ac97) \ | ||
1279 | snd_ac97_cmute_new_stereo(card, name, reg, 0, acheck, ac97) | ||
1214 | 1280 | ||
1215 | static unsigned int snd_ac97_determine_spdif_rates(struct snd_ac97 *ac97); | 1281 | static unsigned int snd_ac97_determine_spdif_rates(struct snd_ac97 *ac97); |
1216 | 1282 | ||
@@ -1226,9 +1292,11 @@ static int snd_ac97_mixer_build(struct snd_ac97 * ac97) | |||
1226 | /* AD claims to remove this control from AD1887, although spec v2.2 does not allow this */ | 1292 | /* AD claims to remove this control from AD1887, although spec v2.2 does not allow this */ |
1227 | if (snd_ac97_try_volume_mix(ac97, AC97_MASTER)) { | 1293 | if (snd_ac97_try_volume_mix(ac97, AC97_MASTER)) { |
1228 | if (ac97->flags & AC97_HAS_NO_MASTER_VOL) | 1294 | if (ac97->flags & AC97_HAS_NO_MASTER_VOL) |
1229 | err = snd_ac97_cmute_new(card, "Master Playback Switch", AC97_MASTER, ac97); | 1295 | err = snd_ac97_cmute_new(card, "Master Playback Switch", |
1296 | AC97_MASTER, 0, ac97); | ||
1230 | else | 1297 | else |
1231 | err = snd_ac97_cmix_new(card, "Master Playback", AC97_MASTER, ac97); | 1298 | err = snd_ac97_cmix_new(card, "Master Playback", |
1299 | AC97_MASTER, 0, ac97); | ||
1232 | if (err < 0) | 1300 | if (err < 0) |
1233 | return err; | 1301 | return err; |
1234 | } | 1302 | } |
@@ -1245,6 +1313,7 @@ static int snd_ac97_mixer_build(struct snd_ac97 * ac97) | |||
1245 | snd_ac97_change_volume_params2(ac97, AC97_CENTER_LFE_MASTER, 0, &max); | 1313 | snd_ac97_change_volume_params2(ac97, AC97_CENTER_LFE_MASTER, 0, &max); |
1246 | kctl->private_value &= ~(0xff << 16); | 1314 | kctl->private_value &= ~(0xff << 16); |
1247 | kctl->private_value |= (int)max << 16; | 1315 | kctl->private_value |= (int)max << 16; |
1316 | set_tlv_db_scale(kctl, find_db_scale(max)); | ||
1248 | snd_ac97_write_cache(ac97, AC97_CENTER_LFE_MASTER, ac97->regs[AC97_CENTER_LFE_MASTER] | max); | 1317 | snd_ac97_write_cache(ac97, AC97_CENTER_LFE_MASTER, ac97->regs[AC97_CENTER_LFE_MASTER] | max); |
1249 | } | 1318 | } |
1250 | 1319 | ||
@@ -1258,6 +1327,7 @@ static int snd_ac97_mixer_build(struct snd_ac97 * ac97) | |||
1258 | snd_ac97_change_volume_params2(ac97, AC97_CENTER_LFE_MASTER, 8, &max); | 1327 | snd_ac97_change_volume_params2(ac97, AC97_CENTER_LFE_MASTER, 8, &max); |
1259 | kctl->private_value &= ~(0xff << 16); | 1328 | kctl->private_value &= ~(0xff << 16); |
1260 | kctl->private_value |= (int)max << 16; | 1329 | kctl->private_value |= (int)max << 16; |
1330 | set_tlv_db_scale(kctl, find_db_scale(max)); | ||
1261 | snd_ac97_write_cache(ac97, AC97_CENTER_LFE_MASTER, ac97->regs[AC97_CENTER_LFE_MASTER] | max << 8); | 1331 | snd_ac97_write_cache(ac97, AC97_CENTER_LFE_MASTER, ac97->regs[AC97_CENTER_LFE_MASTER] | max << 8); |
1262 | } | 1332 | } |
1263 | 1333 | ||
@@ -1265,19 +1335,23 @@ static int snd_ac97_mixer_build(struct snd_ac97 * ac97) | |||
1265 | if ((snd_ac97_try_volume_mix(ac97, AC97_SURROUND_MASTER)) | 1335 | if ((snd_ac97_try_volume_mix(ac97, AC97_SURROUND_MASTER)) |
1266 | && !(ac97->flags & AC97_AD_MULTI)) { | 1336 | && !(ac97->flags & AC97_AD_MULTI)) { |
1267 | /* Surround Master (0x38) is with stereo mutes */ | 1337 | /* Surround Master (0x38) is with stereo mutes */ |
1268 | if ((err = snd_ac97_cmix_new_stereo(card, "Surround Playback", AC97_SURROUND_MASTER, 1, ac97)) < 0) | 1338 | if ((err = snd_ac97_cmix_new_stereo(card, "Surround Playback", |
1339 | AC97_SURROUND_MASTER, 1, 0, | ||
1340 | ac97)) < 0) | ||
1269 | return err; | 1341 | return err; |
1270 | } | 1342 | } |
1271 | 1343 | ||
1272 | /* build headphone controls */ | 1344 | /* build headphone controls */ |
1273 | if (snd_ac97_try_volume_mix(ac97, AC97_HEADPHONE)) { | 1345 | if (snd_ac97_try_volume_mix(ac97, AC97_HEADPHONE)) { |
1274 | if ((err = snd_ac97_cmix_new(card, "Headphone Playback", AC97_HEADPHONE, ac97)) < 0) | 1346 | if ((err = snd_ac97_cmix_new(card, "Headphone Playback", |
1347 | AC97_HEADPHONE, 0, ac97)) < 0) | ||
1275 | return err; | 1348 | return err; |
1276 | } | 1349 | } |
1277 | 1350 | ||
1278 | /* build master mono controls */ | 1351 | /* build master mono controls */ |
1279 | if (snd_ac97_try_volume_mix(ac97, AC97_MASTER_MONO)) { | 1352 | if (snd_ac97_try_volume_mix(ac97, AC97_MASTER_MONO)) { |
1280 | if ((err = snd_ac97_cmix_new(card, "Master Mono Playback", AC97_MASTER_MONO, ac97)) < 0) | 1353 | if ((err = snd_ac97_cmix_new(card, "Master Mono Playback", |
1354 | AC97_MASTER_MONO, 0, ac97)) < 0) | ||
1281 | return err; | 1355 | return err; |
1282 | } | 1356 | } |
1283 | 1357 | ||
@@ -1301,8 +1375,9 @@ static int snd_ac97_mixer_build(struct snd_ac97 * ac97) | |||
1301 | ((ac97->flags & AC97_HAS_PC_BEEP) || | 1375 | ((ac97->flags & AC97_HAS_PC_BEEP) || |
1302 | snd_ac97_try_volume_mix(ac97, AC97_PC_BEEP))) { | 1376 | snd_ac97_try_volume_mix(ac97, AC97_PC_BEEP))) { |
1303 | for (idx = 0; idx < 2; idx++) | 1377 | for (idx = 0; idx < 2; idx++) |
1304 | if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_controls_pc_beep[idx], ac97))) < 0) | 1378 | if ((err = snd_ctl_add(card, kctl = snd_ac97_cnew(&snd_ac97_controls_pc_beep[idx], ac97))) < 0) |
1305 | return err; | 1379 | return err; |
1380 | set_tlv_db_scale(kctl, db_scale_4bit); | ||
1306 | snd_ac97_write_cache(ac97, AC97_PC_BEEP, | 1381 | snd_ac97_write_cache(ac97, AC97_PC_BEEP, |
1307 | snd_ac97_read(ac97, AC97_PC_BEEP) | 0x801e); | 1382 | snd_ac97_read(ac97, AC97_PC_BEEP) | 0x801e); |
1308 | } | 1383 | } |
@@ -1310,7 +1385,8 @@ static int snd_ac97_mixer_build(struct snd_ac97 * ac97) | |||
1310 | /* build Phone controls */ | 1385 | /* build Phone controls */ |
1311 | if (!(ac97->flags & AC97_HAS_NO_PHONE)) { | 1386 | if (!(ac97->flags & AC97_HAS_NO_PHONE)) { |
1312 | if (snd_ac97_try_volume_mix(ac97, AC97_PHONE)) { | 1387 | if (snd_ac97_try_volume_mix(ac97, AC97_PHONE)) { |
1313 | if ((err = snd_ac97_cmix_new(card, "Phone Playback", AC97_PHONE, ac97)) < 0) | 1388 | if ((err = snd_ac97_cmix_new(card, "Phone Playback", |
1389 | AC97_PHONE, 1, ac97)) < 0) | ||
1314 | return err; | 1390 | return err; |
1315 | } | 1391 | } |
1316 | } | 1392 | } |
@@ -1318,7 +1394,8 @@ static int snd_ac97_mixer_build(struct snd_ac97 * ac97) | |||
1318 | /* build MIC controls */ | 1394 | /* build MIC controls */ |
1319 | if (!(ac97->flags & AC97_HAS_NO_MIC)) { | 1395 | if (!(ac97->flags & AC97_HAS_NO_MIC)) { |
1320 | if (snd_ac97_try_volume_mix(ac97, AC97_MIC)) { | 1396 | if (snd_ac97_try_volume_mix(ac97, AC97_MIC)) { |
1321 | if ((err = snd_ac97_cmix_new(card, "Mic Playback", AC97_MIC, ac97)) < 0) | 1397 | if ((err = snd_ac97_cmix_new(card, "Mic Playback", |
1398 | AC97_MIC, 1, ac97)) < 0) | ||
1322 | return err; | 1399 | return err; |
1323 | if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_controls_mic_boost, ac97))) < 0) | 1400 | if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_controls_mic_boost, ac97))) < 0) |
1324 | return err; | 1401 | return err; |
@@ -1327,14 +1404,16 @@ static int snd_ac97_mixer_build(struct snd_ac97 * ac97) | |||
1327 | 1404 | ||
1328 | /* build Line controls */ | 1405 | /* build Line controls */ |
1329 | if (snd_ac97_try_volume_mix(ac97, AC97_LINE)) { | 1406 | if (snd_ac97_try_volume_mix(ac97, AC97_LINE)) { |
1330 | if ((err = snd_ac97_cmix_new(card, "Line Playback", AC97_LINE, ac97)) < 0) | 1407 | if ((err = snd_ac97_cmix_new(card, "Line Playback", |
1408 | AC97_LINE, 1, ac97)) < 0) | ||
1331 | return err; | 1409 | return err; |
1332 | } | 1410 | } |
1333 | 1411 | ||
1334 | /* build CD controls */ | 1412 | /* build CD controls */ |
1335 | if (!(ac97->flags & AC97_HAS_NO_CD)) { | 1413 | if (!(ac97->flags & AC97_HAS_NO_CD)) { |
1336 | if (snd_ac97_try_volume_mix(ac97, AC97_CD)) { | 1414 | if (snd_ac97_try_volume_mix(ac97, AC97_CD)) { |
1337 | if ((err = snd_ac97_cmix_new(card, "CD Playback", AC97_CD, ac97)) < 0) | 1415 | if ((err = snd_ac97_cmix_new(card, "CD Playback", |
1416 | AC97_CD, 1, ac97)) < 0) | ||
1338 | return err; | 1417 | return err; |
1339 | } | 1418 | } |
1340 | } | 1419 | } |
@@ -1342,7 +1421,8 @@ static int snd_ac97_mixer_build(struct snd_ac97 * ac97) | |||
1342 | /* build Video controls */ | 1421 | /* build Video controls */ |
1343 | if (!(ac97->flags & AC97_HAS_NO_VIDEO)) { | 1422 | if (!(ac97->flags & AC97_HAS_NO_VIDEO)) { |
1344 | if (snd_ac97_try_volume_mix(ac97, AC97_VIDEO)) { | 1423 | if (snd_ac97_try_volume_mix(ac97, AC97_VIDEO)) { |
1345 | if ((err = snd_ac97_cmix_new(card, "Video Playback", AC97_VIDEO, ac97)) < 0) | 1424 | if ((err = snd_ac97_cmix_new(card, "Video Playback", |
1425 | AC97_VIDEO, 1, ac97)) < 0) | ||
1346 | return err; | 1426 | return err; |
1347 | } | 1427 | } |
1348 | } | 1428 | } |
@@ -1350,7 +1430,8 @@ static int snd_ac97_mixer_build(struct snd_ac97 * ac97) | |||
1350 | /* build Aux controls */ | 1430 | /* build Aux controls */ |
1351 | if (!(ac97->flags & AC97_HAS_NO_AUX)) { | 1431 | if (!(ac97->flags & AC97_HAS_NO_AUX)) { |
1352 | if (snd_ac97_try_volume_mix(ac97, AC97_AUX)) { | 1432 | if (snd_ac97_try_volume_mix(ac97, AC97_AUX)) { |
1353 | if ((err = snd_ac97_cmix_new(card, "Aux Playback", AC97_AUX, ac97)) < 0) | 1433 | if ((err = snd_ac97_cmix_new(card, "Aux Playback", |
1434 | AC97_AUX, 1, ac97)) < 0) | ||
1354 | return err; | 1435 | return err; |
1355 | } | 1436 | } |
1356 | } | 1437 | } |
@@ -1363,31 +1444,38 @@ static int snd_ac97_mixer_build(struct snd_ac97 * ac97) | |||
1363 | else | 1444 | else |
1364 | init_val = 0x9f1f; | 1445 | init_val = 0x9f1f; |
1365 | for (idx = 0; idx < 2; idx++) | 1446 | for (idx = 0; idx < 2; idx++) |
1366 | if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_controls_ad18xx_pcm[idx], ac97))) < 0) | 1447 | if ((err = snd_ctl_add(card, kctl = snd_ac97_cnew(&snd_ac97_controls_ad18xx_pcm[idx], ac97))) < 0) |
1367 | return err; | 1448 | return err; |
1449 | set_tlv_db_scale(kctl, db_scale_5bit); | ||
1368 | ac97->spec.ad18xx.pcmreg[0] = init_val; | 1450 | ac97->spec.ad18xx.pcmreg[0] = init_val; |
1369 | if (ac97->scaps & AC97_SCAP_SURROUND_DAC) { | 1451 | if (ac97->scaps & AC97_SCAP_SURROUND_DAC) { |
1370 | for (idx = 0; idx < 2; idx++) | 1452 | for (idx = 0; idx < 2; idx++) |
1371 | if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_controls_ad18xx_surround[idx], ac97))) < 0) | 1453 | if ((err = snd_ctl_add(card, kctl = snd_ac97_cnew(&snd_ac97_controls_ad18xx_surround[idx], ac97))) < 0) |
1372 | return err; | 1454 | return err; |
1455 | set_tlv_db_scale(kctl, db_scale_5bit); | ||
1373 | ac97->spec.ad18xx.pcmreg[1] = init_val; | 1456 | ac97->spec.ad18xx.pcmreg[1] = init_val; |
1374 | } | 1457 | } |
1375 | if (ac97->scaps & AC97_SCAP_CENTER_LFE_DAC) { | 1458 | if (ac97->scaps & AC97_SCAP_CENTER_LFE_DAC) { |
1376 | for (idx = 0; idx < 2; idx++) | 1459 | for (idx = 0; idx < 2; idx++) |
1377 | if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_controls_ad18xx_center[idx], ac97))) < 0) | 1460 | if ((err = snd_ctl_add(card, kctl = snd_ac97_cnew(&snd_ac97_controls_ad18xx_center[idx], ac97))) < 0) |
1378 | return err; | 1461 | return err; |
1462 | set_tlv_db_scale(kctl, db_scale_5bit); | ||
1379 | for (idx = 0; idx < 2; idx++) | 1463 | for (idx = 0; idx < 2; idx++) |
1380 | if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_controls_ad18xx_lfe[idx], ac97))) < 0) | 1464 | if ((err = snd_ctl_add(card, kctl = snd_ac97_cnew(&snd_ac97_controls_ad18xx_lfe[idx], ac97))) < 0) |
1381 | return err; | 1465 | return err; |
1466 | set_tlv_db_scale(kctl, db_scale_5bit); | ||
1382 | ac97->spec.ad18xx.pcmreg[2] = init_val; | 1467 | ac97->spec.ad18xx.pcmreg[2] = init_val; |
1383 | } | 1468 | } |
1384 | snd_ac97_write_cache(ac97, AC97_PCM, init_val); | 1469 | snd_ac97_write_cache(ac97, AC97_PCM, init_val); |
1385 | } else { | 1470 | } else { |
1386 | if (!(ac97->flags & AC97_HAS_NO_STD_PCM)) { | 1471 | if (!(ac97->flags & AC97_HAS_NO_STD_PCM)) { |
1387 | if (ac97->flags & AC97_HAS_NO_PCM_VOL) | 1472 | if (ac97->flags & AC97_HAS_NO_PCM_VOL) |
1388 | err = snd_ac97_cmute_new(card, "PCM Playback Switch", AC97_PCM, ac97); | 1473 | err = snd_ac97_cmute_new(card, |
1474 | "PCM Playback Switch", | ||
1475 | AC97_PCM, 0, ac97); | ||
1389 | else | 1476 | else |
1390 | err = snd_ac97_cmix_new(card, "PCM Playback", AC97_PCM, ac97); | 1477 | err = snd_ac97_cmix_new(card, "PCM Playback", |
1478 | AC97_PCM, 0, ac97); | ||
1391 | if (err < 0) | 1479 | if (err < 0) |
1392 | return err; | 1480 | return err; |
1393 | } | 1481 | } |
@@ -1398,19 +1486,23 @@ static int snd_ac97_mixer_build(struct snd_ac97 * ac97) | |||
1398 | if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_control_capture_src, ac97))) < 0) | 1486 | if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_control_capture_src, ac97))) < 0) |
1399 | return err; | 1487 | return err; |
1400 | if (snd_ac97_try_bit(ac97, AC97_REC_GAIN, 15)) { | 1488 | if (snd_ac97_try_bit(ac97, AC97_REC_GAIN, 15)) { |
1401 | if ((err = snd_ac97_cmute_new(card, "Capture Switch", AC97_REC_GAIN, ac97)) < 0) | 1489 | err = snd_ac97_cmute_new(card, "Capture Switch", |
1490 | AC97_REC_GAIN, 0, ac97); | ||
1491 | if (err < 0) | ||
1402 | return err; | 1492 | return err; |
1403 | } | 1493 | } |
1404 | if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_control_capture_vol, ac97))) < 0) | 1494 | if ((err = snd_ctl_add(card, kctl = snd_ac97_cnew(&snd_ac97_control_capture_vol, ac97))) < 0) |
1405 | return err; | 1495 | return err; |
1496 | set_tlv_db_scale(kctl, db_scale_rec_gain); | ||
1406 | snd_ac97_write_cache(ac97, AC97_REC_SEL, 0x0000); | 1497 | snd_ac97_write_cache(ac97, AC97_REC_SEL, 0x0000); |
1407 | snd_ac97_write_cache(ac97, AC97_REC_GAIN, 0x0000); | 1498 | snd_ac97_write_cache(ac97, AC97_REC_GAIN, 0x0000); |
1408 | } | 1499 | } |
1409 | /* build MIC Capture controls */ | 1500 | /* build MIC Capture controls */ |
1410 | if (snd_ac97_try_volume_mix(ac97, AC97_REC_GAIN_MIC)) { | 1501 | if (snd_ac97_try_volume_mix(ac97, AC97_REC_GAIN_MIC)) { |
1411 | for (idx = 0; idx < 2; idx++) | 1502 | for (idx = 0; idx < 2; idx++) |
1412 | if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_controls_mic_capture[idx], ac97))) < 0) | 1503 | if ((err = snd_ctl_add(card, kctl = snd_ac97_cnew(&snd_ac97_controls_mic_capture[idx], ac97))) < 0) |
1413 | return err; | 1504 | return err; |
1505 | set_tlv_db_scale(kctl, db_scale_rec_gain); | ||
1414 | snd_ac97_write_cache(ac97, AC97_REC_GAIN_MIC, 0x0000); | 1506 | snd_ac97_write_cache(ac97, AC97_REC_GAIN_MIC, 0x0000); |
1415 | } | 1507 | } |
1416 | 1508 | ||
@@ -1481,6 +1573,12 @@ static int snd_ac97_mixer_build(struct snd_ac97 * ac97) | |||
1481 | } | 1573 | } |
1482 | 1574 | ||
1483 | /* build S/PDIF controls */ | 1575 | /* build S/PDIF controls */ |
1576 | |||
1577 | /* Hack for ASUS P5P800-VM, which does not indicate S/PDIF capability */ | ||
1578 | if (ac97->subsystem_vendor == 0x1043 && | ||
1579 | ac97->subsystem_device == 0x810f) | ||
1580 | ac97->ext_id |= AC97_EI_SPDIF; | ||
1581 | |||
1484 | if ((ac97->ext_id & AC97_EI_SPDIF) && !(ac97->scaps & AC97_SCAP_NO_SPDIF)) { | 1582 | if ((ac97->ext_id & AC97_EI_SPDIF) && !(ac97->scaps & AC97_SCAP_NO_SPDIF)) { |
1485 | if (ac97->build_ops->build_spdif) { | 1583 | if (ac97->build_ops->build_spdif) { |
1486 | if ((err = ac97->build_ops->build_spdif(ac97)) < 0) | 1584 | if ((err = ac97->build_ops->build_spdif(ac97)) < 0) |
@@ -1817,18 +1915,25 @@ static int snd_ac97_dev_register(struct snd_device *device) | |||
1817 | return 0; | 1915 | return 0; |
1818 | } | 1916 | } |
1819 | 1917 | ||
1820 | /* unregister ac97 codec */ | 1918 | /* disconnect ac97 codec */ |
1821 | static int snd_ac97_dev_unregister(struct snd_device *device) | 1919 | static int snd_ac97_dev_disconnect(struct snd_device *device) |
1822 | { | 1920 | { |
1823 | struct snd_ac97 *ac97 = device->device_data; | 1921 | struct snd_ac97 *ac97 = device->device_data; |
1824 | if (ac97->dev.bus) | 1922 | if (ac97->dev.bus) |
1825 | device_unregister(&ac97->dev); | 1923 | device_unregister(&ac97->dev); |
1826 | return snd_ac97_free(ac97); | 1924 | return 0; |
1827 | } | 1925 | } |
1828 | 1926 | ||
1829 | /* build_ops to do nothing */ | 1927 | /* build_ops to do nothing */ |
1830 | static struct snd_ac97_build_ops null_build_ops; | 1928 | static struct snd_ac97_build_ops null_build_ops; |
1831 | 1929 | ||
1930 | #ifdef CONFIG_SND_AC97_POWER_SAVE | ||
1931 | static void do_update_power(void *data) | ||
1932 | { | ||
1933 | update_power_regs(data); | ||
1934 | } | ||
1935 | #endif | ||
1936 | |||
1832 | /** | 1937 | /** |
1833 | * snd_ac97_mixer - create an Codec97 component | 1938 | * snd_ac97_mixer - create an Codec97 component |
1834 | * @bus: the AC97 bus which codec is attached to | 1939 | * @bus: the AC97 bus which codec is attached to |
@@ -1860,7 +1965,7 @@ int snd_ac97_mixer(struct snd_ac97_bus *bus, struct snd_ac97_template *template, | |||
1860 | static struct snd_device_ops ops = { | 1965 | static struct snd_device_ops ops = { |
1861 | .dev_free = snd_ac97_dev_free, | 1966 | .dev_free = snd_ac97_dev_free, |
1862 | .dev_register = snd_ac97_dev_register, | 1967 | .dev_register = snd_ac97_dev_register, |
1863 | .dev_unregister = snd_ac97_dev_unregister, | 1968 | .dev_disconnect = snd_ac97_dev_disconnect, |
1864 | }; | 1969 | }; |
1865 | 1970 | ||
1866 | snd_assert(rac97 != NULL, return -EINVAL); | 1971 | snd_assert(rac97 != NULL, return -EINVAL); |
@@ -1883,6 +1988,10 @@ int snd_ac97_mixer(struct snd_ac97_bus *bus, struct snd_ac97_template *template, | |||
1883 | bus->codec[ac97->num] = ac97; | 1988 | bus->codec[ac97->num] = ac97; |
1884 | mutex_init(&ac97->reg_mutex); | 1989 | mutex_init(&ac97->reg_mutex); |
1885 | mutex_init(&ac97->page_mutex); | 1990 | mutex_init(&ac97->page_mutex); |
1991 | #ifdef CONFIG_SND_AC97_POWER_SAVE | ||
1992 | ac97->power_workq = create_workqueue("ac97"); | ||
1993 | INIT_WORK(&ac97->power_work, do_update_power, ac97); | ||
1994 | #endif | ||
1886 | 1995 | ||
1887 | #ifdef CONFIG_PCI | 1996 | #ifdef CONFIG_PCI |
1888 | if (ac97->pci) { | 1997 | if (ac97->pci) { |
@@ -2117,15 +2226,8 @@ int snd_ac97_mixer(struct snd_ac97_bus *bus, struct snd_ac97_template *template, | |||
2117 | return -ENOMEM; | 2226 | return -ENOMEM; |
2118 | } | 2227 | } |
2119 | } | 2228 | } |
2120 | /* make sure the proper powerdown bits are cleared */ | 2229 | if (ac97_is_audio(ac97)) |
2121 | if (ac97->scaps && ac97_is_audio(ac97)) { | 2230 | update_power_regs(ac97); |
2122 | reg = snd_ac97_read(ac97, AC97_EXTENDED_STATUS); | ||
2123 | if (ac97->scaps & AC97_SCAP_SURROUND_DAC) | ||
2124 | reg &= ~AC97_EA_PRJ; | ||
2125 | if (ac97->scaps & AC97_SCAP_CENTER_LFE_DAC) | ||
2126 | reg &= ~(AC97_EA_PRI | AC97_EA_PRK); | ||
2127 | snd_ac97_write_cache(ac97, AC97_EXTENDED_STATUS, reg); | ||
2128 | } | ||
2129 | snd_ac97_proc_init(ac97); | 2231 | snd_ac97_proc_init(ac97); |
2130 | if ((err = snd_device_new(card, SNDRV_DEV_CODEC, ac97, &ops)) < 0) { | 2232 | if ((err = snd_device_new(card, SNDRV_DEV_CODEC, ac97, &ops)) < 0) { |
2131 | snd_ac97_free(ac97); | 2233 | snd_ac97_free(ac97); |
@@ -2153,19 +2255,152 @@ static void snd_ac97_powerdown(struct snd_ac97 *ac97) | |||
2153 | snd_ac97_write(ac97, AC97_HEADPHONE, 0x9f9f); | 2255 | snd_ac97_write(ac97, AC97_HEADPHONE, 0x9f9f); |
2154 | } | 2256 | } |
2155 | 2257 | ||
2156 | power = ac97->regs[AC97_POWERDOWN] | 0x8000; /* EAPD */ | 2258 | /* surround, CLFE, mic powerdown */ |
2157 | power |= 0x4000; /* Headphone amplifier powerdown */ | 2259 | power = ac97->regs[AC97_EXTENDED_STATUS]; |
2158 | power |= 0x0300; /* ADC & DAC powerdown */ | 2260 | if (ac97->scaps & AC97_SCAP_SURROUND_DAC) |
2159 | snd_ac97_write(ac97, AC97_POWERDOWN, power); | 2261 | power |= AC97_EA_PRJ; |
2160 | udelay(100); | 2262 | if (ac97->scaps & AC97_SCAP_CENTER_LFE_DAC) |
2161 | power |= 0x0400; /* Analog Mixer powerdown (Vref on) */ | 2263 | power |= AC97_EA_PRI | AC97_EA_PRK; |
2264 | power |= AC97_EA_PRL; | ||
2265 | snd_ac97_write(ac97, AC97_EXTENDED_STATUS, power); | ||
2266 | |||
2267 | /* powerdown external amplifier */ | ||
2268 | if (ac97->scaps & AC97_SCAP_INV_EAPD) | ||
2269 | power = ac97->regs[AC97_POWERDOWN] & ~AC97_PD_EAPD; | ||
2270 | else if (! (ac97->scaps & AC97_SCAP_EAPD_LED)) | ||
2271 | power = ac97->regs[AC97_POWERDOWN] | AC97_PD_EAPD; | ||
2272 | power |= AC97_PD_PR6; /* Headphone amplifier powerdown */ | ||
2273 | power |= AC97_PD_PR0 | AC97_PD_PR1; /* ADC & DAC powerdown */ | ||
2162 | snd_ac97_write(ac97, AC97_POWERDOWN, power); | 2274 | snd_ac97_write(ac97, AC97_POWERDOWN, power); |
2163 | udelay(100); | 2275 | udelay(100); |
2164 | #if 0 | 2276 | power |= AC97_PD_PR2 | AC97_PD_PR3; /* Analog Mixer powerdown */ |
2165 | /* FIXME: this causes click noises on some boards at resume */ | ||
2166 | power |= 0x3800; /* AC-link powerdown, internal Clk disable */ | ||
2167 | snd_ac97_write(ac97, AC97_POWERDOWN, power); | 2277 | snd_ac97_write(ac97, AC97_POWERDOWN, power); |
2278 | #ifdef CONFIG_SND_AC97_POWER_SAVE | ||
2279 | if (power_save) { | ||
2280 | udelay(100); | ||
2281 | /* AC-link powerdown, internal Clk disable */ | ||
2282 | /* FIXME: this may cause click noises on some boards */ | ||
2283 | power |= AC97_PD_PR4 | AC97_PD_PR5; | ||
2284 | snd_ac97_write(ac97, AC97_POWERDOWN, power); | ||
2285 | } | ||
2286 | #endif | ||
2287 | } | ||
2288 | |||
2289 | |||
2290 | struct ac97_power_reg { | ||
2291 | unsigned short reg; | ||
2292 | unsigned short power_reg; | ||
2293 | unsigned short mask; | ||
2294 | }; | ||
2295 | |||
2296 | enum { PWIDX_ADC, PWIDX_FRONT, PWIDX_CLFE, PWIDX_SURR, PWIDX_MIC, PWIDX_SIZE }; | ||
2297 | |||
2298 | static struct ac97_power_reg power_regs[PWIDX_SIZE] = { | ||
2299 | [PWIDX_ADC] = { AC97_PCM_LR_ADC_RATE, AC97_POWERDOWN, AC97_PD_PR0}, | ||
2300 | [PWIDX_FRONT] = { AC97_PCM_FRONT_DAC_RATE, AC97_POWERDOWN, AC97_PD_PR1}, | ||
2301 | [PWIDX_CLFE] = { AC97_PCM_LFE_DAC_RATE, AC97_EXTENDED_STATUS, | ||
2302 | AC97_EA_PRI | AC97_EA_PRK}, | ||
2303 | [PWIDX_SURR] = { AC97_PCM_SURR_DAC_RATE, AC97_EXTENDED_STATUS, | ||
2304 | AC97_EA_PRJ}, | ||
2305 | [PWIDX_MIC] = { AC97_PCM_MIC_ADC_RATE, AC97_EXTENDED_STATUS, | ||
2306 | AC97_EA_PRL}, | ||
2307 | }; | ||
2308 | |||
2309 | #ifdef CONFIG_SND_AC97_POWER_SAVE | ||
2310 | /** | ||
2311 | * snd_ac97_update_power - update the powerdown register | ||
2312 | * @ac97: the codec instance | ||
2313 | * @reg: the rate register, e.g. AC97_PCM_FRONT_DAC_RATE | ||
2314 | * @powerup: non-zero when power up the part | ||
2315 | * | ||
2316 | * Update the AC97 powerdown register bits of the given part. | ||
2317 | */ | ||
2318 | int snd_ac97_update_power(struct snd_ac97 *ac97, int reg, int powerup) | ||
2319 | { | ||
2320 | int i; | ||
2321 | |||
2322 | if (! ac97) | ||
2323 | return 0; | ||
2324 | |||
2325 | if (reg) { | ||
2326 | /* SPDIF requires DAC power, too */ | ||
2327 | if (reg == AC97_SPDIF) | ||
2328 | reg = AC97_PCM_FRONT_DAC_RATE; | ||
2329 | for (i = 0; i < PWIDX_SIZE; i++) { | ||
2330 | if (power_regs[i].reg == reg) { | ||
2331 | if (powerup) | ||
2332 | ac97->power_up |= (1 << i); | ||
2333 | else | ||
2334 | ac97->power_up &= ~(1 << i); | ||
2335 | break; | ||
2336 | } | ||
2337 | } | ||
2338 | } | ||
2339 | |||
2340 | if (! power_save) | ||
2341 | return 0; | ||
2342 | |||
2343 | if (! powerup && ac97->power_workq) | ||
2344 | /* adjust power-down bits after two seconds delay | ||
2345 | * (for avoiding loud click noises for many (OSS) apps | ||
2346 | * that open/close frequently) | ||
2347 | */ | ||
2348 | queue_delayed_work(ac97->power_workq, &ac97->power_work, HZ*2); | ||
2349 | else | ||
2350 | update_power_regs(ac97); | ||
2351 | |||
2352 | return 0; | ||
2353 | } | ||
2354 | |||
2355 | EXPORT_SYMBOL(snd_ac97_update_power); | ||
2356 | #endif /* CONFIG_SND_AC97_POWER_SAVE */ | ||
2357 | |||
2358 | static void update_power_regs(struct snd_ac97 *ac97) | ||
2359 | { | ||
2360 | unsigned int power_up, bits; | ||
2361 | int i; | ||
2362 | |||
2363 | #ifdef CONFIG_SND_AC97_POWER_SAVE | ||
2364 | if (power_save) | ||
2365 | power_up = ac97->power_up; | ||
2366 | else { | ||
2168 | #endif | 2367 | #endif |
2368 | power_up = (1 << PWIDX_FRONT) | (1 << PWIDX_ADC); | ||
2369 | power_up |= (1 << PWIDX_MIC); | ||
2370 | if (ac97->scaps & AC97_SCAP_SURROUND_DAC) | ||
2371 | power_up |= (1 << PWIDX_SURR); | ||
2372 | if (ac97->scaps & AC97_SCAP_CENTER_LFE_DAC) | ||
2373 | power_up |= (1 << PWIDX_CLFE); | ||
2374 | #ifdef CONFIG_SND_AC97_POWER_SAVE | ||
2375 | } | ||
2376 | #endif | ||
2377 | if (power_up) { | ||
2378 | if (ac97->regs[AC97_POWERDOWN] & AC97_PD_PR2) { | ||
2379 | /* needs power-up analog mix and vref */ | ||
2380 | snd_ac97_update_bits(ac97, AC97_POWERDOWN, | ||
2381 | AC97_PD_PR3, 0); | ||
2382 | msleep(1); | ||
2383 | snd_ac97_update_bits(ac97, AC97_POWERDOWN, | ||
2384 | AC97_PD_PR2, 0); | ||
2385 | } | ||
2386 | } | ||
2387 | for (i = 0; i < PWIDX_SIZE; i++) { | ||
2388 | if (power_up & (1 << i)) | ||
2389 | bits = 0; | ||
2390 | else | ||
2391 | bits = power_regs[i].mask; | ||
2392 | snd_ac97_update_bits(ac97, power_regs[i].power_reg, | ||
2393 | power_regs[i].mask, bits); | ||
2394 | } | ||
2395 | if (! power_up) { | ||
2396 | if (! (ac97->regs[AC97_POWERDOWN] & AC97_PD_PR2)) { | ||
2397 | /* power down analog mix and vref */ | ||
2398 | snd_ac97_update_bits(ac97, AC97_POWERDOWN, | ||
2399 | AC97_PD_PR2, AC97_PD_PR2); | ||
2400 | snd_ac97_update_bits(ac97, AC97_POWERDOWN, | ||
2401 | AC97_PD_PR3, AC97_PD_PR3); | ||
2402 | } | ||
2403 | } | ||
2169 | } | 2404 | } |
2170 | 2405 | ||
2171 | 2406 | ||
@@ -2484,6 +2719,7 @@ static int tune_mute_led(struct snd_ac97 *ac97) | |||
2484 | msw->put = master_mute_sw_put; | 2719 | msw->put = master_mute_sw_put; |
2485 | snd_ac97_remove_ctl(ac97, "External Amplifier", NULL); | 2720 | snd_ac97_remove_ctl(ac97, "External Amplifier", NULL); |
2486 | snd_ac97_update_bits(ac97, AC97_POWERDOWN, 0x8000, 0x8000); /* mute LED on */ | 2721 | snd_ac97_update_bits(ac97, AC97_POWERDOWN, 0x8000, 0x8000); /* mute LED on */ |
2722 | ac97->scaps |= AC97_SCAP_EAPD_LED; | ||
2487 | return 0; | 2723 | return 0; |
2488 | } | 2724 | } |
2489 | 2725 | ||
diff --git a/sound/pci/ac97/ac97_patch.c b/sound/pci/ac97/ac97_patch.c index 094cfc1f3a19..dc28b111a06d 100644 --- a/sound/pci/ac97/ac97_patch.c +++ b/sound/pci/ac97/ac97_patch.c | |||
@@ -32,6 +32,7 @@ | |||
32 | #include <sound/core.h> | 32 | #include <sound/core.h> |
33 | #include <sound/pcm.h> | 33 | #include <sound/pcm.h> |
34 | #include <sound/control.h> | 34 | #include <sound/control.h> |
35 | #include <sound/tlv.h> | ||
35 | #include <sound/ac97_codec.h> | 36 | #include <sound/ac97_codec.h> |
36 | #include "ac97_patch.h" | 37 | #include "ac97_patch.h" |
37 | #include "ac97_id.h" | 38 | #include "ac97_id.h" |
@@ -51,6 +52,20 @@ static int patch_build_controls(struct snd_ac97 * ac97, const struct snd_kcontro | |||
51 | return 0; | 52 | return 0; |
52 | } | 53 | } |
53 | 54 | ||
55 | /* replace with a new TLV */ | ||
56 | static void reset_tlv(struct snd_ac97 *ac97, const char *name, | ||
57 | unsigned int *tlv) | ||
58 | { | ||
59 | struct snd_ctl_elem_id sid; | ||
60 | struct snd_kcontrol *kctl; | ||
61 | memset(&sid, 0, sizeof(sid)); | ||
62 | strcpy(sid.name, name); | ||
63 | sid.iface = SNDRV_CTL_ELEM_IFACE_MIXER; | ||
64 | kctl = snd_ctl_find_id(ac97->bus->card, &sid); | ||
65 | if (kctl && kctl->tlv.p) | ||
66 | kctl->tlv.p = tlv; | ||
67 | } | ||
68 | |||
54 | /* set to the page, update bits and restore the page */ | 69 | /* set to the page, update bits and restore the page */ |
55 | static int ac97_update_bits_page(struct snd_ac97 *ac97, unsigned short reg, unsigned short mask, unsigned short value, unsigned short page) | 70 | static int ac97_update_bits_page(struct snd_ac97 *ac97, unsigned short reg, unsigned short mask, unsigned short value, unsigned short page) |
56 | { | 71 | { |
@@ -466,7 +481,7 @@ int patch_wolfson05(struct snd_ac97 * ac97) | |||
466 | ac97->build_ops = &patch_wolfson_wm9705_ops; | 481 | ac97->build_ops = &patch_wolfson_wm9705_ops; |
467 | #ifdef CONFIG_TOUCHSCREEN_WM9705 | 482 | #ifdef CONFIG_TOUCHSCREEN_WM9705 |
468 | /* WM9705 touchscreen uses AUX and VIDEO for touch */ | 483 | /* WM9705 touchscreen uses AUX and VIDEO for touch */ |
469 | ac97->flags |=3D AC97_HAS_NO_VIDEO | AC97_HAS_NO_AUX; | 484 | ac97->flags |= AC97_HAS_NO_VIDEO | AC97_HAS_NO_AUX; |
470 | #endif | 485 | #endif |
471 | return 0; | 486 | return 0; |
472 | } | 487 | } |
@@ -1380,6 +1395,17 @@ static void ad1888_resume(struct snd_ac97 *ac97) | |||
1380 | 1395 | ||
1381 | #endif | 1396 | #endif |
1382 | 1397 | ||
1398 | static const struct snd_ac97_res_table ad1819_restbl[] = { | ||
1399 | { AC97_PHONE, 0x9f1f }, | ||
1400 | { AC97_MIC, 0x9f1f }, | ||
1401 | { AC97_LINE, 0x9f1f }, | ||
1402 | { AC97_CD, 0x9f1f }, | ||
1403 | { AC97_VIDEO, 0x9f1f }, | ||
1404 | { AC97_AUX, 0x9f1f }, | ||
1405 | { AC97_PCM, 0x9f1f }, | ||
1406 | { } /* terminator */ | ||
1407 | }; | ||
1408 | |||
1383 | int patch_ad1819(struct snd_ac97 * ac97) | 1409 | int patch_ad1819(struct snd_ac97 * ac97) |
1384 | { | 1410 | { |
1385 | unsigned short scfg; | 1411 | unsigned short scfg; |
@@ -1387,6 +1413,7 @@ int patch_ad1819(struct snd_ac97 * ac97) | |||
1387 | // patch for Analog Devices | 1413 | // patch for Analog Devices |
1388 | scfg = snd_ac97_read(ac97, AC97_AD_SERIAL_CFG); | 1414 | scfg = snd_ac97_read(ac97, AC97_AD_SERIAL_CFG); |
1389 | snd_ac97_write_cache(ac97, AC97_AD_SERIAL_CFG, scfg | 0x7000); /* select all codecs */ | 1415 | snd_ac97_write_cache(ac97, AC97_AD_SERIAL_CFG, scfg | 0x7000); /* select all codecs */ |
1416 | ac97->res_table = ad1819_restbl; | ||
1390 | return 0; | 1417 | return 0; |
1391 | } | 1418 | } |
1392 | 1419 | ||
@@ -1522,12 +1549,16 @@ static const struct snd_kcontrol_new snd_ac97_controls_ad1885[] = { | |||
1522 | AC97_SINGLE("Line Jack Sense", AC97_AD_JACK_SPDIF, 8, 1, 1), /* inverted */ | 1549 | AC97_SINGLE("Line Jack Sense", AC97_AD_JACK_SPDIF, 8, 1, 1), /* inverted */ |
1523 | }; | 1550 | }; |
1524 | 1551 | ||
1552 | static DECLARE_TLV_DB_SCALE(db_scale_6bit_6db_max, -8850, 150, 0); | ||
1553 | |||
1525 | static int patch_ad1885_specific(struct snd_ac97 * ac97) | 1554 | static int patch_ad1885_specific(struct snd_ac97 * ac97) |
1526 | { | 1555 | { |
1527 | int err; | 1556 | int err; |
1528 | 1557 | ||
1529 | if ((err = patch_build_controls(ac97, snd_ac97_controls_ad1885, ARRAY_SIZE(snd_ac97_controls_ad1885))) < 0) | 1558 | if ((err = patch_build_controls(ac97, snd_ac97_controls_ad1885, ARRAY_SIZE(snd_ac97_controls_ad1885))) < 0) |
1530 | return err; | 1559 | return err; |
1560 | reset_tlv(ac97, "Headphone Playback Volume", | ||
1561 | db_scale_6bit_6db_max); | ||
1531 | return 0; | 1562 | return 0; |
1532 | } | 1563 | } |
1533 | 1564 | ||
@@ -1551,12 +1582,27 @@ int patch_ad1885(struct snd_ac97 * ac97) | |||
1551 | return 0; | 1582 | return 0; |
1552 | } | 1583 | } |
1553 | 1584 | ||
1585 | static int patch_ad1886_specific(struct snd_ac97 * ac97) | ||
1586 | { | ||
1587 | reset_tlv(ac97, "Headphone Playback Volume", | ||
1588 | db_scale_6bit_6db_max); | ||
1589 | return 0; | ||
1590 | } | ||
1591 | |||
1592 | static struct snd_ac97_build_ops patch_ad1886_build_ops = { | ||
1593 | .build_specific = &patch_ad1886_specific, | ||
1594 | #ifdef CONFIG_PM | ||
1595 | .resume = ad18xx_resume | ||
1596 | #endif | ||
1597 | }; | ||
1598 | |||
1554 | int patch_ad1886(struct snd_ac97 * ac97) | 1599 | int patch_ad1886(struct snd_ac97 * ac97) |
1555 | { | 1600 | { |
1556 | patch_ad1881(ac97); | 1601 | patch_ad1881(ac97); |
1557 | /* Presario700 workaround */ | 1602 | /* Presario700 workaround */ |
1558 | /* for Jack Sense/SPDIF Register misetting causing */ | 1603 | /* for Jack Sense/SPDIF Register misetting causing */ |
1559 | snd_ac97_write_cache(ac97, AC97_AD_JACK_SPDIF, 0x0010); | 1604 | snd_ac97_write_cache(ac97, AC97_AD_JACK_SPDIF, 0x0010); |
1605 | ac97->build_ops = &patch_ad1886_build_ops; | ||
1560 | return 0; | 1606 | return 0; |
1561 | } | 1607 | } |
1562 | 1608 | ||
@@ -2015,6 +2061,8 @@ static const struct snd_kcontrol_new snd_ac97_spdif_controls_alc650[] = { | |||
2015 | /* AC97_SINGLE("IEC958 Input Monitor", AC97_ALC650_MULTICH, 13, 1, 0), */ | 2061 | /* AC97_SINGLE("IEC958 Input Monitor", AC97_ALC650_MULTICH, 13, 1, 0), */ |
2016 | }; | 2062 | }; |
2017 | 2063 | ||
2064 | static DECLARE_TLV_DB_SCALE(db_scale_5bit_3db_max, -4350, 150, 0); | ||
2065 | |||
2018 | static int patch_alc650_specific(struct snd_ac97 * ac97) | 2066 | static int patch_alc650_specific(struct snd_ac97 * ac97) |
2019 | { | 2067 | { |
2020 | int err; | 2068 | int err; |
@@ -2025,6 +2073,9 @@ static int patch_alc650_specific(struct snd_ac97 * ac97) | |||
2025 | if ((err = patch_build_controls(ac97, snd_ac97_spdif_controls_alc650, ARRAY_SIZE(snd_ac97_spdif_controls_alc650))) < 0) | 2073 | if ((err = patch_build_controls(ac97, snd_ac97_spdif_controls_alc650, ARRAY_SIZE(snd_ac97_spdif_controls_alc650))) < 0) |
2026 | return err; | 2074 | return err; |
2027 | } | 2075 | } |
2076 | if (ac97->id != AC97_ID_ALC650F) | ||
2077 | reset_tlv(ac97, "Master Playback Volume", | ||
2078 | db_scale_5bit_3db_max); | ||
2028 | return 0; | 2079 | return 0; |
2029 | } | 2080 | } |
2030 | 2081 | ||
@@ -2208,7 +2259,8 @@ int patch_alc655(struct snd_ac97 * ac97) | |||
2208 | val &= ~(1 << 1); /* Pin 47 is spdif input pin */ | 2259 | val &= ~(1 << 1); /* Pin 47 is spdif input pin */ |
2209 | else { /* ALC655 */ | 2260 | else { /* ALC655 */ |
2210 | if (ac97->subsystem_vendor == 0x1462 && | 2261 | if (ac97->subsystem_vendor == 0x1462 && |
2211 | ac97->subsystem_device == 0x0131) /* MSI S270 laptop */ | 2262 | (ac97->subsystem_device == 0x0131 || /* MSI S270 laptop */ |
2263 | ac97->subsystem_device == 0x0161)) /* LG K1 Express */ | ||
2212 | val &= ~(1 << 1); /* Pin 47 is EAPD (for internal speaker) */ | 2264 | val &= ~(1 << 1); /* Pin 47 is EAPD (for internal speaker) */ |
2213 | else | 2265 | else |
2214 | val |= (1 << 1); /* Pin 47 is spdif input pin */ | 2266 | val |= (1 << 1); /* Pin 47 is spdif input pin */ |
@@ -2759,6 +2811,10 @@ int patch_vt1616(struct snd_ac97 * ac97) | |||
2759 | */ | 2811 | */ |
2760 | int patch_vt1617a(struct snd_ac97 * ac97) | 2812 | int patch_vt1617a(struct snd_ac97 * ac97) |
2761 | { | 2813 | { |
2814 | /* bring analog power consumption to normal, like WinXP driver | ||
2815 | * for EPIA SP | ||
2816 | */ | ||
2817 | snd_ac97_write_cache(ac97, 0x5c, 0x20); | ||
2762 | ac97->ext_id |= AC97_EI_SPDIF; /* force the detection of spdif */ | 2818 | ac97->ext_id |= AC97_EI_SPDIF; /* force the detection of spdif */ |
2763 | ac97->rates[AC97_RATES_SPDIF] = SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000; | 2819 | ac97->rates[AC97_RATES_SPDIF] = SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000; |
2764 | return 0; | 2820 | return 0; |
@@ -2872,3 +2928,41 @@ int patch_lm4550(struct snd_ac97 *ac97) | |||
2872 | ac97->res_table = lm4550_restbl; | 2928 | ac97->res_table = lm4550_restbl; |
2873 | return 0; | 2929 | return 0; |
2874 | } | 2930 | } |
2931 | |||
2932 | /* | ||
2933 | * UCB1400 codec (http://www.semiconductors.philips.com/acrobat_download/datasheets/UCB1400-02.pdf) | ||
2934 | */ | ||
2935 | static const struct snd_kcontrol_new snd_ac97_controls_ucb1400[] = { | ||
2936 | /* enable/disable headphone driver which allows direct connection to | ||
2937 | stereo headphone without the use of external DC blocking | ||
2938 | capacitors */ | ||
2939 | AC97_SINGLE("Headphone Driver", 0x6a, 6, 1, 0), | ||
2940 | /* Filter used to compensate the DC offset is added in the ADC to remove idle | ||
2941 | tones from the audio band. */ | ||
2942 | AC97_SINGLE("DC Filter", 0x6a, 4, 1, 0), | ||
2943 | /* Control smart-low-power mode feature. Allows automatic power down | ||
2944 | of unused blocks in the ADC analog front end and the PLL. */ | ||
2945 | AC97_SINGLE("Smart Low Power Mode", 0x6c, 4, 3, 0), | ||
2946 | }; | ||
2947 | |||
2948 | static int patch_ucb1400_specific(struct snd_ac97 * ac97) | ||
2949 | { | ||
2950 | int idx, err; | ||
2951 | for (idx = 0; idx < ARRAY_SIZE(snd_ac97_controls_ucb1400); idx++) | ||
2952 | if ((err = snd_ctl_add(ac97->bus->card, snd_ctl_new1(&snd_ac97_controls_ucb1400[idx], ac97))) < 0) | ||
2953 | return err; | ||
2954 | return 0; | ||
2955 | } | ||
2956 | |||
2957 | static struct snd_ac97_build_ops patch_ucb1400_ops = { | ||
2958 | .build_specific = patch_ucb1400_specific, | ||
2959 | }; | ||
2960 | |||
2961 | int patch_ucb1400(struct snd_ac97 * ac97) | ||
2962 | { | ||
2963 | ac97->build_ops = &patch_ucb1400_ops; | ||
2964 | /* enable headphone driver and smart low power mode by default */ | ||
2965 | snd_ac97_write(ac97, 0x6a, 0x0050); | ||
2966 | snd_ac97_write(ac97, 0x6c, 0x0030); | ||
2967 | return 0; | ||
2968 | } | ||
diff --git a/sound/pci/ac97/ac97_patch.h b/sound/pci/ac97/ac97_patch.h index adcaa04586cb..741979217207 100644 --- a/sound/pci/ac97/ac97_patch.h +++ b/sound/pci/ac97/ac97_patch.h | |||
@@ -58,5 +58,6 @@ int patch_cm9780(struct snd_ac97 * ac97); | |||
58 | int patch_vt1616(struct snd_ac97 * ac97); | 58 | int patch_vt1616(struct snd_ac97 * ac97); |
59 | int patch_vt1617a(struct snd_ac97 * ac97); | 59 | int patch_vt1617a(struct snd_ac97 * ac97); |
60 | int patch_it2646(struct snd_ac97 * ac97); | 60 | int patch_it2646(struct snd_ac97 * ac97); |
61 | int patch_ucb1400(struct snd_ac97 * ac97); | ||
61 | int mpatch_si3036(struct snd_ac97 * ac97); | 62 | int mpatch_si3036(struct snd_ac97 * ac97); |
62 | int patch_lm4550(struct snd_ac97 * ac97); | 63 | int patch_lm4550(struct snd_ac97 * ac97); |
diff --git a/sound/pci/ac97/ac97_pcm.c b/sound/pci/ac97/ac97_pcm.c index f684aa2c0067..3758d07182f8 100644 --- a/sound/pci/ac97/ac97_pcm.c +++ b/sound/pci/ac97/ac97_pcm.c | |||
@@ -269,6 +269,7 @@ int snd_ac97_set_rate(struct snd_ac97 *ac97, int reg, unsigned int rate) | |||
269 | return -EINVAL; | 269 | return -EINVAL; |
270 | } | 270 | } |
271 | 271 | ||
272 | snd_ac97_update_power(ac97, reg, 1); | ||
272 | switch (reg) { | 273 | switch (reg) { |
273 | case AC97_PCM_MIC_ADC_RATE: | 274 | case AC97_PCM_MIC_ADC_RATE: |
274 | if ((ac97->regs[AC97_EXTENDED_STATUS] & AC97_EA_VRM) == 0) /* MIC VRA */ | 275 | if ((ac97->regs[AC97_EXTENDED_STATUS] & AC97_EA_VRM) == 0) /* MIC VRA */ |
@@ -606,6 +607,7 @@ int snd_ac97_pcm_open(struct ac97_pcm *pcm, unsigned int rate, | |||
606 | goto error; | 607 | goto error; |
607 | } | 608 | } |
608 | } | 609 | } |
610 | pcm->cur_dbl = r; | ||
609 | spin_unlock_irq(&pcm->bus->bus_lock); | 611 | spin_unlock_irq(&pcm->bus->bus_lock); |
610 | for (i = 3; i < 12; i++) { | 612 | for (i = 3; i < 12; i++) { |
611 | if (!(slots & (1 << i))) | 613 | if (!(slots & (1 << i))) |
@@ -651,6 +653,21 @@ int snd_ac97_pcm_close(struct ac97_pcm *pcm) | |||
651 | unsigned short slots = pcm->aslots; | 653 | unsigned short slots = pcm->aslots; |
652 | int i, cidx; | 654 | int i, cidx; |
653 | 655 | ||
656 | #ifdef CONFIG_SND_AC97_POWER_SAVE | ||
657 | int r = pcm->cur_dbl; | ||
658 | for (i = 3; i < 12; i++) { | ||
659 | if (!(slots & (1 << i))) | ||
660 | continue; | ||
661 | for (cidx = 0; cidx < 4; cidx++) { | ||
662 | if (pcm->r[r].rslots[cidx] & (1 << i)) { | ||
663 | int reg = get_slot_reg(pcm, cidx, i, r); | ||
664 | snd_ac97_update_power(pcm->r[r].codec[cidx], | ||
665 | reg, 0); | ||
666 | } | ||
667 | } | ||
668 | } | ||
669 | #endif | ||
670 | |||
654 | bus = pcm->bus; | 671 | bus = pcm->bus; |
655 | spin_lock_irq(&pcm->bus->bus_lock); | 672 | spin_lock_irq(&pcm->bus->bus_lock); |
656 | for (i = 3; i < 12; i++) { | 673 | for (i = 3; i < 12; i++) { |
@@ -660,6 +677,7 @@ int snd_ac97_pcm_close(struct ac97_pcm *pcm) | |||
660 | bus->used_slots[pcm->stream][cidx] &= ~(1 << i); | 677 | bus->used_slots[pcm->stream][cidx] &= ~(1 << i); |
661 | } | 678 | } |
662 | pcm->aslots = 0; | 679 | pcm->aslots = 0; |
680 | pcm->cur_dbl = 0; | ||
663 | spin_unlock_irq(&pcm->bus->bus_lock); | 681 | spin_unlock_irq(&pcm->bus->bus_lock); |
664 | return 0; | 682 | return 0; |
665 | } | 683 | } |
diff --git a/sound/pci/ac97/ac97_proc.c b/sound/pci/ac97/ac97_proc.c index 2118df50b9d6..a3fdd7da911c 100644 --- a/sound/pci/ac97/ac97_proc.c +++ b/sound/pci/ac97/ac97_proc.c | |||
@@ -457,14 +457,10 @@ void snd_ac97_proc_init(struct snd_ac97 * ac97) | |||
457 | 457 | ||
458 | void snd_ac97_proc_done(struct snd_ac97 * ac97) | 458 | void snd_ac97_proc_done(struct snd_ac97 * ac97) |
459 | { | 459 | { |
460 | if (ac97->proc_regs) { | 460 | snd_info_free_entry(ac97->proc_regs); |
461 | snd_info_unregister(ac97->proc_regs); | 461 | ac97->proc_regs = NULL; |
462 | ac97->proc_regs = NULL; | 462 | snd_info_free_entry(ac97->proc); |
463 | } | 463 | ac97->proc = NULL; |
464 | if (ac97->proc) { | ||
465 | snd_info_unregister(ac97->proc); | ||
466 | ac97->proc = NULL; | ||
467 | } | ||
468 | } | 464 | } |
469 | 465 | ||
470 | void snd_ac97_bus_proc_init(struct snd_ac97_bus * bus) | 466 | void snd_ac97_bus_proc_init(struct snd_ac97_bus * bus) |
@@ -485,8 +481,6 @@ void snd_ac97_bus_proc_init(struct snd_ac97_bus * bus) | |||
485 | 481 | ||
486 | void snd_ac97_bus_proc_done(struct snd_ac97_bus * bus) | 482 | void snd_ac97_bus_proc_done(struct snd_ac97_bus * bus) |
487 | { | 483 | { |
488 | if (bus->proc) { | 484 | snd_info_free_entry(bus->proc); |
489 | snd_info_unregister(bus->proc); | 485 | bus->proc = NULL; |
490 | bus->proc = NULL; | ||
491 | } | ||
492 | } | 486 | } |
diff --git a/sound/pci/ac97/ak4531_codec.c b/sound/pci/ac97/ak4531_codec.c index 94c26ec05882..c153cb79c518 100644 --- a/sound/pci/ac97/ak4531_codec.c +++ b/sound/pci/ac97/ak4531_codec.c | |||
@@ -27,6 +27,7 @@ | |||
27 | 27 | ||
28 | #include <sound/core.h> | 28 | #include <sound/core.h> |
29 | #include <sound/ak4531_codec.h> | 29 | #include <sound/ak4531_codec.h> |
30 | #include <sound/tlv.h> | ||
30 | 31 | ||
31 | MODULE_AUTHOR("Jaroslav Kysela <perex@suse.cz>"); | 32 | MODULE_AUTHOR("Jaroslav Kysela <perex@suse.cz>"); |
32 | MODULE_DESCRIPTION("Universal routines for AK4531 codec"); | 33 | MODULE_DESCRIPTION("Universal routines for AK4531 codec"); |
@@ -63,6 +64,14 @@ static void snd_ak4531_dump(struct snd_ak4531 *ak4531) | |||
63 | .info = snd_ak4531_info_single, \ | 64 | .info = snd_ak4531_info_single, \ |
64 | .get = snd_ak4531_get_single, .put = snd_ak4531_put_single, \ | 65 | .get = snd_ak4531_get_single, .put = snd_ak4531_put_single, \ |
65 | .private_value = reg | (shift << 16) | (mask << 24) | (invert << 22) } | 66 | .private_value = reg | (shift << 16) | (mask << 24) | (invert << 22) } |
67 | #define AK4531_SINGLE_TLV(xname, xindex, reg, shift, mask, invert, xtlv) \ | ||
68 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ | ||
69 | .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ, \ | ||
70 | .name = xname, .index = xindex, \ | ||
71 | .info = snd_ak4531_info_single, \ | ||
72 | .get = snd_ak4531_get_single, .put = snd_ak4531_put_single, \ | ||
73 | .private_value = reg | (shift << 16) | (mask << 24) | (invert << 22), \ | ||
74 | .tlv = { .p = (xtlv) } } | ||
66 | 75 | ||
67 | static int snd_ak4531_info_single(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) | 76 | static int snd_ak4531_info_single(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) |
68 | { | 77 | { |
@@ -122,6 +131,14 @@ static int snd_ak4531_put_single(struct snd_kcontrol *kcontrol, struct snd_ctl_e | |||
122 | .info = snd_ak4531_info_double, \ | 131 | .info = snd_ak4531_info_double, \ |
123 | .get = snd_ak4531_get_double, .put = snd_ak4531_put_double, \ | 132 | .get = snd_ak4531_get_double, .put = snd_ak4531_put_double, \ |
124 | .private_value = left_reg | (right_reg << 8) | (left_shift << 16) | (right_shift << 19) | (mask << 24) | (invert << 22) } | 133 | .private_value = left_reg | (right_reg << 8) | (left_shift << 16) | (right_shift << 19) | (mask << 24) | (invert << 22) } |
134 | #define AK4531_DOUBLE_TLV(xname, xindex, left_reg, right_reg, left_shift, right_shift, mask, invert, xtlv) \ | ||
135 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ | ||
136 | .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ, \ | ||
137 | .name = xname, .index = xindex, \ | ||
138 | .info = snd_ak4531_info_double, \ | ||
139 | .get = snd_ak4531_get_double, .put = snd_ak4531_put_double, \ | ||
140 | .private_value = left_reg | (right_reg << 8) | (left_shift << 16) | (right_shift << 19) | (mask << 24) | (invert << 22), \ | ||
141 | .tlv = { .p = (xtlv) } } | ||
125 | 142 | ||
126 | static int snd_ak4531_info_double(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) | 143 | static int snd_ak4531_info_double(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) |
127 | { | 144 | { |
@@ -250,50 +267,62 @@ static int snd_ak4531_put_input_sw(struct snd_kcontrol *kcontrol, struct snd_ctl | |||
250 | return change; | 267 | return change; |
251 | } | 268 | } |
252 | 269 | ||
270 | static DECLARE_TLV_DB_SCALE(db_scale_master, -6200, 200, 0); | ||
271 | static DECLARE_TLV_DB_SCALE(db_scale_mono, -2800, 400, 0); | ||
272 | static DECLARE_TLV_DB_SCALE(db_scale_input, -5000, 200, 0); | ||
273 | |||
253 | static struct snd_kcontrol_new snd_ak4531_controls[] = { | 274 | static struct snd_kcontrol_new snd_ak4531_controls[] = { |
254 | 275 | ||
255 | AK4531_DOUBLE("Master Playback Switch", 0, AK4531_LMASTER, AK4531_RMASTER, 7, 7, 1, 1), | 276 | AK4531_DOUBLE_TLV("Master Playback Switch", 0, |
277 | AK4531_LMASTER, AK4531_RMASTER, 7, 7, 1, 1, | ||
278 | db_scale_master), | ||
256 | AK4531_DOUBLE("Master Playback Volume", 0, AK4531_LMASTER, AK4531_RMASTER, 0, 0, 0x1f, 1), | 279 | AK4531_DOUBLE("Master Playback Volume", 0, AK4531_LMASTER, AK4531_RMASTER, 0, 0, 0x1f, 1), |
257 | 280 | ||
258 | AK4531_SINGLE("Master Mono Playback Switch", 0, AK4531_MONO_OUT, 7, 1, 1), | 281 | AK4531_SINGLE_TLV("Master Mono Playback Switch", 0, AK4531_MONO_OUT, 7, 1, 1, |
282 | db_scale_mono), | ||
259 | AK4531_SINGLE("Master Mono Playback Volume", 0, AK4531_MONO_OUT, 0, 0x07, 1), | 283 | AK4531_SINGLE("Master Mono Playback Volume", 0, AK4531_MONO_OUT, 0, 0x07, 1), |
260 | 284 | ||
261 | AK4531_DOUBLE("PCM Switch", 0, AK4531_LVOICE, AK4531_RVOICE, 7, 7, 1, 1), | 285 | AK4531_DOUBLE("PCM Switch", 0, AK4531_LVOICE, AK4531_RVOICE, 7, 7, 1, 1), |
262 | AK4531_DOUBLE("PCM Volume", 0, AK4531_LVOICE, AK4531_RVOICE, 0, 0, 0x1f, 1), | 286 | AK4531_DOUBLE_TLV("PCM Volume", 0, AK4531_LVOICE, AK4531_RVOICE, 0, 0, 0x1f, 1, |
287 | db_scale_input), | ||
263 | AK4531_DOUBLE("PCM Playback Switch", 0, AK4531_OUT_SW2, AK4531_OUT_SW2, 3, 2, 1, 0), | 288 | AK4531_DOUBLE("PCM Playback Switch", 0, AK4531_OUT_SW2, AK4531_OUT_SW2, 3, 2, 1, 0), |
264 | AK4531_DOUBLE("PCM Capture Switch", 0, AK4531_LIN_SW2, AK4531_RIN_SW2, 2, 2, 1, 0), | 289 | AK4531_DOUBLE("PCM Capture Switch", 0, AK4531_LIN_SW2, AK4531_RIN_SW2, 2, 2, 1, 0), |
265 | 290 | ||
266 | AK4531_DOUBLE("PCM Switch", 1, AK4531_LFM, AK4531_RFM, 7, 7, 1, 1), | 291 | AK4531_DOUBLE("PCM Switch", 1, AK4531_LFM, AK4531_RFM, 7, 7, 1, 1), |
267 | AK4531_DOUBLE("PCM Volume", 1, AK4531_LFM, AK4531_RFM, 0, 0, 0x1f, 1), | 292 | AK4531_DOUBLE_TLV("PCM Volume", 1, AK4531_LFM, AK4531_RFM, 0, 0, 0x1f, 1, |
293 | db_scale_input), | ||
268 | AK4531_DOUBLE("PCM Playback Switch", 1, AK4531_OUT_SW1, AK4531_OUT_SW1, 6, 5, 1, 0), | 294 | AK4531_DOUBLE("PCM Playback Switch", 1, AK4531_OUT_SW1, AK4531_OUT_SW1, 6, 5, 1, 0), |
269 | AK4531_INPUT_SW("PCM Capture Route", 1, AK4531_LIN_SW1, AK4531_RIN_SW1, 6, 5), | 295 | AK4531_INPUT_SW("PCM Capture Route", 1, AK4531_LIN_SW1, AK4531_RIN_SW1, 6, 5), |
270 | 296 | ||
271 | AK4531_DOUBLE("CD Switch", 0, AK4531_LCD, AK4531_RCD, 7, 7, 1, 1), | 297 | AK4531_DOUBLE("CD Switch", 0, AK4531_LCD, AK4531_RCD, 7, 7, 1, 1), |
272 | AK4531_DOUBLE("CD Volume", 0, AK4531_LCD, AK4531_RCD, 0, 0, 0x1f, 1), | 298 | AK4531_DOUBLE_TLV("CD Volume", 0, AK4531_LCD, AK4531_RCD, 0, 0, 0x1f, 1, |
299 | db_scale_input), | ||
273 | AK4531_DOUBLE("CD Playback Switch", 0, AK4531_OUT_SW1, AK4531_OUT_SW1, 2, 1, 1, 0), | 300 | AK4531_DOUBLE("CD Playback Switch", 0, AK4531_OUT_SW1, AK4531_OUT_SW1, 2, 1, 1, 0), |
274 | AK4531_INPUT_SW("CD Capture Route", 0, AK4531_LIN_SW1, AK4531_RIN_SW1, 2, 1), | 301 | AK4531_INPUT_SW("CD Capture Route", 0, AK4531_LIN_SW1, AK4531_RIN_SW1, 2, 1), |
275 | 302 | ||
276 | AK4531_DOUBLE("Line Switch", 0, AK4531_LLINE, AK4531_RLINE, 7, 7, 1, 1), | 303 | AK4531_DOUBLE("Line Switch", 0, AK4531_LLINE, AK4531_RLINE, 7, 7, 1, 1), |
277 | AK4531_DOUBLE("Line Volume", 0, AK4531_LLINE, AK4531_RLINE, 0, 0, 0x1f, 1), | 304 | AK4531_DOUBLE_TLV("Line Volume", 0, AK4531_LLINE, AK4531_RLINE, 0, 0, 0x1f, 1, |
305 | db_scale_input), | ||
278 | AK4531_DOUBLE("Line Playback Switch", 0, AK4531_OUT_SW1, AK4531_OUT_SW1, 4, 3, 1, 0), | 306 | AK4531_DOUBLE("Line Playback Switch", 0, AK4531_OUT_SW1, AK4531_OUT_SW1, 4, 3, 1, 0), |
279 | AK4531_INPUT_SW("Line Capture Route", 0, AK4531_LIN_SW1, AK4531_RIN_SW1, 4, 3), | 307 | AK4531_INPUT_SW("Line Capture Route", 0, AK4531_LIN_SW1, AK4531_RIN_SW1, 4, 3), |
280 | 308 | ||
281 | AK4531_DOUBLE("Aux Switch", 0, AK4531_LAUXA, AK4531_RAUXA, 7, 7, 1, 1), | 309 | AK4531_DOUBLE("Aux Switch", 0, AK4531_LAUXA, AK4531_RAUXA, 7, 7, 1, 1), |
282 | AK4531_DOUBLE("Aux Volume", 0, AK4531_LAUXA, AK4531_RAUXA, 0, 0, 0x1f, 1), | 310 | AK4531_DOUBLE_TLV("Aux Volume", 0, AK4531_LAUXA, AK4531_RAUXA, 0, 0, 0x1f, 1, |
311 | db_scale_input), | ||
283 | AK4531_DOUBLE("Aux Playback Switch", 0, AK4531_OUT_SW2, AK4531_OUT_SW2, 5, 4, 1, 0), | 312 | AK4531_DOUBLE("Aux Playback Switch", 0, AK4531_OUT_SW2, AK4531_OUT_SW2, 5, 4, 1, 0), |
284 | AK4531_INPUT_SW("Aux Capture Route", 0, AK4531_LIN_SW2, AK4531_RIN_SW2, 4, 3), | 313 | AK4531_INPUT_SW("Aux Capture Route", 0, AK4531_LIN_SW2, AK4531_RIN_SW2, 4, 3), |
285 | 314 | ||
286 | AK4531_SINGLE("Mono Switch", 0, AK4531_MONO1, 7, 1, 1), | 315 | AK4531_SINGLE("Mono Switch", 0, AK4531_MONO1, 7, 1, 1), |
287 | AK4531_SINGLE("Mono Volume", 0, AK4531_MONO1, 0, 0x1f, 1), | 316 | AK4531_SINGLE_TLV("Mono Volume", 0, AK4531_MONO1, 0, 0x1f, 1, db_scale_input), |
288 | AK4531_SINGLE("Mono Playback Switch", 0, AK4531_OUT_SW2, 0, 1, 0), | 317 | AK4531_SINGLE("Mono Playback Switch", 0, AK4531_OUT_SW2, 0, 1, 0), |
289 | AK4531_DOUBLE("Mono Capture Switch", 0, AK4531_LIN_SW2, AK4531_RIN_SW2, 0, 0, 1, 0), | 318 | AK4531_DOUBLE("Mono Capture Switch", 0, AK4531_LIN_SW2, AK4531_RIN_SW2, 0, 0, 1, 0), |
290 | 319 | ||
291 | AK4531_SINGLE("Mono Switch", 1, AK4531_MONO2, 7, 1, 1), | 320 | AK4531_SINGLE("Mono Switch", 1, AK4531_MONO2, 7, 1, 1), |
292 | AK4531_SINGLE("Mono Volume", 1, AK4531_MONO2, 0, 0x1f, 1), | 321 | AK4531_SINGLE_TLV("Mono Volume", 1, AK4531_MONO2, 0, 0x1f, 1, db_scale_input), |
293 | AK4531_SINGLE("Mono Playback Switch", 1, AK4531_OUT_SW2, 1, 1, 0), | 322 | AK4531_SINGLE("Mono Playback Switch", 1, AK4531_OUT_SW2, 1, 1, 0), |
294 | AK4531_DOUBLE("Mono Capture Switch", 1, AK4531_LIN_SW2, AK4531_RIN_SW2, 1, 1, 1, 0), | 323 | AK4531_DOUBLE("Mono Capture Switch", 1, AK4531_LIN_SW2, AK4531_RIN_SW2, 1, 1, 1, 0), |
295 | 324 | ||
296 | AK4531_SINGLE("Mic Volume", 0, AK4531_MIC, 0, 0x1f, 1), | 325 | AK4531_SINGLE_TLV("Mic Volume", 0, AK4531_MIC, 0, 0x1f, 1, db_scale_input), |
297 | AK4531_SINGLE("Mic Switch", 0, AK4531_MIC, 7, 1, 1), | 326 | AK4531_SINGLE("Mic Switch", 0, AK4531_MIC, 7, 1, 1), |
298 | AK4531_SINGLE("Mic Playback Switch", 0, AK4531_OUT_SW1, 0, 1, 0), | 327 | AK4531_SINGLE("Mic Playback Switch", 0, AK4531_OUT_SW1, 0, 1, 0), |
299 | AK4531_DOUBLE("Mic Capture Switch", 0, AK4531_LIN_SW1, AK4531_RIN_SW1, 0, 0, 1, 0), | 328 | AK4531_DOUBLE("Mic Capture Switch", 0, AK4531_LIN_SW1, AK4531_RIN_SW1, 0, 0, 1, 0), |
diff --git a/sound/pci/ca0106/ca0106_mixer.c b/sound/pci/ca0106/ca0106_mixer.c index 146eed70dce6..9855f528ea78 100644 --- a/sound/pci/ca0106/ca0106_mixer.c +++ b/sound/pci/ca0106/ca0106_mixer.c | |||
@@ -70,9 +70,13 @@ | |||
70 | #include <sound/pcm.h> | 70 | #include <sound/pcm.h> |
71 | #include <sound/ac97_codec.h> | 71 | #include <sound/ac97_codec.h> |
72 | #include <sound/info.h> | 72 | #include <sound/info.h> |
73 | #include <sound/tlv.h> | ||
73 | 74 | ||
74 | #include "ca0106.h" | 75 | #include "ca0106.h" |
75 | 76 | ||
77 | static DECLARE_TLV_DB_SCALE(snd_ca0106_db_scale1, -5175, 25, 1); | ||
78 | static DECLARE_TLV_DB_SCALE(snd_ca0106_db_scale2, -10350, 50, 1); | ||
79 | |||
76 | static int snd_ca0106_shared_spdif_info(struct snd_kcontrol *kcontrol, | 80 | static int snd_ca0106_shared_spdif_info(struct snd_kcontrol *kcontrol, |
77 | struct snd_ctl_elem_info *uinfo) | 81 | struct snd_ctl_elem_info *uinfo) |
78 | { | 82 | { |
@@ -469,18 +473,24 @@ static int snd_ca0106_i2c_volume_put(struct snd_kcontrol *kcontrol, | |||
469 | #define CA_VOLUME(xname,chid,reg) \ | 473 | #define CA_VOLUME(xname,chid,reg) \ |
470 | { \ | 474 | { \ |
471 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ | 475 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ |
476 | .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | \ | ||
477 | SNDRV_CTL_ELEM_ACCESS_TLV_READ, \ | ||
472 | .info = snd_ca0106_volume_info, \ | 478 | .info = snd_ca0106_volume_info, \ |
473 | .get = snd_ca0106_volume_get, \ | 479 | .get = snd_ca0106_volume_get, \ |
474 | .put = snd_ca0106_volume_put, \ | 480 | .put = snd_ca0106_volume_put, \ |
481 | .tlv = { .p = snd_ca0106_db_scale1 }, \ | ||
475 | .private_value = ((chid) << 8) | (reg) \ | 482 | .private_value = ((chid) << 8) | (reg) \ |
476 | } | 483 | } |
477 | 484 | ||
478 | #define I2C_VOLUME(xname,chid) \ | 485 | #define I2C_VOLUME(xname,chid) \ |
479 | { \ | 486 | { \ |
480 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ | 487 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ |
488 | .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | \ | ||
489 | SNDRV_CTL_ELEM_ACCESS_TLV_READ, \ | ||
481 | .info = snd_ca0106_i2c_volume_info, \ | 490 | .info = snd_ca0106_i2c_volume_info, \ |
482 | .get = snd_ca0106_i2c_volume_get, \ | 491 | .get = snd_ca0106_i2c_volume_get, \ |
483 | .put = snd_ca0106_i2c_volume_put, \ | 492 | .put = snd_ca0106_i2c_volume_put, \ |
493 | .tlv = { .p = snd_ca0106_db_scale2 }, \ | ||
484 | .private_value = chid \ | 494 | .private_value = chid \ |
485 | } | 495 | } |
486 | 496 | ||
diff --git a/sound/pci/cs4281.c b/sound/pci/cs4281.c index 9631456ec3de..1990430a21c1 100644 --- a/sound/pci/cs4281.c +++ b/sound/pci/cs4281.c | |||
@@ -33,6 +33,7 @@ | |||
33 | #include <sound/pcm.h> | 33 | #include <sound/pcm.h> |
34 | #include <sound/rawmidi.h> | 34 | #include <sound/rawmidi.h> |
35 | #include <sound/ac97_codec.h> | 35 | #include <sound/ac97_codec.h> |
36 | #include <sound/tlv.h> | ||
36 | #include <sound/opl3.h> | 37 | #include <sound/opl3.h> |
37 | #include <sound/initval.h> | 38 | #include <sound/initval.h> |
38 | 39 | ||
@@ -1054,6 +1055,8 @@ static int snd_cs4281_put_volume(struct snd_kcontrol *kcontrol, | |||
1054 | return change; | 1055 | return change; |
1055 | } | 1056 | } |
1056 | 1057 | ||
1058 | static DECLARE_TLV_DB_SCALE(db_scale_dsp, -4650, 150, 0); | ||
1059 | |||
1057 | static struct snd_kcontrol_new snd_cs4281_fm_vol = | 1060 | static struct snd_kcontrol_new snd_cs4281_fm_vol = |
1058 | { | 1061 | { |
1059 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 1062 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
@@ -1062,6 +1065,7 @@ static struct snd_kcontrol_new snd_cs4281_fm_vol = | |||
1062 | .get = snd_cs4281_get_volume, | 1065 | .get = snd_cs4281_get_volume, |
1063 | .put = snd_cs4281_put_volume, | 1066 | .put = snd_cs4281_put_volume, |
1064 | .private_value = ((BA0_FMLVC << 16) | BA0_FMRVC), | 1067 | .private_value = ((BA0_FMLVC << 16) | BA0_FMRVC), |
1068 | .tlv = { .p = db_scale_dsp }, | ||
1065 | }; | 1069 | }; |
1066 | 1070 | ||
1067 | static struct snd_kcontrol_new snd_cs4281_pcm_vol = | 1071 | static struct snd_kcontrol_new snd_cs4281_pcm_vol = |
@@ -1072,6 +1076,7 @@ static struct snd_kcontrol_new snd_cs4281_pcm_vol = | |||
1072 | .get = snd_cs4281_get_volume, | 1076 | .get = snd_cs4281_get_volume, |
1073 | .put = snd_cs4281_put_volume, | 1077 | .put = snd_cs4281_put_volume, |
1074 | .private_value = ((BA0_PPLVC << 16) | BA0_PPRVC), | 1078 | .private_value = ((BA0_PPLVC << 16) | BA0_PPRVC), |
1079 | .tlv = { .p = db_scale_dsp }, | ||
1075 | }; | 1080 | }; |
1076 | 1081 | ||
1077 | static void snd_cs4281_mixer_free_ac97_bus(struct snd_ac97_bus *bus) | 1082 | static void snd_cs4281_mixer_free_ac97_bus(struct snd_ac97_bus *bus) |
diff --git a/sound/pci/cs46xx/dsp_spos.c b/sound/pci/cs46xx/dsp_spos.c index 5c9711c0265c..89c402770a1d 100644 --- a/sound/pci/cs46xx/dsp_spos.c +++ b/sound/pci/cs46xx/dsp_spos.c | |||
@@ -868,35 +868,23 @@ int cs46xx_dsp_proc_done (struct snd_cs46xx *chip) | |||
868 | struct dsp_spos_instance * ins = chip->dsp_spos_instance; | 868 | struct dsp_spos_instance * ins = chip->dsp_spos_instance; |
869 | int i; | 869 | int i; |
870 | 870 | ||
871 | if (ins->proc_sym_info_entry) { | 871 | snd_info_free_entry(ins->proc_sym_info_entry); |
872 | snd_info_unregister(ins->proc_sym_info_entry); | 872 | ins->proc_sym_info_entry = NULL; |
873 | ins->proc_sym_info_entry = NULL; | 873 | |
874 | } | 874 | snd_info_free_entry(ins->proc_modules_info_entry); |
875 | 875 | ins->proc_modules_info_entry = NULL; | |
876 | if (ins->proc_modules_info_entry) { | 876 | |
877 | snd_info_unregister(ins->proc_modules_info_entry); | 877 | snd_info_free_entry(ins->proc_parameter_dump_info_entry); |
878 | ins->proc_modules_info_entry = NULL; | 878 | ins->proc_parameter_dump_info_entry = NULL; |
879 | } | 879 | |
880 | 880 | snd_info_free_entry(ins->proc_sample_dump_info_entry); | |
881 | if (ins->proc_parameter_dump_info_entry) { | 881 | ins->proc_sample_dump_info_entry = NULL; |
882 | snd_info_unregister(ins->proc_parameter_dump_info_entry); | 882 | |
883 | ins->proc_parameter_dump_info_entry = NULL; | 883 | snd_info_free_entry(ins->proc_scb_info_entry); |
884 | } | 884 | ins->proc_scb_info_entry = NULL; |
885 | 885 | ||
886 | if (ins->proc_sample_dump_info_entry) { | 886 | snd_info_free_entry(ins->proc_task_info_entry); |
887 | snd_info_unregister(ins->proc_sample_dump_info_entry); | 887 | ins->proc_task_info_entry = NULL; |
888 | ins->proc_sample_dump_info_entry = NULL; | ||
889 | } | ||
890 | |||
891 | if (ins->proc_scb_info_entry) { | ||
892 | snd_info_unregister(ins->proc_scb_info_entry); | ||
893 | ins->proc_scb_info_entry = NULL; | ||
894 | } | ||
895 | |||
896 | if (ins->proc_task_info_entry) { | ||
897 | snd_info_unregister(ins->proc_task_info_entry); | ||
898 | ins->proc_task_info_entry = NULL; | ||
899 | } | ||
900 | 888 | ||
901 | mutex_lock(&chip->spos_mutex); | 889 | mutex_lock(&chip->spos_mutex); |
902 | for (i = 0; i < ins->nscb; ++i) { | 890 | for (i = 0; i < ins->nscb; ++i) { |
@@ -905,10 +893,8 @@ int cs46xx_dsp_proc_done (struct snd_cs46xx *chip) | |||
905 | } | 893 | } |
906 | mutex_unlock(&chip->spos_mutex); | 894 | mutex_unlock(&chip->spos_mutex); |
907 | 895 | ||
908 | if (ins->proc_dsp_dir) { | 896 | snd_info_free_entry(ins->proc_dsp_dir); |
909 | snd_info_unregister (ins->proc_dsp_dir); | 897 | ins->proc_dsp_dir = NULL; |
910 | ins->proc_dsp_dir = NULL; | ||
911 | } | ||
912 | 898 | ||
913 | return 0; | 899 | return 0; |
914 | } | 900 | } |
diff --git a/sound/pci/cs46xx/dsp_spos_scb_lib.c b/sound/pci/cs46xx/dsp_spos_scb_lib.c index 232b337852ff..343f51d5311b 100644 --- a/sound/pci/cs46xx/dsp_spos_scb_lib.c +++ b/sound/pci/cs46xx/dsp_spos_scb_lib.c | |||
@@ -233,7 +233,7 @@ void cs46xx_dsp_proc_free_scb_desc (struct dsp_scb_descriptor * scb) | |||
233 | 233 | ||
234 | snd_printdd("cs46xx_dsp_proc_free_scb_desc: freeing %s\n",scb->scb_name); | 234 | snd_printdd("cs46xx_dsp_proc_free_scb_desc: freeing %s\n",scb->scb_name); |
235 | 235 | ||
236 | snd_info_unregister(scb->proc_info); | 236 | snd_info_free_entry(scb->proc_info); |
237 | scb->proc_info = NULL; | 237 | scb->proc_info = NULL; |
238 | 238 | ||
239 | snd_assert (scb_info != NULL, return); | 239 | snd_assert (scb_info != NULL, return); |
diff --git a/sound/pci/cs5535audio/Makefile b/sound/pci/cs5535audio/Makefile index 2911a8adc1f2..ad947b4c04cc 100644 --- a/sound/pci/cs5535audio/Makefile +++ b/sound/pci/cs5535audio/Makefile | |||
@@ -4,7 +4,7 @@ | |||
4 | 4 | ||
5 | snd-cs5535audio-objs := cs5535audio.o cs5535audio_pcm.o | 5 | snd-cs5535audio-objs := cs5535audio.o cs5535audio_pcm.o |
6 | 6 | ||
7 | ifdef CONFIG_PM | 7 | ifeq ($(CONFIG_PM),y) |
8 | snd-cs5535audio-objs += cs5535audio_pm.o | 8 | snd-cs5535audio-objs += cs5535audio_pm.o |
9 | endif | 9 | endif |
10 | 10 | ||
diff --git a/sound/pci/emu10k1/emu10k1.c b/sound/pci/emu10k1/emu10k1.c index 289bcd99c19c..493ec0816bb3 100644 --- a/sound/pci/emu10k1/emu10k1.c +++ b/sound/pci/emu10k1/emu10k1.c | |||
@@ -232,7 +232,7 @@ static int snd_emu10k1_suspend(struct pci_dev *pci, pm_message_t state) | |||
232 | return 0; | 232 | return 0; |
233 | } | 233 | } |
234 | 234 | ||
235 | int snd_emu10k1_resume(struct pci_dev *pci) | 235 | static int snd_emu10k1_resume(struct pci_dev *pci) |
236 | { | 236 | { |
237 | struct snd_card *card = pci_get_drvdata(pci); | 237 | struct snd_card *card = pci_get_drvdata(pci); |
238 | struct snd_emu10k1 *emu = card->private_data; | 238 | struct snd_emu10k1 *emu = card->private_data; |
diff --git a/sound/pci/emu10k1/emu10k1_main.c b/sound/pci/emu10k1/emu10k1_main.c index 79f24cdf5fbf..be65d4db8e27 100644 --- a/sound/pci/emu10k1/emu10k1_main.c +++ b/sound/pci/emu10k1/emu10k1_main.c | |||
@@ -927,6 +927,7 @@ static struct snd_emu_chip_details emu_chip_details[] = { | |||
927 | .ca0151_chip = 1, | 927 | .ca0151_chip = 1, |
928 | .spk71 = 1, | 928 | .spk71 = 1, |
929 | .spdif_bug = 1, | 929 | .spdif_bug = 1, |
930 | .adc_1361t = 1, /* 24 bit capture instead of 16bit */ | ||
930 | .ac97_chip = 1} , | 931 | .ac97_chip = 1} , |
931 | {.vendor = 0x1102, .device = 0x0004, .subsystem = 0x10051102, | 932 | {.vendor = 0x1102, .device = 0x0004, .subsystem = 0x10051102, |
932 | .driver = "Audigy2", .name = "Audigy 2 EX [1005]", | 933 | .driver = "Audigy2", .name = "Audigy 2 EX [1005]", |
diff --git a/sound/pci/emu10k1/emu10k1x.c b/sound/pci/emu10k1/emu10k1x.c index bda8bdf59935..da1610a571b8 100644 --- a/sound/pci/emu10k1/emu10k1x.c +++ b/sound/pci/emu10k1/emu10k1x.c | |||
@@ -1626,12 +1626,7 @@ static struct pci_driver driver = { | |||
1626 | // initialization of the module | 1626 | // initialization of the module |
1627 | static int __init alsa_card_emu10k1x_init(void) | 1627 | static int __init alsa_card_emu10k1x_init(void) |
1628 | { | 1628 | { |
1629 | int err; | 1629 | return pci_register_driver(&driver); |
1630 | |||
1631 | if ((err = pci_register_driver(&driver)) > 0) | ||
1632 | return err; | ||
1633 | |||
1634 | return 0; | ||
1635 | } | 1630 | } |
1636 | 1631 | ||
1637 | // clean up the module | 1632 | // clean up the module |
diff --git a/sound/pci/emu10k1/emufx.c b/sound/pci/emu10k1/emufx.c index dfba00230d4d..13cd6ce89811 100644 --- a/sound/pci/emu10k1/emufx.c +++ b/sound/pci/emu10k1/emufx.c | |||
@@ -35,6 +35,7 @@ | |||
35 | #include <linux/mutex.h> | 35 | #include <linux/mutex.h> |
36 | 36 | ||
37 | #include <sound/core.h> | 37 | #include <sound/core.h> |
38 | #include <sound/tlv.h> | ||
38 | #include <sound/emu10k1.h> | 39 | #include <sound/emu10k1.h> |
39 | 40 | ||
40 | #if 0 /* for testing purposes - digital out -> capture */ | 41 | #if 0 /* for testing purposes - digital out -> capture */ |
@@ -266,6 +267,7 @@ static const u32 treble_table[41][5] = { | |||
266 | { 0x37c4448b, 0xa45ef51d, 0x262f3267, 0x081e36dc, 0xfd8f5d14 } | 267 | { 0x37c4448b, 0xa45ef51d, 0x262f3267, 0x081e36dc, 0xfd8f5d14 } |
267 | }; | 268 | }; |
268 | 269 | ||
270 | /* dB gain = (float) 20 * log10( float(db_table_value) / 0x8000000 ) */ | ||
269 | static const u32 db_table[101] = { | 271 | static const u32 db_table[101] = { |
270 | 0x00000000, 0x01571f82, 0x01674b41, 0x01783a1b, 0x0189f540, | 272 | 0x00000000, 0x01571f82, 0x01674b41, 0x01783a1b, 0x0189f540, |
271 | 0x019c8651, 0x01aff763, 0x01c45306, 0x01d9a446, 0x01eff6b8, | 273 | 0x019c8651, 0x01aff763, 0x01c45306, 0x01d9a446, 0x01eff6b8, |
@@ -290,6 +292,9 @@ static const u32 db_table[101] = { | |||
290 | 0x7fffffff, | 292 | 0x7fffffff, |
291 | }; | 293 | }; |
292 | 294 | ||
295 | /* EMU10k1/EMU10k2 DSP control db gain */ | ||
296 | static DECLARE_TLV_DB_SCALE(snd_emu10k1_db_scale1, -4000, 40, 1); | ||
297 | |||
293 | static const u32 onoff_table[2] = { | 298 | static const u32 onoff_table[2] = { |
294 | 0x00000000, 0x00000001 | 299 | 0x00000000, 0x00000001 |
295 | }; | 300 | }; |
@@ -755,6 +760,11 @@ static int snd_emu10k1_add_controls(struct snd_emu10k1 *emu, | |||
755 | knew.device = gctl->id.device; | 760 | knew.device = gctl->id.device; |
756 | knew.subdevice = gctl->id.subdevice; | 761 | knew.subdevice = gctl->id.subdevice; |
757 | knew.info = snd_emu10k1_gpr_ctl_info; | 762 | knew.info = snd_emu10k1_gpr_ctl_info; |
763 | if (gctl->tlv.p) { | ||
764 | knew.tlv.p = gctl->tlv.p; | ||
765 | knew.access = SNDRV_CTL_ELEM_ACCESS_READWRITE | | ||
766 | SNDRV_CTL_ELEM_ACCESS_TLV_READ; | ||
767 | } | ||
758 | knew.get = snd_emu10k1_gpr_ctl_get; | 768 | knew.get = snd_emu10k1_gpr_ctl_get; |
759 | knew.put = snd_emu10k1_gpr_ctl_put; | 769 | knew.put = snd_emu10k1_gpr_ctl_put; |
760 | memset(nctl, 0, sizeof(*nctl)); | 770 | memset(nctl, 0, sizeof(*nctl)); |
@@ -1013,6 +1023,7 @@ snd_emu10k1_init_mono_control(struct snd_emu10k1_fx8010_control_gpr *ctl, | |||
1013 | ctl->gpr[0] = gpr + 0; ctl->value[0] = defval; | 1023 | ctl->gpr[0] = gpr + 0; ctl->value[0] = defval; |
1014 | ctl->min = 0; | 1024 | ctl->min = 0; |
1015 | ctl->max = 100; | 1025 | ctl->max = 100; |
1026 | ctl->tlv.p = snd_emu10k1_db_scale1; | ||
1016 | ctl->translation = EMU10K1_GPR_TRANSLATION_TABLE100; | 1027 | ctl->translation = EMU10K1_GPR_TRANSLATION_TABLE100; |
1017 | } | 1028 | } |
1018 | 1029 | ||
@@ -1027,6 +1038,7 @@ snd_emu10k1_init_stereo_control(struct snd_emu10k1_fx8010_control_gpr *ctl, | |||
1027 | ctl->gpr[1] = gpr + 1; ctl->value[1] = defval; | 1038 | ctl->gpr[1] = gpr + 1; ctl->value[1] = defval; |
1028 | ctl->min = 0; | 1039 | ctl->min = 0; |
1029 | ctl->max = 100; | 1040 | ctl->max = 100; |
1041 | ctl->tlv.p = snd_emu10k1_db_scale1; | ||
1030 | ctl->translation = EMU10K1_GPR_TRANSLATION_TABLE100; | 1042 | ctl->translation = EMU10K1_GPR_TRANSLATION_TABLE100; |
1031 | } | 1043 | } |
1032 | 1044 | ||
diff --git a/sound/pci/emu10k1/p16v.c b/sound/pci/emu10k1/p16v.c index 9905651935fb..4e0f95438f47 100644 --- a/sound/pci/emu10k1/p16v.c +++ b/sound/pci/emu10k1/p16v.c | |||
@@ -100,6 +100,7 @@ | |||
100 | #include <sound/pcm.h> | 100 | #include <sound/pcm.h> |
101 | #include <sound/ac97_codec.h> | 101 | #include <sound/ac97_codec.h> |
102 | #include <sound/info.h> | 102 | #include <sound/info.h> |
103 | #include <sound/tlv.h> | ||
103 | #include <sound/emu10k1.h> | 104 | #include <sound/emu10k1.h> |
104 | #include "p16v.h" | 105 | #include "p16v.h" |
105 | 106 | ||
@@ -784,12 +785,16 @@ static int snd_p16v_capture_channel_put(struct snd_kcontrol *kcontrol, | |||
784 | } | 785 | } |
785 | return change; | 786 | return change; |
786 | } | 787 | } |
788 | static DECLARE_TLV_DB_SCALE(snd_p16v_db_scale1, -5175, 25, 1); | ||
787 | 789 | ||
788 | #define P16V_VOL(xname,xreg,xhl) { \ | 790 | #define P16V_VOL(xname,xreg,xhl) { \ |
789 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ | 791 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ |
792 | .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | \ | ||
793 | SNDRV_CTL_ELEM_ACCESS_TLV_READ, \ | ||
790 | .info = snd_p16v_volume_info, \ | 794 | .info = snd_p16v_volume_info, \ |
791 | .get = snd_p16v_volume_get, \ | 795 | .get = snd_p16v_volume_get, \ |
792 | .put = snd_p16v_volume_put, \ | 796 | .put = snd_p16v_volume_put, \ |
797 | .tlv = { .p = snd_p16v_db_scale1 }, \ | ||
793 | .private_value = ((xreg) | ((xhl) << 8)) \ | 798 | .private_value = ((xreg) | ((xhl) << 8)) \ |
794 | } | 799 | } |
795 | 800 | ||
diff --git a/sound/pci/es1938.c b/sound/pci/es1938.c index cc0f34f68185..3ce5a4e7e31f 100644 --- a/sound/pci/es1938.c +++ b/sound/pci/es1938.c | |||
@@ -62,6 +62,7 @@ | |||
62 | #include <sound/opl3.h> | 62 | #include <sound/opl3.h> |
63 | #include <sound/mpu401.h> | 63 | #include <sound/mpu401.h> |
64 | #include <sound/initval.h> | 64 | #include <sound/initval.h> |
65 | #include <sound/tlv.h> | ||
65 | 66 | ||
66 | #include <asm/io.h> | 67 | #include <asm/io.h> |
67 | 68 | ||
@@ -1164,6 +1165,14 @@ static int snd_es1938_reg_read(struct es1938 *chip, unsigned char reg) | |||
1164 | return snd_es1938_read(chip, reg); | 1165 | return snd_es1938_read(chip, reg); |
1165 | } | 1166 | } |
1166 | 1167 | ||
1168 | #define ES1938_SINGLE_TLV(xname, xindex, reg, shift, mask, invert, xtlv) \ | ||
1169 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ | ||
1170 | .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ,\ | ||
1171 | .name = xname, .index = xindex, \ | ||
1172 | .info = snd_es1938_info_single, \ | ||
1173 | .get = snd_es1938_get_single, .put = snd_es1938_put_single, \ | ||
1174 | .private_value = reg | (shift << 8) | (mask << 16) | (invert << 24), \ | ||
1175 | .tlv = { .p = xtlv } } | ||
1167 | #define ES1938_SINGLE(xname, xindex, reg, shift, mask, invert) \ | 1176 | #define ES1938_SINGLE(xname, xindex, reg, shift, mask, invert) \ |
1168 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \ | 1177 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \ |
1169 | .info = snd_es1938_info_single, \ | 1178 | .info = snd_es1938_info_single, \ |
@@ -1217,6 +1226,14 @@ static int snd_es1938_put_single(struct snd_kcontrol *kcontrol, | |||
1217 | return snd_es1938_reg_bits(chip, reg, mask, val) != val; | 1226 | return snd_es1938_reg_bits(chip, reg, mask, val) != val; |
1218 | } | 1227 | } |
1219 | 1228 | ||
1229 | #define ES1938_DOUBLE_TLV(xname, xindex, left_reg, right_reg, shift_left, shift_right, mask, invert, xtlv) \ | ||
1230 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ | ||
1231 | .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ,\ | ||
1232 | .name = xname, .index = xindex, \ | ||
1233 | .info = snd_es1938_info_double, \ | ||
1234 | .get = snd_es1938_get_double, .put = snd_es1938_put_double, \ | ||
1235 | .private_value = left_reg | (right_reg << 8) | (shift_left << 16) | (shift_right << 19) | (mask << 24) | (invert << 22), \ | ||
1236 | .tlv = { .p = xtlv } } | ||
1220 | #define ES1938_DOUBLE(xname, xindex, left_reg, right_reg, shift_left, shift_right, mask, invert) \ | 1237 | #define ES1938_DOUBLE(xname, xindex, left_reg, right_reg, shift_left, shift_right, mask, invert) \ |
1221 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \ | 1238 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \ |
1222 | .info = snd_es1938_info_double, \ | 1239 | .info = snd_es1938_info_double, \ |
@@ -1297,8 +1314,41 @@ static int snd_es1938_put_double(struct snd_kcontrol *kcontrol, | |||
1297 | return change; | 1314 | return change; |
1298 | } | 1315 | } |
1299 | 1316 | ||
1317 | static unsigned int db_scale_master[] = { | ||
1318 | TLV_DB_RANGE_HEAD(2), | ||
1319 | 0, 54, TLV_DB_SCALE_ITEM(-3600, 50, 1), | ||
1320 | 54, 63, TLV_DB_SCALE_ITEM(-900, 100, 0), | ||
1321 | }; | ||
1322 | |||
1323 | static unsigned int db_scale_audio1[] = { | ||
1324 | TLV_DB_RANGE_HEAD(2), | ||
1325 | 0, 8, TLV_DB_SCALE_ITEM(-3300, 300, 1), | ||
1326 | 8, 15, TLV_DB_SCALE_ITEM(-900, 150, 0), | ||
1327 | }; | ||
1328 | |||
1329 | static unsigned int db_scale_audio2[] = { | ||
1330 | TLV_DB_RANGE_HEAD(2), | ||
1331 | 0, 8, TLV_DB_SCALE_ITEM(-3450, 300, 1), | ||
1332 | 8, 15, TLV_DB_SCALE_ITEM(-1050, 150, 0), | ||
1333 | }; | ||
1334 | |||
1335 | static unsigned int db_scale_mic[] = { | ||
1336 | TLV_DB_RANGE_HEAD(2), | ||
1337 | 0, 8, TLV_DB_SCALE_ITEM(-2400, 300, 1), | ||
1338 | 8, 15, TLV_DB_SCALE_ITEM(0, 150, 0), | ||
1339 | }; | ||
1340 | |||
1341 | static unsigned int db_scale_line[] = { | ||
1342 | TLV_DB_RANGE_HEAD(2), | ||
1343 | 0, 8, TLV_DB_SCALE_ITEM(-3150, 300, 1), | ||
1344 | 8, 15, TLV_DB_SCALE_ITEM(-750, 150, 0), | ||
1345 | }; | ||
1346 | |||
1347 | static DECLARE_TLV_DB_SCALE(db_scale_capture, 0, 150, 0); | ||
1348 | |||
1300 | static struct snd_kcontrol_new snd_es1938_controls[] = { | 1349 | static struct snd_kcontrol_new snd_es1938_controls[] = { |
1301 | ES1938_DOUBLE("Master Playback Volume", 0, 0x60, 0x62, 0, 0, 63, 0), | 1350 | ES1938_DOUBLE_TLV("Master Playback Volume", 0, 0x60, 0x62, 0, 0, 63, 0, |
1351 | db_scale_master), | ||
1302 | ES1938_DOUBLE("Master Playback Switch", 0, 0x60, 0x62, 6, 6, 1, 1), | 1352 | ES1938_DOUBLE("Master Playback Switch", 0, 0x60, 0x62, 6, 6, 1, 1), |
1303 | { | 1353 | { |
1304 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 1354 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
@@ -1309,19 +1359,27 @@ ES1938_DOUBLE("Master Playback Switch", 0, 0x60, 0x62, 6, 6, 1, 1), | |||
1309 | }, | 1359 | }, |
1310 | { | 1360 | { |
1311 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 1361 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
1362 | .access = (SNDRV_CTL_ELEM_ACCESS_READ | | ||
1363 | SNDRV_CTL_ELEM_ACCESS_TLV_READ), | ||
1312 | .name = "Hardware Master Playback Switch", | 1364 | .name = "Hardware Master Playback Switch", |
1313 | .access = SNDRV_CTL_ELEM_ACCESS_READ, | ||
1314 | .info = snd_es1938_info_hw_switch, | 1365 | .info = snd_es1938_info_hw_switch, |
1315 | .get = snd_es1938_get_hw_switch, | 1366 | .get = snd_es1938_get_hw_switch, |
1367 | .tlv = { .p = db_scale_master }, | ||
1316 | }, | 1368 | }, |
1317 | ES1938_SINGLE("Hardware Volume Split", 0, 0x64, 7, 1, 0), | 1369 | ES1938_SINGLE("Hardware Volume Split", 0, 0x64, 7, 1, 0), |
1318 | ES1938_DOUBLE("Line Playback Volume", 0, 0x3e, 0x3e, 4, 0, 15, 0), | 1370 | ES1938_DOUBLE_TLV("Line Playback Volume", 0, 0x3e, 0x3e, 4, 0, 15, 0, |
1371 | db_scale_line), | ||
1319 | ES1938_DOUBLE("CD Playback Volume", 0, 0x38, 0x38, 4, 0, 15, 0), | 1372 | ES1938_DOUBLE("CD Playback Volume", 0, 0x38, 0x38, 4, 0, 15, 0), |
1320 | ES1938_DOUBLE("FM Playback Volume", 0, 0x36, 0x36, 4, 0, 15, 0), | 1373 | ES1938_DOUBLE_TLV("FM Playback Volume", 0, 0x36, 0x36, 4, 0, 15, 0, |
1321 | ES1938_DOUBLE("Mono Playback Volume", 0, 0x6d, 0x6d, 4, 0, 15, 0), | 1374 | db_scale_mic), |
1322 | ES1938_DOUBLE("Mic Playback Volume", 0, 0x1a, 0x1a, 4, 0, 15, 0), | 1375 | ES1938_DOUBLE_TLV("Mono Playback Volume", 0, 0x6d, 0x6d, 4, 0, 15, 0, |
1323 | ES1938_DOUBLE("Aux Playback Volume", 0, 0x3a, 0x3a, 4, 0, 15, 0), | 1376 | db_scale_line), |
1324 | ES1938_DOUBLE("Capture Volume", 0, 0xb4, 0xb4, 4, 0, 15, 0), | 1377 | ES1938_DOUBLE_TLV("Mic Playback Volume", 0, 0x1a, 0x1a, 4, 0, 15, 0, |
1378 | db_scale_mic), | ||
1379 | ES1938_DOUBLE_TLV("Aux Playback Volume", 0, 0x3a, 0x3a, 4, 0, 15, 0, | ||
1380 | db_scale_line), | ||
1381 | ES1938_DOUBLE_TLV("Capture Volume", 0, 0xb4, 0xb4, 4, 0, 15, 0, | ||
1382 | db_scale_capture), | ||
1325 | ES1938_SINGLE("PC Speaker Volume", 0, 0x3c, 0, 7, 0), | 1383 | ES1938_SINGLE("PC Speaker Volume", 0, 0x3c, 0, 7, 0), |
1326 | ES1938_SINGLE("Record Monitor", 0, 0xa8, 3, 1, 0), | 1384 | ES1938_SINGLE("Record Monitor", 0, 0xa8, 3, 1, 0), |
1327 | ES1938_SINGLE("Capture Switch", 0, 0x1c, 4, 1, 1), | 1385 | ES1938_SINGLE("Capture Switch", 0, 0x1c, 4, 1, 1), |
@@ -1332,16 +1390,26 @@ ES1938_SINGLE("Capture Switch", 0, 0x1c, 4, 1, 1), | |||
1332 | .get = snd_es1938_get_mux, | 1390 | .get = snd_es1938_get_mux, |
1333 | .put = snd_es1938_put_mux, | 1391 | .put = snd_es1938_put_mux, |
1334 | }, | 1392 | }, |
1335 | ES1938_DOUBLE("Mono Input Playback Volume", 0, 0x6d, 0x6d, 4, 0, 15, 0), | 1393 | ES1938_DOUBLE_TLV("Mono Input Playback Volume", 0, 0x6d, 0x6d, 4, 0, 15, 0, |
1336 | ES1938_DOUBLE("PCM Capture Volume", 0, 0x69, 0x69, 4, 0, 15, 0), | 1394 | db_scale_line), |
1337 | ES1938_DOUBLE("Mic Capture Volume", 0, 0x68, 0x68, 4, 0, 15, 0), | 1395 | ES1938_DOUBLE_TLV("PCM Capture Volume", 0, 0x69, 0x69, 4, 0, 15, 0, |
1338 | ES1938_DOUBLE("Line Capture Volume", 0, 0x6e, 0x6e, 4, 0, 15, 0), | 1396 | db_scale_audio2), |
1339 | ES1938_DOUBLE("FM Capture Volume", 0, 0x6b, 0x6b, 4, 0, 15, 0), | 1397 | ES1938_DOUBLE_TLV("Mic Capture Volume", 0, 0x68, 0x68, 4, 0, 15, 0, |
1340 | ES1938_DOUBLE("Mono Capture Volume", 0, 0x6f, 0x6f, 4, 0, 15, 0), | 1398 | db_scale_mic), |
1341 | ES1938_DOUBLE("CD Capture Volume", 0, 0x6a, 0x6a, 4, 0, 15, 0), | 1399 | ES1938_DOUBLE_TLV("Line Capture Volume", 0, 0x6e, 0x6e, 4, 0, 15, 0, |
1342 | ES1938_DOUBLE("Aux Capture Volume", 0, 0x6c, 0x6c, 4, 0, 15, 0), | 1400 | db_scale_line), |
1343 | ES1938_DOUBLE("PCM Playback Volume", 0, 0x7c, 0x7c, 4, 0, 15, 0), | 1401 | ES1938_DOUBLE_TLV("FM Capture Volume", 0, 0x6b, 0x6b, 4, 0, 15, 0, |
1344 | ES1938_DOUBLE("PCM Playback Volume", 1, 0x14, 0x14, 4, 0, 15, 0), | 1402 | db_scale_mic), |
1403 | ES1938_DOUBLE_TLV("Mono Capture Volume", 0, 0x6f, 0x6f, 4, 0, 15, 0, | ||
1404 | db_scale_line), | ||
1405 | ES1938_DOUBLE_TLV("CD Capture Volume", 0, 0x6a, 0x6a, 4, 0, 15, 0, | ||
1406 | db_scale_line), | ||
1407 | ES1938_DOUBLE_TLV("Aux Capture Volume", 0, 0x6c, 0x6c, 4, 0, 15, 0, | ||
1408 | db_scale_line), | ||
1409 | ES1938_DOUBLE_TLV("PCM Playback Volume", 0, 0x7c, 0x7c, 4, 0, 15, 0, | ||
1410 | db_scale_audio2), | ||
1411 | ES1938_DOUBLE_TLV("PCM Playback Volume", 1, 0x14, 0x14, 4, 0, 15, 0, | ||
1412 | db_scale_audio1), | ||
1345 | ES1938_SINGLE("3D Control - Level", 0, 0x52, 0, 63, 0), | 1413 | ES1938_SINGLE("3D Control - Level", 0, 0x52, 0, 63, 0), |
1346 | { | 1414 | { |
1347 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 1415 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
diff --git a/sound/pci/es1968.c b/sound/pci/es1968.c index 3c5ab7c2e72d..f3c40385c87d 100644 --- a/sound/pci/es1968.c +++ b/sound/pci/es1968.c | |||
@@ -1905,7 +1905,7 @@ static void es1968_update_hw_volume(unsigned long private_data) | |||
1905 | /* Figure out which volume control button was pushed, | 1905 | /* Figure out which volume control button was pushed, |
1906 | based on differences from the default register | 1906 | based on differences from the default register |
1907 | values. */ | 1907 | values. */ |
1908 | x = inb(chip->io_port + 0x1c); | 1908 | x = inb(chip->io_port + 0x1c) & 0xee; |
1909 | /* Reset the volume control registers. */ | 1909 | /* Reset the volume control registers. */ |
1910 | outb(0x88, chip->io_port + 0x1c); | 1910 | outb(0x88, chip->io_port + 0x1c); |
1911 | outb(0x88, chip->io_port + 0x1d); | 1911 | outb(0x88, chip->io_port + 0x1d); |
@@ -1921,7 +1921,8 @@ static void es1968_update_hw_volume(unsigned long private_data) | |||
1921 | /* FIXME: we can't call snd_ac97_* functions since here is in tasklet. */ | 1921 | /* FIXME: we can't call snd_ac97_* functions since here is in tasklet. */ |
1922 | spin_lock_irqsave(&chip->ac97_lock, flags); | 1922 | spin_lock_irqsave(&chip->ac97_lock, flags); |
1923 | val = chip->ac97->regs[AC97_MASTER]; | 1923 | val = chip->ac97->regs[AC97_MASTER]; |
1924 | if (x & 1) { | 1924 | switch (x) { |
1925 | case 0x88: | ||
1925 | /* mute */ | 1926 | /* mute */ |
1926 | val ^= 0x8000; | 1927 | val ^= 0x8000; |
1927 | chip->ac97->regs[AC97_MASTER] = val; | 1928 | chip->ac97->regs[AC97_MASTER] = val; |
@@ -1929,26 +1930,31 @@ static void es1968_update_hw_volume(unsigned long private_data) | |||
1929 | outb(AC97_MASTER, chip->io_port + ESM_AC97_INDEX); | 1930 | outb(AC97_MASTER, chip->io_port + ESM_AC97_INDEX); |
1930 | snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_VALUE, | 1931 | snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_VALUE, |
1931 | &chip->master_switch->id); | 1932 | &chip->master_switch->id); |
1932 | } else { | 1933 | break; |
1933 | val &= 0x7fff; | 1934 | case 0xaa: |
1934 | if (((x>>1) & 7) > 4) { | 1935 | /* volume up */ |
1935 | /* volume up */ | 1936 | if ((val & 0x7f) > 0) |
1936 | if ((val & 0xff) > 0) | 1937 | val--; |
1937 | val--; | 1938 | if ((val & 0x7f00) > 0) |
1938 | if ((val & 0xff00) > 0) | 1939 | val -= 0x0100; |
1939 | val -= 0x0100; | 1940 | chip->ac97->regs[AC97_MASTER] = val; |
1940 | } else { | 1941 | outw(val, chip->io_port + ESM_AC97_DATA); |
1941 | /* volume down */ | 1942 | outb(AC97_MASTER, chip->io_port + ESM_AC97_INDEX); |
1942 | if ((val & 0xff) < 0x1f) | 1943 | snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_VALUE, |
1943 | val++; | 1944 | &chip->master_volume->id); |
1944 | if ((val & 0xff00) < 0x1f00) | 1945 | break; |
1945 | val += 0x0100; | 1946 | case 0x66: |
1946 | } | 1947 | /* volume down */ |
1948 | if ((val & 0x7f) < 0x1f) | ||
1949 | val++; | ||
1950 | if ((val & 0x7f00) < 0x1f00) | ||
1951 | val += 0x0100; | ||
1947 | chip->ac97->regs[AC97_MASTER] = val; | 1952 | chip->ac97->regs[AC97_MASTER] = val; |
1948 | outw(val, chip->io_port + ESM_AC97_DATA); | 1953 | outw(val, chip->io_port + ESM_AC97_DATA); |
1949 | outb(AC97_MASTER, chip->io_port + ESM_AC97_INDEX); | 1954 | outb(AC97_MASTER, chip->io_port + ESM_AC97_INDEX); |
1950 | snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_VALUE, | 1955 | snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_VALUE, |
1951 | &chip->master_volume->id); | 1956 | &chip->master_volume->id); |
1957 | break; | ||
1952 | } | 1958 | } |
1953 | spin_unlock_irqrestore(&chip->ac97_lock, flags); | 1959 | spin_unlock_irqrestore(&chip->ac97_lock, flags); |
1954 | } | 1960 | } |
diff --git a/sound/pci/fm801.c b/sound/pci/fm801.c index 13868c985126..bdfda1997d5b 100644 --- a/sound/pci/fm801.c +++ b/sound/pci/fm801.c | |||
@@ -2,6 +2,7 @@ | |||
2 | * The driver for the ForteMedia FM801 based soundcards | 2 | * The driver for the ForteMedia FM801 based soundcards |
3 | * Copyright (c) by Jaroslav Kysela <perex@suse.cz> | 3 | * Copyright (c) by Jaroslav Kysela <perex@suse.cz> |
4 | * | 4 | * |
5 | * Support FM only card by Andy Shevchenko <andy@smile.org.ua> | ||
5 | * | 6 | * |
6 | * This program is free software; you can redistribute it and/or modify | 7 | * This program is free software; you can redistribute it and/or modify |
7 | * it under the terms of the GNU General Public License as published by | 8 | * it under the terms of the GNU General Public License as published by |
@@ -28,6 +29,7 @@ | |||
28 | #include <linux/moduleparam.h> | 29 | #include <linux/moduleparam.h> |
29 | #include <sound/core.h> | 30 | #include <sound/core.h> |
30 | #include <sound/pcm.h> | 31 | #include <sound/pcm.h> |
32 | #include <sound/tlv.h> | ||
31 | #include <sound/ac97_codec.h> | 33 | #include <sound/ac97_codec.h> |
32 | #include <sound/mpu401.h> | 34 | #include <sound/mpu401.h> |
33 | #include <sound/opl3.h> | 35 | #include <sound/opl3.h> |
@@ -54,6 +56,7 @@ static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP; /* Enable this card * | |||
54 | * 1 = MediaForte 256-PCS | 56 | * 1 = MediaForte 256-PCS |
55 | * 2 = MediaForte 256-PCPR | 57 | * 2 = MediaForte 256-PCPR |
56 | * 3 = MediaForte 64-PCR | 58 | * 3 = MediaForte 64-PCR |
59 | * 16 = setup tuner only (this is additional bit), i.e. SF-64-PCR FM card | ||
57 | * High 16-bits are video (radio) device number + 1 | 60 | * High 16-bits are video (radio) device number + 1 |
58 | */ | 61 | */ |
59 | static int tea575x_tuner[SNDRV_CARDS]; | 62 | static int tea575x_tuner[SNDRV_CARDS]; |
@@ -158,6 +161,7 @@ struct fm801 { | |||
158 | unsigned int multichannel: 1, /* multichannel support */ | 161 | unsigned int multichannel: 1, /* multichannel support */ |
159 | secondary: 1; /* secondary codec */ | 162 | secondary: 1; /* secondary codec */ |
160 | unsigned char secondary_addr; /* address of the secondary codec */ | 163 | unsigned char secondary_addr; /* address of the secondary codec */ |
164 | unsigned int tea575x_tuner; /* tuner flags */ | ||
161 | 165 | ||
162 | unsigned short ply_ctrl; /* playback control */ | 166 | unsigned short ply_ctrl; /* playback control */ |
163 | unsigned short cap_ctrl; /* capture control */ | 167 | unsigned short cap_ctrl; /* capture control */ |
@@ -318,10 +322,8 @@ static unsigned int channels[] = { | |||
318 | 2, 4, 6 | 322 | 2, 4, 6 |
319 | }; | 323 | }; |
320 | 324 | ||
321 | #define CHANNELS sizeof(channels) / sizeof(channels[0]) | ||
322 | |||
323 | static struct snd_pcm_hw_constraint_list hw_constraints_channels = { | 325 | static struct snd_pcm_hw_constraint_list hw_constraints_channels = { |
324 | .count = CHANNELS, | 326 | .count = ARRAY_SIZE(channels), |
325 | .list = channels, | 327 | .list = channels, |
326 | .mask = 0, | 328 | .mask = 0, |
327 | }; | 329 | }; |
@@ -1052,6 +1054,13 @@ static int snd_fm801_put_single(struct snd_kcontrol *kcontrol, | |||
1052 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .info = snd_fm801_info_double, \ | 1054 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .info = snd_fm801_info_double, \ |
1053 | .get = snd_fm801_get_double, .put = snd_fm801_put_double, \ | 1055 | .get = snd_fm801_get_double, .put = snd_fm801_put_double, \ |
1054 | .private_value = reg | (shift_left << 8) | (shift_right << 12) | (mask << 16) | (invert << 24) } | 1056 | .private_value = reg | (shift_left << 8) | (shift_right << 12) | (mask << 16) | (invert << 24) } |
1057 | #define FM801_DOUBLE_TLV(xname, reg, shift_left, shift_right, mask, invert, xtlv) \ | ||
1058 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ | ||
1059 | .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ, \ | ||
1060 | .name = xname, .info = snd_fm801_info_double, \ | ||
1061 | .get = snd_fm801_get_double, .put = snd_fm801_put_double, \ | ||
1062 | .private_value = reg | (shift_left << 8) | (shift_right << 12) | (mask << 16) | (invert << 24), \ | ||
1063 | .tlv = { .p = (xtlv) } } | ||
1055 | 1064 | ||
1056 | static int snd_fm801_info_double(struct snd_kcontrol *kcontrol, | 1065 | static int snd_fm801_info_double(struct snd_kcontrol *kcontrol, |
1057 | struct snd_ctl_elem_info *uinfo) | 1066 | struct snd_ctl_elem_info *uinfo) |
@@ -1148,14 +1157,19 @@ static int snd_fm801_put_mux(struct snd_kcontrol *kcontrol, | |||
1148 | return snd_fm801_update_bits(chip, FM801_REC_SRC, 7, val); | 1157 | return snd_fm801_update_bits(chip, FM801_REC_SRC, 7, val); |
1149 | } | 1158 | } |
1150 | 1159 | ||
1160 | static DECLARE_TLV_DB_SCALE(db_scale_dsp, -3450, 150, 0); | ||
1161 | |||
1151 | #define FM801_CONTROLS ARRAY_SIZE(snd_fm801_controls) | 1162 | #define FM801_CONTROLS ARRAY_SIZE(snd_fm801_controls) |
1152 | 1163 | ||
1153 | static struct snd_kcontrol_new snd_fm801_controls[] __devinitdata = { | 1164 | static struct snd_kcontrol_new snd_fm801_controls[] __devinitdata = { |
1154 | FM801_DOUBLE("Wave Playback Volume", FM801_PCM_VOL, 0, 8, 31, 1), | 1165 | FM801_DOUBLE_TLV("Wave Playback Volume", FM801_PCM_VOL, 0, 8, 31, 1, |
1166 | db_scale_dsp), | ||
1155 | FM801_SINGLE("Wave Playback Switch", FM801_PCM_VOL, 15, 1, 1), | 1167 | FM801_SINGLE("Wave Playback Switch", FM801_PCM_VOL, 15, 1, 1), |
1156 | FM801_DOUBLE("I2S Playback Volume", FM801_I2S_VOL, 0, 8, 31, 1), | 1168 | FM801_DOUBLE_TLV("I2S Playback Volume", FM801_I2S_VOL, 0, 8, 31, 1, |
1169 | db_scale_dsp), | ||
1157 | FM801_SINGLE("I2S Playback Switch", FM801_I2S_VOL, 15, 1, 1), | 1170 | FM801_SINGLE("I2S Playback Switch", FM801_I2S_VOL, 15, 1, 1), |
1158 | FM801_DOUBLE("FM Playback Volume", FM801_FM_VOL, 0, 8, 31, 1), | 1171 | FM801_DOUBLE_TLV("FM Playback Volume", FM801_FM_VOL, 0, 8, 31, 1, |
1172 | db_scale_dsp), | ||
1159 | FM801_SINGLE("FM Playback Switch", FM801_FM_VOL, 15, 1, 1), | 1173 | FM801_SINGLE("FM Playback Switch", FM801_FM_VOL, 15, 1, 1), |
1160 | { | 1174 | { |
1161 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 1175 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
@@ -1253,6 +1267,9 @@ static int snd_fm801_chip_init(struct fm801 *chip, int resume) | |||
1253 | int id; | 1267 | int id; |
1254 | unsigned short cmdw; | 1268 | unsigned short cmdw; |
1255 | 1269 | ||
1270 | if (chip->tea575x_tuner & 0x0010) | ||
1271 | goto __ac97_ok; | ||
1272 | |||
1256 | /* codec cold reset + AC'97 warm reset */ | 1273 | /* codec cold reset + AC'97 warm reset */ |
1257 | outw((1<<5) | (1<<6), FM801_REG(chip, CODEC_CTRL)); | 1274 | outw((1<<5) | (1<<6), FM801_REG(chip, CODEC_CTRL)); |
1258 | inw(FM801_REG(chip, CODEC_CTRL)); /* flush posting data */ | 1275 | inw(FM801_REG(chip, CODEC_CTRL)); /* flush posting data */ |
@@ -1290,6 +1307,8 @@ static int snd_fm801_chip_init(struct fm801 *chip, int resume) | |||
1290 | wait_for_codec(chip, 0, AC97_VENDOR_ID1, msecs_to_jiffies(750)); | 1307 | wait_for_codec(chip, 0, AC97_VENDOR_ID1, msecs_to_jiffies(750)); |
1291 | } | 1308 | } |
1292 | 1309 | ||
1310 | __ac97_ok: | ||
1311 | |||
1293 | /* init volume */ | 1312 | /* init volume */ |
1294 | outw(0x0808, FM801_REG(chip, PCM_VOL)); | 1313 | outw(0x0808, FM801_REG(chip, PCM_VOL)); |
1295 | outw(0x9f1f, FM801_REG(chip, FM_VOL)); | 1314 | outw(0x9f1f, FM801_REG(chip, FM_VOL)); |
@@ -1298,9 +1317,12 @@ static int snd_fm801_chip_init(struct fm801 *chip, int resume) | |||
1298 | /* I2S control - I2S mode */ | 1317 | /* I2S control - I2S mode */ |
1299 | outw(0x0003, FM801_REG(chip, I2S_MODE)); | 1318 | outw(0x0003, FM801_REG(chip, I2S_MODE)); |
1300 | 1319 | ||
1301 | /* interrupt setup - unmask MPU, PLAYBACK & CAPTURE */ | 1320 | /* interrupt setup */ |
1302 | cmdw = inw(FM801_REG(chip, IRQ_MASK)); | 1321 | cmdw = inw(FM801_REG(chip, IRQ_MASK)); |
1303 | cmdw &= ~0x0083; | 1322 | if (chip->irq < 0) |
1323 | cmdw |= 0x00c3; /* mask everything, no PCM nor MPU */ | ||
1324 | else | ||
1325 | cmdw &= ~0x0083; /* unmask MPU, PLAYBACK & CAPTURE */ | ||
1304 | outw(cmdw, FM801_REG(chip, IRQ_MASK)); | 1326 | outw(cmdw, FM801_REG(chip, IRQ_MASK)); |
1305 | 1327 | ||
1306 | /* interrupt clear */ | 1328 | /* interrupt clear */ |
@@ -1365,20 +1387,23 @@ static int __devinit snd_fm801_create(struct snd_card *card, | |||
1365 | chip->card = card; | 1387 | chip->card = card; |
1366 | chip->pci = pci; | 1388 | chip->pci = pci; |
1367 | chip->irq = -1; | 1389 | chip->irq = -1; |
1390 | chip->tea575x_tuner = tea575x_tuner; | ||
1368 | if ((err = pci_request_regions(pci, "FM801")) < 0) { | 1391 | if ((err = pci_request_regions(pci, "FM801")) < 0) { |
1369 | kfree(chip); | 1392 | kfree(chip); |
1370 | pci_disable_device(pci); | 1393 | pci_disable_device(pci); |
1371 | return err; | 1394 | return err; |
1372 | } | 1395 | } |
1373 | chip->port = pci_resource_start(pci, 0); | 1396 | chip->port = pci_resource_start(pci, 0); |
1374 | if (request_irq(pci->irq, snd_fm801_interrupt, IRQF_DISABLED|IRQF_SHARED, | 1397 | if ((tea575x_tuner & 0x0010) == 0) { |
1375 | "FM801", chip)) { | 1398 | if (request_irq(pci->irq, snd_fm801_interrupt, IRQF_DISABLED|IRQF_SHARED, |
1376 | snd_printk(KERN_ERR "unable to grab IRQ %d\n", chip->irq); | 1399 | "FM801", chip)) { |
1377 | snd_fm801_free(chip); | 1400 | snd_printk(KERN_ERR "unable to grab IRQ %d\n", chip->irq); |
1378 | return -EBUSY; | 1401 | snd_fm801_free(chip); |
1402 | return -EBUSY; | ||
1403 | } | ||
1404 | chip->irq = pci->irq; | ||
1405 | pci_set_master(pci); | ||
1379 | } | 1406 | } |
1380 | chip->irq = pci->irq; | ||
1381 | pci_set_master(pci); | ||
1382 | 1407 | ||
1383 | pci_read_config_byte(pci, PCI_REVISION_ID, &rev); | 1408 | pci_read_config_byte(pci, PCI_REVISION_ID, &rev); |
1384 | if (rev >= 0xb1) /* FM801-AU */ | 1409 | if (rev >= 0xb1) /* FM801-AU */ |
@@ -1394,12 +1419,12 @@ static int __devinit snd_fm801_create(struct snd_card *card, | |||
1394 | snd_card_set_dev(card, &pci->dev); | 1419 | snd_card_set_dev(card, &pci->dev); |
1395 | 1420 | ||
1396 | #ifdef TEA575X_RADIO | 1421 | #ifdef TEA575X_RADIO |
1397 | if (tea575x_tuner > 0 && (tea575x_tuner & 0xffff) < 4) { | 1422 | if (tea575x_tuner > 0 && (tea575x_tuner & 0x000f) < 4) { |
1398 | chip->tea.dev_nr = tea575x_tuner >> 16; | 1423 | chip->tea.dev_nr = tea575x_tuner >> 16; |
1399 | chip->tea.card = card; | 1424 | chip->tea.card = card; |
1400 | chip->tea.freq_fixup = 10700; | 1425 | chip->tea.freq_fixup = 10700; |
1401 | chip->tea.private_data = chip; | 1426 | chip->tea.private_data = chip; |
1402 | chip->tea.ops = &snd_fm801_tea_ops[(tea575x_tuner & 0xffff) - 1]; | 1427 | chip->tea.ops = &snd_fm801_tea_ops[(tea575x_tuner & 0x000f) - 1]; |
1403 | snd_tea575x_init(&chip->tea); | 1428 | snd_tea575x_init(&chip->tea); |
1404 | } | 1429 | } |
1405 | #endif | 1430 | #endif |
@@ -1439,6 +1464,9 @@ static int __devinit snd_card_fm801_probe(struct pci_dev *pci, | |||
1439 | sprintf(card->longname, "%s at 0x%lx, irq %i", | 1464 | sprintf(card->longname, "%s at 0x%lx, irq %i", |
1440 | card->shortname, chip->port, chip->irq); | 1465 | card->shortname, chip->port, chip->irq); |
1441 | 1466 | ||
1467 | if (tea575x_tuner[dev] & 0x0010) | ||
1468 | goto __fm801_tuner_only; | ||
1469 | |||
1442 | if ((err = snd_fm801_pcm(chip, 0, NULL)) < 0) { | 1470 | if ((err = snd_fm801_pcm(chip, 0, NULL)) < 0) { |
1443 | snd_card_free(card); | 1471 | snd_card_free(card); |
1444 | return err; | 1472 | return err; |
@@ -1465,6 +1493,7 @@ static int __devinit snd_card_fm801_probe(struct pci_dev *pci, | |||
1465 | return err; | 1493 | return err; |
1466 | } | 1494 | } |
1467 | 1495 | ||
1496 | __fm801_tuner_only: | ||
1468 | if ((err = snd_card_register(card)) < 0) { | 1497 | if ((err = snd_card_register(card)) < 0) { |
1469 | snd_card_free(card); | 1498 | snd_card_free(card); |
1470 | return err; | 1499 | return err; |
diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index 23201f3eeb12..9c3d7ac08068 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c | |||
@@ -29,6 +29,7 @@ | |||
29 | #include <sound/core.h> | 29 | #include <sound/core.h> |
30 | #include "hda_codec.h" | 30 | #include "hda_codec.h" |
31 | #include <sound/asoundef.h> | 31 | #include <sound/asoundef.h> |
32 | #include <sound/tlv.h> | ||
32 | #include <sound/initval.h> | 33 | #include <sound/initval.h> |
33 | #include "hda_local.h" | 34 | #include "hda_local.h" |
34 | 35 | ||
@@ -50,8 +51,10 @@ struct hda_vendor_id { | |||
50 | /* codec vendor labels */ | 51 | /* codec vendor labels */ |
51 | static struct hda_vendor_id hda_vendor_ids[] = { | 52 | static struct hda_vendor_id hda_vendor_ids[] = { |
52 | { 0x10ec, "Realtek" }, | 53 | { 0x10ec, "Realtek" }, |
54 | { 0x1057, "Motorola" }, | ||
53 | { 0x11d4, "Analog Devices" }, | 55 | { 0x11d4, "Analog Devices" }, |
54 | { 0x13f6, "C-Media" }, | 56 | { 0x13f6, "C-Media" }, |
57 | { 0x14f1, "Conexant" }, | ||
55 | { 0x434d, "C-Media" }, | 58 | { 0x434d, "C-Media" }, |
56 | { 0x8384, "SigmaTel" }, | 59 | { 0x8384, "SigmaTel" }, |
57 | {} /* terminator */ | 60 | {} /* terminator */ |
@@ -841,6 +844,31 @@ int snd_hda_mixer_amp_volume_put(struct snd_kcontrol *kcontrol, struct snd_ctl_e | |||
841 | return change; | 844 | return change; |
842 | } | 845 | } |
843 | 846 | ||
847 | int snd_hda_mixer_amp_tlv(struct snd_kcontrol *kcontrol, int op_flag, | ||
848 | unsigned int size, unsigned int __user *_tlv) | ||
849 | { | ||
850 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | ||
851 | hda_nid_t nid = get_amp_nid(kcontrol); | ||
852 | int dir = get_amp_direction(kcontrol); | ||
853 | u32 caps, val1, val2; | ||
854 | |||
855 | if (size < 4 * sizeof(unsigned int)) | ||
856 | return -ENOMEM; | ||
857 | caps = query_amp_caps(codec, nid, dir); | ||
858 | val2 = (((caps & AC_AMPCAP_STEP_SIZE) >> AC_AMPCAP_STEP_SIZE_SHIFT) + 1) * 25; | ||
859 | val1 = -((caps & AC_AMPCAP_OFFSET) >> AC_AMPCAP_OFFSET_SHIFT); | ||
860 | val1 = ((int)val1) * ((int)val2); | ||
861 | if (put_user(SNDRV_CTL_TLVT_DB_SCALE, _tlv)) | ||
862 | return -EFAULT; | ||
863 | if (put_user(2 * sizeof(unsigned int), _tlv + 1)) | ||
864 | return -EFAULT; | ||
865 | if (put_user(val1, _tlv + 2)) | ||
866 | return -EFAULT; | ||
867 | if (put_user(val2, _tlv + 3)) | ||
868 | return -EFAULT; | ||
869 | return 0; | ||
870 | } | ||
871 | |||
844 | /* switch */ | 872 | /* switch */ |
845 | int snd_hda_mixer_amp_switch_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) | 873 | int snd_hda_mixer_amp_switch_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) |
846 | { | 874 | { |
@@ -1477,10 +1505,10 @@ int snd_hda_query_supported_pcm(struct hda_codec *codec, hda_nid_t nid, | |||
1477 | formats |= SNDRV_PCM_FMTBIT_S32_LE; | 1505 | formats |= SNDRV_PCM_FMTBIT_S32_LE; |
1478 | if (val & AC_SUPPCM_BITS_32) | 1506 | if (val & AC_SUPPCM_BITS_32) |
1479 | bps = 32; | 1507 | bps = 32; |
1480 | else if (val & AC_SUPPCM_BITS_20) | ||
1481 | bps = 20; | ||
1482 | else if (val & AC_SUPPCM_BITS_24) | 1508 | else if (val & AC_SUPPCM_BITS_24) |
1483 | bps = 24; | 1509 | bps = 24; |
1510 | else if (val & AC_SUPPCM_BITS_20) | ||
1511 | bps = 20; | ||
1484 | } | 1512 | } |
1485 | } | 1513 | } |
1486 | else if (streams == AC_SUPFMT_FLOAT32) { /* should be exclusive */ | 1514 | else if (streams == AC_SUPFMT_FLOAT32) { /* should be exclusive */ |
@@ -1916,7 +1944,7 @@ int snd_hda_multi_out_analog_prepare(struct hda_codec *codec, struct hda_multi_o | |||
1916 | 1944 | ||
1917 | /* front */ | 1945 | /* front */ |
1918 | snd_hda_codec_setup_stream(codec, nids[HDA_FRONT], stream_tag, 0, format); | 1946 | snd_hda_codec_setup_stream(codec, nids[HDA_FRONT], stream_tag, 0, format); |
1919 | if (mout->hp_nid) | 1947 | if (mout->hp_nid && mout->hp_nid != nids[HDA_FRONT]) |
1920 | /* headphone out will just decode front left/right (stereo) */ | 1948 | /* headphone out will just decode front left/right (stereo) */ |
1921 | snd_hda_codec_setup_stream(codec, mout->hp_nid, stream_tag, 0, format); | 1949 | snd_hda_codec_setup_stream(codec, mout->hp_nid, stream_tag, 0, format); |
1922 | /* extra outputs copied from front */ | 1950 | /* extra outputs copied from front */ |
@@ -1984,7 +2012,7 @@ static int is_in_nid_list(hda_nid_t nid, hda_nid_t *list) | |||
1984 | * in the order of front, rear, CLFE, side, ... | 2012 | * in the order of front, rear, CLFE, side, ... |
1985 | * | 2013 | * |
1986 | * If more extra outputs (speaker and headphone) are found, the pins are | 2014 | * If more extra outputs (speaker and headphone) are found, the pins are |
1987 | * assisnged to hp_pin and speaker_pins[], respectively. If no line-out jack | 2015 | * assisnged to hp_pins[] and speaker_pins[], respectively. If no line-out jack |
1988 | * is detected, one of speaker of HP pins is assigned as the primary | 2016 | * is detected, one of speaker of HP pins is assigned as the primary |
1989 | * output, i.e. to line_out_pins[0]. So, line_outs is always positive | 2017 | * output, i.e. to line_out_pins[0]. So, line_outs is always positive |
1990 | * if any analog output exists. | 2018 | * if any analog output exists. |
@@ -2046,14 +2074,26 @@ int snd_hda_parse_pin_def_config(struct hda_codec *codec, struct auto_pin_cfg *c | |||
2046 | cfg->speaker_outs++; | 2074 | cfg->speaker_outs++; |
2047 | break; | 2075 | break; |
2048 | case AC_JACK_HP_OUT: | 2076 | case AC_JACK_HP_OUT: |
2049 | cfg->hp_pin = nid; | 2077 | if (cfg->hp_outs >= ARRAY_SIZE(cfg->hp_pins)) |
2078 | continue; | ||
2079 | cfg->hp_pins[cfg->hp_outs] = nid; | ||
2080 | cfg->hp_outs++; | ||
2050 | break; | 2081 | break; |
2051 | case AC_JACK_MIC_IN: | 2082 | case AC_JACK_MIC_IN: { |
2052 | if (loc == AC_JACK_LOC_FRONT) | 2083 | int preferred, alt; |
2053 | cfg->input_pins[AUTO_PIN_FRONT_MIC] = nid; | 2084 | if (loc == AC_JACK_LOC_FRONT) { |
2054 | else | 2085 | preferred = AUTO_PIN_FRONT_MIC; |
2055 | cfg->input_pins[AUTO_PIN_MIC] = nid; | 2086 | alt = AUTO_PIN_MIC; |
2087 | } else { | ||
2088 | preferred = AUTO_PIN_MIC; | ||
2089 | alt = AUTO_PIN_FRONT_MIC; | ||
2090 | } | ||
2091 | if (!cfg->input_pins[preferred]) | ||
2092 | cfg->input_pins[preferred] = nid; | ||
2093 | else if (!cfg->input_pins[alt]) | ||
2094 | cfg->input_pins[alt] = nid; | ||
2056 | break; | 2095 | break; |
2096 | } | ||
2057 | case AC_JACK_LINE_IN: | 2097 | case AC_JACK_LINE_IN: |
2058 | if (loc == AC_JACK_LOC_FRONT) | 2098 | if (loc == AC_JACK_LOC_FRONT) |
2059 | cfg->input_pins[AUTO_PIN_FRONT_LINE] = nid; | 2099 | cfg->input_pins[AUTO_PIN_FRONT_LINE] = nid; |
@@ -2119,8 +2159,10 @@ int snd_hda_parse_pin_def_config(struct hda_codec *codec, struct auto_pin_cfg *c | |||
2119 | cfg->speaker_outs, cfg->speaker_pins[0], | 2159 | cfg->speaker_outs, cfg->speaker_pins[0], |
2120 | cfg->speaker_pins[1], cfg->speaker_pins[2], | 2160 | cfg->speaker_pins[1], cfg->speaker_pins[2], |
2121 | cfg->speaker_pins[3], cfg->speaker_pins[4]); | 2161 | cfg->speaker_pins[3], cfg->speaker_pins[4]); |
2122 | snd_printd(" hp=0x%x, dig_out=0x%x, din_in=0x%x\n", | 2162 | snd_printd(" hp_outs=%d (0x%x/0x%x/0x%x/0x%x/0x%x)\n", |
2123 | cfg->hp_pin, cfg->dig_out_pin, cfg->dig_in_pin); | 2163 | cfg->hp_outs, cfg->hp_pins[0], |
2164 | cfg->hp_pins[1], cfg->hp_pins[2], | ||
2165 | cfg->hp_pins[3], cfg->hp_pins[4]); | ||
2124 | snd_printd(" inputs: mic=0x%x, fmic=0x%x, line=0x%x, fline=0x%x," | 2166 | snd_printd(" inputs: mic=0x%x, fmic=0x%x, line=0x%x, fline=0x%x," |
2125 | " cd=0x%x, aux=0x%x\n", | 2167 | " cd=0x%x, aux=0x%x\n", |
2126 | cfg->input_pins[AUTO_PIN_MIC], | 2168 | cfg->input_pins[AUTO_PIN_MIC], |
@@ -2141,10 +2183,12 @@ int snd_hda_parse_pin_def_config(struct hda_codec *codec, struct auto_pin_cfg *c | |||
2141 | sizeof(cfg->speaker_pins)); | 2183 | sizeof(cfg->speaker_pins)); |
2142 | cfg->speaker_outs = 0; | 2184 | cfg->speaker_outs = 0; |
2143 | memset(cfg->speaker_pins, 0, sizeof(cfg->speaker_pins)); | 2185 | memset(cfg->speaker_pins, 0, sizeof(cfg->speaker_pins)); |
2144 | } else if (cfg->hp_pin) { | 2186 | } else if (cfg->hp_outs) { |
2145 | cfg->line_outs = 1; | 2187 | cfg->line_outs = cfg->hp_outs; |
2146 | cfg->line_out_pins[0] = cfg->hp_pin; | 2188 | memcpy(cfg->line_out_pins, cfg->hp_pins, |
2147 | cfg->hp_pin = 0; | 2189 | sizeof(cfg->hp_pins)); |
2190 | cfg->hp_outs = 0; | ||
2191 | memset(cfg->hp_pins, 0, sizeof(cfg->hp_pins)); | ||
2148 | } | 2192 | } |
2149 | } | 2193 | } |
2150 | 2194 | ||
diff --git a/sound/pci/hda/hda_codec.h b/sound/pci/hda/hda_codec.h index 40520e9d5a4b..c12bc4e8840f 100644 --- a/sound/pci/hda/hda_codec.h +++ b/sound/pci/hda/hda_codec.h | |||
@@ -479,7 +479,7 @@ struct hda_codec_ops { | |||
479 | struct hda_amp_info { | 479 | struct hda_amp_info { |
480 | u32 key; /* hash key */ | 480 | u32 key; /* hash key */ |
481 | u32 amp_caps; /* amp capabilities */ | 481 | u32 amp_caps; /* amp capabilities */ |
482 | u16 vol[2]; /* current volume & mute*/ | 482 | u16 vol[2]; /* current volume & mute */ |
483 | u16 status; /* update flag */ | 483 | u16 status; /* update flag */ |
484 | u16 next; /* next link */ | 484 | u16 next; /* next link */ |
485 | }; | 485 | }; |
diff --git a/sound/pci/hda/hda_generic.c b/sound/pci/hda/hda_generic.c index 85ad164ada59..97e9af130b71 100644 --- a/sound/pci/hda/hda_generic.c +++ b/sound/pci/hda/hda_generic.c | |||
@@ -46,11 +46,18 @@ struct hda_gnode { | |||
46 | }; | 46 | }; |
47 | 47 | ||
48 | /* patch-specific record */ | 48 | /* patch-specific record */ |
49 | |||
50 | #define MAX_PCM_VOLS 2 | ||
51 | struct pcm_vol { | ||
52 | struct hda_gnode *node; /* Node for PCM volume */ | ||
53 | unsigned int index; /* connection of PCM volume */ | ||
54 | }; | ||
55 | |||
49 | struct hda_gspec { | 56 | struct hda_gspec { |
50 | struct hda_gnode *dac_node[2]; /* DAC node */ | 57 | struct hda_gnode *dac_node[2]; /* DAC node */ |
51 | struct hda_gnode *out_pin_node[2]; /* Output pin (Line-Out) node */ | 58 | struct hda_gnode *out_pin_node[2]; /* Output pin (Line-Out) node */ |
52 | struct hda_gnode *pcm_vol_node[2]; /* Node for PCM volume */ | 59 | struct pcm_vol pcm_vol[MAX_PCM_VOLS]; /* PCM volumes */ |
53 | unsigned int pcm_vol_index[2]; /* connection of PCM volume */ | 60 | unsigned int pcm_vol_nodes; /* number of PCM volumes */ |
54 | 61 | ||
55 | struct hda_gnode *adc_node; /* ADC node */ | 62 | struct hda_gnode *adc_node; /* ADC node */ |
56 | struct hda_gnode *cap_vol_node; /* Node for capture volume */ | 63 | struct hda_gnode *cap_vol_node; /* Node for capture volume */ |
@@ -285,9 +292,11 @@ static int parse_output_path(struct hda_codec *codec, struct hda_gspec *spec, | |||
285 | return node == spec->dac_node[dac_idx]; | 292 | return node == spec->dac_node[dac_idx]; |
286 | } | 293 | } |
287 | spec->dac_node[dac_idx] = node; | 294 | spec->dac_node[dac_idx] = node; |
288 | if (node->wid_caps & AC_WCAP_OUT_AMP) { | 295 | if ((node->wid_caps & AC_WCAP_OUT_AMP) && |
289 | spec->pcm_vol_node[dac_idx] = node; | 296 | spec->pcm_vol_nodes < MAX_PCM_VOLS) { |
290 | spec->pcm_vol_index[dac_idx] = 0; | 297 | spec->pcm_vol[spec->pcm_vol_nodes].node = node; |
298 | spec->pcm_vol[spec->pcm_vol_nodes].index = 0; | ||
299 | spec->pcm_vol_nodes++; | ||
291 | } | 300 | } |
292 | return 1; /* found */ | 301 | return 1; /* found */ |
293 | } | 302 | } |
@@ -307,13 +316,16 @@ static int parse_output_path(struct hda_codec *codec, struct hda_gspec *spec, | |||
307 | select_input_connection(codec, node, i); | 316 | select_input_connection(codec, node, i); |
308 | unmute_input(codec, node, i); | 317 | unmute_input(codec, node, i); |
309 | unmute_output(codec, node); | 318 | unmute_output(codec, node); |
310 | if (! spec->pcm_vol_node[dac_idx]) { | 319 | if (spec->dac_node[dac_idx] && |
311 | if (node->wid_caps & AC_WCAP_IN_AMP) { | 320 | spec->pcm_vol_nodes < MAX_PCM_VOLS && |
312 | spec->pcm_vol_node[dac_idx] = node; | 321 | !(spec->dac_node[dac_idx]->wid_caps & |
313 | spec->pcm_vol_index[dac_idx] = i; | 322 | AC_WCAP_OUT_AMP)) { |
314 | } else if (node->wid_caps & AC_WCAP_OUT_AMP) { | 323 | if ((node->wid_caps & AC_WCAP_IN_AMP) || |
315 | spec->pcm_vol_node[dac_idx] = node; | 324 | (node->wid_caps & AC_WCAP_OUT_AMP)) { |
316 | spec->pcm_vol_index[dac_idx] = 0; | 325 | int n = spec->pcm_vol_nodes; |
326 | spec->pcm_vol[n].node = node; | ||
327 | spec->pcm_vol[n].index = i; | ||
328 | spec->pcm_vol_nodes++; | ||
317 | } | 329 | } |
318 | } | 330 | } |
319 | return 1; | 331 | return 1; |
@@ -370,7 +382,9 @@ static struct hda_gnode *parse_output_jack(struct hda_codec *codec, | |||
370 | /* set PIN-Out enable */ | 382 | /* set PIN-Out enable */ |
371 | snd_hda_codec_write(codec, node->nid, 0, | 383 | snd_hda_codec_write(codec, node->nid, 0, |
372 | AC_VERB_SET_PIN_WIDGET_CONTROL, | 384 | AC_VERB_SET_PIN_WIDGET_CONTROL, |
373 | AC_PINCTL_OUT_EN | AC_PINCTL_HP_EN); | 385 | AC_PINCTL_OUT_EN | |
386 | ((node->pin_caps & AC_PINCAP_HP_DRV) ? | ||
387 | AC_PINCTL_HP_EN : 0)); | ||
374 | return node; | 388 | return node; |
375 | } | 389 | } |
376 | } | 390 | } |
@@ -461,14 +475,19 @@ static const char *get_input_type(struct hda_gnode *node, unsigned int *pinctl) | |||
461 | return "Front Line"; | 475 | return "Front Line"; |
462 | return "Line"; | 476 | return "Line"; |
463 | case AC_JACK_CD: | 477 | case AC_JACK_CD: |
478 | #if 0 | ||
464 | if (pinctl) | 479 | if (pinctl) |
465 | *pinctl |= AC_PINCTL_VREF_GRD; | 480 | *pinctl |= AC_PINCTL_VREF_GRD; |
481 | #endif | ||
466 | return "CD"; | 482 | return "CD"; |
467 | case AC_JACK_AUX: | 483 | case AC_JACK_AUX: |
468 | if ((location & 0x0f) == AC_JACK_LOC_FRONT) | 484 | if ((location & 0x0f) == AC_JACK_LOC_FRONT) |
469 | return "Front Aux"; | 485 | return "Front Aux"; |
470 | return "Aux"; | 486 | return "Aux"; |
471 | case AC_JACK_MIC_IN: | 487 | case AC_JACK_MIC_IN: |
488 | if (node->pin_caps & | ||
489 | (AC_PINCAP_VREF_80 << AC_PINCAP_VREF_SHIFT)) | ||
490 | *pinctl |= AC_PINCTL_VREF_80; | ||
472 | if ((location & 0x0f) == AC_JACK_LOC_FRONT) | 491 | if ((location & 0x0f) == AC_JACK_LOC_FRONT) |
473 | return "Front Mic"; | 492 | return "Front Mic"; |
474 | return "Mic"; | 493 | return "Mic"; |
@@ -556,6 +575,29 @@ static int parse_adc_sub_nodes(struct hda_codec *codec, struct hda_gspec *spec, | |||
556 | return 1; /* found */ | 575 | return 1; /* found */ |
557 | } | 576 | } |
558 | 577 | ||
578 | /* add a capture source element */ | ||
579 | static void add_cap_src(struct hda_gspec *spec, int idx) | ||
580 | { | ||
581 | struct hda_input_mux_item *csrc; | ||
582 | char *buf; | ||
583 | int num, ocap; | ||
584 | |||
585 | num = spec->input_mux.num_items; | ||
586 | csrc = &spec->input_mux.items[num]; | ||
587 | buf = spec->cap_labels[num]; | ||
588 | for (ocap = 0; ocap < num; ocap++) { | ||
589 | if (! strcmp(buf, spec->cap_labels[ocap])) { | ||
590 | /* same label already exists, | ||
591 | * put the index number to be unique | ||
592 | */ | ||
593 | sprintf(buf, "%s %d", spec->cap_labels[ocap], num); | ||
594 | break; | ||
595 | } | ||
596 | } | ||
597 | csrc->index = idx; | ||
598 | spec->input_mux.num_items++; | ||
599 | } | ||
600 | |||
559 | /* | 601 | /* |
560 | * parse input | 602 | * parse input |
561 | */ | 603 | */ |
@@ -576,28 +618,26 @@ static int parse_input_path(struct hda_codec *codec, struct hda_gnode *adc_node) | |||
576 | * if it reaches to a proper input PIN, add the path as the | 618 | * if it reaches to a proper input PIN, add the path as the |
577 | * input path. | 619 | * input path. |
578 | */ | 620 | */ |
621 | /* first, check the direct connections to PIN widgets */ | ||
579 | for (i = 0; i < adc_node->nconns; i++) { | 622 | for (i = 0; i < adc_node->nconns; i++) { |
580 | node = hda_get_node(spec, adc_node->conn_list[i]); | 623 | node = hda_get_node(spec, adc_node->conn_list[i]); |
581 | if (! node) | 624 | if (node && node->type == AC_WID_PIN) { |
582 | continue; | 625 | err = parse_adc_sub_nodes(codec, spec, node); |
583 | err = parse_adc_sub_nodes(codec, spec, node); | 626 | if (err < 0) |
584 | if (err < 0) | 627 | return err; |
585 | return err; | 628 | else if (err > 0) |
586 | else if (err > 0) { | 629 | add_cap_src(spec, i); |
587 | struct hda_input_mux_item *csrc = &spec->input_mux.items[spec->input_mux.num_items]; | 630 | } |
588 | char *buf = spec->cap_labels[spec->input_mux.num_items]; | 631 | } |
589 | int ocap; | 632 | /* ... then check the rests, more complicated connections */ |
590 | for (ocap = 0; ocap < spec->input_mux.num_items; ocap++) { | 633 | for (i = 0; i < adc_node->nconns; i++) { |
591 | if (! strcmp(buf, spec->cap_labels[ocap])) { | 634 | node = hda_get_node(spec, adc_node->conn_list[i]); |
592 | /* same label already exists, | 635 | if (node && node->type != AC_WID_PIN) { |
593 | * put the index number to be unique | 636 | err = parse_adc_sub_nodes(codec, spec, node); |
594 | */ | 637 | if (err < 0) |
595 | sprintf(buf, "%s %d", spec->cap_labels[ocap], | 638 | return err; |
596 | spec->input_mux.num_items); | 639 | else if (err > 0) |
597 | } | 640 | add_cap_src(spec, i); |
598 | } | ||
599 | csrc->index = i; | ||
600 | spec->input_mux.num_items++; | ||
601 | } | 641 | } |
602 | } | 642 | } |
603 | 643 | ||
@@ -647,9 +687,6 @@ static int parse_input(struct hda_codec *codec) | |||
647 | /* | 687 | /* |
648 | * create mixer controls if possible | 688 | * create mixer controls if possible |
649 | */ | 689 | */ |
650 | #define DIR_OUT 0x1 | ||
651 | #define DIR_IN 0x2 | ||
652 | |||
653 | static int create_mixer(struct hda_codec *codec, struct hda_gnode *node, | 690 | static int create_mixer(struct hda_codec *codec, struct hda_gnode *node, |
654 | unsigned int index, const char *type, const char *dir_sfx) | 691 | unsigned int index, const char *type, const char *dir_sfx) |
655 | { | 692 | { |
@@ -722,49 +759,97 @@ static int check_existing_control(struct hda_codec *codec, const char *type, con | |||
722 | /* | 759 | /* |
723 | * build output mixer controls | 760 | * build output mixer controls |
724 | */ | 761 | */ |
725 | static int build_output_controls(struct hda_codec *codec) | 762 | static int create_output_mixers(struct hda_codec *codec, const char **names) |
726 | { | 763 | { |
727 | struct hda_gspec *spec = codec->spec; | 764 | struct hda_gspec *spec = codec->spec; |
728 | static const char *types[2] = { "Master", "Headphone" }; | ||
729 | int i, err; | 765 | int i, err; |
730 | 766 | ||
731 | for (i = 0; i < 2 && spec->pcm_vol_node[i]; i++) { | 767 | for (i = 0; i < spec->pcm_vol_nodes; i++) { |
732 | err = create_mixer(codec, spec->pcm_vol_node[i], | 768 | err = create_mixer(codec, spec->pcm_vol[i].node, |
733 | spec->pcm_vol_index[i], | 769 | spec->pcm_vol[i].index, |
734 | types[i], "Playback"); | 770 | names[i], "Playback"); |
735 | if (err < 0) | 771 | if (err < 0) |
736 | return err; | 772 | return err; |
737 | } | 773 | } |
738 | return 0; | 774 | return 0; |
739 | } | 775 | } |
740 | 776 | ||
777 | static int build_output_controls(struct hda_codec *codec) | ||
778 | { | ||
779 | struct hda_gspec *spec = codec->spec; | ||
780 | static const char *types_speaker[] = { "Speaker", "Headphone" }; | ||
781 | static const char *types_line[] = { "Front", "Headphone" }; | ||
782 | |||
783 | switch (spec->pcm_vol_nodes) { | ||
784 | case 1: | ||
785 | return create_mixer(codec, spec->pcm_vol[0].node, | ||
786 | spec->pcm_vol[0].index, | ||
787 | "Master", "Playback"); | ||
788 | case 2: | ||
789 | if (defcfg_type(spec->out_pin_node[0]) == AC_JACK_SPEAKER) | ||
790 | return create_output_mixers(codec, types_speaker); | ||
791 | else | ||
792 | return create_output_mixers(codec, types_line); | ||
793 | } | ||
794 | return 0; | ||
795 | } | ||
796 | |||
741 | /* create capture volume/switch */ | 797 | /* create capture volume/switch */ |
742 | static int build_input_controls(struct hda_codec *codec) | 798 | static int build_input_controls(struct hda_codec *codec) |
743 | { | 799 | { |
744 | struct hda_gspec *spec = codec->spec; | 800 | struct hda_gspec *spec = codec->spec; |
745 | struct hda_gnode *adc_node = spec->adc_node; | 801 | struct hda_gnode *adc_node = spec->adc_node; |
746 | int err; | 802 | int i, err; |
747 | 803 | static struct snd_kcontrol_new cap_sel = { | |
748 | if (! adc_node) | 804 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
805 | .name = "Capture Source", | ||
806 | .info = capture_source_info, | ||
807 | .get = capture_source_get, | ||
808 | .put = capture_source_put, | ||
809 | }; | ||
810 | |||
811 | if (! adc_node || ! spec->input_mux.num_items) | ||
749 | return 0; /* not found */ | 812 | return 0; /* not found */ |
750 | 813 | ||
814 | spec->cur_cap_src = 0; | ||
815 | select_input_connection(codec, adc_node, | ||
816 | spec->input_mux.items[0].index); | ||
817 | |||
751 | /* create capture volume and switch controls if the ADC has an amp */ | 818 | /* create capture volume and switch controls if the ADC has an amp */ |
752 | err = create_mixer(codec, adc_node, 0, NULL, "Capture"); | 819 | /* do we have only a single item? */ |
820 | if (spec->input_mux.num_items == 1) { | ||
821 | err = create_mixer(codec, adc_node, | ||
822 | spec->input_mux.items[0].index, | ||
823 | NULL, "Capture"); | ||
824 | if (err < 0) | ||
825 | return err; | ||
826 | return 0; | ||
827 | } | ||
753 | 828 | ||
754 | /* create input MUX if multiple sources are available */ | 829 | /* create input MUX if multiple sources are available */ |
755 | if (spec->input_mux.num_items > 1) { | 830 | if ((err = snd_ctl_add(codec->bus->card, |
756 | static struct snd_kcontrol_new cap_sel = { | 831 | snd_ctl_new1(&cap_sel, codec))) < 0) |
757 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 832 | return err; |
758 | .name = "Capture Source", | 833 | |
759 | .info = capture_source_info, | 834 | /* no volume control? */ |
760 | .get = capture_source_get, | 835 | if (! (adc_node->wid_caps & AC_WCAP_IN_AMP) || |
761 | .put = capture_source_put, | 836 | ! (adc_node->amp_in_caps & AC_AMPCAP_NUM_STEPS)) |
762 | }; | 837 | return 0; |
763 | if ((err = snd_ctl_add(codec->bus->card, snd_ctl_new1(&cap_sel, codec))) < 0) | 838 | |
839 | for (i = 0; i < spec->input_mux.num_items; i++) { | ||
840 | struct snd_kcontrol_new knew; | ||
841 | char name[32]; | ||
842 | sprintf(name, "%s Capture Volume", | ||
843 | spec->input_mux.items[i].label); | ||
844 | knew = (struct snd_kcontrol_new) | ||
845 | HDA_CODEC_VOLUME(name, adc_node->nid, | ||
846 | spec->input_mux.items[i].index, | ||
847 | HDA_INPUT); | ||
848 | if ((err = snd_ctl_add(codec->bus->card, | ||
849 | snd_ctl_new1(&knew, codec))) < 0) | ||
764 | return err; | 850 | return err; |
765 | spec->cur_cap_src = 0; | ||
766 | select_input_connection(codec, adc_node, spec->input_mux.items[0].index); | ||
767 | } | 851 | } |
852 | |||
768 | return 0; | 853 | return 0; |
769 | } | 854 | } |
770 | 855 | ||
diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index 79d63c99f092..e9d4cb4d07e1 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c | |||
@@ -55,6 +55,7 @@ static char *model; | |||
55 | static int position_fix; | 55 | static int position_fix; |
56 | static int probe_mask = -1; | 56 | static int probe_mask = -1; |
57 | static int single_cmd; | 57 | static int single_cmd; |
58 | static int disable_msi; | ||
58 | 59 | ||
59 | module_param(index, int, 0444); | 60 | module_param(index, int, 0444); |
60 | MODULE_PARM_DESC(index, "Index value for Intel HD audio interface."); | 61 | MODULE_PARM_DESC(index, "Index value for Intel HD audio interface."); |
@@ -68,6 +69,8 @@ module_param(probe_mask, int, 0444); | |||
68 | MODULE_PARM_DESC(probe_mask, "Bitmask to probe codecs (default = -1)."); | 69 | MODULE_PARM_DESC(probe_mask, "Bitmask to probe codecs (default = -1)."); |
69 | module_param(single_cmd, bool, 0444); | 70 | module_param(single_cmd, bool, 0444); |
70 | MODULE_PARM_DESC(single_cmd, "Use single command to communicate with codecs (for debugging only)."); | 71 | MODULE_PARM_DESC(single_cmd, "Use single command to communicate with codecs (for debugging only)."); |
72 | module_param(disable_msi, int, 0); | ||
73 | MODULE_PARM_DESC(disable_msi, "Disable Message Signaled Interrupt (MSI)"); | ||
71 | 74 | ||
72 | 75 | ||
73 | /* just for backward compatibility */ | 76 | /* just for backward compatibility */ |
@@ -252,7 +255,7 @@ enum { | |||
252 | struct azx_dev { | 255 | struct azx_dev { |
253 | u32 *bdl; /* virtual address of the BDL */ | 256 | u32 *bdl; /* virtual address of the BDL */ |
254 | dma_addr_t bdl_addr; /* physical address of the BDL */ | 257 | dma_addr_t bdl_addr; /* physical address of the BDL */ |
255 | volatile u32 *posbuf; /* position buffer pointer */ | 258 | u32 *posbuf; /* position buffer pointer */ |
256 | 259 | ||
257 | unsigned int bufsize; /* size of the play buffer in bytes */ | 260 | unsigned int bufsize; /* size of the play buffer in bytes */ |
258 | unsigned int fragsize; /* size of each period in bytes */ | 261 | unsigned int fragsize; /* size of each period in bytes */ |
@@ -271,8 +274,8 @@ struct azx_dev { | |||
271 | /* for sanity check of position buffer */ | 274 | /* for sanity check of position buffer */ |
272 | unsigned int period_intr; | 275 | unsigned int period_intr; |
273 | 276 | ||
274 | unsigned int opened: 1; | 277 | unsigned int opened :1; |
275 | unsigned int running: 1; | 278 | unsigned int running :1; |
276 | }; | 279 | }; |
277 | 280 | ||
278 | /* CORB/RIRB */ | 281 | /* CORB/RIRB */ |
@@ -330,8 +333,9 @@ struct azx { | |||
330 | 333 | ||
331 | /* flags */ | 334 | /* flags */ |
332 | int position_fix; | 335 | int position_fix; |
333 | unsigned int initialized: 1; | 336 | unsigned int initialized :1; |
334 | unsigned int single_cmd: 1; | 337 | unsigned int single_cmd :1; |
338 | unsigned int polling_mode :1; | ||
335 | }; | 339 | }; |
336 | 340 | ||
337 | /* driver types */ | 341 | /* driver types */ |
@@ -516,23 +520,36 @@ static void azx_update_rirb(struct azx *chip) | |||
516 | static unsigned int azx_rirb_get_response(struct hda_codec *codec) | 520 | static unsigned int azx_rirb_get_response(struct hda_codec *codec) |
517 | { | 521 | { |
518 | struct azx *chip = codec->bus->private_data; | 522 | struct azx *chip = codec->bus->private_data; |
519 | int timeout = 50; | 523 | unsigned long timeout; |
520 | 524 | ||
521 | while (chip->rirb.cmds) { | 525 | again: |
522 | if (! --timeout) { | 526 | timeout = jiffies + msecs_to_jiffies(1000); |
523 | snd_printk(KERN_ERR | 527 | do { |
524 | "hda_intel: azx_get_response timeout, " | 528 | if (chip->polling_mode) { |
525 | "switching to single_cmd mode...\n"); | 529 | spin_lock_irq(&chip->reg_lock); |
526 | chip->rirb.rp = azx_readb(chip, RIRBWP); | 530 | azx_update_rirb(chip); |
527 | chip->rirb.cmds = 0; | 531 | spin_unlock_irq(&chip->reg_lock); |
528 | /* switch to single_cmd mode */ | ||
529 | chip->single_cmd = 1; | ||
530 | azx_free_cmd_io(chip); | ||
531 | return -1; | ||
532 | } | 532 | } |
533 | msleep(1); | 533 | if (! chip->rirb.cmds) |
534 | return chip->rirb.res; /* the last value */ | ||
535 | schedule_timeout_interruptible(1); | ||
536 | } while (time_after_eq(timeout, jiffies)); | ||
537 | |||
538 | if (!chip->polling_mode) { | ||
539 | snd_printk(KERN_WARNING "hda_intel: azx_get_response timeout, " | ||
540 | "switching to polling mode...\n"); | ||
541 | chip->polling_mode = 1; | ||
542 | goto again; | ||
534 | } | 543 | } |
535 | return chip->rirb.res; /* the last value */ | 544 | |
545 | snd_printk(KERN_ERR "hda_intel: azx_get_response timeout, " | ||
546 | "switching to single_cmd mode...\n"); | ||
547 | chip->rirb.rp = azx_readb(chip, RIRBWP); | ||
548 | chip->rirb.cmds = 0; | ||
549 | /* switch to single_cmd mode */ | ||
550 | chip->single_cmd = 1; | ||
551 | azx_free_cmd_io(chip); | ||
552 | return -1; | ||
536 | } | 553 | } |
537 | 554 | ||
538 | /* | 555 | /* |
@@ -642,14 +659,14 @@ static int azx_reset(struct azx *chip) | |||
642 | azx_writeb(chip, GCTL, azx_readb(chip, GCTL) | ICH6_GCTL_RESET); | 659 | azx_writeb(chip, GCTL, azx_readb(chip, GCTL) | ICH6_GCTL_RESET); |
643 | 660 | ||
644 | count = 50; | 661 | count = 50; |
645 | while (! azx_readb(chip, GCTL) && --count) | 662 | while (!azx_readb(chip, GCTL) && --count) |
646 | msleep(1); | 663 | msleep(1); |
647 | 664 | ||
648 | /* Brent Chartrand said to wait >= 540us for codecs to intialize */ | 665 | /* Brent Chartrand said to wait >= 540us for codecs to initialize */ |
649 | msleep(1); | 666 | msleep(1); |
650 | 667 | ||
651 | /* check to see if controller is ready */ | 668 | /* check to see if controller is ready */ |
652 | if (! azx_readb(chip, GCTL)) { | 669 | if (!azx_readb(chip, GCTL)) { |
653 | snd_printd("azx_reset: controller not ready!\n"); | 670 | snd_printd("azx_reset: controller not ready!\n"); |
654 | return -EBUSY; | 671 | return -EBUSY; |
655 | } | 672 | } |
@@ -658,7 +675,7 @@ static int azx_reset(struct azx *chip) | |||
658 | azx_writel(chip, GCTL, azx_readl(chip, GCTL) | ICH6_GCTL_UREN); | 675 | azx_writel(chip, GCTL, azx_readl(chip, GCTL) | ICH6_GCTL_UREN); |
659 | 676 | ||
660 | /* detect codecs */ | 677 | /* detect codecs */ |
661 | if (! chip->codec_mask) { | 678 | if (!chip->codec_mask) { |
662 | chip->codec_mask = azx_readw(chip, STATESTS); | 679 | chip->codec_mask = azx_readw(chip, STATESTS); |
663 | snd_printdd("codec_mask = 0x%x\n", chip->codec_mask); | 680 | snd_printdd("codec_mask = 0x%x\n", chip->codec_mask); |
664 | } | 681 | } |
@@ -766,7 +783,7 @@ static void azx_init_chip(struct azx *chip) | |||
766 | azx_int_enable(chip); | 783 | azx_int_enable(chip); |
767 | 784 | ||
768 | /* initialize the codec command I/O */ | 785 | /* initialize the codec command I/O */ |
769 | if (! chip->single_cmd) | 786 | if (!chip->single_cmd) |
770 | azx_init_cmd_io(chip); | 787 | azx_init_cmd_io(chip); |
771 | 788 | ||
772 | /* program the position buffer */ | 789 | /* program the position buffer */ |
@@ -794,7 +811,7 @@ static void azx_init_chip(struct azx *chip) | |||
794 | /* | 811 | /* |
795 | * interrupt handler | 812 | * interrupt handler |
796 | */ | 813 | */ |
797 | static irqreturn_t azx_interrupt(int irq, void* dev_id, struct pt_regs *regs) | 814 | static irqreturn_t azx_interrupt(int irq, void *dev_id, struct pt_regs *regs) |
798 | { | 815 | { |
799 | struct azx *chip = dev_id; | 816 | struct azx *chip = dev_id; |
800 | struct azx_dev *azx_dev; | 817 | struct azx_dev *azx_dev; |
@@ -999,8 +1016,9 @@ static struct snd_pcm_hardware azx_pcm_hw = { | |||
999 | .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | | 1016 | .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | |
1000 | SNDRV_PCM_INFO_BLOCK_TRANSFER | | 1017 | SNDRV_PCM_INFO_BLOCK_TRANSFER | |
1001 | SNDRV_PCM_INFO_MMAP_VALID | | 1018 | SNDRV_PCM_INFO_MMAP_VALID | |
1002 | SNDRV_PCM_INFO_PAUSE /*|*/ | 1019 | /* No full-resume yet implemented */ |
1003 | /*SNDRV_PCM_INFO_RESUME*/), | 1020 | /* SNDRV_PCM_INFO_RESUME |*/ |
1021 | SNDRV_PCM_INFO_PAUSE), | ||
1004 | .formats = SNDRV_PCM_FMTBIT_S16_LE, | 1022 | .formats = SNDRV_PCM_FMTBIT_S16_LE, |
1005 | .rates = SNDRV_PCM_RATE_48000, | 1023 | .rates = SNDRV_PCM_RATE_48000, |
1006 | .rate_min = 48000, | 1024 | .rate_min = 48000, |
@@ -1178,7 +1196,7 @@ static snd_pcm_uframes_t azx_pcm_pointer(struct snd_pcm_substream *substream) | |||
1178 | if (chip->position_fix == POS_FIX_POSBUF || | 1196 | if (chip->position_fix == POS_FIX_POSBUF || |
1179 | chip->position_fix == POS_FIX_AUTO) { | 1197 | chip->position_fix == POS_FIX_AUTO) { |
1180 | /* use the position buffer */ | 1198 | /* use the position buffer */ |
1181 | pos = *azx_dev->posbuf; | 1199 | pos = le32_to_cpu(*azx_dev->posbuf); |
1182 | if (chip->position_fix == POS_FIX_AUTO && | 1200 | if (chip->position_fix == POS_FIX_AUTO && |
1183 | azx_dev->period_intr == 1 && ! pos) { | 1201 | azx_dev->period_intr == 1 && ! pos) { |
1184 | printk(KERN_WARNING | 1202 | printk(KERN_WARNING |
@@ -1222,7 +1240,12 @@ static int __devinit create_codec_pcm(struct azx *chip, struct hda_codec *codec, | |||
1222 | struct snd_pcm *pcm; | 1240 | struct snd_pcm *pcm; |
1223 | struct azx_pcm *apcm; | 1241 | struct azx_pcm *apcm; |
1224 | 1242 | ||
1225 | snd_assert(cpcm->stream[0].substreams || cpcm->stream[1].substreams, return -EINVAL); | 1243 | /* if no substreams are defined for both playback and capture, |
1244 | * it's just a placeholder. ignore it. | ||
1245 | */ | ||
1246 | if (!cpcm->stream[0].substreams && !cpcm->stream[1].substreams) | ||
1247 | return 0; | ||
1248 | |||
1226 | snd_assert(cpcm->name, return -EINVAL); | 1249 | snd_assert(cpcm->name, return -EINVAL); |
1227 | 1250 | ||
1228 | err = snd_pcm_new(chip->card, cpcm->name, pcm_dev, | 1251 | err = snd_pcm_new(chip->card, cpcm->name, pcm_dev, |
@@ -1248,7 +1271,8 @@ static int __devinit create_codec_pcm(struct azx *chip, struct hda_codec *codec, | |||
1248 | snd_dma_pci_data(chip->pci), | 1271 | snd_dma_pci_data(chip->pci), |
1249 | 1024 * 64, 1024 * 128); | 1272 | 1024 * 64, 1024 * 128); |
1250 | chip->pcm[pcm_dev] = pcm; | 1273 | chip->pcm[pcm_dev] = pcm; |
1251 | chip->pcm_devs = pcm_dev + 1; | 1274 | if (chip->pcm_devs < pcm_dev + 1) |
1275 | chip->pcm_devs = pcm_dev + 1; | ||
1252 | 1276 | ||
1253 | return 0; | 1277 | return 0; |
1254 | } | 1278 | } |
@@ -1326,7 +1350,7 @@ static int __devinit azx_init_stream(struct azx *chip) | |||
1326 | struct azx_dev *azx_dev = &chip->azx_dev[i]; | 1350 | struct azx_dev *azx_dev = &chip->azx_dev[i]; |
1327 | azx_dev->bdl = (u32 *)(chip->bdl.area + off); | 1351 | azx_dev->bdl = (u32 *)(chip->bdl.area + off); |
1328 | azx_dev->bdl_addr = chip->bdl.addr + off; | 1352 | azx_dev->bdl_addr = chip->bdl.addr + off; |
1329 | azx_dev->posbuf = (volatile u32 *)(chip->posbuf.area + i * 8); | 1353 | azx_dev->posbuf = (u32 __iomem *)(chip->posbuf.area + i * 8); |
1330 | /* offset: SDI0=0x80, SDI1=0xa0, ... SDO3=0x160 */ | 1354 | /* offset: SDI0=0x80, SDI1=0xa0, ... SDO3=0x160 */ |
1331 | azx_dev->sd_addr = chip->remap_addr + (0x20 * i + 0x80); | 1355 | azx_dev->sd_addr = chip->remap_addr + (0x20 * i + 0x80); |
1332 | /* int mask: SDI0=0x01, SDI1=0x02, ... SDO3=0x80 */ | 1356 | /* int mask: SDI0=0x01, SDI1=0x02, ... SDO3=0x80 */ |
@@ -1355,6 +1379,10 @@ static int azx_suspend(struct pci_dev *pci, pm_message_t state) | |||
1355 | snd_pcm_suspend_all(chip->pcm[i]); | 1379 | snd_pcm_suspend_all(chip->pcm[i]); |
1356 | snd_hda_suspend(chip->bus, state); | 1380 | snd_hda_suspend(chip->bus, state); |
1357 | azx_free_cmd_io(chip); | 1381 | azx_free_cmd_io(chip); |
1382 | if (chip->irq >= 0) | ||
1383 | free_irq(chip->irq, chip); | ||
1384 | if (!disable_msi) | ||
1385 | pci_disable_msi(chip->pci); | ||
1358 | pci_disable_device(pci); | 1386 | pci_disable_device(pci); |
1359 | pci_save_state(pci); | 1387 | pci_save_state(pci); |
1360 | return 0; | 1388 | return 0; |
@@ -1367,6 +1395,12 @@ static int azx_resume(struct pci_dev *pci) | |||
1367 | 1395 | ||
1368 | pci_restore_state(pci); | 1396 | pci_restore_state(pci); |
1369 | pci_enable_device(pci); | 1397 | pci_enable_device(pci); |
1398 | if (!disable_msi) | ||
1399 | pci_enable_msi(pci); | ||
1400 | /* FIXME: need proper error handling */ | ||
1401 | request_irq(pci->irq, azx_interrupt, IRQF_DISABLED|IRQF_SHARED, | ||
1402 | "HDA Intel", chip); | ||
1403 | chip->irq = pci->irq; | ||
1370 | pci_set_master(pci); | 1404 | pci_set_master(pci); |
1371 | azx_init_chip(chip); | 1405 | azx_init_chip(chip); |
1372 | snd_hda_resume(chip->bus); | 1406 | snd_hda_resume(chip->bus); |
@@ -1398,12 +1432,14 @@ static int azx_free(struct azx *chip) | |||
1398 | azx_writel(chip, DPLBASE, 0); | 1432 | azx_writel(chip, DPLBASE, 0); |
1399 | azx_writel(chip, DPUBASE, 0); | 1433 | azx_writel(chip, DPUBASE, 0); |
1400 | 1434 | ||
1401 | /* wait a little for interrupts to finish */ | 1435 | synchronize_irq(chip->irq); |
1402 | msleep(1); | ||
1403 | } | 1436 | } |
1404 | 1437 | ||
1405 | if (chip->irq >= 0) | 1438 | if (chip->irq >= 0) { |
1406 | free_irq(chip->irq, (void*)chip); | 1439 | free_irq(chip->irq, (void*)chip); |
1440 | if (!disable_msi) | ||
1441 | pci_disable_msi(chip->pci); | ||
1442 | } | ||
1407 | if (chip->remap_addr) | 1443 | if (chip->remap_addr) |
1408 | iounmap(chip->remap_addr); | 1444 | iounmap(chip->remap_addr); |
1409 | 1445 | ||
@@ -1434,19 +1470,19 @@ static int __devinit azx_create(struct snd_card *card, struct pci_dev *pci, | |||
1434 | struct azx **rchip) | 1470 | struct azx **rchip) |
1435 | { | 1471 | { |
1436 | struct azx *chip; | 1472 | struct azx *chip; |
1437 | int err = 0; | 1473 | int err; |
1438 | static struct snd_device_ops ops = { | 1474 | static struct snd_device_ops ops = { |
1439 | .dev_free = azx_dev_free, | 1475 | .dev_free = azx_dev_free, |
1440 | }; | 1476 | }; |
1441 | 1477 | ||
1442 | *rchip = NULL; | 1478 | *rchip = NULL; |
1443 | 1479 | ||
1444 | if ((err = pci_enable_device(pci)) < 0) | 1480 | err = pci_enable_device(pci); |
1481 | if (err < 0) | ||
1445 | return err; | 1482 | return err; |
1446 | 1483 | ||
1447 | chip = kzalloc(sizeof(*chip), GFP_KERNEL); | 1484 | chip = kzalloc(sizeof(*chip), GFP_KERNEL); |
1448 | 1485 | if (!chip) { | |
1449 | if (NULL == chip) { | ||
1450 | snd_printk(KERN_ERR SFX "cannot allocate chip\n"); | 1486 | snd_printk(KERN_ERR SFX "cannot allocate chip\n"); |
1451 | pci_disable_device(pci); | 1487 | pci_disable_device(pci); |
1452 | return -ENOMEM; | 1488 | return -ENOMEM; |
@@ -1472,13 +1508,14 @@ static int __devinit azx_create(struct snd_card *card, struct pci_dev *pci, | |||
1472 | } | 1508 | } |
1473 | #endif | 1509 | #endif |
1474 | 1510 | ||
1475 | if ((err = pci_request_regions(pci, "ICH HD audio")) < 0) { | 1511 | err = pci_request_regions(pci, "ICH HD audio"); |
1512 | if (err < 0) { | ||
1476 | kfree(chip); | 1513 | kfree(chip); |
1477 | pci_disable_device(pci); | 1514 | pci_disable_device(pci); |
1478 | return err; | 1515 | return err; |
1479 | } | 1516 | } |
1480 | 1517 | ||
1481 | chip->addr = pci_resource_start(pci,0); | 1518 | chip->addr = pci_resource_start(pci, 0); |
1482 | chip->remap_addr = ioremap_nocache(chip->addr, pci_resource_len(pci,0)); | 1519 | chip->remap_addr = ioremap_nocache(chip->addr, pci_resource_len(pci,0)); |
1483 | if (chip->remap_addr == NULL) { | 1520 | if (chip->remap_addr == NULL) { |
1484 | snd_printk(KERN_ERR SFX "ioremap error\n"); | 1521 | snd_printk(KERN_ERR SFX "ioremap error\n"); |
@@ -1486,6 +1523,9 @@ static int __devinit azx_create(struct snd_card *card, struct pci_dev *pci, | |||
1486 | goto errout; | 1523 | goto errout; |
1487 | } | 1524 | } |
1488 | 1525 | ||
1526 | if (!disable_msi) | ||
1527 | pci_enable_msi(pci); | ||
1528 | |||
1489 | if (request_irq(pci->irq, azx_interrupt, IRQF_DISABLED|IRQF_SHARED, | 1529 | if (request_irq(pci->irq, azx_interrupt, IRQF_DISABLED|IRQF_SHARED, |
1490 | "HDA Intel", (void*)chip)) { | 1530 | "HDA Intel", (void*)chip)) { |
1491 | snd_printk(KERN_ERR SFX "unable to grab IRQ %d\n", pci->irq); | 1531 | snd_printk(KERN_ERR SFX "unable to grab IRQ %d\n", pci->irq); |
@@ -1519,7 +1559,7 @@ static int __devinit azx_create(struct snd_card *card, struct pci_dev *pci, | |||
1519 | } | 1559 | } |
1520 | chip->num_streams = chip->playback_streams + chip->capture_streams; | 1560 | chip->num_streams = chip->playback_streams + chip->capture_streams; |
1521 | chip->azx_dev = kcalloc(chip->num_streams, sizeof(*chip->azx_dev), GFP_KERNEL); | 1561 | chip->azx_dev = kcalloc(chip->num_streams, sizeof(*chip->azx_dev), GFP_KERNEL); |
1522 | if (! chip->azx_dev) { | 1562 | if (!chip->azx_dev) { |
1523 | snd_printk(KERN_ERR "cannot malloc azx_dev\n"); | 1563 | snd_printk(KERN_ERR "cannot malloc azx_dev\n"); |
1524 | goto errout; | 1564 | goto errout; |
1525 | } | 1565 | } |
@@ -1550,7 +1590,7 @@ static int __devinit azx_create(struct snd_card *card, struct pci_dev *pci, | |||
1550 | chip->initialized = 1; | 1590 | chip->initialized = 1; |
1551 | 1591 | ||
1552 | /* codec detection */ | 1592 | /* codec detection */ |
1553 | if (! chip->codec_mask) { | 1593 | if (!chip->codec_mask) { |
1554 | snd_printk(KERN_ERR SFX "no codecs found!\n"); | 1594 | snd_printk(KERN_ERR SFX "no codecs found!\n"); |
1555 | err = -ENODEV; | 1595 | err = -ENODEV; |
1556 | goto errout; | 1596 | goto errout; |
@@ -1577,16 +1617,16 @@ static int __devinit azx_probe(struct pci_dev *pci, const struct pci_device_id * | |||
1577 | { | 1617 | { |
1578 | struct snd_card *card; | 1618 | struct snd_card *card; |
1579 | struct azx *chip; | 1619 | struct azx *chip; |
1580 | int err = 0; | 1620 | int err; |
1581 | 1621 | ||
1582 | card = snd_card_new(index, id, THIS_MODULE, 0); | 1622 | card = snd_card_new(index, id, THIS_MODULE, 0); |
1583 | if (NULL == card) { | 1623 | if (!card) { |
1584 | snd_printk(KERN_ERR SFX "Error creating card!\n"); | 1624 | snd_printk(KERN_ERR SFX "Error creating card!\n"); |
1585 | return -ENOMEM; | 1625 | return -ENOMEM; |
1586 | } | 1626 | } |
1587 | 1627 | ||
1588 | if ((err = azx_create(card, pci, pci_id->driver_data, | 1628 | err = azx_create(card, pci, pci_id->driver_data, &chip); |
1589 | &chip)) < 0) { | 1629 | if (err < 0) { |
1590 | snd_card_free(card); | 1630 | snd_card_free(card); |
1591 | return err; | 1631 | return err; |
1592 | } | 1632 | } |
diff --git a/sound/pci/hda/hda_local.h b/sound/pci/hda/hda_local.h index 14e8aa2806ed..f9416c36396e 100644 --- a/sound/pci/hda/hda_local.h +++ b/sound/pci/hda/hda_local.h | |||
@@ -30,9 +30,13 @@ | |||
30 | /* mono volume with index (index=0,1,...) (channel=1,2) */ | 30 | /* mono volume with index (index=0,1,...) (channel=1,2) */ |
31 | #define HDA_CODEC_VOLUME_MONO_IDX(xname, xcidx, nid, channel, xindex, direction) \ | 31 | #define HDA_CODEC_VOLUME_MONO_IDX(xname, xcidx, nid, channel, xindex, direction) \ |
32 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xcidx, \ | 32 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xcidx, \ |
33 | .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | \ | ||
34 | SNDRV_CTL_ELEM_ACCESS_TLV_READ | \ | ||
35 | SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK, \ | ||
33 | .info = snd_hda_mixer_amp_volume_info, \ | 36 | .info = snd_hda_mixer_amp_volume_info, \ |
34 | .get = snd_hda_mixer_amp_volume_get, \ | 37 | .get = snd_hda_mixer_amp_volume_get, \ |
35 | .put = snd_hda_mixer_amp_volume_put, \ | 38 | .put = snd_hda_mixer_amp_volume_put, \ |
39 | .tlv = { .c = snd_hda_mixer_amp_tlv }, \ | ||
36 | .private_value = HDA_COMPOSE_AMP_VAL(nid, channel, xindex, direction) } | 40 | .private_value = HDA_COMPOSE_AMP_VAL(nid, channel, xindex, direction) } |
37 | /* stereo volume with index */ | 41 | /* stereo volume with index */ |
38 | #define HDA_CODEC_VOLUME_IDX(xname, xcidx, nid, xindex, direction) \ | 42 | #define HDA_CODEC_VOLUME_IDX(xname, xcidx, nid, xindex, direction) \ |
@@ -63,6 +67,7 @@ | |||
63 | int snd_hda_mixer_amp_volume_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo); | 67 | int snd_hda_mixer_amp_volume_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo); |
64 | int snd_hda_mixer_amp_volume_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol); | 68 | int snd_hda_mixer_amp_volume_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol); |
65 | int snd_hda_mixer_amp_volume_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol); | 69 | int snd_hda_mixer_amp_volume_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol); |
70 | int snd_hda_mixer_amp_tlv(struct snd_kcontrol *kcontrol, int op_flag, unsigned int size, unsigned int __user *tlv); | ||
66 | int snd_hda_mixer_amp_switch_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo); | 71 | int snd_hda_mixer_amp_switch_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo); |
67 | int snd_hda_mixer_amp_switch_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol); | 72 | int snd_hda_mixer_amp_switch_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol); |
68 | int snd_hda_mixer_amp_switch_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol); | 73 | int snd_hda_mixer_amp_switch_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol); |
@@ -224,7 +229,8 @@ struct auto_pin_cfg { | |||
224 | hda_nid_t line_out_pins[5]; /* sorted in the order of Front/Surr/CLFE/Side */ | 229 | hda_nid_t line_out_pins[5]; /* sorted in the order of Front/Surr/CLFE/Side */ |
225 | int speaker_outs; | 230 | int speaker_outs; |
226 | hda_nid_t speaker_pins[5]; | 231 | hda_nid_t speaker_pins[5]; |
227 | hda_nid_t hp_pin; | 232 | int hp_outs; |
233 | hda_nid_t hp_pins[5]; | ||
228 | hda_nid_t input_pins[AUTO_PIN_LAST]; | 234 | hda_nid_t input_pins[AUTO_PIN_LAST]; |
229 | hda_nid_t dig_out_pin; | 235 | hda_nid_t dig_out_pin; |
230 | hda_nid_t dig_in_pin; | 236 | hda_nid_t dig_in_pin; |
diff --git a/sound/pci/hda/hda_proc.c b/sound/pci/hda/hda_proc.c index c2f0fe85bf35..d737f17695a3 100644 --- a/sound/pci/hda/hda_proc.c +++ b/sound/pci/hda/hda_proc.c | |||
@@ -52,10 +52,9 @@ static void print_amp_caps(struct snd_info_buffer *buffer, | |||
52 | struct hda_codec *codec, hda_nid_t nid, int dir) | 52 | struct hda_codec *codec, hda_nid_t nid, int dir) |
53 | { | 53 | { |
54 | unsigned int caps; | 54 | unsigned int caps; |
55 | if (dir == HDA_OUTPUT) | 55 | caps = snd_hda_param_read(codec, nid, |
56 | caps = snd_hda_param_read(codec, nid, AC_PAR_AMP_OUT_CAP); | 56 | dir == HDA_OUTPUT ? |
57 | else | 57 | AC_PAR_AMP_OUT_CAP : AC_PAR_AMP_IN_CAP); |
58 | caps = snd_hda_param_read(codec, nid, AC_PAR_AMP_IN_CAP); | ||
59 | if (caps == -1 || caps == 0) { | 58 | if (caps == -1 || caps == 0) { |
60 | snd_iprintf(buffer, "N/A\n"); | 59 | snd_iprintf(buffer, "N/A\n"); |
61 | return; | 60 | return; |
@@ -74,10 +73,7 @@ static void print_amp_vals(struct snd_info_buffer *buffer, | |||
74 | unsigned int val; | 73 | unsigned int val; |
75 | int i; | 74 | int i; |
76 | 75 | ||
77 | if (dir == HDA_OUTPUT) | 76 | dir = dir == HDA_OUTPUT ? AC_AMP_GET_OUTPUT : AC_AMP_GET_INPUT; |
78 | dir = AC_AMP_GET_OUTPUT; | ||
79 | else | ||
80 | dir = AC_AMP_GET_INPUT; | ||
81 | for (i = 0; i < indices; i++) { | 77 | for (i = 0; i < indices; i++) { |
82 | snd_iprintf(buffer, " ["); | 78 | snd_iprintf(buffer, " ["); |
83 | if (stereo) { | 79 | if (stereo) { |
diff --git a/sound/pci/hda/patch_analog.c b/sound/pci/hda/patch_analog.c index 6823f2bc10b3..511df07fa2a3 100644 --- a/sound/pci/hda/patch_analog.c +++ b/sound/pci/hda/patch_analog.c | |||
@@ -488,9 +488,13 @@ static struct snd_kcontrol_new ad1986a_mixers[] = { | |||
488 | { | 488 | { |
489 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 489 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
490 | .name = "PCM Playback Volume", | 490 | .name = "PCM Playback Volume", |
491 | .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | | ||
492 | SNDRV_CTL_ELEM_ACCESS_TLV_READ | | ||
493 | SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK, | ||
491 | .info = ad1986a_pcm_amp_vol_info, | 494 | .info = ad1986a_pcm_amp_vol_info, |
492 | .get = ad1986a_pcm_amp_vol_get, | 495 | .get = ad1986a_pcm_amp_vol_get, |
493 | .put = ad1986a_pcm_amp_vol_put, | 496 | .put = ad1986a_pcm_amp_vol_put, |
497 | .tlv = { .c = snd_hda_mixer_amp_tlv }, | ||
494 | .private_value = HDA_COMPOSE_AMP_VAL(AD1986A_FRONT_DAC, 3, 0, HDA_OUTPUT) | 498 | .private_value = HDA_COMPOSE_AMP_VAL(AD1986A_FRONT_DAC, 3, 0, HDA_OUTPUT) |
495 | }, | 499 | }, |
496 | { | 500 | { |
@@ -637,6 +641,7 @@ static struct snd_kcontrol_new ad1986a_laptop_eapd_mixers[] = { | |||
637 | .info = snd_hda_mixer_amp_volume_info, | 641 | .info = snd_hda_mixer_amp_volume_info, |
638 | .get = snd_hda_mixer_amp_volume_get, | 642 | .get = snd_hda_mixer_amp_volume_get, |
639 | .put = ad1986a_laptop_master_vol_put, | 643 | .put = ad1986a_laptop_master_vol_put, |
644 | .tlv = { .c = snd_hda_mixer_amp_tlv }, | ||
640 | .private_value = HDA_COMPOSE_AMP_VAL(0x1a, 3, 0, HDA_OUTPUT), | 645 | .private_value = HDA_COMPOSE_AMP_VAL(0x1a, 3, 0, HDA_OUTPUT), |
641 | }, | 646 | }, |
642 | { | 647 | { |
@@ -791,6 +796,8 @@ static struct hda_board_config ad1986a_cfg_tbl[] = { | |||
791 | .config = AD1986A_3STACK }, /* ASUS A8N-VM CSM */ | 796 | .config = AD1986A_3STACK }, /* ASUS A8N-VM CSM */ |
792 | { .pci_subvendor = 0x1043, .pci_subdevice = 0x81b3, | 797 | { .pci_subvendor = 0x1043, .pci_subdevice = 0x81b3, |
793 | .config = AD1986A_3STACK }, /* ASUS P5RD2-VM / P5GPL-X SE */ | 798 | .config = AD1986A_3STACK }, /* ASUS P5RD2-VM / P5GPL-X SE */ |
799 | { .pci_subvendor = 0x1043, .pci_subdevice = 0x81cb, | ||
800 | .config = AD1986A_3STACK }, /* ASUS M2NPV-VM */ | ||
794 | { .modelname = "laptop", .config = AD1986A_LAPTOP }, | 801 | { .modelname = "laptop", .config = AD1986A_LAPTOP }, |
795 | { .pci_subvendor = 0x144d, .pci_subdevice = 0xc01e, | 802 | { .pci_subvendor = 0x144d, .pci_subdevice = 0xc01e, |
796 | .config = AD1986A_LAPTOP }, /* FSC V2060 */ | 803 | .config = AD1986A_LAPTOP }, /* FSC V2060 */ |
@@ -803,6 +810,8 @@ static struct hda_board_config ad1986a_cfg_tbl[] = { | |||
803 | .config = AD1986A_LAPTOP_EAPD }, /* Samsung X60 Chane */ | 810 | .config = AD1986A_LAPTOP_EAPD }, /* Samsung X60 Chane */ |
804 | { .pci_subvendor = 0x144d, .pci_subdevice = 0xc024, | 811 | { .pci_subvendor = 0x144d, .pci_subdevice = 0xc024, |
805 | .config = AD1986A_LAPTOP_EAPD }, /* Samsung R65-T2300 Charis */ | 812 | .config = AD1986A_LAPTOP_EAPD }, /* Samsung R65-T2300 Charis */ |
813 | { .pci_subvendor = 0x144d, .pci_subdevice = 0xc026, | ||
814 | .config = AD1986A_LAPTOP_EAPD }, /* Samsung X10-T2300 Culesa */ | ||
806 | { .pci_subvendor = 0x1043, .pci_subdevice = 0x1153, | 815 | { .pci_subvendor = 0x1043, .pci_subdevice = 0x1153, |
807 | .config = AD1986A_LAPTOP_EAPD }, /* ASUS M9 */ | 816 | .config = AD1986A_LAPTOP_EAPD }, /* ASUS M9 */ |
808 | { .pci_subvendor = 0x1043, .pci_subdevice = 0x1213, | 817 | { .pci_subvendor = 0x1043, .pci_subdevice = 0x1213, |
@@ -1626,10 +1635,12 @@ static int ad198x_ch_mode_put(struct snd_kcontrol *kcontrol, | |||
1626 | { | 1635 | { |
1627 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | 1636 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); |
1628 | struct ad198x_spec *spec = codec->spec; | 1637 | struct ad198x_spec *spec = codec->spec; |
1629 | if (spec->need_dac_fix) | 1638 | int err = snd_hda_ch_mode_put(codec, ucontrol, spec->channel_mode, |
1639 | spec->num_channel_mode, | ||
1640 | &spec->multiout.max_channels); | ||
1641 | if (! err && spec->need_dac_fix) | ||
1630 | spec->multiout.num_dacs = spec->multiout.max_channels / 2; | 1642 | spec->multiout.num_dacs = spec->multiout.max_channels / 2; |
1631 | return snd_hda_ch_mode_put(codec, ucontrol, spec->channel_mode, | 1643 | return err; |
1632 | spec->num_channel_mode, &spec->multiout.max_channels); | ||
1633 | } | 1644 | } |
1634 | 1645 | ||
1635 | /* 6-stack mode */ | 1646 | /* 6-stack mode */ |
@@ -2460,7 +2471,7 @@ static void ad1988_auto_init_extra_out(struct hda_codec *codec) | |||
2460 | pin = spec->autocfg.speaker_pins[0]; | 2471 | pin = spec->autocfg.speaker_pins[0]; |
2461 | if (pin) /* connect to front */ | 2472 | if (pin) /* connect to front */ |
2462 | ad1988_auto_set_output_and_unmute(codec, pin, PIN_OUT, 0); | 2473 | ad1988_auto_set_output_and_unmute(codec, pin, PIN_OUT, 0); |
2463 | pin = spec->autocfg.hp_pin; | 2474 | pin = spec->autocfg.hp_pins[0]; |
2464 | if (pin) /* connect to front */ | 2475 | if (pin) /* connect to front */ |
2465 | ad1988_auto_set_output_and_unmute(codec, pin, PIN_HP, 0); | 2476 | ad1988_auto_set_output_and_unmute(codec, pin, PIN_HP, 0); |
2466 | } | 2477 | } |
@@ -2512,7 +2523,7 @@ static int ad1988_parse_auto_config(struct hda_codec *codec) | |||
2512 | (err = ad1988_auto_create_extra_out(codec, | 2523 | (err = ad1988_auto_create_extra_out(codec, |
2513 | spec->autocfg.speaker_pins[0], | 2524 | spec->autocfg.speaker_pins[0], |
2514 | "Speaker")) < 0 || | 2525 | "Speaker")) < 0 || |
2515 | (err = ad1988_auto_create_extra_out(codec, spec->autocfg.hp_pin, | 2526 | (err = ad1988_auto_create_extra_out(codec, spec->autocfg.hp_pins[0], |
2516 | "Headphone")) < 0 || | 2527 | "Headphone")) < 0 || |
2517 | (err = ad1988_auto_create_analog_input_ctls(spec, &spec->autocfg)) < 0) | 2528 | (err = ad1988_auto_create_analog_input_ctls(spec, &spec->autocfg)) < 0) |
2518 | return err; | 2529 | return err; |
diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 18d105263fea..d08d2e399c8f 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c | |||
@@ -79,6 +79,7 @@ enum { | |||
79 | ALC262_BASIC, | 79 | ALC262_BASIC, |
80 | ALC262_FUJITSU, | 80 | ALC262_FUJITSU, |
81 | ALC262_HP_BPC, | 81 | ALC262_HP_BPC, |
82 | ALC262_BENQ_ED8, | ||
82 | ALC262_AUTO, | 83 | ALC262_AUTO, |
83 | ALC262_MODEL_LAST /* last tag */ | 84 | ALC262_MODEL_LAST /* last tag */ |
84 | }; | 85 | }; |
@@ -89,6 +90,7 @@ enum { | |||
89 | ALC660_3ST, | 90 | ALC660_3ST, |
90 | ALC861_3ST_DIG, | 91 | ALC861_3ST_DIG, |
91 | ALC861_6ST_DIG, | 92 | ALC861_6ST_DIG, |
93 | ALC861_UNIWILL_M31, | ||
92 | ALC861_AUTO, | 94 | ALC861_AUTO, |
93 | ALC861_MODEL_LAST, | 95 | ALC861_MODEL_LAST, |
94 | }; | 96 | }; |
@@ -97,6 +99,7 @@ enum { | |||
97 | enum { | 99 | enum { |
98 | ALC882_3ST_DIG, | 100 | ALC882_3ST_DIG, |
99 | ALC882_6ST_DIG, | 101 | ALC882_6ST_DIG, |
102 | ALC882_ARIMA, | ||
100 | ALC882_AUTO, | 103 | ALC882_AUTO, |
101 | ALC882_MODEL_LAST, | 104 | ALC882_MODEL_LAST, |
102 | }; | 105 | }; |
@@ -108,6 +111,7 @@ enum { | |||
108 | ALC883_3ST_6ch, | 111 | ALC883_3ST_6ch, |
109 | ALC883_6ST_DIG, | 112 | ALC883_6ST_DIG, |
110 | ALC888_DEMO_BOARD, | 113 | ALC888_DEMO_BOARD, |
114 | ALC883_ACER, | ||
111 | ALC883_AUTO, | 115 | ALC883_AUTO, |
112 | ALC883_MODEL_LAST, | 116 | ALC883_MODEL_LAST, |
113 | }; | 117 | }; |
@@ -153,6 +157,7 @@ struct alc_spec { | |||
153 | /* channel model */ | 157 | /* channel model */ |
154 | const struct hda_channel_mode *channel_mode; | 158 | const struct hda_channel_mode *channel_mode; |
155 | int num_channel_mode; | 159 | int num_channel_mode; |
160 | int need_dac_fix; | ||
156 | 161 | ||
157 | /* PCM information */ | 162 | /* PCM information */ |
158 | struct hda_pcm pcm_rec[3]; /* used in alc_build_pcms() */ | 163 | struct hda_pcm pcm_rec[3]; /* used in alc_build_pcms() */ |
@@ -190,6 +195,7 @@ struct alc_config_preset { | |||
190 | hda_nid_t dig_in_nid; | 195 | hda_nid_t dig_in_nid; |
191 | unsigned int num_channel_mode; | 196 | unsigned int num_channel_mode; |
192 | const struct hda_channel_mode *channel_mode; | 197 | const struct hda_channel_mode *channel_mode; |
198 | int need_dac_fix; | ||
193 | unsigned int num_mux_defs; | 199 | unsigned int num_mux_defs; |
194 | const struct hda_input_mux *input_mux; | 200 | const struct hda_input_mux *input_mux; |
195 | void (*unsol_event)(struct hda_codec *, unsigned int); | 201 | void (*unsol_event)(struct hda_codec *, unsigned int); |
@@ -262,9 +268,12 @@ static int alc_ch_mode_put(struct snd_kcontrol *kcontrol, | |||
262 | { | 268 | { |
263 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | 269 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); |
264 | struct alc_spec *spec = codec->spec; | 270 | struct alc_spec *spec = codec->spec; |
265 | return snd_hda_ch_mode_put(codec, ucontrol, spec->channel_mode, | 271 | int err = snd_hda_ch_mode_put(codec, ucontrol, spec->channel_mode, |
266 | spec->num_channel_mode, | 272 | spec->num_channel_mode, |
267 | &spec->multiout.max_channels); | 273 | &spec->multiout.max_channels); |
274 | if (! err && spec->need_dac_fix) | ||
275 | spec->multiout.num_dacs = spec->multiout.max_channels / 2; | ||
276 | return err; | ||
268 | } | 277 | } |
269 | 278 | ||
270 | /* | 279 | /* |
@@ -544,6 +553,7 @@ static void setup_preset(struct alc_spec *spec, | |||
544 | 553 | ||
545 | spec->channel_mode = preset->channel_mode; | 554 | spec->channel_mode = preset->channel_mode; |
546 | spec->num_channel_mode = preset->num_channel_mode; | 555 | spec->num_channel_mode = preset->num_channel_mode; |
556 | spec->need_dac_fix = preset->need_dac_fix; | ||
547 | 557 | ||
548 | spec->multiout.max_channels = spec->channel_mode[0].channels; | 558 | spec->multiout.max_channels = spec->channel_mode[0].channels; |
549 | 559 | ||
@@ -1348,6 +1358,10 @@ static struct hda_verb alc880_pin_clevo_init_verbs[] = { | |||
1348 | }; | 1358 | }; |
1349 | 1359 | ||
1350 | static struct hda_verb alc880_pin_tcl_S700_init_verbs[] = { | 1360 | static struct hda_verb alc880_pin_tcl_S700_init_verbs[] = { |
1361 | /* change to EAPD mode */ | ||
1362 | {0x20, AC_VERB_SET_COEF_INDEX, 0x07}, | ||
1363 | {0x20, AC_VERB_SET_PROC_COEF, 0x3060}, | ||
1364 | |||
1351 | /* Headphone output */ | 1365 | /* Headphone output */ |
1352 | {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, | 1366 | {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, |
1353 | /* Front output*/ | 1367 | /* Front output*/ |
@@ -1782,25 +1796,9 @@ static int alc_build_pcms(struct hda_codec *codec) | |||
1782 | } | 1796 | } |
1783 | } | 1797 | } |
1784 | 1798 | ||
1785 | /* If the use of more than one ADC is requested for the current | 1799 | /* SPDIF for stream index #1 */ |
1786 | * model, configure a second analog capture-only PCM. | ||
1787 | */ | ||
1788 | if (spec->num_adc_nids > 1) { | ||
1789 | codec->num_pcms++; | ||
1790 | info++; | ||
1791 | info->name = spec->stream_name_analog; | ||
1792 | /* No playback stream for second PCM */ | ||
1793 | info->stream[SNDRV_PCM_STREAM_PLAYBACK] = alc_pcm_null_playback; | ||
1794 | info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = 0; | ||
1795 | if (spec->stream_analog_capture) { | ||
1796 | snd_assert(spec->adc_nids, return -EINVAL); | ||
1797 | info->stream[SNDRV_PCM_STREAM_CAPTURE] = *(spec->stream_analog_capture); | ||
1798 | info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adc_nids[1]; | ||
1799 | } | ||
1800 | } | ||
1801 | |||
1802 | if (spec->multiout.dig_out_nid || spec->dig_in_nid) { | 1800 | if (spec->multiout.dig_out_nid || spec->dig_in_nid) { |
1803 | codec->num_pcms++; | 1801 | codec->num_pcms = 2; |
1804 | info++; | 1802 | info++; |
1805 | info->name = spec->stream_name_digital; | 1803 | info->name = spec->stream_name_digital; |
1806 | if (spec->multiout.dig_out_nid && | 1804 | if (spec->multiout.dig_out_nid && |
@@ -1815,6 +1813,24 @@ static int alc_build_pcms(struct hda_codec *codec) | |||
1815 | } | 1813 | } |
1816 | } | 1814 | } |
1817 | 1815 | ||
1816 | /* If the use of more than one ADC is requested for the current | ||
1817 | * model, configure a second analog capture-only PCM. | ||
1818 | */ | ||
1819 | /* Additional Analaog capture for index #2 */ | ||
1820 | if (spec->num_adc_nids > 1 && spec->stream_analog_capture && | ||
1821 | spec->adc_nids) { | ||
1822 | codec->num_pcms = 3; | ||
1823 | info++; | ||
1824 | info->name = spec->stream_name_analog; | ||
1825 | /* No playback stream for second PCM */ | ||
1826 | info->stream[SNDRV_PCM_STREAM_PLAYBACK] = alc_pcm_null_playback; | ||
1827 | info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = 0; | ||
1828 | if (spec->stream_analog_capture) { | ||
1829 | info->stream[SNDRV_PCM_STREAM_CAPTURE] = *(spec->stream_analog_capture); | ||
1830 | info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adc_nids[1]; | ||
1831 | } | ||
1832 | } | ||
1833 | |||
1818 | return 0; | 1834 | return 0; |
1819 | } | 1835 | } |
1820 | 1836 | ||
@@ -2130,7 +2146,10 @@ static struct hda_board_config alc880_cfg_tbl[] = { | |||
2130 | { .pci_subvendor = 0x8086, .pci_subdevice = 0xe20f, .config = ALC880_3ST }, | 2146 | { .pci_subvendor = 0x8086, .pci_subdevice = 0xe20f, .config = ALC880_3ST }, |
2131 | { .pci_subvendor = 0x8086, .pci_subdevice = 0xe210, .config = ALC880_3ST }, | 2147 | { .pci_subvendor = 0x8086, .pci_subdevice = 0xe210, .config = ALC880_3ST }, |
2132 | { .pci_subvendor = 0x8086, .pci_subdevice = 0xe211, .config = ALC880_3ST }, | 2148 | { .pci_subvendor = 0x8086, .pci_subdevice = 0xe211, .config = ALC880_3ST }, |
2149 | { .pci_subvendor = 0x8086, .pci_subdevice = 0xe212, .config = ALC880_3ST }, | ||
2150 | { .pci_subvendor = 0x8086, .pci_subdevice = 0xe213, .config = ALC880_3ST }, | ||
2133 | { .pci_subvendor = 0x8086, .pci_subdevice = 0xe214, .config = ALC880_3ST }, | 2151 | { .pci_subvendor = 0x8086, .pci_subdevice = 0xe214, .config = ALC880_3ST }, |
2152 | { .pci_subvendor = 0x8086, .pci_subdevice = 0xe234, .config = ALC880_3ST }, | ||
2134 | { .pci_subvendor = 0x8086, .pci_subdevice = 0xe302, .config = ALC880_3ST }, | 2153 | { .pci_subvendor = 0x8086, .pci_subdevice = 0xe302, .config = ALC880_3ST }, |
2135 | { .pci_subvendor = 0x8086, .pci_subdevice = 0xe303, .config = ALC880_3ST }, | 2154 | { .pci_subvendor = 0x8086, .pci_subdevice = 0xe303, .config = ALC880_3ST }, |
2136 | { .pci_subvendor = 0x8086, .pci_subdevice = 0xe304, .config = ALC880_3ST }, | 2155 | { .pci_subvendor = 0x8086, .pci_subdevice = 0xe304, .config = ALC880_3ST }, |
@@ -2145,6 +2164,7 @@ static struct hda_board_config alc880_cfg_tbl[] = { | |||
2145 | { .pci_subvendor = 0x107b, .pci_subdevice = 0x4040, .config = ALC880_3ST }, | 2164 | { .pci_subvendor = 0x107b, .pci_subdevice = 0x4040, .config = ALC880_3ST }, |
2146 | { .pci_subvendor = 0x107b, .pci_subdevice = 0x4041, .config = ALC880_3ST }, | 2165 | { .pci_subvendor = 0x107b, .pci_subdevice = 0x4041, .config = ALC880_3ST }, |
2147 | /* TCL S700 */ | 2166 | /* TCL S700 */ |
2167 | { .modelname = "tcl", .config = ALC880_TCL_S700 }, | ||
2148 | { .pci_subvendor = 0x19db, .pci_subdevice = 0x4188, .config = ALC880_TCL_S700 }, | 2168 | { .pci_subvendor = 0x19db, .pci_subdevice = 0x4188, .config = ALC880_TCL_S700 }, |
2149 | 2169 | ||
2150 | /* Back 3 jack, front 2 jack (Internal add Aux-In) */ | 2170 | /* Back 3 jack, front 2 jack (Internal add Aux-In) */ |
@@ -2156,8 +2176,13 @@ static struct hda_board_config alc880_cfg_tbl[] = { | |||
2156 | { .modelname = "3stack-digout", .config = ALC880_3ST_DIG }, | 2176 | { .modelname = "3stack-digout", .config = ALC880_3ST_DIG }, |
2157 | { .pci_subvendor = 0x8086, .pci_subdevice = 0xe308, .config = ALC880_3ST_DIG }, | 2177 | { .pci_subvendor = 0x8086, .pci_subdevice = 0xe308, .config = ALC880_3ST_DIG }, |
2158 | { .pci_subvendor = 0x1025, .pci_subdevice = 0x0070, .config = ALC880_3ST_DIG }, | 2178 | { .pci_subvendor = 0x1025, .pci_subdevice = 0x0070, .config = ALC880_3ST_DIG }, |
2159 | /* Clevo m520G NB */ | 2179 | |
2160 | { .pci_subvendor = 0x1558, .pci_subdevice = 0x0520, .config = ALC880_CLEVO }, | 2180 | /* Clevo laptops */ |
2181 | { .modelname = "clevo", .config = ALC880_CLEVO }, | ||
2182 | { .pci_subvendor = 0x1558, .pci_subdevice = 0x0520, | ||
2183 | .config = ALC880_CLEVO }, /* Clevo m520G NB */ | ||
2184 | { .pci_subvendor = 0x1558, .pci_subdevice = 0x0660, | ||
2185 | .config = ALC880_CLEVO }, /* Clevo m665n */ | ||
2161 | 2186 | ||
2162 | /* Back 3 jack plus 1 SPDIF out jack, front 2 jack (Internal add Aux-In)*/ | 2187 | /* Back 3 jack plus 1 SPDIF out jack, front 2 jack (Internal add Aux-In)*/ |
2163 | { .pci_subvendor = 0x8086, .pci_subdevice = 0xe305, .config = ALC880_3ST_DIG }, | 2188 | { .pci_subvendor = 0x8086, .pci_subdevice = 0xe305, .config = ALC880_3ST_DIG }, |
@@ -2222,12 +2247,16 @@ static struct hda_board_config alc880_cfg_tbl[] = { | |||
2222 | { .pci_subvendor = 0x1043, .pci_subdevice = 0x1113, .config = ALC880_ASUS_DIG }, | 2247 | { .pci_subvendor = 0x1043, .pci_subdevice = 0x1113, .config = ALC880_ASUS_DIG }, |
2223 | { .pci_subvendor = 0x1043, .pci_subdevice = 0x1173, .config = ALC880_ASUS_DIG }, | 2248 | { .pci_subvendor = 0x1043, .pci_subdevice = 0x1173, .config = ALC880_ASUS_DIG }, |
2224 | { .pci_subvendor = 0x1043, .pci_subdevice = 0x1993, .config = ALC880_ASUS }, | 2249 | { .pci_subvendor = 0x1043, .pci_subdevice = 0x1993, .config = ALC880_ASUS }, |
2250 | { .pci_subvendor = 0x1043, .pci_subdevice = 0x10c2, .config = ALC880_ASUS_DIG }, /* Asus W6A */ | ||
2225 | { .pci_subvendor = 0x1043, .pci_subdevice = 0x10c3, .config = ALC880_ASUS_DIG }, | 2251 | { .pci_subvendor = 0x1043, .pci_subdevice = 0x10c3, .config = ALC880_ASUS_DIG }, |
2226 | { .pci_subvendor = 0x1043, .pci_subdevice = 0x1133, .config = ALC880_ASUS }, | 2252 | { .pci_subvendor = 0x1043, .pci_subdevice = 0x1133, .config = ALC880_ASUS }, |
2227 | { .pci_subvendor = 0x1043, .pci_subdevice = 0x1123, .config = ALC880_ASUS_DIG }, | 2253 | { .pci_subvendor = 0x1043, .pci_subdevice = 0x1123, .config = ALC880_ASUS_DIG }, |
2228 | { .pci_subvendor = 0x1043, .pci_subdevice = 0x1143, .config = ALC880_ASUS }, | 2254 | { .pci_subvendor = 0x1043, .pci_subdevice = 0x1143, .config = ALC880_ASUS }, |
2255 | { .modelname = "asus-w1v", .config = ALC880_ASUS_W1V }, | ||
2229 | { .pci_subvendor = 0x1043, .pci_subdevice = 0x10b3, .config = ALC880_ASUS_W1V }, | 2256 | { .pci_subvendor = 0x1043, .pci_subdevice = 0x10b3, .config = ALC880_ASUS_W1V }, |
2257 | { .modelname = "asus-dig", .config = ALC880_ASUS_DIG }, | ||
2230 | { .pci_subvendor = 0x1043, .pci_subdevice = 0x8181, .config = ALC880_ASUS_DIG }, /* ASUS P4GPL-X */ | 2258 | { .pci_subvendor = 0x1043, .pci_subdevice = 0x8181, .config = ALC880_ASUS_DIG }, /* ASUS P4GPL-X */ |
2259 | { .modelname = "asus-dig2", .config = ALC880_ASUS_DIG2 }, | ||
2231 | { .pci_subvendor = 0x1558, .pci_subdevice = 0x5401, .config = ALC880_ASUS_DIG2 }, | 2260 | { .pci_subvendor = 0x1558, .pci_subdevice = 0x5401, .config = ALC880_ASUS_DIG2 }, |
2232 | 2261 | ||
2233 | { .modelname = "uniwill", .config = ALC880_UNIWILL_DIG }, | 2262 | { .modelname = "uniwill", .config = ALC880_UNIWILL_DIG }, |
@@ -2243,6 +2272,7 @@ static struct hda_board_config alc880_cfg_tbl[] = { | |||
2243 | 2272 | ||
2244 | { .modelname = "lg-lw", .config = ALC880_LG_LW }, | 2273 | { .modelname = "lg-lw", .config = ALC880_LG_LW }, |
2245 | { .pci_subvendor = 0x1854, .pci_subdevice = 0x0018, .config = ALC880_LG_LW }, | 2274 | { .pci_subvendor = 0x1854, .pci_subdevice = 0x0018, .config = ALC880_LG_LW }, |
2275 | { .pci_subvendor = 0x1854, .pci_subdevice = 0x0077, .config = ALC880_LG_LW }, | ||
2246 | 2276 | ||
2247 | #ifdef CONFIG_SND_DEBUG | 2277 | #ifdef CONFIG_SND_DEBUG |
2248 | { .modelname = "test", .config = ALC880_TEST }, | 2278 | { .modelname = "test", .config = ALC880_TEST }, |
@@ -2263,6 +2293,7 @@ static struct alc_config_preset alc880_presets[] = { | |||
2263 | .dac_nids = alc880_dac_nids, | 2293 | .dac_nids = alc880_dac_nids, |
2264 | .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes), | 2294 | .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes), |
2265 | .channel_mode = alc880_threestack_modes, | 2295 | .channel_mode = alc880_threestack_modes, |
2296 | .need_dac_fix = 1, | ||
2266 | .input_mux = &alc880_capture_source, | 2297 | .input_mux = &alc880_capture_source, |
2267 | }, | 2298 | }, |
2268 | [ALC880_3ST_DIG] = { | 2299 | [ALC880_3ST_DIG] = { |
@@ -2273,6 +2304,7 @@ static struct alc_config_preset alc880_presets[] = { | |||
2273 | .dig_out_nid = ALC880_DIGOUT_NID, | 2304 | .dig_out_nid = ALC880_DIGOUT_NID, |
2274 | .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes), | 2305 | .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes), |
2275 | .channel_mode = alc880_threestack_modes, | 2306 | .channel_mode = alc880_threestack_modes, |
2307 | .need_dac_fix = 1, | ||
2276 | .input_mux = &alc880_capture_source, | 2308 | .input_mux = &alc880_capture_source, |
2277 | }, | 2309 | }, |
2278 | [ALC880_TCL_S700] = { | 2310 | [ALC880_TCL_S700] = { |
@@ -2365,6 +2397,7 @@ static struct alc_config_preset alc880_presets[] = { | |||
2365 | .dac_nids = alc880_asus_dac_nids, | 2397 | .dac_nids = alc880_asus_dac_nids, |
2366 | .num_channel_mode = ARRAY_SIZE(alc880_asus_modes), | 2398 | .num_channel_mode = ARRAY_SIZE(alc880_asus_modes), |
2367 | .channel_mode = alc880_asus_modes, | 2399 | .channel_mode = alc880_asus_modes, |
2400 | .need_dac_fix = 1, | ||
2368 | .input_mux = &alc880_capture_source, | 2401 | .input_mux = &alc880_capture_source, |
2369 | }, | 2402 | }, |
2370 | [ALC880_ASUS_DIG] = { | 2403 | [ALC880_ASUS_DIG] = { |
@@ -2376,6 +2409,7 @@ static struct alc_config_preset alc880_presets[] = { | |||
2376 | .dig_out_nid = ALC880_DIGOUT_NID, | 2409 | .dig_out_nid = ALC880_DIGOUT_NID, |
2377 | .num_channel_mode = ARRAY_SIZE(alc880_asus_modes), | 2410 | .num_channel_mode = ARRAY_SIZE(alc880_asus_modes), |
2378 | .channel_mode = alc880_asus_modes, | 2411 | .channel_mode = alc880_asus_modes, |
2412 | .need_dac_fix = 1, | ||
2379 | .input_mux = &alc880_capture_source, | 2413 | .input_mux = &alc880_capture_source, |
2380 | }, | 2414 | }, |
2381 | [ALC880_ASUS_DIG2] = { | 2415 | [ALC880_ASUS_DIG2] = { |
@@ -2387,6 +2421,7 @@ static struct alc_config_preset alc880_presets[] = { | |||
2387 | .dig_out_nid = ALC880_DIGOUT_NID, | 2421 | .dig_out_nid = ALC880_DIGOUT_NID, |
2388 | .num_channel_mode = ARRAY_SIZE(alc880_asus_modes), | 2422 | .num_channel_mode = ARRAY_SIZE(alc880_asus_modes), |
2389 | .channel_mode = alc880_asus_modes, | 2423 | .channel_mode = alc880_asus_modes, |
2424 | .need_dac_fix = 1, | ||
2390 | .input_mux = &alc880_capture_source, | 2425 | .input_mux = &alc880_capture_source, |
2391 | }, | 2426 | }, |
2392 | [ALC880_ASUS_W1V] = { | 2427 | [ALC880_ASUS_W1V] = { |
@@ -2398,6 +2433,7 @@ static struct alc_config_preset alc880_presets[] = { | |||
2398 | .dig_out_nid = ALC880_DIGOUT_NID, | 2433 | .dig_out_nid = ALC880_DIGOUT_NID, |
2399 | .num_channel_mode = ARRAY_SIZE(alc880_asus_modes), | 2434 | .num_channel_mode = ARRAY_SIZE(alc880_asus_modes), |
2400 | .channel_mode = alc880_asus_modes, | 2435 | .channel_mode = alc880_asus_modes, |
2436 | .need_dac_fix = 1, | ||
2401 | .input_mux = &alc880_capture_source, | 2437 | .input_mux = &alc880_capture_source, |
2402 | }, | 2438 | }, |
2403 | [ALC880_UNIWILL_DIG] = { | 2439 | [ALC880_UNIWILL_DIG] = { |
@@ -2408,6 +2444,7 @@ static struct alc_config_preset alc880_presets[] = { | |||
2408 | .dig_out_nid = ALC880_DIGOUT_NID, | 2444 | .dig_out_nid = ALC880_DIGOUT_NID, |
2409 | .num_channel_mode = ARRAY_SIZE(alc880_asus_modes), | 2445 | .num_channel_mode = ARRAY_SIZE(alc880_asus_modes), |
2410 | .channel_mode = alc880_asus_modes, | 2446 | .channel_mode = alc880_asus_modes, |
2447 | .need_dac_fix = 1, | ||
2411 | .input_mux = &alc880_capture_source, | 2448 | .input_mux = &alc880_capture_source, |
2412 | }, | 2449 | }, |
2413 | [ALC880_CLEVO] = { | 2450 | [ALC880_CLEVO] = { |
@@ -2419,6 +2456,7 @@ static struct alc_config_preset alc880_presets[] = { | |||
2419 | .hp_nid = 0x03, | 2456 | .hp_nid = 0x03, |
2420 | .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes), | 2457 | .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes), |
2421 | .channel_mode = alc880_threestack_modes, | 2458 | .channel_mode = alc880_threestack_modes, |
2459 | .need_dac_fix = 1, | ||
2422 | .input_mux = &alc880_capture_source, | 2460 | .input_mux = &alc880_capture_source, |
2423 | }, | 2461 | }, |
2424 | [ALC880_LG] = { | 2462 | [ALC880_LG] = { |
@@ -2430,6 +2468,7 @@ static struct alc_config_preset alc880_presets[] = { | |||
2430 | .dig_out_nid = ALC880_DIGOUT_NID, | 2468 | .dig_out_nid = ALC880_DIGOUT_NID, |
2431 | .num_channel_mode = ARRAY_SIZE(alc880_lg_ch_modes), | 2469 | .num_channel_mode = ARRAY_SIZE(alc880_lg_ch_modes), |
2432 | .channel_mode = alc880_lg_ch_modes, | 2470 | .channel_mode = alc880_lg_ch_modes, |
2471 | .need_dac_fix = 1, | ||
2433 | .input_mux = &alc880_lg_capture_source, | 2472 | .input_mux = &alc880_lg_capture_source, |
2434 | .unsol_event = alc880_lg_unsol_event, | 2473 | .unsol_event = alc880_lg_unsol_event, |
2435 | .init_hook = alc880_lg_automute, | 2474 | .init_hook = alc880_lg_automute, |
@@ -2714,7 +2753,7 @@ static void alc880_auto_init_extra_out(struct hda_codec *codec) | |||
2714 | pin = spec->autocfg.speaker_pins[0]; | 2753 | pin = spec->autocfg.speaker_pins[0]; |
2715 | if (pin) /* connect to front */ | 2754 | if (pin) /* connect to front */ |
2716 | alc880_auto_set_output_and_unmute(codec, pin, PIN_OUT, 0); | 2755 | alc880_auto_set_output_and_unmute(codec, pin, PIN_OUT, 0); |
2717 | pin = spec->autocfg.hp_pin; | 2756 | pin = spec->autocfg.hp_pins[0]; |
2718 | if (pin) /* connect to front */ | 2757 | if (pin) /* connect to front */ |
2719 | alc880_auto_set_output_and_unmute(codec, pin, PIN_HP, 0); | 2758 | alc880_auto_set_output_and_unmute(codec, pin, PIN_HP, 0); |
2720 | } | 2759 | } |
@@ -2755,7 +2794,7 @@ static int alc880_parse_auto_config(struct hda_codec *codec) | |||
2755 | (err = alc880_auto_create_extra_out(spec, | 2794 | (err = alc880_auto_create_extra_out(spec, |
2756 | spec->autocfg.speaker_pins[0], | 2795 | spec->autocfg.speaker_pins[0], |
2757 | "Speaker")) < 0 || | 2796 | "Speaker")) < 0 || |
2758 | (err = alc880_auto_create_extra_out(spec, spec->autocfg.hp_pin, | 2797 | (err = alc880_auto_create_extra_out(spec, spec->autocfg.hp_pins[0], |
2759 | "Headphone")) < 0 || | 2798 | "Headphone")) < 0 || |
2760 | (err = alc880_auto_create_analog_input_ctls(spec, &spec->autocfg)) < 0) | 2799 | (err = alc880_auto_create_analog_input_ctls(spec, &spec->autocfg)) < 0) |
2761 | return err; | 2800 | return err; |
@@ -3697,7 +3736,7 @@ static int alc260_auto_create_multi_out_ctls(struct alc_spec *spec, | |||
3697 | return err; | 3736 | return err; |
3698 | } | 3737 | } |
3699 | 3738 | ||
3700 | nid = cfg->hp_pin; | 3739 | nid = cfg->hp_pins[0]; |
3701 | if (nid) { | 3740 | if (nid) { |
3702 | err = alc260_add_playback_controls(spec, nid, "Headphone"); | 3741 | err = alc260_add_playback_controls(spec, nid, "Headphone"); |
3703 | if (err < 0) | 3742 | if (err < 0) |
@@ -3767,7 +3806,7 @@ static void alc260_auto_init_multi_out(struct hda_codec *codec) | |||
3767 | if (nid) | 3806 | if (nid) |
3768 | alc260_auto_set_output_and_unmute(codec, nid, PIN_OUT, 0); | 3807 | alc260_auto_set_output_and_unmute(codec, nid, PIN_OUT, 0); |
3769 | 3808 | ||
3770 | nid = spec->autocfg.hp_pin; | 3809 | nid = spec->autocfg.hp_pins[0]; |
3771 | if (nid) | 3810 | if (nid) |
3772 | alc260_auto_set_output_and_unmute(codec, nid, PIN_OUT, 0); | 3811 | alc260_auto_set_output_and_unmute(codec, nid, PIN_OUT, 0); |
3773 | } | 3812 | } |
@@ -3900,7 +3939,8 @@ static struct hda_board_config alc260_cfg_tbl[] = { | |||
3900 | { .pci_subvendor = 0x152d, .pci_subdevice = 0x0729, | 3939 | { .pci_subvendor = 0x152d, .pci_subdevice = 0x0729, |
3901 | .config = ALC260_BASIC }, /* CTL Travel Master U553W */ | 3940 | .config = ALC260_BASIC }, /* CTL Travel Master U553W */ |
3902 | { .modelname = "hp", .config = ALC260_HP }, | 3941 | { .modelname = "hp", .config = ALC260_HP }, |
3903 | { .pci_subvendor = 0x103c, .pci_subdevice = 0x3010, .config = ALC260_HP }, | 3942 | { .modelname = "hp-3013", .config = ALC260_HP_3013 }, |
3943 | { .pci_subvendor = 0x103c, .pci_subdevice = 0x3010, .config = ALC260_HP_3013 }, | ||
3904 | { .pci_subvendor = 0x103c, .pci_subdevice = 0x3011, .config = ALC260_HP }, | 3944 | { .pci_subvendor = 0x103c, .pci_subdevice = 0x3011, .config = ALC260_HP }, |
3905 | { .pci_subvendor = 0x103c, .pci_subdevice = 0x3012, .config = ALC260_HP_3013 }, | 3945 | { .pci_subvendor = 0x103c, .pci_subdevice = 0x3012, .config = ALC260_HP_3013 }, |
3906 | { .pci_subvendor = 0x103c, .pci_subdevice = 0x3013, .config = ALC260_HP_3013 }, | 3946 | { .pci_subvendor = 0x103c, .pci_subdevice = 0x3013, .config = ALC260_HP_3013 }, |
@@ -4266,6 +4306,13 @@ static struct hda_verb alc882_init_verbs[] = { | |||
4266 | { } | 4306 | { } |
4267 | }; | 4307 | }; |
4268 | 4308 | ||
4309 | static struct hda_verb alc882_eapd_verbs[] = { | ||
4310 | /* change to EAPD mode */ | ||
4311 | {0x20, AC_VERB_SET_COEF_INDEX, 0x07}, | ||
4312 | {0x20, AC_VERB_SET_PROC_COEF, 0x3060}, | ||
4313 | { } | ||
4314 | }; | ||
4315 | |||
4269 | /* | 4316 | /* |
4270 | * generic initialization of ADC, input mixers and output mixers | 4317 | * generic initialization of ADC, input mixers and output mixers |
4271 | */ | 4318 | */ |
@@ -4397,6 +4444,9 @@ static struct hda_board_config alc882_cfg_tbl[] = { | |||
4397 | .config = ALC882_6ST_DIG }, /* Foxconn */ | 4444 | .config = ALC882_6ST_DIG }, /* Foxconn */ |
4398 | { .pci_subvendor = 0x1019, .pci_subdevice = 0x6668, | 4445 | { .pci_subvendor = 0x1019, .pci_subdevice = 0x6668, |
4399 | .config = ALC882_6ST_DIG }, /* ECS to Intel*/ | 4446 | .config = ALC882_6ST_DIG }, /* ECS to Intel*/ |
4447 | { .modelname = "arima", .config = ALC882_ARIMA }, | ||
4448 | { .pci_subvendor = 0x161f, .pci_subdevice = 0x2054, | ||
4449 | .config = ALC882_ARIMA }, /* Arima W820Di1 */ | ||
4400 | { .modelname = "auto", .config = ALC882_AUTO }, | 4450 | { .modelname = "auto", .config = ALC882_AUTO }, |
4401 | {} | 4451 | {} |
4402 | }; | 4452 | }; |
@@ -4411,6 +4461,7 @@ static struct alc_config_preset alc882_presets[] = { | |||
4411 | .dig_in_nid = ALC882_DIGIN_NID, | 4461 | .dig_in_nid = ALC882_DIGIN_NID, |
4412 | .num_channel_mode = ARRAY_SIZE(alc882_ch_modes), | 4462 | .num_channel_mode = ARRAY_SIZE(alc882_ch_modes), |
4413 | .channel_mode = alc882_ch_modes, | 4463 | .channel_mode = alc882_ch_modes, |
4464 | .need_dac_fix = 1, | ||
4414 | .input_mux = &alc882_capture_source, | 4465 | .input_mux = &alc882_capture_source, |
4415 | }, | 4466 | }, |
4416 | [ALC882_6ST_DIG] = { | 4467 | [ALC882_6ST_DIG] = { |
@@ -4424,6 +4475,15 @@ static struct alc_config_preset alc882_presets[] = { | |||
4424 | .channel_mode = alc882_sixstack_modes, | 4475 | .channel_mode = alc882_sixstack_modes, |
4425 | .input_mux = &alc882_capture_source, | 4476 | .input_mux = &alc882_capture_source, |
4426 | }, | 4477 | }, |
4478 | [ALC882_ARIMA] = { | ||
4479 | .mixers = { alc882_base_mixer, alc882_chmode_mixer }, | ||
4480 | .init_verbs = { alc882_init_verbs, alc882_eapd_verbs }, | ||
4481 | .num_dacs = ARRAY_SIZE(alc882_dac_nids), | ||
4482 | .dac_nids = alc882_dac_nids, | ||
4483 | .num_channel_mode = ARRAY_SIZE(alc882_sixstack_modes), | ||
4484 | .channel_mode = alc882_sixstack_modes, | ||
4485 | .input_mux = &alc882_capture_source, | ||
4486 | }, | ||
4427 | }; | 4487 | }; |
4428 | 4488 | ||
4429 | 4489 | ||
@@ -4466,7 +4526,7 @@ static void alc882_auto_init_hp_out(struct hda_codec *codec) | |||
4466 | struct alc_spec *spec = codec->spec; | 4526 | struct alc_spec *spec = codec->spec; |
4467 | hda_nid_t pin; | 4527 | hda_nid_t pin; |
4468 | 4528 | ||
4469 | pin = spec->autocfg.hp_pin; | 4529 | pin = spec->autocfg.hp_pins[0]; |
4470 | if (pin) /* connect to front */ | 4530 | if (pin) /* connect to front */ |
4471 | alc882_auto_set_output_and_unmute(codec, pin, PIN_HP, 0); /* use dac 0 */ | 4531 | alc882_auto_set_output_and_unmute(codec, pin, PIN_HP, 0); /* use dac 0 */ |
4472 | } | 4532 | } |
@@ -4999,16 +5059,23 @@ static struct snd_kcontrol_new alc883_capture_mixer[] = { | |||
4999 | */ | 5059 | */ |
5000 | static struct hda_board_config alc883_cfg_tbl[] = { | 5060 | static struct hda_board_config alc883_cfg_tbl[] = { |
5001 | { .modelname = "3stack-dig", .config = ALC883_3ST_2ch_DIG }, | 5061 | { .modelname = "3stack-dig", .config = ALC883_3ST_2ch_DIG }, |
5062 | { .modelname = "3stack-6ch-dig", .config = ALC883_3ST_6ch_DIG }, | ||
5063 | { .pci_subvendor = 0x1019, .pci_subdevice = 0x6668, | ||
5064 | .config = ALC883_3ST_6ch_DIG }, /* ECS to Intel*/ | ||
5065 | { .modelname = "3stack-6ch", .config = ALC883_3ST_6ch }, | ||
5066 | { .pci_subvendor = 0x108e, .pci_subdevice = 0x534d, | ||
5067 | .config = ALC883_3ST_6ch }, | ||
5068 | { .pci_subvendor = 0x8086, .pci_subdevice = 0xd601, | ||
5069 | .config = ALC883_3ST_6ch }, /* D102GGC */ | ||
5002 | { .modelname = "6stack-dig", .config = ALC883_6ST_DIG }, | 5070 | { .modelname = "6stack-dig", .config = ALC883_6ST_DIG }, |
5003 | { .modelname = "6stack-dig-demo", .config = ALC888_DEMO_BOARD }, | ||
5004 | { .pci_subvendor = 0x1462, .pci_subdevice = 0x6668, | 5071 | { .pci_subvendor = 0x1462, .pci_subdevice = 0x6668, |
5005 | .config = ALC883_6ST_DIG }, /* MSI */ | 5072 | .config = ALC883_6ST_DIG }, /* MSI */ |
5006 | { .pci_subvendor = 0x105b, .pci_subdevice = 0x6668, | 5073 | { .pci_subvendor = 0x105b, .pci_subdevice = 0x6668, |
5007 | .config = ALC883_6ST_DIG }, /* Foxconn */ | 5074 | .config = ALC883_6ST_DIG }, /* Foxconn */ |
5008 | { .pci_subvendor = 0x1019, .pci_subdevice = 0x6668, | 5075 | { .modelname = "6stack-dig-demo", .config = ALC888_DEMO_BOARD }, |
5009 | .config = ALC883_3ST_6ch_DIG }, /* ECS to Intel*/ | 5076 | { .modelname = "acer", .config = ALC883_ACER }, |
5010 | { .pci_subvendor = 0x108e, .pci_subdevice = 0x534d, | 5077 | { .pci_subvendor = 0x1025, .pci_subdevice = 0/*0x0102*/, |
5011 | .config = ALC883_3ST_6ch }, | 5078 | .config = ALC883_ACER }, |
5012 | { .modelname = "auto", .config = ALC883_AUTO }, | 5079 | { .modelname = "auto", .config = ALC883_AUTO }, |
5013 | {} | 5080 | {} |
5014 | }; | 5081 | }; |
@@ -5038,6 +5105,7 @@ static struct alc_config_preset alc883_presets[] = { | |||
5038 | .dig_in_nid = ALC883_DIGIN_NID, | 5105 | .dig_in_nid = ALC883_DIGIN_NID, |
5039 | .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes), | 5106 | .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes), |
5040 | .channel_mode = alc883_3ST_6ch_modes, | 5107 | .channel_mode = alc883_3ST_6ch_modes, |
5108 | .need_dac_fix = 1, | ||
5041 | .input_mux = &alc883_capture_source, | 5109 | .input_mux = &alc883_capture_source, |
5042 | }, | 5110 | }, |
5043 | [ALC883_3ST_6ch] = { | 5111 | [ALC883_3ST_6ch] = { |
@@ -5049,6 +5117,7 @@ static struct alc_config_preset alc883_presets[] = { | |||
5049 | .adc_nids = alc883_adc_nids, | 5117 | .adc_nids = alc883_adc_nids, |
5050 | .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes), | 5118 | .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes), |
5051 | .channel_mode = alc883_3ST_6ch_modes, | 5119 | .channel_mode = alc883_3ST_6ch_modes, |
5120 | .need_dac_fix = 1, | ||
5052 | .input_mux = &alc883_capture_source, | 5121 | .input_mux = &alc883_capture_source, |
5053 | }, | 5122 | }, |
5054 | [ALC883_6ST_DIG] = { | 5123 | [ALC883_6ST_DIG] = { |
@@ -5077,6 +5146,23 @@ static struct alc_config_preset alc883_presets[] = { | |||
5077 | .channel_mode = alc883_sixstack_modes, | 5146 | .channel_mode = alc883_sixstack_modes, |
5078 | .input_mux = &alc883_capture_source, | 5147 | .input_mux = &alc883_capture_source, |
5079 | }, | 5148 | }, |
5149 | [ALC883_ACER] = { | ||
5150 | .mixers = { alc883_base_mixer, | ||
5151 | alc883_chmode_mixer }, | ||
5152 | /* On TravelMate laptops, GPIO 0 enables the internal speaker | ||
5153 | * and the headphone jack. Turn this on and rely on the | ||
5154 | * standard mute methods whenever the user wants to turn | ||
5155 | * these outputs off. | ||
5156 | */ | ||
5157 | .init_verbs = { alc883_init_verbs, alc880_gpio1_init_verbs }, | ||
5158 | .num_dacs = ARRAY_SIZE(alc883_dac_nids), | ||
5159 | .dac_nids = alc883_dac_nids, | ||
5160 | .num_adc_nids = ARRAY_SIZE(alc883_adc_nids), | ||
5161 | .adc_nids = alc883_adc_nids, | ||
5162 | .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes), | ||
5163 | .channel_mode = alc883_3ST_2ch_modes, | ||
5164 | .input_mux = &alc883_capture_source, | ||
5165 | }, | ||
5080 | }; | 5166 | }; |
5081 | 5167 | ||
5082 | 5168 | ||
@@ -5121,7 +5207,7 @@ static void alc883_auto_init_hp_out(struct hda_codec *codec) | |||
5121 | struct alc_spec *spec = codec->spec; | 5207 | struct alc_spec *spec = codec->spec; |
5122 | hda_nid_t pin; | 5208 | hda_nid_t pin; |
5123 | 5209 | ||
5124 | pin = spec->autocfg.hp_pin; | 5210 | pin = spec->autocfg.hp_pins[0]; |
5125 | if (pin) /* connect to front */ | 5211 | if (pin) /* connect to front */ |
5126 | /* use dac 0 */ | 5212 | /* use dac 0 */ |
5127 | alc883_auto_set_output_and_unmute(codec, pin, PIN_HP, 0); | 5213 | alc883_auto_set_output_and_unmute(codec, pin, PIN_HP, 0); |
@@ -5217,8 +5303,10 @@ static int patch_alc883(struct hda_codec *codec) | |||
5217 | spec->stream_digital_playback = &alc883_pcm_digital_playback; | 5303 | spec->stream_digital_playback = &alc883_pcm_digital_playback; |
5218 | spec->stream_digital_capture = &alc883_pcm_digital_capture; | 5304 | spec->stream_digital_capture = &alc883_pcm_digital_capture; |
5219 | 5305 | ||
5220 | spec->adc_nids = alc883_adc_nids; | 5306 | if (! spec->adc_nids && spec->input_mux) { |
5221 | spec->num_adc_nids = ARRAY_SIZE(alc883_adc_nids); | 5307 | spec->adc_nids = alc883_adc_nids; |
5308 | spec->num_adc_nids = ARRAY_SIZE(alc883_adc_nids); | ||
5309 | } | ||
5222 | 5310 | ||
5223 | codec->patch_ops = alc_patch_ops; | 5311 | codec->patch_ops = alc_patch_ops; |
5224 | if (board_config == ALC883_AUTO) | 5312 | if (board_config == ALC883_AUTO) |
@@ -5481,6 +5569,7 @@ static struct snd_kcontrol_new alc262_fujitsu_mixer[] = { | |||
5481 | .info = snd_hda_mixer_amp_volume_info, | 5569 | .info = snd_hda_mixer_amp_volume_info, |
5482 | .get = snd_hda_mixer_amp_volume_get, | 5570 | .get = snd_hda_mixer_amp_volume_get, |
5483 | .put = alc262_fujitsu_master_vol_put, | 5571 | .put = alc262_fujitsu_master_vol_put, |
5572 | .tlv = { .c = snd_hda_mixer_amp_tlv }, | ||
5484 | .private_value = HDA_COMPOSE_AMP_VAL(0x0c, 3, 0, HDA_OUTPUT), | 5573 | .private_value = HDA_COMPOSE_AMP_VAL(0x0c, 3, 0, HDA_OUTPUT), |
5485 | }, | 5574 | }, |
5486 | { | 5575 | { |
@@ -5499,6 +5588,13 @@ static struct snd_kcontrol_new alc262_fujitsu_mixer[] = { | |||
5499 | { } /* end */ | 5588 | { } /* end */ |
5500 | }; | 5589 | }; |
5501 | 5590 | ||
5591 | /* additional init verbs for Benq laptops */ | ||
5592 | static struct hda_verb alc262_EAPD_verbs[] = { | ||
5593 | {0x20, AC_VERB_SET_COEF_INDEX, 0x07}, | ||
5594 | {0x20, AC_VERB_SET_PROC_COEF, 0x3070}, | ||
5595 | {} | ||
5596 | }; | ||
5597 | |||
5502 | /* add playback controls from the parsed DAC table */ | 5598 | /* add playback controls from the parsed DAC table */ |
5503 | static int alc262_auto_create_multi_out_ctls(struct alc_spec *spec, const struct auto_pin_cfg *cfg) | 5599 | static int alc262_auto_create_multi_out_ctls(struct alc_spec *spec, const struct auto_pin_cfg *cfg) |
5504 | { | 5600 | { |
@@ -5534,7 +5630,7 @@ static int alc262_auto_create_multi_out_ctls(struct alc_spec *spec, const struct | |||
5534 | return err; | 5630 | return err; |
5535 | } | 5631 | } |
5536 | } | 5632 | } |
5537 | nid = cfg->hp_pin; | 5633 | nid = cfg->hp_pins[0]; |
5538 | if (nid) { | 5634 | if (nid) { |
5539 | /* spec->multiout.hp_nid = 2; */ | 5635 | /* spec->multiout.hp_nid = 2; */ |
5540 | if (nid == 0x16) { | 5636 | if (nid == 0x16) { |
@@ -5769,6 +5865,7 @@ static struct hda_board_config alc262_cfg_tbl[] = { | |||
5769 | { .modelname = "fujitsu", .config = ALC262_FUJITSU }, | 5865 | { .modelname = "fujitsu", .config = ALC262_FUJITSU }, |
5770 | { .pci_subvendor = 0x10cf, .pci_subdevice = 0x1397, | 5866 | { .pci_subvendor = 0x10cf, .pci_subdevice = 0x1397, |
5771 | .config = ALC262_FUJITSU }, | 5867 | .config = ALC262_FUJITSU }, |
5868 | { .modelname = "hp-bpc", .config = ALC262_HP_BPC }, | ||
5772 | { .pci_subvendor = 0x103c, .pci_subdevice = 0x208c, | 5869 | { .pci_subvendor = 0x103c, .pci_subdevice = 0x208c, |
5773 | .config = ALC262_HP_BPC }, /* xw4400 */ | 5870 | .config = ALC262_HP_BPC }, /* xw4400 */ |
5774 | { .pci_subvendor = 0x103c, .pci_subdevice = 0x3014, | 5871 | { .pci_subvendor = 0x103c, .pci_subdevice = 0x3014, |
@@ -5777,6 +5874,9 @@ static struct hda_board_config alc262_cfg_tbl[] = { | |||
5777 | .config = ALC262_HP_BPC }, /* xw8400 */ | 5874 | .config = ALC262_HP_BPC }, /* xw8400 */ |
5778 | { .pci_subvendor = 0x103c, .pci_subdevice = 0x12fe, | 5875 | { .pci_subvendor = 0x103c, .pci_subdevice = 0x12fe, |
5779 | .config = ALC262_HP_BPC }, /* xw9400 */ | 5876 | .config = ALC262_HP_BPC }, /* xw9400 */ |
5877 | { .modelname = "benq", .config = ALC262_BENQ_ED8 }, | ||
5878 | { .pci_subvendor = 0x17ff, .pci_subdevice = 0x0560, | ||
5879 | .config = ALC262_BENQ_ED8 }, | ||
5780 | { .modelname = "auto", .config = ALC262_AUTO }, | 5880 | { .modelname = "auto", .config = ALC262_AUTO }, |
5781 | {} | 5881 | {} |
5782 | }; | 5882 | }; |
@@ -5814,6 +5914,16 @@ static struct alc_config_preset alc262_presets[] = { | |||
5814 | .channel_mode = alc262_modes, | 5914 | .channel_mode = alc262_modes, |
5815 | .input_mux = &alc262_HP_capture_source, | 5915 | .input_mux = &alc262_HP_capture_source, |
5816 | }, | 5916 | }, |
5917 | [ALC262_BENQ_ED8] = { | ||
5918 | .mixers = { alc262_base_mixer }, | ||
5919 | .init_verbs = { alc262_init_verbs, alc262_EAPD_verbs }, | ||
5920 | .num_dacs = ARRAY_SIZE(alc262_dac_nids), | ||
5921 | .dac_nids = alc262_dac_nids, | ||
5922 | .hp_nid = 0x03, | ||
5923 | .num_channel_mode = ARRAY_SIZE(alc262_modes), | ||
5924 | .channel_mode = alc262_modes, | ||
5925 | .input_mux = &alc262_capture_source, | ||
5926 | }, | ||
5817 | }; | 5927 | }; |
5818 | 5928 | ||
5819 | static int patch_alc262(struct hda_codec *codec) | 5929 | static int patch_alc262(struct hda_codec *codec) |
@@ -5942,6 +6052,23 @@ static struct hda_channel_mode alc861_threestack_modes[2] = { | |||
5942 | { 2, alc861_threestack_ch2_init }, | 6052 | { 2, alc861_threestack_ch2_init }, |
5943 | { 6, alc861_threestack_ch6_init }, | 6053 | { 6, alc861_threestack_ch6_init }, |
5944 | }; | 6054 | }; |
6055 | /* Set mic1 as input and unmute the mixer */ | ||
6056 | static struct hda_verb alc861_uniwill_m31_ch2_init[] = { | ||
6057 | { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 }, | ||
6058 | { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x01 << 8)) }, /*mic*/ | ||
6059 | { } /* end */ | ||
6060 | }; | ||
6061 | /* Set mic1 as output and mute mixer */ | ||
6062 | static struct hda_verb alc861_uniwill_m31_ch4_init[] = { | ||
6063 | { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 }, | ||
6064 | { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8)) }, /*mic*/ | ||
6065 | { } /* end */ | ||
6066 | }; | ||
6067 | |||
6068 | static struct hda_channel_mode alc861_uniwill_m31_modes[2] = { | ||
6069 | { 2, alc861_uniwill_m31_ch2_init }, | ||
6070 | { 4, alc861_uniwill_m31_ch4_init }, | ||
6071 | }; | ||
5945 | 6072 | ||
5946 | /* patch-ALC861 */ | 6073 | /* patch-ALC861 */ |
5947 | 6074 | ||
@@ -6020,6 +6147,47 @@ static struct snd_kcontrol_new alc861_3ST_mixer[] = { | |||
6020 | }, | 6147 | }, |
6021 | { } /* end */ | 6148 | { } /* end */ |
6022 | }; | 6149 | }; |
6150 | static struct snd_kcontrol_new alc861_uniwill_m31_mixer[] = { | ||
6151 | /* output mixer control */ | ||
6152 | HDA_CODEC_MUTE("Front Playback Switch", 0x03, 0x0, HDA_OUTPUT), | ||
6153 | HDA_CODEC_MUTE("Surround Playback Switch", 0x06, 0x0, HDA_OUTPUT), | ||
6154 | HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x05, 1, 0x0, HDA_OUTPUT), | ||
6155 | HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x05, 2, 0x0, HDA_OUTPUT), | ||
6156 | /*HDA_CODEC_MUTE("Side Playback Switch", 0x04, 0x0, HDA_OUTPUT), */ | ||
6157 | |||
6158 | /* Input mixer control */ | ||
6159 | /* HDA_CODEC_VOLUME("Input Playback Volume", 0x15, 0x0, HDA_OUTPUT), | ||
6160 | HDA_CODEC_MUTE("Input Playback Switch", 0x15, 0x0, HDA_OUTPUT), */ | ||
6161 | HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_INPUT), | ||
6162 | HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_INPUT), | ||
6163 | HDA_CODEC_VOLUME("Line Playback Volume", 0x15, 0x02, HDA_INPUT), | ||
6164 | HDA_CODEC_MUTE("Line Playback Switch", 0x15, 0x02, HDA_INPUT), | ||
6165 | HDA_CODEC_VOLUME("Mic Playback Volume", 0x15, 0x01, HDA_INPUT), | ||
6166 | HDA_CODEC_MUTE("Mic Playback Switch", 0x15, 0x01, HDA_INPUT), | ||
6167 | HDA_CODEC_MUTE("Front Mic Playback Switch", 0x10, 0x01, HDA_OUTPUT), | ||
6168 | HDA_CODEC_MUTE("Headphone Playback Switch", 0x1a, 0x03, HDA_INPUT), | ||
6169 | |||
6170 | /* Capture mixer control */ | ||
6171 | HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT), | ||
6172 | HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT), | ||
6173 | { | ||
6174 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
6175 | .name = "Capture Source", | ||
6176 | .count = 1, | ||
6177 | .info = alc_mux_enum_info, | ||
6178 | .get = alc_mux_enum_get, | ||
6179 | .put = alc_mux_enum_put, | ||
6180 | }, | ||
6181 | { | ||
6182 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
6183 | .name = "Channel Mode", | ||
6184 | .info = alc_ch_mode_info, | ||
6185 | .get = alc_ch_mode_get, | ||
6186 | .put = alc_ch_mode_put, | ||
6187 | .private_value = ARRAY_SIZE(alc861_uniwill_m31_modes), | ||
6188 | }, | ||
6189 | { } /* end */ | ||
6190 | }; | ||
6023 | 6191 | ||
6024 | /* | 6192 | /* |
6025 | * generic initialization of ADC, input mixers and output mixers | 6193 | * generic initialization of ADC, input mixers and output mixers |
@@ -6148,6 +6316,67 @@ static struct hda_verb alc861_threestack_init_verbs[] = { | |||
6148 | {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, | 6316 | {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, |
6149 | { } | 6317 | { } |
6150 | }; | 6318 | }; |
6319 | |||
6320 | static struct hda_verb alc861_uniwill_m31_init_verbs[] = { | ||
6321 | /* | ||
6322 | * Unmute ADC0 and set the default input to mic-in | ||
6323 | */ | ||
6324 | /* port-A for surround (rear panel) */ | ||
6325 | { 0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 }, | ||
6326 | /* port-B for mic-in (rear panel) with vref */ | ||
6327 | { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 }, | ||
6328 | /* port-C for line-in (rear panel) */ | ||
6329 | { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 }, | ||
6330 | /* port-D for Front */ | ||
6331 | { 0x0b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 }, | ||
6332 | { 0x0b, AC_VERB_SET_CONNECT_SEL, 0x00 }, | ||
6333 | /* port-E for HP out (front panel) */ | ||
6334 | { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 }, // this has to be set to VREF80 | ||
6335 | /* route front PCM to HP */ | ||
6336 | { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x01 }, | ||
6337 | /* port-F for mic-in (front panel) with vref */ | ||
6338 | { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 }, | ||
6339 | /* port-G for CLFE (rear panel) */ | ||
6340 | { 0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 }, | ||
6341 | /* port-H for side (rear panel) */ | ||
6342 | { 0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 }, | ||
6343 | /* CD-in */ | ||
6344 | { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 }, | ||
6345 | /* route front mic to ADC1*/ | ||
6346 | {0x08, AC_VERB_SET_CONNECT_SEL, 0x00}, | ||
6347 | {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | ||
6348 | /* Unmute DAC0~3 & spdif out*/ | ||
6349 | {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, | ||
6350 | {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, | ||
6351 | {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, | ||
6352 | {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, | ||
6353 | {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, | ||
6354 | |||
6355 | /* Unmute Mixer 14 (mic) 1c (Line in)*/ | ||
6356 | {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | ||
6357 | {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, | ||
6358 | {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | ||
6359 | {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, | ||
6360 | |||
6361 | /* Unmute Stereo Mixer 15 */ | ||
6362 | {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | ||
6363 | {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, | ||
6364 | {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, | ||
6365 | {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c }, //Output 0~12 step | ||
6366 | |||
6367 | {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | ||
6368 | {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, | ||
6369 | {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | ||
6370 | {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, | ||
6371 | {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | ||
6372 | {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, | ||
6373 | {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | ||
6374 | {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, | ||
6375 | {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)}, // hp used DAC 3 (Front) | ||
6376 | {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, | ||
6377 | { } | ||
6378 | }; | ||
6379 | |||
6151 | /* | 6380 | /* |
6152 | * generic initialization of ADC, input mixers and output mixers | 6381 | * generic initialization of ADC, input mixers and output mixers |
6153 | */ | 6382 | */ |
@@ -6401,7 +6630,7 @@ static void alc861_auto_init_hp_out(struct hda_codec *codec) | |||
6401 | struct alc_spec *spec = codec->spec; | 6630 | struct alc_spec *spec = codec->spec; |
6402 | hda_nid_t pin; | 6631 | hda_nid_t pin; |
6403 | 6632 | ||
6404 | pin = spec->autocfg.hp_pin; | 6633 | pin = spec->autocfg.hp_pins[0]; |
6405 | if (pin) /* connect to front */ | 6634 | if (pin) /* connect to front */ |
6406 | alc861_auto_set_output_and_unmute(codec, pin, PIN_HP, spec->multiout.dac_nids[0]); | 6635 | alc861_auto_set_output_and_unmute(codec, pin, PIN_HP, spec->multiout.dac_nids[0]); |
6407 | } | 6636 | } |
@@ -6436,7 +6665,7 @@ static int alc861_parse_auto_config(struct hda_codec *codec) | |||
6436 | 6665 | ||
6437 | if ((err = alc861_auto_fill_dac_nids(spec, &spec->autocfg)) < 0 || | 6666 | if ((err = alc861_auto_fill_dac_nids(spec, &spec->autocfg)) < 0 || |
6438 | (err = alc861_auto_create_multi_out_ctls(spec, &spec->autocfg)) < 0 || | 6667 | (err = alc861_auto_create_multi_out_ctls(spec, &spec->autocfg)) < 0 || |
6439 | (err = alc861_auto_create_hp_ctls(spec, spec->autocfg.hp_pin)) < 0 || | 6668 | (err = alc861_auto_create_hp_ctls(spec, spec->autocfg.hp_pins[0])) < 0 || |
6440 | (err = alc861_auto_create_analog_input_ctls(spec, &spec->autocfg)) < 0) | 6669 | (err = alc861_auto_create_analog_input_ctls(spec, &spec->autocfg)) < 0) |
6441 | return err; | 6670 | return err; |
6442 | 6671 | ||
@@ -6477,10 +6706,14 @@ static struct hda_board_config alc861_cfg_tbl[] = { | |||
6477 | { .modelname = "3stack", .config = ALC861_3ST }, | 6706 | { .modelname = "3stack", .config = ALC861_3ST }, |
6478 | { .pci_subvendor = 0x8086, .pci_subdevice = 0xd600, | 6707 | { .pci_subvendor = 0x8086, .pci_subdevice = 0xd600, |
6479 | .config = ALC861_3ST }, | 6708 | .config = ALC861_3ST }, |
6709 | { .modelname = "3stack-660", .config = ALC660_3ST }, | ||
6480 | { .pci_subvendor = 0x1043, .pci_subdevice = 0x81e7, | 6710 | { .pci_subvendor = 0x1043, .pci_subdevice = 0x81e7, |
6481 | .config = ALC660_3ST }, | 6711 | .config = ALC660_3ST }, |
6482 | { .modelname = "3stack-dig", .config = ALC861_3ST_DIG }, | 6712 | { .modelname = "3stack-dig", .config = ALC861_3ST_DIG }, |
6483 | { .modelname = "6stack-dig", .config = ALC861_6ST_DIG }, | 6713 | { .modelname = "6stack-dig", .config = ALC861_6ST_DIG }, |
6714 | { .modelname = "uniwill-m31", .config = ALC861_UNIWILL_M31}, | ||
6715 | { .pci_subvendor = 0x1584, .pci_subdevice = 0x9072, | ||
6716 | .config = ALC861_UNIWILL_M31 }, | ||
6484 | { .modelname = "auto", .config = ALC861_AUTO }, | 6717 | { .modelname = "auto", .config = ALC861_AUTO }, |
6485 | {} | 6718 | {} |
6486 | }; | 6719 | }; |
@@ -6493,6 +6726,7 @@ static struct alc_config_preset alc861_presets[] = { | |||
6493 | .dac_nids = alc861_dac_nids, | 6726 | .dac_nids = alc861_dac_nids, |
6494 | .num_channel_mode = ARRAY_SIZE(alc861_threestack_modes), | 6727 | .num_channel_mode = ARRAY_SIZE(alc861_threestack_modes), |
6495 | .channel_mode = alc861_threestack_modes, | 6728 | .channel_mode = alc861_threestack_modes, |
6729 | .need_dac_fix = 1, | ||
6496 | .num_adc_nids = ARRAY_SIZE(alc861_adc_nids), | 6730 | .num_adc_nids = ARRAY_SIZE(alc861_adc_nids), |
6497 | .adc_nids = alc861_adc_nids, | 6731 | .adc_nids = alc861_adc_nids, |
6498 | .input_mux = &alc861_capture_source, | 6732 | .input_mux = &alc861_capture_source, |
@@ -6505,6 +6739,7 @@ static struct alc_config_preset alc861_presets[] = { | |||
6505 | .dig_out_nid = ALC861_DIGOUT_NID, | 6739 | .dig_out_nid = ALC861_DIGOUT_NID, |
6506 | .num_channel_mode = ARRAY_SIZE(alc861_threestack_modes), | 6740 | .num_channel_mode = ARRAY_SIZE(alc861_threestack_modes), |
6507 | .channel_mode = alc861_threestack_modes, | 6741 | .channel_mode = alc861_threestack_modes, |
6742 | .need_dac_fix = 1, | ||
6508 | .num_adc_nids = ARRAY_SIZE(alc861_adc_nids), | 6743 | .num_adc_nids = ARRAY_SIZE(alc861_adc_nids), |
6509 | .adc_nids = alc861_adc_nids, | 6744 | .adc_nids = alc861_adc_nids, |
6510 | .input_mux = &alc861_capture_source, | 6745 | .input_mux = &alc861_capture_source, |
@@ -6528,10 +6763,25 @@ static struct alc_config_preset alc861_presets[] = { | |||
6528 | .dac_nids = alc660_dac_nids, | 6763 | .dac_nids = alc660_dac_nids, |
6529 | .num_channel_mode = ARRAY_SIZE(alc861_threestack_modes), | 6764 | .num_channel_mode = ARRAY_SIZE(alc861_threestack_modes), |
6530 | .channel_mode = alc861_threestack_modes, | 6765 | .channel_mode = alc861_threestack_modes, |
6766 | .need_dac_fix = 1, | ||
6767 | .num_adc_nids = ARRAY_SIZE(alc861_adc_nids), | ||
6768 | .adc_nids = alc861_adc_nids, | ||
6769 | .input_mux = &alc861_capture_source, | ||
6770 | }, | ||
6771 | [ALC861_UNIWILL_M31] = { | ||
6772 | .mixers = { alc861_uniwill_m31_mixer }, | ||
6773 | .init_verbs = { alc861_uniwill_m31_init_verbs }, | ||
6774 | .num_dacs = ARRAY_SIZE(alc861_dac_nids), | ||
6775 | .dac_nids = alc861_dac_nids, | ||
6776 | .dig_out_nid = ALC861_DIGOUT_NID, | ||
6777 | .num_channel_mode = ARRAY_SIZE(alc861_uniwill_m31_modes), | ||
6778 | .channel_mode = alc861_uniwill_m31_modes, | ||
6779 | .need_dac_fix = 1, | ||
6531 | .num_adc_nids = ARRAY_SIZE(alc861_adc_nids), | 6780 | .num_adc_nids = ARRAY_SIZE(alc861_adc_nids), |
6532 | .adc_nids = alc861_adc_nids, | 6781 | .adc_nids = alc861_adc_nids, |
6533 | .input_mux = &alc861_capture_source, | 6782 | .input_mux = &alc861_capture_source, |
6534 | }, | 6783 | }, |
6784 | |||
6535 | }; | 6785 | }; |
6536 | 6786 | ||
6537 | 6787 | ||
diff --git a/sound/pci/hda/patch_si3054.c b/sound/pci/hda/patch_si3054.c index 250242cd6c70..76ec3d75fa9e 100644 --- a/sound/pci/hda/patch_si3054.c +++ b/sound/pci/hda/patch_si3054.c | |||
@@ -298,6 +298,7 @@ struct hda_codec_preset snd_hda_preset_si3054[] = { | |||
298 | { .id = 0x163c3055, .name = "Si3054", .patch = patch_si3054 }, | 298 | { .id = 0x163c3055, .name = "Si3054", .patch = patch_si3054 }, |
299 | { .id = 0x163c3155, .name = "Si3054", .patch = patch_si3054 }, | 299 | { .id = 0x163c3155, .name = "Si3054", .patch = patch_si3054 }, |
300 | { .id = 0x11c13026, .name = "Si3054", .patch = patch_si3054 }, | 300 | { .id = 0x11c13026, .name = "Si3054", .patch = patch_si3054 }, |
301 | { .id = 0x10573057, .name = "Si3054", .patch = patch_si3054 }, | ||
301 | {} | 302 | {} |
302 | }; | 303 | }; |
303 | 304 | ||
diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index ea99083a1024..731b7b97ee71 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c | |||
@@ -36,15 +36,15 @@ | |||
36 | 36 | ||
37 | #define NUM_CONTROL_ALLOC 32 | 37 | #define NUM_CONTROL_ALLOC 32 |
38 | #define STAC_HP_EVENT 0x37 | 38 | #define STAC_HP_EVENT 0x37 |
39 | #define STAC_UNSOL_ENABLE (AC_USRSP_EN | STAC_HP_EVENT) | ||
40 | 39 | ||
41 | #define STAC_REF 0 | 40 | #define STAC_REF 0 |
42 | #define STAC_D945GTP3 1 | 41 | #define STAC_D945GTP3 1 |
43 | #define STAC_D945GTP5 2 | 42 | #define STAC_D945GTP5 2 |
44 | #define STAC_MACMINI 3 | 43 | #define STAC_MACMINI 3 |
45 | #define STAC_D965_2112 4 | 44 | #define STAC_922X_MODELS 4 /* number of 922x models */ |
46 | #define STAC_D965_284B 5 | 45 | #define STAC_D965_3ST 4 |
47 | #define STAC_922X_MODELS 6 /* number of 922x models */ | 46 | #define STAC_D965_5ST 5 |
47 | #define STAC_927X_MODELS 6 /* number of 922x models */ | ||
48 | 48 | ||
49 | struct sigmatel_spec { | 49 | struct sigmatel_spec { |
50 | struct snd_kcontrol_new *mixers[4]; | 50 | struct snd_kcontrol_new *mixers[4]; |
@@ -73,6 +73,7 @@ struct sigmatel_spec { | |||
73 | hda_nid_t *pin_nids; | 73 | hda_nid_t *pin_nids; |
74 | unsigned int num_pins; | 74 | unsigned int num_pins; |
75 | unsigned int *pin_configs; | 75 | unsigned int *pin_configs; |
76 | unsigned int *bios_pin_configs; | ||
76 | 77 | ||
77 | /* codec specific stuff */ | 78 | /* codec specific stuff */ |
78 | struct hda_verb *init; | 79 | struct hda_verb *init; |
@@ -110,24 +111,10 @@ static hda_nid_t stac922x_adc_nids[2] = { | |||
110 | 0x06, 0x07, | 111 | 0x06, 0x07, |
111 | }; | 112 | }; |
112 | 113 | ||
113 | static hda_nid_t stac9227_adc_nids[2] = { | ||
114 | 0x07, 0x08, | ||
115 | }; | ||
116 | |||
117 | #if 0 | ||
118 | static hda_nid_t d965_2112_dac_nids[3] = { | ||
119 | 0x02, 0x03, 0x05, | ||
120 | }; | ||
121 | #endif | ||
122 | |||
123 | static hda_nid_t stac922x_mux_nids[2] = { | 114 | static hda_nid_t stac922x_mux_nids[2] = { |
124 | 0x12, 0x13, | 115 | 0x12, 0x13, |
125 | }; | 116 | }; |
126 | 117 | ||
127 | static hda_nid_t stac9227_mux_nids[2] = { | ||
128 | 0x15, 0x16, | ||
129 | }; | ||
130 | |||
131 | static hda_nid_t stac927x_adc_nids[3] = { | 118 | static hda_nid_t stac927x_adc_nids[3] = { |
132 | 0x07, 0x08, 0x09 | 119 | 0x07, 0x08, 0x09 |
133 | }; | 120 | }; |
@@ -136,8 +123,17 @@ static hda_nid_t stac927x_mux_nids[3] = { | |||
136 | 0x15, 0x16, 0x17 | 123 | 0x15, 0x16, 0x17 |
137 | }; | 124 | }; |
138 | 125 | ||
126 | static hda_nid_t stac9205_adc_nids[2] = { | ||
127 | 0x12, 0x13 | ||
128 | }; | ||
129 | |||
130 | static hda_nid_t stac9205_mux_nids[2] = { | ||
131 | 0x19, 0x1a | ||
132 | }; | ||
133 | |||
139 | static hda_nid_t stac9200_pin_nids[8] = { | 134 | static hda_nid_t stac9200_pin_nids[8] = { |
140 | 0x08, 0x09, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, | 135 | 0x08, 0x09, 0x0d, 0x0e, |
136 | 0x0f, 0x10, 0x11, 0x12, | ||
141 | }; | 137 | }; |
142 | 138 | ||
143 | static hda_nid_t stac922x_pin_nids[10] = { | 139 | static hda_nid_t stac922x_pin_nids[10] = { |
@@ -151,6 +147,13 @@ static hda_nid_t stac927x_pin_nids[14] = { | |||
151 | 0x14, 0x21, 0x22, 0x23, | 147 | 0x14, 0x21, 0x22, 0x23, |
152 | }; | 148 | }; |
153 | 149 | ||
150 | static hda_nid_t stac9205_pin_nids[12] = { | ||
151 | 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, | ||
152 | 0x0f, 0x14, 0x16, 0x17, 0x18, | ||
153 | 0x21, 0x22, | ||
154 | |||
155 | }; | ||
156 | |||
154 | static int stac92xx_mux_enum_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) | 157 | static int stac92xx_mux_enum_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) |
155 | { | 158 | { |
156 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | 159 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); |
@@ -190,25 +193,23 @@ static struct hda_verb stac922x_core_init[] = { | |||
190 | {} | 193 | {} |
191 | }; | 194 | }; |
192 | 195 | ||
193 | static struct hda_verb stac9227_core_init[] = { | 196 | static struct hda_verb d965_core_init[] = { |
194 | /* set master volume and direct control */ | 197 | /* set master volume and direct control */ |
195 | { 0x16, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff}, | 198 | { 0x24, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff}, |
196 | /* unmute node 0x1b */ | 199 | /* unmute node 0x1b */ |
197 | { 0x1b, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000}, | 200 | { 0x1b, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000}, |
201 | /* select node 0x03 as DAC */ | ||
202 | { 0x0b, AC_VERB_SET_CONNECT_SEL, 0x01}, | ||
198 | {} | 203 | {} |
199 | }; | 204 | }; |
200 | 205 | ||
201 | static struct hda_verb d965_2112_core_init[] = { | 206 | static struct hda_verb stac927x_core_init[] = { |
202 | /* set master volume and direct control */ | 207 | /* set master volume and direct control */ |
203 | { 0x16, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff}, | 208 | { 0x24, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff}, |
204 | /* unmute node 0x1b */ | ||
205 | { 0x1b, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000}, | ||
206 | /* select node 0x03 as DAC */ | ||
207 | { 0x0b, AC_VERB_SET_CONNECT_SEL, 0x01}, | ||
208 | {} | 209 | {} |
209 | }; | 210 | }; |
210 | 211 | ||
211 | static struct hda_verb stac927x_core_init[] = { | 212 | static struct hda_verb stac9205_core_init[] = { |
212 | /* set master volume and direct control */ | 213 | /* set master volume and direct control */ |
213 | { 0x24, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff}, | 214 | { 0x24, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff}, |
214 | {} | 215 | {} |
@@ -277,6 +278,21 @@ static snd_kcontrol_new_t stac927x_mixer[] = { | |||
277 | { } /* end */ | 278 | { } /* end */ |
278 | }; | 279 | }; |
279 | 280 | ||
281 | static snd_kcontrol_new_t stac9205_mixer[] = { | ||
282 | { | ||
283 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
284 | .name = "Input Source", | ||
285 | .count = 1, | ||
286 | .info = stac92xx_mux_enum_info, | ||
287 | .get = stac92xx_mux_enum_get, | ||
288 | .put = stac92xx_mux_enum_put, | ||
289 | }, | ||
290 | HDA_CODEC_VOLUME("InMux Capture Volume", 0x19, 0x0, HDA_OUTPUT), | ||
291 | HDA_CODEC_VOLUME("InVol Capture Volume", 0x1b, 0x0, HDA_INPUT), | ||
292 | HDA_CODEC_MUTE("ADCMux Capture Switch", 0x1d, 0x0, HDA_OUTPUT), | ||
293 | { } /* end */ | ||
294 | }; | ||
295 | |||
280 | static int stac92xx_build_controls(struct hda_codec *codec) | 296 | static int stac92xx_build_controls(struct hda_codec *codec) |
281 | { | 297 | { |
282 | struct sigmatel_spec *spec = codec->spec; | 298 | struct sigmatel_spec *spec = codec->spec; |
@@ -341,38 +357,67 @@ static unsigned int d945gtp5_pin_configs[10] = { | |||
341 | 0x02a19320, 0x40000100, | 357 | 0x02a19320, 0x40000100, |
342 | }; | 358 | }; |
343 | 359 | ||
344 | static unsigned int d965_2112_pin_configs[10] = { | ||
345 | 0x0221401f, 0x40000100, 0x40000100, 0x01014011, | ||
346 | 0x01a19021, 0x01813024, 0x01452130, 0x40000100, | ||
347 | 0x02a19320, 0x40000100, | ||
348 | }; | ||
349 | |||
350 | static unsigned int *stac922x_brd_tbl[STAC_922X_MODELS] = { | 360 | static unsigned int *stac922x_brd_tbl[STAC_922X_MODELS] = { |
351 | [STAC_REF] = ref922x_pin_configs, | 361 | [STAC_REF] = ref922x_pin_configs, |
352 | [STAC_D945GTP3] = d945gtp3_pin_configs, | 362 | [STAC_D945GTP3] = d945gtp3_pin_configs, |
353 | [STAC_D945GTP5] = d945gtp5_pin_configs, | 363 | [STAC_D945GTP5] = d945gtp5_pin_configs, |
354 | [STAC_MACMINI] = d945gtp5_pin_configs, | 364 | [STAC_MACMINI] = d945gtp5_pin_configs, |
355 | [STAC_D965_2112] = d965_2112_pin_configs, | ||
356 | }; | 365 | }; |
357 | 366 | ||
358 | static struct hda_board_config stac922x_cfg_tbl[] = { | 367 | static struct hda_board_config stac922x_cfg_tbl[] = { |
368 | { .modelname = "5stack", .config = STAC_D945GTP5 }, | ||
369 | { .modelname = "3stack", .config = STAC_D945GTP3 }, | ||
359 | { .modelname = "ref", | 370 | { .modelname = "ref", |
360 | .pci_subvendor = PCI_VENDOR_ID_INTEL, | 371 | .pci_subvendor = PCI_VENDOR_ID_INTEL, |
361 | .pci_subdevice = 0x2668, /* DFI LanParty */ | 372 | .pci_subdevice = 0x2668, /* DFI LanParty */ |
362 | .config = STAC_REF }, /* SigmaTel reference board */ | 373 | .config = STAC_REF }, /* SigmaTel reference board */ |
374 | /* Intel 945G based systems */ | ||
363 | { .pci_subvendor = PCI_VENDOR_ID_INTEL, | 375 | { .pci_subvendor = PCI_VENDOR_ID_INTEL, |
364 | .pci_subdevice = 0x0101, | 376 | .pci_subdevice = 0x0101, |
365 | .config = STAC_D945GTP3 }, /* Intel D945GTP - 3 Stack */ | 377 | .config = STAC_D945GTP3 }, /* Intel D945GTP - 3 Stack */ |
366 | { .pci_subvendor = PCI_VENDOR_ID_INTEL, | 378 | { .pci_subvendor = PCI_VENDOR_ID_INTEL, |
367 | .pci_subdevice = 0x0202, | 379 | .pci_subdevice = 0x0202, |
368 | .config = STAC_D945GTP3 }, /* Intel D945GNT - 3 Stack, 9221 A1 */ | 380 | .config = STAC_D945GTP3 }, /* Intel D945GNT - 3 Stack */ |
369 | { .pci_subvendor = PCI_VENDOR_ID_INTEL, | 381 | { .pci_subvendor = PCI_VENDOR_ID_INTEL, |
370 | .pci_subdevice = 0x0b0b, | 382 | .pci_subdevice = 0x0606, |
371 | .config = STAC_D945GTP3 }, /* Intel D945PSN - 3 Stack, 9221 A1 */ | 383 | .config = STAC_D945GTP3 }, /* Intel D945GTP - 3 Stack */ |
384 | { .pci_subvendor = PCI_VENDOR_ID_INTEL, | ||
385 | .pci_subdevice = 0x0601, | ||
386 | .config = STAC_D945GTP3 }, /* Intel D945GTP - 3 Stack */ | ||
387 | { .pci_subvendor = PCI_VENDOR_ID_INTEL, | ||
388 | .pci_subdevice = 0x0111, | ||
389 | .config = STAC_D945GTP3 }, /* Intel D945GZP - 3 Stack */ | ||
390 | { .pci_subvendor = PCI_VENDOR_ID_INTEL, | ||
391 | .pci_subdevice = 0x1115, | ||
392 | .config = STAC_D945GTP3 }, /* Intel D945GPM - 3 Stack */ | ||
393 | { .pci_subvendor = PCI_VENDOR_ID_INTEL, | ||
394 | .pci_subdevice = 0x1116, | ||
395 | .config = STAC_D945GTP3 }, /* Intel D945GBO - 3 Stack */ | ||
396 | { .pci_subvendor = PCI_VENDOR_ID_INTEL, | ||
397 | .pci_subdevice = 0x1117, | ||
398 | .config = STAC_D945GTP3 }, /* Intel D945GPM - 3 Stack */ | ||
399 | { .pci_subvendor = PCI_VENDOR_ID_INTEL, | ||
400 | .pci_subdevice = 0x1118, | ||
401 | .config = STAC_D945GTP3 }, /* Intel D945GPM - 3 Stack */ | ||
402 | { .pci_subvendor = PCI_VENDOR_ID_INTEL, | ||
403 | .pci_subdevice = 0x1119, | ||
404 | .config = STAC_D945GTP3 }, /* Intel D945GPM - 3 Stack */ | ||
405 | { .pci_subvendor = PCI_VENDOR_ID_INTEL, | ||
406 | .pci_subdevice = 0x8826, | ||
407 | .config = STAC_D945GTP3 }, /* Intel D945GPM - 3 Stack */ | ||
408 | { .pci_subvendor = PCI_VENDOR_ID_INTEL, | ||
409 | .pci_subdevice = 0x5049, | ||
410 | .config = STAC_D945GTP3 }, /* Intel D945GCZ - 3 Stack */ | ||
411 | { .pci_subvendor = PCI_VENDOR_ID_INTEL, | ||
412 | .pci_subdevice = 0x5055, | ||
413 | .config = STAC_D945GTP3 }, /* Intel D945GCZ - 3 Stack */ | ||
414 | { .pci_subvendor = PCI_VENDOR_ID_INTEL, | ||
415 | .pci_subdevice = 0x5048, | ||
416 | .config = STAC_D945GTP3 }, /* Intel D945GPB - 3 Stack */ | ||
417 | { .pci_subvendor = PCI_VENDOR_ID_INTEL, | ||
418 | .pci_subdevice = 0x0110, | ||
419 | .config = STAC_D945GTP3 }, /* Intel D945GLR - 3 Stack */ | ||
372 | { .pci_subvendor = PCI_VENDOR_ID_INTEL, | 420 | { .pci_subvendor = PCI_VENDOR_ID_INTEL, |
373 | .pci_subdevice = 0x0707, | ||
374 | .config = STAC_D945GTP5 }, /* Intel D945PSV - 5 Stack */ | ||
375 | { .pci_subvendor = PCI_VENDOR_ID_INTEL, | ||
376 | .pci_subdevice = 0x0404, | 421 | .pci_subdevice = 0x0404, |
377 | .config = STAC_D945GTP5 }, /* Intel D945GTP - 5 Stack */ | 422 | .config = STAC_D945GTP5 }, /* Intel D945GTP - 5 Stack */ |
378 | { .pci_subvendor = PCI_VENDOR_ID_INTEL, | 423 | { .pci_subvendor = PCI_VENDOR_ID_INTEL, |
@@ -384,44 +429,214 @@ static struct hda_board_config stac922x_cfg_tbl[] = { | |||
384 | { .pci_subvendor = PCI_VENDOR_ID_INTEL, | 429 | { .pci_subvendor = PCI_VENDOR_ID_INTEL, |
385 | .pci_subdevice = 0x0417, | 430 | .pci_subdevice = 0x0417, |
386 | .config = STAC_D945GTP5 }, /* Intel D975XBK - 5 Stack */ | 431 | .config = STAC_D945GTP5 }, /* Intel D975XBK - 5 Stack */ |
432 | /* Intel 945P based systems */ | ||
433 | { .pci_subvendor = PCI_VENDOR_ID_INTEL, | ||
434 | .pci_subdevice = 0x0b0b, | ||
435 | .config = STAC_D945GTP3 }, /* Intel D945PSN - 3 Stack */ | ||
436 | { .pci_subvendor = PCI_VENDOR_ID_INTEL, | ||
437 | .pci_subdevice = 0x0112, | ||
438 | .config = STAC_D945GTP3 }, /* Intel D945PLN - 3 Stack */ | ||
439 | { .pci_subvendor = PCI_VENDOR_ID_INTEL, | ||
440 | .pci_subdevice = 0x0d0d, | ||
441 | .config = STAC_D945GTP3 }, /* Intel D945PLM - 3 Stack */ | ||
442 | { .pci_subvendor = PCI_VENDOR_ID_INTEL, | ||
443 | .pci_subdevice = 0x0909, | ||
444 | .config = STAC_D945GTP3 }, /* Intel D945PAW - 3 Stack */ | ||
445 | { .pci_subvendor = PCI_VENDOR_ID_INTEL, | ||
446 | .pci_subdevice = 0x0505, | ||
447 | .config = STAC_D945GTP3 }, /* Intel D945PLM - 3 Stack */ | ||
448 | { .pci_subvendor = PCI_VENDOR_ID_INTEL, | ||
449 | .pci_subdevice = 0x0707, | ||
450 | .config = STAC_D945GTP5 }, /* Intel D945PSV - 5 Stack */ | ||
451 | /* other systems */ | ||
387 | { .pci_subvendor = 0x8384, | 452 | { .pci_subvendor = 0x8384, |
388 | .pci_subdevice = 0x7680, | 453 | .pci_subdevice = 0x7680, |
389 | .config = STAC_MACMINI }, /* Apple Mac Mini (early 2006) */ | 454 | .config = STAC_MACMINI }, /* Apple Mac Mini (early 2006) */ |
455 | {} /* terminator */ | ||
456 | }; | ||
457 | |||
458 | static unsigned int ref927x_pin_configs[14] = { | ||
459 | 0x02214020, 0x02a19080, 0x0181304e, 0x01014010, | ||
460 | 0x01a19040, 0x01011012, 0x01016011, 0x0101201f, | ||
461 | 0x183301f0, 0x18a001f0, 0x18a001f0, 0x01442070, | ||
462 | 0x01c42190, 0x40000100, | ||
463 | }; | ||
464 | |||
465 | static unsigned int d965_3st_pin_configs[14] = { | ||
466 | 0x0221401f, 0x02a19120, 0x40000100, 0x01014011, | ||
467 | 0x01a19021, 0x01813024, 0x40000100, 0x40000100, | ||
468 | 0x40000100, 0x40000100, 0x40000100, 0x40000100, | ||
469 | 0x40000100, 0x40000100 | ||
470 | }; | ||
471 | |||
472 | static unsigned int d965_5st_pin_configs[14] = { | ||
473 | 0x02214020, 0x02a19080, 0x0181304e, 0x01014010, | ||
474 | 0x01a19040, 0x01011012, 0x01016011, 0x40000100, | ||
475 | 0x40000100, 0x40000100, 0x40000100, 0x01442070, | ||
476 | 0x40000100, 0x40000100 | ||
477 | }; | ||
478 | |||
479 | static unsigned int *stac927x_brd_tbl[STAC_927X_MODELS] = { | ||
480 | [STAC_REF] = ref927x_pin_configs, | ||
481 | [STAC_D965_3ST] = d965_3st_pin_configs, | ||
482 | [STAC_D965_5ST] = d965_5st_pin_configs, | ||
483 | }; | ||
484 | |||
485 | static struct hda_board_config stac927x_cfg_tbl[] = { | ||
486 | { .modelname = "5stack", .config = STAC_D965_5ST }, | ||
487 | { .modelname = "3stack", .config = STAC_D965_3ST }, | ||
488 | { .modelname = "ref", | ||
489 | .pci_subvendor = PCI_VENDOR_ID_INTEL, | ||
490 | .pci_subdevice = 0x2668, /* DFI LanParty */ | ||
491 | .config = STAC_REF }, /* SigmaTel reference board */ | ||
492 | /* Intel 946 based systems */ | ||
493 | { .pci_subvendor = PCI_VENDOR_ID_INTEL, | ||
494 | .pci_subdevice = 0x3d01, | ||
495 | .config = STAC_D965_3ST }, /* D946 configuration */ | ||
496 | { .pci_subvendor = PCI_VENDOR_ID_INTEL, | ||
497 | .pci_subdevice = 0xa301, | ||
498 | .config = STAC_D965_3ST }, /* Intel D946GZT - 3 stack */ | ||
499 | /* 965 based 3 stack systems */ | ||
500 | { .pci_subvendor = PCI_VENDOR_ID_INTEL, | ||
501 | .pci_subdevice = 0x2116, | ||
502 | .config = STAC_D965_3ST }, /* Intel D965 3Stack config */ | ||
503 | { .pci_subvendor = PCI_VENDOR_ID_INTEL, | ||
504 | .pci_subdevice = 0x2115, | ||
505 | .config = STAC_D965_3ST }, /* Intel DQ965WC - 3 Stack */ | ||
506 | { .pci_subvendor = PCI_VENDOR_ID_INTEL, | ||
507 | .pci_subdevice = 0x2114, | ||
508 | .config = STAC_D965_3ST }, /* Intel D965 3Stack config */ | ||
509 | { .pci_subvendor = PCI_VENDOR_ID_INTEL, | ||
510 | .pci_subdevice = 0x2113, | ||
511 | .config = STAC_D965_3ST }, /* Intel D965 3Stack config */ | ||
390 | { .pci_subvendor = PCI_VENDOR_ID_INTEL, | 512 | { .pci_subvendor = PCI_VENDOR_ID_INTEL, |
391 | .pci_subdevice = 0x2112, | 513 | .pci_subdevice = 0x2112, |
392 | .config = STAC_D965_2112 }, | 514 | .config = STAC_D965_3ST }, /* Intel DG965MS - 3 Stack */ |
515 | { .pci_subvendor = PCI_VENDOR_ID_INTEL, | ||
516 | .pci_subdevice = 0x2111, | ||
517 | .config = STAC_D965_3ST }, /* Intel D965 3Stack config */ | ||
518 | { .pci_subvendor = PCI_VENDOR_ID_INTEL, | ||
519 | .pci_subdevice = 0x2110, | ||
520 | .config = STAC_D965_3ST }, /* Intel D965 3Stack config */ | ||
521 | { .pci_subvendor = PCI_VENDOR_ID_INTEL, | ||
522 | .pci_subdevice = 0x2009, | ||
523 | .config = STAC_D965_3ST }, /* Intel D965 3Stack config */ | ||
524 | { .pci_subvendor = PCI_VENDOR_ID_INTEL, | ||
525 | .pci_subdevice = 0x2008, | ||
526 | .config = STAC_D965_3ST }, /* Intel DQ965GF - 3 Stack */ | ||
527 | { .pci_subvendor = PCI_VENDOR_ID_INTEL, | ||
528 | .pci_subdevice = 0x2007, | ||
529 | .config = STAC_D965_3ST }, /* Intel D965 3Stack config */ | ||
530 | { .pci_subvendor = PCI_VENDOR_ID_INTEL, | ||
531 | .pci_subdevice = 0x2006, | ||
532 | .config = STAC_D965_3ST }, /* Intel D965 3Stack config */ | ||
533 | { .pci_subvendor = PCI_VENDOR_ID_INTEL, | ||
534 | .pci_subdevice = 0x2005, | ||
535 | .config = STAC_D965_3ST }, /* Intel D965 3Stack config */ | ||
536 | { .pci_subvendor = PCI_VENDOR_ID_INTEL, | ||
537 | .pci_subdevice = 0x2004, | ||
538 | .config = STAC_D965_3ST }, /* Intel D965 3Stack config */ | ||
539 | { .pci_subvendor = PCI_VENDOR_ID_INTEL, | ||
540 | .pci_subdevice = 0x2003, | ||
541 | .config = STAC_D965_3ST }, /* Intel D965 3Stack config */ | ||
542 | { .pci_subvendor = PCI_VENDOR_ID_INTEL, | ||
543 | .pci_subdevice = 0x2002, | ||
544 | .config = STAC_D965_3ST }, /* Intel D965 3Stack config */ | ||
545 | { .pci_subvendor = PCI_VENDOR_ID_INTEL, | ||
546 | .pci_subdevice = 0x2001, | ||
547 | .config = STAC_D965_3ST }, /* Intel DQ965GF - 3 Stack */ | ||
548 | /* 965 based 5 stack systems */ | ||
549 | { .pci_subvendor = PCI_VENDOR_ID_INTEL, | ||
550 | .pci_subdevice = 0x2301, | ||
551 | .config = STAC_D965_5ST }, /* Intel DG965 - 5 Stack */ | ||
552 | { .pci_subvendor = PCI_VENDOR_ID_INTEL, | ||
553 | .pci_subdevice = 0x2302, | ||
554 | .config = STAC_D965_5ST }, /* Intel DG965 - 5 Stack */ | ||
555 | { .pci_subvendor = PCI_VENDOR_ID_INTEL, | ||
556 | .pci_subdevice = 0x2303, | ||
557 | .config = STAC_D965_5ST }, /* Intel DG965 - 5 Stack */ | ||
393 | { .pci_subvendor = PCI_VENDOR_ID_INTEL, | 558 | { .pci_subvendor = PCI_VENDOR_ID_INTEL, |
394 | .pci_subdevice = 0x284b, | 559 | .pci_subdevice = 0x2304, |
395 | .config = STAC_D965_284B }, | 560 | .config = STAC_D965_5ST }, /* Intel DG965 - 5 Stack */ |
561 | { .pci_subvendor = PCI_VENDOR_ID_INTEL, | ||
562 | .pci_subdevice = 0x2305, | ||
563 | .config = STAC_D965_5ST }, /* Intel DG965 - 5 Stack */ | ||
564 | { .pci_subvendor = PCI_VENDOR_ID_INTEL, | ||
565 | .pci_subdevice = 0x2501, | ||
566 | .config = STAC_D965_5ST }, /* Intel DG965MQ - 5 Stack */ | ||
567 | { .pci_subvendor = PCI_VENDOR_ID_INTEL, | ||
568 | .pci_subdevice = 0x2502, | ||
569 | .config = STAC_D965_5ST }, /* Intel DG965 - 5 Stack */ | ||
570 | { .pci_subvendor = PCI_VENDOR_ID_INTEL, | ||
571 | .pci_subdevice = 0x2503, | ||
572 | .config = STAC_D965_5ST }, /* Intel DG965 - 5 Stack */ | ||
573 | { .pci_subvendor = PCI_VENDOR_ID_INTEL, | ||
574 | .pci_subdevice = 0x2504, | ||
575 | .config = STAC_D965_5ST }, /* Intel DQ965GF - 5 Stack */ | ||
396 | {} /* terminator */ | 576 | {} /* terminator */ |
397 | }; | 577 | }; |
398 | 578 | ||
399 | static unsigned int ref927x_pin_configs[14] = { | 579 | static unsigned int ref9205_pin_configs[12] = { |
400 | 0x01813122, 0x01a19021, 0x01014010, 0x01016011, | 580 | 0x40000100, 0x40000100, 0x01016011, 0x01014010, |
401 | 0x01012012, 0x01011014, 0x40000100, 0x40000100, | 581 | 0x01813122, 0x01a19021, 0x40000100, 0x40000100, |
402 | 0x40000100, 0x40000100, 0x40000100, 0x01441030, | 582 | 0x40000100, 0x40000100, 0x01441030, 0x01c41030 |
403 | 0x01c41030, 0x40000100, | ||
404 | }; | 583 | }; |
405 | 584 | ||
406 | static unsigned int *stac927x_brd_tbl[] = { | 585 | static unsigned int *stac9205_brd_tbl[] = { |
407 | ref927x_pin_configs, | 586 | ref9205_pin_configs, |
408 | }; | 587 | }; |
409 | 588 | ||
410 | static struct hda_board_config stac927x_cfg_tbl[] = { | 589 | static struct hda_board_config stac9205_cfg_tbl[] = { |
411 | { .modelname = "ref", | 590 | { .modelname = "ref", |
412 | .pci_subvendor = PCI_VENDOR_ID_INTEL, | 591 | .pci_subvendor = PCI_VENDOR_ID_INTEL, |
413 | .pci_subdevice = 0x2668, /* DFI LanParty */ | 592 | .pci_subdevice = 0x2668, /* DFI LanParty */ |
414 | .config = STAC_REF }, /* SigmaTel reference board */ | 593 | .config = STAC_REF }, /* SigmaTel reference board */ |
594 | /* Dell laptops have BIOS problem */ | ||
595 | { .pci_subvendor = PCI_VENDOR_ID_DELL, .pci_subdevice = 0x01b5, | ||
596 | .config = STAC_REF }, /* Dell Inspiron 630m */ | ||
597 | { .pci_subvendor = PCI_VENDOR_ID_DELL, .pci_subdevice = 0x01c2, | ||
598 | .config = STAC_REF }, /* Dell Latitude D620 */ | ||
599 | { .pci_subvendor = PCI_VENDOR_ID_DELL, .pci_subdevice = 0x01cb, | ||
600 | .config = STAC_REF }, /* Dell Latitude 120L */ | ||
415 | {} /* terminator */ | 601 | {} /* terminator */ |
416 | }; | 602 | }; |
417 | 603 | ||
604 | static int stac92xx_save_bios_config_regs(struct hda_codec *codec) | ||
605 | { | ||
606 | int i; | ||
607 | struct sigmatel_spec *spec = codec->spec; | ||
608 | |||
609 | if (! spec->bios_pin_configs) { | ||
610 | spec->bios_pin_configs = kcalloc(spec->num_pins, | ||
611 | sizeof(*spec->bios_pin_configs), GFP_KERNEL); | ||
612 | if (! spec->bios_pin_configs) | ||
613 | return -ENOMEM; | ||
614 | } | ||
615 | |||
616 | for (i = 0; i < spec->num_pins; i++) { | ||
617 | hda_nid_t nid = spec->pin_nids[i]; | ||
618 | unsigned int pin_cfg; | ||
619 | |||
620 | pin_cfg = snd_hda_codec_read(codec, nid, 0, | ||
621 | AC_VERB_GET_CONFIG_DEFAULT, 0x00); | ||
622 | snd_printdd(KERN_INFO "hda_codec: pin nid %2.2x bios pin config %8.8x\n", | ||
623 | nid, pin_cfg); | ||
624 | spec->bios_pin_configs[i] = pin_cfg; | ||
625 | } | ||
626 | |||
627 | return 0; | ||
628 | } | ||
629 | |||
418 | static void stac92xx_set_config_regs(struct hda_codec *codec) | 630 | static void stac92xx_set_config_regs(struct hda_codec *codec) |
419 | { | 631 | { |
420 | int i; | 632 | int i; |
421 | struct sigmatel_spec *spec = codec->spec; | 633 | struct sigmatel_spec *spec = codec->spec; |
422 | unsigned int pin_cfg; | 634 | unsigned int pin_cfg; |
423 | 635 | ||
424 | for (i=0; i < spec->num_pins; i++) { | 636 | if (! spec->pin_nids || ! spec->pin_configs) |
637 | return; | ||
638 | |||
639 | for (i = 0; i < spec->num_pins; i++) { | ||
425 | snd_hda_codec_write(codec, spec->pin_nids[i], 0, | 640 | snd_hda_codec_write(codec, spec->pin_nids[i], 0, |
426 | AC_VERB_SET_CONFIG_DEFAULT_BYTES_0, | 641 | AC_VERB_SET_CONFIG_DEFAULT_BYTES_0, |
427 | spec->pin_configs[i] & 0x000000ff); | 642 | spec->pin_configs[i] & 0x000000ff); |
@@ -795,11 +1010,29 @@ static int stac92xx_auto_fill_dac_nids(struct hda_codec *codec, | |||
795 | return 0; | 1010 | return 0; |
796 | } | 1011 | } |
797 | 1012 | ||
1013 | /* create volume control/switch for the given prefx type */ | ||
1014 | static int create_controls(struct sigmatel_spec *spec, const char *pfx, hda_nid_t nid, int chs) | ||
1015 | { | ||
1016 | char name[32]; | ||
1017 | int err; | ||
1018 | |||
1019 | sprintf(name, "%s Playback Volume", pfx); | ||
1020 | err = stac92xx_add_control(spec, STAC_CTL_WIDGET_VOL, name, | ||
1021 | HDA_COMPOSE_AMP_VAL(nid, chs, 0, HDA_OUTPUT)); | ||
1022 | if (err < 0) | ||
1023 | return err; | ||
1024 | sprintf(name, "%s Playback Switch", pfx); | ||
1025 | err = stac92xx_add_control(spec, STAC_CTL_WIDGET_MUTE, name, | ||
1026 | HDA_COMPOSE_AMP_VAL(nid, chs, 0, HDA_OUTPUT)); | ||
1027 | if (err < 0) | ||
1028 | return err; | ||
1029 | return 0; | ||
1030 | } | ||
1031 | |||
798 | /* add playback controls from the parsed DAC table */ | 1032 | /* add playback controls from the parsed DAC table */ |
799 | static int stac92xx_auto_create_multi_out_ctls(struct sigmatel_spec *spec, | 1033 | static int stac92xx_auto_create_multi_out_ctls(struct sigmatel_spec *spec, |
800 | const struct auto_pin_cfg *cfg) | 1034 | const struct auto_pin_cfg *cfg) |
801 | { | 1035 | { |
802 | char name[32]; | ||
803 | static const char *chname[4] = { | 1036 | static const char *chname[4] = { |
804 | "Front", "Surround", NULL /*CLFE*/, "Side" | 1037 | "Front", "Surround", NULL /*CLFE*/, "Side" |
805 | }; | 1038 | }; |
@@ -814,26 +1047,15 @@ static int stac92xx_auto_create_multi_out_ctls(struct sigmatel_spec *spec, | |||
814 | 1047 | ||
815 | if (i == 2) { | 1048 | if (i == 2) { |
816 | /* Center/LFE */ | 1049 | /* Center/LFE */ |
817 | if ((err = stac92xx_add_control(spec, STAC_CTL_WIDGET_VOL, "Center Playback Volume", | 1050 | err = create_controls(spec, "Center", nid, 1); |
818 | HDA_COMPOSE_AMP_VAL(nid, 1, 0, HDA_OUTPUT))) < 0) | 1051 | if (err < 0) |
819 | return err; | ||
820 | if ((err = stac92xx_add_control(spec, STAC_CTL_WIDGET_VOL, "LFE Playback Volume", | ||
821 | HDA_COMPOSE_AMP_VAL(nid, 2, 0, HDA_OUTPUT))) < 0) | ||
822 | return err; | ||
823 | if ((err = stac92xx_add_control(spec, STAC_CTL_WIDGET_MUTE, "Center Playback Switch", | ||
824 | HDA_COMPOSE_AMP_VAL(nid, 1, 0, HDA_OUTPUT))) < 0) | ||
825 | return err; | 1052 | return err; |
826 | if ((err = stac92xx_add_control(spec, STAC_CTL_WIDGET_MUTE, "LFE Playback Switch", | 1053 | err = create_controls(spec, "LFE", nid, 2); |
827 | HDA_COMPOSE_AMP_VAL(nid, 2, 0, HDA_OUTPUT))) < 0) | 1054 | if (err < 0) |
828 | return err; | 1055 | return err; |
829 | } else { | 1056 | } else { |
830 | sprintf(name, "%s Playback Volume", chname[i]); | 1057 | err = create_controls(spec, chname[i], nid, 3); |
831 | if ((err = stac92xx_add_control(spec, STAC_CTL_WIDGET_VOL, name, | 1058 | if (err < 0) |
832 | HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT))) < 0) | ||
833 | return err; | ||
834 | sprintf(name, "%s Playback Switch", chname[i]); | ||
835 | if ((err = stac92xx_add_control(spec, STAC_CTL_WIDGET_MUTE, name, | ||
836 | HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT))) < 0) | ||
837 | return err; | 1059 | return err; |
838 | } | 1060 | } |
839 | } | 1061 | } |
@@ -849,39 +1071,85 @@ static int stac92xx_auto_create_multi_out_ctls(struct sigmatel_spec *spec, | |||
849 | return 0; | 1071 | return 0; |
850 | } | 1072 | } |
851 | 1073 | ||
852 | /* add playback controls for HP output */ | 1074 | static int check_in_dac_nids(struct sigmatel_spec *spec, hda_nid_t nid) |
853 | static int stac92xx_auto_create_hp_ctls(struct hda_codec *codec, struct auto_pin_cfg *cfg) | ||
854 | { | 1075 | { |
855 | struct sigmatel_spec *spec = codec->spec; | 1076 | int i; |
856 | hda_nid_t pin = cfg->hp_pin; | ||
857 | hda_nid_t nid; | ||
858 | int i, err; | ||
859 | unsigned int wid_caps; | ||
860 | 1077 | ||
861 | if (! pin) | 1078 | for (i = 0; i < spec->multiout.num_dacs; i++) { |
862 | return 0; | 1079 | if (spec->multiout.dac_nids[i] == nid) |
1080 | return 1; | ||
1081 | } | ||
1082 | if (spec->multiout.hp_nid == nid) | ||
1083 | return 1; | ||
1084 | return 0; | ||
1085 | } | ||
863 | 1086 | ||
864 | wid_caps = get_wcaps(codec, pin); | 1087 | static int add_spec_dacs(struct sigmatel_spec *spec, hda_nid_t nid) |
865 | if (wid_caps & AC_WCAP_UNSOL_CAP) | 1088 | { |
866 | spec->hp_detect = 1; | 1089 | if (!spec->multiout.hp_nid) |
1090 | spec->multiout.hp_nid = nid; | ||
1091 | else if (spec->multiout.num_dacs > 4) { | ||
1092 | printk(KERN_WARNING "stac92xx: No space for DAC 0x%x\n", nid); | ||
1093 | return 1; | ||
1094 | } else { | ||
1095 | spec->multiout.dac_nids[spec->multiout.num_dacs] = nid; | ||
1096 | spec->multiout.num_dacs++; | ||
1097 | } | ||
1098 | return 0; | ||
1099 | } | ||
867 | 1100 | ||
868 | nid = snd_hda_codec_read(codec, pin, 0, AC_VERB_GET_CONNECT_LIST, 0) & 0xff; | 1101 | /* add playback controls for Speaker and HP outputs */ |
869 | for (i = 0; i < cfg->line_outs; i++) { | 1102 | static int stac92xx_auto_create_hp_ctls(struct hda_codec *codec, |
870 | if (! spec->multiout.dac_nids[i]) | 1103 | struct auto_pin_cfg *cfg) |
1104 | { | ||
1105 | struct sigmatel_spec *spec = codec->spec; | ||
1106 | hda_nid_t nid; | ||
1107 | int i, old_num_dacs, err; | ||
1108 | |||
1109 | old_num_dacs = spec->multiout.num_dacs; | ||
1110 | for (i = 0; i < cfg->hp_outs; i++) { | ||
1111 | unsigned int wid_caps = get_wcaps(codec, cfg->hp_pins[i]); | ||
1112 | if (wid_caps & AC_WCAP_UNSOL_CAP) | ||
1113 | spec->hp_detect = 1; | ||
1114 | nid = snd_hda_codec_read(codec, cfg->hp_pins[i], 0, | ||
1115 | AC_VERB_GET_CONNECT_LIST, 0) & 0xff; | ||
1116 | if (check_in_dac_nids(spec, nid)) | ||
1117 | nid = 0; | ||
1118 | if (! nid) | ||
871 | continue; | 1119 | continue; |
872 | if (spec->multiout.dac_nids[i] == nid) | 1120 | add_spec_dacs(spec, nid); |
873 | return 0; | 1121 | } |
1122 | for (i = 0; i < cfg->speaker_outs; i++) { | ||
1123 | nid = snd_hda_codec_read(codec, cfg->speaker_pins[0], 0, | ||
1124 | AC_VERB_GET_CONNECT_LIST, 0) & 0xff; | ||
1125 | if (check_in_dac_nids(spec, nid)) | ||
1126 | nid = 0; | ||
1127 | if (check_in_dac_nids(spec, nid)) | ||
1128 | nid = 0; | ||
1129 | if (! nid) | ||
1130 | continue; | ||
1131 | add_spec_dacs(spec, nid); | ||
874 | } | 1132 | } |
875 | 1133 | ||
876 | spec->multiout.hp_nid = nid; | 1134 | for (i = old_num_dacs; i < spec->multiout.num_dacs; i++) { |
877 | 1135 | static const char *pfxs[] = { | |
878 | /* control HP volume/switch on the output mixer amp */ | 1136 | "Speaker", "External Speaker", "Speaker2", |
879 | if ((err = stac92xx_add_control(spec, STAC_CTL_WIDGET_VOL, "Headphone Playback Volume", | 1137 | }; |
880 | HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT))) < 0) | 1138 | err = create_controls(spec, pfxs[i - old_num_dacs], |
881 | return err; | 1139 | spec->multiout.dac_nids[i], 3); |
882 | if ((err = stac92xx_add_control(spec, STAC_CTL_WIDGET_MUTE, "Headphone Playback Switch", | 1140 | if (err < 0) |
883 | HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT))) < 0) | 1141 | return err; |
884 | return err; | 1142 | } |
1143 | if (spec->multiout.hp_nid) { | ||
1144 | const char *pfx; | ||
1145 | if (old_num_dacs == spec->multiout.num_dacs) | ||
1146 | pfx = "Master"; | ||
1147 | else | ||
1148 | pfx = "Headphone"; | ||
1149 | err = create_controls(spec, pfx, spec->multiout.hp_nid, 3); | ||
1150 | if (err < 0) | ||
1151 | return err; | ||
1152 | } | ||
885 | 1153 | ||
886 | return 0; | 1154 | return 0; |
887 | } | 1155 | } |
@@ -895,23 +1163,28 @@ static int stac92xx_auto_create_analog_input_ctls(struct hda_codec *codec, const | |||
895 | int i, j, k; | 1163 | int i, j, k; |
896 | 1164 | ||
897 | for (i = 0; i < AUTO_PIN_LAST; i++) { | 1165 | for (i = 0; i < AUTO_PIN_LAST; i++) { |
898 | int index = -1; | 1166 | int index; |
899 | if (cfg->input_pins[i]) { | 1167 | |
900 | imux->items[imux->num_items].label = auto_pin_cfg_labels[i]; | 1168 | if (!cfg->input_pins[i]) |
901 | 1169 | continue; | |
902 | for (j=0; j<spec->num_muxes; j++) { | 1170 | index = -1; |
903 | int num_cons = snd_hda_get_connections(codec, spec->mux_nids[j], con_lst, HDA_MAX_NUM_INPUTS); | 1171 | for (j = 0; j < spec->num_muxes; j++) { |
904 | for (k=0; k<num_cons; k++) | 1172 | int num_cons; |
905 | if (con_lst[k] == cfg->input_pins[i]) { | 1173 | num_cons = snd_hda_get_connections(codec, |
906 | index = k; | 1174 | spec->mux_nids[j], |
907 | break; | 1175 | con_lst, |
908 | } | 1176 | HDA_MAX_NUM_INPUTS); |
909 | if (index >= 0) | 1177 | for (k = 0; k < num_cons; k++) |
910 | break; | 1178 | if (con_lst[k] == cfg->input_pins[i]) { |
911 | } | 1179 | index = k; |
912 | imux->items[imux->num_items].index = index; | 1180 | goto found; |
913 | imux->num_items++; | 1181 | } |
914 | } | 1182 | } |
1183 | continue; | ||
1184 | found: | ||
1185 | imux->items[imux->num_items].label = auto_pin_cfg_labels[i]; | ||
1186 | imux->items[imux->num_items].index = index; | ||
1187 | imux->num_items++; | ||
915 | } | 1188 | } |
916 | 1189 | ||
917 | if (imux->num_items == 1) { | 1190 | if (imux->num_items == 1) { |
@@ -944,11 +1217,20 @@ static void stac92xx_auto_init_multi_out(struct hda_codec *codec) | |||
944 | static void stac92xx_auto_init_hp_out(struct hda_codec *codec) | 1217 | static void stac92xx_auto_init_hp_out(struct hda_codec *codec) |
945 | { | 1218 | { |
946 | struct sigmatel_spec *spec = codec->spec; | 1219 | struct sigmatel_spec *spec = codec->spec; |
947 | hda_nid_t pin; | 1220 | int i; |
948 | 1221 | ||
949 | pin = spec->autocfg.hp_pin; | 1222 | for (i = 0; i < spec->autocfg.hp_outs; i++) { |
950 | if (pin) /* connect to front */ | 1223 | hda_nid_t pin; |
951 | stac92xx_auto_set_pinctl(codec, pin, AC_PINCTL_OUT_EN | AC_PINCTL_HP_EN); | 1224 | pin = spec->autocfg.hp_pins[i]; |
1225 | if (pin) /* connect to front */ | ||
1226 | stac92xx_auto_set_pinctl(codec, pin, AC_PINCTL_OUT_EN | AC_PINCTL_HP_EN); | ||
1227 | } | ||
1228 | for (i = 0; i < spec->autocfg.speaker_outs; i++) { | ||
1229 | hda_nid_t pin; | ||
1230 | pin = spec->autocfg.speaker_pins[i]; | ||
1231 | if (pin) /* connect to front */ | ||
1232 | stac92xx_auto_set_pinctl(codec, pin, AC_PINCTL_OUT_EN); | ||
1233 | } | ||
952 | } | 1234 | } |
953 | 1235 | ||
954 | static int stac92xx_parse_auto_config(struct hda_codec *codec, hda_nid_t dig_out, hda_nid_t dig_in) | 1236 | static int stac92xx_parse_auto_config(struct hda_codec *codec, hda_nid_t dig_out, hda_nid_t dig_in) |
@@ -994,7 +1276,7 @@ static int stac9200_auto_create_hp_ctls(struct hda_codec *codec, | |||
994 | struct auto_pin_cfg *cfg) | 1276 | struct auto_pin_cfg *cfg) |
995 | { | 1277 | { |
996 | struct sigmatel_spec *spec = codec->spec; | 1278 | struct sigmatel_spec *spec = codec->spec; |
997 | hda_nid_t pin = cfg->hp_pin; | 1279 | hda_nid_t pin = cfg->hp_pins[0]; |
998 | unsigned int wid_caps; | 1280 | unsigned int wid_caps; |
999 | 1281 | ||
1000 | if (! pin) | 1282 | if (! pin) |
@@ -1007,6 +1289,57 @@ static int stac9200_auto_create_hp_ctls(struct hda_codec *codec, | |||
1007 | return 0; | 1289 | return 0; |
1008 | } | 1290 | } |
1009 | 1291 | ||
1292 | /* add playback controls for LFE output */ | ||
1293 | static int stac9200_auto_create_lfe_ctls(struct hda_codec *codec, | ||
1294 | struct auto_pin_cfg *cfg) | ||
1295 | { | ||
1296 | struct sigmatel_spec *spec = codec->spec; | ||
1297 | int err; | ||
1298 | hda_nid_t lfe_pin = 0x0; | ||
1299 | int i; | ||
1300 | |||
1301 | /* | ||
1302 | * search speaker outs and line outs for a mono speaker pin | ||
1303 | * with an amp. If one is found, add LFE controls | ||
1304 | * for it. | ||
1305 | */ | ||
1306 | for (i = 0; i < spec->autocfg.speaker_outs && lfe_pin == 0x0; i++) { | ||
1307 | hda_nid_t pin = spec->autocfg.speaker_pins[i]; | ||
1308 | unsigned long wcaps = get_wcaps(codec, pin); | ||
1309 | wcaps &= (AC_WCAP_STEREO | AC_WCAP_OUT_AMP); | ||
1310 | if (wcaps == AC_WCAP_OUT_AMP) | ||
1311 | /* found a mono speaker with an amp, must be lfe */ | ||
1312 | lfe_pin = pin; | ||
1313 | } | ||
1314 | |||
1315 | /* if speaker_outs is 0, then speakers may be in line_outs */ | ||
1316 | if (lfe_pin == 0 && spec->autocfg.speaker_outs == 0) { | ||
1317 | for (i = 0; i < spec->autocfg.line_outs && lfe_pin == 0x0; i++) { | ||
1318 | hda_nid_t pin = spec->autocfg.line_out_pins[i]; | ||
1319 | unsigned long cfg; | ||
1320 | cfg = snd_hda_codec_read(codec, pin, 0, | ||
1321 | AC_VERB_GET_CONFIG_DEFAULT, | ||
1322 | 0x00); | ||
1323 | if (get_defcfg_device(cfg) == AC_JACK_SPEAKER) { | ||
1324 | unsigned long wcaps = get_wcaps(codec, pin); | ||
1325 | wcaps &= (AC_WCAP_STEREO | AC_WCAP_OUT_AMP); | ||
1326 | if (wcaps == AC_WCAP_OUT_AMP) | ||
1327 | /* found a mono speaker with an amp, | ||
1328 | must be lfe */ | ||
1329 | lfe_pin = pin; | ||
1330 | } | ||
1331 | } | ||
1332 | } | ||
1333 | |||
1334 | if (lfe_pin) { | ||
1335 | err = create_controls(spec, "LFE", lfe_pin, 1); | ||
1336 | if (err < 0) | ||
1337 | return err; | ||
1338 | } | ||
1339 | |||
1340 | return 0; | ||
1341 | } | ||
1342 | |||
1010 | static int stac9200_parse_auto_config(struct hda_codec *codec) | 1343 | static int stac9200_parse_auto_config(struct hda_codec *codec) |
1011 | { | 1344 | { |
1012 | struct sigmatel_spec *spec = codec->spec; | 1345 | struct sigmatel_spec *spec = codec->spec; |
@@ -1021,6 +1354,9 @@ static int stac9200_parse_auto_config(struct hda_codec *codec) | |||
1021 | if ((err = stac9200_auto_create_hp_ctls(codec, &spec->autocfg)) < 0) | 1354 | if ((err = stac9200_auto_create_hp_ctls(codec, &spec->autocfg)) < 0) |
1022 | return err; | 1355 | return err; |
1023 | 1356 | ||
1357 | if ((err = stac9200_auto_create_lfe_ctls(codec, &spec->autocfg)) < 0) | ||
1358 | return err; | ||
1359 | |||
1024 | if (spec->autocfg.dig_out_pin) | 1360 | if (spec->autocfg.dig_out_pin) |
1025 | spec->multiout.dig_out_nid = 0x05; | 1361 | spec->multiout.dig_out_nid = 0x05; |
1026 | if (spec->autocfg.dig_in_pin) | 1362 | if (spec->autocfg.dig_in_pin) |
@@ -1073,6 +1409,15 @@ static void stac922x_gpio_mute(struct hda_codec *codec, int pin, int muted) | |||
1073 | AC_VERB_SET_GPIO_DATA, gpiostate); | 1409 | AC_VERB_SET_GPIO_DATA, gpiostate); |
1074 | } | 1410 | } |
1075 | 1411 | ||
1412 | static void enable_pin_detect(struct hda_codec *codec, hda_nid_t nid, | ||
1413 | unsigned int event) | ||
1414 | { | ||
1415 | if (get_wcaps(codec, nid) & AC_WCAP_UNSOL_CAP) | ||
1416 | snd_hda_codec_write(codec, nid, 0, | ||
1417 | AC_VERB_SET_UNSOLICITED_ENABLE, | ||
1418 | (AC_USRSP_EN | event)); | ||
1419 | } | ||
1420 | |||
1076 | static int stac92xx_init(struct hda_codec *codec) | 1421 | static int stac92xx_init(struct hda_codec *codec) |
1077 | { | 1422 | { |
1078 | struct sigmatel_spec *spec = codec->spec; | 1423 | struct sigmatel_spec *spec = codec->spec; |
@@ -1084,9 +1429,10 @@ static int stac92xx_init(struct hda_codec *codec) | |||
1084 | /* set up pins */ | 1429 | /* set up pins */ |
1085 | if (spec->hp_detect) { | 1430 | if (spec->hp_detect) { |
1086 | /* Enable unsolicited responses on the HP widget */ | 1431 | /* Enable unsolicited responses on the HP widget */ |
1087 | snd_hda_codec_write(codec, cfg->hp_pin, 0, | 1432 | for (i = 0; i < cfg->hp_outs; i++) |
1088 | AC_VERB_SET_UNSOLICITED_ENABLE, | 1433 | enable_pin_detect(codec, cfg->hp_pins[i], |
1089 | STAC_UNSOL_ENABLE); | 1434 | STAC_HP_EVENT); |
1435 | stac92xx_auto_init_hp_out(codec); | ||
1090 | /* fake event to set up pins */ | 1436 | /* fake event to set up pins */ |
1091 | codec->patch_ops.unsol_event(codec, STAC_HP_EVENT << 26); | 1437 | codec->patch_ops.unsol_event(codec, STAC_HP_EVENT << 26); |
1092 | } else { | 1438 | } else { |
@@ -1131,6 +1477,9 @@ static void stac92xx_free(struct hda_codec *codec) | |||
1131 | kfree(spec->kctl_alloc); | 1477 | kfree(spec->kctl_alloc); |
1132 | } | 1478 | } |
1133 | 1479 | ||
1480 | if (spec->bios_pin_configs) | ||
1481 | kfree(spec->bios_pin_configs); | ||
1482 | |||
1134 | kfree(spec); | 1483 | kfree(spec); |
1135 | } | 1484 | } |
1136 | 1485 | ||
@@ -1139,6 +1488,8 @@ static void stac92xx_set_pinctl(struct hda_codec *codec, hda_nid_t nid, | |||
1139 | { | 1488 | { |
1140 | unsigned int pin_ctl = snd_hda_codec_read(codec, nid, | 1489 | unsigned int pin_ctl = snd_hda_codec_read(codec, nid, |
1141 | 0, AC_VERB_GET_PIN_WIDGET_CONTROL, 0x00); | 1490 | 0, AC_VERB_GET_PIN_WIDGET_CONTROL, 0x00); |
1491 | if (flag == AC_PINCTL_OUT_EN && (pin_ctl & AC_PINCTL_IN_EN)) | ||
1492 | return; | ||
1142 | snd_hda_codec_write(codec, nid, 0, | 1493 | snd_hda_codec_write(codec, nid, 0, |
1143 | AC_VERB_SET_PIN_WIDGET_CONTROL, | 1494 | AC_VERB_SET_PIN_WIDGET_CONTROL, |
1144 | pin_ctl | flag); | 1495 | pin_ctl | flag); |
@@ -1154,33 +1505,57 @@ static void stac92xx_reset_pinctl(struct hda_codec *codec, hda_nid_t nid, | |||
1154 | pin_ctl & ~flag); | 1505 | pin_ctl & ~flag); |
1155 | } | 1506 | } |
1156 | 1507 | ||
1157 | static void stac92xx_unsol_event(struct hda_codec *codec, unsigned int res) | 1508 | static int get_pin_presence(struct hda_codec *codec, hda_nid_t nid) |
1509 | { | ||
1510 | if (!nid) | ||
1511 | return 0; | ||
1512 | if (snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_PIN_SENSE, 0x00) | ||
1513 | & (1 << 31)) | ||
1514 | return 1; | ||
1515 | return 0; | ||
1516 | } | ||
1517 | |||
1518 | static void stac92xx_hp_detect(struct hda_codec *codec, unsigned int res) | ||
1158 | { | 1519 | { |
1159 | struct sigmatel_spec *spec = codec->spec; | 1520 | struct sigmatel_spec *spec = codec->spec; |
1160 | struct auto_pin_cfg *cfg = &spec->autocfg; | 1521 | struct auto_pin_cfg *cfg = &spec->autocfg; |
1161 | int i, presence; | 1522 | int i, presence; |
1162 | 1523 | ||
1163 | if ((res >> 26) != STAC_HP_EVENT) | 1524 | presence = 0; |
1164 | return; | 1525 | for (i = 0; i < cfg->hp_outs; i++) { |
1165 | 1526 | presence = get_pin_presence(codec, cfg->hp_pins[i]); | |
1166 | presence = snd_hda_codec_read(codec, cfg->hp_pin, 0, | 1527 | if (presence) |
1167 | AC_VERB_GET_PIN_SENSE, 0x00) >> 31; | 1528 | break; |
1529 | } | ||
1168 | 1530 | ||
1169 | if (presence) { | 1531 | if (presence) { |
1170 | /* disable lineouts, enable hp */ | 1532 | /* disable lineouts, enable hp */ |
1171 | for (i = 0; i < cfg->line_outs; i++) | 1533 | for (i = 0; i < cfg->line_outs; i++) |
1172 | stac92xx_reset_pinctl(codec, cfg->line_out_pins[i], | 1534 | stac92xx_reset_pinctl(codec, cfg->line_out_pins[i], |
1173 | AC_PINCTL_OUT_EN); | 1535 | AC_PINCTL_OUT_EN); |
1174 | stac92xx_set_pinctl(codec, cfg->hp_pin, AC_PINCTL_OUT_EN); | 1536 | for (i = 0; i < cfg->speaker_outs; i++) |
1537 | stac92xx_reset_pinctl(codec, cfg->speaker_pins[i], | ||
1538 | AC_PINCTL_OUT_EN); | ||
1175 | } else { | 1539 | } else { |
1176 | /* enable lineouts, disable hp */ | 1540 | /* enable lineouts, disable hp */ |
1177 | for (i = 0; i < cfg->line_outs; i++) | 1541 | for (i = 0; i < cfg->line_outs; i++) |
1178 | stac92xx_set_pinctl(codec, cfg->line_out_pins[i], | 1542 | stac92xx_set_pinctl(codec, cfg->line_out_pins[i], |
1179 | AC_PINCTL_OUT_EN); | 1543 | AC_PINCTL_OUT_EN); |
1180 | stac92xx_reset_pinctl(codec, cfg->hp_pin, AC_PINCTL_OUT_EN); | 1544 | for (i = 0; i < cfg->speaker_outs; i++) |
1545 | stac92xx_set_pinctl(codec, cfg->speaker_pins[i], | ||
1546 | AC_PINCTL_OUT_EN); | ||
1181 | } | 1547 | } |
1182 | } | 1548 | } |
1183 | 1549 | ||
1550 | static void stac92xx_unsol_event(struct hda_codec *codec, unsigned int res) | ||
1551 | { | ||
1552 | switch (res >> 26) { | ||
1553 | case STAC_HP_EVENT: | ||
1554 | stac92xx_hp_detect(codec, res); | ||
1555 | break; | ||
1556 | } | ||
1557 | } | ||
1558 | |||
1184 | #ifdef CONFIG_PM | 1559 | #ifdef CONFIG_PM |
1185 | static int stac92xx_resume(struct hda_codec *codec) | 1560 | static int stac92xx_resume(struct hda_codec *codec) |
1186 | { | 1561 | { |
@@ -1188,6 +1563,7 @@ static int stac92xx_resume(struct hda_codec *codec) | |||
1188 | int i; | 1563 | int i; |
1189 | 1564 | ||
1190 | stac92xx_init(codec); | 1565 | stac92xx_init(codec); |
1566 | stac92xx_set_config_regs(codec); | ||
1191 | for (i = 0; i < spec->num_mixers; i++) | 1567 | for (i = 0; i < spec->num_mixers; i++) |
1192 | snd_hda_resume_ctls(codec, spec->mixers[i]); | 1568 | snd_hda_resume_ctls(codec, spec->mixers[i]); |
1193 | if (spec->multiout.dig_out_nid) | 1569 | if (spec->multiout.dig_out_nid) |
@@ -1220,12 +1596,18 @@ static int patch_stac9200(struct hda_codec *codec) | |||
1220 | return -ENOMEM; | 1596 | return -ENOMEM; |
1221 | 1597 | ||
1222 | codec->spec = spec; | 1598 | codec->spec = spec; |
1599 | spec->num_pins = 8; | ||
1600 | spec->pin_nids = stac9200_pin_nids; | ||
1223 | spec->board_config = snd_hda_check_board_config(codec, stac9200_cfg_tbl); | 1601 | spec->board_config = snd_hda_check_board_config(codec, stac9200_cfg_tbl); |
1224 | if (spec->board_config < 0) | 1602 | if (spec->board_config < 0) { |
1225 | snd_printdd(KERN_INFO "hda_codec: Unknown model for STAC9200, using BIOS defaults\n"); | 1603 | snd_printdd(KERN_INFO "hda_codec: Unknown model for STAC9200, using BIOS defaults\n"); |
1226 | else { | 1604 | err = stac92xx_save_bios_config_regs(codec); |
1227 | spec->num_pins = 8; | 1605 | if (err < 0) { |
1228 | spec->pin_nids = stac9200_pin_nids; | 1606 | stac92xx_free(codec); |
1607 | return err; | ||
1608 | } | ||
1609 | spec->pin_configs = spec->bios_pin_configs; | ||
1610 | } else { | ||
1229 | spec->pin_configs = stac9200_brd_tbl[spec->board_config]; | 1611 | spec->pin_configs = stac9200_brd_tbl[spec->board_config]; |
1230 | stac92xx_set_config_regs(codec); | 1612 | stac92xx_set_config_regs(codec); |
1231 | } | 1613 | } |
@@ -1261,13 +1643,19 @@ static int patch_stac922x(struct hda_codec *codec) | |||
1261 | return -ENOMEM; | 1643 | return -ENOMEM; |
1262 | 1644 | ||
1263 | codec->spec = spec; | 1645 | codec->spec = spec; |
1646 | spec->num_pins = 10; | ||
1647 | spec->pin_nids = stac922x_pin_nids; | ||
1264 | spec->board_config = snd_hda_check_board_config(codec, stac922x_cfg_tbl); | 1648 | spec->board_config = snd_hda_check_board_config(codec, stac922x_cfg_tbl); |
1265 | if (spec->board_config < 0) | 1649 | if (spec->board_config < 0) { |
1266 | snd_printdd(KERN_INFO "hda_codec: Unknown model for STAC922x, " | 1650 | snd_printdd(KERN_INFO "hda_codec: Unknown model for STAC922x, " |
1267 | "using BIOS defaults\n"); | 1651 | "using BIOS defaults\n"); |
1268 | else if (stac922x_brd_tbl[spec->board_config] != NULL) { | 1652 | err = stac92xx_save_bios_config_regs(codec); |
1269 | spec->num_pins = 10; | 1653 | if (err < 0) { |
1270 | spec->pin_nids = stac922x_pin_nids; | 1654 | stac92xx_free(codec); |
1655 | return err; | ||
1656 | } | ||
1657 | spec->pin_configs = spec->bios_pin_configs; | ||
1658 | } else if (stac922x_brd_tbl[spec->board_config] != NULL) { | ||
1271 | spec->pin_configs = stac922x_brd_tbl[spec->board_config]; | 1659 | spec->pin_configs = stac922x_brd_tbl[spec->board_config]; |
1272 | stac92xx_set_config_regs(codec); | 1660 | stac92xx_set_config_regs(codec); |
1273 | } | 1661 | } |
@@ -1281,25 +1669,6 @@ static int patch_stac922x(struct hda_codec *codec) | |||
1281 | 1669 | ||
1282 | spec->multiout.dac_nids = spec->dac_nids; | 1670 | spec->multiout.dac_nids = spec->dac_nids; |
1283 | 1671 | ||
1284 | switch (spec->board_config) { | ||
1285 | case STAC_D965_2112: | ||
1286 | spec->adc_nids = stac9227_adc_nids; | ||
1287 | spec->mux_nids = stac9227_mux_nids; | ||
1288 | #if 0 | ||
1289 | spec->multiout.dac_nids = d965_2112_dac_nids; | ||
1290 | spec->multiout.num_dacs = ARRAY_SIZE(d965_2112_dac_nids); | ||
1291 | #endif | ||
1292 | spec->init = d965_2112_core_init; | ||
1293 | spec->mixer = stac9227_mixer; | ||
1294 | break; | ||
1295 | case STAC_D965_284B: | ||
1296 | spec->adc_nids = stac9227_adc_nids; | ||
1297 | spec->mux_nids = stac9227_mux_nids; | ||
1298 | spec->init = stac9227_core_init; | ||
1299 | spec->mixer = stac9227_mixer; | ||
1300 | break; | ||
1301 | } | ||
1302 | |||
1303 | err = stac92xx_parse_auto_config(codec, 0x08, 0x09); | 1672 | err = stac92xx_parse_auto_config(codec, 0x08, 0x09); |
1304 | if (err < 0) { | 1673 | if (err < 0) { |
1305 | stac92xx_free(codec); | 1674 | stac92xx_free(codec); |
@@ -1324,26 +1693,94 @@ static int patch_stac927x(struct hda_codec *codec) | |||
1324 | return -ENOMEM; | 1693 | return -ENOMEM; |
1325 | 1694 | ||
1326 | codec->spec = spec; | 1695 | codec->spec = spec; |
1696 | spec->num_pins = 14; | ||
1697 | spec->pin_nids = stac927x_pin_nids; | ||
1327 | spec->board_config = snd_hda_check_board_config(codec, stac927x_cfg_tbl); | 1698 | spec->board_config = snd_hda_check_board_config(codec, stac927x_cfg_tbl); |
1328 | if (spec->board_config < 0) | 1699 | if (spec->board_config < 0) { |
1329 | snd_printdd(KERN_INFO "hda_codec: Unknown model for STAC927x, using BIOS defaults\n"); | 1700 | snd_printdd(KERN_INFO "hda_codec: Unknown model for STAC927x, using BIOS defaults\n"); |
1330 | else { | 1701 | err = stac92xx_save_bios_config_regs(codec); |
1331 | spec->num_pins = 14; | 1702 | if (err < 0) { |
1332 | spec->pin_nids = stac927x_pin_nids; | 1703 | stac92xx_free(codec); |
1704 | return err; | ||
1705 | } | ||
1706 | spec->pin_configs = spec->bios_pin_configs; | ||
1707 | } else if (stac927x_brd_tbl[spec->board_config] != NULL) { | ||
1333 | spec->pin_configs = stac927x_brd_tbl[spec->board_config]; | 1708 | spec->pin_configs = stac927x_brd_tbl[spec->board_config]; |
1334 | stac92xx_set_config_regs(codec); | 1709 | stac92xx_set_config_regs(codec); |
1335 | } | 1710 | } |
1336 | 1711 | ||
1337 | spec->adc_nids = stac927x_adc_nids; | 1712 | switch (spec->board_config) { |
1338 | spec->mux_nids = stac927x_mux_nids; | 1713 | case STAC_D965_3ST: |
1714 | spec->adc_nids = stac927x_adc_nids; | ||
1715 | spec->mux_nids = stac927x_mux_nids; | ||
1716 | spec->num_muxes = 3; | ||
1717 | spec->init = d965_core_init; | ||
1718 | spec->mixer = stac9227_mixer; | ||
1719 | break; | ||
1720 | case STAC_D965_5ST: | ||
1721 | spec->adc_nids = stac927x_adc_nids; | ||
1722 | spec->mux_nids = stac927x_mux_nids; | ||
1723 | spec->num_muxes = 3; | ||
1724 | spec->init = d965_core_init; | ||
1725 | spec->mixer = stac9227_mixer; | ||
1726 | break; | ||
1727 | default: | ||
1728 | spec->adc_nids = stac927x_adc_nids; | ||
1729 | spec->mux_nids = stac927x_mux_nids; | ||
1730 | spec->num_muxes = 3; | ||
1731 | spec->init = stac927x_core_init; | ||
1732 | spec->mixer = stac927x_mixer; | ||
1733 | } | ||
1734 | |||
1735 | spec->multiout.dac_nids = spec->dac_nids; | ||
1736 | |||
1737 | err = stac92xx_parse_auto_config(codec, 0x1e, 0x20); | ||
1738 | if (err < 0) { | ||
1739 | stac92xx_free(codec); | ||
1740 | return err; | ||
1741 | } | ||
1742 | |||
1743 | codec->patch_ops = stac92xx_patch_ops; | ||
1744 | |||
1745 | return 0; | ||
1746 | } | ||
1747 | |||
1748 | static int patch_stac9205(struct hda_codec *codec) | ||
1749 | { | ||
1750 | struct sigmatel_spec *spec; | ||
1751 | int err; | ||
1752 | |||
1753 | spec = kzalloc(sizeof(*spec), GFP_KERNEL); | ||
1754 | if (spec == NULL) | ||
1755 | return -ENOMEM; | ||
1756 | |||
1757 | codec->spec = spec; | ||
1758 | spec->num_pins = 14; | ||
1759 | spec->pin_nids = stac9205_pin_nids; | ||
1760 | spec->board_config = snd_hda_check_board_config(codec, stac9205_cfg_tbl); | ||
1761 | if (spec->board_config < 0) { | ||
1762 | snd_printdd(KERN_INFO "hda_codec: Unknown model for STAC9205, using BIOS defaults\n"); | ||
1763 | err = stac92xx_save_bios_config_regs(codec); | ||
1764 | if (err < 0) { | ||
1765 | stac92xx_free(codec); | ||
1766 | return err; | ||
1767 | } | ||
1768 | spec->pin_configs = spec->bios_pin_configs; | ||
1769 | } else { | ||
1770 | spec->pin_configs = stac9205_brd_tbl[spec->board_config]; | ||
1771 | stac92xx_set_config_regs(codec); | ||
1772 | } | ||
1773 | |||
1774 | spec->adc_nids = stac9205_adc_nids; | ||
1775 | spec->mux_nids = stac9205_mux_nids; | ||
1339 | spec->num_muxes = 3; | 1776 | spec->num_muxes = 3; |
1340 | 1777 | ||
1341 | spec->init = stac927x_core_init; | 1778 | spec->init = stac9205_core_init; |
1342 | spec->mixer = stac927x_mixer; | 1779 | spec->mixer = stac9205_mixer; |
1343 | 1780 | ||
1344 | spec->multiout.dac_nids = spec->dac_nids; | 1781 | spec->multiout.dac_nids = spec->dac_nids; |
1345 | 1782 | ||
1346 | err = stac92xx_parse_auto_config(codec, 0x1e, 0x20); | 1783 | err = stac92xx_parse_auto_config(codec, 0x1f, 0x20); |
1347 | if (err < 0) { | 1784 | if (err < 0) { |
1348 | stac92xx_free(codec); | 1785 | stac92xx_free(codec); |
1349 | return err; | 1786 | return err; |
@@ -1355,10 +1792,10 @@ static int patch_stac927x(struct hda_codec *codec) | |||
1355 | } | 1792 | } |
1356 | 1793 | ||
1357 | /* | 1794 | /* |
1358 | * STAC 7661(?) hack | 1795 | * STAC9872 hack |
1359 | */ | 1796 | */ |
1360 | 1797 | ||
1361 | /* static config for Sony VAIO FE550G */ | 1798 | /* static config for Sony VAIO FE550G and Sony VAIO AR */ |
1362 | static hda_nid_t vaio_dacs[] = { 0x2 }; | 1799 | static hda_nid_t vaio_dacs[] = { 0x2 }; |
1363 | #define VAIO_HP_DAC 0x5 | 1800 | #define VAIO_HP_DAC 0x5 |
1364 | static hda_nid_t vaio_adcs[] = { 0x8 /*,0x6*/ }; | 1801 | static hda_nid_t vaio_adcs[] = { 0x8 /*,0x6*/ }; |
@@ -1389,6 +1826,23 @@ static struct hda_verb vaio_init[] = { | |||
1389 | {} | 1826 | {} |
1390 | }; | 1827 | }; |
1391 | 1828 | ||
1829 | static struct hda_verb vaio_ar_init[] = { | ||
1830 | {0x0a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP }, /* HP <- 0x2 */ | ||
1831 | {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, /* Speaker <- 0x5 */ | ||
1832 | {0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* Mic? (<- 0x2) */ | ||
1833 | {0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, /* CD */ | ||
1834 | /* {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },*/ /* Optical Out */ | ||
1835 | {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* Mic? */ | ||
1836 | {0x15, AC_VERB_SET_CONNECT_SEL, 0x2}, /* mic-sel: 0a,0d,14,02 */ | ||
1837 | {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, /* HP */ | ||
1838 | {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, /* Speaker */ | ||
1839 | /* {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},*/ /* Optical Out */ | ||
1840 | {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* capture sw/vol -> 0x8 */ | ||
1841 | {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, /* CD-in -> 0x6 */ | ||
1842 | {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* Mic-in -> 0x9 */ | ||
1843 | {} | ||
1844 | }; | ||
1845 | |||
1392 | /* bind volumes of both NID 0x02 and 0x05 */ | 1846 | /* bind volumes of both NID 0x02 and 0x05 */ |
1393 | static int vaio_master_vol_put(struct snd_kcontrol *kcontrol, | 1847 | static int vaio_master_vol_put(struct snd_kcontrol *kcontrol, |
1394 | struct snd_ctl_elem_value *ucontrol) | 1848 | struct snd_ctl_elem_value *ucontrol) |
@@ -1434,6 +1888,38 @@ static struct snd_kcontrol_new vaio_mixer[] = { | |||
1434 | .info = snd_hda_mixer_amp_volume_info, | 1888 | .info = snd_hda_mixer_amp_volume_info, |
1435 | .get = snd_hda_mixer_amp_volume_get, | 1889 | .get = snd_hda_mixer_amp_volume_get, |
1436 | .put = vaio_master_vol_put, | 1890 | .put = vaio_master_vol_put, |
1891 | .tlv = { .c = snd_hda_mixer_amp_tlv }, | ||
1892 | .private_value = HDA_COMPOSE_AMP_VAL(0x02, 3, 0, HDA_OUTPUT), | ||
1893 | }, | ||
1894 | { | ||
1895 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
1896 | .name = "Master Playback Switch", | ||
1897 | .info = snd_hda_mixer_amp_switch_info, | ||
1898 | .get = snd_hda_mixer_amp_switch_get, | ||
1899 | .put = vaio_master_sw_put, | ||
1900 | .private_value = HDA_COMPOSE_AMP_VAL(0x02, 3, 0, HDA_OUTPUT), | ||
1901 | }, | ||
1902 | /* HDA_CODEC_VOLUME("CD Capture Volume", 0x07, 0, HDA_INPUT), */ | ||
1903 | HDA_CODEC_VOLUME("Capture Volume", 0x09, 0, HDA_INPUT), | ||
1904 | HDA_CODEC_MUTE("Capture Switch", 0x09, 0, HDA_INPUT), | ||
1905 | { | ||
1906 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
1907 | .name = "Capture Source", | ||
1908 | .count = 1, | ||
1909 | .info = stac92xx_mux_enum_info, | ||
1910 | .get = stac92xx_mux_enum_get, | ||
1911 | .put = stac92xx_mux_enum_put, | ||
1912 | }, | ||
1913 | {} | ||
1914 | }; | ||
1915 | |||
1916 | static struct snd_kcontrol_new vaio_ar_mixer[] = { | ||
1917 | { | ||
1918 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
1919 | .name = "Master Playback Volume", | ||
1920 | .info = snd_hda_mixer_amp_volume_info, | ||
1921 | .get = snd_hda_mixer_amp_volume_get, | ||
1922 | .put = vaio_master_vol_put, | ||
1437 | .private_value = HDA_COMPOSE_AMP_VAL(0x02, 3, 0, HDA_OUTPUT), | 1923 | .private_value = HDA_COMPOSE_AMP_VAL(0x02, 3, 0, HDA_OUTPUT), |
1438 | }, | 1924 | }, |
1439 | { | 1925 | { |
@@ -1447,6 +1933,8 @@ static struct snd_kcontrol_new vaio_mixer[] = { | |||
1447 | /* HDA_CODEC_VOLUME("CD Capture Volume", 0x07, 0, HDA_INPUT), */ | 1933 | /* HDA_CODEC_VOLUME("CD Capture Volume", 0x07, 0, HDA_INPUT), */ |
1448 | HDA_CODEC_VOLUME("Capture Volume", 0x09, 0, HDA_INPUT), | 1934 | HDA_CODEC_VOLUME("Capture Volume", 0x09, 0, HDA_INPUT), |
1449 | HDA_CODEC_MUTE("Capture Switch", 0x09, 0, HDA_INPUT), | 1935 | HDA_CODEC_MUTE("Capture Switch", 0x09, 0, HDA_INPUT), |
1936 | /*HDA_CODEC_MUTE("Optical Out Switch", 0x10, 0, HDA_OUTPUT), | ||
1937 | HDA_CODEC_VOLUME("Optical Out Volume", 0x10, 0, HDA_OUTPUT),*/ | ||
1450 | { | 1938 | { |
1451 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 1939 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
1452 | .name = "Capture Source", | 1940 | .name = "Capture Source", |
@@ -1458,7 +1946,7 @@ static struct snd_kcontrol_new vaio_mixer[] = { | |||
1458 | {} | 1946 | {} |
1459 | }; | 1947 | }; |
1460 | 1948 | ||
1461 | static struct hda_codec_ops stac7661_patch_ops = { | 1949 | static struct hda_codec_ops stac9872_patch_ops = { |
1462 | .build_controls = stac92xx_build_controls, | 1950 | .build_controls = stac92xx_build_controls, |
1463 | .build_pcms = stac92xx_build_pcms, | 1951 | .build_pcms = stac92xx_build_pcms, |
1464 | .init = stac92xx_init, | 1952 | .init = stac92xx_init, |
@@ -1468,23 +1956,34 @@ static struct hda_codec_ops stac7661_patch_ops = { | |||
1468 | #endif | 1956 | #endif |
1469 | }; | 1957 | }; |
1470 | 1958 | ||
1471 | enum { STAC7661_VAIO }; | 1959 | enum { /* FE and SZ series. id=0x83847661 and subsys=0x104D0700 or 104D1000. */ |
1472 | 1960 | CXD9872RD_VAIO, | |
1473 | static struct hda_board_config stac7661_cfg_tbl[] = { | 1961 | /* Unknown. id=0x83847662 and subsys=0x104D1200 or 104D1000. */ |
1474 | { .modelname = "vaio", .config = STAC7661_VAIO }, | 1962 | STAC9872AK_VAIO, |
1963 | /* Unknown. id=0x83847661 and subsys=0x104D1200. */ | ||
1964 | STAC9872K_VAIO, | ||
1965 | /* AR Series. id=0x83847664 and subsys=104D1300 */ | ||
1966 | CXD9872AKD_VAIO | ||
1967 | }; | ||
1968 | |||
1969 | static struct hda_board_config stac9872_cfg_tbl[] = { | ||
1970 | { .modelname = "vaio", .config = CXD9872RD_VAIO }, | ||
1971 | { .modelname = "vaio-ar", .config = CXD9872AKD_VAIO }, | ||
1475 | { .pci_subvendor = 0x104d, .pci_subdevice = 0x81e6, | 1972 | { .pci_subvendor = 0x104d, .pci_subdevice = 0x81e6, |
1476 | .config = STAC7661_VAIO }, | 1973 | .config = CXD9872RD_VAIO }, |
1477 | { .pci_subvendor = 0x104d, .pci_subdevice = 0x81ef, | 1974 | { .pci_subvendor = 0x104d, .pci_subdevice = 0x81ef, |
1478 | .config = STAC7661_VAIO }, | 1975 | .config = CXD9872RD_VAIO }, |
1976 | { .pci_subvendor = 0x104d, .pci_subdevice = 0x81fd, | ||
1977 | .config = CXD9872AKD_VAIO }, | ||
1479 | {} | 1978 | {} |
1480 | }; | 1979 | }; |
1481 | 1980 | ||
1482 | static int patch_stac7661(struct hda_codec *codec) | 1981 | static int patch_stac9872(struct hda_codec *codec) |
1483 | { | 1982 | { |
1484 | struct sigmatel_spec *spec; | 1983 | struct sigmatel_spec *spec; |
1485 | int board_config; | 1984 | int board_config; |
1486 | 1985 | ||
1487 | board_config = snd_hda_check_board_config(codec, stac7661_cfg_tbl); | 1986 | board_config = snd_hda_check_board_config(codec, stac9872_cfg_tbl); |
1488 | if (board_config < 0) | 1987 | if (board_config < 0) |
1489 | /* unknown config, let generic-parser do its job... */ | 1988 | /* unknown config, let generic-parser do its job... */ |
1490 | return snd_hda_parse_generic_codec(codec); | 1989 | return snd_hda_parse_generic_codec(codec); |
@@ -1495,7 +1994,9 @@ static int patch_stac7661(struct hda_codec *codec) | |||
1495 | 1994 | ||
1496 | codec->spec = spec; | 1995 | codec->spec = spec; |
1497 | switch (board_config) { | 1996 | switch (board_config) { |
1498 | case STAC7661_VAIO: | 1997 | case CXD9872RD_VAIO: |
1998 | case STAC9872AK_VAIO: | ||
1999 | case STAC9872K_VAIO: | ||
1499 | spec->mixer = vaio_mixer; | 2000 | spec->mixer = vaio_mixer; |
1500 | spec->init = vaio_init; | 2001 | spec->init = vaio_init; |
1501 | spec->multiout.max_channels = 2; | 2002 | spec->multiout.max_channels = 2; |
@@ -1507,9 +2008,22 @@ static int patch_stac7661(struct hda_codec *codec) | |||
1507 | spec->input_mux = &vaio_mux; | 2008 | spec->input_mux = &vaio_mux; |
1508 | spec->mux_nids = vaio_mux_nids; | 2009 | spec->mux_nids = vaio_mux_nids; |
1509 | break; | 2010 | break; |
2011 | |||
2012 | case CXD9872AKD_VAIO: | ||
2013 | spec->mixer = vaio_ar_mixer; | ||
2014 | spec->init = vaio_ar_init; | ||
2015 | spec->multiout.max_channels = 2; | ||
2016 | spec->multiout.num_dacs = ARRAY_SIZE(vaio_dacs); | ||
2017 | spec->multiout.dac_nids = vaio_dacs; | ||
2018 | spec->multiout.hp_nid = VAIO_HP_DAC; | ||
2019 | spec->num_adcs = ARRAY_SIZE(vaio_adcs); | ||
2020 | spec->adc_nids = vaio_adcs; | ||
2021 | spec->input_mux = &vaio_mux; | ||
2022 | spec->mux_nids = vaio_mux_nids; | ||
2023 | break; | ||
1510 | } | 2024 | } |
1511 | 2025 | ||
1512 | codec->patch_ops = stac7661_patch_ops; | 2026 | codec->patch_ops = stac9872_patch_ops; |
1513 | return 0; | 2027 | return 0; |
1514 | } | 2028 | } |
1515 | 2029 | ||
@@ -1525,12 +2039,12 @@ struct hda_codec_preset snd_hda_preset_sigmatel[] = { | |||
1525 | { .id = 0x83847681, .name = "STAC9220D/9223D A2", .patch = patch_stac922x }, | 2039 | { .id = 0x83847681, .name = "STAC9220D/9223D A2", .patch = patch_stac922x }, |
1526 | { .id = 0x83847682, .name = "STAC9221 A2", .patch = patch_stac922x }, | 2040 | { .id = 0x83847682, .name = "STAC9221 A2", .patch = patch_stac922x }, |
1527 | { .id = 0x83847683, .name = "STAC9221D A2", .patch = patch_stac922x }, | 2041 | { .id = 0x83847683, .name = "STAC9221D A2", .patch = patch_stac922x }, |
1528 | { .id = 0x83847618, .name = "STAC9227", .patch = patch_stac922x }, | 2042 | { .id = 0x83847618, .name = "STAC9227", .patch = patch_stac927x }, |
1529 | { .id = 0x83847619, .name = "STAC9227", .patch = patch_stac922x }, | 2043 | { .id = 0x83847619, .name = "STAC9227", .patch = patch_stac927x }, |
1530 | { .id = 0x83847616, .name = "STAC9228", .patch = patch_stac922x }, | 2044 | { .id = 0x83847616, .name = "STAC9228", .patch = patch_stac927x }, |
1531 | { .id = 0x83847617, .name = "STAC9228", .patch = patch_stac922x }, | 2045 | { .id = 0x83847617, .name = "STAC9228", .patch = patch_stac927x }, |
1532 | { .id = 0x83847614, .name = "STAC9229", .patch = patch_stac922x }, | 2046 | { .id = 0x83847614, .name = "STAC9229", .patch = patch_stac927x }, |
1533 | { .id = 0x83847615, .name = "STAC9229", .patch = patch_stac922x }, | 2047 | { .id = 0x83847615, .name = "STAC9229", .patch = patch_stac927x }, |
1534 | { .id = 0x83847620, .name = "STAC9274", .patch = patch_stac927x }, | 2048 | { .id = 0x83847620, .name = "STAC9274", .patch = patch_stac927x }, |
1535 | { .id = 0x83847621, .name = "STAC9274D", .patch = patch_stac927x }, | 2049 | { .id = 0x83847621, .name = "STAC9274D", .patch = patch_stac927x }, |
1536 | { .id = 0x83847622, .name = "STAC9273X", .patch = patch_stac927x }, | 2050 | { .id = 0x83847622, .name = "STAC9273X", .patch = patch_stac927x }, |
@@ -1541,6 +2055,20 @@ struct hda_codec_preset snd_hda_preset_sigmatel[] = { | |||
1541 | { .id = 0x83847627, .name = "STAC9271D", .patch = patch_stac927x }, | 2055 | { .id = 0x83847627, .name = "STAC9271D", .patch = patch_stac927x }, |
1542 | { .id = 0x83847628, .name = "STAC9274X5NH", .patch = patch_stac927x }, | 2056 | { .id = 0x83847628, .name = "STAC9274X5NH", .patch = patch_stac927x }, |
1543 | { .id = 0x83847629, .name = "STAC9274D5NH", .patch = patch_stac927x }, | 2057 | { .id = 0x83847629, .name = "STAC9274D5NH", .patch = patch_stac927x }, |
1544 | { .id = 0x83847661, .name = "STAC7661", .patch = patch_stac7661 }, | 2058 | /* The following does not take into account .id=0x83847661 when subsys = |
2059 | * 104D0C00 which is STAC9225s. Because of this, some SZ Notebooks are | ||
2060 | * currently not fully supported. | ||
2061 | */ | ||
2062 | { .id = 0x83847661, .name = "CXD9872RD/K", .patch = patch_stac9872 }, | ||
2063 | { .id = 0x83847662, .name = "STAC9872AK", .patch = patch_stac9872 }, | ||
2064 | { .id = 0x83847664, .name = "CXD9872AKD", .patch = patch_stac9872 }, | ||
2065 | { .id = 0x838476a0, .name = "STAC9205", .patch = patch_stac9205 }, | ||
2066 | { .id = 0x838476a1, .name = "STAC9205D", .patch = patch_stac9205 }, | ||
2067 | { .id = 0x838476a2, .name = "STAC9204", .patch = patch_stac9205 }, | ||
2068 | { .id = 0x838476a3, .name = "STAC9204D", .patch = patch_stac9205 }, | ||
2069 | { .id = 0x838476a4, .name = "STAC9255", .patch = patch_stac9205 }, | ||
2070 | { .id = 0x838476a5, .name = "STAC9255D", .patch = patch_stac9205 }, | ||
2071 | { .id = 0x838476a6, .name = "STAC9254", .patch = patch_stac9205 }, | ||
2072 | { .id = 0x838476a7, .name = "STAC9254D", .patch = patch_stac9205 }, | ||
1545 | {} /* terminator */ | 2073 | {} /* terminator */ |
1546 | }; | 2074 | }; |
diff --git a/sound/pci/ice1712/aureon.c b/sound/pci/ice1712/aureon.c index 9492f3d2455b..9e76cebd2d22 100644 --- a/sound/pci/ice1712/aureon.c +++ b/sound/pci/ice1712/aureon.c | |||
@@ -60,6 +60,7 @@ | |||
60 | #include "ice1712.h" | 60 | #include "ice1712.h" |
61 | #include "envy24ht.h" | 61 | #include "envy24ht.h" |
62 | #include "aureon.h" | 62 | #include "aureon.h" |
63 | #include <sound/tlv.h> | ||
63 | 64 | ||
64 | /* WM8770 registers */ | 65 | /* WM8770 registers */ |
65 | #define WM_DAC_ATTEN 0x00 /* DAC1-8 analog attenuation */ | 66 | #define WM_DAC_ATTEN 0x00 /* DAC1-8 analog attenuation */ |
@@ -660,6 +661,12 @@ static int aureon_ac97_mmute_put(struct snd_kcontrol *kcontrol, struct snd_ctl_e | |||
660 | return change; | 661 | return change; |
661 | } | 662 | } |
662 | 663 | ||
664 | static DECLARE_TLV_DB_SCALE(db_scale_wm_dac, -12700, 100, 1); | ||
665 | static DECLARE_TLV_DB_SCALE(db_scale_wm_pcm, -6400, 50, 1); | ||
666 | static DECLARE_TLV_DB_SCALE(db_scale_wm_adc, -1200, 100, 0); | ||
667 | static DECLARE_TLV_DB_SCALE(db_scale_ac97_master, -4650, 150, 0); | ||
668 | static DECLARE_TLV_DB_SCALE(db_scale_ac97_gain, -3450, 150, 0); | ||
669 | |||
663 | /* | 670 | /* |
664 | * Logarithmic volume values for WM8770 | 671 | * Logarithmic volume values for WM8770 |
665 | * Computed as 20 * Log10(255 / x) | 672 | * Computed as 20 * Log10(255 / x) |
@@ -1409,10 +1416,13 @@ static struct snd_kcontrol_new aureon_dac_controls[] __devinitdata = { | |||
1409 | }, | 1416 | }, |
1410 | { | 1417 | { |
1411 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 1418 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
1419 | .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | | ||
1420 | SNDRV_CTL_ELEM_ACCESS_TLV_READ), | ||
1412 | .name = "Master Playback Volume", | 1421 | .name = "Master Playback Volume", |
1413 | .info = wm_master_vol_info, | 1422 | .info = wm_master_vol_info, |
1414 | .get = wm_master_vol_get, | 1423 | .get = wm_master_vol_get, |
1415 | .put = wm_master_vol_put | 1424 | .put = wm_master_vol_put, |
1425 | .tlv = { .p = db_scale_wm_dac } | ||
1416 | }, | 1426 | }, |
1417 | { | 1427 | { |
1418 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 1428 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
@@ -1424,11 +1434,14 @@ static struct snd_kcontrol_new aureon_dac_controls[] __devinitdata = { | |||
1424 | }, | 1434 | }, |
1425 | { | 1435 | { |
1426 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 1436 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
1437 | .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | | ||
1438 | SNDRV_CTL_ELEM_ACCESS_TLV_READ), | ||
1427 | .name = "Front Playback Volume", | 1439 | .name = "Front Playback Volume", |
1428 | .info = wm_vol_info, | 1440 | .info = wm_vol_info, |
1429 | .get = wm_vol_get, | 1441 | .get = wm_vol_get, |
1430 | .put = wm_vol_put, | 1442 | .put = wm_vol_put, |
1431 | .private_value = (2 << 8) | 0 | 1443 | .private_value = (2 << 8) | 0, |
1444 | .tlv = { .p = db_scale_wm_dac } | ||
1432 | }, | 1445 | }, |
1433 | { | 1446 | { |
1434 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 1447 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
@@ -1440,11 +1453,14 @@ static struct snd_kcontrol_new aureon_dac_controls[] __devinitdata = { | |||
1440 | }, | 1453 | }, |
1441 | { | 1454 | { |
1442 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 1455 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
1456 | .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | | ||
1457 | SNDRV_CTL_ELEM_ACCESS_TLV_READ), | ||
1443 | .name = "Rear Playback Volume", | 1458 | .name = "Rear Playback Volume", |
1444 | .info = wm_vol_info, | 1459 | .info = wm_vol_info, |
1445 | .get = wm_vol_get, | 1460 | .get = wm_vol_get, |
1446 | .put = wm_vol_put, | 1461 | .put = wm_vol_put, |
1447 | .private_value = (2 << 8) | 2 | 1462 | .private_value = (2 << 8) | 2, |
1463 | .tlv = { .p = db_scale_wm_dac } | ||
1448 | }, | 1464 | }, |
1449 | { | 1465 | { |
1450 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 1466 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
@@ -1456,11 +1472,14 @@ static struct snd_kcontrol_new aureon_dac_controls[] __devinitdata = { | |||
1456 | }, | 1472 | }, |
1457 | { | 1473 | { |
1458 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 1474 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
1475 | .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | | ||
1476 | SNDRV_CTL_ELEM_ACCESS_TLV_READ), | ||
1459 | .name = "Center Playback Volume", | 1477 | .name = "Center Playback Volume", |
1460 | .info = wm_vol_info, | 1478 | .info = wm_vol_info, |
1461 | .get = wm_vol_get, | 1479 | .get = wm_vol_get, |
1462 | .put = wm_vol_put, | 1480 | .put = wm_vol_put, |
1463 | .private_value = (1 << 8) | 4 | 1481 | .private_value = (1 << 8) | 4, |
1482 | .tlv = { .p = db_scale_wm_dac } | ||
1464 | }, | 1483 | }, |
1465 | { | 1484 | { |
1466 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 1485 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
@@ -1472,11 +1491,14 @@ static struct snd_kcontrol_new aureon_dac_controls[] __devinitdata = { | |||
1472 | }, | 1491 | }, |
1473 | { | 1492 | { |
1474 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 1493 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
1494 | .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | | ||
1495 | SNDRV_CTL_ELEM_ACCESS_TLV_READ), | ||
1475 | .name = "LFE Playback Volume", | 1496 | .name = "LFE Playback Volume", |
1476 | .info = wm_vol_info, | 1497 | .info = wm_vol_info, |
1477 | .get = wm_vol_get, | 1498 | .get = wm_vol_get, |
1478 | .put = wm_vol_put, | 1499 | .put = wm_vol_put, |
1479 | .private_value = (1 << 8) | 5 | 1500 | .private_value = (1 << 8) | 5, |
1501 | .tlv = { .p = db_scale_wm_dac } | ||
1480 | }, | 1502 | }, |
1481 | { | 1503 | { |
1482 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 1504 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
@@ -1488,11 +1510,14 @@ static struct snd_kcontrol_new aureon_dac_controls[] __devinitdata = { | |||
1488 | }, | 1510 | }, |
1489 | { | 1511 | { |
1490 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 1512 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
1513 | .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | | ||
1514 | SNDRV_CTL_ELEM_ACCESS_TLV_READ), | ||
1491 | .name = "Side Playback Volume", | 1515 | .name = "Side Playback Volume", |
1492 | .info = wm_vol_info, | 1516 | .info = wm_vol_info, |
1493 | .get = wm_vol_get, | 1517 | .get = wm_vol_get, |
1494 | .put = wm_vol_put, | 1518 | .put = wm_vol_put, |
1495 | .private_value = (2 << 8) | 6 | 1519 | .private_value = (2 << 8) | 6, |
1520 | .tlv = { .p = db_scale_wm_dac } | ||
1496 | } | 1521 | } |
1497 | }; | 1522 | }; |
1498 | 1523 | ||
@@ -1506,10 +1531,13 @@ static struct snd_kcontrol_new wm_controls[] __devinitdata = { | |||
1506 | }, | 1531 | }, |
1507 | { | 1532 | { |
1508 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 1533 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
1534 | .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | | ||
1535 | SNDRV_CTL_ELEM_ACCESS_TLV_READ), | ||
1509 | .name = "PCM Playback Volume", | 1536 | .name = "PCM Playback Volume", |
1510 | .info = wm_pcm_vol_info, | 1537 | .info = wm_pcm_vol_info, |
1511 | .get = wm_pcm_vol_get, | 1538 | .get = wm_pcm_vol_get, |
1512 | .put = wm_pcm_vol_put | 1539 | .put = wm_pcm_vol_put, |
1540 | .tlv = { .p = db_scale_wm_pcm } | ||
1513 | }, | 1541 | }, |
1514 | { | 1542 | { |
1515 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 1543 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
@@ -1520,10 +1548,13 @@ static struct snd_kcontrol_new wm_controls[] __devinitdata = { | |||
1520 | }, | 1548 | }, |
1521 | { | 1549 | { |
1522 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 1550 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
1551 | .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | | ||
1552 | SNDRV_CTL_ELEM_ACCESS_TLV_READ), | ||
1523 | .name = "Capture Volume", | 1553 | .name = "Capture Volume", |
1524 | .info = wm_adc_vol_info, | 1554 | .info = wm_adc_vol_info, |
1525 | .get = wm_adc_vol_get, | 1555 | .get = wm_adc_vol_get, |
1526 | .put = wm_adc_vol_put | 1556 | .put = wm_adc_vol_put, |
1557 | .tlv = { .p = db_scale_wm_adc } | ||
1527 | }, | 1558 | }, |
1528 | { | 1559 | { |
1529 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 1560 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
@@ -1567,11 +1598,14 @@ static struct snd_kcontrol_new ac97_controls[] __devinitdata = { | |||
1567 | }, | 1598 | }, |
1568 | { | 1599 | { |
1569 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 1600 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
1601 | .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | | ||
1602 | SNDRV_CTL_ELEM_ACCESS_TLV_READ), | ||
1570 | .name = "AC97 Playback Volume", | 1603 | .name = "AC97 Playback Volume", |
1571 | .info = aureon_ac97_vol_info, | 1604 | .info = aureon_ac97_vol_info, |
1572 | .get = aureon_ac97_vol_get, | 1605 | .get = aureon_ac97_vol_get, |
1573 | .put = aureon_ac97_vol_put, | 1606 | .put = aureon_ac97_vol_put, |
1574 | .private_value = AC97_MASTER|AUREON_AC97_STEREO | 1607 | .private_value = AC97_MASTER|AUREON_AC97_STEREO, |
1608 | .tlv = { .p = db_scale_ac97_master } | ||
1575 | }, | 1609 | }, |
1576 | { | 1610 | { |
1577 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 1611 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
@@ -1583,11 +1617,14 @@ static struct snd_kcontrol_new ac97_controls[] __devinitdata = { | |||
1583 | }, | 1617 | }, |
1584 | { | 1618 | { |
1585 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 1619 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
1620 | .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | | ||
1621 | SNDRV_CTL_ELEM_ACCESS_TLV_READ), | ||
1586 | .name = "CD Playback Volume", | 1622 | .name = "CD Playback Volume", |
1587 | .info = aureon_ac97_vol_info, | 1623 | .info = aureon_ac97_vol_info, |
1588 | .get = aureon_ac97_vol_get, | 1624 | .get = aureon_ac97_vol_get, |
1589 | .put = aureon_ac97_vol_put, | 1625 | .put = aureon_ac97_vol_put, |
1590 | .private_value = AC97_CD|AUREON_AC97_STEREO | 1626 | .private_value = AC97_CD|AUREON_AC97_STEREO, |
1627 | .tlv = { .p = db_scale_ac97_gain } | ||
1591 | }, | 1628 | }, |
1592 | { | 1629 | { |
1593 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 1630 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
@@ -1599,11 +1636,14 @@ static struct snd_kcontrol_new ac97_controls[] __devinitdata = { | |||
1599 | }, | 1636 | }, |
1600 | { | 1637 | { |
1601 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 1638 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
1639 | .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | | ||
1640 | SNDRV_CTL_ELEM_ACCESS_TLV_READ), | ||
1602 | .name = "Aux Playback Volume", | 1641 | .name = "Aux Playback Volume", |
1603 | .info = aureon_ac97_vol_info, | 1642 | .info = aureon_ac97_vol_info, |
1604 | .get = aureon_ac97_vol_get, | 1643 | .get = aureon_ac97_vol_get, |
1605 | .put = aureon_ac97_vol_put, | 1644 | .put = aureon_ac97_vol_put, |
1606 | .private_value = AC97_AUX|AUREON_AC97_STEREO | 1645 | .private_value = AC97_AUX|AUREON_AC97_STEREO, |
1646 | .tlv = { .p = db_scale_ac97_gain } | ||
1607 | }, | 1647 | }, |
1608 | { | 1648 | { |
1609 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 1649 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
@@ -1615,11 +1655,14 @@ static struct snd_kcontrol_new ac97_controls[] __devinitdata = { | |||
1615 | }, | 1655 | }, |
1616 | { | 1656 | { |
1617 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 1657 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
1658 | .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | | ||
1659 | SNDRV_CTL_ELEM_ACCESS_TLV_READ), | ||
1618 | .name = "Line Playback Volume", | 1660 | .name = "Line Playback Volume", |
1619 | .info = aureon_ac97_vol_info, | 1661 | .info = aureon_ac97_vol_info, |
1620 | .get = aureon_ac97_vol_get, | 1662 | .get = aureon_ac97_vol_get, |
1621 | .put = aureon_ac97_vol_put, | 1663 | .put = aureon_ac97_vol_put, |
1622 | .private_value = AC97_LINE|AUREON_AC97_STEREO | 1664 | .private_value = AC97_LINE|AUREON_AC97_STEREO, |
1665 | .tlv = { .p = db_scale_ac97_gain } | ||
1623 | }, | 1666 | }, |
1624 | { | 1667 | { |
1625 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 1668 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
@@ -1631,11 +1674,14 @@ static struct snd_kcontrol_new ac97_controls[] __devinitdata = { | |||
1631 | }, | 1674 | }, |
1632 | { | 1675 | { |
1633 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 1676 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
1677 | .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | | ||
1678 | SNDRV_CTL_ELEM_ACCESS_TLV_READ), | ||
1634 | .name = "Mic Playback Volume", | 1679 | .name = "Mic Playback Volume", |
1635 | .info = aureon_ac97_vol_info, | 1680 | .info = aureon_ac97_vol_info, |
1636 | .get = aureon_ac97_vol_get, | 1681 | .get = aureon_ac97_vol_get, |
1637 | .put = aureon_ac97_vol_put, | 1682 | .put = aureon_ac97_vol_put, |
1638 | .private_value = AC97_MIC | 1683 | .private_value = AC97_MIC, |
1684 | .tlv = { .p = db_scale_ac97_gain } | ||
1639 | }, | 1685 | }, |
1640 | { | 1686 | { |
1641 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 1687 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
@@ -1657,11 +1703,14 @@ static struct snd_kcontrol_new universe_ac97_controls[] __devinitdata = { | |||
1657 | }, | 1703 | }, |
1658 | { | 1704 | { |
1659 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 1705 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
1706 | .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | | ||
1707 | SNDRV_CTL_ELEM_ACCESS_TLV_READ), | ||
1660 | .name = "AC97 Playback Volume", | 1708 | .name = "AC97 Playback Volume", |
1661 | .info = aureon_ac97_vol_info, | 1709 | .info = aureon_ac97_vol_info, |
1662 | .get = aureon_ac97_vol_get, | 1710 | .get = aureon_ac97_vol_get, |
1663 | .put = aureon_ac97_vol_put, | 1711 | .put = aureon_ac97_vol_put, |
1664 | .private_value = AC97_MASTER|AUREON_AC97_STEREO | 1712 | .private_value = AC97_MASTER|AUREON_AC97_STEREO, |
1713 | .tlv = { .p = db_scale_ac97_master } | ||
1665 | }, | 1714 | }, |
1666 | { | 1715 | { |
1667 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 1716 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
@@ -1673,11 +1722,14 @@ static struct snd_kcontrol_new universe_ac97_controls[] __devinitdata = { | |||
1673 | }, | 1722 | }, |
1674 | { | 1723 | { |
1675 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 1724 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
1725 | .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | | ||
1726 | SNDRV_CTL_ELEM_ACCESS_TLV_READ), | ||
1676 | .name = "CD Playback Volume", | 1727 | .name = "CD Playback Volume", |
1677 | .info = aureon_ac97_vol_info, | 1728 | .info = aureon_ac97_vol_info, |
1678 | .get = aureon_ac97_vol_get, | 1729 | .get = aureon_ac97_vol_get, |
1679 | .put = aureon_ac97_vol_put, | 1730 | .put = aureon_ac97_vol_put, |
1680 | .private_value = AC97_AUX|AUREON_AC97_STEREO | 1731 | .private_value = AC97_AUX|AUREON_AC97_STEREO, |
1732 | .tlv = { .p = db_scale_ac97_gain } | ||
1681 | }, | 1733 | }, |
1682 | { | 1734 | { |
1683 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 1735 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
@@ -1685,15 +1737,18 @@ static struct snd_kcontrol_new universe_ac97_controls[] __devinitdata = { | |||
1685 | .info = aureon_ac97_mute_info, | 1737 | .info = aureon_ac97_mute_info, |
1686 | .get = aureon_ac97_mute_get, | 1738 | .get = aureon_ac97_mute_get, |
1687 | .put = aureon_ac97_mute_put, | 1739 | .put = aureon_ac97_mute_put, |
1688 | .private_value = AC97_CD, | 1740 | .private_value = AC97_CD |
1689 | }, | 1741 | }, |
1690 | { | 1742 | { |
1691 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 1743 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
1744 | .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | | ||
1745 | SNDRV_CTL_ELEM_ACCESS_TLV_READ), | ||
1692 | .name = "Phono Playback Volume", | 1746 | .name = "Phono Playback Volume", |
1693 | .info = aureon_ac97_vol_info, | 1747 | .info = aureon_ac97_vol_info, |
1694 | .get = aureon_ac97_vol_get, | 1748 | .get = aureon_ac97_vol_get, |
1695 | .put = aureon_ac97_vol_put, | 1749 | .put = aureon_ac97_vol_put, |
1696 | .private_value = AC97_CD|AUREON_AC97_STEREO | 1750 | .private_value = AC97_CD|AUREON_AC97_STEREO, |
1751 | .tlv = { .p = db_scale_ac97_gain } | ||
1697 | }, | 1752 | }, |
1698 | { | 1753 | { |
1699 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 1754 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
@@ -1705,11 +1760,14 @@ static struct snd_kcontrol_new universe_ac97_controls[] __devinitdata = { | |||
1705 | }, | 1760 | }, |
1706 | { | 1761 | { |
1707 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 1762 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
1763 | .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | | ||
1764 | SNDRV_CTL_ELEM_ACCESS_TLV_READ), | ||
1708 | .name = "Line Playback Volume", | 1765 | .name = "Line Playback Volume", |
1709 | .info = aureon_ac97_vol_info, | 1766 | .info = aureon_ac97_vol_info, |
1710 | .get = aureon_ac97_vol_get, | 1767 | .get = aureon_ac97_vol_get, |
1711 | .put = aureon_ac97_vol_put, | 1768 | .put = aureon_ac97_vol_put, |
1712 | .private_value = AC97_LINE|AUREON_AC97_STEREO | 1769 | .private_value = AC97_LINE|AUREON_AC97_STEREO, |
1770 | .tlv = { .p = db_scale_ac97_gain } | ||
1713 | }, | 1771 | }, |
1714 | { | 1772 | { |
1715 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 1773 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
@@ -1721,11 +1779,14 @@ static struct snd_kcontrol_new universe_ac97_controls[] __devinitdata = { | |||
1721 | }, | 1779 | }, |
1722 | { | 1780 | { |
1723 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 1781 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
1782 | .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | | ||
1783 | SNDRV_CTL_ELEM_ACCESS_TLV_READ), | ||
1724 | .name = "Mic Playback Volume", | 1784 | .name = "Mic Playback Volume", |
1725 | .info = aureon_ac97_vol_info, | 1785 | .info = aureon_ac97_vol_info, |
1726 | .get = aureon_ac97_vol_get, | 1786 | .get = aureon_ac97_vol_get, |
1727 | .put = aureon_ac97_vol_put, | 1787 | .put = aureon_ac97_vol_put, |
1728 | .private_value = AC97_MIC | 1788 | .private_value = AC97_MIC, |
1789 | .tlv = { .p = db_scale_ac97_gain } | ||
1729 | }, | 1790 | }, |
1730 | { | 1791 | { |
1731 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 1792 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
@@ -1744,11 +1805,14 @@ static struct snd_kcontrol_new universe_ac97_controls[] __devinitdata = { | |||
1744 | }, | 1805 | }, |
1745 | { | 1806 | { |
1746 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 1807 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
1808 | .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | | ||
1809 | SNDRV_CTL_ELEM_ACCESS_TLV_READ), | ||
1747 | .name = "Aux Playback Volume", | 1810 | .name = "Aux Playback Volume", |
1748 | .info = aureon_ac97_vol_info, | 1811 | .info = aureon_ac97_vol_info, |
1749 | .get = aureon_ac97_vol_get, | 1812 | .get = aureon_ac97_vol_get, |
1750 | .put = aureon_ac97_vol_put, | 1813 | .put = aureon_ac97_vol_put, |
1751 | .private_value = AC97_VIDEO|AUREON_AC97_STEREO | 1814 | .private_value = AC97_VIDEO|AUREON_AC97_STEREO, |
1815 | .tlv = { .p = db_scale_ac97_gain } | ||
1752 | }, | 1816 | }, |
1753 | { | 1817 | { |
1754 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 1818 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
diff --git a/sound/pci/ice1712/ice1712.c b/sound/pci/ice1712/ice1712.c index bf20858d9f19..dc69392eafa3 100644 --- a/sound/pci/ice1712/ice1712.c +++ b/sound/pci/ice1712/ice1712.c | |||
@@ -62,6 +62,7 @@ | |||
62 | #include <sound/cs8427.h> | 62 | #include <sound/cs8427.h> |
63 | #include <sound/info.h> | 63 | #include <sound/info.h> |
64 | #include <sound/initval.h> | 64 | #include <sound/initval.h> |
65 | #include <sound/tlv.h> | ||
65 | 66 | ||
66 | #include <sound/asoundef.h> | 67 | #include <sound/asoundef.h> |
67 | 68 | ||
@@ -1377,6 +1378,7 @@ static int snd_ice1712_pro_mixer_volume_put(struct snd_kcontrol *kcontrol, struc | |||
1377 | return change; | 1378 | return change; |
1378 | } | 1379 | } |
1379 | 1380 | ||
1381 | static DECLARE_TLV_DB_SCALE(db_scale_playback, -14400, 150, 0); | ||
1380 | 1382 | ||
1381 | static struct snd_kcontrol_new snd_ice1712_multi_playback_ctrls[] __devinitdata = { | 1383 | static struct snd_kcontrol_new snd_ice1712_multi_playback_ctrls[] __devinitdata = { |
1382 | { | 1384 | { |
@@ -1390,12 +1392,15 @@ static struct snd_kcontrol_new snd_ice1712_multi_playback_ctrls[] __devinitdata | |||
1390 | }, | 1392 | }, |
1391 | { | 1393 | { |
1392 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 1394 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
1395 | .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | | ||
1396 | SNDRV_CTL_ELEM_ACCESS_TLV_READ), | ||
1393 | .name = "Multi Playback Volume", | 1397 | .name = "Multi Playback Volume", |
1394 | .info = snd_ice1712_pro_mixer_volume_info, | 1398 | .info = snd_ice1712_pro_mixer_volume_info, |
1395 | .get = snd_ice1712_pro_mixer_volume_get, | 1399 | .get = snd_ice1712_pro_mixer_volume_get, |
1396 | .put = snd_ice1712_pro_mixer_volume_put, | 1400 | .put = snd_ice1712_pro_mixer_volume_put, |
1397 | .private_value = 0, | 1401 | .private_value = 0, |
1398 | .count = 10, | 1402 | .count = 10, |
1403 | .tlv = { .p = db_scale_playback } | ||
1399 | }, | 1404 | }, |
1400 | }; | 1405 | }; |
1401 | 1406 | ||
@@ -1420,11 +1425,14 @@ static struct snd_kcontrol_new snd_ice1712_multi_capture_spdif_switch __devinitd | |||
1420 | 1425 | ||
1421 | static struct snd_kcontrol_new snd_ice1712_multi_capture_analog_volume __devinitdata = { | 1426 | static struct snd_kcontrol_new snd_ice1712_multi_capture_analog_volume __devinitdata = { |
1422 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 1427 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
1428 | .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | | ||
1429 | SNDRV_CTL_ELEM_ACCESS_TLV_READ), | ||
1423 | .name = "H/W Multi Capture Volume", | 1430 | .name = "H/W Multi Capture Volume", |
1424 | .info = snd_ice1712_pro_mixer_volume_info, | 1431 | .info = snd_ice1712_pro_mixer_volume_info, |
1425 | .get = snd_ice1712_pro_mixer_volume_get, | 1432 | .get = snd_ice1712_pro_mixer_volume_get, |
1426 | .put = snd_ice1712_pro_mixer_volume_put, | 1433 | .put = snd_ice1712_pro_mixer_volume_put, |
1427 | .private_value = 10, | 1434 | .private_value = 10, |
1435 | .tlv = { .p = db_scale_playback } | ||
1428 | }; | 1436 | }; |
1429 | 1437 | ||
1430 | static struct snd_kcontrol_new snd_ice1712_multi_capture_spdif_volume __devinitdata = { | 1438 | static struct snd_kcontrol_new snd_ice1712_multi_capture_spdif_volume __devinitdata = { |
@@ -1857,7 +1865,7 @@ static int snd_ice1712_pro_internal_clock_put(struct snd_kcontrol *kcontrol, | |||
1857 | { | 1865 | { |
1858 | struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); | 1866 | struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); |
1859 | static unsigned int xrate[13] = { | 1867 | static unsigned int xrate[13] = { |
1860 | 8000, 9600, 11025, 12000, 1600, 22050, 24000, | 1868 | 8000, 9600, 11025, 12000, 16000, 22050, 24000, |
1861 | 32000, 44100, 48000, 64000, 88200, 96000 | 1869 | 32000, 44100, 48000, 64000, 88200, 96000 |
1862 | }; | 1870 | }; |
1863 | unsigned char oval; | 1871 | unsigned char oval; |
@@ -1924,7 +1932,7 @@ static int snd_ice1712_pro_internal_clock_default_get(struct snd_kcontrol *kcont | |||
1924 | { | 1932 | { |
1925 | int val; | 1933 | int val; |
1926 | static unsigned int xrate[13] = { | 1934 | static unsigned int xrate[13] = { |
1927 | 8000, 9600, 11025, 12000, 1600, 22050, 24000, | 1935 | 8000, 9600, 11025, 12000, 16000, 22050, 24000, |
1928 | 32000, 44100, 48000, 64000, 88200, 96000 | 1936 | 32000, 44100, 48000, 64000, 88200, 96000 |
1929 | }; | 1937 | }; |
1930 | 1938 | ||
@@ -1941,7 +1949,7 @@ static int snd_ice1712_pro_internal_clock_default_put(struct snd_kcontrol *kcont | |||
1941 | struct snd_ctl_elem_value *ucontrol) | 1949 | struct snd_ctl_elem_value *ucontrol) |
1942 | { | 1950 | { |
1943 | static unsigned int xrate[13] = { | 1951 | static unsigned int xrate[13] = { |
1944 | 8000, 9600, 11025, 12000, 1600, 22050, 24000, | 1952 | 8000, 9600, 11025, 12000, 16000, 22050, 24000, |
1945 | 32000, 44100, 48000, 64000, 88200, 96000 | 1953 | 32000, 44100, 48000, 64000, 88200, 96000 |
1946 | }; | 1954 | }; |
1947 | unsigned char oval; | 1955 | unsigned char oval; |
diff --git a/sound/pci/ice1712/phase.c b/sound/pci/ice1712/phase.c index 502da1c8b5f7..e08d73f4ff85 100644 --- a/sound/pci/ice1712/phase.c +++ b/sound/pci/ice1712/phase.c | |||
@@ -46,6 +46,7 @@ | |||
46 | #include "ice1712.h" | 46 | #include "ice1712.h" |
47 | #include "envy24ht.h" | 47 | #include "envy24ht.h" |
48 | #include "phase.h" | 48 | #include "phase.h" |
49 | #include <sound/tlv.h> | ||
49 | 50 | ||
50 | /* WM8770 registers */ | 51 | /* WM8770 registers */ |
51 | #define WM_DAC_ATTEN 0x00 /* DAC1-8 analog attenuation */ | 52 | #define WM_DAC_ATTEN 0x00 /* DAC1-8 analog attenuation */ |
@@ -696,6 +697,9 @@ static int phase28_oversampling_put(struct snd_kcontrol *kcontrol, struct snd_ct | |||
696 | return 0; | 697 | return 0; |
697 | } | 698 | } |
698 | 699 | ||
700 | static DECLARE_TLV_DB_SCALE(db_scale_wm_dac, -12700, 100, 1); | ||
701 | static DECLARE_TLV_DB_SCALE(db_scale_wm_pcm, -6400, 50, 1); | ||
702 | |||
699 | static struct snd_kcontrol_new phase28_dac_controls[] __devinitdata = { | 703 | static struct snd_kcontrol_new phase28_dac_controls[] __devinitdata = { |
700 | { | 704 | { |
701 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 705 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
@@ -706,10 +710,13 @@ static struct snd_kcontrol_new phase28_dac_controls[] __devinitdata = { | |||
706 | }, | 710 | }, |
707 | { | 711 | { |
708 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 712 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
713 | .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | | ||
714 | SNDRV_CTL_ELEM_ACCESS_TLV_READ), | ||
709 | .name = "Master Playback Volume", | 715 | .name = "Master Playback Volume", |
710 | .info = wm_master_vol_info, | 716 | .info = wm_master_vol_info, |
711 | .get = wm_master_vol_get, | 717 | .get = wm_master_vol_get, |
712 | .put = wm_master_vol_put | 718 | .put = wm_master_vol_put, |
719 | .tlv = { .p = db_scale_wm_dac } | ||
713 | }, | 720 | }, |
714 | { | 721 | { |
715 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 722 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
@@ -721,11 +728,14 @@ static struct snd_kcontrol_new phase28_dac_controls[] __devinitdata = { | |||
721 | }, | 728 | }, |
722 | { | 729 | { |
723 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 730 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
731 | .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | | ||
732 | SNDRV_CTL_ELEM_ACCESS_TLV_READ), | ||
724 | .name = "Front Playback Volume", | 733 | .name = "Front Playback Volume", |
725 | .info = wm_vol_info, | 734 | .info = wm_vol_info, |
726 | .get = wm_vol_get, | 735 | .get = wm_vol_get, |
727 | .put = wm_vol_put, | 736 | .put = wm_vol_put, |
728 | .private_value = (2 << 8) | 0 | 737 | .private_value = (2 << 8) | 0, |
738 | .tlv = { .p = db_scale_wm_dac } | ||
729 | }, | 739 | }, |
730 | { | 740 | { |
731 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 741 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
@@ -737,11 +747,14 @@ static struct snd_kcontrol_new phase28_dac_controls[] __devinitdata = { | |||
737 | }, | 747 | }, |
738 | { | 748 | { |
739 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 749 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
750 | .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | | ||
751 | SNDRV_CTL_ELEM_ACCESS_TLV_READ), | ||
740 | .name = "Rear Playback Volume", | 752 | .name = "Rear Playback Volume", |
741 | .info = wm_vol_info, | 753 | .info = wm_vol_info, |
742 | .get = wm_vol_get, | 754 | .get = wm_vol_get, |
743 | .put = wm_vol_put, | 755 | .put = wm_vol_put, |
744 | .private_value = (2 << 8) | 2 | 756 | .private_value = (2 << 8) | 2, |
757 | .tlv = { .p = db_scale_wm_dac } | ||
745 | }, | 758 | }, |
746 | { | 759 | { |
747 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 760 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
@@ -753,11 +766,14 @@ static struct snd_kcontrol_new phase28_dac_controls[] __devinitdata = { | |||
753 | }, | 766 | }, |
754 | { | 767 | { |
755 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 768 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
769 | .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | | ||
770 | SNDRV_CTL_ELEM_ACCESS_TLV_READ), | ||
756 | .name = "Center Playback Volume", | 771 | .name = "Center Playback Volume", |
757 | .info = wm_vol_info, | 772 | .info = wm_vol_info, |
758 | .get = wm_vol_get, | 773 | .get = wm_vol_get, |
759 | .put = wm_vol_put, | 774 | .put = wm_vol_put, |
760 | .private_value = (1 << 8) | 4 | 775 | .private_value = (1 << 8) | 4, |
776 | .tlv = { .p = db_scale_wm_dac } | ||
761 | }, | 777 | }, |
762 | { | 778 | { |
763 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 779 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
@@ -769,11 +785,14 @@ static struct snd_kcontrol_new phase28_dac_controls[] __devinitdata = { | |||
769 | }, | 785 | }, |
770 | { | 786 | { |
771 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 787 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
788 | .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | | ||
789 | SNDRV_CTL_ELEM_ACCESS_TLV_READ), | ||
772 | .name = "LFE Playback Volume", | 790 | .name = "LFE Playback Volume", |
773 | .info = wm_vol_info, | 791 | .info = wm_vol_info, |
774 | .get = wm_vol_get, | 792 | .get = wm_vol_get, |
775 | .put = wm_vol_put, | 793 | .put = wm_vol_put, |
776 | .private_value = (1 << 8) | 5 | 794 | .private_value = (1 << 8) | 5, |
795 | .tlv = { .p = db_scale_wm_dac } | ||
777 | }, | 796 | }, |
778 | { | 797 | { |
779 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 798 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
@@ -785,11 +804,14 @@ static struct snd_kcontrol_new phase28_dac_controls[] __devinitdata = { | |||
785 | }, | 804 | }, |
786 | { | 805 | { |
787 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 806 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
807 | .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | | ||
808 | SNDRV_CTL_ELEM_ACCESS_TLV_READ), | ||
788 | .name = "Side Playback Volume", | 809 | .name = "Side Playback Volume", |
789 | .info = wm_vol_info, | 810 | .info = wm_vol_info, |
790 | .get = wm_vol_get, | 811 | .get = wm_vol_get, |
791 | .put = wm_vol_put, | 812 | .put = wm_vol_put, |
792 | .private_value = (2 << 8) | 6 | 813 | .private_value = (2 << 8) | 6, |
814 | .tlv = { .p = db_scale_wm_dac } | ||
793 | } | 815 | } |
794 | }; | 816 | }; |
795 | 817 | ||
@@ -803,10 +825,13 @@ static struct snd_kcontrol_new wm_controls[] __devinitdata = { | |||
803 | }, | 825 | }, |
804 | { | 826 | { |
805 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 827 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
828 | .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | | ||
829 | SNDRV_CTL_ELEM_ACCESS_TLV_READ), | ||
806 | .name = "PCM Playback Volume", | 830 | .name = "PCM Playback Volume", |
807 | .info = wm_pcm_vol_info, | 831 | .info = wm_pcm_vol_info, |
808 | .get = wm_pcm_vol_get, | 832 | .get = wm_pcm_vol_get, |
809 | .put = wm_pcm_vol_put | 833 | .put = wm_pcm_vol_put, |
834 | .tlv = { .p = db_scale_wm_pcm } | ||
810 | }, | 835 | }, |
811 | { | 836 | { |
812 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 837 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
diff --git a/sound/pci/ice1712/pontis.c b/sound/pci/ice1712/pontis.c index 0efcad9260a5..6c74c2d2e7f3 100644 --- a/sound/pci/ice1712/pontis.c +++ b/sound/pci/ice1712/pontis.c | |||
@@ -31,6 +31,7 @@ | |||
31 | 31 | ||
32 | #include <sound/core.h> | 32 | #include <sound/core.h> |
33 | #include <sound/info.h> | 33 | #include <sound/info.h> |
34 | #include <sound/tlv.h> | ||
34 | 35 | ||
35 | #include "ice1712.h" | 36 | #include "ice1712.h" |
36 | #include "envy24ht.h" | 37 | #include "envy24ht.h" |
@@ -564,6 +565,8 @@ static int pontis_gpio_data_put(struct snd_kcontrol *kcontrol, struct snd_ctl_el | |||
564 | return changed; | 565 | return changed; |
565 | } | 566 | } |
566 | 567 | ||
568 | static DECLARE_TLV_DB_SCALE(db_scale_volume, -6400, 50, 1); | ||
569 | |||
567 | /* | 570 | /* |
568 | * mixers | 571 | * mixers |
569 | */ | 572 | */ |
@@ -571,17 +574,23 @@ static int pontis_gpio_data_put(struct snd_kcontrol *kcontrol, struct snd_ctl_el | |||
571 | static struct snd_kcontrol_new pontis_controls[] __devinitdata = { | 574 | static struct snd_kcontrol_new pontis_controls[] __devinitdata = { |
572 | { | 575 | { |
573 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 576 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
577 | .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | | ||
578 | SNDRV_CTL_ELEM_ACCESS_TLV_READ), | ||
574 | .name = "PCM Playback Volume", | 579 | .name = "PCM Playback Volume", |
575 | .info = wm_dac_vol_info, | 580 | .info = wm_dac_vol_info, |
576 | .get = wm_dac_vol_get, | 581 | .get = wm_dac_vol_get, |
577 | .put = wm_dac_vol_put, | 582 | .put = wm_dac_vol_put, |
583 | .tlv = { .p = db_scale_volume }, | ||
578 | }, | 584 | }, |
579 | { | 585 | { |
580 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 586 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
587 | .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | | ||
588 | SNDRV_CTL_ELEM_ACCESS_TLV_READ), | ||
581 | .name = "Capture Volume", | 589 | .name = "Capture Volume", |
582 | .info = wm_adc_vol_info, | 590 | .info = wm_adc_vol_info, |
583 | .get = wm_adc_vol_get, | 591 | .get = wm_adc_vol_get, |
584 | .put = wm_adc_vol_put, | 592 | .put = wm_adc_vol_put, |
593 | .tlv = { .p = db_scale_volume }, | ||
585 | }, | 594 | }, |
586 | { | 595 | { |
587 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 596 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
diff --git a/sound/pci/ice1712/prodigy192.c b/sound/pci/ice1712/prodigy192.c index fdb5cb8fac97..41b2605daa3a 100644 --- a/sound/pci/ice1712/prodigy192.c +++ b/sound/pci/ice1712/prodigy192.c | |||
@@ -35,6 +35,7 @@ | |||
35 | #include "envy24ht.h" | 35 | #include "envy24ht.h" |
36 | #include "prodigy192.h" | 36 | #include "prodigy192.h" |
37 | #include "stac946x.h" | 37 | #include "stac946x.h" |
38 | #include <sound/tlv.h> | ||
38 | 39 | ||
39 | static inline void stac9460_put(struct snd_ice1712 *ice, int reg, unsigned char val) | 40 | static inline void stac9460_put(struct snd_ice1712 *ice, int reg, unsigned char val) |
40 | { | 41 | { |
@@ -356,6 +357,9 @@ static int aureon_oversampling_put(struct snd_kcontrol *kcontrol, struct snd_ctl | |||
356 | } | 357 | } |
357 | #endif | 358 | #endif |
358 | 359 | ||
360 | static DECLARE_TLV_DB_SCALE(db_scale_dac, -19125, 75, 0); | ||
361 | static DECLARE_TLV_DB_SCALE(db_scale_adc, 0, 150, 0); | ||
362 | |||
359 | /* | 363 | /* |
360 | * mixers | 364 | * mixers |
361 | */ | 365 | */ |
@@ -368,14 +372,18 @@ static struct snd_kcontrol_new stac_controls[] __devinitdata = { | |||
368 | .get = stac9460_dac_mute_get, | 372 | .get = stac9460_dac_mute_get, |
369 | .put = stac9460_dac_mute_put, | 373 | .put = stac9460_dac_mute_put, |
370 | .private_value = 1, | 374 | .private_value = 1, |
375 | .tlv = { .p = db_scale_dac } | ||
371 | }, | 376 | }, |
372 | { | 377 | { |
373 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 378 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
379 | .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | | ||
380 | SNDRV_CTL_ELEM_ACCESS_TLV_READ), | ||
374 | .name = "Master Playback Volume", | 381 | .name = "Master Playback Volume", |
375 | .info = stac9460_dac_vol_info, | 382 | .info = stac9460_dac_vol_info, |
376 | .get = stac9460_dac_vol_get, | 383 | .get = stac9460_dac_vol_get, |
377 | .put = stac9460_dac_vol_put, | 384 | .put = stac9460_dac_vol_put, |
378 | .private_value = 1, | 385 | .private_value = 1, |
386 | .tlv = { .p = db_scale_dac } | ||
379 | }, | 387 | }, |
380 | { | 388 | { |
381 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 389 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
@@ -387,11 +395,14 @@ static struct snd_kcontrol_new stac_controls[] __devinitdata = { | |||
387 | }, | 395 | }, |
388 | { | 396 | { |
389 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 397 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
398 | .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | | ||
399 | SNDRV_CTL_ELEM_ACCESS_TLV_READ), | ||
390 | .name = "DAC Volume", | 400 | .name = "DAC Volume", |
391 | .count = 6, | 401 | .count = 6, |
392 | .info = stac9460_dac_vol_info, | 402 | .info = stac9460_dac_vol_info, |
393 | .get = stac9460_dac_vol_get, | 403 | .get = stac9460_dac_vol_get, |
394 | .put = stac9460_dac_vol_put, | 404 | .put = stac9460_dac_vol_put, |
405 | .tlv = { .p = db_scale_dac } | ||
395 | }, | 406 | }, |
396 | { | 407 | { |
397 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 408 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
@@ -404,11 +415,14 @@ static struct snd_kcontrol_new stac_controls[] __devinitdata = { | |||
404 | }, | 415 | }, |
405 | { | 416 | { |
406 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 417 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
418 | .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | | ||
419 | SNDRV_CTL_ELEM_ACCESS_TLV_READ), | ||
407 | .name = "ADC Volume", | 420 | .name = "ADC Volume", |
408 | .count = 1, | 421 | .count = 1, |
409 | .info = stac9460_adc_vol_info, | 422 | .info = stac9460_adc_vol_info, |
410 | .get = stac9460_adc_vol_get, | 423 | .get = stac9460_adc_vol_get, |
411 | .put = stac9460_adc_vol_put, | 424 | .put = stac9460_adc_vol_put, |
425 | .tlv = { .p = db_scale_adc } | ||
412 | }, | 426 | }, |
413 | #if 0 | 427 | #if 0 |
414 | { | 428 | { |
diff --git a/sound/pci/ice1712/revo.c b/sound/pci/ice1712/revo.c index fec9440cb310..bf98ea34feb0 100644 --- a/sound/pci/ice1712/revo.c +++ b/sound/pci/ice1712/revo.c | |||
@@ -87,16 +87,33 @@ static void revo_set_rate_val(struct snd_akm4xxx *ak, unsigned int rate) | |||
87 | * initialize the chips on M-Audio Revolution cards | 87 | * initialize the chips on M-Audio Revolution cards |
88 | */ | 88 | */ |
89 | 89 | ||
90 | static unsigned int revo71_num_stereo_front[] = {2}; | 90 | #define AK_DAC(xname,xch) { .name = xname, .num_channels = xch } |
91 | static char *revo71_channel_names_front[] = {"PCM Playback Volume"}; | ||
92 | 91 | ||
93 | static unsigned int revo71_num_stereo_surround[] = {1, 1, 2, 2}; | 92 | static struct snd_akm4xxx_dac_channel revo71_front[] = { |
94 | static char *revo71_channel_names_surround[] = {"PCM Center Playback Volume", "PCM LFE Playback Volume", | 93 | AK_DAC("PCM Playback Volume", 2) |
95 | "PCM Side Playback Volume", "PCM Rear Playback Volume"}; | 94 | }; |
95 | |||
96 | static struct snd_akm4xxx_dac_channel revo71_surround[] = { | ||
97 | AK_DAC("PCM Center Playback Volume", 1), | ||
98 | AK_DAC("PCM LFE Playback Volume", 1), | ||
99 | AK_DAC("PCM Side Playback Volume", 2), | ||
100 | AK_DAC("PCM Rear Playback Volume", 2), | ||
101 | }; | ||
96 | 102 | ||
97 | static unsigned int revo51_num_stereo[] = {2, 1, 1, 2}; | 103 | static struct snd_akm4xxx_dac_channel revo51_dac[] = { |
98 | static char *revo51_channel_names[] = {"PCM Playback Volume", "PCM Center Playback Volume", | 104 | AK_DAC("PCM Playback Volume", 2), |
99 | "PCM LFE Playback Volume", "PCM Rear Playback Volume"}; | 105 | AK_DAC("PCM Center Playback Volume", 1), |
106 | AK_DAC("PCM LFE Playback Volume", 1), | ||
107 | AK_DAC("PCM Rear Playback Volume", 2), | ||
108 | }; | ||
109 | |||
110 | static struct snd_akm4xxx_adc_channel revo51_adc[] = { | ||
111 | { | ||
112 | .name = "PCM Capture Volume", | ||
113 | .switch_name = "PCM Capture Switch", | ||
114 | .num_channels = 2 | ||
115 | }, | ||
116 | }; | ||
100 | 117 | ||
101 | static struct snd_akm4xxx akm_revo_front __devinitdata = { | 118 | static struct snd_akm4xxx akm_revo_front __devinitdata = { |
102 | .type = SND_AK4381, | 119 | .type = SND_AK4381, |
@@ -104,8 +121,7 @@ static struct snd_akm4xxx akm_revo_front __devinitdata = { | |||
104 | .ops = { | 121 | .ops = { |
105 | .set_rate_val = revo_set_rate_val | 122 | .set_rate_val = revo_set_rate_val |
106 | }, | 123 | }, |
107 | .num_stereo = revo71_num_stereo_front, | 124 | .dac_info = revo71_front, |
108 | .channel_names = revo71_channel_names_front | ||
109 | }; | 125 | }; |
110 | 126 | ||
111 | static struct snd_ak4xxx_private akm_revo_front_priv __devinitdata = { | 127 | static struct snd_ak4xxx_private akm_revo_front_priv __devinitdata = { |
@@ -127,8 +143,7 @@ static struct snd_akm4xxx akm_revo_surround __devinitdata = { | |||
127 | .ops = { | 143 | .ops = { |
128 | .set_rate_val = revo_set_rate_val | 144 | .set_rate_val = revo_set_rate_val |
129 | }, | 145 | }, |
130 | .num_stereo = revo71_num_stereo_surround, | 146 | .dac_info = revo71_surround, |
131 | .channel_names = revo71_channel_names_surround | ||
132 | }; | 147 | }; |
133 | 148 | ||
134 | static struct snd_ak4xxx_private akm_revo_surround_priv __devinitdata = { | 149 | static struct snd_ak4xxx_private akm_revo_surround_priv __devinitdata = { |
@@ -149,8 +164,7 @@ static struct snd_akm4xxx akm_revo51 __devinitdata = { | |||
149 | .ops = { | 164 | .ops = { |
150 | .set_rate_val = revo_set_rate_val | 165 | .set_rate_val = revo_set_rate_val |
151 | }, | 166 | }, |
152 | .num_stereo = revo51_num_stereo, | 167 | .dac_info = revo51_dac, |
153 | .channel_names = revo51_channel_names | ||
154 | }; | 168 | }; |
155 | 169 | ||
156 | static struct snd_ak4xxx_private akm_revo51_priv __devinitdata = { | 170 | static struct snd_ak4xxx_private akm_revo51_priv __devinitdata = { |
@@ -159,7 +173,25 @@ static struct snd_ak4xxx_private akm_revo51_priv __devinitdata = { | |||
159 | .data_mask = VT1724_REVO_CDOUT, | 173 | .data_mask = VT1724_REVO_CDOUT, |
160 | .clk_mask = VT1724_REVO_CCLK, | 174 | .clk_mask = VT1724_REVO_CCLK, |
161 | .cs_mask = VT1724_REVO_CS0 | VT1724_REVO_CS1 | VT1724_REVO_CS2, | 175 | .cs_mask = VT1724_REVO_CS0 | VT1724_REVO_CS1 | VT1724_REVO_CS2, |
162 | .cs_addr = 0, | 176 | .cs_addr = VT1724_REVO_CS1 | VT1724_REVO_CS2, |
177 | .cs_none = VT1724_REVO_CS0 | VT1724_REVO_CS1 | VT1724_REVO_CS2, | ||
178 | .add_flags = VT1724_REVO_CCLK, /* high at init */ | ||
179 | .mask_flags = 0, | ||
180 | }; | ||
181 | |||
182 | static struct snd_akm4xxx akm_revo51_adc __devinitdata = { | ||
183 | .type = SND_AK5365, | ||
184 | .num_adcs = 2, | ||
185 | .adc_info = revo51_adc, | ||
186 | }; | ||
187 | |||
188 | static struct snd_ak4xxx_private akm_revo51_adc_priv __devinitdata = { | ||
189 | .caddr = 2, | ||
190 | .cif = 0, | ||
191 | .data_mask = VT1724_REVO_CDOUT, | ||
192 | .clk_mask = VT1724_REVO_CCLK, | ||
193 | .cs_mask = VT1724_REVO_CS0 | VT1724_REVO_CS1 | VT1724_REVO_CS2, | ||
194 | .cs_addr = VT1724_REVO_CS0 | VT1724_REVO_CS2, | ||
163 | .cs_none = VT1724_REVO_CS0 | VT1724_REVO_CS1 | VT1724_REVO_CS2, | 195 | .cs_none = VT1724_REVO_CS0 | VT1724_REVO_CS1 | VT1724_REVO_CS2, |
164 | .add_flags = VT1724_REVO_CCLK, /* high at init */ | 196 | .add_flags = VT1724_REVO_CCLK, /* high at init */ |
165 | .mask_flags = 0, | 197 | .mask_flags = 0, |
@@ -202,9 +234,13 @@ static int __devinit revo_init(struct snd_ice1712 *ice) | |||
202 | snd_ice1712_gpio_write_bits(ice, VT1724_REVO_MUTE, VT1724_REVO_MUTE); | 234 | snd_ice1712_gpio_write_bits(ice, VT1724_REVO_MUTE, VT1724_REVO_MUTE); |
203 | break; | 235 | break; |
204 | case VT1724_SUBDEVICE_REVOLUTION51: | 236 | case VT1724_SUBDEVICE_REVOLUTION51: |
205 | ice->akm_codecs = 1; | 237 | ice->akm_codecs = 2; |
206 | if ((err = snd_ice1712_akm4xxx_init(ak, &akm_revo51, &akm_revo51_priv, ice)) < 0) | 238 | if ((err = snd_ice1712_akm4xxx_init(ak, &akm_revo51, &akm_revo51_priv, ice)) < 0) |
207 | return err; | 239 | return err; |
240 | err = snd_ice1712_akm4xxx_init(ak + 1, &akm_revo51_adc, | ||
241 | &akm_revo51_adc_priv, ice); | ||
242 | if (err < 0) | ||
243 | return err; | ||
208 | /* unmute all codecs - needed! */ | 244 | /* unmute all codecs - needed! */ |
209 | snd_ice1712_gpio_write_bits(ice, VT1724_REVO_MUTE, VT1724_REVO_MUTE); | 245 | snd_ice1712_gpio_write_bits(ice, VT1724_REVO_MUTE, VT1724_REVO_MUTE); |
210 | break; | 246 | break; |
diff --git a/sound/pci/ice1712/revo.h b/sound/pci/ice1712/revo.h index dea52ea219df..efbb86ec3289 100644 --- a/sound/pci/ice1712/revo.h +++ b/sound/pci/ice1712/revo.h | |||
@@ -42,7 +42,7 @@ extern struct snd_ice1712_card_info snd_vt1724_revo_cards[]; | |||
42 | #define VT1724_REVO_CCLK 0x02 | 42 | #define VT1724_REVO_CCLK 0x02 |
43 | #define VT1724_REVO_CDIN 0x04 /* not used */ | 43 | #define VT1724_REVO_CDIN 0x04 /* not used */ |
44 | #define VT1724_REVO_CDOUT 0x08 | 44 | #define VT1724_REVO_CDOUT 0x08 |
45 | #define VT1724_REVO_CS0 0x10 /* not used */ | 45 | #define VT1724_REVO_CS0 0x10 /* AK5365 chipselect for Rev. 5.1 */ |
46 | #define VT1724_REVO_CS1 0x20 /* front AKM4381 chipselect */ | 46 | #define VT1724_REVO_CS1 0x20 /* front AKM4381 chipselect */ |
47 | #define VT1724_REVO_CS2 0x40 /* surround AKM4355 chipselect */ | 47 | #define VT1724_REVO_CS2 0x40 /* surround AKM4355 chipselect */ |
48 | #define VT1724_REVO_MUTE (1<<22) /* 0 = all mute, 1 = normal operation */ | 48 | #define VT1724_REVO_MUTE (1<<22) /* 0 = all mute, 1 = normal operation */ |
diff --git a/sound/pci/intel8x0.c b/sound/pci/intel8x0.c index 6874263f1681..72dbaedcbdf5 100644 --- a/sound/pci/intel8x0.c +++ b/sound/pci/intel8x0.c | |||
@@ -2251,6 +2251,16 @@ static int snd_intel8x0_ich_chip_init(struct intel8x0 *chip, int probing) | |||
2251 | /* ACLink on, 2 channels */ | 2251 | /* ACLink on, 2 channels */ |
2252 | cnt = igetdword(chip, ICHREG(GLOB_CNT)); | 2252 | cnt = igetdword(chip, ICHREG(GLOB_CNT)); |
2253 | cnt &= ~(ICH_ACLINK | ICH_PCM_246_MASK); | 2253 | cnt &= ~(ICH_ACLINK | ICH_PCM_246_MASK); |
2254 | #ifdef CONFIG_SND_AC97_POWER_SAVE | ||
2255 | /* do cold reset - the full ac97 powerdown may leave the controller | ||
2256 | * in a warm state but actually it cannot communicate with the codec. | ||
2257 | */ | ||
2258 | iputdword(chip, ICHREG(GLOB_CNT), cnt & ~ICH_AC97COLD); | ||
2259 | cnt = igetdword(chip, ICHREG(GLOB_CNT)); | ||
2260 | udelay(10); | ||
2261 | iputdword(chip, ICHREG(GLOB_CNT), cnt | ICH_AC97COLD); | ||
2262 | msleep(1); | ||
2263 | #else | ||
2254 | /* finish cold or do warm reset */ | 2264 | /* finish cold or do warm reset */ |
2255 | cnt |= (cnt & ICH_AC97COLD) == 0 ? ICH_AC97COLD : ICH_AC97WARM; | 2265 | cnt |= (cnt & ICH_AC97COLD) == 0 ? ICH_AC97COLD : ICH_AC97WARM; |
2256 | iputdword(chip, ICHREG(GLOB_CNT), cnt); | 2266 | iputdword(chip, ICHREG(GLOB_CNT), cnt); |
@@ -2265,6 +2275,7 @@ static int snd_intel8x0_ich_chip_init(struct intel8x0 *chip, int probing) | |||
2265 | return -EIO; | 2275 | return -EIO; |
2266 | 2276 | ||
2267 | __ok: | 2277 | __ok: |
2278 | #endif | ||
2268 | if (probing) { | 2279 | if (probing) { |
2269 | /* wait for any codec ready status. | 2280 | /* wait for any codec ready status. |
2270 | * Once it becomes ready it should remain ready | 2281 | * Once it becomes ready it should remain ready |
@@ -2485,7 +2496,7 @@ static int intel8x0_resume(struct pci_dev *pci) | |||
2485 | card->shortname, chip); | 2496 | card->shortname, chip); |
2486 | chip->irq = pci->irq; | 2497 | chip->irq = pci->irq; |
2487 | synchronize_irq(chip->irq); | 2498 | synchronize_irq(chip->irq); |
2488 | snd_intel8x0_chip_init(chip, 1); | 2499 | snd_intel8x0_chip_init(chip, 0); |
2489 | 2500 | ||
2490 | /* re-initialize mixer stuff */ | 2501 | /* re-initialize mixer stuff */ |
2491 | if (chip->device_type == DEVICE_INTEL_ICH4) { | 2502 | if (chip->device_type == DEVICE_INTEL_ICH4) { |
@@ -2615,6 +2626,7 @@ static void __devinit intel8x0_measure_ac97_clock(struct intel8x0 *chip) | |||
2615 | /* not 48000Hz, tuning the clock.. */ | 2626 | /* not 48000Hz, tuning the clock.. */ |
2616 | chip->ac97_bus->clock = (chip->ac97_bus->clock * 48000) / pos; | 2627 | chip->ac97_bus->clock = (chip->ac97_bus->clock * 48000) / pos; |
2617 | printk(KERN_INFO "intel8x0: clocking to %d\n", chip->ac97_bus->clock); | 2628 | printk(KERN_INFO "intel8x0: clocking to %d\n", chip->ac97_bus->clock); |
2629 | snd_ac97_update_power(chip->ac97[0], AC97_PCM_FRONT_DAC_RATE, 0); | ||
2618 | } | 2630 | } |
2619 | 2631 | ||
2620 | #ifdef CONFIG_PROC_FS | 2632 | #ifdef CONFIG_PROC_FS |
diff --git a/sound/pci/intel8x0m.c b/sound/pci/intel8x0m.c index 91850281f89b..268e2f7241ea 100644 --- a/sound/pci/intel8x0m.c +++ b/sound/pci/intel8x0m.c | |||
@@ -1045,6 +1045,8 @@ static int intel8x0m_suspend(struct pci_dev *pci, pm_message_t state) | |||
1045 | for (i = 0; i < chip->pcm_devs; i++) | 1045 | for (i = 0; i < chip->pcm_devs; i++) |
1046 | snd_pcm_suspend_all(chip->pcm[i]); | 1046 | snd_pcm_suspend_all(chip->pcm[i]); |
1047 | snd_ac97_suspend(chip->ac97); | 1047 | snd_ac97_suspend(chip->ac97); |
1048 | if (chip->irq >= 0) | ||
1049 | free_irq(chip->irq, chip); | ||
1048 | pci_disable_device(pci); | 1050 | pci_disable_device(pci); |
1049 | pci_save_state(pci); | 1051 | pci_save_state(pci); |
1050 | return 0; | 1052 | return 0; |
@@ -1058,6 +1060,9 @@ static int intel8x0m_resume(struct pci_dev *pci) | |||
1058 | pci_restore_state(pci); | 1060 | pci_restore_state(pci); |
1059 | pci_enable_device(pci); | 1061 | pci_enable_device(pci); |
1060 | pci_set_master(pci); | 1062 | pci_set_master(pci); |
1063 | request_irq(pci->irq, snd_intel8x0_interrupt, IRQF_DISABLED|IRQF_SHARED, | ||
1064 | card->shortname, chip); | ||
1065 | chip->irq = pci->irq; | ||
1061 | snd_intel8x0_chip_init(chip, 0); | 1066 | snd_intel8x0_chip_init(chip, 0); |
1062 | snd_ac97_resume(chip->ac97); | 1067 | snd_ac97_resume(chip->ac97); |
1063 | 1068 | ||
diff --git a/sound/pci/mixart/mixart.c b/sound/pci/mixart/mixart.c index cc43ecd67906..216aee5f93e7 100644 --- a/sound/pci/mixart/mixart.c +++ b/sound/pci/mixart/mixart.c | |||
@@ -1109,13 +1109,13 @@ static long long snd_mixart_BA0_llseek(struct snd_info_entry *entry, | |||
1109 | offset = offset & ~3; /* 4 bytes aligned */ | 1109 | offset = offset & ~3; /* 4 bytes aligned */ |
1110 | 1110 | ||
1111 | switch(orig) { | 1111 | switch(orig) { |
1112 | case 0: /* SEEK_SET */ | 1112 | case SEEK_SET: |
1113 | file->f_pos = offset; | 1113 | file->f_pos = offset; |
1114 | break; | 1114 | break; |
1115 | case 1: /* SEEK_CUR */ | 1115 | case SEEK_CUR: |
1116 | file->f_pos += offset; | 1116 | file->f_pos += offset; |
1117 | break; | 1117 | break; |
1118 | case 2: /* SEEK_END, offset is negative */ | 1118 | case SEEK_END: /* offset is negative */ |
1119 | file->f_pos = MIXART_BA0_SIZE + offset; | 1119 | file->f_pos = MIXART_BA0_SIZE + offset; |
1120 | break; | 1120 | break; |
1121 | default: | 1121 | default: |
@@ -1135,13 +1135,13 @@ static long long snd_mixart_BA1_llseek(struct snd_info_entry *entry, | |||
1135 | offset = offset & ~3; /* 4 bytes aligned */ | 1135 | offset = offset & ~3; /* 4 bytes aligned */ |
1136 | 1136 | ||
1137 | switch(orig) { | 1137 | switch(orig) { |
1138 | case 0: /* SEEK_SET */ | 1138 | case SEEK_SET: |
1139 | file->f_pos = offset; | 1139 | file->f_pos = offset; |
1140 | break; | 1140 | break; |
1141 | case 1: /* SEEK_CUR */ | 1141 | case SEEK_CUR: |
1142 | file->f_pos += offset; | 1142 | file->f_pos += offset; |
1143 | break; | 1143 | break; |
1144 | case 2: /* SEEK_END, offset is negative */ | 1144 | case SEEK_END: /* offset is negative */ |
1145 | file->f_pos = MIXART_BA1_SIZE + offset; | 1145 | file->f_pos = MIXART_BA1_SIZE + offset; |
1146 | break; | 1146 | break; |
1147 | default: | 1147 | default: |
diff --git a/sound/pci/mixart/mixart_mixer.c b/sound/pci/mixart/mixart_mixer.c index ed47b732c103..13de0f71d4b7 100644 --- a/sound/pci/mixart/mixart_mixer.c +++ b/sound/pci/mixart/mixart_mixer.c | |||
@@ -31,6 +31,7 @@ | |||
31 | #include "mixart_core.h" | 31 | #include "mixart_core.h" |
32 | #include "mixart_hwdep.h" | 32 | #include "mixart_hwdep.h" |
33 | #include <sound/control.h> | 33 | #include <sound/control.h> |
34 | #include <sound/tlv.h> | ||
34 | #include "mixart_mixer.h" | 35 | #include "mixart_mixer.h" |
35 | 36 | ||
36 | static u32 mixart_analog_level[256] = { | 37 | static u32 mixart_analog_level[256] = { |
@@ -388,12 +389,17 @@ static int mixart_analog_vol_put(struct snd_kcontrol *kcontrol, struct snd_ctl_e | |||
388 | return changed; | 389 | return changed; |
389 | } | 390 | } |
390 | 391 | ||
392 | static DECLARE_TLV_DB_SCALE(db_scale_analog, -9600, 50, 0); | ||
393 | |||
391 | static struct snd_kcontrol_new mixart_control_analog_level = { | 394 | static struct snd_kcontrol_new mixart_control_analog_level = { |
392 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 395 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
396 | .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | | ||
397 | SNDRV_CTL_ELEM_ACCESS_TLV_READ), | ||
393 | /* name will be filled later */ | 398 | /* name will be filled later */ |
394 | .info = mixart_analog_vol_info, | 399 | .info = mixart_analog_vol_info, |
395 | .get = mixart_analog_vol_get, | 400 | .get = mixart_analog_vol_get, |
396 | .put = mixart_analog_vol_put, | 401 | .put = mixart_analog_vol_put, |
402 | .tlv = { .p = db_scale_analog }, | ||
397 | }; | 403 | }; |
398 | 404 | ||
399 | /* shared */ | 405 | /* shared */ |
@@ -866,14 +872,19 @@ static int mixart_pcm_vol_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem | |||
866 | return changed; | 872 | return changed; |
867 | } | 873 | } |
868 | 874 | ||
875 | static DECLARE_TLV_DB_SCALE(db_scale_digital, -10950, 50, 0); | ||
876 | |||
869 | static struct snd_kcontrol_new snd_mixart_pcm_vol = | 877 | static struct snd_kcontrol_new snd_mixart_pcm_vol = |
870 | { | 878 | { |
871 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 879 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
880 | .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | | ||
881 | SNDRV_CTL_ELEM_ACCESS_TLV_READ), | ||
872 | /* name will be filled later */ | 882 | /* name will be filled later */ |
873 | /* count will be filled later */ | 883 | /* count will be filled later */ |
874 | .info = mixart_digital_vol_info, /* shared */ | 884 | .info = mixart_digital_vol_info, /* shared */ |
875 | .get = mixart_pcm_vol_get, | 885 | .get = mixart_pcm_vol_get, |
876 | .put = mixart_pcm_vol_put, | 886 | .put = mixart_pcm_vol_put, |
887 | .tlv = { .p = db_scale_digital }, | ||
877 | }; | 888 | }; |
878 | 889 | ||
879 | 890 | ||
@@ -984,10 +995,13 @@ static int mixart_monitor_vol_put(struct snd_kcontrol *kcontrol, struct snd_ctl_ | |||
984 | 995 | ||
985 | static struct snd_kcontrol_new mixart_control_monitor_vol = { | 996 | static struct snd_kcontrol_new mixart_control_monitor_vol = { |
986 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 997 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
998 | .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | | ||
999 | SNDRV_CTL_ELEM_ACCESS_TLV_READ), | ||
987 | .name = "Monitoring Volume", | 1000 | .name = "Monitoring Volume", |
988 | .info = mixart_digital_vol_info, /* shared */ | 1001 | .info = mixart_digital_vol_info, /* shared */ |
989 | .get = mixart_monitor_vol_get, | 1002 | .get = mixart_monitor_vol_get, |
990 | .put = mixart_monitor_vol_put, | 1003 | .put = mixart_monitor_vol_put, |
1004 | .tlv = { .p = db_scale_digital }, | ||
991 | }; | 1005 | }; |
992 | 1006 | ||
993 | /* | 1007 | /* |
diff --git a/sound/pci/pcxhr/pcxhr_mixer.c b/sound/pci/pcxhr/pcxhr_mixer.c index 94e63a1e90d9..b133ad9e095e 100644 --- a/sound/pci/pcxhr/pcxhr_mixer.c +++ b/sound/pci/pcxhr/pcxhr_mixer.c | |||
@@ -31,6 +31,7 @@ | |||
31 | #include "pcxhr_hwdep.h" | 31 | #include "pcxhr_hwdep.h" |
32 | #include "pcxhr_core.h" | 32 | #include "pcxhr_core.h" |
33 | #include <sound/control.h> | 33 | #include <sound/control.h> |
34 | #include <sound/tlv.h> | ||
34 | #include <sound/asoundef.h> | 35 | #include <sound/asoundef.h> |
35 | #include "pcxhr_mixer.h" | 36 | #include "pcxhr_mixer.h" |
36 | 37 | ||
@@ -43,6 +44,9 @@ | |||
43 | #define PCXHR_ANALOG_PLAYBACK_LEVEL_MAX 128 /* 0.0 dB */ | 44 | #define PCXHR_ANALOG_PLAYBACK_LEVEL_MAX 128 /* 0.0 dB */ |
44 | #define PCXHR_ANALOG_PLAYBACK_ZERO_LEVEL 104 /* -24.0 dB ( 0.0 dB - fix level +24.0 dB ) */ | 45 | #define PCXHR_ANALOG_PLAYBACK_ZERO_LEVEL 104 /* -24.0 dB ( 0.0 dB - fix level +24.0 dB ) */ |
45 | 46 | ||
47 | static DECLARE_TLV_DB_SCALE(db_scale_analog_capture, -9600, 50, 0); | ||
48 | static DECLARE_TLV_DB_SCALE(db_scale_analog_playback, -12800, 100, 0); | ||
49 | |||
46 | static int pcxhr_update_analog_audio_level(struct snd_pcxhr *chip, int is_capture, int channel) | 50 | static int pcxhr_update_analog_audio_level(struct snd_pcxhr *chip, int is_capture, int channel) |
47 | { | 51 | { |
48 | int err, vol; | 52 | int err, vol; |
@@ -130,10 +134,13 @@ static int pcxhr_analog_vol_put(struct snd_kcontrol *kcontrol, | |||
130 | 134 | ||
131 | static struct snd_kcontrol_new pcxhr_control_analog_level = { | 135 | static struct snd_kcontrol_new pcxhr_control_analog_level = { |
132 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 136 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
137 | .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | | ||
138 | SNDRV_CTL_ELEM_ACCESS_TLV_READ), | ||
133 | /* name will be filled later */ | 139 | /* name will be filled later */ |
134 | .info = pcxhr_analog_vol_info, | 140 | .info = pcxhr_analog_vol_info, |
135 | .get = pcxhr_analog_vol_get, | 141 | .get = pcxhr_analog_vol_get, |
136 | .put = pcxhr_analog_vol_put, | 142 | .put = pcxhr_analog_vol_put, |
143 | /* tlv will be filled later */ | ||
137 | }; | 144 | }; |
138 | 145 | ||
139 | /* shared */ | 146 | /* shared */ |
@@ -188,6 +195,7 @@ static struct snd_kcontrol_new pcxhr_control_output_switch = { | |||
188 | #define PCXHR_DIGITAL_LEVEL_MAX 0x1ff /* +18 dB */ | 195 | #define PCXHR_DIGITAL_LEVEL_MAX 0x1ff /* +18 dB */ |
189 | #define PCXHR_DIGITAL_ZERO_LEVEL 0x1b7 /* 0 dB */ | 196 | #define PCXHR_DIGITAL_ZERO_LEVEL 0x1b7 /* 0 dB */ |
190 | 197 | ||
198 | static DECLARE_TLV_DB_SCALE(db_scale_digital, -10950, 50, 0); | ||
191 | 199 | ||
192 | #define MORE_THAN_ONE_STREAM_LEVEL 0x000001 | 200 | #define MORE_THAN_ONE_STREAM_LEVEL 0x000001 |
193 | #define VALID_STREAM_PAN_LEVEL_MASK 0x800000 | 201 | #define VALID_STREAM_PAN_LEVEL_MASK 0x800000 |
@@ -343,11 +351,14 @@ static int pcxhr_pcm_vol_put(struct snd_kcontrol *kcontrol, | |||
343 | static struct snd_kcontrol_new snd_pcxhr_pcm_vol = | 351 | static struct snd_kcontrol_new snd_pcxhr_pcm_vol = |
344 | { | 352 | { |
345 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 353 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
354 | .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | | ||
355 | SNDRV_CTL_ELEM_ACCESS_TLV_READ), | ||
346 | /* name will be filled later */ | 356 | /* name will be filled later */ |
347 | /* count will be filled later */ | 357 | /* count will be filled later */ |
348 | .info = pcxhr_digital_vol_info, /* shared */ | 358 | .info = pcxhr_digital_vol_info, /* shared */ |
349 | .get = pcxhr_pcm_vol_get, | 359 | .get = pcxhr_pcm_vol_get, |
350 | .put = pcxhr_pcm_vol_put, | 360 | .put = pcxhr_pcm_vol_put, |
361 | .tlv = { .p = db_scale_digital }, | ||
351 | }; | 362 | }; |
352 | 363 | ||
353 | 364 | ||
@@ -433,10 +444,13 @@ static int pcxhr_monitor_vol_put(struct snd_kcontrol *kcontrol, | |||
433 | 444 | ||
434 | static struct snd_kcontrol_new pcxhr_control_monitor_vol = { | 445 | static struct snd_kcontrol_new pcxhr_control_monitor_vol = { |
435 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 446 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
447 | .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | | ||
448 | SNDRV_CTL_ELEM_ACCESS_TLV_READ), | ||
436 | .name = "Monitoring Volume", | 449 | .name = "Monitoring Volume", |
437 | .info = pcxhr_digital_vol_info, /* shared */ | 450 | .info = pcxhr_digital_vol_info, /* shared */ |
438 | .get = pcxhr_monitor_vol_get, | 451 | .get = pcxhr_monitor_vol_get, |
439 | .put = pcxhr_monitor_vol_put, | 452 | .put = pcxhr_monitor_vol_put, |
453 | .tlv = { .p = db_scale_digital }, | ||
440 | }; | 454 | }; |
441 | 455 | ||
442 | /* | 456 | /* |
@@ -928,6 +942,7 @@ int pcxhr_create_mixer(struct pcxhr_mgr *mgr) | |||
928 | temp = pcxhr_control_analog_level; | 942 | temp = pcxhr_control_analog_level; |
929 | temp.name = "Master Playback Volume"; | 943 | temp.name = "Master Playback Volume"; |
930 | temp.private_value = 0; /* playback */ | 944 | temp.private_value = 0; /* playback */ |
945 | temp.tlv.p = db_scale_analog_playback; | ||
931 | if ((err = snd_ctl_add(chip->card, snd_ctl_new1(&temp, chip))) < 0) | 946 | if ((err = snd_ctl_add(chip->card, snd_ctl_new1(&temp, chip))) < 0) |
932 | return err; | 947 | return err; |
933 | /* output mute controls */ | 948 | /* output mute controls */ |
@@ -963,6 +978,7 @@ int pcxhr_create_mixer(struct pcxhr_mgr *mgr) | |||
963 | temp = pcxhr_control_analog_level; | 978 | temp = pcxhr_control_analog_level; |
964 | temp.name = "Master Capture Volume"; | 979 | temp.name = "Master Capture Volume"; |
965 | temp.private_value = 1; /* capture */ | 980 | temp.private_value = 1; /* capture */ |
981 | temp.tlv.p = db_scale_analog_capture; | ||
966 | if ((err = snd_ctl_add(chip->card, snd_ctl_new1(&temp, chip))) < 0) | 982 | if ((err = snd_ctl_add(chip->card, snd_ctl_new1(&temp, chip))) < 0) |
967 | return err; | 983 | return err; |
968 | 984 | ||
diff --git a/sound/pci/riptide/riptide.c b/sound/pci/riptide/riptide.c index f435fcd6dca9..fe210c853442 100644 --- a/sound/pci/riptide/riptide.c +++ b/sound/pci/riptide/riptide.c | |||
@@ -673,9 +673,13 @@ static struct lbuspath lbus_rec_path = { | |||
673 | #define FIRMWARE_VERSIONS 1 | 673 | #define FIRMWARE_VERSIONS 1 |
674 | static union firmware_version firmware_versions[] = { | 674 | static union firmware_version firmware_versions[] = { |
675 | { | 675 | { |
676 | .firmware.ASIC = 3,.firmware.CODEC = 2, | 676 | .firmware = { |
677 | .firmware.AUXDSP = 3,.firmware.PROG = 773, | 677 | .ASIC = 3, |
678 | }, | 678 | .CODEC = 2, |
679 | .AUXDSP = 3, | ||
680 | .PROG = 773, | ||
681 | }, | ||
682 | }, | ||
679 | }; | 683 | }; |
680 | 684 | ||
681 | static u32 atoh(unsigned char *in, unsigned int len) | 685 | static u32 atoh(unsigned char *in, unsigned int len) |
diff --git a/sound/pci/rme9652/hdsp.c b/sound/pci/rme9652/hdsp.c index e5a52da77b85..d3e07de433b0 100644 --- a/sound/pci/rme9652/hdsp.c +++ b/sound/pci/rme9652/hdsp.c | |||
@@ -726,22 +726,36 @@ static int hdsp_get_iobox_version (struct hdsp *hdsp) | |||
726 | } | 726 | } |
727 | 727 | ||
728 | 728 | ||
729 | static int hdsp_check_for_firmware (struct hdsp *hdsp, int show_err) | 729 | #ifdef HDSP_FW_LOADER |
730 | static int __devinit hdsp_request_fw_loader(struct hdsp *hdsp); | ||
731 | #endif | ||
732 | |||
733 | static int hdsp_check_for_firmware (struct hdsp *hdsp, int load_on_demand) | ||
730 | { | 734 | { |
731 | if (hdsp->io_type == H9652 || hdsp->io_type == H9632) return 0; | 735 | if (hdsp->io_type == H9652 || hdsp->io_type == H9632) |
736 | return 0; | ||
732 | if ((hdsp_read (hdsp, HDSP_statusRegister) & HDSP_DllError) != 0) { | 737 | if ((hdsp_read (hdsp, HDSP_statusRegister) & HDSP_DllError) != 0) { |
733 | snd_printk(KERN_ERR "Hammerfall-DSP: firmware not present.\n"); | ||
734 | hdsp->state &= ~HDSP_FirmwareLoaded; | 738 | hdsp->state &= ~HDSP_FirmwareLoaded; |
735 | if (! show_err) | 739 | if (! load_on_demand) |
736 | return -EIO; | 740 | return -EIO; |
741 | snd_printk(KERN_ERR "Hammerfall-DSP: firmware not present.\n"); | ||
737 | /* try to load firmware */ | 742 | /* try to load firmware */ |
738 | if (hdsp->state & HDSP_FirmwareCached) { | 743 | if (! (hdsp->state & HDSP_FirmwareCached)) { |
739 | if (snd_hdsp_load_firmware_from_cache(hdsp) != 0) | 744 | #ifdef HDSP_FW_LOADER |
740 | snd_printk(KERN_ERR "Hammerfall-DSP: Firmware loading from cache failed, please upload manually.\n"); | 745 | if (! hdsp_request_fw_loader(hdsp)) |
741 | } else { | 746 | return 0; |
742 | snd_printk(KERN_ERR "Hammerfall-DSP: No firmware loaded nor cached, please upload firmware.\n"); | 747 | #endif |
748 | snd_printk(KERN_ERR | ||
749 | "Hammerfall-DSP: No firmware loaded nor " | ||
750 | "cached, please upload firmware.\n"); | ||
751 | return -EIO; | ||
752 | } | ||
753 | if (snd_hdsp_load_firmware_from_cache(hdsp) != 0) { | ||
754 | snd_printk(KERN_ERR | ||
755 | "Hammerfall-DSP: Firmware loading from " | ||
756 | "cache failed, please upload manually.\n"); | ||
757 | return -EIO; | ||
743 | } | 758 | } |
744 | return -EIO; | ||
745 | } | 759 | } |
746 | return 0; | 760 | return 0; |
747 | } | 761 | } |
@@ -3181,8 +3195,16 @@ snd_hdsp_proc_read(struct snd_info_entry *entry, struct snd_info_buffer *buffer) | |||
3181 | return; | 3195 | return; |
3182 | } | 3196 | } |
3183 | } else { | 3197 | } else { |
3184 | snd_iprintf(buffer, "No firmware loaded nor cached, please upload firmware.\n"); | 3198 | int err = -EINVAL; |
3185 | return; | 3199 | #ifdef HDSP_FW_LOADER |
3200 | err = hdsp_request_fw_loader(hdsp); | ||
3201 | #endif | ||
3202 | if (err < 0) { | ||
3203 | snd_iprintf(buffer, | ||
3204 | "No firmware loaded nor cached, " | ||
3205 | "please upload firmware.\n"); | ||
3206 | return; | ||
3207 | } | ||
3186 | } | 3208 | } |
3187 | } | 3209 | } |
3188 | 3210 | ||
@@ -3851,7 +3873,7 @@ static int snd_hdsp_trigger(struct snd_pcm_substream *substream, int cmd) | |||
3851 | if (hdsp_check_for_iobox (hdsp)) | 3873 | if (hdsp_check_for_iobox (hdsp)) |
3852 | return -EIO; | 3874 | return -EIO; |
3853 | 3875 | ||
3854 | if (hdsp_check_for_firmware(hdsp, 1)) | 3876 | if (hdsp_check_for_firmware(hdsp, 0)) /* no auto-loading in trigger */ |
3855 | return -EIO; | 3877 | return -EIO; |
3856 | 3878 | ||
3857 | spin_lock(&hdsp->lock); | 3879 | spin_lock(&hdsp->lock); |
diff --git a/sound/pci/trident/trident_main.c b/sound/pci/trident/trident_main.c index 4930cc6b054d..ebbe12d78d8c 100644 --- a/sound/pci/trident/trident_main.c +++ b/sound/pci/trident/trident_main.c | |||
@@ -40,6 +40,7 @@ | |||
40 | #include <sound/core.h> | 40 | #include <sound/core.h> |
41 | #include <sound/info.h> | 41 | #include <sound/info.h> |
42 | #include <sound/control.h> | 42 | #include <sound/control.h> |
43 | #include <sound/tlv.h> | ||
43 | #include <sound/trident.h> | 44 | #include <sound/trident.h> |
44 | #include <sound/asoundef.h> | 45 | #include <sound/asoundef.h> |
45 | 46 | ||
@@ -2627,6 +2628,8 @@ static int snd_trident_vol_control_get(struct snd_kcontrol *kcontrol, | |||
2627 | return 0; | 2628 | return 0; |
2628 | } | 2629 | } |
2629 | 2630 | ||
2631 | static DECLARE_TLV_DB_SCALE(db_scale_gvol, -6375, 25, 0); | ||
2632 | |||
2630 | static int snd_trident_vol_control_put(struct snd_kcontrol *kcontrol, | 2633 | static int snd_trident_vol_control_put(struct snd_kcontrol *kcontrol, |
2631 | struct snd_ctl_elem_value *ucontrol) | 2634 | struct snd_ctl_elem_value *ucontrol) |
2632 | { | 2635 | { |
@@ -2653,6 +2656,7 @@ static struct snd_kcontrol_new snd_trident_vol_music_control __devinitdata = | |||
2653 | .get = snd_trident_vol_control_get, | 2656 | .get = snd_trident_vol_control_get, |
2654 | .put = snd_trident_vol_control_put, | 2657 | .put = snd_trident_vol_control_put, |
2655 | .private_value = 16, | 2658 | .private_value = 16, |
2659 | .tlv = { .p = db_scale_gvol }, | ||
2656 | }; | 2660 | }; |
2657 | 2661 | ||
2658 | static struct snd_kcontrol_new snd_trident_vol_wave_control __devinitdata = | 2662 | static struct snd_kcontrol_new snd_trident_vol_wave_control __devinitdata = |
@@ -2663,6 +2667,7 @@ static struct snd_kcontrol_new snd_trident_vol_wave_control __devinitdata = | |||
2663 | .get = snd_trident_vol_control_get, | 2667 | .get = snd_trident_vol_control_get, |
2664 | .put = snd_trident_vol_control_put, | 2668 | .put = snd_trident_vol_control_put, |
2665 | .private_value = 0, | 2669 | .private_value = 0, |
2670 | .tlv = { .p = db_scale_gvol }, | ||
2666 | }; | 2671 | }; |
2667 | 2672 | ||
2668 | /*--------------------------------------------------------------------------- | 2673 | /*--------------------------------------------------------------------------- |
@@ -2730,6 +2735,7 @@ static struct snd_kcontrol_new snd_trident_pcm_vol_control __devinitdata = | |||
2730 | .info = snd_trident_pcm_vol_control_info, | 2735 | .info = snd_trident_pcm_vol_control_info, |
2731 | .get = snd_trident_pcm_vol_control_get, | 2736 | .get = snd_trident_pcm_vol_control_get, |
2732 | .put = snd_trident_pcm_vol_control_put, | 2737 | .put = snd_trident_pcm_vol_control_put, |
2738 | /* FIXME: no tlv yet */ | ||
2733 | }; | 2739 | }; |
2734 | 2740 | ||
2735 | /*--------------------------------------------------------------------------- | 2741 | /*--------------------------------------------------------------------------- |
@@ -2839,6 +2845,8 @@ static int snd_trident_pcm_rvol_control_put(struct snd_kcontrol *kcontrol, | |||
2839 | return change; | 2845 | return change; |
2840 | } | 2846 | } |
2841 | 2847 | ||
2848 | static DECLARE_TLV_DB_SCALE(db_scale_crvol, -3175, 25, 1); | ||
2849 | |||
2842 | static struct snd_kcontrol_new snd_trident_pcm_rvol_control __devinitdata = | 2850 | static struct snd_kcontrol_new snd_trident_pcm_rvol_control __devinitdata = |
2843 | { | 2851 | { |
2844 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 2852 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
@@ -2848,6 +2856,7 @@ static struct snd_kcontrol_new snd_trident_pcm_rvol_control __devinitdata = | |||
2848 | .info = snd_trident_pcm_rvol_control_info, | 2856 | .info = snd_trident_pcm_rvol_control_info, |
2849 | .get = snd_trident_pcm_rvol_control_get, | 2857 | .get = snd_trident_pcm_rvol_control_get, |
2850 | .put = snd_trident_pcm_rvol_control_put, | 2858 | .put = snd_trident_pcm_rvol_control_put, |
2859 | .tlv = { .p = db_scale_crvol }, | ||
2851 | }; | 2860 | }; |
2852 | 2861 | ||
2853 | /*--------------------------------------------------------------------------- | 2862 | /*--------------------------------------------------------------------------- |
@@ -2903,6 +2912,7 @@ static struct snd_kcontrol_new snd_trident_pcm_cvol_control __devinitdata = | |||
2903 | .info = snd_trident_pcm_cvol_control_info, | 2912 | .info = snd_trident_pcm_cvol_control_info, |
2904 | .get = snd_trident_pcm_cvol_control_get, | 2913 | .get = snd_trident_pcm_cvol_control_get, |
2905 | .put = snd_trident_pcm_cvol_control_put, | 2914 | .put = snd_trident_pcm_cvol_control_put, |
2915 | .tlv = { .p = db_scale_crvol }, | ||
2906 | }; | 2916 | }; |
2907 | 2917 | ||
2908 | static void snd_trident_notify_pcm_change1(struct snd_card *card, | 2918 | static void snd_trident_notify_pcm_change1(struct snd_card *card, |
diff --git a/sound/pci/via82xx.c b/sound/pci/via82xx.c index 08da9234efb3..6db3d4cc4d8d 100644 --- a/sound/pci/via82xx.c +++ b/sound/pci/via82xx.c | |||
@@ -59,6 +59,7 @@ | |||
59 | #include <sound/pcm.h> | 59 | #include <sound/pcm.h> |
60 | #include <sound/pcm_params.h> | 60 | #include <sound/pcm_params.h> |
61 | #include <sound/info.h> | 61 | #include <sound/info.h> |
62 | #include <sound/tlv.h> | ||
62 | #include <sound/ac97_codec.h> | 63 | #include <sound/ac97_codec.h> |
63 | #include <sound/mpu401.h> | 64 | #include <sound/mpu401.h> |
64 | #include <sound/initval.h> | 65 | #include <sound/initval.h> |
@@ -1277,7 +1278,18 @@ static int snd_via82xx_pcm_close(struct snd_pcm_substream *substream) | |||
1277 | if (! ratep->used) | 1278 | if (! ratep->used) |
1278 | ratep->rate = 0; | 1279 | ratep->rate = 0; |
1279 | spin_unlock_irq(&ratep->lock); | 1280 | spin_unlock_irq(&ratep->lock); |
1280 | 1281 | if (! ratep->rate) { | |
1282 | if (! viadev->direction) { | ||
1283 | snd_ac97_update_power(chip->ac97, | ||
1284 | AC97_PCM_FRONT_DAC_RATE, 0); | ||
1285 | snd_ac97_update_power(chip->ac97, | ||
1286 | AC97_PCM_SURR_DAC_RATE, 0); | ||
1287 | snd_ac97_update_power(chip->ac97, | ||
1288 | AC97_PCM_LFE_DAC_RATE, 0); | ||
1289 | } else | ||
1290 | snd_ac97_update_power(chip->ac97, | ||
1291 | AC97_PCM_LR_ADC_RATE, 0); | ||
1292 | } | ||
1281 | viadev->substream = NULL; | 1293 | viadev->substream = NULL; |
1282 | return 0; | 1294 | return 0; |
1283 | } | 1295 | } |
@@ -1687,21 +1699,29 @@ static int snd_via8233_pcmdxs_volume_put(struct snd_kcontrol *kcontrol, | |||
1687 | return change; | 1699 | return change; |
1688 | } | 1700 | } |
1689 | 1701 | ||
1702 | static DECLARE_TLV_DB_SCALE(db_scale_dxs, -9450, 150, 1); | ||
1703 | |||
1690 | static struct snd_kcontrol_new snd_via8233_pcmdxs_volume_control __devinitdata = { | 1704 | static struct snd_kcontrol_new snd_via8233_pcmdxs_volume_control __devinitdata = { |
1691 | .name = "PCM Playback Volume", | 1705 | .name = "PCM Playback Volume", |
1692 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 1706 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
1707 | .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | | ||
1708 | SNDRV_CTL_ELEM_ACCESS_TLV_READ), | ||
1693 | .info = snd_via8233_dxs_volume_info, | 1709 | .info = snd_via8233_dxs_volume_info, |
1694 | .get = snd_via8233_pcmdxs_volume_get, | 1710 | .get = snd_via8233_pcmdxs_volume_get, |
1695 | .put = snd_via8233_pcmdxs_volume_put, | 1711 | .put = snd_via8233_pcmdxs_volume_put, |
1712 | .tlv = { .p = db_scale_dxs } | ||
1696 | }; | 1713 | }; |
1697 | 1714 | ||
1698 | static struct snd_kcontrol_new snd_via8233_dxs_volume_control __devinitdata = { | 1715 | static struct snd_kcontrol_new snd_via8233_dxs_volume_control __devinitdata = { |
1699 | .name = "VIA DXS Playback Volume", | 1716 | .name = "VIA DXS Playback Volume", |
1700 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 1717 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
1718 | .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | | ||
1719 | SNDRV_CTL_ELEM_ACCESS_TLV_READ), | ||
1701 | .count = 4, | 1720 | .count = 4, |
1702 | .info = snd_via8233_dxs_volume_info, | 1721 | .info = snd_via8233_dxs_volume_info, |
1703 | .get = snd_via8233_dxs_volume_get, | 1722 | .get = snd_via8233_dxs_volume_get, |
1704 | .put = snd_via8233_dxs_volume_put, | 1723 | .put = snd_via8233_dxs_volume_put, |
1724 | .tlv = { .p = db_scale_dxs } | ||
1705 | }; | 1725 | }; |
1706 | 1726 | ||
1707 | /* | 1727 | /* |
@@ -2393,6 +2413,7 @@ static int __devinit check_dxs_list(struct pci_dev *pci, int revision) | |||
2393 | { .subvendor = 0x16f3, .subdevice = 0x6405, .action = VIA_DXS_SRC }, /* Jetway K8M8MS */ | 2413 | { .subvendor = 0x16f3, .subdevice = 0x6405, .action = VIA_DXS_SRC }, /* Jetway K8M8MS */ |
2394 | { .subvendor = 0x1734, .subdevice = 0x1078, .action = VIA_DXS_SRC }, /* FSC Amilo L7300 */ | 2414 | { .subvendor = 0x1734, .subdevice = 0x1078, .action = VIA_DXS_SRC }, /* FSC Amilo L7300 */ |
2395 | { .subvendor = 0x1734, .subdevice = 0x1093, .action = VIA_DXS_SRC }, /* FSC */ | 2415 | { .subvendor = 0x1734, .subdevice = 0x1093, .action = VIA_DXS_SRC }, /* FSC */ |
2416 | { .subvendor = 0x1734, .subdevice = 0x10ab, .action = VIA_DXS_SRC }, /* FSC */ | ||
2396 | { .subvendor = 0x1849, .subdevice = 0x3059, .action = VIA_DXS_NO_VRA }, /* ASRock K7VM2 */ | 2417 | { .subvendor = 0x1849, .subdevice = 0x3059, .action = VIA_DXS_NO_VRA }, /* ASRock K7VM2 */ |
2397 | { .subvendor = 0x1849, .subdevice = 0x9739, .action = VIA_DXS_SRC }, /* ASRock mobo(?) */ | 2418 | { .subvendor = 0x1849, .subdevice = 0x9739, .action = VIA_DXS_SRC }, /* ASRock mobo(?) */ |
2398 | { .subvendor = 0x1849, .subdevice = 0x9761, .action = VIA_DXS_SRC }, /* ASRock mobo(?) */ | 2419 | { .subvendor = 0x1849, .subdevice = 0x9761, .action = VIA_DXS_SRC }, /* ASRock mobo(?) */ |
diff --git a/sound/pci/vx222/vx222.c b/sound/pci/vx222/vx222.c index 9c03c6b4e490..e7cd8acab59a 100644 --- a/sound/pci/vx222/vx222.c +++ b/sound/pci/vx222/vx222.c | |||
@@ -26,6 +26,7 @@ | |||
26 | #include <linux/moduleparam.h> | 26 | #include <linux/moduleparam.h> |
27 | #include <sound/core.h> | 27 | #include <sound/core.h> |
28 | #include <sound/initval.h> | 28 | #include <sound/initval.h> |
29 | #include <sound/tlv.h> | ||
29 | #include "vx222.h" | 30 | #include "vx222.h" |
30 | 31 | ||
31 | #define CARD_NAME "VX222" | 32 | #define CARD_NAME "VX222" |
@@ -72,6 +73,9 @@ MODULE_DEVICE_TABLE(pci, snd_vx222_ids); | |||
72 | /* | 73 | /* |
73 | */ | 74 | */ |
74 | 75 | ||
76 | static DECLARE_TLV_DB_SCALE(db_scale_old_vol, -11350, 50, 0); | ||
77 | static DECLARE_TLV_DB_SCALE(db_scale_akm, -7350, 50, 0); | ||
78 | |||
75 | static struct snd_vx_hardware vx222_old_hw = { | 79 | static struct snd_vx_hardware vx222_old_hw = { |
76 | 80 | ||
77 | .name = "VX222/Old", | 81 | .name = "VX222/Old", |
@@ -81,6 +85,7 @@ static struct snd_vx_hardware vx222_old_hw = { | |||
81 | .num_ins = 1, | 85 | .num_ins = 1, |
82 | .num_outs = 1, | 86 | .num_outs = 1, |
83 | .output_level_max = VX_ANALOG_OUT_LEVEL_MAX, | 87 | .output_level_max = VX_ANALOG_OUT_LEVEL_MAX, |
88 | .output_level_db_scale = db_scale_old_vol, | ||
84 | }; | 89 | }; |
85 | 90 | ||
86 | static struct snd_vx_hardware vx222_v2_hw = { | 91 | static struct snd_vx_hardware vx222_v2_hw = { |
@@ -92,6 +97,7 @@ static struct snd_vx_hardware vx222_v2_hw = { | |||
92 | .num_ins = 1, | 97 | .num_ins = 1, |
93 | .num_outs = 1, | 98 | .num_outs = 1, |
94 | .output_level_max = VX2_AKM_LEVEL_MAX, | 99 | .output_level_max = VX2_AKM_LEVEL_MAX, |
100 | .output_level_db_scale = db_scale_akm, | ||
95 | }; | 101 | }; |
96 | 102 | ||
97 | static struct snd_vx_hardware vx222_mic_hw = { | 103 | static struct snd_vx_hardware vx222_mic_hw = { |
@@ -103,6 +109,7 @@ static struct snd_vx_hardware vx222_mic_hw = { | |||
103 | .num_ins = 1, | 109 | .num_ins = 1, |
104 | .num_outs = 1, | 110 | .num_outs = 1, |
105 | .output_level_max = VX2_AKM_LEVEL_MAX, | 111 | .output_level_max = VX2_AKM_LEVEL_MAX, |
112 | .output_level_db_scale = db_scale_akm, | ||
106 | }; | 113 | }; |
107 | 114 | ||
108 | 115 | ||
diff --git a/sound/pci/vx222/vx222_ops.c b/sound/pci/vx222/vx222_ops.c index 9b6d345b83a6..5e51950e05f9 100644 --- a/sound/pci/vx222/vx222_ops.c +++ b/sound/pci/vx222/vx222_ops.c | |||
@@ -28,6 +28,7 @@ | |||
28 | 28 | ||
29 | #include <sound/core.h> | 29 | #include <sound/core.h> |
30 | #include <sound/control.h> | 30 | #include <sound/control.h> |
31 | #include <sound/tlv.h> | ||
31 | #include <asm/io.h> | 32 | #include <asm/io.h> |
32 | #include "vx222.h" | 33 | #include "vx222.h" |
33 | 34 | ||
@@ -845,6 +846,8 @@ static void vx2_set_input_level(struct snd_vx222 *chip) | |||
845 | 846 | ||
846 | #define MIC_LEVEL_MAX 0xff | 847 | #define MIC_LEVEL_MAX 0xff |
847 | 848 | ||
849 | static DECLARE_TLV_DB_SCALE(db_scale_mic, -6450, 50, 0); | ||
850 | |||
848 | /* | 851 | /* |
849 | * controls API for input levels | 852 | * controls API for input levels |
850 | */ | 853 | */ |
@@ -922,18 +925,24 @@ static int vx_mic_level_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_v | |||
922 | 925 | ||
923 | static struct snd_kcontrol_new vx_control_input_level = { | 926 | static struct snd_kcontrol_new vx_control_input_level = { |
924 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 927 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
928 | .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | | ||
929 | SNDRV_CTL_ELEM_ACCESS_TLV_READ), | ||
925 | .name = "Capture Volume", | 930 | .name = "Capture Volume", |
926 | .info = vx_input_level_info, | 931 | .info = vx_input_level_info, |
927 | .get = vx_input_level_get, | 932 | .get = vx_input_level_get, |
928 | .put = vx_input_level_put, | 933 | .put = vx_input_level_put, |
934 | .tlv = { .p = db_scale_mic }, | ||
929 | }; | 935 | }; |
930 | 936 | ||
931 | static struct snd_kcontrol_new vx_control_mic_level = { | 937 | static struct snd_kcontrol_new vx_control_mic_level = { |
932 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 938 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
939 | .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | | ||
940 | SNDRV_CTL_ELEM_ACCESS_TLV_READ), | ||
933 | .name = "Mic Capture Volume", | 941 | .name = "Mic Capture Volume", |
934 | .info = vx_mic_level_info, | 942 | .info = vx_mic_level_info, |
935 | .get = vx_mic_level_get, | 943 | .get = vx_mic_level_get, |
936 | .put = vx_mic_level_put, | 944 | .put = vx_mic_level_put, |
945 | .tlv = { .p = db_scale_mic }, | ||
937 | }; | 946 | }; |
938 | 947 | ||
939 | /* | 948 | /* |
diff --git a/sound/pci/ymfpci/ymfpci_main.c b/sound/pci/ymfpci/ymfpci_main.c index a55b5fd7da64..24f6fc52f898 100644 --- a/sound/pci/ymfpci/ymfpci_main.c +++ b/sound/pci/ymfpci/ymfpci_main.c | |||
@@ -36,6 +36,7 @@ | |||
36 | #include <sound/core.h> | 36 | #include <sound/core.h> |
37 | #include <sound/control.h> | 37 | #include <sound/control.h> |
38 | #include <sound/info.h> | 38 | #include <sound/info.h> |
39 | #include <sound/tlv.h> | ||
39 | #include <sound/ymfpci.h> | 40 | #include <sound/ymfpci.h> |
40 | #include <sound/asoundef.h> | 41 | #include <sound/asoundef.h> |
41 | #include <sound/mpu401.h> | 42 | #include <sound/mpu401.h> |
@@ -1477,11 +1478,15 @@ static int snd_ymfpci_put_single(struct snd_kcontrol *kcontrol, | |||
1477 | return change; | 1478 | return change; |
1478 | } | 1479 | } |
1479 | 1480 | ||
1481 | static DECLARE_TLV_DB_LINEAR(db_scale_native, TLV_DB_GAIN_MUTE, 0); | ||
1482 | |||
1480 | #define YMFPCI_DOUBLE(xname, xindex, reg) \ | 1483 | #define YMFPCI_DOUBLE(xname, xindex, reg) \ |
1481 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \ | 1484 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \ |
1485 | .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ, \ | ||
1482 | .info = snd_ymfpci_info_double, \ | 1486 | .info = snd_ymfpci_info_double, \ |
1483 | .get = snd_ymfpci_get_double, .put = snd_ymfpci_put_double, \ | 1487 | .get = snd_ymfpci_get_double, .put = snd_ymfpci_put_double, \ |
1484 | .private_value = reg } | 1488 | .private_value = reg, \ |
1489 | .tlv = { .p = db_scale_native } } | ||
1485 | 1490 | ||
1486 | static int snd_ymfpci_info_double(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) | 1491 | static int snd_ymfpci_info_double(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) |
1487 | { | 1492 | { |
diff --git a/sound/pcmcia/pdaudiocf/pdaudiocf.c b/sound/pcmcia/pdaudiocf/pdaudiocf.c index 1c09e5f49da8..fd3590fcaedb 100644 --- a/sound/pcmcia/pdaudiocf/pdaudiocf.c +++ b/sound/pcmcia/pdaudiocf/pdaudiocf.c | |||
@@ -206,7 +206,7 @@ static void snd_pdacf_detach(struct pcmcia_device *link) | |||
206 | snd_pdacf_powerdown(chip); | 206 | snd_pdacf_powerdown(chip); |
207 | chip->chip_status |= PDAUDIOCF_STAT_IS_STALE; /* to be sure */ | 207 | chip->chip_status |= PDAUDIOCF_STAT_IS_STALE; /* to be sure */ |
208 | snd_card_disconnect(chip->card); | 208 | snd_card_disconnect(chip->card); |
209 | snd_card_free_in_thread(chip->card); | 209 | snd_card_free_when_closed(chip->card); |
210 | } | 210 | } |
211 | 211 | ||
212 | /* | 212 | /* |
diff --git a/sound/pcmcia/vx/vxp_mixer.c b/sound/pcmcia/vx/vxp_mixer.c index e237f6c2018f..bced7b623b12 100644 --- a/sound/pcmcia/vx/vxp_mixer.c +++ b/sound/pcmcia/vx/vxp_mixer.c | |||
@@ -23,6 +23,7 @@ | |||
23 | #include <sound/driver.h> | 23 | #include <sound/driver.h> |
24 | #include <sound/core.h> | 24 | #include <sound/core.h> |
25 | #include <sound/control.h> | 25 | #include <sound/control.h> |
26 | #include <sound/tlv.h> | ||
26 | #include "vxpocket.h" | 27 | #include "vxpocket.h" |
27 | 28 | ||
28 | #define MIC_LEVEL_MIN 0 | 29 | #define MIC_LEVEL_MIN 0 |
@@ -63,12 +64,17 @@ static int vx_mic_level_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_v | |||
63 | return 0; | 64 | return 0; |
64 | } | 65 | } |
65 | 66 | ||
67 | static DECLARE_TLV_DB_SCALE(db_scale_mic, -21, 3, 0); | ||
68 | |||
66 | static struct snd_kcontrol_new vx_control_mic_level = { | 69 | static struct snd_kcontrol_new vx_control_mic_level = { |
67 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 70 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
71 | .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | | ||
72 | SNDRV_CTL_ELEM_ACCESS_TLV_READ), | ||
68 | .name = "Mic Capture Volume", | 73 | .name = "Mic Capture Volume", |
69 | .info = vx_mic_level_info, | 74 | .info = vx_mic_level_info, |
70 | .get = vx_mic_level_get, | 75 | .get = vx_mic_level_get, |
71 | .put = vx_mic_level_put, | 76 | .put = vx_mic_level_put, |
77 | .tlv = { .p = db_scale_mic }, | ||
72 | }; | 78 | }; |
73 | 79 | ||
74 | /* | 80 | /* |
diff --git a/sound/pcmcia/vx/vxpocket.c b/sound/pcmcia/vx/vxpocket.c index cafe6640cc1a..3089fcca800e 100644 --- a/sound/pcmcia/vx/vxpocket.c +++ b/sound/pcmcia/vx/vxpocket.c | |||
@@ -27,6 +27,7 @@ | |||
27 | #include <pcmcia/ciscode.h> | 27 | #include <pcmcia/ciscode.h> |
28 | #include <pcmcia/cisreg.h> | 28 | #include <pcmcia/cisreg.h> |
29 | #include <sound/initval.h> | 29 | #include <sound/initval.h> |
30 | #include <sound/tlv.h> | ||
30 | 31 | ||
31 | /* | 32 | /* |
32 | */ | 33 | */ |
@@ -65,7 +66,7 @@ static void vxpocket_release(struct pcmcia_device *link) | |||
65 | } | 66 | } |
66 | 67 | ||
67 | /* | 68 | /* |
68 | * destructor, called from snd_card_free_in_thread() | 69 | * destructor, called from snd_card_free_when_closed() |
69 | */ | 70 | */ |
70 | static int snd_vxpocket_dev_free(struct snd_device *device) | 71 | static int snd_vxpocket_dev_free(struct snd_device *device) |
71 | { | 72 | { |
@@ -90,6 +91,8 @@ static int snd_vxpocket_dev_free(struct snd_device *device) | |||
90 | * Only output levels can be modified | 91 | * Only output levels can be modified |
91 | */ | 92 | */ |
92 | 93 | ||
94 | static DECLARE_TLV_DB_SCALE(db_scale_old_vol, -11350, 50, 0); | ||
95 | |||
93 | static struct snd_vx_hardware vxpocket_hw = { | 96 | static struct snd_vx_hardware vxpocket_hw = { |
94 | .name = "VXPocket", | 97 | .name = "VXPocket", |
95 | .type = VX_TYPE_VXPOCKET, | 98 | .type = VX_TYPE_VXPOCKET, |
@@ -99,6 +102,7 @@ static struct snd_vx_hardware vxpocket_hw = { | |||
99 | .num_ins = 1, | 102 | .num_ins = 1, |
100 | .num_outs = 1, | 103 | .num_outs = 1, |
101 | .output_level_max = VX_ANALOG_OUT_LEVEL_MAX, | 104 | .output_level_max = VX_ANALOG_OUT_LEVEL_MAX, |
105 | .output_level_db_scale = db_scale_old_vol, | ||
102 | }; | 106 | }; |
103 | 107 | ||
104 | /* VX-pocket 440 | 108 | /* VX-pocket 440 |
@@ -120,6 +124,7 @@ static struct snd_vx_hardware vxp440_hw = { | |||
120 | .num_ins = 2, | 124 | .num_ins = 2, |
121 | .num_outs = 2, | 125 | .num_outs = 2, |
122 | .output_level_max = VX_ANALOG_OUT_LEVEL_MAX, | 126 | .output_level_max = VX_ANALOG_OUT_LEVEL_MAX, |
127 | .output_level_db_scale = db_scale_old_vol, | ||
123 | }; | 128 | }; |
124 | 129 | ||
125 | 130 | ||
@@ -363,7 +368,7 @@ static void vxpocket_detach(struct pcmcia_device *link) | |||
363 | chip->chip_status |= VX_STAT_IS_STALE; /* to be sure */ | 368 | chip->chip_status |= VX_STAT_IS_STALE; /* to be sure */ |
364 | snd_card_disconnect(chip->card); | 369 | snd_card_disconnect(chip->card); |
365 | vxpocket_release(link); | 370 | vxpocket_release(link); |
366 | snd_card_free_in_thread(chip->card); | 371 | snd_card_free_when_closed(chip->card); |
367 | } | 372 | } |
368 | 373 | ||
369 | /* | 374 | /* |
diff --git a/sound/ppc/beep.c b/sound/ppc/beep.c index 5fec1e58f310..5f38f670102c 100644 --- a/sound/ppc/beep.c +++ b/sound/ppc/beep.c | |||
@@ -215,15 +215,18 @@ int __init snd_pmac_attach_beep(struct snd_pmac *chip) | |||
215 | { | 215 | { |
216 | struct pmac_beep *beep; | 216 | struct pmac_beep *beep; |
217 | struct input_dev *input_dev; | 217 | struct input_dev *input_dev; |
218 | struct snd_kcontrol *beep_ctl; | ||
218 | void *dmabuf; | 219 | void *dmabuf; |
219 | int err = -ENOMEM; | 220 | int err = -ENOMEM; |
220 | 221 | ||
221 | beep = kzalloc(sizeof(*beep), GFP_KERNEL); | 222 | beep = kzalloc(sizeof(*beep), GFP_KERNEL); |
223 | if (! beep) | ||
224 | return -ENOMEM; | ||
222 | dmabuf = dma_alloc_coherent(&chip->pdev->dev, BEEP_BUFLEN * 4, | 225 | dmabuf = dma_alloc_coherent(&chip->pdev->dev, BEEP_BUFLEN * 4, |
223 | &beep->addr, GFP_KERNEL); | 226 | &beep->addr, GFP_KERNEL); |
224 | input_dev = input_allocate_device(); | 227 | input_dev = input_allocate_device(); |
225 | if (!beep || !dmabuf || !input_dev) | 228 | if (! dmabuf || ! input_dev) |
226 | goto fail; | 229 | goto fail1; |
227 | 230 | ||
228 | /* FIXME: set more better values */ | 231 | /* FIXME: set more better values */ |
229 | input_dev->name = "PowerMac Beep"; | 232 | input_dev->name = "PowerMac Beep"; |
@@ -244,17 +247,24 @@ int __init snd_pmac_attach_beep(struct snd_pmac *chip) | |||
244 | beep->volume = BEEP_VOLUME; | 247 | beep->volume = BEEP_VOLUME; |
245 | beep->running = 0; | 248 | beep->running = 0; |
246 | 249 | ||
247 | err = snd_ctl_add(chip->card, snd_ctl_new1(&snd_pmac_beep_mixer, chip)); | 250 | beep_ctl = snd_ctl_new1(&snd_pmac_beep_mixer, chip); |
251 | err = snd_ctl_add(chip->card, beep_ctl); | ||
248 | if (err < 0) | 252 | if (err < 0) |
249 | goto fail; | 253 | goto fail1; |
254 | |||
255 | chip->beep = beep; | ||
250 | 256 | ||
251 | chip->beep = beep; | 257 | err = input_register_device(beep->dev); |
252 | input_register_device(beep->dev); | 258 | if (err) |
253 | 259 | goto fail2; | |
254 | return 0; | 260 | |
255 | 261 | return 0; | |
256 | fail: input_free_device(input_dev); | 262 | |
257 | kfree(dmabuf); | 263 | fail2: snd_ctl_remove(chip->card, beep_ctl); |
264 | fail1: input_free_device(input_dev); | ||
265 | if (dmabuf) | ||
266 | dma_free_coherent(&chip->pdev->dev, BEEP_BUFLEN * 4, | ||
267 | dmabuf, beep->addr); | ||
258 | kfree(beep); | 268 | kfree(beep); |
259 | return err; | 269 | return err; |
260 | } | 270 | } |
diff --git a/sound/ppc/keywest.c b/sound/ppc/keywest.c index 59482a4cd446..272ae38e9b18 100644 --- a/sound/ppc/keywest.c +++ b/sound/ppc/keywest.c | |||
@@ -117,6 +117,9 @@ int __init snd_pmac_tumbler_post_init(void) | |||
117 | { | 117 | { |
118 | int err; | 118 | int err; |
119 | 119 | ||
120 | if (!keywest_ctx || !keywest_ctx->client) | ||
121 | return -ENXIO; | ||
122 | |||
120 | if ((err = keywest_ctx->init_client(keywest_ctx)) < 0) { | 123 | if ((err = keywest_ctx->init_client(keywest_ctx)) < 0) { |
121 | snd_printk(KERN_ERR "tumbler: %i :cannot initialize the MCS\n", err); | 124 | snd_printk(KERN_ERR "tumbler: %i :cannot initialize the MCS\n", err); |
122 | return err; | 125 | return err; |
diff --git a/sound/ppc/tumbler.c b/sound/ppc/tumbler.c index 6ae2d5b9aa4a..cdff53e4a17e 100644 --- a/sound/ppc/tumbler.c +++ b/sound/ppc/tumbler.c | |||
@@ -190,7 +190,7 @@ static int check_audio_gpio(struct pmac_gpio *gp) | |||
190 | 190 | ||
191 | ret = do_gpio_read(gp); | 191 | ret = do_gpio_read(gp); |
192 | 192 | ||
193 | return (ret & 0xd) == (gp->active_val & 0xd); | 193 | return (ret & 0x1) == (gp->active_val & 0x1); |
194 | } | 194 | } |
195 | 195 | ||
196 | static int read_audio_gpio(struct pmac_gpio *gp) | 196 | static int read_audio_gpio(struct pmac_gpio *gp) |
@@ -198,7 +198,8 @@ static int read_audio_gpio(struct pmac_gpio *gp) | |||
198 | int ret; | 198 | int ret; |
199 | if (! gp->addr) | 199 | if (! gp->addr) |
200 | return 0; | 200 | return 0; |
201 | ret = ((do_gpio_read(gp) & 0x02) !=0); | 201 | ret = do_gpio_read(gp); |
202 | ret = (ret & 0x02) !=0; | ||
202 | return ret == gp->active_state; | 203 | return ret == gp->active_state; |
203 | } | 204 | } |
204 | 205 | ||
diff --git a/sound/sparc/dbri.c b/sound/sparc/dbri.c index f3ae6e23610e..e4935fca12df 100644 --- a/sound/sparc/dbri.c +++ b/sound/sparc/dbri.c | |||
@@ -2,6 +2,8 @@ | |||
2 | * Driver for DBRI sound chip found on Sparcs. | 2 | * Driver for DBRI sound chip found on Sparcs. |
3 | * Copyright (C) 2004, 2005 Martin Habets (mhabets@users.sourceforge.net) | 3 | * Copyright (C) 2004, 2005 Martin Habets (mhabets@users.sourceforge.net) |
4 | * | 4 | * |
5 | * Converted to ring buffered version by Krzysztof Helt (krzysztof.h1@wp.pl) | ||
6 | * | ||
5 | * Based entirely upon drivers/sbus/audio/dbri.c which is: | 7 | * Based entirely upon drivers/sbus/audio/dbri.c which is: |
6 | * Copyright (C) 1997 Rudolf Koenig (rfkoenig@immd4.informatik.uni-erlangen.de) | 8 | * Copyright (C) 1997 Rudolf Koenig (rfkoenig@immd4.informatik.uni-erlangen.de) |
7 | * Copyright (C) 1998, 1999 Brent Baccala (baccala@freesoft.org) | 9 | * Copyright (C) 1998, 1999 Brent Baccala (baccala@freesoft.org) |
@@ -34,7 +36,7 @@ | |||
34 | * (the second one is a monitor/tee pipe, valid only for serial input). | 36 | * (the second one is a monitor/tee pipe, valid only for serial input). |
35 | * | 37 | * |
36 | * The mmcodec is connected via the CHI bus and needs the data & some | 38 | * The mmcodec is connected via the CHI bus and needs the data & some |
37 | * parameters (volume, balance, output selection) timemultiplexed in 8 byte | 39 | * parameters (volume, output selection) timemultiplexed in 8 byte |
38 | * chunks. It also has a control mode, which serves for audio format setting. | 40 | * chunks. It also has a control mode, which serves for audio format setting. |
39 | * | 41 | * |
40 | * Looking at the CS4215 data sheet it is easy to set up 2 or 4 codecs on | 42 | * Looking at the CS4215 data sheet it is easy to set up 2 or 4 codecs on |
@@ -83,7 +85,7 @@ MODULE_PARM_DESC(id, "ID string for Sun DBRI soundcard."); | |||
83 | module_param_array(enable, bool, NULL, 0444); | 85 | module_param_array(enable, bool, NULL, 0444); |
84 | MODULE_PARM_DESC(enable, "Enable Sun DBRI soundcard."); | 86 | MODULE_PARM_DESC(enable, "Enable Sun DBRI soundcard."); |
85 | 87 | ||
86 | #define DBRI_DEBUG | 88 | #undef DBRI_DEBUG |
87 | 89 | ||
88 | #define D_INT (1<<0) | 90 | #define D_INT (1<<0) |
89 | #define D_GEN (1<<1) | 91 | #define D_GEN (1<<1) |
@@ -104,17 +106,15 @@ static char *cmds[] = { | |||
104 | 106 | ||
105 | #define dprintk(a, x...) if(dbri_debug & a) printk(KERN_DEBUG x) | 107 | #define dprintk(a, x...) if(dbri_debug & a) printk(KERN_DEBUG x) |
106 | 108 | ||
107 | #define DBRI_CMD(cmd, intr, value) ((cmd << 28) | \ | ||
108 | (1 << 27) | \ | ||
109 | value) | ||
110 | #else | 109 | #else |
111 | #define dprintk(a, x...) | 110 | #define dprintk(a, x...) do { } while (0) |
112 | 111 | ||
113 | #define DBRI_CMD(cmd, intr, value) ((cmd << 28) | \ | ||
114 | (intr << 27) | \ | ||
115 | value) | ||
116 | #endif /* DBRI_DEBUG */ | 112 | #endif /* DBRI_DEBUG */ |
117 | 113 | ||
114 | #define DBRI_CMD(cmd, intr, value) ((cmd << 28) | \ | ||
115 | (intr << 27) | \ | ||
116 | value) | ||
117 | |||
118 | /*************************************************************************** | 118 | /*************************************************************************** |
119 | CS4215 specific definitions and structures | 119 | CS4215 specific definitions and structures |
120 | ****************************************************************************/ | 120 | ****************************************************************************/ |
@@ -160,7 +160,7 @@ static struct { | |||
160 | /* { NA, (1 << 4), (5 << 3) }, */ | 160 | /* { NA, (1 << 4), (5 << 3) }, */ |
161 | { 48000, (1 << 4), (6 << 3) }, | 161 | { 48000, (1 << 4), (6 << 3) }, |
162 | { 9600, (1 << 4), (7 << 3) }, | 162 | { 9600, (1 << 4), (7 << 3) }, |
163 | { 5513, (2 << 4), (0 << 3) }, /* Actually 5512.5 */ | 163 | { 5512, (2 << 4), (0 << 3) }, /* Actually 5512.5 */ |
164 | { 11025, (2 << 4), (1 << 3) }, | 164 | { 11025, (2 << 4), (1 << 3) }, |
165 | { 18900, (2 << 4), (2 << 3) }, | 165 | { 18900, (2 << 4), (2 << 3) }, |
166 | { 22050, (2 << 4), (3 << 3) }, | 166 | { 22050, (2 << 4), (3 << 3) }, |
@@ -240,28 +240,21 @@ static struct { | |||
240 | #define REG9 0x24UL /* Interrupt Queue Pointer */ | 240 | #define REG9 0x24UL /* Interrupt Queue Pointer */ |
241 | 241 | ||
242 | #define DBRI_NO_CMDS 64 | 242 | #define DBRI_NO_CMDS 64 |
243 | #define DBRI_NO_INTS 1 /* Note: the value of this define was | ||
244 | * originally 2. The ringbuffer to store | ||
245 | * interrupts in dma is currently broken. | ||
246 | * This is a temporary fix until the ringbuffer | ||
247 | * is fixed. | ||
248 | */ | ||
249 | #define DBRI_INT_BLK 64 | 243 | #define DBRI_INT_BLK 64 |
250 | #define DBRI_NO_DESCS 64 | 244 | #define DBRI_NO_DESCS 64 |
251 | #define DBRI_NO_PIPES 32 | 245 | #define DBRI_NO_PIPES 32 |
252 | 246 | #define DBRI_MAX_PIPE (DBRI_NO_PIPES - 1) | |
253 | #define DBRI_MM_ONB 1 | ||
254 | #define DBRI_MM_SB 2 | ||
255 | 247 | ||
256 | #define DBRI_REC 0 | 248 | #define DBRI_REC 0 |
257 | #define DBRI_PLAY 1 | 249 | #define DBRI_PLAY 1 |
258 | #define DBRI_NO_STREAMS 2 | 250 | #define DBRI_NO_STREAMS 2 |
259 | 251 | ||
260 | /* One transmit/receive descriptor */ | 252 | /* One transmit/receive descriptor */ |
253 | /* When ba != 0 descriptor is used */ | ||
261 | struct dbri_mem { | 254 | struct dbri_mem { |
262 | volatile __u32 word1; | 255 | volatile __u32 word1; |
263 | volatile __u32 ba; /* Transmit/Receive Buffer Address */ | 256 | __u32 ba; /* Transmit/Receive Buffer Address */ |
264 | volatile __u32 nda; /* Next Descriptor Address */ | 257 | __u32 nda; /* Next Descriptor Address */ |
265 | volatile __u32 word4; | 258 | volatile __u32 word4; |
266 | }; | 259 | }; |
267 | 260 | ||
@@ -269,8 +262,8 @@ struct dbri_mem { | |||
269 | * the CPU and the DBRI | 262 | * the CPU and the DBRI |
270 | */ | 263 | */ |
271 | struct dbri_dma { | 264 | struct dbri_dma { |
272 | volatile s32 cmd[DBRI_NO_CMDS]; /* Place for commands */ | 265 | s32 cmd[DBRI_NO_CMDS]; /* Place for commands */ |
273 | volatile s32 intr[DBRI_NO_INTS * DBRI_INT_BLK]; /* Interrupt field */ | 266 | volatile s32 intr[DBRI_INT_BLK]; /* Interrupt field */ |
274 | struct dbri_mem desc[DBRI_NO_DESCS]; /* Xmit/receive descriptors */ | 267 | struct dbri_mem desc[DBRI_NO_DESCS]; /* Xmit/receive descriptors */ |
275 | }; | 268 | }; |
276 | 269 | ||
@@ -282,58 +275,43 @@ enum in_or_out { PIPEinput, PIPEoutput }; | |||
282 | 275 | ||
283 | struct dbri_pipe { | 276 | struct dbri_pipe { |
284 | u32 sdp; /* SDP command word */ | 277 | u32 sdp; /* SDP command word */ |
285 | enum in_or_out direction; | ||
286 | int nextpipe; /* Next pipe in linked list */ | 278 | int nextpipe; /* Next pipe in linked list */ |
287 | int prevpipe; | ||
288 | int cycle; /* Offset of timeslot (bits) */ | ||
289 | int length; /* Length of timeslot (bits) */ | 279 | int length; /* Length of timeslot (bits) */ |
290 | int first_desc; /* Index of first descriptor */ | 280 | int first_desc; /* Index of first descriptor */ |
291 | int desc; /* Index of active descriptor */ | 281 | int desc; /* Index of active descriptor */ |
292 | volatile __u32 *recv_fixed_ptr; /* Ptr to receive fixed data */ | 282 | volatile __u32 *recv_fixed_ptr; /* Ptr to receive fixed data */ |
293 | }; | 283 | }; |
294 | 284 | ||
295 | struct dbri_desc { | ||
296 | int inuse; /* Boolean flag */ | ||
297 | int next; /* Index of next desc, or -1 */ | ||
298 | unsigned int len; | ||
299 | }; | ||
300 | |||
301 | /* Per stream (playback or record) information */ | 285 | /* Per stream (playback or record) information */ |
302 | struct dbri_streaminfo { | 286 | struct dbri_streaminfo { |
303 | struct snd_pcm_substream *substream; | 287 | struct snd_pcm_substream *substream; |
304 | u32 dvma_buffer; /* Device view of Alsa DMA buffer */ | 288 | u32 dvma_buffer; /* Device view of Alsa DMA buffer */ |
305 | int left; /* # of bytes left in DMA buffer */ | ||
306 | int size; /* Size of DMA buffer */ | 289 | int size; /* Size of DMA buffer */ |
307 | size_t offset; /* offset in user buffer */ | 290 | size_t offset; /* offset in user buffer */ |
308 | int pipe; /* Data pipe used */ | 291 | int pipe; /* Data pipe used */ |
309 | int left_gain; /* mixer elements */ | 292 | int left_gain; /* mixer elements */ |
310 | int right_gain; | 293 | int right_gain; |
311 | int balance; | ||
312 | }; | 294 | }; |
313 | 295 | ||
314 | /* This structure holds the information for both chips (DBRI & CS4215) */ | 296 | /* This structure holds the information for both chips (DBRI & CS4215) */ |
315 | struct snd_dbri { | 297 | struct snd_dbri { |
316 | struct snd_card *card; /* ALSA card */ | 298 | struct snd_card *card; /* ALSA card */ |
317 | struct snd_pcm *pcm; | ||
318 | 299 | ||
319 | int regs_size, irq; /* Needed for unload */ | 300 | int regs_size, irq; /* Needed for unload */ |
320 | struct sbus_dev *sdev; /* SBUS device info */ | 301 | struct sbus_dev *sdev; /* SBUS device info */ |
321 | spinlock_t lock; | 302 | spinlock_t lock; |
322 | 303 | ||
323 | volatile struct dbri_dma *dma; /* Pointer to our DMA block */ | 304 | struct dbri_dma *dma; /* Pointer to our DMA block */ |
324 | u32 dma_dvma; /* DBRI visible DMA address */ | 305 | u32 dma_dvma; /* DBRI visible DMA address */ |
325 | 306 | ||
326 | void __iomem *regs; /* dbri HW regs */ | 307 | void __iomem *regs; /* dbri HW regs */ |
327 | int dbri_version; /* 'e' and up is OK */ | ||
328 | int dbri_irqp; /* intr queue pointer */ | 308 | int dbri_irqp; /* intr queue pointer */ |
329 | int wait_send; /* sequence of command buffers send */ | ||
330 | int wait_ackd; /* sequence of command buffers acknowledged */ | ||
331 | 309 | ||
332 | struct dbri_pipe pipes[DBRI_NO_PIPES]; /* DBRI's 32 data pipes */ | 310 | struct dbri_pipe pipes[DBRI_NO_PIPES]; /* DBRI's 32 data pipes */ |
333 | struct dbri_desc descs[DBRI_NO_DESCS]; | 311 | int next_desc[DBRI_NO_DESCS]; /* Index of next desc, or -1 */ |
312 | spinlock_t cmdlock; /* Protects cmd queue accesses */ | ||
313 | s32 *cmdptr; /* Pointer to the last queued cmd */ | ||
334 | 314 | ||
335 | int chi_in_pipe; | ||
336 | int chi_out_pipe; | ||
337 | int chi_bpf; | 315 | int chi_bpf; |
338 | 316 | ||
339 | struct cs4215 mm; /* mmcodec special info */ | 317 | struct cs4215 mm; /* mmcodec special info */ |
@@ -345,8 +323,6 @@ struct snd_dbri { | |||
345 | 323 | ||
346 | #define DBRI_MAX_VOLUME 63 /* Output volume */ | 324 | #define DBRI_MAX_VOLUME 63 /* Output volume */ |
347 | #define DBRI_MAX_GAIN 15 /* Input gain */ | 325 | #define DBRI_MAX_GAIN 15 /* Input gain */ |
348 | #define DBRI_RIGHT_BALANCE 255 | ||
349 | #define DBRI_MID_BALANCE (DBRI_RIGHT_BALANCE >> 1) | ||
350 | 326 | ||
351 | /* DBRI Reg0 - Status Control Register - defines. (Page 17) */ | 327 | /* DBRI Reg0 - Status Control Register - defines. (Page 17) */ |
352 | #define D_P (1<<15) /* Program command & queue pointer valid */ | 328 | #define D_P (1<<15) /* Program command & queue pointer valid */ |
@@ -569,7 +545,7 @@ struct snd_dbri { | |||
569 | #define DBRI_TD_TBC (1<<0) /* Transmit buffer Complete */ | 545 | #define DBRI_TD_TBC (1<<0) /* Transmit buffer Complete */ |
570 | #define DBRI_TD_STATUS(v) ((v)&0xff) /* Transmit status */ | 546 | #define DBRI_TD_STATUS(v) ((v)&0xff) /* Transmit status */ |
571 | /* Maximum buffer size per TD: almost 8Kb */ | 547 | /* Maximum buffer size per TD: almost 8Kb */ |
572 | #define DBRI_TD_MAXCNT ((1 << 13) - 1) | 548 | #define DBRI_TD_MAXCNT ((1 << 13) - 4) |
573 | 549 | ||
574 | /* Receive descriptor defines */ | 550 | /* Receive descriptor defines */ |
575 | #define DBRI_RD_F (1<<31) /* End of Frame */ | 551 | #define DBRI_RD_F (1<<31) /* End of Frame */ |
@@ -633,93 +609,124 @@ The list is terminated with a WAIT command, which generates a | |||
633 | CPU interrupt to signal completion. | 609 | CPU interrupt to signal completion. |
634 | 610 | ||
635 | Since the DBRI can run in parallel with the CPU, several means of | 611 | Since the DBRI can run in parallel with the CPU, several means of |
636 | synchronization present themselves. The method implemented here is close | 612 | synchronization present themselves. The method implemented here is only |
637 | to the original scheme (Rudolf's), and uses 2 counters (wait_send and | 613 | use of the dbri_cmdwait() to wait for execution of batch of sent commands. |
638 | wait_ackd) to synchronize the command buffer between the CPU and the DBRI. | ||
639 | 614 | ||
640 | A more sophisticated scheme might involve a circular command buffer | 615 | A circular command buffer is used here. A new command is being added |
641 | or an array of command buffers. A routine could fill one with | 616 | while another can be executed. The scheme works by adding two WAIT commands |
642 | commands and link it onto a list. When a interrupt signaled | 617 | after each sent batch of commands. When the next batch is prepared it is |
643 | completion of the current command buffer, look on the list for | 618 | added after the WAIT commands then the WAITs are replaced with single JUMP |
644 | the next one. | 619 | command to the new batch. The the DBRI is forced to reread the last WAIT |
620 | command (replaced by the JUMP by then). If the DBRI is still executing | ||
621 | previous commands the request to reread the WAIT command is ignored. | ||
645 | 622 | ||
646 | Every time a routine wants to write commands to the DBRI, it must | 623 | Every time a routine wants to write commands to the DBRI, it must |
647 | first call dbri_cmdlock() and get an initial pointer into dbri->dma->cmd | 624 | first call dbri_cmdlock() and get pointer to a free space in |
648 | in return. dbri_cmdlock() will block if the previous commands have not | 625 | dbri->dma->cmd buffer. After this, the commands can be written to |
649 | been completed yet. After this the commands can be written to the buffer, | 626 | the buffer, and dbri_cmdsend() is called with the final pointer value |
650 | and dbri_cmdsend() is called with the final pointer value to send them | 627 | to send them to the DBRI. |
651 | to the DBRI. | ||
652 | 628 | ||
653 | */ | 629 | */ |
654 | 630 | ||
655 | static void dbri_process_interrupt_buffer(struct snd_dbri * dbri); | 631 | #define MAXLOOPS 20 |
656 | 632 | /* | |
657 | enum dbri_lock { NoGetLock, GetLock }; | 633 | * Wait for the current command string to execute |
658 | #define MAXLOOPS 10 | 634 | */ |
659 | 635 | static void dbri_cmdwait(struct snd_dbri *dbri) | |
660 | static volatile s32 *dbri_cmdlock(struct snd_dbri * dbri, enum dbri_lock get) | ||
661 | { | 636 | { |
662 | int maxloops = MAXLOOPS; | 637 | int maxloops = MAXLOOPS; |
663 | 638 | unsigned long flags; | |
664 | #ifndef SMP | ||
665 | if ((get == GetLock) && spin_is_locked(&dbri->lock)) { | ||
666 | printk(KERN_ERR "DBRI: cmdlock called while in spinlock."); | ||
667 | } | ||
668 | #endif | ||
669 | 639 | ||
670 | /* Delay if previous commands are still being processed */ | 640 | /* Delay if previous commands are still being processed */ |
671 | while ((--maxloops) > 0 && (dbri->wait_send != dbri->wait_ackd)) { | 641 | spin_lock_irqsave(&dbri->lock, flags); |
642 | while ((--maxloops) > 0 && (sbus_readl(dbri->regs + REG0) & D_P)) { | ||
643 | spin_unlock_irqrestore(&dbri->lock, flags); | ||
672 | msleep_interruptible(1); | 644 | msleep_interruptible(1); |
673 | /* If dbri_cmdlock() got called from inside the | 645 | spin_lock_irqsave(&dbri->lock, flags); |
674 | * interrupt handler, this will do the processing. | ||
675 | */ | ||
676 | dbri_process_interrupt_buffer(dbri); | ||
677 | } | 646 | } |
647 | spin_unlock_irqrestore(&dbri->lock, flags); | ||
648 | |||
678 | if (maxloops == 0) { | 649 | if (maxloops == 0) { |
679 | printk(KERN_ERR "DBRI: Chip never completed command buffer %d\n", | 650 | printk(KERN_ERR "DBRI: Chip never completed command buffer\n"); |
680 | dbri->wait_send); | ||
681 | } else { | 651 | } else { |
682 | dprintk(D_CMD, "Chip completed command buffer (%d)\n", | 652 | dprintk(D_CMD, "Chip completed command buffer (%d)\n", |
683 | MAXLOOPS - maxloops - 1); | 653 | MAXLOOPS - maxloops - 1); |
684 | } | 654 | } |
655 | } | ||
656 | /* | ||
657 | * Lock the command queue and returns pointer to a space for len cmd words | ||
658 | * It locks the cmdlock spinlock. | ||
659 | */ | ||
660 | static s32 *dbri_cmdlock(struct snd_dbri * dbri, int len) | ||
661 | { | ||
662 | /* Space for 2 WAIT cmds (replaced later by 1 JUMP cmd) */ | ||
663 | len += 2; | ||
664 | spin_lock(&dbri->cmdlock); | ||
665 | if (dbri->cmdptr - dbri->dma->cmd + len < DBRI_NO_CMDS - 2) | ||
666 | return dbri->cmdptr + 2; | ||
667 | else if (len < sbus_readl(dbri->regs + REG8) - dbri->dma_dvma) | ||
668 | return dbri->dma->cmd; | ||
669 | else | ||
670 | printk(KERN_ERR "DBRI: no space for commands."); | ||
685 | 671 | ||
686 | /*if (get == GetLock) spin_lock(&dbri->lock); */ | 672 | return 0; |
687 | return &dbri->dma->cmd[0]; | ||
688 | } | 673 | } |
689 | 674 | ||
690 | static void dbri_cmdsend(struct snd_dbri * dbri, volatile s32 * cmd) | 675 | /* |
676 | * Send prepared cmd string. It works by writting a JUMP cmd into | ||
677 | * the last WAIT cmd and force DBRI to reread the cmd. | ||
678 | * The JUMP cmd points to the new cmd string. | ||
679 | * It also releases the cmdlock spinlock. | ||
680 | * | ||
681 | * Lock must not be held before calling this. | ||
682 | */ | ||
683 | static void dbri_cmdsend(struct snd_dbri * dbri, s32 * cmd,int len) | ||
691 | { | 684 | { |
692 | volatile s32 *ptr; | 685 | s32 tmp, addr; |
693 | u32 reg; | 686 | static int wait_id = 0; |
694 | 687 | ||
695 | for (ptr = &dbri->dma->cmd[0]; ptr < cmd; ptr++) { | 688 | wait_id++; |
696 | dprintk(D_CMD, "cmd: %lx:%08x\n", (unsigned long)ptr, *ptr); | 689 | wait_id &= 0xffff; /* restrict it to a 16 bit counter. */ |
697 | } | 690 | *(cmd) = DBRI_CMD(D_WAIT, 1, wait_id); |
691 | *(cmd+1) = DBRI_CMD(D_WAIT, 1, wait_id); | ||
698 | 692 | ||
699 | if ((cmd - &dbri->dma->cmd[0]) >= DBRI_NO_CMDS - 1) { | 693 | /* Replace the last command with JUMP */ |
700 | printk(KERN_ERR "DBRI: Command buffer overflow! (bug in driver)\n"); | 694 | addr = dbri->dma_dvma + (cmd - len - dbri->dma->cmd) * sizeof(s32); |
701 | /* Ignore the last part. */ | 695 | *(dbri->cmdptr+1) = addr; |
702 | cmd = &dbri->dma->cmd[DBRI_NO_CMDS - 3]; | 696 | *(dbri->cmdptr) = DBRI_CMD(D_JUMP, 0, 0); |
703 | } | ||
704 | 697 | ||
705 | dbri->wait_send++; | 698 | #ifdef DBRI_DEBUG |
706 | dbri->wait_send &= 0xffff; /* restrict it to a 16 bit counter. */ | 699 | if (cmd > dbri->cmdptr) { |
707 | *(cmd++) = DBRI_CMD(D_PAUSE, 0, 0); | 700 | s32 *ptr; |
708 | *(cmd++) = DBRI_CMD(D_WAIT, 1, dbri->wait_send); | 701 | |
702 | for (ptr = dbri->cmdptr; ptr < cmd+2; ptr++) | ||
703 | dprintk(D_CMD, "cmd: %lx:%08x\n", (unsigned long)ptr, *ptr); | ||
704 | } else { | ||
705 | s32 *ptr = dbri->cmdptr; | ||
706 | |||
707 | dprintk(D_CMD, "cmd: %lx:%08x\n", (unsigned long)ptr, *ptr); | ||
708 | ptr++; | ||
709 | dprintk(D_CMD, "cmd: %lx:%08x\n", (unsigned long)ptr, *ptr); | ||
710 | for (ptr = dbri->dma->cmd; ptr < cmd+2; ptr++) { | ||
711 | dprintk(D_CMD, "cmd: %lx:%08x\n", (unsigned long)ptr, *ptr); | ||
712 | } | ||
713 | } | ||
714 | #endif | ||
709 | 715 | ||
710 | /* Set command pointer and signal it is valid. */ | 716 | /* Reread the last command */ |
711 | sbus_writel(dbri->dma_dvma, dbri->regs + REG8); | 717 | tmp = sbus_readl(dbri->regs + REG0); |
712 | reg = sbus_readl(dbri->regs + REG0); | 718 | tmp |= D_P; |
713 | reg |= D_P; | 719 | sbus_writel(tmp, dbri->regs + REG0); |
714 | sbus_writel(reg, dbri->regs + REG0); | ||
715 | 720 | ||
716 | /*spin_unlock(&dbri->lock); */ | 721 | dbri->cmdptr = cmd; |
722 | spin_unlock(&dbri->cmdlock); | ||
717 | } | 723 | } |
718 | 724 | ||
719 | /* Lock must be held when calling this */ | 725 | /* Lock must be held when calling this */ |
720 | static void dbri_reset(struct snd_dbri * dbri) | 726 | static void dbri_reset(struct snd_dbri * dbri) |
721 | { | 727 | { |
722 | int i; | 728 | int i; |
729 | u32 tmp; | ||
723 | 730 | ||
724 | dprintk(D_GEN, "reset 0:%x 2:%x 8:%x 9:%x\n", | 731 | dprintk(D_GEN, "reset 0:%x 2:%x 8:%x 9:%x\n", |
725 | sbus_readl(dbri->regs + REG0), | 732 | sbus_readl(dbri->regs + REG0), |
@@ -729,13 +736,20 @@ static void dbri_reset(struct snd_dbri * dbri) | |||
729 | sbus_writel(D_R, dbri->regs + REG0); /* Soft Reset */ | 736 | sbus_writel(D_R, dbri->regs + REG0); /* Soft Reset */ |
730 | for (i = 0; (sbus_readl(dbri->regs + REG0) & D_R) && i < 64; i++) | 737 | for (i = 0; (sbus_readl(dbri->regs + REG0) & D_R) && i < 64; i++) |
731 | udelay(10); | 738 | udelay(10); |
739 | |||
740 | /* A brute approach - DBRI falls back to working burst size by itself | ||
741 | * On SS20 D_S does not work, so do not try so high. */ | ||
742 | tmp = sbus_readl(dbri->regs + REG0); | ||
743 | tmp |= D_G | D_E; | ||
744 | tmp &= ~D_S; | ||
745 | sbus_writel(tmp, dbri->regs + REG0); | ||
732 | } | 746 | } |
733 | 747 | ||
734 | /* Lock must not be held before calling this */ | 748 | /* Lock must not be held before calling this */ |
735 | static void dbri_initialize(struct snd_dbri * dbri) | 749 | static void dbri_initialize(struct snd_dbri * dbri) |
736 | { | 750 | { |
737 | volatile s32 *cmd; | 751 | s32 *cmd; |
738 | u32 dma_addr, tmp; | 752 | u32 dma_addr; |
739 | unsigned long flags; | 753 | unsigned long flags; |
740 | int n; | 754 | int n; |
741 | 755 | ||
@@ -743,42 +757,34 @@ static void dbri_initialize(struct snd_dbri * dbri) | |||
743 | 757 | ||
744 | dbri_reset(dbri); | 758 | dbri_reset(dbri); |
745 | 759 | ||
746 | cmd = dbri_cmdlock(dbri, NoGetLock); | 760 | /* Initialize pipes */ |
747 | dprintk(D_GEN, "init: cmd: %p, int: %p\n", | 761 | for (n = 0; n < DBRI_NO_PIPES; n++) |
748 | &dbri->dma->cmd[0], &dbri->dma->intr[0]); | 762 | dbri->pipes[n].desc = dbri->pipes[n].first_desc = -1; |
749 | 763 | ||
764 | spin_lock_init(&dbri->cmdlock); | ||
750 | /* | 765 | /* |
751 | * Initialize the interrupt ringbuffer. | 766 | * Initialize the interrupt ringbuffer. |
752 | */ | 767 | */ |
753 | for (n = 0; n < DBRI_NO_INTS - 1; n++) { | ||
754 | dma_addr = dbri->dma_dvma; | ||
755 | dma_addr += dbri_dma_off(intr, ((n + 1) & DBRI_INT_BLK)); | ||
756 | dbri->dma->intr[n * DBRI_INT_BLK] = dma_addr; | ||
757 | } | ||
758 | dma_addr = dbri->dma_dvma + dbri_dma_off(intr, 0); | 768 | dma_addr = dbri->dma_dvma + dbri_dma_off(intr, 0); |
759 | dbri->dma->intr[n * DBRI_INT_BLK] = dma_addr; | 769 | dbri->dma->intr[0] = dma_addr; |
760 | dbri->dbri_irqp = 1; | 770 | dbri->dbri_irqp = 1; |
761 | |||
762 | /* Initialize pipes */ | ||
763 | for (n = 0; n < DBRI_NO_PIPES; n++) | ||
764 | dbri->pipes[n].desc = dbri->pipes[n].first_desc = -1; | ||
765 | |||
766 | /* A brute approach - DBRI falls back to working burst size by itself | ||
767 | * On SS20 D_S does not work, so do not try so high. */ | ||
768 | tmp = sbus_readl(dbri->regs + REG0); | ||
769 | tmp |= D_G | D_E; | ||
770 | tmp &= ~D_S; | ||
771 | sbus_writel(tmp, dbri->regs + REG0); | ||
772 | |||
773 | /* | 771 | /* |
774 | * Set up the interrupt queue | 772 | * Set up the interrupt queue |
775 | */ | 773 | */ |
776 | dma_addr = dbri->dma_dvma + dbri_dma_off(intr, 0); | 774 | spin_lock(&dbri->cmdlock); |
775 | cmd = dbri->cmdptr = dbri->dma->cmd; | ||
777 | *(cmd++) = DBRI_CMD(D_IIQ, 0, 0); | 776 | *(cmd++) = DBRI_CMD(D_IIQ, 0, 0); |
778 | *(cmd++) = dma_addr; | 777 | *(cmd++) = dma_addr; |
778 | *(cmd++) = DBRI_CMD(D_PAUSE, 0, 0); | ||
779 | dbri->cmdptr = cmd; | ||
780 | *(cmd++) = DBRI_CMD(D_WAIT, 1, 0); | ||
781 | *(cmd++) = DBRI_CMD(D_WAIT, 1, 0); | ||
782 | dma_addr = dbri->dma_dvma + dbri_dma_off(cmd, 0); | ||
783 | sbus_writel(dma_addr, dbri->regs + REG8); | ||
784 | spin_unlock(&dbri->cmdlock); | ||
779 | 785 | ||
780 | dbri_cmdsend(dbri, cmd); | ||
781 | spin_unlock_irqrestore(&dbri->lock, flags); | 786 | spin_unlock_irqrestore(&dbri->lock, flags); |
787 | dbri_cmdwait(dbri); | ||
782 | } | 788 | } |
783 | 789 | ||
784 | /* | 790 | /* |
@@ -809,9 +815,9 @@ static void reset_pipe(struct snd_dbri * dbri, int pipe) | |||
809 | { | 815 | { |
810 | int sdp; | 816 | int sdp; |
811 | int desc; | 817 | int desc; |
812 | volatile int *cmd; | 818 | s32 *cmd; |
813 | 819 | ||
814 | if (pipe < 0 || pipe > 31) { | 820 | if (pipe < 0 || pipe > DBRI_MAX_PIPE) { |
815 | printk(KERN_ERR "DBRI: reset_pipe called with illegal pipe number\n"); | 821 | printk(KERN_ERR "DBRI: reset_pipe called with illegal pipe number\n"); |
816 | return; | 822 | return; |
817 | } | 823 | } |
@@ -822,25 +828,29 @@ static void reset_pipe(struct snd_dbri * dbri, int pipe) | |||
822 | return; | 828 | return; |
823 | } | 829 | } |
824 | 830 | ||
825 | cmd = dbri_cmdlock(dbri, NoGetLock); | 831 | cmd = dbri_cmdlock(dbri, 3); |
826 | *(cmd++) = DBRI_CMD(D_SDP, 0, sdp | D_SDP_C | D_SDP_P); | 832 | *(cmd++) = DBRI_CMD(D_SDP, 0, sdp | D_SDP_C | D_SDP_P); |
827 | *(cmd++) = 0; | 833 | *(cmd++) = 0; |
828 | dbri_cmdsend(dbri, cmd); | 834 | *(cmd++) = DBRI_CMD(D_PAUSE, 0, 0); |
835 | dbri_cmdsend(dbri, cmd, 3); | ||
829 | 836 | ||
830 | desc = dbri->pipes[pipe].first_desc; | 837 | desc = dbri->pipes[pipe].first_desc; |
831 | while (desc != -1) { | 838 | if ( desc >= 0) |
832 | dbri->descs[desc].inuse = 0; | 839 | do { |
833 | desc = dbri->descs[desc].next; | 840 | dbri->dma->desc[desc].nda = dbri->dma->desc[desc].ba = 0; |
834 | } | 841 | desc = dbri->next_desc[desc]; |
842 | } while (desc != -1 && desc != dbri->pipes[pipe].first_desc); | ||
835 | 843 | ||
836 | dbri->pipes[pipe].desc = -1; | 844 | dbri->pipes[pipe].desc = -1; |
837 | dbri->pipes[pipe].first_desc = -1; | 845 | dbri->pipes[pipe].first_desc = -1; |
838 | } | 846 | } |
839 | 847 | ||
840 | /* FIXME: direction as an argument? */ | 848 | /* |
849 | * Lock must be held before calling this. | ||
850 | */ | ||
841 | static void setup_pipe(struct snd_dbri * dbri, int pipe, int sdp) | 851 | static void setup_pipe(struct snd_dbri * dbri, int pipe, int sdp) |
842 | { | 852 | { |
843 | if (pipe < 0 || pipe > 31) { | 853 | if (pipe < 0 || pipe > DBRI_MAX_PIPE) { |
844 | printk(KERN_ERR "DBRI: setup_pipe called with illegal pipe number\n"); | 854 | printk(KERN_ERR "DBRI: setup_pipe called with illegal pipe number\n"); |
845 | return; | 855 | return; |
846 | } | 856 | } |
@@ -860,119 +870,87 @@ static void setup_pipe(struct snd_dbri * dbri, int pipe, int sdp) | |||
860 | dbri->pipes[pipe].sdp = sdp; | 870 | dbri->pipes[pipe].sdp = sdp; |
861 | dbri->pipes[pipe].desc = -1; | 871 | dbri->pipes[pipe].desc = -1; |
862 | dbri->pipes[pipe].first_desc = -1; | 872 | dbri->pipes[pipe].first_desc = -1; |
863 | if (sdp & D_SDP_TO_SER) | ||
864 | dbri->pipes[pipe].direction = PIPEoutput; | ||
865 | else | ||
866 | dbri->pipes[pipe].direction = PIPEinput; | ||
867 | 873 | ||
868 | reset_pipe(dbri, pipe); | 874 | reset_pipe(dbri, pipe); |
869 | } | 875 | } |
870 | 876 | ||
871 | /* FIXME: direction not needed */ | 877 | /* |
878 | * Lock must be held before calling this. | ||
879 | */ | ||
872 | static void link_time_slot(struct snd_dbri * dbri, int pipe, | 880 | static void link_time_slot(struct snd_dbri * dbri, int pipe, |
873 | enum in_or_out direction, int basepipe, | 881 | int prevpipe, int nextpipe, |
874 | int length, int cycle) | 882 | int length, int cycle) |
875 | { | 883 | { |
876 | volatile s32 *cmd; | 884 | s32 *cmd; |
877 | int val; | 885 | int val; |
878 | int prevpipe; | ||
879 | int nextpipe; | ||
880 | 886 | ||
881 | if (pipe < 0 || pipe > 31 || basepipe < 0 || basepipe > 31) { | 887 | if (pipe < 0 || pipe > DBRI_MAX_PIPE |
888 | || prevpipe < 0 || prevpipe > DBRI_MAX_PIPE | ||
889 | || nextpipe < 0 || nextpipe > DBRI_MAX_PIPE) { | ||
882 | printk(KERN_ERR | 890 | printk(KERN_ERR |
883 | "DBRI: link_time_slot called with illegal pipe number\n"); | 891 | "DBRI: link_time_slot called with illegal pipe number\n"); |
884 | return; | 892 | return; |
885 | } | 893 | } |
886 | 894 | ||
887 | if (dbri->pipes[pipe].sdp == 0 || dbri->pipes[basepipe].sdp == 0) { | 895 | if (dbri->pipes[pipe].sdp == 0 |
896 | || dbri->pipes[prevpipe].sdp == 0 | ||
897 | || dbri->pipes[nextpipe].sdp == 0) { | ||
888 | printk(KERN_ERR "DBRI: link_time_slot called on uninitialized pipe\n"); | 898 | printk(KERN_ERR "DBRI: link_time_slot called on uninitialized pipe\n"); |
889 | return; | 899 | return; |
890 | } | 900 | } |
891 | 901 | ||
892 | /* Deal with CHI special case: | 902 | dbri->pipes[prevpipe].nextpipe = pipe; |
893 | * "If transmission on edges 0 or 1 is desired, then cycle n | ||
894 | * (where n = # of bit times per frame...) must be used." | ||
895 | * - DBRI data sheet, page 11 | ||
896 | */ | ||
897 | if (basepipe == 16 && direction == PIPEoutput && cycle == 0) | ||
898 | cycle = dbri->chi_bpf; | ||
899 | |||
900 | if (basepipe == pipe) { | ||
901 | prevpipe = pipe; | ||
902 | nextpipe = pipe; | ||
903 | } else { | ||
904 | /* We're not initializing a new linked list (basepipe != pipe), | ||
905 | * so run through the linked list and find where this pipe | ||
906 | * should be sloted in, based on its cycle. CHI confuses | ||
907 | * things a bit, since it has a single anchor for both its | ||
908 | * transmit and receive lists. | ||
909 | */ | ||
910 | if (basepipe == 16) { | ||
911 | if (direction == PIPEinput) { | ||
912 | prevpipe = dbri->chi_in_pipe; | ||
913 | } else { | ||
914 | prevpipe = dbri->chi_out_pipe; | ||
915 | } | ||
916 | } else { | ||
917 | prevpipe = basepipe; | ||
918 | } | ||
919 | |||
920 | nextpipe = dbri->pipes[prevpipe].nextpipe; | ||
921 | |||
922 | while (dbri->pipes[nextpipe].cycle < cycle | ||
923 | && dbri->pipes[nextpipe].nextpipe != basepipe) { | ||
924 | prevpipe = nextpipe; | ||
925 | nextpipe = dbri->pipes[nextpipe].nextpipe; | ||
926 | } | ||
927 | } | ||
928 | |||
929 | if (prevpipe == 16) { | ||
930 | if (direction == PIPEinput) { | ||
931 | dbri->chi_in_pipe = pipe; | ||
932 | } else { | ||
933 | dbri->chi_out_pipe = pipe; | ||
934 | } | ||
935 | } else { | ||
936 | dbri->pipes[prevpipe].nextpipe = pipe; | ||
937 | } | ||
938 | |||
939 | dbri->pipes[pipe].nextpipe = nextpipe; | 903 | dbri->pipes[pipe].nextpipe = nextpipe; |
940 | dbri->pipes[pipe].cycle = cycle; | ||
941 | dbri->pipes[pipe].length = length; | 904 | dbri->pipes[pipe].length = length; |
942 | 905 | ||
943 | cmd = dbri_cmdlock(dbri, NoGetLock); | 906 | cmd = dbri_cmdlock(dbri, 4); |
944 | 907 | ||
945 | if (direction == PIPEinput) { | 908 | if (dbri->pipes[pipe].sdp & D_SDP_TO_SER) { |
946 | val = D_DTS_VI | D_DTS_INS | D_DTS_PRVIN(prevpipe) | pipe; | 909 | /* Deal with CHI special case: |
910 | * "If transmission on edges 0 or 1 is desired, then cycle n | ||
911 | * (where n = # of bit times per frame...) must be used." | ||
912 | * - DBRI data sheet, page 11 | ||
913 | */ | ||
914 | if (prevpipe == 16 && cycle == 0) | ||
915 | cycle = dbri->chi_bpf; | ||
916 | |||
917 | val = D_DTS_VO | D_DTS_INS | D_DTS_PRVOUT(prevpipe) | pipe; | ||
947 | *(cmd++) = DBRI_CMD(D_DTS, 0, val); | 918 | *(cmd++) = DBRI_CMD(D_DTS, 0, val); |
919 | *(cmd++) = 0; | ||
948 | *(cmd++) = | 920 | *(cmd++) = |
949 | D_TS_LEN(length) | D_TS_CYCLE(cycle) | D_TS_NEXT(nextpipe); | 921 | D_TS_LEN(length) | D_TS_CYCLE(cycle) | D_TS_NEXT(nextpipe); |
950 | *(cmd++) = 0; | ||
951 | } else { | 922 | } else { |
952 | val = D_DTS_VO | D_DTS_INS | D_DTS_PRVOUT(prevpipe) | pipe; | 923 | val = D_DTS_VI | D_DTS_INS | D_DTS_PRVIN(prevpipe) | pipe; |
953 | *(cmd++) = DBRI_CMD(D_DTS, 0, val); | 924 | *(cmd++) = DBRI_CMD(D_DTS, 0, val); |
954 | *(cmd++) = 0; | ||
955 | *(cmd++) = | 925 | *(cmd++) = |
956 | D_TS_LEN(length) | D_TS_CYCLE(cycle) | D_TS_NEXT(nextpipe); | 926 | D_TS_LEN(length) | D_TS_CYCLE(cycle) | D_TS_NEXT(nextpipe); |
927 | *(cmd++) = 0; | ||
957 | } | 928 | } |
929 | *(cmd++) = DBRI_CMD(D_PAUSE, 0, 0); | ||
958 | 930 | ||
959 | dbri_cmdsend(dbri, cmd); | 931 | dbri_cmdsend(dbri, cmd, 4); |
960 | } | 932 | } |
961 | 933 | ||
934 | #if 0 | ||
935 | /* | ||
936 | * Lock must be held before calling this. | ||
937 | */ | ||
962 | static void unlink_time_slot(struct snd_dbri * dbri, int pipe, | 938 | static void unlink_time_slot(struct snd_dbri * dbri, int pipe, |
963 | enum in_or_out direction, int prevpipe, | 939 | enum in_or_out direction, int prevpipe, |
964 | int nextpipe) | 940 | int nextpipe) |
965 | { | 941 | { |
966 | volatile s32 *cmd; | 942 | s32 *cmd; |
967 | int val; | 943 | int val; |
968 | 944 | ||
969 | if (pipe < 0 || pipe > 31 || prevpipe < 0 || prevpipe > 31) { | 945 | if (pipe < 0 || pipe > DBRI_MAX_PIPE |
946 | || prevpipe < 0 || prevpipe > DBRI_MAX_PIPE | ||
947 | || nextpipe < 0 || nextpipe > DBRI_MAX_PIPE) { | ||
970 | printk(KERN_ERR | 948 | printk(KERN_ERR |
971 | "DBRI: unlink_time_slot called with illegal pipe number\n"); | 949 | "DBRI: unlink_time_slot called with illegal pipe number\n"); |
972 | return; | 950 | return; |
973 | } | 951 | } |
974 | 952 | ||
975 | cmd = dbri_cmdlock(dbri, NoGetLock); | 953 | cmd = dbri_cmdlock(dbri, 4); |
976 | 954 | ||
977 | if (direction == PIPEinput) { | 955 | if (direction == PIPEinput) { |
978 | val = D_DTS_VI | D_DTS_DEL | D_DTS_PRVIN(prevpipe) | pipe; | 956 | val = D_DTS_VI | D_DTS_DEL | D_DTS_PRVIN(prevpipe) | pipe; |
@@ -985,9 +963,11 @@ static void unlink_time_slot(struct snd_dbri * dbri, int pipe, | |||
985 | *(cmd++) = 0; | 963 | *(cmd++) = 0; |
986 | *(cmd++) = D_TS_NEXT(nextpipe); | 964 | *(cmd++) = D_TS_NEXT(nextpipe); |
987 | } | 965 | } |
966 | *(cmd++) = DBRI_CMD(D_PAUSE, 0, 0); | ||
988 | 967 | ||
989 | dbri_cmdsend(dbri, cmd); | 968 | dbri_cmdsend(dbri, cmd, 4); |
990 | } | 969 | } |
970 | #endif | ||
991 | 971 | ||
992 | /* xmit_fixed() / recv_fixed() | 972 | /* xmit_fixed() / recv_fixed() |
993 | * | 973 | * |
@@ -1001,13 +981,16 @@ static void unlink_time_slot(struct snd_dbri * dbri, int pipe, | |||
1001 | * the actual time slot is. The interrupt handler takes care of bit | 981 | * the actual time slot is. The interrupt handler takes care of bit |
1002 | * ordering and alignment. An 8-bit time slot will always end up | 982 | * ordering and alignment. An 8-bit time slot will always end up |
1003 | * in the low-order 8 bits, filled either MSB-first or LSB-first, | 983 | * in the low-order 8 bits, filled either MSB-first or LSB-first, |
1004 | * depending on the settings passed to setup_pipe() | 984 | * depending on the settings passed to setup_pipe(). |
985 | * | ||
986 | * Lock must not be held before calling it. | ||
1005 | */ | 987 | */ |
1006 | static void xmit_fixed(struct snd_dbri * dbri, int pipe, unsigned int data) | 988 | static void xmit_fixed(struct snd_dbri * dbri, int pipe, unsigned int data) |
1007 | { | 989 | { |
1008 | volatile s32 *cmd; | 990 | s32 *cmd; |
991 | unsigned long flags; | ||
1009 | 992 | ||
1010 | if (pipe < 16 || pipe > 31) { | 993 | if (pipe < 16 || pipe > DBRI_MAX_PIPE) { |
1011 | printk(KERN_ERR "DBRI: xmit_fixed: Illegal pipe number\n"); | 994 | printk(KERN_ERR "DBRI: xmit_fixed: Illegal pipe number\n"); |
1012 | return; | 995 | return; |
1013 | } | 996 | } |
@@ -1032,17 +1015,22 @@ static void xmit_fixed(struct snd_dbri * dbri, int pipe, unsigned int data) | |||
1032 | if (dbri->pipes[pipe].sdp & D_SDP_MSB) | 1015 | if (dbri->pipes[pipe].sdp & D_SDP_MSB) |
1033 | data = reverse_bytes(data, dbri->pipes[pipe].length); | 1016 | data = reverse_bytes(data, dbri->pipes[pipe].length); |
1034 | 1017 | ||
1035 | cmd = dbri_cmdlock(dbri, GetLock); | 1018 | cmd = dbri_cmdlock(dbri, 3); |
1036 | 1019 | ||
1037 | *(cmd++) = DBRI_CMD(D_SSP, 0, pipe); | 1020 | *(cmd++) = DBRI_CMD(D_SSP, 0, pipe); |
1038 | *(cmd++) = data; | 1021 | *(cmd++) = data; |
1022 | *(cmd++) = DBRI_CMD(D_PAUSE, 0, 0); | ||
1023 | |||
1024 | spin_lock_irqsave(&dbri->lock, flags); | ||
1025 | dbri_cmdsend(dbri, cmd, 3); | ||
1026 | spin_unlock_irqrestore(&dbri->lock, flags); | ||
1027 | dbri_cmdwait(dbri); | ||
1039 | 1028 | ||
1040 | dbri_cmdsend(dbri, cmd); | ||
1041 | } | 1029 | } |
1042 | 1030 | ||
1043 | static void recv_fixed(struct snd_dbri * dbri, int pipe, volatile __u32 * ptr) | 1031 | static void recv_fixed(struct snd_dbri * dbri, int pipe, volatile __u32 * ptr) |
1044 | { | 1032 | { |
1045 | if (pipe < 16 || pipe > 31) { | 1033 | if (pipe < 16 || pipe > DBRI_MAX_PIPE) { |
1046 | printk(KERN_ERR "DBRI: recv_fixed called with illegal pipe number\n"); | 1034 | printk(KERN_ERR "DBRI: recv_fixed called with illegal pipe number\n"); |
1047 | return; | 1035 | return; |
1048 | } | 1036 | } |
@@ -1071,12 +1059,16 @@ static void recv_fixed(struct snd_dbri * dbri, int pipe, volatile __u32 * ptr) | |||
1071 | * and work by building chains of descriptors which identify the | 1059 | * and work by building chains of descriptors which identify the |
1072 | * data buffers. Buffers too large for a single descriptor will | 1060 | * data buffers. Buffers too large for a single descriptor will |
1073 | * be spread across multiple descriptors. | 1061 | * be spread across multiple descriptors. |
1062 | * | ||
1063 | * All descriptors create a ring buffer. | ||
1064 | * | ||
1065 | * Lock must be held before calling this. | ||
1074 | */ | 1066 | */ |
1075 | static int setup_descs(struct snd_dbri * dbri, int streamno, unsigned int period) | 1067 | static int setup_descs(struct snd_dbri * dbri, int streamno, unsigned int period) |
1076 | { | 1068 | { |
1077 | struct dbri_streaminfo *info = &dbri->stream_info[streamno]; | 1069 | struct dbri_streaminfo *info = &dbri->stream_info[streamno]; |
1078 | __u32 dvma_buffer; | 1070 | __u32 dvma_buffer; |
1079 | int desc = 0; | 1071 | int desc; |
1080 | int len; | 1072 | int len; |
1081 | int first_desc = -1; | 1073 | int first_desc = -1; |
1082 | int last_desc = -1; | 1074 | int last_desc = -1; |
@@ -1119,11 +1111,23 @@ static int setup_descs(struct snd_dbri * dbri, int streamno, unsigned int period | |||
1119 | len &= ~3; | 1111 | len &= ~3; |
1120 | } | 1112 | } |
1121 | 1113 | ||
1114 | /* Free descriptors if pipe has any */ | ||
1115 | desc = dbri->pipes[info->pipe].first_desc; | ||
1116 | if ( desc >= 0) | ||
1117 | do { | ||
1118 | dbri->dma->desc[desc].nda = dbri->dma->desc[desc].ba = 0; | ||
1119 | desc = dbri->next_desc[desc]; | ||
1120 | } while (desc != -1 && desc != dbri->pipes[info->pipe].first_desc); | ||
1121 | |||
1122 | dbri->pipes[info->pipe].desc = -1; | ||
1123 | dbri->pipes[info->pipe].first_desc = -1; | ||
1124 | |||
1125 | desc = 0; | ||
1122 | while (len > 0) { | 1126 | while (len > 0) { |
1123 | int mylen; | 1127 | int mylen; |
1124 | 1128 | ||
1125 | for (; desc < DBRI_NO_DESCS; desc++) { | 1129 | for (; desc < DBRI_NO_DESCS; desc++) { |
1126 | if (!dbri->descs[desc].inuse) | 1130 | if (!dbri->dma->desc[desc].ba) |
1127 | break; | 1131 | break; |
1128 | } | 1132 | } |
1129 | if (desc == DBRI_NO_DESCS) { | 1133 | if (desc == DBRI_NO_DESCS) { |
@@ -1131,37 +1135,33 @@ static int setup_descs(struct snd_dbri * dbri, int streamno, unsigned int period | |||
1131 | return -1; | 1135 | return -1; |
1132 | } | 1136 | } |
1133 | 1137 | ||
1134 | if (len > DBRI_TD_MAXCNT) { | 1138 | if (len > DBRI_TD_MAXCNT) |
1135 | mylen = DBRI_TD_MAXCNT; /* 8KB - 1 */ | 1139 | mylen = DBRI_TD_MAXCNT; /* 8KB - 4 */ |
1136 | } else { | 1140 | else |
1137 | mylen = len; | 1141 | mylen = len; |
1138 | } | 1142 | |
1139 | if (mylen > period) { | 1143 | if (mylen > period) |
1140 | mylen = period; | 1144 | mylen = period; |
1141 | } | ||
1142 | 1145 | ||
1143 | dbri->descs[desc].inuse = 1; | 1146 | dbri->next_desc[desc] = -1; |
1144 | dbri->descs[desc].next = -1; | ||
1145 | dbri->dma->desc[desc].ba = dvma_buffer; | 1147 | dbri->dma->desc[desc].ba = dvma_buffer; |
1146 | dbri->dma->desc[desc].nda = 0; | 1148 | dbri->dma->desc[desc].nda = 0; |
1147 | 1149 | ||
1148 | if (streamno == DBRI_PLAY) { | 1150 | if (streamno == DBRI_PLAY) { |
1149 | dbri->descs[desc].len = mylen; | ||
1150 | dbri->dma->desc[desc].word1 = DBRI_TD_CNT(mylen); | 1151 | dbri->dma->desc[desc].word1 = DBRI_TD_CNT(mylen); |
1151 | dbri->dma->desc[desc].word4 = 0; | 1152 | dbri->dma->desc[desc].word4 = 0; |
1152 | if (first_desc != -1) | 1153 | dbri->dma->desc[desc].word1 |= |
1153 | dbri->dma->desc[desc].word1 |= DBRI_TD_M; | 1154 | DBRI_TD_F | DBRI_TD_B; |
1154 | } else { | 1155 | } else { |
1155 | dbri->descs[desc].len = 0; | ||
1156 | dbri->dma->desc[desc].word1 = 0; | 1156 | dbri->dma->desc[desc].word1 = 0; |
1157 | dbri->dma->desc[desc].word4 = | 1157 | dbri->dma->desc[desc].word4 = |
1158 | DBRI_RD_B | DBRI_RD_BCNT(mylen); | 1158 | DBRI_RD_B | DBRI_RD_BCNT(mylen); |
1159 | } | 1159 | } |
1160 | 1160 | ||
1161 | if (first_desc == -1) { | 1161 | if (first_desc == -1) |
1162 | first_desc = desc; | 1162 | first_desc = desc; |
1163 | } else { | 1163 | else { |
1164 | dbri->descs[last_desc].next = desc; | 1164 | dbri->next_desc[last_desc] = desc; |
1165 | dbri->dma->desc[last_desc].nda = | 1165 | dbri->dma->desc[last_desc].nda = |
1166 | dbri->dma_dvma + dbri_dma_off(desc, desc); | 1166 | dbri->dma_dvma + dbri_dma_off(desc, desc); |
1167 | } | 1167 | } |
@@ -1176,21 +1176,24 @@ static int setup_descs(struct snd_dbri * dbri, int streamno, unsigned int period | |||
1176 | return -1; | 1176 | return -1; |
1177 | } | 1177 | } |
1178 | 1178 | ||
1179 | dbri->dma->desc[last_desc].word1 &= ~DBRI_TD_M; | 1179 | dbri->dma->desc[last_desc].nda = |
1180 | if (streamno == DBRI_PLAY) { | 1180 | dbri->dma_dvma + dbri_dma_off(desc, first_desc); |
1181 | dbri->dma->desc[last_desc].word1 |= | 1181 | dbri->next_desc[last_desc] = first_desc; |
1182 | DBRI_TD_I | DBRI_TD_F | DBRI_TD_B; | ||
1183 | } | ||
1184 | dbri->pipes[info->pipe].first_desc = first_desc; | 1182 | dbri->pipes[info->pipe].first_desc = first_desc; |
1185 | dbri->pipes[info->pipe].desc = first_desc; | 1183 | dbri->pipes[info->pipe].desc = first_desc; |
1186 | 1184 | ||
1187 | for (desc = first_desc; desc != -1; desc = dbri->descs[desc].next) { | 1185 | #ifdef DBRI_DEBUG |
1186 | for (desc = first_desc; desc != -1; ) { | ||
1188 | dprintk(D_DESC, "DESC %d: %08x %08x %08x %08x\n", | 1187 | dprintk(D_DESC, "DESC %d: %08x %08x %08x %08x\n", |
1189 | desc, | 1188 | desc, |
1190 | dbri->dma->desc[desc].word1, | 1189 | dbri->dma->desc[desc].word1, |
1191 | dbri->dma->desc[desc].ba, | 1190 | dbri->dma->desc[desc].ba, |
1192 | dbri->dma->desc[desc].nda, dbri->dma->desc[desc].word4); | 1191 | dbri->dma->desc[desc].nda, dbri->dma->desc[desc].word4); |
1192 | desc = dbri->next_desc[desc]; | ||
1193 | if ( desc == first_desc ) | ||
1194 | break; | ||
1193 | } | 1195 | } |
1196 | #endif | ||
1194 | return 0; | 1197 | return 0; |
1195 | } | 1198 | } |
1196 | 1199 | ||
@@ -1207,56 +1210,30 @@ multiplexed serial interface which the DBRI can operate in either master | |||
1207 | 1210 | ||
1208 | enum master_or_slave { CHImaster, CHIslave }; | 1211 | enum master_or_slave { CHImaster, CHIslave }; |
1209 | 1212 | ||
1213 | /* | ||
1214 | * Lock must not be held before calling it. | ||
1215 | */ | ||
1210 | static void reset_chi(struct snd_dbri * dbri, enum master_or_slave master_or_slave, | 1216 | static void reset_chi(struct snd_dbri * dbri, enum master_or_slave master_or_slave, |
1211 | int bits_per_frame) | 1217 | int bits_per_frame) |
1212 | { | 1218 | { |
1213 | volatile s32 *cmd; | 1219 | s32 *cmd; |
1214 | int val; | 1220 | int val; |
1215 | static int chi_initialized = 0; /* FIXME: mutex? */ | ||
1216 | |||
1217 | if (!chi_initialized) { | ||
1218 | |||
1219 | cmd = dbri_cmdlock(dbri, GetLock); | ||
1220 | |||
1221 | /* Set CHI Anchor: Pipe 16 */ | ||
1222 | |||
1223 | val = D_DTS_VI | D_DTS_INS | D_DTS_PRVIN(16) | D_PIPE(16); | ||
1224 | *(cmd++) = DBRI_CMD(D_DTS, 0, val); | ||
1225 | *(cmd++) = D_TS_ANCHOR | D_TS_NEXT(16); | ||
1226 | *(cmd++) = 0; | ||
1227 | |||
1228 | val = D_DTS_VO | D_DTS_INS | D_DTS_PRVOUT(16) | D_PIPE(16); | ||
1229 | *(cmd++) = DBRI_CMD(D_DTS, 0, val); | ||
1230 | *(cmd++) = 0; | ||
1231 | *(cmd++) = D_TS_ANCHOR | D_TS_NEXT(16); | ||
1232 | 1221 | ||
1233 | dbri->pipes[16].sdp = 1; | 1222 | /* Set CHI Anchor: Pipe 16 */ |
1234 | dbri->pipes[16].nextpipe = 16; | ||
1235 | dbri->chi_in_pipe = 16; | ||
1236 | dbri->chi_out_pipe = 16; | ||
1237 | |||
1238 | #if 0 | ||
1239 | chi_initialized++; | ||
1240 | #endif | ||
1241 | } else { | ||
1242 | int pipe; | ||
1243 | 1223 | ||
1244 | for (pipe = dbri->chi_in_pipe; | 1224 | cmd = dbri_cmdlock(dbri, 4); |
1245 | pipe != 16; pipe = dbri->pipes[pipe].nextpipe) { | 1225 | val = D_DTS_VO | D_DTS_VI | D_DTS_INS |
1246 | unlink_time_slot(dbri, pipe, PIPEinput, | 1226 | | D_DTS_PRVIN(16) | D_PIPE(16) | D_DTS_PRVOUT(16); |
1247 | 16, dbri->pipes[pipe].nextpipe); | 1227 | *(cmd++) = DBRI_CMD(D_DTS, 0, val); |
1248 | } | 1228 | *(cmd++) = D_TS_ANCHOR | D_TS_NEXT(16); |
1249 | for (pipe = dbri->chi_out_pipe; | 1229 | *(cmd++) = D_TS_ANCHOR | D_TS_NEXT(16); |
1250 | pipe != 16; pipe = dbri->pipes[pipe].nextpipe) { | 1230 | *(cmd++) = DBRI_CMD(D_PAUSE, 0, 0); |
1251 | unlink_time_slot(dbri, pipe, PIPEoutput, | 1231 | dbri_cmdsend(dbri, cmd, 4); |
1252 | 16, dbri->pipes[pipe].nextpipe); | ||
1253 | } | ||
1254 | 1232 | ||
1255 | dbri->chi_in_pipe = 16; | 1233 | dbri->pipes[16].sdp = 1; |
1256 | dbri->chi_out_pipe = 16; | 1234 | dbri->pipes[16].nextpipe = 16; |
1257 | 1235 | ||
1258 | cmd = dbri_cmdlock(dbri, GetLock); | 1236 | cmd = dbri_cmdlock(dbri, 4); |
1259 | } | ||
1260 | 1237 | ||
1261 | if (master_or_slave == CHIslave) { | 1238 | if (master_or_slave == CHIslave) { |
1262 | /* Setup DBRI for CHI Slave - receive clock, frame sync (FS) | 1239 | /* Setup DBRI for CHI Slave - receive clock, frame sync (FS) |
@@ -1295,8 +1272,9 @@ static void reset_chi(struct snd_dbri * dbri, enum master_or_slave master_or_sla | |||
1295 | 1272 | ||
1296 | *(cmd++) = DBRI_CMD(D_PAUSE, 0, 0); | 1273 | *(cmd++) = DBRI_CMD(D_PAUSE, 0, 0); |
1297 | *(cmd++) = DBRI_CMD(D_CDM, 0, D_CDM_XCE | D_CDM_XEN | D_CDM_REN); | 1274 | *(cmd++) = DBRI_CMD(D_CDM, 0, D_CDM_XCE | D_CDM_XEN | D_CDM_REN); |
1275 | *(cmd++) = DBRI_CMD(D_PAUSE, 0, 0); | ||
1298 | 1276 | ||
1299 | dbri_cmdsend(dbri, cmd); | 1277 | dbri_cmdsend(dbri, cmd, 4); |
1300 | } | 1278 | } |
1301 | 1279 | ||
1302 | /* | 1280 | /* |
@@ -1307,9 +1285,14 @@ static void reset_chi(struct snd_dbri * dbri, enum master_or_slave master_or_sla | |||
1307 | In the standard SPARC audio configuration, the CS4215 codec is attached | 1285 | In the standard SPARC audio configuration, the CS4215 codec is attached |
1308 | to the DBRI via the CHI interface and few of the DBRI's PIO pins. | 1286 | to the DBRI via the CHI interface and few of the DBRI's PIO pins. |
1309 | 1287 | ||
1288 | * Lock must not be held before calling it. | ||
1289 | |||
1310 | */ | 1290 | */ |
1311 | static void cs4215_setup_pipes(struct snd_dbri * dbri) | 1291 | static void cs4215_setup_pipes(struct snd_dbri * dbri) |
1312 | { | 1292 | { |
1293 | unsigned long flags; | ||
1294 | |||
1295 | spin_lock_irqsave(&dbri->lock, flags); | ||
1313 | /* | 1296 | /* |
1314 | * Data mode: | 1297 | * Data mode: |
1315 | * Pipe 4: Send timeslots 1-4 (audio data) | 1298 | * Pipe 4: Send timeslots 1-4 (audio data) |
@@ -1333,6 +1316,9 @@ static void cs4215_setup_pipes(struct snd_dbri * dbri) | |||
1333 | setup_pipe(dbri, 17, D_SDP_FIXED | D_SDP_TO_SER | D_SDP_MSB); | 1316 | setup_pipe(dbri, 17, D_SDP_FIXED | D_SDP_TO_SER | D_SDP_MSB); |
1334 | setup_pipe(dbri, 18, D_SDP_FIXED | D_SDP_FROM_SER | D_SDP_MSB); | 1317 | setup_pipe(dbri, 18, D_SDP_FIXED | D_SDP_FROM_SER | D_SDP_MSB); |
1335 | setup_pipe(dbri, 19, D_SDP_FIXED | D_SDP_FROM_SER | D_SDP_MSB); | 1318 | setup_pipe(dbri, 19, D_SDP_FIXED | D_SDP_FROM_SER | D_SDP_MSB); |
1319 | spin_unlock_irqrestore(&dbri->lock, flags); | ||
1320 | |||
1321 | dbri_cmdwait(dbri); | ||
1336 | } | 1322 | } |
1337 | 1323 | ||
1338 | static int cs4215_init_data(struct cs4215 *mm) | 1324 | static int cs4215_init_data(struct cs4215 *mm) |
@@ -1364,7 +1350,7 @@ static int cs4215_init_data(struct cs4215 *mm) | |||
1364 | mm->status = 0; | 1350 | mm->status = 0; |
1365 | mm->version = 0xff; | 1351 | mm->version = 0xff; |
1366 | mm->precision = 8; /* For ULAW */ | 1352 | mm->precision = 8; /* For ULAW */ |
1367 | mm->channels = 2; | 1353 | mm->channels = 1; |
1368 | 1354 | ||
1369 | return 0; | 1355 | return 0; |
1370 | } | 1356 | } |
@@ -1379,16 +1365,8 @@ static void cs4215_setdata(struct snd_dbri * dbri, int muted) | |||
1379 | } else { | 1365 | } else { |
1380 | /* Start by setting the playback attenuation. */ | 1366 | /* Start by setting the playback attenuation. */ |
1381 | struct dbri_streaminfo *info = &dbri->stream_info[DBRI_PLAY]; | 1367 | struct dbri_streaminfo *info = &dbri->stream_info[DBRI_PLAY]; |
1382 | int left_gain = info->left_gain % 64; | 1368 | int left_gain = info->left_gain & 0x3f; |
1383 | int right_gain = info->right_gain % 64; | 1369 | int right_gain = info->right_gain & 0x3f; |
1384 | |||
1385 | if (info->balance < DBRI_MID_BALANCE) { | ||
1386 | right_gain *= info->balance; | ||
1387 | right_gain /= DBRI_MID_BALANCE; | ||
1388 | } else { | ||
1389 | left_gain *= DBRI_RIGHT_BALANCE - info->balance; | ||
1390 | left_gain /= DBRI_MID_BALANCE; | ||
1391 | } | ||
1392 | 1370 | ||
1393 | dbri->mm.data[0] &= ~0x3f; /* Reset the volume bits */ | 1371 | dbri->mm.data[0] &= ~0x3f; /* Reset the volume bits */ |
1394 | dbri->mm.data[1] &= ~0x3f; | 1372 | dbri->mm.data[1] &= ~0x3f; |
@@ -1397,8 +1375,8 @@ static void cs4215_setdata(struct snd_dbri * dbri, int muted) | |||
1397 | 1375 | ||
1398 | /* Now set the recording gain. */ | 1376 | /* Now set the recording gain. */ |
1399 | info = &dbri->stream_info[DBRI_REC]; | 1377 | info = &dbri->stream_info[DBRI_REC]; |
1400 | left_gain = info->left_gain % 16; | 1378 | left_gain = info->left_gain & 0xf; |
1401 | right_gain = info->right_gain % 16; | 1379 | right_gain = info->right_gain & 0xf; |
1402 | dbri->mm.data[2] |= CS4215_LG(left_gain); | 1380 | dbri->mm.data[2] |= CS4215_LG(left_gain); |
1403 | dbri->mm.data[3] |= CS4215_RG(right_gain); | 1381 | dbri->mm.data[3] |= CS4215_RG(right_gain); |
1404 | } | 1382 | } |
@@ -1413,6 +1391,7 @@ static void cs4215_open(struct snd_dbri * dbri) | |||
1413 | { | 1391 | { |
1414 | int data_width; | 1392 | int data_width; |
1415 | u32 tmp; | 1393 | u32 tmp; |
1394 | unsigned long flags; | ||
1416 | 1395 | ||
1417 | dprintk(D_MM, "cs4215_open: %d channels, %d bits\n", | 1396 | dprintk(D_MM, "cs4215_open: %d channels, %d bits\n", |
1418 | dbri->mm.channels, dbri->mm.precision); | 1397 | dbri->mm.channels, dbri->mm.precision); |
@@ -1437,6 +1416,7 @@ static void cs4215_open(struct snd_dbri * dbri) | |||
1437 | * bits. The CS4215, it seems, observes TSIN (the delayed signal) | 1416 | * bits. The CS4215, it seems, observes TSIN (the delayed signal) |
1438 | * even if it's the CHI master. Don't ask me... | 1417 | * even if it's the CHI master. Don't ask me... |
1439 | */ | 1418 | */ |
1419 | spin_lock_irqsave(&dbri->lock, flags); | ||
1440 | tmp = sbus_readl(dbri->regs + REG0); | 1420 | tmp = sbus_readl(dbri->regs + REG0); |
1441 | tmp &= ~(D_C); /* Disable CHI */ | 1421 | tmp &= ~(D_C); /* Disable CHI */ |
1442 | sbus_writel(tmp, dbri->regs + REG0); | 1422 | sbus_writel(tmp, dbri->regs + REG0); |
@@ -1455,15 +1435,16 @@ static void cs4215_open(struct snd_dbri * dbri) | |||
1455 | */ | 1435 | */ |
1456 | data_width = dbri->mm.channels * dbri->mm.precision; | 1436 | data_width = dbri->mm.channels * dbri->mm.precision; |
1457 | 1437 | ||
1458 | link_time_slot(dbri, 20, PIPEoutput, 16, 32, dbri->mm.offset + 32); | 1438 | link_time_slot(dbri, 4, 16, 16, data_width, dbri->mm.offset); |
1459 | link_time_slot(dbri, 4, PIPEoutput, 16, data_width, dbri->mm.offset); | 1439 | link_time_slot(dbri, 20, 4, 16, 32, dbri->mm.offset + 32); |
1460 | link_time_slot(dbri, 6, PIPEinput, 16, data_width, dbri->mm.offset); | 1440 | link_time_slot(dbri, 6, 16, 16, data_width, dbri->mm.offset); |
1461 | link_time_slot(dbri, 21, PIPEinput, 16, 16, dbri->mm.offset + 40); | 1441 | link_time_slot(dbri, 21, 6, 16, 16, dbri->mm.offset + 40); |
1462 | 1442 | ||
1463 | /* FIXME: enable CHI after _setdata? */ | 1443 | /* FIXME: enable CHI after _setdata? */ |
1464 | tmp = sbus_readl(dbri->regs + REG0); | 1444 | tmp = sbus_readl(dbri->regs + REG0); |
1465 | tmp |= D_C; /* Enable CHI */ | 1445 | tmp |= D_C; /* Enable CHI */ |
1466 | sbus_writel(tmp, dbri->regs + REG0); | 1446 | sbus_writel(tmp, dbri->regs + REG0); |
1447 | spin_unlock_irqrestore(&dbri->lock, flags); | ||
1467 | 1448 | ||
1468 | cs4215_setdata(dbri, 0); | 1449 | cs4215_setdata(dbri, 0); |
1469 | } | 1450 | } |
@@ -1475,6 +1456,7 @@ static int cs4215_setctrl(struct snd_dbri * dbri) | |||
1475 | { | 1456 | { |
1476 | int i, val; | 1457 | int i, val; |
1477 | u32 tmp; | 1458 | u32 tmp; |
1459 | unsigned long flags; | ||
1478 | 1460 | ||
1479 | /* FIXME - let the CPU do something useful during these delays */ | 1461 | /* FIXME - let the CPU do something useful during these delays */ |
1480 | 1462 | ||
@@ -1511,6 +1493,7 @@ static int cs4215_setctrl(struct snd_dbri * dbri) | |||
1511 | * done in hardware by a TI 248 that delays the DBRI->4215 | 1493 | * done in hardware by a TI 248 that delays the DBRI->4215 |
1512 | * frame sync signal by eight clock cycles. Anybody know why? | 1494 | * frame sync signal by eight clock cycles. Anybody know why? |
1513 | */ | 1495 | */ |
1496 | spin_lock_irqsave(&dbri->lock, flags); | ||
1514 | tmp = sbus_readl(dbri->regs + REG0); | 1497 | tmp = sbus_readl(dbri->regs + REG0); |
1515 | tmp &= ~D_C; /* Disable CHI */ | 1498 | tmp &= ~D_C; /* Disable CHI */ |
1516 | sbus_writel(tmp, dbri->regs + REG0); | 1499 | sbus_writel(tmp, dbri->regs + REG0); |
@@ -1524,17 +1507,20 @@ static int cs4215_setctrl(struct snd_dbri * dbri) | |||
1524 | * Pipe 19: Receive timeslot 7 (version). | 1507 | * Pipe 19: Receive timeslot 7 (version). |
1525 | */ | 1508 | */ |
1526 | 1509 | ||
1527 | link_time_slot(dbri, 17, PIPEoutput, 16, 32, dbri->mm.offset); | 1510 | link_time_slot(dbri, 17, 16, 16, 32, dbri->mm.offset); |
1528 | link_time_slot(dbri, 18, PIPEinput, 16, 8, dbri->mm.offset); | 1511 | link_time_slot(dbri, 18, 16, 16, 8, dbri->mm.offset); |
1529 | link_time_slot(dbri, 19, PIPEinput, 16, 8, dbri->mm.offset + 48); | 1512 | link_time_slot(dbri, 19, 18, 16, 8, dbri->mm.offset + 48); |
1513 | spin_unlock_irqrestore(&dbri->lock, flags); | ||
1530 | 1514 | ||
1531 | /* Wait for the chip to echo back CLB (Control Latch Bit) as zero */ | 1515 | /* Wait for the chip to echo back CLB (Control Latch Bit) as zero */ |
1532 | dbri->mm.ctrl[0] &= ~CS4215_CLB; | 1516 | dbri->mm.ctrl[0] &= ~CS4215_CLB; |
1533 | xmit_fixed(dbri, 17, *(int *)dbri->mm.ctrl); | 1517 | xmit_fixed(dbri, 17, *(int *)dbri->mm.ctrl); |
1534 | 1518 | ||
1519 | spin_lock_irqsave(&dbri->lock, flags); | ||
1535 | tmp = sbus_readl(dbri->regs + REG0); | 1520 | tmp = sbus_readl(dbri->regs + REG0); |
1536 | tmp |= D_C; /* Enable CHI */ | 1521 | tmp |= D_C; /* Enable CHI */ |
1537 | sbus_writel(tmp, dbri->regs + REG0); | 1522 | sbus_writel(tmp, dbri->regs + REG0); |
1523 | spin_unlock_irqrestore(&dbri->lock, flags); | ||
1538 | 1524 | ||
1539 | for (i = 10; ((dbri->mm.status & 0xe4) != 0x20); --i) { | 1525 | for (i = 10; ((dbri->mm.status & 0xe4) != 0x20); --i) { |
1540 | msleep_interruptible(1); | 1526 | msleep_interruptible(1); |
@@ -1614,8 +1600,7 @@ static int cs4215_prepare(struct snd_dbri * dbri, unsigned int rate, | |||
1614 | CS4215_BSEL_128 | CS4215_FREQ[freq_idx].xtal; | 1600 | CS4215_BSEL_128 | CS4215_FREQ[freq_idx].xtal; |
1615 | 1601 | ||
1616 | dbri->mm.channels = channels; | 1602 | dbri->mm.channels = channels; |
1617 | /* Stereo bit: 8 bit stereo not working yet. */ | 1603 | if (channels == 2) |
1618 | if ((channels > 1) && (dbri->mm.precision == 16)) | ||
1619 | dbri->mm.ctrl[1] |= CS4215_DFR_STEREO; | 1604 | dbri->mm.ctrl[1] |= CS4215_DFR_STEREO; |
1620 | 1605 | ||
1621 | ret = cs4215_setctrl(dbri); | 1606 | ret = cs4215_setctrl(dbri); |
@@ -1655,7 +1640,6 @@ static int cs4215_init(struct snd_dbri * dbri) | |||
1655 | } | 1640 | } |
1656 | 1641 | ||
1657 | cs4215_setup_pipes(dbri); | 1642 | cs4215_setup_pipes(dbri); |
1658 | |||
1659 | cs4215_init_data(&dbri->mm); | 1643 | cs4215_init_data(&dbri->mm); |
1660 | 1644 | ||
1661 | /* Enable capture of the status & version timeslots. */ | 1645 | /* Enable capture of the status & version timeslots. */ |
@@ -1684,88 +1668,71 @@ buffer and calls dbri_process_one_interrupt() for each interrupt word. | |||
1684 | Complicated interrupts are handled by dedicated functions (which | 1668 | Complicated interrupts are handled by dedicated functions (which |
1685 | appear first in this file). Any pending interrupts can be serviced by | 1669 | appear first in this file). Any pending interrupts can be serviced by |
1686 | calling dbri_process_interrupt_buffer(), which works even if the CPU's | 1670 | calling dbri_process_interrupt_buffer(), which works even if the CPU's |
1687 | interrupts are disabled. This function is used by dbri_cmdlock() | 1671 | interrupts are disabled. |
1688 | to make sure we're synced up with the chip before each command sequence, | ||
1689 | even if we're running cli'ed. | ||
1690 | 1672 | ||
1691 | */ | 1673 | */ |
1692 | 1674 | ||
1693 | /* xmit_descs() | 1675 | /* xmit_descs() |
1694 | * | 1676 | * |
1695 | * Transmit the current TD's for recording/playing, if needed. | 1677 | * Starts transmiting the current TD's for recording/playing. |
1696 | * For playback, ALSA has filled the DMA memory with new data (we hope). | 1678 | * For playback, ALSA has filled the DMA memory with new data (we hope). |
1697 | */ | 1679 | */ |
1698 | static void xmit_descs(unsigned long data) | 1680 | static void xmit_descs(struct snd_dbri *dbri) |
1699 | { | 1681 | { |
1700 | struct snd_dbri *dbri = (struct snd_dbri *) data; | ||
1701 | struct dbri_streaminfo *info; | 1682 | struct dbri_streaminfo *info; |
1702 | volatile s32 *cmd; | 1683 | s32 *cmd; |
1703 | unsigned long flags; | 1684 | unsigned long flags; |
1704 | int first_td; | 1685 | int first_td; |
1705 | 1686 | ||
1706 | if (dbri == NULL) | 1687 | if (dbri == NULL) |
1707 | return; /* Disabled */ | 1688 | return; /* Disabled */ |
1708 | 1689 | ||
1709 | /* First check the recording stream for buffer overflow */ | ||
1710 | info = &dbri->stream_info[DBRI_REC]; | 1690 | info = &dbri->stream_info[DBRI_REC]; |
1711 | spin_lock_irqsave(&dbri->lock, flags); | 1691 | spin_lock_irqsave(&dbri->lock, flags); |
1712 | 1692 | ||
1713 | if ((info->left >= info->size) && (info->pipe >= 0)) { | 1693 | if (info->pipe >= 0) { |
1714 | first_td = dbri->pipes[info->pipe].first_desc; | 1694 | first_td = dbri->pipes[info->pipe].first_desc; |
1715 | 1695 | ||
1716 | dprintk(D_DESC, "xmit_descs rec @ TD %d\n", first_td); | 1696 | dprintk(D_DESC, "xmit_descs rec @ TD %d\n", first_td); |
1717 | 1697 | ||
1718 | /* Stream could be closed by the time we run. */ | 1698 | /* Stream could be closed by the time we run. */ |
1719 | if (first_td < 0) { | 1699 | if (first_td >= 0) { |
1720 | goto play; | 1700 | cmd = dbri_cmdlock(dbri, 2); |
1721 | } | 1701 | *(cmd++) = DBRI_CMD(D_SDP, 0, |
1722 | 1702 | dbri->pipes[info->pipe].sdp | |
1723 | cmd = dbri_cmdlock(dbri, NoGetLock); | 1703 | | D_SDP_P | D_SDP_EVERY | D_SDP_C); |
1724 | *(cmd++) = DBRI_CMD(D_SDP, 0, | 1704 | *(cmd++) = dbri->dma_dvma + dbri_dma_off(desc, first_td); |
1725 | dbri->pipes[info->pipe].sdp | 1705 | dbri_cmdsend(dbri, cmd, 2); |
1726 | | D_SDP_P | D_SDP_EVERY | D_SDP_C); | ||
1727 | *(cmd++) = dbri->dma_dvma + dbri_dma_off(desc, first_td); | ||
1728 | dbri_cmdsend(dbri, cmd); | ||
1729 | 1706 | ||
1730 | /* Reset our admin of the pipe & bytes read. */ | 1707 | /* Reset our admin of the pipe. */ |
1731 | dbri->pipes[info->pipe].desc = first_td; | 1708 | dbri->pipes[info->pipe].desc = first_td; |
1732 | info->left = 0; | 1709 | } |
1733 | } | 1710 | } |
1734 | 1711 | ||
1735 | play: | ||
1736 | spin_unlock_irqrestore(&dbri->lock, flags); | ||
1737 | |||
1738 | /* Now check the playback stream for buffer underflow */ | ||
1739 | info = &dbri->stream_info[DBRI_PLAY]; | 1712 | info = &dbri->stream_info[DBRI_PLAY]; |
1740 | spin_lock_irqsave(&dbri->lock, flags); | ||
1741 | 1713 | ||
1742 | if ((info->left <= 0) && (info->pipe >= 0)) { | 1714 | if (info->pipe >= 0) { |
1743 | first_td = dbri->pipes[info->pipe].first_desc; | 1715 | first_td = dbri->pipes[info->pipe].first_desc; |
1744 | 1716 | ||
1745 | dprintk(D_DESC, "xmit_descs play @ TD %d\n", first_td); | 1717 | dprintk(D_DESC, "xmit_descs play @ TD %d\n", first_td); |
1746 | 1718 | ||
1747 | /* Stream could be closed by the time we run. */ | 1719 | /* Stream could be closed by the time we run. */ |
1748 | if (first_td < 0) { | 1720 | if (first_td >= 0) { |
1749 | spin_unlock_irqrestore(&dbri->lock, flags); | 1721 | cmd = dbri_cmdlock(dbri, 2); |
1750 | return; | 1722 | *(cmd++) = DBRI_CMD(D_SDP, 0, |
1751 | } | 1723 | dbri->pipes[info->pipe].sdp |
1752 | 1724 | | D_SDP_P | D_SDP_EVERY | D_SDP_C); | |
1753 | cmd = dbri_cmdlock(dbri, NoGetLock); | 1725 | *(cmd++) = dbri->dma_dvma + dbri_dma_off(desc, first_td); |
1754 | *(cmd++) = DBRI_CMD(D_SDP, 0, | 1726 | dbri_cmdsend(dbri, cmd, 2); |
1755 | dbri->pipes[info->pipe].sdp | ||
1756 | | D_SDP_P | D_SDP_EVERY | D_SDP_C); | ||
1757 | *(cmd++) = dbri->dma_dvma + dbri_dma_off(desc, first_td); | ||
1758 | dbri_cmdsend(dbri, cmd); | ||
1759 | 1727 | ||
1760 | /* Reset our admin of the pipe & bytes written. */ | 1728 | /* Reset our admin of the pipe. */ |
1761 | dbri->pipes[info->pipe].desc = first_td; | 1729 | dbri->pipes[info->pipe].desc = first_td; |
1762 | info->left = info->size; | 1730 | } |
1763 | } | 1731 | } |
1732 | |||
1764 | spin_unlock_irqrestore(&dbri->lock, flags); | 1733 | spin_unlock_irqrestore(&dbri->lock, flags); |
1765 | } | 1734 | } |
1766 | 1735 | ||
1767 | static DECLARE_TASKLET(xmit_descs_task, xmit_descs, 0); | ||
1768 | |||
1769 | /* transmission_complete_intr() | 1736 | /* transmission_complete_intr() |
1770 | * | 1737 | * |
1771 | * Called by main interrupt handler when DBRI signals transmission complete | 1738 | * Called by main interrupt handler when DBRI signals transmission complete |
@@ -1775,9 +1742,9 @@ static DECLARE_TASKLET(xmit_descs_task, xmit_descs, 0); | |||
1775 | * them as available. Stops when the first descriptor is found without | 1742 | * them as available. Stops when the first descriptor is found without |
1776 | * TBC (Transmit Buffer Complete) set, or we've run through them all. | 1743 | * TBC (Transmit Buffer Complete) set, or we've run through them all. |
1777 | * | 1744 | * |
1778 | * The DMA buffers are not released, but re-used. Since the transmit buffer | 1745 | * The DMA buffers are not released. They form a ring buffer and |
1779 | * descriptors are not clobbered, they can be re-submitted as is. This is | 1746 | * they are filled by ALSA while others are transmitted by DMA. |
1780 | * done by the xmit_descs() tasklet above since that could take longer. | 1747 | * |
1781 | */ | 1748 | */ |
1782 | 1749 | ||
1783 | static void transmission_complete_intr(struct snd_dbri * dbri, int pipe) | 1750 | static void transmission_complete_intr(struct snd_dbri * dbri, int pipe) |
@@ -1803,21 +1770,9 @@ static void transmission_complete_intr(struct snd_dbri * dbri, int pipe) | |||
1803 | dprintk(D_INT, "TD %d, status 0x%02x\n", td, status); | 1770 | dprintk(D_INT, "TD %d, status 0x%02x\n", td, status); |
1804 | 1771 | ||
1805 | dbri->dma->desc[td].word4 = 0; /* Reset it for next time. */ | 1772 | dbri->dma->desc[td].word4 = 0; /* Reset it for next time. */ |
1806 | info->offset += dbri->descs[td].len; | 1773 | info->offset += DBRI_RD_CNT(dbri->dma->desc[td].word1); |
1807 | info->left -= dbri->descs[td].len; | ||
1808 | |||
1809 | /* On the last TD, transmit them all again. */ | ||
1810 | if (dbri->descs[td].next == -1) { | ||
1811 | if (info->left > 0) { | ||
1812 | printk(KERN_WARNING | ||
1813 | "%d bytes left after last transfer.\n", | ||
1814 | info->left); | ||
1815 | info->left = 0; | ||
1816 | } | ||
1817 | tasklet_schedule(&xmit_descs_task); | ||
1818 | } | ||
1819 | 1774 | ||
1820 | td = dbri->descs[td].next; | 1775 | td = dbri->next_desc[td]; |
1821 | dbri->pipes[pipe].desc = td; | 1776 | dbri->pipes[pipe].desc = td; |
1822 | } | 1777 | } |
1823 | 1778 | ||
@@ -1841,30 +1796,18 @@ static void reception_complete_intr(struct snd_dbri * dbri, int pipe) | |||
1841 | return; | 1796 | return; |
1842 | } | 1797 | } |
1843 | 1798 | ||
1844 | dbri->descs[rd].inuse = 0; | 1799 | dbri->pipes[pipe].desc = dbri->next_desc[rd]; |
1845 | dbri->pipes[pipe].desc = dbri->descs[rd].next; | ||
1846 | status = dbri->dma->desc[rd].word1; | 1800 | status = dbri->dma->desc[rd].word1; |
1847 | dbri->dma->desc[rd].word1 = 0; /* Reset it for next time. */ | 1801 | dbri->dma->desc[rd].word1 = 0; /* Reset it for next time. */ |
1848 | 1802 | ||
1849 | info = &dbri->stream_info[DBRI_REC]; | 1803 | info = &dbri->stream_info[DBRI_REC]; |
1850 | info->offset += DBRI_RD_CNT(status); | 1804 | info->offset += DBRI_RD_CNT(status); |
1851 | info->left += DBRI_RD_CNT(status); | ||
1852 | 1805 | ||
1853 | /* FIXME: Check status */ | 1806 | /* FIXME: Check status */ |
1854 | 1807 | ||
1855 | dprintk(D_INT, "Recv RD %d, status 0x%02x, len %d\n", | 1808 | dprintk(D_INT, "Recv RD %d, status 0x%02x, len %d\n", |
1856 | rd, DBRI_RD_STATUS(status), DBRI_RD_CNT(status)); | 1809 | rd, DBRI_RD_STATUS(status), DBRI_RD_CNT(status)); |
1857 | 1810 | ||
1858 | /* On the last TD, transmit them all again. */ | ||
1859 | if (dbri->descs[rd].next == -1) { | ||
1860 | if (info->left > info->size) { | ||
1861 | printk(KERN_WARNING | ||
1862 | "%d bytes recorded in %d size buffer.\n", | ||
1863 | info->left, info->size); | ||
1864 | } | ||
1865 | tasklet_schedule(&xmit_descs_task); | ||
1866 | } | ||
1867 | |||
1868 | /* Notify ALSA */ | 1811 | /* Notify ALSA */ |
1869 | if (spin_is_locked(&dbri->lock)) { | 1812 | if (spin_is_locked(&dbri->lock)) { |
1870 | spin_unlock(&dbri->lock); | 1813 | spin_unlock(&dbri->lock); |
@@ -1892,16 +1835,11 @@ static void dbri_process_one_interrupt(struct snd_dbri * dbri, int x) | |||
1892 | channel, code, rval); | 1835 | channel, code, rval); |
1893 | } | 1836 | } |
1894 | 1837 | ||
1895 | if (channel == D_INTR_CMD && command == D_WAIT) { | ||
1896 | dbri->wait_ackd = val; | ||
1897 | if (dbri->wait_send != val) { | ||
1898 | printk(KERN_ERR "Processing wait command %d when %d was send.\n", | ||
1899 | val, dbri->wait_send); | ||
1900 | } | ||
1901 | return; | ||
1902 | } | ||
1903 | |||
1904 | switch (code) { | 1838 | switch (code) { |
1839 | case D_INTR_CMDI: | ||
1840 | if (command != D_WAIT) | ||
1841 | printk(KERN_ERR "DBRI: Command read interrupt\n"); | ||
1842 | break; | ||
1905 | case D_INTR_BRDY: | 1843 | case D_INTR_BRDY: |
1906 | reception_complete_intr(dbri, channel); | 1844 | reception_complete_intr(dbri, channel); |
1907 | break; | 1845 | break; |
@@ -1914,8 +1852,10 @@ static void dbri_process_one_interrupt(struct snd_dbri * dbri, int x) | |||
1914 | * resend SDP command with clear pipe bit (C) set | 1852 | * resend SDP command with clear pipe bit (C) set |
1915 | */ | 1853 | */ |
1916 | { | 1854 | { |
1917 | volatile s32 *cmd; | 1855 | /* FIXME: do something useful in case of underrun */ |
1918 | 1856 | printk(KERN_ERR "DBRI: Underrun error\n"); | |
1857 | #if 0 | ||
1858 | s32 *cmd; | ||
1919 | int pipe = channel; | 1859 | int pipe = channel; |
1920 | int td = dbri->pipes[pipe].desc; | 1860 | int td = dbri->pipes[pipe].desc; |
1921 | 1861 | ||
@@ -1926,6 +1866,7 @@ static void dbri_process_one_interrupt(struct snd_dbri * dbri, int x) | |||
1926 | | D_SDP_P | D_SDP_C | D_SDP_2SAME); | 1866 | | D_SDP_P | D_SDP_C | D_SDP_2SAME); |
1927 | *(cmd++) = dbri->dma_dvma + dbri_dma_off(desc, td); | 1867 | *(cmd++) = dbri->dma_dvma + dbri_dma_off(desc, td); |
1928 | dbri_cmdsend(dbri, cmd); | 1868 | dbri_cmdsend(dbri, cmd); |
1869 | #endif | ||
1929 | } | 1870 | } |
1930 | break; | 1871 | break; |
1931 | case D_INTR_FXDT: | 1872 | case D_INTR_FXDT: |
@@ -1946,9 +1887,7 @@ static void dbri_process_one_interrupt(struct snd_dbri * dbri, int x) | |||
1946 | /* dbri_process_interrupt_buffer advances through the DBRI's interrupt | 1887 | /* dbri_process_interrupt_buffer advances through the DBRI's interrupt |
1947 | * buffer until it finds a zero word (indicating nothing more to do | 1888 | * buffer until it finds a zero word (indicating nothing more to do |
1948 | * right now). Non-zero words require processing and are handed off | 1889 | * right now). Non-zero words require processing and are handed off |
1949 | * to dbri_process_one_interrupt AFTER advancing the pointer. This | 1890 | * to dbri_process_one_interrupt AFTER advancing the pointer. |
1950 | * order is important since we might recurse back into this function | ||
1951 | * and need to make sure the pointer has been advanced first. | ||
1952 | */ | 1891 | */ |
1953 | static void dbri_process_interrupt_buffer(struct snd_dbri * dbri) | 1892 | static void dbri_process_interrupt_buffer(struct snd_dbri * dbri) |
1954 | { | 1893 | { |
@@ -1957,10 +1896,8 @@ static void dbri_process_interrupt_buffer(struct snd_dbri * dbri) | |||
1957 | while ((x = dbri->dma->intr[dbri->dbri_irqp]) != 0) { | 1896 | while ((x = dbri->dma->intr[dbri->dbri_irqp]) != 0) { |
1958 | dbri->dma->intr[dbri->dbri_irqp] = 0; | 1897 | dbri->dma->intr[dbri->dbri_irqp] = 0; |
1959 | dbri->dbri_irqp++; | 1898 | dbri->dbri_irqp++; |
1960 | if (dbri->dbri_irqp == (DBRI_NO_INTS * DBRI_INT_BLK)) | 1899 | if (dbri->dbri_irqp == DBRI_INT_BLK) |
1961 | dbri->dbri_irqp = 1; | 1900 | dbri->dbri_irqp = 1; |
1962 | else if ((dbri->dbri_irqp & (DBRI_INT_BLK - 1)) == 0) | ||
1963 | dbri->dbri_irqp++; | ||
1964 | 1901 | ||
1965 | dbri_process_one_interrupt(dbri, x); | 1902 | dbri_process_one_interrupt(dbri, x); |
1966 | } | 1903 | } |
@@ -2020,8 +1957,6 @@ static irqreturn_t snd_dbri_interrupt(int irq, void *dev_id, | |||
2020 | 1957 | ||
2021 | dbri_process_interrupt_buffer(dbri); | 1958 | dbri_process_interrupt_buffer(dbri); |
2022 | 1959 | ||
2023 | /* FIXME: Write 0 into regs to ACK interrupt */ | ||
2024 | |||
2025 | spin_unlock(&dbri->lock); | 1960 | spin_unlock(&dbri->lock); |
2026 | 1961 | ||
2027 | return IRQ_HANDLED; | 1962 | return IRQ_HANDLED; |
@@ -2039,8 +1974,8 @@ static struct snd_pcm_hardware snd_dbri_pcm_hw = { | |||
2039 | SNDRV_PCM_FMTBIT_A_LAW | | 1974 | SNDRV_PCM_FMTBIT_A_LAW | |
2040 | SNDRV_PCM_FMTBIT_U8 | | 1975 | SNDRV_PCM_FMTBIT_U8 | |
2041 | SNDRV_PCM_FMTBIT_S16_BE, | 1976 | SNDRV_PCM_FMTBIT_S16_BE, |
2042 | .rates = SNDRV_PCM_RATE_8000_48000, | 1977 | .rates = SNDRV_PCM_RATE_8000_48000 | SNDRV_PCM_RATE_5512, |
2043 | .rate_min = 8000, | 1978 | .rate_min = 5512, |
2044 | .rate_max = 48000, | 1979 | .rate_max = 48000, |
2045 | .channels_min = 1, | 1980 | .channels_min = 1, |
2046 | .channels_max = 2, | 1981 | .channels_max = 2, |
@@ -2051,6 +1986,39 @@ static struct snd_pcm_hardware snd_dbri_pcm_hw = { | |||
2051 | .periods_max = 1024, | 1986 | .periods_max = 1024, |
2052 | }; | 1987 | }; |
2053 | 1988 | ||
1989 | static int snd_hw_rule_format(struct snd_pcm_hw_params *params, | ||
1990 | struct snd_pcm_hw_rule *rule) | ||
1991 | { | ||
1992 | struct snd_interval *c = hw_param_interval(params, | ||
1993 | SNDRV_PCM_HW_PARAM_CHANNELS); | ||
1994 | struct snd_mask *f = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT); | ||
1995 | struct snd_mask fmt; | ||
1996 | |||
1997 | snd_mask_any(&fmt); | ||
1998 | if (c->min > 1) { | ||
1999 | fmt.bits[0] &= SNDRV_PCM_FMTBIT_S16_BE; | ||
2000 | return snd_mask_refine(f, &fmt); | ||
2001 | } | ||
2002 | return 0; | ||
2003 | } | ||
2004 | |||
2005 | static int snd_hw_rule_channels(struct snd_pcm_hw_params *params, | ||
2006 | struct snd_pcm_hw_rule *rule) | ||
2007 | { | ||
2008 | struct snd_interval *c = hw_param_interval(params, | ||
2009 | SNDRV_PCM_HW_PARAM_CHANNELS); | ||
2010 | struct snd_mask *f = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT); | ||
2011 | struct snd_interval ch; | ||
2012 | |||
2013 | snd_interval_any(&ch); | ||
2014 | if (!(f->bits[0] & SNDRV_PCM_FMTBIT_S16_BE)) { | ||
2015 | ch.min = ch.max = 1; | ||
2016 | ch.integer = 1; | ||
2017 | return snd_interval_refine(c, &ch); | ||
2018 | } | ||
2019 | return 0; | ||
2020 | } | ||
2021 | |||
2054 | static int snd_dbri_open(struct snd_pcm_substream *substream) | 2022 | static int snd_dbri_open(struct snd_pcm_substream *substream) |
2055 | { | 2023 | { |
2056 | struct snd_dbri *dbri = snd_pcm_substream_chip(substream); | 2024 | struct snd_dbri *dbri = snd_pcm_substream_chip(substream); |
@@ -2063,12 +2031,19 @@ static int snd_dbri_open(struct snd_pcm_substream *substream) | |||
2063 | 2031 | ||
2064 | spin_lock_irqsave(&dbri->lock, flags); | 2032 | spin_lock_irqsave(&dbri->lock, flags); |
2065 | info->substream = substream; | 2033 | info->substream = substream; |
2066 | info->left = 0; | ||
2067 | info->offset = 0; | 2034 | info->offset = 0; |
2068 | info->dvma_buffer = 0; | 2035 | info->dvma_buffer = 0; |
2069 | info->pipe = -1; | 2036 | info->pipe = -1; |
2070 | spin_unlock_irqrestore(&dbri->lock, flags); | 2037 | spin_unlock_irqrestore(&dbri->lock, flags); |
2071 | 2038 | ||
2039 | snd_pcm_hw_rule_add(runtime,0,SNDRV_PCM_HW_PARAM_CHANNELS, | ||
2040 | snd_hw_rule_format, 0, SNDRV_PCM_HW_PARAM_FORMAT, | ||
2041 | -1); | ||
2042 | snd_pcm_hw_rule_add(runtime,0,SNDRV_PCM_HW_PARAM_FORMAT, | ||
2043 | snd_hw_rule_channels, 0, | ||
2044 | SNDRV_PCM_HW_PARAM_CHANNELS, | ||
2045 | -1); | ||
2046 | |||
2072 | cs4215_open(dbri); | 2047 | cs4215_open(dbri); |
2073 | 2048 | ||
2074 | return 0; | 2049 | return 0; |
@@ -2081,7 +2056,6 @@ static int snd_dbri_close(struct snd_pcm_substream *substream) | |||
2081 | 2056 | ||
2082 | dprintk(D_USR, "close audio output.\n"); | 2057 | dprintk(D_USR, "close audio output.\n"); |
2083 | info->substream = NULL; | 2058 | info->substream = NULL; |
2084 | info->left = 0; | ||
2085 | info->offset = 0; | 2059 | info->offset = 0; |
2086 | 2060 | ||
2087 | return 0; | 2061 | return 0; |
@@ -2134,6 +2108,7 @@ static int snd_dbri_hw_free(struct snd_pcm_substream *substream) | |||
2134 | struct snd_dbri *dbri = snd_pcm_substream_chip(substream); | 2108 | struct snd_dbri *dbri = snd_pcm_substream_chip(substream); |
2135 | struct dbri_streaminfo *info = DBRI_STREAM(dbri, substream); | 2109 | struct dbri_streaminfo *info = DBRI_STREAM(dbri, substream); |
2136 | int direction; | 2110 | int direction; |
2111 | |||
2137 | dprintk(D_USR, "hw_free.\n"); | 2112 | dprintk(D_USR, "hw_free.\n"); |
2138 | 2113 | ||
2139 | /* hw_free can get called multiple times. Only unmap the DMA once. | 2114 | /* hw_free can get called multiple times. Only unmap the DMA once. |
@@ -2148,7 +2123,10 @@ static int snd_dbri_hw_free(struct snd_pcm_substream *substream) | |||
2148 | substream->runtime->buffer_size, direction); | 2123 | substream->runtime->buffer_size, direction); |
2149 | info->dvma_buffer = 0; | 2124 | info->dvma_buffer = 0; |
2150 | } | 2125 | } |
2151 | info->pipe = -1; | 2126 | if (info->pipe != -1) { |
2127 | reset_pipe(dbri, info->pipe); | ||
2128 | info->pipe = -1; | ||
2129 | } | ||
2152 | 2130 | ||
2153 | return snd_pcm_lib_free_pages(substream); | 2131 | return snd_pcm_lib_free_pages(substream); |
2154 | } | 2132 | } |
@@ -2157,18 +2135,16 @@ static int snd_dbri_prepare(struct snd_pcm_substream *substream) | |||
2157 | { | 2135 | { |
2158 | struct snd_dbri *dbri = snd_pcm_substream_chip(substream); | 2136 | struct snd_dbri *dbri = snd_pcm_substream_chip(substream); |
2159 | struct dbri_streaminfo *info = DBRI_STREAM(dbri, substream); | 2137 | struct dbri_streaminfo *info = DBRI_STREAM(dbri, substream); |
2160 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
2161 | int ret; | 2138 | int ret; |
2162 | 2139 | ||
2163 | info->size = snd_pcm_lib_buffer_bytes(substream); | 2140 | info->size = snd_pcm_lib_buffer_bytes(substream); |
2164 | if (DBRI_STREAMNO(substream) == DBRI_PLAY) | 2141 | if (DBRI_STREAMNO(substream) == DBRI_PLAY) |
2165 | info->pipe = 4; /* Send pipe */ | 2142 | info->pipe = 4; /* Send pipe */ |
2166 | else { | 2143 | else |
2167 | info->pipe = 6; /* Receive pipe */ | 2144 | info->pipe = 6; /* Receive pipe */ |
2168 | info->left = info->size; /* To trigger submittal */ | ||
2169 | } | ||
2170 | 2145 | ||
2171 | spin_lock_irq(&dbri->lock); | 2146 | spin_lock_irq(&dbri->lock); |
2147 | info->offset = 0; | ||
2172 | 2148 | ||
2173 | /* Setup the all the transmit/receive desciptors to cover the | 2149 | /* Setup the all the transmit/receive desciptors to cover the |
2174 | * whole DMA buffer. | 2150 | * whole DMA buffer. |
@@ -2176,8 +2152,6 @@ static int snd_dbri_prepare(struct snd_pcm_substream *substream) | |||
2176 | ret = setup_descs(dbri, DBRI_STREAMNO(substream), | 2152 | ret = setup_descs(dbri, DBRI_STREAMNO(substream), |
2177 | snd_pcm_lib_period_bytes(substream)); | 2153 | snd_pcm_lib_period_bytes(substream)); |
2178 | 2154 | ||
2179 | runtime->stop_threshold = DBRI_TD_MAXCNT / runtime->channels; | ||
2180 | |||
2181 | spin_unlock_irq(&dbri->lock); | 2155 | spin_unlock_irq(&dbri->lock); |
2182 | 2156 | ||
2183 | dprintk(D_USR, "prepare audio output. %d bytes\n", info->size); | 2157 | dprintk(D_USR, "prepare audio output. %d bytes\n", info->size); |
@@ -2194,14 +2168,11 @@ static int snd_dbri_trigger(struct snd_pcm_substream *substream, int cmd) | |||
2194 | case SNDRV_PCM_TRIGGER_START: | 2168 | case SNDRV_PCM_TRIGGER_START: |
2195 | dprintk(D_USR, "start audio, period is %d bytes\n", | 2169 | dprintk(D_USR, "start audio, period is %d bytes\n", |
2196 | (int)snd_pcm_lib_period_bytes(substream)); | 2170 | (int)snd_pcm_lib_period_bytes(substream)); |
2197 | /* Enable & schedule the tasklet that re-submits the TDs. */ | 2171 | /* Re-submit the TDs. */ |
2198 | xmit_descs_task.data = (unsigned long)dbri; | 2172 | xmit_descs(dbri); |
2199 | tasklet_schedule(&xmit_descs_task); | ||
2200 | break; | 2173 | break; |
2201 | case SNDRV_PCM_TRIGGER_STOP: | 2174 | case SNDRV_PCM_TRIGGER_STOP: |
2202 | dprintk(D_USR, "stop audio.\n"); | 2175 | dprintk(D_USR, "stop audio.\n"); |
2203 | /* Make the tasklet bail out immediately. */ | ||
2204 | xmit_descs_task.data = 0; | ||
2205 | reset_pipe(dbri, info->pipe); | 2176 | reset_pipe(dbri, info->pipe); |
2206 | break; | 2177 | break; |
2207 | default: | 2178 | default: |
@@ -2219,8 +2190,8 @@ static snd_pcm_uframes_t snd_dbri_pointer(struct snd_pcm_substream *substream) | |||
2219 | 2190 | ||
2220 | ret = bytes_to_frames(substream->runtime, info->offset) | 2191 | ret = bytes_to_frames(substream->runtime, info->offset) |
2221 | % substream->runtime->buffer_size; | 2192 | % substream->runtime->buffer_size; |
2222 | dprintk(D_USR, "I/O pointer: %ld frames, %d bytes left.\n", | 2193 | dprintk(D_USR, "I/O pointer: %ld frames of %ld.\n", |
2223 | ret, info->left); | 2194 | ret, substream->runtime->buffer_size); |
2224 | return ret; | 2195 | return ret; |
2225 | } | 2196 | } |
2226 | 2197 | ||
@@ -2254,7 +2225,6 @@ static int __devinit snd_dbri_pcm(struct snd_dbri * dbri) | |||
2254 | pcm->private_data = dbri; | 2225 | pcm->private_data = dbri; |
2255 | pcm->info_flags = 0; | 2226 | pcm->info_flags = 0; |
2256 | strcpy(pcm->name, dbri->card->shortname); | 2227 | strcpy(pcm->name, dbri->card->shortname); |
2257 | dbri->pcm = pcm; | ||
2258 | 2228 | ||
2259 | if ((err = snd_pcm_lib_preallocate_pages_for_all(pcm, | 2229 | if ((err = snd_pcm_lib_preallocate_pages_for_all(pcm, |
2260 | SNDRV_DMA_TYPE_CONTINUOUS, | 2230 | SNDRV_DMA_TYPE_CONTINUOUS, |
@@ -2303,7 +2273,6 @@ static int snd_cs4215_put_volume(struct snd_kcontrol *kcontrol, | |||
2303 | { | 2273 | { |
2304 | struct snd_dbri *dbri = snd_kcontrol_chip(kcontrol); | 2274 | struct snd_dbri *dbri = snd_kcontrol_chip(kcontrol); |
2305 | struct dbri_streaminfo *info = &dbri->stream_info[kcontrol->private_value]; | 2275 | struct dbri_streaminfo *info = &dbri->stream_info[kcontrol->private_value]; |
2306 | unsigned long flags; | ||
2307 | int changed = 0; | 2276 | int changed = 0; |
2308 | 2277 | ||
2309 | if (info->left_gain != ucontrol->value.integer.value[0]) { | 2278 | if (info->left_gain != ucontrol->value.integer.value[0]) { |
@@ -2318,13 +2287,9 @@ static int snd_cs4215_put_volume(struct snd_kcontrol *kcontrol, | |||
2318 | /* First mute outputs, and wait 1/8000 sec (125 us) | 2287 | /* First mute outputs, and wait 1/8000 sec (125 us) |
2319 | * to make sure this takes. This avoids clicking noises. | 2288 | * to make sure this takes. This avoids clicking noises. |
2320 | */ | 2289 | */ |
2321 | spin_lock_irqsave(&dbri->lock, flags); | ||
2322 | |||
2323 | cs4215_setdata(dbri, 1); | 2290 | cs4215_setdata(dbri, 1); |
2324 | udelay(125); | 2291 | udelay(125); |
2325 | cs4215_setdata(dbri, 0); | 2292 | cs4215_setdata(dbri, 0); |
2326 | |||
2327 | spin_unlock_irqrestore(&dbri->lock, flags); | ||
2328 | } | 2293 | } |
2329 | return changed; | 2294 | return changed; |
2330 | } | 2295 | } |
@@ -2371,7 +2336,6 @@ static int snd_cs4215_put_single(struct snd_kcontrol *kcontrol, | |||
2371 | struct snd_ctl_elem_value *ucontrol) | 2336 | struct snd_ctl_elem_value *ucontrol) |
2372 | { | 2337 | { |
2373 | struct snd_dbri *dbri = snd_kcontrol_chip(kcontrol); | 2338 | struct snd_dbri *dbri = snd_kcontrol_chip(kcontrol); |
2374 | unsigned long flags; | ||
2375 | int elem = kcontrol->private_value & 0xff; | 2339 | int elem = kcontrol->private_value & 0xff; |
2376 | int shift = (kcontrol->private_value >> 8) & 0xff; | 2340 | int shift = (kcontrol->private_value >> 8) & 0xff; |
2377 | int mask = (kcontrol->private_value >> 16) & 0xff; | 2341 | int mask = (kcontrol->private_value >> 16) & 0xff; |
@@ -2404,13 +2368,9 @@ static int snd_cs4215_put_single(struct snd_kcontrol *kcontrol, | |||
2404 | /* First mute outputs, and wait 1/8000 sec (125 us) | 2368 | /* First mute outputs, and wait 1/8000 sec (125 us) |
2405 | * to make sure this takes. This avoids clicking noises. | 2369 | * to make sure this takes. This avoids clicking noises. |
2406 | */ | 2370 | */ |
2407 | spin_lock_irqsave(&dbri->lock, flags); | ||
2408 | |||
2409 | cs4215_setdata(dbri, 1); | 2371 | cs4215_setdata(dbri, 1); |
2410 | udelay(125); | 2372 | udelay(125); |
2411 | cs4215_setdata(dbri, 0); | 2373 | cs4215_setdata(dbri, 0); |
2412 | |||
2413 | spin_unlock_irqrestore(&dbri->lock, flags); | ||
2414 | } | 2374 | } |
2415 | return changed; | 2375 | return changed; |
2416 | } | 2376 | } |
@@ -2473,7 +2433,6 @@ static int __init snd_dbri_mixer(struct snd_dbri * dbri) | |||
2473 | for (idx = DBRI_REC; idx < DBRI_NO_STREAMS; idx++) { | 2433 | for (idx = DBRI_REC; idx < DBRI_NO_STREAMS; idx++) { |
2474 | dbri->stream_info[idx].left_gain = 0; | 2434 | dbri->stream_info[idx].left_gain = 0; |
2475 | dbri->stream_info[idx].right_gain = 0; | 2435 | dbri->stream_info[idx].right_gain = 0; |
2476 | dbri->stream_info[idx].balance = DBRI_MID_BALANCE; | ||
2477 | } | 2436 | } |
2478 | 2437 | ||
2479 | return 0; | 2438 | return 0; |
@@ -2505,12 +2464,11 @@ static void dbri_debug_read(struct snd_info_entry * entry, | |||
2505 | struct dbri_pipe *pptr = &dbri->pipes[pipe]; | 2464 | struct dbri_pipe *pptr = &dbri->pipes[pipe]; |
2506 | snd_iprintf(buffer, | 2465 | snd_iprintf(buffer, |
2507 | "Pipe %d: %s SDP=0x%x desc=%d, " | 2466 | "Pipe %d: %s SDP=0x%x desc=%d, " |
2508 | "len=%d @ %d prev: %d next %d\n", | 2467 | "len=%d next %d\n", |
2509 | pipe, | 2468 | pipe, |
2510 | (pptr->direction == | 2469 | ((pptr->sdp & D_SDP_TO_SER) ? "output" : "input"), |
2511 | PIPEinput ? "input" : "output"), pptr->sdp, | 2470 | pptr->sdp, pptr->desc, |
2512 | pptr->desc, pptr->length, pptr->cycle, | 2471 | pptr->length, pptr->nextpipe); |
2513 | pptr->prevpipe, pptr->nextpipe); | ||
2514 | } | 2472 | } |
2515 | } | 2473 | } |
2516 | } | 2474 | } |
@@ -2549,7 +2507,6 @@ static int __init snd_dbri_create(struct snd_card *card, | |||
2549 | dbri->card = card; | 2507 | dbri->card = card; |
2550 | dbri->sdev = sdev; | 2508 | dbri->sdev = sdev; |
2551 | dbri->irq = irq->pri; | 2509 | dbri->irq = irq->pri; |
2552 | dbri->dbri_version = sdev->prom_name[9]; | ||
2553 | 2510 | ||
2554 | dbri->dma = sbus_alloc_consistent(sdev, sizeof(struct dbri_dma), | 2511 | dbri->dma = sbus_alloc_consistent(sdev, sizeof(struct dbri_dma), |
2555 | &dbri->dma_dvma); | 2512 | &dbri->dma_dvma); |
@@ -2669,7 +2626,7 @@ static int __init dbri_attach(int prom_node, struct sbus_dev *sdev) | |||
2669 | 2626 | ||
2670 | printk(KERN_INFO "audio%d at %p (irq %d) is DBRI(%c)+CS4215(%d)\n", | 2627 | printk(KERN_INFO "audio%d at %p (irq %d) is DBRI(%c)+CS4215(%d)\n", |
2671 | dev, dbri->regs, | 2628 | dev, dbri->regs, |
2672 | dbri->irq, dbri->dbri_version, dbri->mm.version); | 2629 | dbri->irq, sdev->prom_name[9], dbri->mm.version); |
2673 | dev++; | 2630 | dev++; |
2674 | 2631 | ||
2675 | return 0; | 2632 | return 0; |
diff --git a/sound/synth/emux/emux_proc.c b/sound/synth/emux/emux_proc.c index 58b9601f3ad0..59144ec026e4 100644 --- a/sound/synth/emux/emux_proc.c +++ b/sound/synth/emux/emux_proc.c | |||
@@ -128,10 +128,8 @@ void snd_emux_proc_init(struct snd_emux *emu, struct snd_card *card, int device) | |||
128 | 128 | ||
129 | void snd_emux_proc_free(struct snd_emux *emu) | 129 | void snd_emux_proc_free(struct snd_emux *emu) |
130 | { | 130 | { |
131 | if (emu->proc) { | 131 | snd_info_free_entry(emu->proc); |
132 | snd_info_unregister(emu->proc); | 132 | emu->proc = NULL; |
133 | emu->proc = NULL; | ||
134 | } | ||
135 | } | 133 | } |
136 | 134 | ||
137 | #endif /* CONFIG_PROC_FS */ | 135 | #endif /* CONFIG_PROC_FS */ |
diff --git a/sound/usb/usbaudio.c b/sound/usb/usbaudio.c index 1b7f499c549d..49248fa7aef4 100644 --- a/sound/usb/usbaudio.c +++ b/sound/usb/usbaudio.c | |||
@@ -68,7 +68,7 @@ static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */ | |||
68 | static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP; /* Enable this card */ | 68 | static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP; /* Enable this card */ |
69 | static int vid[SNDRV_CARDS] = { [0 ... (SNDRV_CARDS-1)] = -1 }; /* Vendor ID for this card */ | 69 | static int vid[SNDRV_CARDS] = { [0 ... (SNDRV_CARDS-1)] = -1 }; /* Vendor ID for this card */ |
70 | static int pid[SNDRV_CARDS] = { [0 ... (SNDRV_CARDS-1)] = -1 }; /* Product ID for this card */ | 70 | static int pid[SNDRV_CARDS] = { [0 ... (SNDRV_CARDS-1)] = -1 }; /* Product ID for this card */ |
71 | static int nrpacks = 4; /* max. number of packets per urb */ | 71 | static int nrpacks = 8; /* max. number of packets per urb */ |
72 | static int async_unlink = 1; | 72 | static int async_unlink = 1; |
73 | static int device_setup[SNDRV_CARDS]; /* device parameter for this card*/ | 73 | static int device_setup[SNDRV_CARDS]; /* device parameter for this card*/ |
74 | 74 | ||
@@ -100,7 +100,7 @@ MODULE_PARM_DESC(device_setup, "Specific device setup (if needed)."); | |||
100 | * | 100 | * |
101 | */ | 101 | */ |
102 | 102 | ||
103 | #define MAX_PACKS 10 | 103 | #define MAX_PACKS 20 |
104 | #define MAX_PACKS_HS (MAX_PACKS * 8) /* in high speed mode */ | 104 | #define MAX_PACKS_HS (MAX_PACKS * 8) /* in high speed mode */ |
105 | #define MAX_URBS 8 | 105 | #define MAX_URBS 8 |
106 | #define SYNC_URBS 4 /* always four urbs for sync */ | 106 | #define SYNC_URBS 4 /* always four urbs for sync */ |
@@ -123,6 +123,7 @@ struct audioformat { | |||
123 | unsigned int rate_min, rate_max; /* min/max rates */ | 123 | unsigned int rate_min, rate_max; /* min/max rates */ |
124 | unsigned int nr_rates; /* number of rate table entries */ | 124 | unsigned int nr_rates; /* number of rate table entries */ |
125 | unsigned int *rate_table; /* rate table */ | 125 | unsigned int *rate_table; /* rate table */ |
126 | unsigned int needs_knot; /* any unusual rates? */ | ||
126 | }; | 127 | }; |
127 | 128 | ||
128 | struct snd_usb_substream; | 129 | struct snd_usb_substream; |
@@ -1759,6 +1760,9 @@ static int check_hw_params_convention(struct snd_usb_substream *subs) | |||
1759 | } | 1760 | } |
1760 | channels[f->format] |= (1 << f->channels); | 1761 | channels[f->format] |= (1 << f->channels); |
1761 | rates[f->format] |= f->rates; | 1762 | rates[f->format] |= f->rates; |
1763 | /* needs knot? */ | ||
1764 | if (f->needs_knot) | ||
1765 | goto __out; | ||
1762 | } | 1766 | } |
1763 | /* check whether channels and rates match for all formats */ | 1767 | /* check whether channels and rates match for all formats */ |
1764 | cmaster = rmaster = 0; | 1768 | cmaster = rmaster = 0; |
@@ -1799,6 +1803,38 @@ static int check_hw_params_convention(struct snd_usb_substream *subs) | |||
1799 | return err; | 1803 | return err; |
1800 | } | 1804 | } |
1801 | 1805 | ||
1806 | /* | ||
1807 | * If the device supports unusual bit rates, does the request meet these? | ||
1808 | */ | ||
1809 | static int snd_usb_pcm_check_knot(struct snd_pcm_runtime *runtime, | ||
1810 | struct snd_usb_substream *subs) | ||
1811 | { | ||
1812 | struct list_head *p; | ||
1813 | struct snd_pcm_hw_constraint_list constraints_rates; | ||
1814 | int err; | ||
1815 | |||
1816 | list_for_each(p, &subs->fmt_list) { | ||
1817 | struct audioformat *fp; | ||
1818 | fp = list_entry(p, struct audioformat, list); | ||
1819 | |||
1820 | if (!fp->needs_knot) | ||
1821 | continue; | ||
1822 | |||
1823 | constraints_rates.count = fp->nr_rates; | ||
1824 | constraints_rates.list = fp->rate_table; | ||
1825 | constraints_rates.mask = 0; | ||
1826 | |||
1827 | err = snd_pcm_hw_constraint_list(runtime, 0, | ||
1828 | SNDRV_PCM_HW_PARAM_RATE, | ||
1829 | &constraints_rates); | ||
1830 | |||
1831 | if (err < 0) | ||
1832 | return err; | ||
1833 | } | ||
1834 | |||
1835 | return 0; | ||
1836 | } | ||
1837 | |||
1802 | 1838 | ||
1803 | /* | 1839 | /* |
1804 | * set up the runtime hardware information. | 1840 | * set up the runtime hardware information. |
@@ -1861,6 +1897,8 @@ static int setup_hw_info(struct snd_pcm_runtime *runtime, struct snd_usb_substre | |||
1861 | SNDRV_PCM_HW_PARAM_CHANNELS, | 1897 | SNDRV_PCM_HW_PARAM_CHANNELS, |
1862 | -1)) < 0) | 1898 | -1)) < 0) |
1863 | return err; | 1899 | return err; |
1900 | if ((err = snd_usb_pcm_check_knot(runtime, subs)) < 0) | ||
1901 | return err; | ||
1864 | } | 1902 | } |
1865 | return 0; | 1903 | return 0; |
1866 | } | 1904 | } |
@@ -2049,7 +2087,7 @@ static struct usb_driver usb_audio_driver = { | |||
2049 | }; | 2087 | }; |
2050 | 2088 | ||
2051 | 2089 | ||
2052 | #if defined(CONFIG_PROCFS) && defined(CONFIG_SND_VERBOSE_PROCFS) | 2090 | #if defined(CONFIG_PROC_FS) && defined(CONFIG_SND_VERBOSE_PROCFS) |
2053 | 2091 | ||
2054 | /* | 2092 | /* |
2055 | * proc interface for list the supported pcm formats | 2093 | * proc interface for list the supported pcm formats |
@@ -2406,6 +2444,7 @@ static int parse_audio_format_rates(struct snd_usb_audio *chip, struct audioform | |||
2406 | unsigned char *fmt, int offset) | 2444 | unsigned char *fmt, int offset) |
2407 | { | 2445 | { |
2408 | int nr_rates = fmt[offset]; | 2446 | int nr_rates = fmt[offset]; |
2447 | int found; | ||
2409 | if (fmt[0] < offset + 1 + 3 * (nr_rates ? nr_rates : 2)) { | 2448 | if (fmt[0] < offset + 1 + 3 * (nr_rates ? nr_rates : 2)) { |
2410 | snd_printk(KERN_ERR "%d:%u:%d : invalid FORMAT_TYPE desc\n", | 2449 | snd_printk(KERN_ERR "%d:%u:%d : invalid FORMAT_TYPE desc\n", |
2411 | chip->dev->devnum, fp->iface, fp->altsetting); | 2450 | chip->dev->devnum, fp->iface, fp->altsetting); |
@@ -2428,6 +2467,7 @@ static int parse_audio_format_rates(struct snd_usb_audio *chip, struct audioform | |||
2428 | return -1; | 2467 | return -1; |
2429 | } | 2468 | } |
2430 | 2469 | ||
2470 | fp->needs_knot = 0; | ||
2431 | fp->nr_rates = nr_rates; | 2471 | fp->nr_rates = nr_rates; |
2432 | fp->rate_min = fp->rate_max = combine_triple(&fmt[8]); | 2472 | fp->rate_min = fp->rate_max = combine_triple(&fmt[8]); |
2433 | for (r = 0, idx = offset + 1; r < nr_rates; r++, idx += 3) { | 2473 | for (r = 0, idx = offset + 1; r < nr_rates; r++, idx += 3) { |
@@ -2436,13 +2476,19 @@ static int parse_audio_format_rates(struct snd_usb_audio *chip, struct audioform | |||
2436 | fp->rate_min = rate; | 2476 | fp->rate_min = rate; |
2437 | else if (rate > fp->rate_max) | 2477 | else if (rate > fp->rate_max) |
2438 | fp->rate_max = rate; | 2478 | fp->rate_max = rate; |
2479 | found = 0; | ||
2439 | for (c = 0; c < (int)ARRAY_SIZE(conv_rates); c++) { | 2480 | for (c = 0; c < (int)ARRAY_SIZE(conv_rates); c++) { |
2440 | if (rate == conv_rates[c]) { | 2481 | if (rate == conv_rates[c]) { |
2482 | found = 1; | ||
2441 | fp->rates |= (1 << c); | 2483 | fp->rates |= (1 << c); |
2442 | break; | 2484 | break; |
2443 | } | 2485 | } |
2444 | } | 2486 | } |
2487 | if (!found) | ||
2488 | fp->needs_knot = 1; | ||
2445 | } | 2489 | } |
2490 | if (fp->needs_knot) | ||
2491 | fp->rates |= SNDRV_PCM_RATE_KNOT; | ||
2446 | } else { | 2492 | } else { |
2447 | /* continuous rates */ | 2493 | /* continuous rates */ |
2448 | fp->rates = SNDRV_PCM_RATE_CONTINUOUS; | 2494 | fp->rates = SNDRV_PCM_RATE_CONTINUOUS; |
@@ -3499,7 +3545,7 @@ static void snd_usb_audio_disconnect(struct usb_device *dev, void *ptr) | |||
3499 | } | 3545 | } |
3500 | usb_chip[chip->index] = NULL; | 3546 | usb_chip[chip->index] = NULL; |
3501 | mutex_unlock(®ister_mutex); | 3547 | mutex_unlock(®ister_mutex); |
3502 | snd_card_free(card); | 3548 | snd_card_free_when_closed(card); |
3503 | } else { | 3549 | } else { |
3504 | mutex_unlock(®ister_mutex); | 3550 | mutex_unlock(®ister_mutex); |
3505 | } | 3551 | } |
diff --git a/sound/usb/usbmixer.c b/sound/usb/usbmixer.c index 491e975a0c87..e516d6adbb22 100644 --- a/sound/usb/usbmixer.c +++ b/sound/usb/usbmixer.c | |||
@@ -37,6 +37,7 @@ | |||
37 | #include <sound/control.h> | 37 | #include <sound/control.h> |
38 | #include <sound/hwdep.h> | 38 | #include <sound/hwdep.h> |
39 | #include <sound/info.h> | 39 | #include <sound/info.h> |
40 | #include <sound/tlv.h> | ||
40 | 41 | ||
41 | #include "usbaudio.h" | 42 | #include "usbaudio.h" |
42 | 43 | ||
@@ -416,6 +417,26 @@ static inline int set_cur_mix_value(struct usb_mixer_elem_info *cval, int channe | |||
416 | return set_ctl_value(cval, SET_CUR, (cval->control << 8) | channel, value); | 417 | return set_ctl_value(cval, SET_CUR, (cval->control << 8) | channel, value); |
417 | } | 418 | } |
418 | 419 | ||
420 | /* | ||
421 | * TLV callback for mixer volume controls | ||
422 | */ | ||
423 | static int mixer_vol_tlv(struct snd_kcontrol *kcontrol, int op_flag, | ||
424 | unsigned int size, unsigned int __user *_tlv) | ||
425 | { | ||
426 | struct usb_mixer_elem_info *cval = kcontrol->private_data; | ||
427 | DECLARE_TLV_DB_SCALE(scale, 0, 0, 0); | ||
428 | |||
429 | if (size < sizeof(scale)) | ||
430 | return -ENOMEM; | ||
431 | /* USB descriptions contain the dB scale in 1/256 dB unit | ||
432 | * while ALSA TLV contains in 1/100 dB unit | ||
433 | */ | ||
434 | scale[2] = (convert_signed_value(cval, cval->min) * 100) / 256; | ||
435 | scale[3] = (convert_signed_value(cval, cval->res) * 100) / 256; | ||
436 | if (copy_to_user(_tlv, scale, sizeof(scale))) | ||
437 | return -EFAULT; | ||
438 | return 0; | ||
439 | } | ||
419 | 440 | ||
420 | /* | 441 | /* |
421 | * parser routines begin here... | 442 | * parser routines begin here... |
@@ -933,6 +954,12 @@ static void build_feature_ctl(struct mixer_build *state, unsigned char *desc, | |||
933 | } | 954 | } |
934 | strlcat(kctl->id.name + len, control == USB_FEATURE_MUTE ? " Switch" : " Volume", | 955 | strlcat(kctl->id.name + len, control == USB_FEATURE_MUTE ? " Switch" : " Volume", |
935 | sizeof(kctl->id.name)); | 956 | sizeof(kctl->id.name)); |
957 | if (control == USB_FEATURE_VOLUME) { | ||
958 | kctl->tlv.c = mixer_vol_tlv; | ||
959 | kctl->vd[0].access |= | ||
960 | SNDRV_CTL_ELEM_ACCESS_TLV_READ | | ||
961 | SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK; | ||
962 | } | ||
936 | break; | 963 | break; |
937 | 964 | ||
938 | default: | 965 | default: |
diff --git a/sound/usb/usbmixer_maps.c b/sound/usb/usbmixer_maps.c index 37accb68652d..7c4dcb3f436a 100644 --- a/sound/usb/usbmixer_maps.c +++ b/sound/usb/usbmixer_maps.c | |||
@@ -234,6 +234,26 @@ static struct usbmix_name_map justlink_map[] = { | |||
234 | { 0 } /* terminator */ | 234 | { 0 } /* terminator */ |
235 | }; | 235 | }; |
236 | 236 | ||
237 | /* TerraTec Aureon 5.1 MkII USB */ | ||
238 | static struct usbmix_name_map aureon_51_2_map[] = { | ||
239 | /* 1: IT USB */ | ||
240 | /* 2: IT Mic */ | ||
241 | /* 3: IT Line */ | ||
242 | /* 4: IT SPDIF */ | ||
243 | /* 5: OT SPDIF */ | ||
244 | /* 6: OT Speaker */ | ||
245 | /* 7: OT USB */ | ||
246 | { 8, "Capture Source" }, /* SU */ | ||
247 | { 9, "Master Playback" }, /* FU */ | ||
248 | { 10, "Mic Capture" }, /* FU */ | ||
249 | { 11, "Line Capture" }, /* FU */ | ||
250 | { 12, "IEC958 In Capture" }, /* FU */ | ||
251 | { 13, "Mic Playback" }, /* FU */ | ||
252 | { 14, "Line Playback" }, /* FU */ | ||
253 | /* 15: MU */ | ||
254 | {} /* terminator */ | ||
255 | }; | ||
256 | |||
237 | /* | 257 | /* |
238 | * Control map entries | 258 | * Control map entries |
239 | */ | 259 | */ |
@@ -276,6 +296,10 @@ static struct usbmix_ctl_map usbmix_ctl_maps[] = { | |||
276 | .id = USB_ID(0x0c45, 0x1158), | 296 | .id = USB_ID(0x0c45, 0x1158), |
277 | .map = justlink_map, | 297 | .map = justlink_map, |
278 | }, | 298 | }, |
299 | { | ||
300 | .id = USB_ID(0x0ccd, 0x0028), | ||
301 | .map = aureon_51_2_map, | ||
302 | }, | ||
279 | { 0 } /* terminator */ | 303 | { 0 } /* terminator */ |
280 | }; | 304 | }; |
281 | 305 | ||
diff --git a/sound/usb/usbquirks.h b/sound/usb/usbquirks.h index 9351846d7a9d..a7e9563a01df 100644 --- a/sound/usb/usbquirks.h +++ b/sound/usb/usbquirks.h | |||
@@ -123,6 +123,10 @@ YAMAHA_DEVICE(0x103e, NULL), | |||
123 | YAMAHA_DEVICE(0x103f, NULL), | 123 | YAMAHA_DEVICE(0x103f, NULL), |
124 | YAMAHA_DEVICE(0x1040, NULL), | 124 | YAMAHA_DEVICE(0x1040, NULL), |
125 | YAMAHA_DEVICE(0x1041, NULL), | 125 | YAMAHA_DEVICE(0x1041, NULL), |
126 | YAMAHA_DEVICE(0x1042, NULL), | ||
127 | YAMAHA_DEVICE(0x1043, NULL), | ||
128 | YAMAHA_DEVICE(0x1044, NULL), | ||
129 | YAMAHA_DEVICE(0x1045, NULL), | ||
126 | YAMAHA_DEVICE(0x2000, "DGP-7"), | 130 | YAMAHA_DEVICE(0x2000, "DGP-7"), |
127 | YAMAHA_DEVICE(0x2001, "DGP-5"), | 131 | YAMAHA_DEVICE(0x2001, "DGP-5"), |
128 | YAMAHA_DEVICE(0x2002, NULL), | 132 | YAMAHA_DEVICE(0x2002, NULL), |
@@ -141,6 +145,7 @@ YAMAHA_DEVICE(0x500b, "DME64N"), | |||
141 | YAMAHA_DEVICE(0x500c, "DME24N"), | 145 | YAMAHA_DEVICE(0x500c, "DME24N"), |
142 | YAMAHA_DEVICE(0x500d, NULL), | 146 | YAMAHA_DEVICE(0x500d, NULL), |
143 | YAMAHA_DEVICE(0x500e, NULL), | 147 | YAMAHA_DEVICE(0x500e, NULL), |
148 | YAMAHA_DEVICE(0x500f, NULL), | ||
144 | YAMAHA_DEVICE(0x7000, "DTX"), | 149 | YAMAHA_DEVICE(0x7000, "DTX"), |
145 | YAMAHA_DEVICE(0x7010, "UB99"), | 150 | YAMAHA_DEVICE(0x7010, "UB99"), |
146 | #undef YAMAHA_DEVICE | 151 | #undef YAMAHA_DEVICE |