| 761 | } |
| 762 | |
| 763 | static struct rt_msghdr * |
| 764 | rtmsg(int cmd, struct sockaddr_in *dst, struct sockaddr_dl *sdl) |
| 765 | { |
| 766 | static int seq; |
| 767 | int rlen; |
| 768 | int l; |
| 769 | static int s = -1; |
| 770 | static pid_t pid; |
| 771 | |
| 772 | static struct { |
| 773 | struct rt_msghdr m_rtm; |
| 774 | char m_space[512]; |
| 775 | } m_rtmsg; |
| 776 | |
| 777 | struct rt_msghdr *rtm = &m_rtmsg.m_rtm; |
| 778 | char *cp = m_rtmsg.m_space; |
| 779 | |
| 780 | if (s < 0) { /* first time: open socket, get pid */ |
| 781 | s = socket(PF_ROUTE, SOCK_RAW, 0); |
| 782 | if (s < 0) |
| 783 | xo_err(1, "socket"); |
| 784 | pid = getpid(); |
| 785 | } |
| 786 | |
| 787 | errno = 0; |
| 788 | /* |
| 789 | * XXX RTM_DELETE relies on a previous RTM_GET to fill the buffer |
| 790 | * appropriately. |
| 791 | */ |
| 792 | if (cmd == RTM_DELETE) |
| 793 | goto doit; |
| 794 | bzero((char *)&m_rtmsg, sizeof(m_rtmsg)); |
| 795 | rtm->rtm_flags = flags; |
| 796 | rtm->rtm_version = RTM_VERSION; |
| 797 | |
| 798 | switch (cmd) { |
| 799 | default: |
| 800 | xo_errx(1, "internal wrong cmd"); |
| 801 | case RTM_ADD: |
| 802 | rtm->rtm_addrs |= RTA_GATEWAY; |
| 803 | rtm->rtm_rmx.rmx_expire = expire_time; |
| 804 | rtm->rtm_inits = RTV_EXPIRE; |
| 805 | rtm->rtm_flags |= (RTF_HOST | RTF_STATIC | RTF_LLDATA); |
| 806 | /* FALLTHROUGH */ |
| 807 | case RTM_GET: |
| 808 | rtm->rtm_addrs |= RTA_DST; |
| 809 | } |
| 810 | #define NEXTADDR(w, s) \ |
| 811 | do { \ |
| 812 | if ((s) != NULL && rtm->rtm_addrs & (w)) { \ |
| 813 | bcopy((s), cp, sizeof(*(s))); \ |
| 814 | cp += SA_SIZE(s); \ |
| 815 | } \ |
| 816 | } while (0) |
| 817 | |
| 818 | NEXTADDR(RTA_DST, dst); |
| 819 | NEXTADDR(RTA_GATEWAY, sdl); |
| 820 | |