diff options
| author | Jiri Kosina <jkosina@suse.cz> | 2011-04-26 04:22:15 -0400 |
|---|---|---|
| committer | Jiri Kosina <jkosina@suse.cz> | 2011-04-26 04:22:59 -0400 |
| commit | 07f9479a40cc778bc1462ada11f95b01360ae4ff (patch) | |
| tree | 0676cf38df3844004bb3ebfd99dfa67a4a8998f5 /net/rose/rose_subr.c | |
| parent | 9d5e6bdb3013acfb311ab407eeca0b6a6a3dedbf (diff) | |
| parent | cd2e49e90f1cae7726c9a2c54488d881d7f1cd1c (diff) | |
Merge branch 'master' into for-next
Fast-forwarded to current state of Linus' tree as there are patches to be
applied for files that didn't exist on the old branch.
Diffstat (limited to 'net/rose/rose_subr.c')
| -rw-r--r-- | net/rose/rose_subr.c | 101 |
1 files changed, 69 insertions, 32 deletions
diff --git a/net/rose/rose_subr.c b/net/rose/rose_subr.c index 1734abba26a2..f6c71caa94b9 100644 --- a/net/rose/rose_subr.c +++ b/net/rose/rose_subr.c | |||
| @@ -142,7 +142,7 @@ void rose_write_internal(struct sock *sk, int frametype) | |||
| 142 | *dptr++ = ROSE_GFI | lci1; | 142 | *dptr++ = ROSE_GFI | lci1; |
| 143 | *dptr++ = lci2; | 143 | *dptr++ = lci2; |
| 144 | *dptr++ = frametype; | 144 | *dptr++ = frametype; |
| 145 | *dptr++ = 0xAA; | 145 | *dptr++ = ROSE_CALL_REQ_ADDR_LEN_VAL; |
| 146 | memcpy(dptr, &rose->dest_addr, ROSE_ADDR_LEN); | 146 | memcpy(dptr, &rose->dest_addr, ROSE_ADDR_LEN); |
| 147 | dptr += ROSE_ADDR_LEN; | 147 | dptr += ROSE_ADDR_LEN; |
| 148 | memcpy(dptr, &rose->source_addr, ROSE_ADDR_LEN); | 148 | memcpy(dptr, &rose->source_addr, ROSE_ADDR_LEN); |
| @@ -246,12 +246,16 @@ static int rose_parse_national(unsigned char *p, struct rose_facilities_struct * | |||
| 246 | do { | 246 | do { |
| 247 | switch (*p & 0xC0) { | 247 | switch (*p & 0xC0) { |
| 248 | case 0x00: | 248 | case 0x00: |
| 249 | if (len < 2) | ||
| 250 | return -1; | ||
| 249 | p += 2; | 251 | p += 2; |
| 250 | n += 2; | 252 | n += 2; |
| 251 | len -= 2; | 253 | len -= 2; |
| 252 | break; | 254 | break; |
| 253 | 255 | ||
| 254 | case 0x40: | 256 | case 0x40: |
| 257 | if (len < 3) | ||
| 258 | return -1; | ||
| 255 | if (*p == FAC_NATIONAL_RAND) | 259 | if (*p == FAC_NATIONAL_RAND) |
| 256 | facilities->rand = ((p[1] << 8) & 0xFF00) + ((p[2] << 0) & 0x00FF); | 260 | facilities->rand = ((p[1] << 8) & 0xFF00) + ((p[2] << 0) & 0x00FF); |
| 257 | p += 3; | 261 | p += 3; |
| @@ -260,40 +264,61 @@ static int rose_parse_national(unsigned char *p, struct rose_facilities_struct * | |||
| 260 | break; | 264 | break; |
| 261 | 265 | ||
| 262 | case 0x80: | 266 | case 0x80: |
| 267 | if (len < 4) | ||
| 268 | return -1; | ||
| 263 | p += 4; | 269 | p += 4; |
| 264 | n += 4; | 270 | n += 4; |
| 265 | len -= 4; | 271 | len -= 4; |
| 266 | break; | 272 | break; |
| 267 | 273 | ||
| 268 | case 0xC0: | 274 | case 0xC0: |
| 275 | if (len < 2) | ||
| 276 | return -1; | ||
| 269 | l = p[1]; | 277 | l = p[1]; |
| 278 | if (len < 2 + l) | ||
| 279 | return -1; | ||
| 270 | if (*p == FAC_NATIONAL_DEST_DIGI) { | 280 | if (*p == FAC_NATIONAL_DEST_DIGI) { |
| 271 | if (!fac_national_digis_received) { | 281 | if (!fac_national_digis_received) { |
| 282 | if (l < AX25_ADDR_LEN) | ||
| 283 | return -1; | ||
| 272 | memcpy(&facilities->source_digis[0], p + 2, AX25_ADDR_LEN); | 284 | memcpy(&facilities->source_digis[0], p + 2, AX25_ADDR_LEN); |
| 273 | facilities->source_ndigis = 1; | 285 | facilities->source_ndigis = 1; |
| 274 | } | 286 | } |
| 275 | } | 287 | } |
| 276 | else if (*p == FAC_NATIONAL_SRC_DIGI) { | 288 | else if (*p == FAC_NATIONAL_SRC_DIGI) { |
| 277 | if (!fac_national_digis_received) { | 289 | if (!fac_national_digis_received) { |
| 290 | if (l < AX25_ADDR_LEN) | ||
| 291 | return -1; | ||
| 278 | memcpy(&facilities->dest_digis[0], p + 2, AX25_ADDR_LEN); | 292 | memcpy(&facilities->dest_digis[0], p + 2, AX25_ADDR_LEN); |
| 279 | facilities->dest_ndigis = 1; | 293 | facilities->dest_ndigis = 1; |
| 280 | } | 294 | } |
| 281 | } | 295 | } |
| 282 | else if (*p == FAC_NATIONAL_FAIL_CALL) { | 296 | else if (*p == FAC_NATIONAL_FAIL_CALL) { |
| 297 | if (l < AX25_ADDR_LEN) | ||
| 298 | return -1; | ||
| 283 | memcpy(&facilities->fail_call, p + 2, AX25_ADDR_LEN); | 299 | memcpy(&facilities->fail_call, p + 2, AX25_ADDR_LEN); |
| 284 | } | 300 | } |
| 285 | else if (*p == FAC_NATIONAL_FAIL_ADD) { | 301 | else if (*p == FAC_NATIONAL_FAIL_ADD) { |
| 302 | if (l < 1 + ROSE_ADDR_LEN) | ||
| 303 | return -1; | ||
| 286 | memcpy(&facilities->fail_addr, p + 3, ROSE_ADDR_LEN); | 304 | memcpy(&facilities->fail_addr, p + 3, ROSE_ADDR_LEN); |
| 287 | } | 305 | } |
| 288 | else if (*p == FAC_NATIONAL_DIGIS) { | 306 | else if (*p == FAC_NATIONAL_DIGIS) { |
| 307 | if (l % AX25_ADDR_LEN) | ||
| 308 | return -1; | ||
| 289 | fac_national_digis_received = 1; | 309 | fac_national_digis_received = 1; |
| 290 | facilities->source_ndigis = 0; | 310 | facilities->source_ndigis = 0; |
| 291 | facilities->dest_ndigis = 0; | 311 | facilities->dest_ndigis = 0; |
| 292 | for (pt = p + 2, lg = 0 ; lg < l ; pt += AX25_ADDR_LEN, lg += AX25_ADDR_LEN) { | 312 | for (pt = p + 2, lg = 0 ; lg < l ; pt += AX25_ADDR_LEN, lg += AX25_ADDR_LEN) { |
| 293 | if (pt[6] & AX25_HBIT) | 313 | if (pt[6] & AX25_HBIT) { |
| 314 | if (facilities->dest_ndigis >= ROSE_MAX_DIGIS) | ||
| 315 | return -1; | ||
| 294 | memcpy(&facilities->dest_digis[facilities->dest_ndigis++], pt, AX25_ADDR_LEN); | 316 | memcpy(&facilities->dest_digis[facilities->dest_ndigis++], pt, AX25_ADDR_LEN); |
| 295 | else | 317 | } else { |
| 318 | if (facilities->source_ndigis >= ROSE_MAX_DIGIS) | ||
| 319 | return -1; | ||
| 296 | memcpy(&facilities->source_digis[facilities->source_ndigis++], pt, AX25_ADDR_LEN); | 320 | memcpy(&facilities->source_digis[facilities->source_ndigis++], pt, AX25_ADDR_LEN); |
| 321 | } | ||
| 297 | } | 322 | } |
| 298 | } | 323 | } |
| 299 | p += l + 2; | 324 | p += l + 2; |
| @@ -314,25 +339,38 @@ static int rose_parse_ccitt(unsigned char *p, struct rose_facilities_struct *fac | |||
| 314 | do { | 339 | do { |
| 315 | switch (*p & 0xC0) { | 340 | switch (*p & 0xC0) { |
| 316 | case 0x00: | 341 | case 0x00: |
| 342 | if (len < 2) | ||
| 343 | return -1; | ||
| 317 | p += 2; | 344 | p += 2; |
| 318 | n += 2; | 345 | n += 2; |
| 319 | len -= 2; | 346 | len -= 2; |
| 320 | break; | 347 | break; |
| 321 | 348 | ||
| 322 | case 0x40: | 349 | case 0x40: |
| 350 | if (len < 3) | ||
| 351 | return -1; | ||
| 323 | p += 3; | 352 | p += 3; |
| 324 | n += 3; | 353 | n += 3; |
| 325 | len -= 3; | 354 | len -= 3; |
| 326 | break; | 355 | break; |
| 327 | 356 | ||
| 328 | case 0x80: | 357 | case 0x80: |
| 358 | if (len < 4) | ||
| 359 | return -1; | ||
| 329 | p += 4; | 360 | p += 4; |
| 330 | n += 4; | 361 | n += 4; |
| 331 | len -= 4; | 362 | len -= 4; |
| 332 | break; | 363 | break; |
| 333 | 364 | ||
| 334 | case 0xC0: | 365 | case 0xC0: |
| 366 | if (len < 2) | ||
| 367 | return -1; | ||
| 335 | l = p[1]; | 368 | l = p[1]; |
| 369 | |||
| 370 | /* Prevent overflows*/ | ||
| 371 | if (l < 10 || l > 20) | ||
| 372 | return -1; | ||
| 373 | |||
| 336 | if (*p == FAC_CCITT_DEST_NSAP) { | 374 | if (*p == FAC_CCITT_DEST_NSAP) { |
| 337 | memcpy(&facilities->source_addr, p + 7, ROSE_ADDR_LEN); | 375 | memcpy(&facilities->source_addr, p + 7, ROSE_ADDR_LEN); |
| 338 | memcpy(callsign, p + 12, l - 10); | 376 | memcpy(callsign, p + 12, l - 10); |
| @@ -355,45 +393,44 @@ static int rose_parse_ccitt(unsigned char *p, struct rose_facilities_struct *fac | |||
| 355 | return n; | 393 | return n; |
| 356 | } | 394 | } |
| 357 | 395 | ||
| 358 | int rose_parse_facilities(unsigned char *p, | 396 | int rose_parse_facilities(unsigned char *p, unsigned packet_len, |
| 359 | struct rose_facilities_struct *facilities) | 397 | struct rose_facilities_struct *facilities) |
| 360 | { | 398 | { |
| 361 | int facilities_len, len; | 399 | int facilities_len, len; |
| 362 | 400 | ||
| 363 | facilities_len = *p++; | 401 | facilities_len = *p++; |
| 364 | 402 | ||
| 365 | if (facilities_len == 0) | 403 | if (facilities_len == 0 || (unsigned)facilities_len > packet_len) |
| 366 | return 0; | 404 | return 0; |
| 367 | 405 | ||
| 368 | while (facilities_len > 0) { | 406 | while (facilities_len >= 3 && *p == 0x00) { |
| 369 | if (*p == 0x00) { | 407 | facilities_len--; |
| 370 | facilities_len--; | 408 | p++; |
| 371 | p++; | 409 | |
| 372 | 410 | switch (*p) { | |
| 373 | switch (*p) { | 411 | case FAC_NATIONAL: /* National */ |
| 374 | case FAC_NATIONAL: /* National */ | 412 | len = rose_parse_national(p + 1, facilities, facilities_len - 1); |
| 375 | len = rose_parse_national(p + 1, facilities, facilities_len - 1); | 413 | break; |
| 376 | facilities_len -= len + 1; | 414 | |
| 377 | p += len + 1; | 415 | case FAC_CCITT: /* CCITT */ |
| 378 | break; | 416 | len = rose_parse_ccitt(p + 1, facilities, facilities_len - 1); |
| 379 | 417 | break; | |
| 380 | case FAC_CCITT: /* CCITT */ | 418 | |
| 381 | len = rose_parse_ccitt(p + 1, facilities, facilities_len - 1); | 419 | default: |
| 382 | facilities_len -= len + 1; | 420 | printk(KERN_DEBUG "ROSE: rose_parse_facilities - unknown facilities family %02X\n", *p); |
| 383 | p += len + 1; | 421 | len = 1; |
| 384 | break; | 422 | break; |
| 385 | 423 | } | |
| 386 | default: | 424 | |
| 387 | printk(KERN_DEBUG "ROSE: rose_parse_facilities - unknown facilities family %02X\n", *p); | 425 | if (len < 0) |
| 388 | facilities_len--; | 426 | return 0; |
| 389 | p++; | 427 | if (WARN_ON(len >= facilities_len)) |
| 390 | break; | 428 | return 0; |
| 391 | } | 429 | facilities_len -= len + 1; |
| 392 | } else | 430 | p += len + 1; |
| 393 | break; /* Error in facilities format */ | ||
| 394 | } | 431 | } |
| 395 | 432 | ||
| 396 | return 1; | 433 | return facilities_len == 0; |
| 397 | } | 434 | } |
| 398 | 435 | ||
| 399 | static int rose_create_facilities(unsigned char *buffer, struct rose_sock *rose) | 436 | static int rose_create_facilities(unsigned char *buffer, struct rose_sock *rose) |
