| 708 | } |
| 709 | |
| 710 | static inline int |
| 711 | freebsd2linux_cmsghdr(struct linux_msghdr *linux_msg, const struct msghdr *freebsd_msg) |
| 712 | { |
| 713 | struct cmsghdr *freebsd_cmsg = CMSG_FIRSTHDR(freebsd_msg); |
| 714 | struct linux_cmsghdr *linux_cmsg = LINUX_CMSG_FIRSTHDR(linux_msg); |
| 715 | |
| 716 | while (freebsd_cmsg && linux_cmsg) { |
| 717 | unsigned char *freebsd_optval = CMSG_DATA(freebsd_cmsg); |
| 718 | unsigned char *linux_optval = LINUX_CMSG_DATA(linux_cmsg); |
| 719 | |
| 720 | /* |
| 721 | * The address of linux_cmsg and freebsd_cmsg coincides while recvmsg, |
| 722 | * but the position of the variable pointer is different, |
| 723 | * and the assignment must be reversed. |
| 724 | * |
| 725 | * Although sizeof(struct linux_msghdr) and sizeof(struct msghdr) have different lengths, |
| 726 | * but cmsg_data both skip the same 16 bytes,both aligned to 8 bytes. |
| 727 | */ |
| 728 | linux_cmsg->cmsg_type = freebsd_cmsg->cmsg_type; |
| 729 | linux_cmsg->cmsg_level = freebsd_cmsg->cmsg_level; |
| 730 | linux_cmsg->cmsg_len = LINUX_CMSG_LEN(freebsd_cmsg->cmsg_len - CMSG_ALIGN(sizeof(struct cmsghdr))); |
| 731 | |
| 732 | /* |
| 733 | * The freebsd_msg's cmsg_level and cmsg_type has been moddied while recvmsg, |
| 734 | * must use linux_cmsg to judge and calculate data length. |
| 735 | * And don't copy other the bytes that used aligned. |
| 736 | */ |
| 737 | switch (linux_cmsg->cmsg_level) { |
| 738 | case IPPROTO_IP: |
| 739 | switch (linux_cmsg->cmsg_type) { |
| 740 | case IP_RECVTOS: |
| 741 | linux_cmsg->cmsg_type = LINUX_IP_TOS; |
| 742 | *linux_optval = *freebsd_optval; |
| 743 | break; |
| 744 | case IP_RECVTTL: |
| 745 | linux_cmsg->cmsg_len = LINUX_CMSG_LEN(sizeof(int)); |
| 746 | linux_cmsg->cmsg_type = LINUX_IP_TTL; |
| 747 | *(int *)linux_optval = *freebsd_optval; |
| 748 | break; |
| 749 | /*case XXXX: |
| 750 | break;*/ |
| 751 | default: |
| 752 | memcpy(linux_optval, freebsd_optval, linux_cmsg->cmsg_len - sizeof(struct linux_cmsghdr)); |
| 753 | break; |
| 754 | } |
| 755 | |
| 756 | break; |
| 757 | default: |
| 758 | memcpy(linux_optval, freebsd_optval, linux_cmsg->cmsg_len - sizeof(struct linux_cmsghdr)); |
| 759 | break; |
| 760 | } |
| 761 | |
| 762 | linux_cmsg = LINUX_CMSG_NXTHDR(linux_msg, linux_cmsg); |
| 763 | freebsd_cmsg = CMSG_NXTHDR(freebsd_msg, freebsd_cmsg); |
| 764 | } |
| 765 | |
| 766 | return 0; |
| 767 | } |
no test coverage detected