* Take one ND option. */
| 385 | * Take one ND option. |
| 386 | */ |
| 387 | struct nd_opt_hdr * |
| 388 | nd6_option(union nd_opts *ndopts) |
| 389 | { |
| 390 | struct nd_opt_hdr *nd_opt; |
| 391 | int olen; |
| 392 | |
| 393 | KASSERT(ndopts != NULL, ("%s: ndopts == NULL", __func__)); |
| 394 | KASSERT(ndopts->nd_opts_last != NULL, ("%s: uninitialized ndopts", |
| 395 | __func__)); |
| 396 | if (ndopts->nd_opts_search == NULL) |
| 397 | return NULL; |
| 398 | if (ndopts->nd_opts_done) |
| 399 | return NULL; |
| 400 | |
| 401 | nd_opt = ndopts->nd_opts_search; |
| 402 | |
| 403 | /* make sure nd_opt_len is inside the buffer */ |
| 404 | if ((caddr_t)&nd_opt->nd_opt_len >= (caddr_t)ndopts->nd_opts_last) { |
| 405 | bzero(ndopts, sizeof(*ndopts)); |
| 406 | return NULL; |
| 407 | } |
| 408 | |
| 409 | olen = nd_opt->nd_opt_len << 3; |
| 410 | if (olen == 0) { |
| 411 | /* |
| 412 | * Message validation requires that all included |
| 413 | * options have a length that is greater than zero. |
| 414 | */ |
| 415 | bzero(ndopts, sizeof(*ndopts)); |
| 416 | return NULL; |
| 417 | } |
| 418 | |
| 419 | ndopts->nd_opts_search = (struct nd_opt_hdr *)((caddr_t)nd_opt + olen); |
| 420 | if (ndopts->nd_opts_search > ndopts->nd_opts_last) { |
| 421 | /* option overruns the end of buffer, invalid */ |
| 422 | bzero(ndopts, sizeof(*ndopts)); |
| 423 | return NULL; |
| 424 | } else if (ndopts->nd_opts_search == ndopts->nd_opts_last) { |
| 425 | /* reached the end of options chain */ |
| 426 | ndopts->nd_opts_done = 1; |
| 427 | ndopts->nd_opts_search = NULL; |
| 428 | } |
| 429 | return nd_opt; |
| 430 | } |
| 431 | |
| 432 | /* |
| 433 | * Parse multiple ND options. |