-/*
- * Hard limit on the number of source and/or destination addresses
- * that can be specified by an application.
- */
-#define SOCKADDRLIST_MAX_ENTRIES 64
-
-static int
-getsockaddrlist(struct socket *so, struct sockaddr_list **slp,
- user_addr_t uaddr, socklen_t uaddrlen, boolean_t xlate_unspec)
-{
- struct sockaddr_list *sl;
- int error = 0;
-
- *slp = NULL;
-
- if (uaddr == USER_ADDR_NULL || uaddrlen == 0 ||
- uaddrlen > (sizeof(struct sockaddr_in6) * SOCKADDRLIST_MAX_ENTRIES))
- return (EINVAL);
-
- sl = sockaddrlist_alloc(M_WAITOK);
- if (sl == NULL)
- return (ENOMEM);
-
- VERIFY(sl->sl_cnt == 0);
- while (uaddrlen > 0 && sl->sl_cnt < SOCKADDRLIST_MAX_ENTRIES) {
- struct sockaddr_storage ss;
- struct sockaddr_entry *se;
- struct sockaddr *sa;
-
- if (uaddrlen < sizeof (struct sockaddr)) {
- error = EINVAL;
- break;
- }
-
- bzero(&ss, sizeof (ss));
- error = copyin(uaddr, (caddr_t)&ss, sizeof (struct sockaddr));
- if (error != 0)
- break;
-
- /* getsockaddr does the same but we need them now */
- if (uaddrlen < ss.ss_len ||
- ss.ss_len < offsetof(struct sockaddr, sa_data[0])) {
- error = EINVAL;
- break;
- } else if (ss.ss_len > sizeof (ss)) {
- /*
- * sockaddr_storage size is less than SOCK_MAXADDRLEN,
- * so the check here is inclusive. We could use the
- * latter instead, but seems like an overkill for now.
- */
- error = ENAMETOOLONG;
- break;
- }
-
- se = sockaddrentry_alloc(M_WAITOK);
- if (se == NULL) {
- error = ENOBUFS;
- break;
- }
-
- sockaddrlist_insert(sl, se);
-
- error = getsockaddr(so, &sa, uaddr, ss.ss_len, xlate_unspec);
- if (error != 0)
- break;
-
- VERIFY(sa != NULL && sa->sa_len == ss.ss_len);
- se->se_addr = sa;
-
- uaddr += ss.ss_len;
- VERIFY(((signed)uaddrlen - ss.ss_len) >= 0);
- uaddrlen -= ss.ss_len;
- }
-
- if (error != 0)
- sockaddrlist_free(sl);
- else
- *slp = sl;
-
- return (error);
-}
-