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 |
